diff --git a/.eslintrc.js b/.eslintrc.js index 63ace2611b..e50982d63a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -20,6 +20,7 @@ module.exports = { rules: { "indent": ["error", 2], "no-unused-vars": "off", + "semi": ["error", "always"], } }, { @@ -47,7 +48,9 @@ module.exports = { "@typescript-eslint/ban-types": "off", "@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/no-empty-interface": "off", - "indent": ["error", 2] + "indent": ["error", 2], + "semi": "off", + "@typescript-eslint/semi": ["error"], }, }, { @@ -75,7 +78,9 @@ module.exports = { "@typescript-eslint/explicit-module-boundary-types": "off", "@typescript-eslint/ban-types": "off", "@typescript-eslint/no-empty-function": "off", - "indent": ["error", 2] + "indent": ["error", 2], + "semi": "off", + "@typescript-eslint/semi": ["error"], }, } ] diff --git a/__mocks__/electron.ts b/__mocks__/electron.ts index 08c94f0f8c..86f35c956d 100644 --- a/__mocks__/electron.ts +++ b/__mocks__/electron.ts @@ -5,7 +5,7 @@ module.exports = { getVersion: jest.fn().mockReturnValue("3.0.0"), getLocale: jest.fn().mockRejectedValue("en"), getPath: jest.fn((name: string) => { - return "tmp" + return "tmp"; }), }, remote: { diff --git a/build/build_tray_icon.ts b/build/build_tray_icon.ts index 00d09b69bc..e02d884412 100644 --- a/build/build_tray_icon.ts +++ b/build/build_tray_icon.ts @@ -1,9 +1,9 @@ // Generate tray icons from SVG to PNG + different sizes and colors (B&W) // Command: `yarn build:tray-icons` -import path from "path" +import path from "path"; import sharp from "sharp"; -import jsdom from "jsdom" -import fs from "fs-extra" +import jsdom from "jsdom"; +import fs from "fs-extra"; export async function generateTrayIcon( { @@ -14,15 +14,15 @@ export async function generateTrayIcon( pixelSize = 32, shouldUseDarkColors = false, // managed by electron.nativeTheme.shouldUseDarkColors } = {}) { - outputFilename += shouldUseDarkColors ? "_dark" : "" - dpiSuffix = dpiSuffix !== "1x" ? `@${dpiSuffix}` : "" - const pngIconDestPath = path.resolve(outputFolder, `${outputFilename}${dpiSuffix}.png`) + outputFilename += shouldUseDarkColors ? "_dark" : ""; + dpiSuffix = dpiSuffix !== "1x" ? `@${dpiSuffix}` : ""; + const pngIconDestPath = path.resolve(outputFolder, `${outputFilename}${dpiSuffix}.png`); try { // Modify .SVG colors const trayIconColor = shouldUseDarkColors ? "white" : "black"; const svgDom = await jsdom.JSDOM.fromFile(svgIconPath); const svgRoot = svgDom.window.document.body.getElementsByTagName("svg")[0]; - svgRoot.innerHTML += `` + svgRoot.innerHTML += ``; const svgIconBuffer = Buffer.from(svgRoot.outerHTML); // Resize and convert to .PNG diff --git a/build/download_helm.ts b/build/download_helm.ts index 9dddf7fcdc..7a3dc62a72 100644 --- a/build/download_helm.ts +++ b/build/download_helm.ts @@ -1,3 +1,3 @@ -import { helmCli } from "../src/main/helm/helm-cli" +import { helmCli } from "../src/main/helm/helm-cli"; -helmCli.ensureBinary() +helmCli.ensureBinary(); diff --git a/build/download_kubectl.ts b/build/download_kubectl.ts index a697552aa8..137588ff58 100644 --- a/build/download_kubectl.ts +++ b/build/download_kubectl.ts @@ -1,20 +1,20 @@ -import packageInfo from "../package.json" -import fs from "fs" -import request from "request" -import md5File from "md5-file" -import requestPromise from "request-promise-native" -import { ensureDir, pathExists } from "fs-extra" -import path from "path" +import packageInfo from "../package.json"; +import fs from "fs"; +import request from "request"; +import md5File from "md5-file"; +import requestPromise from "request-promise-native"; +import { ensureDir, pathExists } from "fs-extra"; +import path from "path"; class KubectlDownloader { - public kubectlVersion: string - protected url: string + public kubectlVersion: string; + protected url: string; protected path: string; - protected dirname: string + protected dirname: string; constructor(clusterVersion: string, platform: string, arch: string, target: string) { this.kubectlVersion = clusterVersion; - const binaryName = platform === "windows" ? "kubectl.exe" : "kubectl" + const binaryName = platform === "windows" ? "kubectl.exe" : "kubectl"; this.url = `https://storage.googleapis.com/kubernetes-release/release/v${this.kubectlVersion}/bin/${platform}/${arch}/${binaryName}`; this.dirname = path.dirname(target); this.path = target; @@ -25,83 +25,85 @@ class KubectlDownloader { method: "HEAD", uri: this.url, resolveWithFullResponse: true - }).catch((error) => { console.log(error) }) + }).catch((error) => { console.log(error); }); if (response.headers["etag"]) { - return response.headers["etag"].replace(/"/g, "") + return response.headers["etag"].replace(/"/g, ""); } - return "" + return ""; } public async checkBinary() { - const exists = await pathExists(this.path) + const exists = await pathExists(this.path); if (exists) { - const hash = md5File.sync(this.path) - const etag = await this.urlEtag() + const hash = md5File.sync(this.path); + const etag = await this.urlEtag(); if(hash == etag) { - console.log("Kubectl md5sum matches the remote etag") - return true + console.log("Kubectl md5sum matches the remote etag"); + return true; } - console.log("Kubectl md5sum " + hash + " does not match the remote etag " + etag + ", unlinking and downloading again") - await fs.promises.unlink(this.path) + console.log("Kubectl md5sum " + hash + " does not match the remote etag " + etag + ", unlinking and downloading again"); + await fs.promises.unlink(this.path); } - return false + return false; } public async downloadKubectl() { const exists = await this.checkBinary(); if(exists) { - console.log("Already exists and is valid") - return + console.log("Already exists and is valid"); + return; } - await ensureDir(path.dirname(this.path), 0o755) + await ensureDir(path.dirname(this.path), 0o755); - const file = fs.createWriteStream(this.path) - console.log(`Downloading kubectl ${this.kubectlVersion} from ${this.url} to ${this.path}`) + const file = fs.createWriteStream(this.path); + console.log(`Downloading kubectl ${this.kubectlVersion} from ${this.url} to ${this.path}`); const requestOpts: request.UriOptions & request.CoreOptions = { uri: this.url, gzip: true - } - const stream = request(requestOpts) + }; + const stream = request(requestOpts); stream.on("complete", () => { - console.log("kubectl binary download finished") - file.end(() => {}) - }) + console.log("kubectl binary download finished"); + // eslint-disable-next-line @typescript-eslint/no-empty-function + file.end(() => {}); + }); stream.on("error", (error) => { - console.log(error) - fs.unlink(this.path, () => {}) - throw(error) - }) + console.log(error); + // eslint-disable-next-line @typescript-eslint/no-empty-function + fs.unlink(this.path, () => {}); + throw(error); + }); return new Promise((resolve, reject) => { file.on("close", () => { - console.log("kubectl binary download closed") + console.log("kubectl binary download closed"); fs.chmod(this.path, 0o755, (err) => { if (err) reject(err); - }) - resolve() - }) - stream.pipe(file) - }) + }); + resolve(); + }); + stream.pipe(file); + }); } } const downloadVersion = packageInfo.config.bundledKubectlVersion; -const baseDir = path.join(process.env.INIT_CWD, 'binaries', 'client') +const baseDir = path.join(process.env.INIT_CWD, 'binaries', 'client'); const downloads = [ { platform: 'linux', arch: 'amd64', target: path.join(baseDir, 'linux', 'x64', 'kubectl') }, { platform: 'darwin', arch: 'amd64', target: path.join(baseDir, 'darwin', 'x64', 'kubectl') }, { platform: 'windows', arch: 'amd64', target: path.join(baseDir, 'windows', 'x64', 'kubectl.exe') }, { platform: 'windows', arch: '386', target: path.join(baseDir, 'windows', 'ia32', 'kubectl.exe') } -] +]; downloads.forEach((dlOpts) => { - console.log(dlOpts) + console.log(dlOpts); const downloader = new KubectlDownloader(downloadVersion, dlOpts.platform, dlOpts.arch, dlOpts.target); console.log("Downloading: " + JSON.stringify(dlOpts)); - downloader.downloadKubectl().then(() => downloader.checkBinary().then(() => console.log("Download complete"))) -}) + downloader.downloadKubectl().then(() => downloader.checkBinary().then(() => console.log("Download complete"))); +}); diff --git a/build/notarize.js b/build/notarize.js index 3d97b152c5..9904dccc3b 100644 --- a/build/notarize.js +++ b/build/notarize.js @@ -1,4 +1,4 @@ -const { notarize } = require('electron-notarize') +const { notarize } = require('electron-notarize'); exports.default = async function notarizing(context) { const { electronPlatformName, appOutDir } = context; diff --git a/build/set_npm_version.ts b/build/set_npm_version.ts index 70ce97416d..17d4a1ef83 100644 --- a/build/set_npm_version.ts +++ b/build/set_npm_version.ts @@ -1,9 +1,9 @@ -import * as fs from "fs" -import * as path from "path" -import packageInfo from "../src/extensions/npm/extensions/package.json" -import appInfo from "../package.json" +import * as fs from "fs"; +import * as path from "path"; +import packageInfo from "../src/extensions/npm/extensions/package.json"; +import appInfo from "../package.json"; -const packagePath = path.join(__dirname, "../src/extensions/npm/extensions/package.json") +const packagePath = path.join(__dirname, "../src/extensions/npm/extensions/package.json"); -packageInfo.version = appInfo.version -fs.writeFileSync(packagePath, JSON.stringify(packageInfo, null, 2) + "\n") +packageInfo.version = appInfo.version; +fs.writeFileSync(packagePath, JSON.stringify(packageInfo, null, 2) + "\n"); diff --git a/extensions/example-extension/page.tsx b/extensions/example-extension/page.tsx index fbb91848a9..2fe28ea49c 100644 --- a/extensions/example-extension/page.tsx +++ b/extensions/example-extension/page.tsx @@ -1,10 +1,10 @@ import { LensRendererExtension, Component } from "@k8slens/extensions"; import { CoffeeDoodle } from "react-open-doodles"; import path from "path"; -import React from "react" +import React from "react"; export function ExampleIcon(props: Component.IconProps) { - return + return ; } export class ExamplePage extends React.Component<{ extension: LensRendererExtension }> { @@ -16,7 +16,7 @@ export class ExamplePage extends React.Component<{ extension: LensRendererExtens render() { const doodleStyle = { width: "200px" - } + }; return ( @@ -24,6 +24,6 @@ export class ExamplePage extends React.Component<{ extension: LensRendererExtens File: {__filename} - ) + ); } } diff --git a/extensions/example-extension/renderer.tsx b/extensions/example-extension/renderer.tsx index 7733ec6e47..ffec687e40 100644 --- a/extensions/example-extension/renderer.tsx +++ b/extensions/example-extension/renderer.tsx @@ -1,6 +1,6 @@ import { LensRendererExtension } from "@k8slens/extensions"; -import { ExampleIcon, ExamplePage } from "./page" -import React from "react" +import { ExampleIcon, ExamplePage } from "./page"; +import React from "react"; export default class ExampleExtension extends LensRendererExtension { clusterPages = [ diff --git a/extensions/kube-object-event-status/renderer.tsx b/extensions/kube-object-event-status/renderer.tsx index d5ca828c22..6224464a56 100644 --- a/extensions/kube-object-event-status/renderer.tsx +++ b/extensions/kube-object-event-status/renderer.tsx @@ -1,5 +1,5 @@ import { LensRendererExtension, K8sApi } from "@k8slens/extensions"; -import { resolveStatus, resolveStatusForCronJobs, resolveStatusForPods } from "./src/resolver" +import { resolveStatus, resolveStatusForCronJobs, resolveStatusForPods } from "./src/resolver"; export default class EventResourceStatusRendererExtension extends LensRendererExtension { kubeObjectStatusTexts = [ diff --git a/extensions/kube-object-event-status/src/resolver.tsx b/extensions/kube-object-event-status/src/resolver.tsx index ee83293815..e3921a9cd0 100644 --- a/extensions/kube-object-event-status/src/resolver.tsx +++ b/extensions/kube-object-event-status/src/resolver.tsx @@ -1,9 +1,9 @@ import { K8sApi } from "@k8slens/extensions"; export function resolveStatus(object: K8sApi.KubeObject): K8sApi.KubeObjectStatus { - const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi) + const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi); const events = (eventStore as K8sApi.EventStore).getEventsByObject(object); - let warnings = events.filter(evt => evt.isWarning()); + const warnings = events.filter(evt => evt.isWarning()); if (!events.length || !warnings.length) { return null; } @@ -12,16 +12,16 @@ export function resolveStatus(object: K8sApi.KubeObject): K8sApi.KubeObjectStatu level: K8sApi.KubeObjectStatusLevel.WARNING, text: `${event.message}`, timestamp: event.metadata.creationTimestamp - } + }; } export function resolveStatusForPods(pod: K8sApi.Pod): K8sApi.KubeObjectStatus { if (!pod.hasIssues()) { - return null + return null; } - const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi) + const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi); const events = (eventStore as K8sApi.EventStore).getEventsByObject(pod); - let warnings = events.filter(evt => evt.isWarning()); + const warnings = events.filter(evt => evt.isWarning()); if (!events.length || !warnings.length) { return null; } @@ -30,13 +30,13 @@ export function resolveStatusForPods(pod: K8sApi.Pod): K8sApi.KubeObjectStatus { level: K8sApi.KubeObjectStatusLevel.WARNING, text: `${event.message}`, timestamp: event.metadata.creationTimestamp - } + }; } export function resolveStatusForCronJobs(cronJob: K8sApi.CronJob): K8sApi.KubeObjectStatus { - const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi) + const eventStore = K8sApi.apiManager.getStore(K8sApi.eventApi); let events = (eventStore as K8sApi.EventStore).getEventsByObject(cronJob); - let warnings = events.filter(evt => evt.isWarning()); + const warnings = events.filter(evt => evt.isWarning()); if (cronJob.isNeverRun()) { events = events.filter(event => event.reason != "FailedNeedsStart"); } @@ -48,5 +48,5 @@ export function resolveStatusForCronJobs(cronJob: K8sApi.CronJob): K8sApi.KubeOb level: K8sApi.KubeObjectStatusLevel.WARNING, text: `${event.message}`, timestamp: event.metadata.creationTimestamp - } + }; } \ No newline at end of file diff --git a/extensions/license-menu-item/main.ts b/extensions/license-menu-item/main.ts index d43cf09e96..ca84041036 100644 --- a/extensions/license-menu-item/main.ts +++ b/extensions/license-menu-item/main.ts @@ -6,7 +6,7 @@ export default class LicenseLensMainExtension extends LensMainExtension { parentId: "help", label: "License", async click() { - Util.openExternal("https://k8slens.dev/licenses/eula.md") + Util.openExternal("https://k8slens.dev/licenses/eula.md"); } } ] diff --git a/extensions/license-menu-item/webpack.config.ts b/extensions/license-menu-item/webpack.config.ts index fec13a7096..7edcb8355e 100644 --- a/extensions/license-menu-item/webpack.config.ts +++ b/extensions/license-menu-item/webpack.config.ts @@ -1,4 +1,4 @@ -import path from "path" +import path from "path"; const outputPath = path.resolve(__dirname, 'dist'); diff --git a/extensions/metrics-cluster-feature/renderer.tsx b/extensions/metrics-cluster-feature/renderer.tsx index 58565c13f5..a285328b12 100644 --- a/extensions/metrics-cluster-feature/renderer.tsx +++ b/extensions/metrics-cluster-feature/renderer.tsx @@ -1,6 +1,6 @@ -import { LensRendererExtension } from "@k8slens/extensions" -import { MetricsFeature } from "./src/metrics-feature" -import React from "react" +import { LensRendererExtension } from "@k8slens/extensions"; +import { MetricsFeature } from "./src/metrics-feature"; +import React from "react"; export default class ClusterMetricsFeatureExtension extends LensRendererExtension { clusterFeatures = [ @@ -13,8 +13,8 @@ export default class ClusterMetricsFeatureExtension extends LensRendererExtensio Enable timeseries data visualization (Prometheus stack) for your cluster. Install this only if you don't have existing Prometheus stack installed. You can see preview of manifests here. - - ) + + ); } }, feature: new MetricsFeature() diff --git a/extensions/metrics-cluster-feature/src/metrics-feature.ts b/extensions/metrics-cluster-feature/src/metrics-feature.ts index b42b726c0b..777f36b35a 100644 --- a/extensions/metrics-cluster-feature/src/metrics-feature.ts +++ b/extensions/metrics-cluster-feature/src/metrics-feature.ts @@ -1,6 +1,6 @@ -import { ClusterFeature, Store, K8sApi } from "@k8slens/extensions" -import semver from "semver" -import * as path from "path" +import { ClusterFeature, Store, K8sApi } from "@k8slens/extensions"; +import semver from "semver"; +import * as path from "path"; export interface MetricsConfiguration { // Placeholder for Metrics config structure @@ -51,46 +51,46 @@ export class MetricsFeature extends ClusterFeature.Feature { async install(cluster: Store.Cluster): Promise { // Check if there are storageclasses - const storageClassApi = K8sApi.forCluster(cluster, K8sApi.StorageClass) - const scs = await storageClassApi.list() + const storageClassApi = K8sApi.forCluster(cluster, K8sApi.StorageClass); + const scs = await storageClassApi.list(); this.config.persistence.enabled = scs.some(sc => ( sc.metadata?.annotations?.['storageclass.kubernetes.io/is-default-class'] === 'true' || sc.metadata?.annotations?.['storageclass.beta.kubernetes.io/is-default-class'] === 'true' )); - super.applyResources(cluster, super.renderTemplates(path.join(__dirname, "../resources/"))) + super.applyResources(cluster, super.renderTemplates(path.join(__dirname, "../resources/"))); } async upgrade(cluster: Store.Cluster): Promise { - return this.install(cluster) + return this.install(cluster); } async updateStatus(cluster: Store.Cluster): Promise { try { - const statefulSet = K8sApi.forCluster(cluster, K8sApi.StatefulSet) - const prometheus = await statefulSet.get({name: "prometheus", namespace: "lens-metrics"}) + const statefulSet = K8sApi.forCluster(cluster, K8sApi.StatefulSet); + const prometheus = await statefulSet.get({name: "prometheus", namespace: "lens-metrics"}); if (prometheus?.kind) { this.status.installed = true; this.status.currentVersion = prometheus.spec.template.spec.containers[0].image.split(":")[1]; this.status.canUpgrade = semver.lt(this.status.currentVersion, this.latestVersion, true); } else { - this.status.installed = false + this.status.installed = false; } } catch(e) { if (e?.error?.code === 404) { - this.status.installed = false + this.status.installed = false; } } - return this.status + return this.status; } async uninstall(cluster: Store.Cluster): Promise { - const namespaceApi = K8sApi.forCluster(cluster, K8sApi.Namespace) - const clusterRoleBindingApi = K8sApi.forCluster(cluster, K8sApi.ClusterRoleBinding) - const clusterRoleApi = K8sApi.forCluster(cluster, K8sApi.ClusterRole) + const namespaceApi = K8sApi.forCluster(cluster, K8sApi.Namespace); + const clusterRoleBindingApi = K8sApi.forCluster(cluster, K8sApi.ClusterRoleBinding); + const clusterRoleApi = K8sApi.forCluster(cluster, K8sApi.ClusterRole); - await namespaceApi.delete({name: "lens-metrics"}) - await clusterRoleBindingApi.delete({name: "lens-prometheus"}) - await clusterRoleApi.delete({name: "lens-prometheus"}) } + await namespaceApi.delete({name: "lens-metrics"}); + await clusterRoleBindingApi.delete({name: "lens-prometheus"}); + await clusterRoleApi.delete({name: "lens-prometheus"}); } } diff --git a/extensions/node-menu/renderer.tsx b/extensions/node-menu/renderer.tsx index db8232a518..ebe6cf46ce 100644 --- a/extensions/node-menu/renderer.tsx +++ b/extensions/node-menu/renderer.tsx @@ -1,6 +1,6 @@ import { LensRendererExtension } from "@k8slens/extensions"; -import React from "react" -import { NodeMenu, NodeMenuProps } from "./src/node-menu" +import React from "react"; +import { NodeMenu, NodeMenuProps } from "./src/node-menu"; export default class NodeMenuRendererExtension extends LensRendererExtension { kubeObjectMenuItems = [ diff --git a/extensions/node-menu/src/node-menu.tsx b/extensions/node-menu/src/node-menu.tsx index 8c7466694e..7284518ac4 100644 --- a/extensions/node-menu/src/node-menu.tsx +++ b/extensions/node-menu/src/node-menu.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { Component, K8sApi, Navigation} from "@k8slens/extensions" +import { Component, K8sApi, Navigation} from "@k8slens/extensions"; export interface NodeMenuProps extends Component.KubeObjectMenuProps { } @@ -15,7 +15,7 @@ export function NodeMenu(props: NodeMenuProps) { newTab: true, }); Navigation.hideDetails(); - } + }; const shell = () => { Component.createTerminalTab({ @@ -23,15 +23,15 @@ export function NodeMenu(props: NodeMenuProps) { node: nodeName, }); Navigation.hideDetails(); - } + }; const cordon = () => { sendToTerminal(`kubectl cordon ${nodeName}`); - } + }; const unCordon = () => { - sendToTerminal(`kubectl uncordon ${nodeName}`) - } + sendToTerminal(`kubectl uncordon ${nodeName}`); + }; const drain = () => { const command = `kubectl drain ${nodeName} --delete-local-data --ignore-daemonsets --force`; @@ -43,8 +43,8 @@ export function NodeMenu(props: NodeMenuProps) { Are you sure you want to drain {nodeName}?
File: {__filename}
{ params?: P; @@ -8,7 +8,7 @@ export interface IURLParams
{ export function buildURL
(path: string | any) { const pathBuilder = compile(String(path)); return function ({ params, query }: IURLParams
= {}) { - const queryParams = query ? new URLSearchParams(Object.entries(query)).toString() : "" - return pathBuilder(params) + (queryParams ? `?${queryParams}` : "") - } + const queryParams = query ? new URLSearchParams(Object.entries(query)).toString() : ""; + return pathBuilder(params) + (queryParams ? `?${queryParams}` : ""); + }; } diff --git a/src/common/utils/defineGlobal.ts b/src/common/utils/defineGlobal.ts index 29e2e60ea0..1a4c5993d9 100755 --- a/src/common/utils/defineGlobal.ts +++ b/src/common/utils/defineGlobal.ts @@ -5,7 +5,7 @@ export function defineGlobal(propName: string, descriptor: PropertyDescriptor) { const scope = typeof global !== "undefined" ? global : window; if (scope.hasOwnProperty(propName)) { - console.info(`Global variable "${propName}" already exists. Skipping.`) + console.info(`Global variable "${propName}" already exists. Skipping.`); return; } Object.defineProperty(scope, propName, descriptor); diff --git a/src/common/utils/index.ts b/src/common/utils/index.ts index 0dfad2d15f..e43863284d 100644 --- a/src/common/utils/index.ts +++ b/src/common/utils/index.ts @@ -1,14 +1,14 @@ // Common utils (main OR renderer) -export * from "./app-version" -export * from "./autobind" -export * from "./base64" -export * from "./camelCase" -export * from "./cloneJson" -export * from "./debouncePromise" -export * from "./defineGlobal" -export * from "./getRandId" -export * from "./splitArray" -export * from "./saveToAppFiles" -export * from "./singleton" -export * from "./openExternal" +export * from "./app-version"; +export * from "./autobind"; +export * from "./base64"; +export * from "./camelCase"; +export * from "./cloneJson"; +export * from "./debouncePromise"; +export * from "./defineGlobal"; +export * from "./getRandId"; +export * from "./splitArray"; +export * from "./saveToAppFiles"; +export * from "./singleton"; +export * from "./openExternal"; diff --git a/src/common/utils/openExternal.ts b/src/common/utils/openExternal.ts index 02c4da6c3b..56d7f90ce6 100644 --- a/src/common/utils/openExternal.ts +++ b/src/common/utils/openExternal.ts @@ -1,5 +1,5 @@ // Opens a link in external browser -import { shell } from "electron" +import { shell } from "electron"; export function openExternal(url: string) { return shell.openExternal(url); diff --git a/src/common/utils/saveToAppFiles.ts b/src/common/utils/saveToAppFiles.ts index e6fab1cfa9..57c47f0d70 100644 --- a/src/common/utils/saveToAppFiles.ts +++ b/src/common/utils/saveToAppFiles.ts @@ -2,7 +2,7 @@ import path from "path"; import { app, remote } from "electron"; import { ensureDirSync, writeFileSync } from "fs-extra"; -import { WriteFileOptions } from "fs" +import { WriteFileOptions } from "fs"; export function saveToAppFiles(filePath: string, contents: any, options?: WriteFileOptions): string { const absPath = path.resolve((app || remote.app).getPath("userData"), filePath); diff --git a/src/common/utils/singleton.ts b/src/common/utils/singleton.ts index 70347f9b42..ed3f0cc962 100644 --- a/src/common/utils/singleton.ts +++ b/src/common/utils/singleton.ts @@ -24,5 +24,5 @@ class Singleton { } } -export { Singleton } +export { Singleton }; export default Singleton; \ No newline at end of file diff --git a/src/common/utils/splitArray.ts b/src/common/utils/splitArray.ts index 90c342827d..f93392f736 100644 --- a/src/common/utils/splitArray.ts +++ b/src/common/utils/splitArray.ts @@ -15,5 +15,5 @@ export function splitArray(array: T[], element: T): [T[], T[], boolean] { if (index < 0) { return [array, [], false]; } - return [array.slice(0, index), array.slice(index + 1, array.length), true] + return [array.slice(0, index), array.slice(index + 1, array.length), true]; } diff --git a/src/common/vars.ts b/src/common/vars.ts index dd792e3bed..1957a6dcff 100644 --- a/src/common/vars.ts +++ b/src/common/vars.ts @@ -1,19 +1,19 @@ // App's common configuration for any process (main, renderer, build pipeline, etc.) import path from "path"; -import packageInfo from "../../package.json" +import packageInfo from "../../package.json"; import { defineGlobal } from "./utils/defineGlobal"; -export const isMac = process.platform === "darwin" -export const isWindows = process.platform === "win32" -export const isLinux = process.platform === "linux" +export const isMac = process.platform === "darwin"; +export const isWindows = process.platform === "win32"; +export const isLinux = process.platform === "linux"; export const isDebugging = process.env.DEBUG === "true"; -export const isSnap = !!process.env["SNAP"] -export const isProduction = process.env.NODE_ENV === "production" +export const isSnap = !!process.env["SNAP"]; +export const isProduction = process.env.NODE_ENV === "production"; export const isTestEnv = !!process.env.JEST_WORKER_ID; export const isDevelopment = !isTestEnv && !isProduction; -export const appName = `${packageInfo.productName}${isDevelopment ? "Dev" : ""}` -export const publicPath = "/build/" +export const appName = `${packageInfo.productName}${isDevelopment ? "Dev" : ""}`; +export const publicPath = "/build/"; // Webpack build paths export const contextDir = process.cwd(); @@ -22,7 +22,7 @@ export const mainDir = path.join(contextDir, "src/main"); export const rendererDir = path.join(contextDir, "src/renderer"); export const htmlTemplate = path.resolve(rendererDir, "template.html"); export const sassCommonVars = path.resolve(rendererDir, "components/vars.scss"); -export const webpackDevServerPort = 9009 +export const webpackDevServerPort = 9009; // Special runtime paths defineGlobal("__static", { @@ -30,14 +30,14 @@ defineGlobal("__static", { if (isDevelopment) { return path.resolve(contextDir, "static"); } - return path.resolve(process.resourcesPath, "static") + return path.resolve(process.resourcesPath, "static"); } -}) +}); // Apis -export const apiPrefix = "/api" // local router apis -export const apiKubePrefix = "/api-kube" // k8s cluster apis +export const apiPrefix = "/api"; // local router apis +export const apiKubePrefix = "/api-kube"; // k8s cluster apis // Links -export const issuesTrackerUrl = "https://github.com/lensapp/lens/issues" -export const slackUrl = "https://join.slack.com/t/k8slens/shared_invite/enQtOTc5NjAyNjYyOTk4LWU1NDQ0ZGFkOWJkNTRhYTc2YjVmZDdkM2FkNGM5MjhiYTRhMDU2NDQ1MzIyMDA4ZGZlNmExOTc0N2JmY2M3ZGI" +export const issuesTrackerUrl = "https://github.com/lensapp/lens/issues"; +export const slackUrl = "https://join.slack.com/t/k8slens/shared_invite/enQtOTc5NjAyNjYyOTk4LWU1NDQ0ZGFkOWJkNTRhYTc2YjVmZDdkM2FkNGM5MjhiYTRhMDU2NDQ1MzIyMDA4ZGZlNmExOTc0N2JmY2M3ZGI"; diff --git a/src/common/workspace-store.ts b/src/common/workspace-store.ts index baae6287ab..67e1c4d22a 100644 --- a/src/common/workspace-store.ts +++ b/src/common/workspace-store.ts @@ -1,7 +1,7 @@ import { ipcRenderer } from "electron"; import { action, computed, observable, toJS, reaction } from "mobx"; import { BaseStore } from "./base-store"; -import { clusterStore } from "./cluster-store" +import { clusterStore } from "./cluster-store"; import { appEventBus } from "./event-bus"; import { broadcastMessage } from "../common/ipc"; import logger from "../main/logger"; @@ -25,40 +25,40 @@ export interface WorkspaceState { } export class Workspace implements WorkspaceModel, WorkspaceState { - @observable id: WorkspaceId - @observable name: string - @observable description?: string - @observable ownerRef?: string - @observable enabled: boolean + @observable id: WorkspaceId; + @observable name: string; + @observable description?: string; + @observable ownerRef?: string; + @observable enabled: boolean; constructor(data: WorkspaceModel) { - Object.assign(this, data) + Object.assign(this, data); if (!ipcRenderer) { reaction(() => this.getState(), () => { - this.pushState() - }) + this.pushState(); + }); } } get isManaged(): boolean { - return !!this.ownerRef + return !!this.ownerRef; } getState(): WorkspaceState { return { enabled: this.enabled - } + }; } pushState(state = this.getState()) { - logger.silly("[WORKSPACE] pushing state", {...state, id: this.id}) - broadcastMessage("workspace:state", this.id, toJS(state)) + logger.silly("[WORKSPACE] pushing state", {...state, id: this.id}); + broadcastMessage("workspace:state", this.id, toJS(state)); } @action setState(state: WorkspaceState) { - Object.assign(this, state) + Object.assign(this, state); } toJSON(): WorkspaceModel { @@ -67,12 +67,12 @@ export class Workspace implements WorkspaceModel, WorkspaceState { name: this.name, description: this.description, ownerRef: this.ownerRef - }) + }); } } export class WorkspaceStore extends BaseStore { - static readonly defaultId: WorkspaceId = "default" + static readonly defaultId: WorkspaceId = "default"; private constructor() { super({ @@ -81,21 +81,21 @@ export class WorkspaceStore extends BaseStore { if (!ipcRenderer) { setInterval(() => { - this.pushState() - }, 5000) + this.pushState(); + }, 5000); } } registerIpcListener() { - logger.info("[WORKSPACE-STORE] starting to listen state events") + logger.info("[WORKSPACE-STORE] starting to listen state events"); ipcRenderer.on("workspace:state", (event, workspaceId: string, state: WorkspaceState) => { - this.getById(workspaceId)?.setState(state) - }) + this.getById(workspaceId)?.setState(state); + }); } unregisterIpcListener() { - super.unregisterIpcListener() - ipcRenderer.removeAllListeners("workspace:state") + super.unregisterIpcListener(); + ipcRenderer.removeAllListeners("workspace:state"); } @observable currentWorkspaceId = WorkspaceStore.defaultId; @@ -121,8 +121,8 @@ export class WorkspaceStore extends BaseStore { pushState() { this.workspaces.forEach((w) => { - w.pushState() - }) + w.pushState(); + }); } isDefault(id: WorkspaceId) { @@ -154,7 +154,7 @@ export class WorkspaceStore extends BaseStore { return; } this.workspaces.set(id, workspace); - appEventBus.emit({name: "workspace", action: "add"}) + appEventBus.emit({name: "workspace", action: "add"}); return workspace; } @@ -166,7 +166,7 @@ export class WorkspaceStore extends BaseStore { @action removeWorkspace(workspace: Workspace) { - this.removeWorkspaceById(workspace.id) + this.removeWorkspaceById(workspace.id); } @action @@ -180,24 +180,24 @@ export class WorkspaceStore extends BaseStore { this.currentWorkspaceId = WorkspaceStore.defaultId; // reset to default } this.workspaces.delete(id); - appEventBus.emit({name: "workspace", action: "remove"}) - clusterStore.removeByWorkspaceId(id) + appEventBus.emit({name: "workspace", action: "remove"}); + clusterStore.removeByWorkspaceId(id); } @action protected fromStore({ currentWorkspace, workspaces = [] }: WorkspaceStoreModel) { if (currentWorkspace) { - this.currentWorkspaceId = currentWorkspace + this.currentWorkspaceId = currentWorkspace; } if (workspaces.length) { this.workspaces.clear(); workspaces.forEach(ws => { - const workspace = new Workspace(ws) + const workspace = new Workspace(ws); if (!workspace.isManaged) { - workspace.enabled = true + workspace.enabled = true; } - this.workspaces.set(workspace.id, workspace) - }) + this.workspaces.set(workspace.id, workspace); + }); } } @@ -207,8 +207,8 @@ export class WorkspaceStore extends BaseStore { workspaces: this.workspacesList.map((w) => w.toJSON()), }, { recurseEverything: true - }) + }); } } -export const workspaceStore = WorkspaceStore.getInstance() +export const workspaceStore = WorkspaceStore.getInstance(); diff --git a/src/extensions/__tests__/lens-extension.test.ts b/src/extensions/__tests__/lens-extension.test.ts index c7e9ed5513..d6ba04cbb5 100644 --- a/src/extensions/__tests__/lens-extension.test.ts +++ b/src/extensions/__tests__/lens-extension.test.ts @@ -1,6 +1,6 @@ -import { LensExtension } from "../lens-extension" +import { LensExtension } from "../lens-extension"; -let ext: LensExtension = null +let ext: LensExtension = null; describe("lens extension", () => { beforeEach(async () => { @@ -12,12 +12,12 @@ describe("lens extension", () => { manifestPath: "/this/is/fake/package.json", isBundled: false, isEnabled: true - }) - }) + }); + }); describe("name", () => { it("returns name", () => { - expect(ext.name).toBe("foo-bar") - }) - }) -}) + expect(ext.name).toBe("foo-bar"); + }); + }); +}); diff --git a/src/extensions/cluster-feature.ts b/src/extensions/cluster-feature.ts index 90cbd3a0a9..6381d267cc 100644 --- a/src/extensions/cluster-feature.ts +++ b/src/extensions/cluster-feature.ts @@ -1,11 +1,11 @@ import fs from "fs"; -import path from "path" -import hb from "handlebars" -import { observable } from "mobx" -import { ResourceApplier } from "../main/resource-applier" +import path from "path"; +import hb from "handlebars"; +import { observable } from "mobx"; +import { ResourceApplier } from "../main/resource-applier"; import { Cluster } from "../main/cluster"; import logger from "../main/logger"; -import { app } from "electron" +import { app } from "electron"; import { requestMain } from "../common/ipc"; import { clusterKubectlApplyAllHandler } from "../common/cluster-ipc"; @@ -26,7 +26,7 @@ export abstract class ClusterFeature { installed: false, latestVersion: null, canUpgrade: false - } + }; abstract async install(cluster: Cluster): Promise; @@ -38,9 +38,9 @@ export abstract class ClusterFeature { protected async applyResources(cluster: Cluster, resources: string[]) { if (app) { - await new ResourceApplier(cluster).kubectlApplyAll(resources) + await new ResourceApplier(cluster).kubectlApplyAll(resources); } else { - await requestMain(clusterKubectlApplyAllHandler, cluster.id, resources) + await requestMain(clusterKubectlApplyAllHandler, cluster.id, resources); } } diff --git a/src/extensions/core-api/app.ts b/src/extensions/core-api/app.ts index f3e44ed001..fdd9425b47 100644 --- a/src/extensions/core-api/app.ts +++ b/src/extensions/core-api/app.ts @@ -1,4 +1,4 @@ import { getAppVersion } from "../../common/utils"; -export const version = getAppVersion() -export { isSnap, isWindows, isMac, isLinux, appName, slackUrl, issuesTrackerUrl } from "../../common/vars" \ No newline at end of file +export const version = getAppVersion(); +export { isSnap, isWindows, isMac, isLinux, appName, slackUrl, issuesTrackerUrl } from "../../common/vars"; \ No newline at end of file diff --git a/src/extensions/core-api/cluster-feature.ts b/src/extensions/core-api/cluster-feature.ts index 9f2d3b8a40..170f4543f3 100644 --- a/src/extensions/core-api/cluster-feature.ts +++ b/src/extensions/core-api/cluster-feature.ts @@ -1,2 +1,2 @@ -export { ClusterFeature as Feature } from "../cluster-feature" -export type { ClusterFeatureStatus as FeatureStatus } from "../cluster-feature" +export { ClusterFeature as Feature } from "../cluster-feature"; +export type { ClusterFeatureStatus as FeatureStatus } from "../cluster-feature"; diff --git a/src/extensions/core-api/event-bus.ts b/src/extensions/core-api/event-bus.ts index c958d19129..1a7be58143 100644 --- a/src/extensions/core-api/event-bus.ts +++ b/src/extensions/core-api/event-bus.ts @@ -1,2 +1,2 @@ -export { appEventBus } from "../../common/event-bus" -export type { AppEvent } from "../../common/event-bus" +export { appEventBus } from "../../common/event-bus"; +export type { AppEvent } from "../../common/event-bus"; diff --git a/src/extensions/core-api/index.ts b/src/extensions/core-api/index.ts index dc040a3355..19ede51817 100644 --- a/src/extensions/core-api/index.ts +++ b/src/extensions/core-api/index.ts @@ -1,14 +1,14 @@ // Lens-extensions api developer's kit -export * from "../lens-main-extension" -export * from "../lens-renderer-extension" +export * from "../lens-main-extension"; +export * from "../lens-renderer-extension"; // APIs -import * as App from "./app" -import * as EventBus from "./event-bus" -import * as Store from "./stores" -import * as Util from "./utils" -import * as ClusterFeature from "./cluster-feature" -import * as Interface from "../interfaces" +import * as App from "./app"; +import * as EventBus from "./event-bus"; +import * as Store from "./stores"; +import * as Util from "./utils"; +import * as ClusterFeature from "./cluster-feature"; +import * as Interface from "../interfaces"; export { App, @@ -17,4 +17,4 @@ export { Interface, Store, Util, -} +}; diff --git a/src/extensions/core-api/stores.ts b/src/extensions/core-api/stores.ts index d44536769f..d7e489e5c0 100644 --- a/src/extensions/core-api/stores.ts +++ b/src/extensions/core-api/stores.ts @@ -1,6 +1,6 @@ -export { ExtensionStore } from "../extension-store" -export { clusterStore } from "../../common/cluster-store" -export type { ClusterModel } from "../../common/cluster-store" -export { Cluster } from "../../main/cluster" -export { workspaceStore, Workspace } from "../../common/workspace-store" -export type { WorkspaceModel } from "../../common/workspace-store" +export { ExtensionStore } from "../extension-store"; +export { clusterStore } from "../../common/cluster-store"; +export type { ClusterModel } from "../../common/cluster-store"; +export { Cluster } from "../../main/cluster"; +export { workspaceStore, Workspace } from "../../common/workspace-store"; +export type { WorkspaceModel } from "../../common/workspace-store"; diff --git a/src/extensions/core-api/utils.ts b/src/extensions/core-api/utils.ts index c70959f2ba..c249ff5238 100644 --- a/src/extensions/core-api/utils.ts +++ b/src/extensions/core-api/utils.ts @@ -1,3 +1,3 @@ -export { Singleton, openExternal } from "../../common/utils" -export { prevDefault, stopPropagation } from "../../renderer/utils/prevDefault" -export { cssNames } from "../../renderer/utils/cssNames" +export { Singleton, openExternal } from "../../common/utils"; +export { prevDefault, stopPropagation } from "../../renderer/utils/prevDefault"; +export { cssNames } from "../../renderer/utils/cssNames"; diff --git a/src/extensions/extension-api.ts b/src/extensions/extension-api.ts index b6be0b9f4e..e4a8a77334 100644 --- a/src/extensions/extension-api.ts +++ b/src/extensions/extension-api.ts @@ -1,4 +1,4 @@ // Extension-api types generation bundle -export * from "./core-api" -export * from "./renderer-api" +export * from "./core-api"; +export * from "./renderer-api"; diff --git a/src/extensions/extension-loader.ts b/src/extensions/extension-loader.ts index 643d9658bc..c71fe90db2 100644 --- a/src/extensions/extension-loader.ts +++ b/src/extensions/extension-loader.ts @@ -1,24 +1,24 @@ -import type { LensExtension, LensExtensionConstructor, LensExtensionId } from "./lens-extension" -import type { LensMainExtension } from "./lens-main-extension" -import type { LensRendererExtension } from "./lens-renderer-extension" +import type { LensExtension, LensExtensionConstructor, LensExtensionId } from "./lens-extension"; +import type { LensMainExtension } from "./lens-main-extension"; +import type { LensRendererExtension } from "./lens-renderer-extension"; import type { InstalledExtension } from "./extension-manager"; -import path from "path" -import { broadcastMessage, handleRequest, requestMain, subscribeToBroadcast } from "../common/ipc" -import { action, computed, observable, reaction, toJS, when } from "mobx" -import logger from "../main/logger" -import { app, ipcRenderer, remote } from "electron" +import path from "path"; +import { broadcastMessage, handleRequest, requestMain, subscribeToBroadcast } from "../common/ipc"; +import { action, computed, observable, reaction, toJS, when } from "mobx"; +import logger from "../main/logger"; +import { app, ipcRenderer, remote } from "electron"; import * as registries from "./registries"; import { extensionsStore } from "./extensions-store"; // lazy load so that we get correct userData export function extensionPackagesRoot() { - return path.join((app || remote.app).getPath("userData")) + return path.join((app || remote.app).getPath("userData")); } export class ExtensionLoader { protected extensions = observable.map(); protected instances = observable.map(); - protected readonly requestExtensionsChannel = "extensions:loaded" + protected readonly requestExtensionsChannel = "extensions:loaded"; @observable isLoaded = false; whenLoaded = when(() => this.isLoaded); @@ -29,22 +29,22 @@ export class ExtensionLoader { if (ext.isBundled) { extensions.delete(extId); } - }) + }); return extensions; } @action async init() { if (ipcRenderer) { - this.initRenderer() + this.initRenderer(); } else { - this.initMain() + this.initMain(); } extensionsStore.manageState(this); } initExtensions(extensions?: Map) { - this.extensions.replace(extensions) + this.extensions.replace(extensions); } protected async initMain() { @@ -53,12 +53,12 @@ export class ExtensionLoader { this.broadcastExtensions(); reaction(() => this.extensions.toJS(), () => { - this.broadcastExtensions() - }) + this.broadcastExtensions(); + }); handleRequest(this.requestExtensionsChannel, () => { - return Array.from(this.toJSON()) - }) + return Array.from(this.toJSON()); + }); } protected async initRenderer() { @@ -66,25 +66,25 @@ export class ExtensionLoader { this.isLoaded = true; extensions.forEach(([extId, ext]) => { if (!this.extensions.has(extId)) { - this.extensions.set(extId, ext) + this.extensions.set(extId, ext); } - }) - } - requestMain(this.requestExtensionsChannel).then(extensionListHandler) + }); + }; + requestMain(this.requestExtensionsChannel).then(extensionListHandler); subscribeToBroadcast(this.requestExtensionsChannel, (event, extensions: [LensExtensionId, InstalledExtension][]) => { - extensionListHandler(extensions) + extensionListHandler(extensions); }); } loadOnMain() { - logger.info('[EXTENSIONS-LOADER]: load on main') + logger.info('[EXTENSIONS-LOADER]: load on main'); this.autoInitExtensions((ext: LensMainExtension) => [ registries.menuRegistry.add(ext.appMenus) ]); } loadOnClusterManagerRenderer() { - logger.info('[EXTENSIONS-LOADER]: load on main renderer (cluster manager)') + logger.info('[EXTENSIONS-LOADER]: load on main renderer (cluster manager)'); this.autoInitExtensions((ext: LensRendererExtension) => [ registries.globalPageRegistry.add(ext.globalPages, ext), registries.globalPageMenuRegistry.add(ext.globalPageMenus, ext), @@ -95,14 +95,14 @@ export class ExtensionLoader { } loadOnClusterRenderer() { - logger.info('[EXTENSIONS-LOADER]: load on cluster renderer (dashboard)') + logger.info('[EXTENSIONS-LOADER]: load on cluster renderer (dashboard)'); this.autoInitExtensions((ext: LensRendererExtension) => [ registries.clusterPageRegistry.add(ext.clusterPages, ext), registries.clusterPageMenuRegistry.add(ext.clusterPageMenus, ext), registries.kubeObjectMenuRegistry.add(ext.kubeObjectMenuItems), registries.kubeObjectDetailRegistry.add(ext.kubeObjectDetailItems), registries.kubeObjectStatusRegistry.add(ext.kubeObjectStatusTexts) - ]) + ]); } protected autoInitExtensions(register: (ext: LensExtension) => Function[]) { @@ -111,43 +111,43 @@ export class ExtensionLoader { let instance = this.instances.get(extId); if (ext.isEnabled && !instance) { try { - const LensExtensionClass: LensExtensionConstructor = this.requireExtension(ext) + const LensExtensionClass: LensExtensionConstructor = this.requireExtension(ext); if (!LensExtensionClass) continue; instance = new LensExtensionClass(ext); instance.whenEnabled(() => register(instance)); instance.enable(); this.instances.set(extId, instance); } catch (err) { - logger.error(`[EXTENSION-LOADER]: activation extension error`, { ext, err }) + logger.error(`[EXTENSION-LOADER]: activation extension error`, { ext, err }); } } else if (!ext.isEnabled && instance) { try { instance.disable(); this.instances.delete(extId); } catch (err) { - logger.error(`[EXTENSION-LOADER]: deactivation extension error`, { ext, err }) + logger.error(`[EXTENSION-LOADER]: deactivation extension error`, { ext, err }); } } } }, { fireImmediately: true, - }) + }); } protected requireExtension(extension: InstalledExtension) { - let extEntrypoint = "" + let extEntrypoint = ""; try { if (ipcRenderer && extension.manifest.renderer) { - extEntrypoint = path.resolve(path.join(path.dirname(extension.manifestPath), extension.manifest.renderer)) + extEntrypoint = path.resolve(path.join(path.dirname(extension.manifestPath), extension.manifest.renderer)); } else if (!ipcRenderer && extension.manifest.main) { - extEntrypoint = path.resolve(path.join(path.dirname(extension.manifestPath), extension.manifest.main)) + extEntrypoint = path.resolve(path.join(path.dirname(extension.manifestPath), extension.manifest.main)); } if (extEntrypoint !== "") { return __non_webpack_require__(extEntrypoint).default; } } catch (err) { console.error(`[EXTENSION-LOADER]: can't load extension main at ${extEntrypoint}: ${err}`, { extension }); - console.trace(err) + console.trace(err); } } @@ -159,11 +159,11 @@ export class ExtensionLoader { return toJS(this.extensions, { exportMapsAsObjects: false, recurseEverything: true, - }) + }); } broadcastExtensions() { - broadcastMessage(this.requestExtensionsChannel, Array.from(this.toJSON())) + broadcastMessage(this.requestExtensionsChannel, Array.from(this.toJSON())); } } diff --git a/src/extensions/extension-manager.ts b/src/extensions/extension-manager.ts index 7a10fa35f4..0e51eeb666 100644 --- a/src/extensions/extension-manager.ts +++ b/src/extensions/extension-manager.ts @@ -1,11 +1,11 @@ -import type { LensExtensionId, LensExtensionManifest } from "./lens-extension" -import path from "path" -import os from "os" -import fs from "fs-extra" +import type { LensExtensionId, LensExtensionManifest } from "./lens-extension"; +import path from "path"; +import os from "os"; +import fs from "fs-extra"; import child_process from "child_process"; -import logger from "../main/logger" -import { extensionPackagesRoot } from "./extension-loader" -import { getBundledExtensions } from "../common/utils/app-version" +import logger from "../main/logger"; +import { extensionPackagesRoot } from "./extension-loader"; +import { getBundledExtensions } from "../common/utils/app-version"; export interface InstalledExtension { readonly manifest: LensExtensionManifest; @@ -16,26 +16,26 @@ export interface InstalledExtension { type Dependencies = { [name: string]: string; -} +}; type PackageJson = { dependencies: Dependencies; -} +}; export class ExtensionManager { - protected bundledFolderPath: string + protected bundledFolderPath: string; protected packagesJson: PackageJson = { dependencies: {} - } + }; get extensionPackagesRoot() { - return extensionPackagesRoot() + return extensionPackagesRoot(); } get inTreeTargetPath() { - return path.join(this.extensionPackagesRoot, "extensions") + return path.join(this.extensionPackagesRoot, "extensions"); } get inTreeFolderPath(): string { @@ -43,7 +43,7 @@ export class ExtensionManager { } get nodeModulesPath(): string { - return path.join(this.extensionPackagesRoot, "node_modules") + return path.join(this.extensionPackagesRoot, "node_modules"); } get localFolderPath(): string { @@ -51,30 +51,30 @@ export class ExtensionManager { } get npmPath() { - return __non_webpack_require__.resolve('npm/bin/npm-cli') + return __non_webpack_require__.resolve('npm/bin/npm-cli'); } get packageJsonPath() { - return path.join(this.extensionPackagesRoot, "package.json") + return path.join(this.extensionPackagesRoot, "package.json"); } async load(): Promise> { - logger.info("[EXTENSION-MANAGER] loading extensions from " + this.extensionPackagesRoot) + logger.info("[EXTENSION-MANAGER] loading extensions from " + this.extensionPackagesRoot); if (fs.existsSync(path.join(this.extensionPackagesRoot, "package-lock.json"))) { - await fs.remove(path.join(this.extensionPackagesRoot, "package-lock.json")) + await fs.remove(path.join(this.extensionPackagesRoot, "package-lock.json")); } try { - await fs.access(this.inTreeFolderPath, fs.constants.W_OK) - this.bundledFolderPath = this.inTreeFolderPath + await fs.access(this.inTreeFolderPath, fs.constants.W_OK); + this.bundledFolderPath = this.inTreeFolderPath; } catch { // we need to copy in-tree extensions so that we can symlink them properly on "npm install" - await fs.remove(this.inTreeTargetPath) - await fs.ensureDir(this.inTreeTargetPath) - await fs.copy(this.inTreeFolderPath, this.inTreeTargetPath) - this.bundledFolderPath = this.inTreeTargetPath + await fs.remove(this.inTreeTargetPath); + await fs.ensureDir(this.inTreeTargetPath); + await fs.copy(this.inTreeFolderPath, this.inTreeTargetPath); + this.bundledFolderPath = this.inTreeTargetPath; } - await fs.ensureDir(this.nodeModulesPath) - await fs.ensureDir(this.localFolderPath) + await fs.ensureDir(this.nodeModulesPath); + await fs.ensureDir(this.localFolderPath); return await this.loadExtensions(); } @@ -82,16 +82,16 @@ export class ExtensionManager { let manifestJson: LensExtensionManifest; try { fs.accessSync(manifestPath, fs.constants.F_OK); // check manifest file for existence - manifestJson = __non_webpack_require__(manifestPath) - this.packagesJson.dependencies[manifestJson.name] = path.dirname(manifestPath) + manifestJson = __non_webpack_require__(manifestPath); + this.packagesJson.dependencies[manifestJson.name] = path.dirname(manifestPath); - logger.info("[EXTENSION-MANAGER] installed extension " + manifestJson.name) + logger.info("[EXTENSION-MANAGER] installed extension " + manifestJson.name); return { manifestPath: path.join(this.nodeModulesPath, manifestJson.name, "package.json"), manifest: manifestJson, isBundled: isBundled, isEnabled: isBundled, - } + }; } catch (err) { logger.error(`[EXTENSION-MANAGER]: can't install extension at ${manifestPath}: ${err}`, { manifestJson }); } @@ -102,65 +102,65 @@ export class ExtensionManager { const child = child_process.fork(this.npmPath, ["install", "--silent", "--no-audit", "--only=prod", "--prefer-offline", "--no-package-lock"], { cwd: extensionPackagesRoot(), silent: true - }) + }); child.on("close", () => { - resolve() - }) + resolve(); + }); child.on("error", (err) => { - reject(err) - }) - }) + reject(err); + }); + }); } async loadExtensions() { - const bundledExtensions = await this.loadBundledExtensions() - const localExtensions = await this.loadFromFolder(this.localFolderPath) - await fs.writeFile(path.join(this.packageJsonPath), JSON.stringify(this.packagesJson, null, 2), { mode: 0o600 }) - await this.installPackages() - const extensions = bundledExtensions.concat(localExtensions) + const bundledExtensions = await this.loadBundledExtensions(); + const localExtensions = await this.loadFromFolder(this.localFolderPath); + await fs.writeFile(path.join(this.packageJsonPath), JSON.stringify(this.packagesJson, null, 2), { mode: 0o600 }); + await this.installPackages(); + const extensions = bundledExtensions.concat(localExtensions); return new Map(extensions.map(ext => [ext.manifestPath, ext])); } async loadBundledExtensions() { - const extensions: InstalledExtension[] = [] - const folderPath = this.bundledFolderPath - const bundledExtensions = getBundledExtensions() + const extensions: InstalledExtension[] = []; + const folderPath = this.bundledFolderPath; + const bundledExtensions = getBundledExtensions(); const paths = await fs.readdir(folderPath); for (const fileName of paths) { if (!bundledExtensions.includes(fileName)) { - continue + continue; } const absPath = path.resolve(folderPath, fileName); const manifestPath = path.resolve(absPath, "package.json"); - const ext = await this.getByManifest(manifestPath, { isBundled: true }).catch(() => null) + const ext = await this.getByManifest(manifestPath, { isBundled: true }).catch(() => null); if (ext) { - extensions.push(ext) + extensions.push(ext); } } logger.debug(`[EXTENSION-MANAGER]: ${extensions.length} extensions loaded`, { folderPath, extensions }); - return extensions + return extensions; } async loadFromFolder(folderPath: string): Promise { - const bundledExtensions = getBundledExtensions() - const extensions: InstalledExtension[] = [] + const bundledExtensions = getBundledExtensions(); + const extensions: InstalledExtension[] = []; const paths = await fs.readdir(folderPath); for (const fileName of paths) { if (bundledExtensions.includes(fileName)) { // do no allow to override bundled extensions - continue + continue; } const absPath = path.resolve(folderPath, fileName); if (!fs.existsSync(absPath)) { - continue + continue; } - const lstat = await fs.lstat(absPath) + const lstat = await fs.lstat(absPath); if (!lstat.isDirectory() && !lstat.isSymbolicLink()) { // skip non-directories - continue + continue; } const manifestPath = path.resolve(absPath, "package.json"); - const ext = await this.getByManifest(manifestPath).catch(() => null) + const ext = await this.getByManifest(manifestPath).catch(() => null); if (ext) { - extensions.push(ext) + extensions.push(ext); } } @@ -169,4 +169,4 @@ export class ExtensionManager { } } -export const extensionManager = new ExtensionManager() +export const extensionManager = new ExtensionManager(); diff --git a/src/extensions/extension-store.ts b/src/extensions/extension-store.ts index ec2f61948e..a8078994ca 100644 --- a/src/extensions/extension-store.ts +++ b/src/extensions/extension-store.ts @@ -1,21 +1,21 @@ -import { BaseStore } from "../common/base-store" -import * as path from "path" -import { LensExtension } from "./lens-extension" +import { BaseStore } from "../common/base-store"; +import * as path from "path"; +import { LensExtension } from "./lens-extension"; export abstract class ExtensionStore extends BaseStore { - protected extension: LensExtension + protected extension: LensExtension; async loadExtension(extension: LensExtension) { - this.extension = extension - return super.load() + this.extension = extension; + return super.load(); } async load() { - if (!this.extension) { return } - return super.load() + if (!this.extension) { return; } + return super.load(); } protected cwd() { - return path.join(super.cwd(), "extension-store", this.extension.name) + return path.join(super.cwd(), "extension-store", this.extension.name); } } diff --git a/src/extensions/extensions-store.ts b/src/extensions/extensions-store.ts index ba942c41d9..1669dd4bcc 100644 --- a/src/extensions/extensions-store.ts +++ b/src/extensions/extensions-store.ts @@ -1,6 +1,6 @@ import type { LensExtensionId } from "./lens-extension"; import type { ExtensionLoader } from "./extension-loader"; -import { BaseStore } from "../common/base-store" +import { BaseStore } from "../common/base-store"; import { action, observable, reaction, toJS } from "mobx"; export interface LensExtensionsStoreModel { @@ -25,9 +25,9 @@ export class ExtensionsStore extends BaseStore { return Array.from(extensionLoader.userExtensions).reduce((state, [extId, ext]) => { state[extId] = { enabled: ext.isEnabled, - } + }; return state; - }, state) + }, state); } async manageState(extensionLoader: ExtensionLoader) { @@ -46,13 +46,13 @@ export class ExtensionsStore extends BaseStore { if (ext && !ext.isBundled) { ext.isEnabled = state.enabled; } - }) - }) + }); + }); // save state on change `extension.isEnabled` reaction(() => this.getState(extensionLoader), extensionsState => { - this.state.merge(extensionsState) - }) + this.state.merge(extensionsState); + }); } isEnabled(extId: LensExtensionId) { @@ -70,7 +70,7 @@ export class ExtensionsStore extends BaseStore { extensions: this.state.toJSON(), }, { recurseEverything: true - }) + }); } } diff --git a/src/extensions/interfaces/index.ts b/src/extensions/interfaces/index.ts index e3612bdb7f..c91d8cdd19 100644 --- a/src/extensions/interfaces/index.ts +++ b/src/extensions/interfaces/index.ts @@ -1 +1 @@ -export * from "./registrations" \ No newline at end of file +export * from "./registrations"; \ No newline at end of file diff --git a/src/extensions/interfaces/registrations.ts b/src/extensions/interfaces/registrations.ts index 14c9f66c22..a2ebb10290 100644 --- a/src/extensions/interfaces/registrations.ts +++ b/src/extensions/interfaces/registrations.ts @@ -1,8 +1,8 @@ -export type { AppPreferenceRegistration, AppPreferenceComponents } from "../registries/app-preference-registry" -export type { ClusterFeatureRegistration, ClusterFeatureComponents } from "../registries/cluster-feature-registry" -export type { KubeObjectDetailRegistration, KubeObjectDetailComponents } from "../registries/kube-object-detail-registry" -export type { KubeObjectMenuRegistration, KubeObjectMenuComponents } from "../registries/kube-object-menu-registry" -export type { KubeObjectStatusRegistration } from "../registries/kube-object-status-registry" -export type { PageRegistration, PageComponents } from "../registries/page-registry" -export type { PageMenuRegistration, PageMenuComponents } from "../registries/page-menu-registry" -export type { StatusBarRegistration } from "../registries/status-bar-registry" \ No newline at end of file +export type { AppPreferenceRegistration, AppPreferenceComponents } from "../registries/app-preference-registry"; +export type { ClusterFeatureRegistration, ClusterFeatureComponents } from "../registries/cluster-feature-registry"; +export type { KubeObjectDetailRegistration, KubeObjectDetailComponents } from "../registries/kube-object-detail-registry"; +export type { KubeObjectMenuRegistration, KubeObjectMenuComponents } from "../registries/kube-object-menu-registry"; +export type { KubeObjectStatusRegistration } from "../registries/kube-object-status-registry"; +export type { PageRegistration, PageComponents } from "../registries/page-registry"; +export type { PageMenuRegistration, PageMenuComponents } from "../registries/page-menu-registry"; +export type { StatusBarRegistration } from "../registries/status-bar-registry"; \ No newline at end of file diff --git a/src/extensions/lens-extension.ts b/src/extensions/lens-extension.ts index f1ffb9184b..444cf449d6 100644 --- a/src/extensions/lens-extension.ts +++ b/src/extensions/lens-extension.ts @@ -21,9 +21,9 @@ export class LensExtension { @observable private isEnabled = false; constructor({ manifest, manifestPath, isBundled }: InstalledExtension) { - this.manifest = manifest - this.manifestPath = manifestPath - this.isBundled = !!isBundled + this.manifest = manifest; + this.manifestPath = manifestPath; + this.isBundled = !!isBundled; } get id(): LensExtensionId { @@ -31,15 +31,15 @@ export class LensExtension { } get name() { - return this.manifest.name + return this.manifest.name; } get version() { - return this.manifest.version + return this.manifest.version; } get description() { - return this.manifest.description + return this.manifest.description; } @action @@ -60,18 +60,18 @@ export class LensExtension { toggle(enable?: boolean) { if (typeof enable === "boolean") { - enable ? this.enable() : this.disable() + enable ? this.enable() : this.disable(); } else { - this.isEnabled ? this.disable() : this.enable() + this.isEnabled ? this.disable() : this.enable(); } } async whenEnabled(handlers: () => Function[]) { const disposers: Function[] = []; const unregisterHandlers = () => { - disposers.forEach(unregister => unregister()) + disposers.forEach(unregister => unregister()); disposers.length = 0; - } + }; const cancelReaction = reaction(() => this.isEnabled, isEnabled => { if (isEnabled) { disposers.push(...handlers()); @@ -80,11 +80,11 @@ export class LensExtension { } }, { fireImmediately: true - }) + }); return () => { unregisterHandlers(); cancelReaction(); - } + }; } protected onActivate() { diff --git a/src/extensions/lens-main-extension.ts b/src/extensions/lens-main-extension.ts index af091e0c1c..b425c5bf46 100644 --- a/src/extensions/lens-main-extension.ts +++ b/src/extensions/lens-main-extension.ts @@ -1,11 +1,11 @@ import type { MenuRegistration } from "./registries/menu-registry"; import { observable } from "mobx"; -import { LensExtension } from "./lens-extension" +import { LensExtension } from "./lens-extension"; import { WindowManager } from "../main/window-manager"; -import { getExtensionPageUrl } from "./registries/page-registry" +import { getExtensionPageUrl } from "./registries/page-registry"; export class LensMainExtension extends LensExtension { - @observable.shallow appMenus: MenuRegistration[] = [] + @observable.shallow appMenus: MenuRegistration[] = []; async navigate(pageId?: string, params?: P, frameId?: number) { const windowManager = WindowManager.getInstance(); diff --git a/src/extensions/lens-renderer-extension.ts b/src/extensions/lens-renderer-extension.ts index 0fb346e1a1..56ed90684f 100644 --- a/src/extensions/lens-renderer-extension.ts +++ b/src/extensions/lens-renderer-extension.ts @@ -1,19 +1,19 @@ -import type { AppPreferenceRegistration, ClusterFeatureRegistration, KubeObjectDetailRegistration, KubeObjectMenuRegistration, KubeObjectStatusRegistration, PageMenuRegistration, PageRegistration, StatusBarRegistration, } from "./registries" +import type { AppPreferenceRegistration, ClusterFeatureRegistration, KubeObjectDetailRegistration, KubeObjectMenuRegistration, KubeObjectStatusRegistration, PageMenuRegistration, PageRegistration, StatusBarRegistration, } from "./registries"; import { observable } from "mobx"; -import { LensExtension } from "./lens-extension" -import { getExtensionPageUrl } from "./registries/page-registry" +import { LensExtension } from "./lens-extension"; +import { getExtensionPageUrl } from "./registries/page-registry"; export class LensRendererExtension extends LensExtension { - @observable.shallow globalPages: PageRegistration[] = [] - @observable.shallow clusterPages: PageRegistration[] = [] - @observable.shallow globalPageMenus: PageMenuRegistration[] = [] - @observable.shallow clusterPageMenus: PageMenuRegistration[] = [] - @observable.shallow kubeObjectStatusTexts: KubeObjectStatusRegistration[] = [] - @observable.shallow appPreferences: AppPreferenceRegistration[] = [] - @observable.shallow clusterFeatures: ClusterFeatureRegistration[] = [] - @observable.shallow statusBarItems: StatusBarRegistration[] = [] - @observable.shallow kubeObjectDetailItems: KubeObjectDetailRegistration[] = [] - @observable.shallow kubeObjectMenuItems: KubeObjectMenuRegistration[] = [] + @observable.shallow globalPages: PageRegistration[] = []; + @observable.shallow clusterPages: PageRegistration[] = []; + @observable.shallow globalPageMenus: PageMenuRegistration[] = []; + @observable.shallow clusterPageMenus: PageMenuRegistration[] = []; + @observable.shallow kubeObjectStatusTexts: KubeObjectStatusRegistration[] = []; + @observable.shallow appPreferences: AppPreferenceRegistration[] = []; + @observable.shallow clusterFeatures: ClusterFeatureRegistration[] = []; + @observable.shallow statusBarItems: StatusBarRegistration[] = []; + @observable.shallow kubeObjectDetailItems: KubeObjectDetailRegistration[] = []; + @observable.shallow kubeObjectMenuItems: KubeObjectMenuRegistration[] = []; async navigate(pageId?: string, params?: P) { const { navigate } = await import("../renderer/navigation"); diff --git a/src/extensions/registries/__tests__/page-registry.test.ts b/src/extensions/registries/__tests__/page-registry.test.ts index 47a5f82d9d..29e60dccc0 100644 --- a/src/extensions/registries/__tests__/page-registry.test.ts +++ b/src/extensions/registries/__tests__/page-registry.test.ts @@ -1,8 +1,8 @@ -import { getExtensionPageUrl, globalPageRegistry, PageRegistration } from "../page-registry" -import { LensExtension } from "../../lens-extension" +import { getExtensionPageUrl, globalPageRegistry, PageRegistration } from "../page-registry"; +import { LensExtension } from "../../lens-extension"; import React from "react"; -let ext: LensExtension = null +let ext: LensExtension = null; describe("getPageUrl", () => { beforeEach(async () => { @@ -14,25 +14,25 @@ describe("getPageUrl", () => { manifestPath: "/this/is/fake/package.json", isBundled: false, isEnabled: true - }) - }) + }); + }); it("returns a page url for extension", () => { - expect(getExtensionPageUrl({ extensionId: ext.name })).toBe("/extension/foo-bar") - }) + expect(getExtensionPageUrl({ extensionId: ext.name })).toBe("/extension/foo-bar"); + }); it("allows to pass base url as parameter", () => { - expect(getExtensionPageUrl({ extensionId: ext.name, pageId: "/test" })).toBe("/extension/foo-bar/test") - }) + expect(getExtensionPageUrl({ extensionId: ext.name, pageId: "/test" })).toBe("/extension/foo-bar/test"); + }); it("removes @", () => { - expect(getExtensionPageUrl({ extensionId: "@foo/bar" })).toBe("/extension/foo-bar") - }) + expect(getExtensionPageUrl({ extensionId: "@foo/bar" })).toBe("/extension/foo-bar"); + }); it("adds / prefix", () => { - expect(getExtensionPageUrl({ extensionId: ext.name, pageId: "test" })).toBe("/extension/foo-bar/test") - }) -}) + expect(getExtensionPageUrl({ extensionId: ext.name, pageId: "test" })).toBe("/extension/foo-bar/test"); + }); +}); describe("globalPageRegistry", () => { beforeEach(async () => { @@ -44,7 +44,7 @@ describe("globalPageRegistry", () => { manifestPath: "/this/is/fake/package.json", isBundled: false, isEnabled: true - }) + }); globalPageRegistry.add([ { id: "test-page", @@ -63,12 +63,12 @@ describe("globalPageRegistry", () => { Page: () => React.createElement('Default') } }, - ], ext) - }) + ], ext); + }); describe("getByPageMenuTarget", () => { it("matching to first registered page without id", () => { - const page = globalPageRegistry.getByPageMenuTarget({ extensionId: ext.name }) + const page = globalPageRegistry.getByPageMenuTarget({ extensionId: ext.name }); expect(page.id).toEqual(undefined); expect(page.extensionId).toEqual(ext.name); expect(page.routePath).toEqual(getExtensionPageUrl({ extensionId: ext.name })); @@ -78,16 +78,16 @@ describe("globalPageRegistry", () => { const page = globalPageRegistry.getByPageMenuTarget({ pageId: "test-page", extensionId: ext.name - }) - expect(page.id).toEqual("test-page") - }) + }); + expect(page.id).toEqual("test-page"); + }); it("returns null if target not found", () => { const page = globalPageRegistry.getByPageMenuTarget({ pageId: "wrong-page", extensionId: ext.name - }) - expect(page).toBeNull() - }) - }) -}) + }); + expect(page).toBeNull(); + }); + }); +}); diff --git a/src/extensions/registries/app-preference-registry.ts b/src/extensions/registries/app-preference-registry.ts index 6c54911f82..338f93b5bc 100644 --- a/src/extensions/registries/app-preference-registry.ts +++ b/src/extensions/registries/app-preference-registry.ts @@ -1,4 +1,4 @@ -import type React from "react" +import type React from "react"; import { BaseRegistry } from "./base-registry"; export interface AppPreferenceComponents { @@ -14,4 +14,4 @@ export interface AppPreferenceRegistration { export class AppPreferenceRegistry extends BaseRegistry { } -export const appPreferenceRegistry = new AppPreferenceRegistry() +export const appPreferenceRegistry = new AppPreferenceRegistry(); diff --git a/src/extensions/registries/base-registry.ts b/src/extensions/registries/base-registry.ts index e82c9d11bf..73dbd373f0 100644 --- a/src/extensions/registries/base-registry.ts +++ b/src/extensions/registries/base-registry.ts @@ -12,7 +12,7 @@ export class BaseRegistry { add(items: T | T[], ext?: LensExtension): () => void; // allow method overloading with required "ext" @action add(items: T | T[]) { - const normalizedItems = (Array.isArray(items) ? items : [items]) + const normalizedItems = (Array.isArray(items) ? items : [items]); this.items.push(...normalizedItems); return () => this.remove(...normalizedItems); } @@ -21,6 +21,6 @@ export class BaseRegistry { remove(...items: T[]) { items.forEach(item => { this.items.remove(item); // works because of {deep: false}; - }) + }); } } diff --git a/src/extensions/registries/cluster-feature-registry.ts b/src/extensions/registries/cluster-feature-registry.ts index 0e3363d0f0..5017ad27a6 100644 --- a/src/extensions/registries/cluster-feature-registry.ts +++ b/src/extensions/registries/cluster-feature-registry.ts @@ -1,4 +1,4 @@ -import type React from "react" +import type React from "react"; import { BaseRegistry } from "./base-registry"; import { ClusterFeature } from "../cluster-feature"; @@ -15,4 +15,4 @@ export interface ClusterFeatureRegistration { export class ClusterFeatureRegistry extends BaseRegistry { } -export const clusterFeatureRegistry = new ClusterFeatureRegistry() +export const clusterFeatureRegistry = new ClusterFeatureRegistry(); diff --git a/src/extensions/registries/index.ts b/src/extensions/registries/index.ts index cdcfb7124b..8e343742ec 100644 --- a/src/extensions/registries/index.ts +++ b/src/extensions/registries/index.ts @@ -1,11 +1,11 @@ // All registries managed by extensions api -export * from "./page-registry" -export * from "./page-menu-registry" -export * from "./menu-registry" -export * from "./app-preference-registry" -export * from "./status-bar-registry" +export * from "./page-registry"; +export * from "./page-menu-registry"; +export * from "./menu-registry"; +export * from "./app-preference-registry"; +export * from "./status-bar-registry"; export * from "./kube-object-detail-registry"; export * from "./kube-object-menu-registry"; -export * from "./cluster-feature-registry" -export * from "./kube-object-status-registry" +export * from "./cluster-feature-registry"; +export * from "./kube-object-status-registry"; diff --git a/src/extensions/registries/kube-object-detail-registry.ts b/src/extensions/registries/kube-object-detail-registry.ts index 32fea66b81..2638e82ade 100644 --- a/src/extensions/registries/kube-object-detail-registry.ts +++ b/src/extensions/registries/kube-object-detail-registry.ts @@ -1,4 +1,4 @@ -import React from "react" +import React from "react"; import { BaseRegistry } from "./base-registry"; export interface KubeObjectDetailComponents { @@ -15,15 +15,15 @@ export interface KubeObjectDetailRegistration { export class KubeObjectDetailRegistry extends BaseRegistry { getItemsForKind(kind: string, apiVersion: string) { const items = this.getItems().filter((item) => { - return item.kind === kind && item.apiVersions.includes(apiVersion) + return item.kind === kind && item.apiVersions.includes(apiVersion); }).map((item) => { if (item.priority === null) { - item.priority = 50 + item.priority = 50; } - return item - }) - return items.sort((a, b) => b.priority - a.priority) + return item; + }); + return items.sort((a, b) => b.priority - a.priority); } } -export const kubeObjectDetailRegistry = new KubeObjectDetailRegistry() +export const kubeObjectDetailRegistry = new KubeObjectDetailRegistry(); diff --git a/src/extensions/registries/kube-object-menu-registry.ts b/src/extensions/registries/kube-object-menu-registry.ts index 8f527d6a3d..25901f66ad 100644 --- a/src/extensions/registries/kube-object-menu-registry.ts +++ b/src/extensions/registries/kube-object-menu-registry.ts @@ -1,4 +1,4 @@ -import React from "react" +import React from "react"; import { BaseRegistry } from "./base-registry"; export interface KubeObjectMenuComponents { @@ -14,9 +14,9 @@ export interface KubeObjectMenuRegistration { export class KubeObjectMenuRegistry extends BaseRegistry { getItemsForKind(kind: string, apiVersion: string) { return this.getItems().filter((item) => { - return item.kind === kind && item.apiVersions.includes(apiVersion) - }) + return item.kind === kind && item.apiVersions.includes(apiVersion); + }); } } -export const kubeObjectMenuRegistry = new KubeObjectMenuRegistry() +export const kubeObjectMenuRegistry = new KubeObjectMenuRegistry(); diff --git a/src/extensions/registries/kube-object-status-registry.ts b/src/extensions/registries/kube-object-status-registry.ts index 74fd8145d2..5f7aab8d5d 100644 --- a/src/extensions/registries/kube-object-status-registry.ts +++ b/src/extensions/registries/kube-object-status-registry.ts @@ -10,8 +10,8 @@ export interface KubeObjectStatusRegistration { export class KubeObjectStatusRegistry extends BaseRegistry { getItemsForKind(kind: string, apiVersion: string) { return this.getItems().filter((item) => { - return item.kind === kind && item.apiVersions.includes(apiVersion) - }) + return item.kind === kind && item.apiVersions.includes(apiVersion); + }); } } diff --git a/src/extensions/registries/page-menu-registry.ts b/src/extensions/registries/page-menu-registry.ts index ebaaa42dbb..15f11139e6 100644 --- a/src/extensions/registries/page-menu-registry.ts +++ b/src/extensions/registries/page-menu-registry.ts @@ -29,8 +29,8 @@ export class PageMenuRegistry extends BaseRegistry({ extensionId, pageId = "", params }: PageMenuTarget): string { @@ -68,13 +68,13 @@ export class PageRegistry extends BaseRegistry ...page, extensionId: ext.name, routePath: getExtensionPageUrl({ extensionId: ext.name, pageId: page.id ?? page.routePath }), - })) + })); } catch (err) { logger.error(`[EXTENSION]: page-registration failed`, { items, extension: ext, error: String(err), - }) + }); } return super.add(registeredPages); } diff --git a/src/extensions/renderer-api/components.ts b/src/extensions/renderer-api/components.ts index c051ce13e3..242799c749 100644 --- a/src/extensions/renderer-api/components.ts +++ b/src/extensions/renderer-api/components.ts @@ -1,36 +1,36 @@ // Common UI components // layouts -export * from "../../renderer/components/layout/page-layout" -export * from "../../renderer/components/layout/wizard-layout" -export * from "../../renderer/components/layout/tab-layout" +export * from "../../renderer/components/layout/page-layout"; +export * from "../../renderer/components/layout/wizard-layout"; +export * from "../../renderer/components/layout/tab-layout"; // form-controls -export * from "../../renderer/components/button" -export * from "../../renderer/components/checkbox" -export * from "../../renderer/components/radio" -export * from "../../renderer/components/select" -export * from "../../renderer/components/slider" -export * from "../../renderer/components/input/input" +export * from "../../renderer/components/button"; +export * from "../../renderer/components/checkbox"; +export * from "../../renderer/components/radio"; +export * from "../../renderer/components/select"; +export * from "../../renderer/components/slider"; +export * from "../../renderer/components/input/input"; // other components -export * from "../../renderer/components/icon" -export * from "../../renderer/components/tooltip" -export * from "../../renderer/components/tabs" -export * from "../../renderer/components/table" -export * from "../../renderer/components/badge" -export * from "../../renderer/components/drawer" -export * from "../../renderer/components/dialog" +export * from "../../renderer/components/icon"; +export * from "../../renderer/components/tooltip"; +export * from "../../renderer/components/tabs"; +export * from "../../renderer/components/table"; +export * from "../../renderer/components/badge"; +export * from "../../renderer/components/drawer"; +export * from "../../renderer/components/dialog"; export * from "../../renderer/components/confirm-dialog"; -export * from "../../renderer/components/line-progress" -export * from "../../renderer/components/menu" -export * from "../../renderer/components/notifications" -export * from "../../renderer/components/spinner" -export * from "../../renderer/components/stepper" +export * from "../../renderer/components/line-progress"; +export * from "../../renderer/components/menu"; +export * from "../../renderer/components/notifications"; +export * from "../../renderer/components/spinner"; +export * from "../../renderer/components/stepper"; // kube helpers -export * from "../../renderer/components/kube-object" -export * from "../../renderer/components/+events/kube-event-details" +export * from "../../renderer/components/kube-object"; +export * from "../../renderer/components/+events/kube-event-details"; // specific exports export * from "../../renderer/components/status-brick"; diff --git a/src/extensions/renderer-api/index.ts b/src/extensions/renderer-api/index.ts index 009f49c366..c8e14c0951 100644 --- a/src/extensions/renderer-api/index.ts +++ b/src/extensions/renderer-api/index.ts @@ -1,14 +1,14 @@ // Lens-extensions apis, required in renderer process runtime // APIs -import * as Component from "./components" -import * as K8sApi from "./k8s-api" -import * as Navigation from "./navigation" -import * as Theme from "./theming" +import * as Component from "./components"; +import * as K8sApi from "./k8s-api"; +import * as Navigation from "./navigation"; +import * as Theme from "./theming"; export { Component, K8sApi, Navigation, Theme, -} +}; diff --git a/src/extensions/renderer-api/k8s-api.ts b/src/extensions/renderer-api/k8s-api.ts index 2a26b49cdd..fe04550fb7 100644 --- a/src/extensions/renderer-api/k8s-api.ts +++ b/src/extensions/renderer-api/k8s-api.ts @@ -1,6 +1,6 @@ -export { isAllowedResource } from "../../common/rbac" +export { isAllowedResource } from "../../common/rbac"; export { apiManager } from "../../renderer/api/api-manager"; -export { KubeObjectStore } from "../../renderer/kube-object.store" +export { KubeObjectStore } from "../../renderer/kube-object.store"; export { KubeApi, forCluster, IKubeApiCluster } from "../../renderer/api/kube-api"; export { KubeObject } from "../../renderer/api/kube-object"; export { Pod, podsApi, PodsApi, IPodContainer, IPodContainerStatus } from "../../renderer/api/endpoints"; @@ -31,33 +31,33 @@ export { RoleBinding, roleBindingApi } from "../../renderer/api/endpoints"; export { ClusterRole, clusterRoleApi } from "../../renderer/api/endpoints"; export { ClusterRoleBinding, clusterRoleBindingApi } from "../../renderer/api/endpoints"; export { CustomResourceDefinition, crdApi } from "../../renderer/api/endpoints"; -export { KubeObjectStatus, KubeObjectStatusLevel } from "./kube-object-status" +export { KubeObjectStatus, KubeObjectStatusLevel } from "./kube-object-status"; // stores -export type { EventStore } from "../../renderer/components/+events/event.store" -export type { PodsStore } from "../../renderer/components/+workloads-pods/pods.store" -export type { NodesStore } from "../../renderer/components/+nodes/nodes.store" -export type { DeploymentStore } from "../../renderer/components/+workloads-deployments/deployments.store" -export type { DaemonSetStore } from "../../renderer/components/+workloads-daemonsets/daemonsets.store" -export type { StatefulSetStore } from "../../renderer/components/+workloads-statefulsets/statefulset.store" -export type { JobStore } from "../../renderer/components/+workloads-jobs/job.store" -export type { CronJobStore } from "../../renderer/components/+workloads-cronjobs/cronjob.store" -export type { ConfigMapsStore } from "../../renderer/components/+config-maps/config-maps.store" -export type { SecretsStore } from "../../renderer/components/+config-secrets/secrets.store" -export type { ReplicaSetStore } from "../../renderer/components/+workloads-replicasets/replicasets.store" -export type { ResourceQuotasStore } from "../../renderer/components/+config-resource-quotas/resource-quotas.store" -export type { HPAStore } from "../../renderer/components/+config-autoscalers/hpa.store" -export type { PodDisruptionBudgetsStore } from "../../renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store" -export type { ServiceStore } from "../../renderer/components/+network-services/services.store" -export type { EndpointStore } from "../../renderer/components/+network-endpoints/endpoints.store" -export type { IngressStore } from "../../renderer/components/+network-ingresses/ingress.store" -export type { NetworkPolicyStore } from "../../renderer/components/+network-policies/network-policy.store" -export type { PersistentVolumesStore } from "../../renderer/components/+storage-volumes/volumes.store" -export type { VolumeClaimStore } from "../../renderer/components/+storage-volume-claims/volume-claim.store" -export type { StorageClassStore } from "../../renderer/components/+storage-classes/storage-class.store" -export type { NamespaceStore } from "../../renderer/components/+namespaces/namespace.store" -export type { ServiceAccountsStore } from "../../renderer/components/+user-management-service-accounts/service-accounts.store" -export type { RolesStore } from "../../renderer/components/+user-management-roles/roles.store" -export type { RoleBindingsStore } from "../../renderer/components/+user-management-roles-bindings/role-bindings.store" -export type { CRDStore } from "../../renderer/components/+custom-resources/crd.store" -export type { CRDResourceStore } from "../../renderer/components/+custom-resources/crd-resource.store" +export type { EventStore } from "../../renderer/components/+events/event.store"; +export type { PodsStore } from "../../renderer/components/+workloads-pods/pods.store"; +export type { NodesStore } from "../../renderer/components/+nodes/nodes.store"; +export type { DeploymentStore } from "../../renderer/components/+workloads-deployments/deployments.store"; +export type { DaemonSetStore } from "../../renderer/components/+workloads-daemonsets/daemonsets.store"; +export type { StatefulSetStore } from "../../renderer/components/+workloads-statefulsets/statefulset.store"; +export type { JobStore } from "../../renderer/components/+workloads-jobs/job.store"; +export type { CronJobStore } from "../../renderer/components/+workloads-cronjobs/cronjob.store"; +export type { ConfigMapsStore } from "../../renderer/components/+config-maps/config-maps.store"; +export type { SecretsStore } from "../../renderer/components/+config-secrets/secrets.store"; +export type { ReplicaSetStore } from "../../renderer/components/+workloads-replicasets/replicasets.store"; +export type { ResourceQuotasStore } from "../../renderer/components/+config-resource-quotas/resource-quotas.store"; +export type { HPAStore } from "../../renderer/components/+config-autoscalers/hpa.store"; +export type { PodDisruptionBudgetsStore } from "../../renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store"; +export type { ServiceStore } from "../../renderer/components/+network-services/services.store"; +export type { EndpointStore } from "../../renderer/components/+network-endpoints/endpoints.store"; +export type { IngressStore } from "../../renderer/components/+network-ingresses/ingress.store"; +export type { NetworkPolicyStore } from "../../renderer/components/+network-policies/network-policy.store"; +export type { PersistentVolumesStore } from "../../renderer/components/+storage-volumes/volumes.store"; +export type { VolumeClaimStore } from "../../renderer/components/+storage-volume-claims/volume-claim.store"; +export type { StorageClassStore } from "../../renderer/components/+storage-classes/storage-class.store"; +export type { NamespaceStore } from "../../renderer/components/+namespaces/namespace.store"; +export type { ServiceAccountsStore } from "../../renderer/components/+user-management-service-accounts/service-accounts.store"; +export type { RolesStore } from "../../renderer/components/+user-management-roles/roles.store"; +export type { RoleBindingsStore } from "../../renderer/components/+user-management-roles-bindings/role-bindings.store"; +export type { CRDStore } from "../../renderer/components/+custom-resources/crd.store"; +export type { CRDResourceStore } from "../../renderer/components/+custom-resources/crd-resource.store"; diff --git a/src/extensions/renderer-api/kube-object-status.ts b/src/extensions/renderer-api/kube-object-status.ts index 22994ee85d..f609d736fe 100644 --- a/src/extensions/renderer-api/kube-object-status.ts +++ b/src/extensions/renderer-api/kube-object-status.ts @@ -2,7 +2,7 @@ export type KubeObjectStatus = { level: KubeObjectStatusLevel; text: string; timestamp?: string; -} +}; export enum KubeObjectStatusLevel { INFO = 1, diff --git a/src/extensions/renderer-api/navigation.ts b/src/extensions/renderer-api/navigation.ts index f923f6e152..a1191a4b30 100644 --- a/src/extensions/renderer-api/navigation.ts +++ b/src/extensions/renderer-api/navigation.ts @@ -1,3 +1,3 @@ export { navigate } from "../../renderer/navigation"; -export { hideDetails, showDetails, getDetailsUrl } from "../../renderer/navigation" +export { hideDetails, showDetails, getDetailsUrl } from "../../renderer/navigation"; export { IURLParams } from "../../common/utils/buildUrl"; diff --git a/src/jest.setup.ts b/src/jest.setup.ts index 08727bc910..7b4732930e 100644 --- a/src/jest.setup.ts +++ b/src/jest.setup.ts @@ -1,4 +1,4 @@ -import fetchMock from "jest-fetch-mock" +import fetchMock from "jest-fetch-mock"; // rewire global.fetch to call 'fetchMock' fetchMock.enableMocks(); diff --git a/src/main/__test__/cluster.test.ts b/src/main/__test__/cluster.test.ts index 1fb92ed4bc..95177408af 100644 --- a/src/main/__test__/cluster.test.ts +++ b/src/main/__test__/cluster.test.ts @@ -21,35 +21,35 @@ jest.mock("winston", () => ({ Console: jest.fn(), File: jest.fn(), } -})) +})); -jest.mock("../../common/ipc") -jest.mock("../context-handler") -jest.mock("request") -jest.mock("request-promise-native") +jest.mock("../../common/ipc"); +jest.mock("../context-handler"); +jest.mock("request"); +jest.mock("request-promise-native"); import { Console } from "console"; import mockFs from "mock-fs"; import { workspaceStore } from "../../common/workspace-store"; -import { Cluster } from "../cluster" +import { Cluster } from "../cluster"; import { ContextHandler } from "../context-handler"; import { getFreePort } from "../port"; import { V1ResourceAttributes } from "@kubernetes/client-node"; import { apiResources } from "../../common/rbac"; -import request from "request-promise-native" +import request from "request-promise-native"; import { Kubectl } from "../kubectl"; -const mockedRequest = request as jest.MockedFunction +const mockedRequest = request as jest.MockedFunction; -console = new Console(process.stdout, process.stderr) // fix mockFS +console = new Console(process.stdout, process.stderr); // fix mockFS describe("create clusters", () => { beforeEach(() => { - jest.clearAllMocks() - }) + jest.clearAllMocks(); + }); - let c: Cluster + let c: Cluster; beforeEach(() => { const mockOpts = { @@ -74,68 +74,68 @@ describe("create clusters", () => { kind: "Config", preferences: {}, }) - } - mockFs(mockOpts) - jest.spyOn(Kubectl.prototype, "ensureKubectl").mockReturnValue(Promise.resolve(true)) + }; + mockFs(mockOpts); + jest.spyOn(Kubectl.prototype, "ensureKubectl").mockReturnValue(Promise.resolve(true)); c = new Cluster({ id: "foo", contextName: "minikube", kubeConfigPath: "minikube-config.yml", workspace: workspaceStore.currentWorkspaceId - }) - }) + }); + }); afterEach(() => { - mockFs.restore() - }) + mockFs.restore(); + }); it("should be able to create a cluster from a cluster model and apiURL should be decoded", () => { - expect(c.apiUrl).toBe("https://192.168.64.3:8443") - }) + expect(c.apiUrl).toBe("https://192.168.64.3:8443"); + }); it("reconnect should not throw if contextHandler is missing", () => { - expect(() => c.reconnect()).not.toThrowError() - }) + expect(() => c.reconnect()).not.toThrowError(); + }); it("disconnect should not throw if contextHandler is missing", () => { - expect(() => c.disconnect()).not.toThrowError() - }) + expect(() => c.disconnect()).not.toThrowError(); + }); it("init should not throw if everything is in order", async () => { - await c.init(await getFreePort()) + await c.init(await getFreePort()); expect(logger.info).toBeCalledWith(expect.stringContaining("init success"), { id: "foo", apiUrl: "https://192.168.64.3:8443", context: "minikube", - }) - }) + }); + }); it("activating cluster should try to connect to cluster and do a refresh", async () => { - const port = await getFreePort() + const port = await getFreePort(); jest.spyOn(ContextHandler.prototype, "ensureServer"); - const mockListNSs = jest.fn() + const mockListNSs = jest.fn(); const mockKC = { makeApiClient() { return { listNamespace: mockListNSs, - } + }; } - } - jest.spyOn(Cluster.prototype, "isClusterAdmin").mockReturnValue(Promise.resolve(true)) + }; + jest.spyOn(Cluster.prototype, "isClusterAdmin").mockReturnValue(Promise.resolve(true)); jest.spyOn(Cluster.prototype, "canI") .mockImplementationOnce((attr: V1ResourceAttributes): Promise => { - expect(attr.namespace).toBe("default") - expect(attr.resource).toBe("pods") - expect(attr.verb).toBe("list") - return Promise.resolve(true) + expect(attr.namespace).toBe("default"); + expect(attr.resource).toBe("pods"); + expect(attr.verb).toBe("list"); + return Promise.resolve(true); }) .mockImplementation((attr: V1ResourceAttributes): Promise => { - expect(attr.namespace).toBe("default") - expect(attr.verb).toBe("list") - return Promise.resolve(true) - }) - jest.spyOn(Cluster.prototype, "getProxyKubeconfig").mockReturnValue(mockKC as any) + expect(attr.namespace).toBe("default"); + expect(attr.verb).toBe("list"); + return Promise.resolve(true); + }); + jest.spyOn(Cluster.prototype, "getProxyKubeconfig").mockReturnValue(mockKC as any); mockListNSs.mockImplementationOnce(() => ({ body: { items: [{ @@ -144,36 +144,36 @@ describe("create clusters", () => { } }] } - })) + })); mockedRequest.mockImplementationOnce(((uri: any, _options: any) => { - expect(uri).toBe(`http://localhost:${port}/api-kube/version`) - return Promise.resolve({ gitVersion: "1.2.3" }) - }) as any) + expect(uri).toBe(`http://localhost:${port}/api-kube/version`); + return Promise.resolve({ gitVersion: "1.2.3" }); + }) as any); const c = new class extends Cluster { // only way to mock protected methods, without these we leak promises protected bindEvents() { - return + return; } protected async ensureKubectl() { - return Promise.resolve(true) + return Promise.resolve(true); } }({ id: "foo", contextName: "minikube", kubeConfigPath: "minikube-config.yml", workspace: workspaceStore.currentWorkspaceId - }) - await c.init(port) - await c.activate() + }); + await c.init(port); + await c.activate(); - expect(ContextHandler.prototype.ensureServer).toBeCalled() - expect(mockedRequest).toBeCalled() - expect(c.accessible).toBe(true) - expect(c.allowedNamespaces.length).toBe(1) - expect(c.allowedResources.length).toBe(apiResources.length) - c.disconnect() - jest.resetAllMocks() - }) -}) + expect(ContextHandler.prototype.ensureServer).toBeCalled(); + expect(mockedRequest).toBeCalled(); + expect(c.accessible).toBe(true); + expect(c.allowedNamespaces.length).toBe(1); + expect(c.allowedResources.length).toBe(apiResources.length); + c.disconnect(); + jest.resetAllMocks(); + }); +}); diff --git a/src/main/__test__/kube-auth-proxy.test.ts b/src/main/__test__/kube-auth-proxy.test.ts index 8ef1f058e7..dbb3e308e3 100644 --- a/src/main/__test__/kube-auth-proxy.test.ts +++ b/src/main/__test__/kube-auth-proxy.test.ts @@ -21,109 +21,109 @@ jest.mock("winston", () => ({ Console: jest.fn(), File: jest.fn(), } -})) +})); -jest.mock("../../common/ipc") -jest.mock("child_process") -jest.mock("tcp-port-used") +jest.mock("../../common/ipc"); +jest.mock("child_process"); +jest.mock("tcp-port-used"); -import { Cluster } from "../cluster" -import { KubeAuthProxy } from "../kube-auth-proxy" -import { getFreePort } from "../port" -import { broadcastMessage } from "../../common/ipc" -import { ChildProcess, spawn, SpawnOptions } from "child_process" -import { bundledKubectlPath, Kubectl } from "../kubectl" +import { Cluster } from "../cluster"; +import { KubeAuthProxy } from "../kube-auth-proxy"; +import { getFreePort } from "../port"; +import { broadcastMessage } from "../../common/ipc"; +import { ChildProcess, spawn, SpawnOptions } from "child_process"; +import { bundledKubectlPath, Kubectl } from "../kubectl"; import { mock, MockProxy } from 'jest-mock-extended'; import { waitUntilUsed } from 'tcp-port-used'; -import { Readable } from "stream" +import { Readable } from "stream"; -const mockBroadcastIpc = broadcastMessage as jest.MockedFunction -const mockSpawn = spawn as jest.MockedFunction -const mockWaitUntilUsed = waitUntilUsed as jest.MockedFunction +const mockBroadcastIpc = broadcastMessage as jest.MockedFunction; +const mockSpawn = spawn as jest.MockedFunction; +const mockWaitUntilUsed = waitUntilUsed as jest.MockedFunction; describe("kube auth proxy tests", () => { beforeEach(() => { - jest.clearAllMocks() - }) + jest.clearAllMocks(); + }); it("calling exit multiple times shouldn't throw", async () => { - const port = await getFreePort() - const kap = new KubeAuthProxy(new Cluster({ id: "foobar", kubeConfigPath: "fake-path.yml" }), port, {}) - kap.exit() - kap.exit() - kap.exit() - }) + const port = await getFreePort(); + const kap = new KubeAuthProxy(new Cluster({ id: "foobar", kubeConfigPath: "fake-path.yml" }), port, {}); + kap.exit(); + kap.exit(); + kap.exit(); + }); describe("spawn tests", () => { - let port: number - let mockedCP: MockProxy - let listeners: Record void> - let proxy: KubeAuthProxy + let port: number; + let mockedCP: MockProxy; + let listeners: Record void>; + let proxy: KubeAuthProxy; beforeEach(async () => { - port = await getFreePort() - mockedCP = mock() - listeners = {} + port = await getFreePort(); + mockedCP = mock(); + listeners = {}; - jest.spyOn(Kubectl.prototype, "checkBinary").mockReturnValueOnce(Promise.resolve(true)) - jest.spyOn(Kubectl.prototype, "ensureKubectl").mockReturnValueOnce(Promise.resolve(false)) + jest.spyOn(Kubectl.prototype, "checkBinary").mockReturnValueOnce(Promise.resolve(true)); + jest.spyOn(Kubectl.prototype, "ensureKubectl").mockReturnValueOnce(Promise.resolve(false)); mockedCP.on.mockImplementation((event: string, listener: (message: any, sendHandle: any) => void): ChildProcess => { - listeners[event] = listener - return mockedCP - }) - mockedCP.stderr = mock() + listeners[event] = listener; + return mockedCP; + }); + mockedCP.stderr = mock(); mockedCP.stderr.on.mockImplementation((event: string, listener: (message: any, sendHandle: any) => void): Readable => { - listeners[`stderr/${event}`] = listener - return mockedCP.stderr - }) - mockedCP.stdout = mock() + listeners[`stderr/${event}`] = listener; + return mockedCP.stderr; + }); + mockedCP.stdout = mock(); mockedCP.stdout.on.mockImplementation((event: string, listener: (message: any, sendHandle: any) => void): Readable => { - listeners[`stdout/${event}`] = listener - return mockedCP.stdout - }) + listeners[`stdout/${event}`] = listener; + return mockedCP.stdout; + }); mockSpawn.mockImplementationOnce((command: string, args: readonly string[], options: SpawnOptions): ChildProcess => { - expect(command).toBe(bundledKubectlPath()) - return mockedCP - }) - mockWaitUntilUsed.mockReturnValueOnce(Promise.resolve()) - const cluster = new Cluster({ id: "foobar", kubeConfigPath: "fake-path.yml" }) - jest.spyOn(cluster, "apiUrl", "get").mockReturnValue("https://fake.k8s.internal") - proxy = new KubeAuthProxy(cluster, port, {}) - }) + expect(command).toBe(bundledKubectlPath()); + return mockedCP; + }); + mockWaitUntilUsed.mockReturnValueOnce(Promise.resolve()); + const cluster = new Cluster({ id: "foobar", kubeConfigPath: "fake-path.yml" }); + jest.spyOn(cluster, "apiUrl", "get").mockReturnValue("https://fake.k8s.internal"); + proxy = new KubeAuthProxy(cluster, port, {}); + }); it("should call spawn and broadcast errors", async () => { - await proxy.run() - listeners["error"]({ message: "foobarbat" }) + await proxy.run(); + listeners["error"]({ message: "foobarbat" }); - expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "foobarbat", error: true }) - }) + expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "foobarbat", error: true }); + }); it("should call spawn and broadcast exit", async () => { - await proxy.run() - listeners["exit"](0) + await proxy.run(); + listeners["exit"](0); - expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "proxy exited with code: 0", error: false }) - }) + expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "proxy exited with code: 0", error: false }); + }); it("should call spawn and broadcast errors from stderr", async () => { - await proxy.run() - listeners["stderr/data"]("an error") + await proxy.run(); + listeners["stderr/data"]("an error"); - expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "an error", error: true }) - }) + expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "an error", error: true }); + }); it("should call spawn and broadcast stdout serving info", async () => { - await proxy.run() - listeners["stdout/data"]("Starting to serve on") + await proxy.run(); + listeners["stdout/data"]("Starting to serve on"); - expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "Authentication proxy started\n" }) - }) + expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "Authentication proxy started\n" }); + }); it("should call spawn and broadcast stdout other info", async () => { - await proxy.run() - listeners["stdout/data"]("some info") + await proxy.run(); + listeners["stdout/data"]("some info"); - expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "some info" }) - }) - }) -}) + expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "some info" }); + }); + }); +}); diff --git a/src/main/__test__/kubeconfig-manager.test.ts b/src/main/__test__/kubeconfig-manager.test.ts index a0a4060111..152a13055d 100644 --- a/src/main/__test__/kubeconfig-manager.test.ts +++ b/src/main/__test__/kubeconfig-manager.test.ts @@ -21,24 +21,24 @@ jest.mock("winston", () => ({ Console: jest.fn(), File: jest.fn(), } -})) +})); -import { KubeconfigManager } from "../kubeconfig-manager" -import mockFs from "mock-fs" +import { KubeconfigManager } from "../kubeconfig-manager"; +import mockFs from "mock-fs"; import { Cluster } from "../cluster"; import { workspaceStore } from "../../common/workspace-store"; import { ContextHandler } from "../context-handler"; import { getFreePort } from "../port"; -import fse from "fs-extra" +import fse from "fs-extra"; import { loadYaml } from "@kubernetes/client-node"; import { Console } from "console"; -console = new Console(process.stdout, process.stderr) // fix mockFS +console = new Console(process.stdout, process.stderr); // fix mockFS describe("kubeconfig manager tests", () => { beforeEach(() => { - jest.clearAllMocks() - }) + jest.clearAllMocks(); + }); beforeEach(() => { const mockOpts = { @@ -63,13 +63,13 @@ describe("kubeconfig manager tests", () => { kind: "Config", preferences: {}, }) - } - mockFs(mockOpts) - }) + }; + mockFs(mockOpts); + }); afterEach(() => { - mockFs.restore() - }) + mockFs.restore(); + }); it("should create 'temp' kube config with proxy", async () => { const cluster = new Cluster({ @@ -77,19 +77,19 @@ describe("kubeconfig manager tests", () => { contextName: "minikube", kubeConfigPath: "minikube-config.yml", workspace: workspaceStore.currentWorkspaceId - }) - const contextHandler = new ContextHandler(cluster) - const port = await getFreePort() - const kubeConfManager = await KubeconfigManager.create(cluster, contextHandler, port) + }); + const contextHandler = new ContextHandler(cluster); + const port = await getFreePort(); + const kubeConfManager = await KubeconfigManager.create(cluster, contextHandler, port); - expect(logger.error).not.toBeCalled() - expect(kubeConfManager.getPath()).toBe("tmp/kubeconfig-foo") - const file = await fse.readFile(kubeConfManager.getPath()) - const yml = loadYaml(file.toString()) - expect(yml["current-context"]).toBe("minikube") - expect(yml["clusters"][0]["cluster"]["server"]).toBe(`http://127.0.0.1:${port}/foo`) - expect(yml["users"][0]["name"]).toBe("proxy") - }) + expect(logger.error).not.toBeCalled(); + expect(kubeConfManager.getPath()).toBe("tmp/kubeconfig-foo"); + const file = await fse.readFile(kubeConfManager.getPath()); + const yml = loadYaml(file.toString()); + expect(yml["current-context"]).toBe("minikube"); + expect(yml["clusters"][0]["cluster"]["server"]).toBe(`http://127.0.0.1:${port}/foo`); + expect(yml["users"][0]["name"]).toBe("proxy"); + }); it("should remove 'temp' kube config on unlink and remove reference from inside class", async () => { const cluster = new Cluster({ @@ -97,16 +97,16 @@ describe("kubeconfig manager tests", () => { contextName: "minikube", kubeConfigPath: "minikube-config.yml", workspace: workspaceStore.currentWorkspaceId - }) - const contextHandler = new ContextHandler(cluster) - const port = await getFreePort() - const kubeConfManager = await KubeconfigManager.create(cluster, contextHandler, port) + }); + const contextHandler = new ContextHandler(cluster); + const port = await getFreePort(); + const kubeConfManager = await KubeconfigManager.create(cluster, contextHandler, port); - const configPath = kubeConfManager.getPath() - expect(await fse.pathExists(configPath)).toBe(true) - await kubeConfManager.unlink() - expect(await fse.pathExists(configPath)).toBe(false) - await kubeConfManager.unlink() // doesn't throw - expect(kubeConfManager.getPath()).toBeUndefined() - }) -}) + const configPath = kubeConfManager.getPath(); + expect(await fse.pathExists(configPath)).toBe(true); + await kubeConfManager.unlink(); + expect(await fse.pathExists(configPath)).toBe(false); + await kubeConfManager.unlink(); // doesn't throw + expect(kubeConfManager.getPath()).toBeUndefined(); + }); +}); diff --git a/src/main/app-updater.ts b/src/main/app-updater.ts index 3613c3ef18..c7b6659149 100644 --- a/src/main/app-updater.ts +++ b/src/main/app-updater.ts @@ -1,19 +1,19 @@ -import { autoUpdater } from "electron-updater" -import logger from "./logger" +import { autoUpdater } from "electron-updater"; +import logger from "./logger"; export class AppUpdater { - static readonly defaultUpdateIntervalMs = 1000 * 60 * 60 * 24 // once a day + static readonly defaultUpdateIntervalMs = 1000 * 60 * 60 * 24; // once a day static checkForUpdates() { - return autoUpdater.checkForUpdatesAndNotify() + return autoUpdater.checkForUpdatesAndNotify(); } constructor(protected updateInterval = AppUpdater.defaultUpdateIntervalMs) { - autoUpdater.logger = logger + autoUpdater.logger = logger; } public start() { - setInterval(AppUpdater.checkForUpdates, this.updateInterval) + setInterval(AppUpdater.checkForUpdates, this.updateInterval); return AppUpdater.checkForUpdates(); } } diff --git a/src/main/cluster-detectors/base-cluster-detector.ts b/src/main/cluster-detectors/base-cluster-detector.ts index 8663313005..f73cc2ac81 100644 --- a/src/main/cluster-detectors/base-cluster-detector.ts +++ b/src/main/cluster-detectors/base-cluster-detector.ts @@ -1,21 +1,21 @@ -import request, { RequestPromiseOptions } from "request-promise-native" +import request, { RequestPromiseOptions } from "request-promise-native"; import { Cluster } from "../cluster"; export type ClusterDetectionResult = { value: string | number | boolean accuracy: number -} +}; export class BaseClusterDetector { - cluster: Cluster - key: string + cluster: Cluster; + key: string; constructor(cluster: Cluster) { - this.cluster = cluster + this.cluster = cluster; } detect(): Promise { - return null + return null; } protected async k8sRequest(path: string, options: RequestPromiseOptions = {}): Promise { @@ -28,6 +28,6 @@ export class BaseClusterDetector { Host: `${this.cluster.id}.${new URL(this.cluster.kubeProxyUrl).host}`, // required in ClusterManager.getClusterForRequest() ...(options.headers || {}), }, - }) + }); } } \ No newline at end of file diff --git a/src/main/cluster-detectors/cluster-id-detector.ts b/src/main/cluster-detectors/cluster-id-detector.ts index 558e52d43c..8419ae9db4 100644 --- a/src/main/cluster-detectors/cluster-id-detector.ts +++ b/src/main/cluster-detectors/cluster-id-detector.ts @@ -1,23 +1,23 @@ import { BaseClusterDetector } from "./base-cluster-detector"; -import { createHash } from "crypto" +import { createHash } from "crypto"; import { ClusterMetadataKey } from "../cluster"; export class ClusterIdDetector extends BaseClusterDetector { - key = ClusterMetadataKey.CLUSTER_ID + key = ClusterMetadataKey.CLUSTER_ID; public async detect() { - let id: string + let id: string; try { - id = await this.getDefaultNamespaceId() + id = await this.getDefaultNamespaceId(); } catch(_) { - id = this.cluster.apiUrl + id = this.cluster.apiUrl; } - const value = createHash("sha256").update(id).digest("hex") - return { value: value, accuracy: 100 } + const value = createHash("sha256").update(id).digest("hex"); + return { value: value, accuracy: 100 }; } protected async getDefaultNamespaceId() { - const response = await this.k8sRequest("/api/v1/namespaces/default") - return response.metadata.uid + const response = await this.k8sRequest("/api/v1/namespaces/default"); + return response.metadata.uid; } } \ No newline at end of file diff --git a/src/main/cluster-detectors/detector-registry.ts b/src/main/cluster-detectors/detector-registry.ts index 577fdf2d85..d4abe01304 100644 --- a/src/main/cluster-detectors/detector-registry.ts +++ b/src/main/cluster-detectors/detector-registry.ts @@ -12,34 +12,34 @@ export class DetectorRegistry { registry = observable.array([], { deep: false }); add(detectorClass: typeof BaseClusterDetector) { - this.registry.push(detectorClass) + this.registry.push(detectorClass); } async detectForCluster(cluster: Cluster): Promise { - const results: {[key: string]: ClusterDetectionResult } = {} + const results: {[key: string]: ClusterDetectionResult } = {}; for (const detectorClass of this.registry) { - const detector = new detectorClass(cluster) + const detector = new detectorClass(cluster); try { - const data = await detector.detect() + const data = await detector.detect(); if (!data) continue; - const existingValue = results[detector.key] + const existingValue = results[detector.key]; if (existingValue && existingValue.accuracy > data.accuracy) continue; // previous value exists and is more accurate - results[detector.key] = data + results[detector.key] = data; } catch (e) { // detector raised error, do nothing } } - const metadata: ClusterMetadata = {} + const metadata: ClusterMetadata = {}; for (const [key, result] of Object.entries(results)) { - metadata[key] = result.value + metadata[key] = result.value; } - return metadata + return metadata; } } -export const detectorRegistry = new DetectorRegistry() -detectorRegistry.add(ClusterIdDetector) -detectorRegistry.add(LastSeenDetector) -detectorRegistry.add(VersionDetector) -detectorRegistry.add(DistributionDetector) -detectorRegistry.add(NodesCountDetector) \ No newline at end of file +export const detectorRegistry = new DetectorRegistry(); +detectorRegistry.add(ClusterIdDetector); +detectorRegistry.add(LastSeenDetector); +detectorRegistry.add(VersionDetector); +detectorRegistry.add(DistributionDetector); +detectorRegistry.add(NodesCountDetector); \ No newline at end of file diff --git a/src/main/cluster-detectors/distribution-detector.ts b/src/main/cluster-detectors/distribution-detector.ts index b5895f8a71..181425cb26 100644 --- a/src/main/cluster-detectors/distribution-detector.ts +++ b/src/main/cluster-detectors/distribution-detector.ts @@ -2,79 +2,79 @@ import { BaseClusterDetector } from "./base-cluster-detector"; import { ClusterMetadataKey } from "../cluster"; export class DistributionDetector extends BaseClusterDetector { - key = ClusterMetadataKey.DISTRIBUTION - version: string + key = ClusterMetadataKey.DISTRIBUTION; + version: string; public async detect() { - this.version = await this.getKubernetesVersion() + this.version = await this.getKubernetesVersion(); if (await this.isRancher()) { - return { value: "rancher", accuracy: 80} + return { value: "rancher", accuracy: 80}; } if (this.isGKE()) { - return { value: "gke", accuracy: 80} + return { value: "gke", accuracy: 80}; } if (this.isEKS()) { - return { value: "eks", accuracy: 80} + return { value: "eks", accuracy: 80}; } if (this.isIKS()) { - return { value: "iks", accuracy: 80} + return { value: "iks", accuracy: 80}; } if (this.isAKS()) { - return { value: "aks", accuracy: 80} + return { value: "aks", accuracy: 80}; } if (this.isDigitalOcean()) { - return { value: "digitalocean", accuracy: 90} + return { value: "digitalocean", accuracy: 90}; } if (this.isMinikube()) { - return { value: "minikube", accuracy: 80} + return { value: "minikube", accuracy: 80}; } if (this.isCustom()) { - return { value: "custom", accuracy: 10} + return { value: "custom", accuracy: 10}; } - return { value: "unknown", accuracy: 10} + return { value: "unknown", accuracy: 10}; } public async getKubernetesVersion() { - if (this.cluster.version) return this.cluster.version + if (this.cluster.version) return this.cluster.version; - const response = await this.k8sRequest("/version") - return response.gitVersion + const response = await this.k8sRequest("/version"); + return response.gitVersion; } protected isGKE() { - return this.version.includes("gke") + return this.version.includes("gke"); } protected isEKS() { - return this.version.includes("eks") + return this.version.includes("eks"); } protected isIKS() { - return this.version.includes("IKS") + return this.version.includes("IKS"); } protected isAKS() { - return this.cluster.apiUrl.endsWith("azmk8s.io") + return this.cluster.apiUrl.endsWith("azmk8s.io"); } protected isDigitalOcean() { - return this.cluster.apiUrl.endsWith("k8s.ondigitalocean.com") + return this.cluster.apiUrl.endsWith("k8s.ondigitalocean.com"); } protected isMinikube() { - return this.cluster.contextName.startsWith("minikube") + return this.cluster.contextName.startsWith("minikube"); } protected isCustom() { - return this.version.includes("+") + return this.version.includes("+"); } protected async isRancher() { try { - const response = await this.k8sRequest("") - return response.data.find((api: any) => api?.apiVersion?.group === "meta.cattle.io") !== undefined + const response = await this.k8sRequest(""); + return response.data.find((api: any) => api?.apiVersion?.group === "meta.cattle.io") !== undefined; } catch (e) { - return false + return false; } } } \ No newline at end of file diff --git a/src/main/cluster-detectors/last-seen-detector.ts b/src/main/cluster-detectors/last-seen-detector.ts index 0c231116fe..d56483625a 100644 --- a/src/main/cluster-detectors/last-seen-detector.ts +++ b/src/main/cluster-detectors/last-seen-detector.ts @@ -2,12 +2,12 @@ import { BaseClusterDetector } from "./base-cluster-detector"; import { ClusterMetadataKey } from "../cluster"; export class LastSeenDetector extends BaseClusterDetector { - key = ClusterMetadataKey.LAST_SEEN + key = ClusterMetadataKey.LAST_SEEN; public async detect() { if (!this.cluster.accessible) return null; - await this.k8sRequest("/version") - return { value: new Date().toJSON(), accuracy: 100 } + await this.k8sRequest("/version"); + return { value: new Date().toJSON(), accuracy: 100 }; } } \ No newline at end of file diff --git a/src/main/cluster-detectors/nodes-count-detector.ts b/src/main/cluster-detectors/nodes-count-detector.ts index 858ff43d9f..ba5fc93583 100644 --- a/src/main/cluster-detectors/nodes-count-detector.ts +++ b/src/main/cluster-detectors/nodes-count-detector.ts @@ -2,16 +2,16 @@ import { BaseClusterDetector } from "./base-cluster-detector"; import { ClusterMetadataKey } from "../cluster"; export class NodesCountDetector extends BaseClusterDetector { - key = ClusterMetadataKey.NODES_COUNT + key = ClusterMetadataKey.NODES_COUNT; public async detect() { if (!this.cluster.accessible) return null; - const nodeCount = await this.getNodeCount() - return { value: nodeCount, accuracy: 100} + const nodeCount = await this.getNodeCount(); + return { value: nodeCount, accuracy: 100}; } protected async getNodeCount(): Promise { - const response = await this.k8sRequest("/api/v1/nodes") - return response.items.length + const response = await this.k8sRequest("/api/v1/nodes"); + return response.items.length; } } \ No newline at end of file diff --git a/src/main/cluster-detectors/version-detector.ts b/src/main/cluster-detectors/version-detector.ts index 4092b40b42..e59e6291b9 100644 --- a/src/main/cluster-detectors/version-detector.ts +++ b/src/main/cluster-detectors/version-detector.ts @@ -2,16 +2,16 @@ import { BaseClusterDetector } from "./base-cluster-detector"; import { ClusterMetadataKey } from "../cluster"; export class VersionDetector extends BaseClusterDetector { - key = ClusterMetadataKey.VERSION - value: string + key = ClusterMetadataKey.VERSION; + value: string; public async detect() { - const version = await this.getKubernetesVersion() - return { value: version, accuracy: 100} + const version = await this.getKubernetesVersion(); + return { value: version, accuracy: 100}; } public async getKubernetesVersion() { - const response = await this.k8sRequest("/version") - return response.gitVersion + const response = await this.k8sRequest("/version"); + return response.gitVersion; } } \ No newline at end of file diff --git a/src/main/cluster-manager.ts b/src/main/cluster-manager.ts index 1a479e724e..9b2e88ef89 100644 --- a/src/main/cluster-manager.ts +++ b/src/main/cluster-manager.ts @@ -1,16 +1,16 @@ import "../common/cluster-ipc"; -import type http from "http" -import { ipcMain } from "electron" +import type http from "http"; +import { ipcMain } from "electron"; import { autorun } from "mobx"; -import { clusterStore, getClusterIdFromHost } from "../common/cluster-store" -import { Cluster } from "./cluster" +import { clusterStore, getClusterIdFromHost } from "../common/cluster-store"; +import { Cluster } from "./cluster"; import logger from "./logger"; import { apiKubePrefix } from "../common/vars"; import { Singleton } from "../common/utils"; export class ClusterManager extends Singleton { constructor(public readonly port: number) { - super() + super(); // auto-init clusters autorun(() => { clusterStore.enabledClustersList.forEach(cluster => { @@ -34,52 +34,52 @@ export class ClusterManager extends Singleton { delay: 250 }); - ipcMain.on("network:offline", () => { this.onNetworkOffline() }) - ipcMain.on("network:online", () => { this.onNetworkOnline() }) + ipcMain.on("network:offline", () => { this.onNetworkOffline(); }); + ipcMain.on("network:online", () => { this.onNetworkOnline(); }); } protected onNetworkOffline() { - logger.info("[CLUSTER-MANAGER]: network is offline") + logger.info("[CLUSTER-MANAGER]: network is offline"); clusterStore.enabledClustersList.forEach((cluster) => { if (!cluster.disconnected) { - cluster.online = false - cluster.accessible = false - cluster.refreshConnectionStatus().catch((e) => e) + cluster.online = false; + cluster.accessible = false; + cluster.refreshConnectionStatus().catch((e) => e); } - }) + }); } protected onNetworkOnline() { - logger.info("[CLUSTER-MANAGER]: network is online") + logger.info("[CLUSTER-MANAGER]: network is online"); clusterStore.enabledClustersList.forEach((cluster) => { if (!cluster.disconnected) { - cluster.refreshConnectionStatus().catch((e) => e) + cluster.refreshConnectionStatus().catch((e) => e); } - }) + }); } stop() { clusterStore.clusters.forEach((cluster: Cluster) => { cluster.disconnect(); - }) + }); } getClusterForRequest(req: http.IncomingMessage): Cluster { - let cluster: Cluster = null + let cluster: Cluster = null; // lens-server is connecting to 127.0.0.1:/ if (req.headers.host.startsWith("127.0.0.1")) { - const clusterId = req.url.split("/")[1] - cluster = clusterStore.getById(clusterId) + const clusterId = req.url.split("/")[1]; + cluster = clusterStore.getById(clusterId); if (cluster) { // we need to swap path prefix so that request is proxied to kube api - req.url = req.url.replace(`/${clusterId}`, apiKubePrefix) + req.url = req.url.replace(`/${clusterId}`, apiKubePrefix); } } else if (req.headers["x-cluster-id"]) { - cluster = clusterStore.getById(req.headers["x-cluster-id"].toString()) + cluster = clusterStore.getById(req.headers["x-cluster-id"].toString()); } else { const clusterId = getClusterIdFromHost(req.headers.host); - cluster = clusterStore.getById(clusterId) + cluster = clusterStore.getById(clusterId); } return cluster; diff --git a/src/main/cluster.ts b/src/main/cluster.ts index a2b71a865b..e2831e8c3f 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -1,18 +1,18 @@ -import { ipcMain } from "electron" -import type { ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences } from "../common/cluster-store" +import { ipcMain } from "electron"; +import type { ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences } from "../common/cluster-store"; import type { IMetricsReqParams } from "../renderer/api/endpoints/metrics.api"; import type { WorkspaceId } from "../common/workspace-store"; import { action, computed, observable, reaction, toJS, when } from "mobx"; import { apiKubePrefix } from "../common/vars"; import { broadcastMessage } from "../common/ipc"; -import { ContextHandler } from "./context-handler" -import { AuthorizationV1Api, CoreV1Api, KubeConfig, V1ResourceAttributes } from "@kubernetes/client-node" +import { ContextHandler } from "./context-handler"; +import { AuthorizationV1Api, CoreV1Api, KubeConfig, V1ResourceAttributes } from "@kubernetes/client-node"; import { Kubectl } from "./kubectl"; -import { KubeconfigManager } from "./kubeconfig-manager" -import { getNodeWarningConditions, loadConfig, podHasIssues } from "../common/kube-helpers" -import request, { RequestPromiseOptions } from "request-promise-native" +import { KubeconfigManager } from "./kubeconfig-manager"; +import { getNodeWarningConditions, loadConfig, podHasIssues } from "../common/kube-helpers"; +import request, { RequestPromiseOptions } from "request-promise-native"; import { apiResources } from "../common/rbac"; -import logger from "./logger" +import logger from "./logger"; import { VersionDetector } from "./cluster-detectors/version-detector"; import { detectorRegistry } from "./cluster-detectors/detector-registry"; @@ -32,7 +32,7 @@ export enum ClusterMetadataKey { export type ClusterRefreshOptions = { refreshMetadata?: boolean -} +}; export interface ClusterState { initialized: boolean; @@ -50,7 +50,7 @@ export interface ClusterState { export class Cluster implements ClusterModel, ClusterState { public id: ClusterId; - public kubeCtl: Kubectl + public kubeCtl: Kubectl; public contextHandler: ContextHandler; public ownerRef: string; protected kubeconfigManager: KubeconfigManager; @@ -86,23 +86,23 @@ export class Cluster implements ClusterModel, ClusterState { } @computed get name() { - return this.preferences.clusterName || this.contextName + return this.preferences.clusterName || this.contextName; } get version(): string { - return String(this.metadata?.version) || "" + return String(this.metadata?.version) || ""; } constructor(model: ClusterModel) { this.updateModel(model); - const kubeconfig = this.getKubeconfig() + const kubeconfig = this.getKubeconfig(); if (kubeconfig.getContextObject(this.contextName)) { - this.apiUrl = kubeconfig.getCluster(kubeconfig.getContextObject(this.contextName).cluster).server + this.apiUrl = kubeconfig.getCluster(kubeconfig.getContextObject(this.contextName).cluster).server; } } get isManaged(): boolean { - return !!this.ownerRef + return !!this.ownerRef; } @action @@ -131,16 +131,16 @@ export class Cluster implements ClusterModel, ClusterState { } protected bindEvents() { - logger.info(`[CLUSTER]: bind events`, this.getMeta()) - const refreshTimer = setInterval(() => !this.disconnected && this.refresh(), 30000) // every 30s - const refreshMetadataTimer = setInterval(() => !this.disconnected && this.refreshMetadata(), 900000) // every 15 minutes + logger.info(`[CLUSTER]: bind events`, this.getMeta()); + const refreshTimer = setInterval(() => !this.disconnected && this.refresh(), 30000); // every 30s + const refreshMetadataTimer = setInterval(() => !this.disconnected && this.refreshMetadata(), 900000); // every 15 minutes if (ipcMain) { this.eventDisposers.push( reaction(() => this.getState(), () => this.pushState()), () => { - clearInterval(refreshTimer) - clearInterval(refreshMetadataTimer) + clearInterval(refreshTimer); + clearInterval(refreshMetadataTimer); }, ); } @@ -165,20 +165,20 @@ export class Cluster implements ClusterModel, ClusterState { if (this.disconnected || !this.accessible) { await this.reconnect(); } - await this.refreshConnectionStatus() + await this.refreshConnectionStatus(); if (this.accessible) { - await this.refreshAllowedResources() - this.isAdmin = await this.isClusterAdmin() - this.ready = true - this.ensureKubectl() + await this.refreshAllowedResources(); + this.isAdmin = await this.isClusterAdmin(); + this.ready = true; + this.ensureKubectl(); } - this.activated = true + this.activated = true; return this.pushState(); } protected async ensureKubectl() { - this.kubeCtl = new Kubectl(this.version) - return this.kubeCtl.ensureKubectl() // download kubectl in background, so it's not blocking dashboard + this.kubeCtl = new Kubectl(this.version); + return this.kubeCtl.ensureKubectl(); // download kubectl in background, so it's not blocking dashboard } @action @@ -214,9 +214,9 @@ export class Cluster implements ClusterModel, ClusterState { this.refreshAllowedResources(), ]); if (opts.refreshMetadata) { - this.refreshMetadata() + this.refreshMetadata(); } - this.ready = true + this.ready = true; } this.pushState(); } @@ -224,9 +224,9 @@ export class Cluster implements ClusterModel, ClusterState { @action async refreshMetadata() { logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta()); - const metadata = await detectorRegistry.detectForCluster(this) - const existingMetadata = this.metadata - this.metadata = Object.assign(existingMetadata, metadata) + const metadata = await detectorRegistry.detectForCluster(this); + const existingMetadata = this.metadata; + this.metadata = Object.assign(existingMetadata, metadata); } @action @@ -256,16 +256,16 @@ export class Cluster implements ClusterModel, ClusterState { } getProxyKubeconfigPath(): string { - return this.kubeconfigManager.getPath() + return this.kubeconfigManager.getPath(); } protected async k8sRequest(path: string, options: RequestPromiseOptions = {}): Promise { - options.headers ??= {} - options.json ??= true - options.timeout ??= 30000 - options.headers.Host = `${this.id}.${new URL(this.kubeProxyUrl).host}` // required in ClusterManager.getClusterForRequest() + options.headers ??= {}; + options.json ??= true; + options.timeout ??= 30000; + options.headers.Host = `${this.id}.${new URL(this.kubeProxyUrl).host}`; // required in ClusterManager.getClusterForRequest() - return request(this.kubeProxyUrl + path, options) + return request(this.kubeProxyUrl + path, options); } getMetrics(prometheusPath: string, queryParams: IMetricsReqParams & { query: string }) { @@ -276,17 +276,17 @@ export class Cluster implements ClusterModel, ClusterState { resolveWithFullResponse: false, json: true, qs: queryParams, - }) + }); } protected async getConnectionStatus(): Promise { try { - const versionDetector = new VersionDetector(this) - const versionData = await versionDetector.detect() - this.metadata.version = versionData.value + const versionDetector = new VersionDetector(this); + const versionData = await versionDetector.detect(); + this.metadata.version = versionData.value; return ClusterStatus.AccessGranted; } catch (error) { - logger.error(`Failed to connect cluster "${this.contextName}": ${error}`) + logger.error(`Failed to connect cluster "${this.contextName}": ${error}`); if (error.statusCode) { if (error.statusCode >= 400 && error.statusCode < 500) { this.failureReason = "Invalid credentials"; @@ -310,17 +310,17 @@ export class Cluster implements ClusterModel, ClusterState { } async canI(resourceAttributes: V1ResourceAttributes): Promise { - const authApi = this.getProxyKubeconfig().makeApiClient(AuthorizationV1Api) + const authApi = this.getProxyKubeconfig().makeApiClient(AuthorizationV1Api); try { const accessReview = await authApi.createSelfSubjectAccessReview({ apiVersion: "authorization.k8s.io/v1", kind: "SelfSubjectAccessReview", spec: { resourceAttributes } - }) - return accessReview.body.status.allowed + }); + return accessReview.body.status.allowed; } catch (error) { - logger.error(`failed to request selfSubjectAccessReview: ${error}`) - return false + logger.error(`failed to request selfSubjectAccessReview: ${error}`); + return false; } } @@ -329,7 +329,7 @@ export class Cluster implements ClusterModel, ClusterState { namespace: "kube-system", resource: "*", verb: "create", - }) + }); } protected async getEventCount(): Promise { @@ -345,7 +345,7 @@ export class Cluster implements ClusterModel, ClusterState { if (w.involvedObject.kind === 'Pod') { try { const { body: pod } = await client.readNamespacedPod(w.involvedObject.name, w.involvedObject.namespace); - logger.debug(`checking pod ${w.involvedObject.namespace}/${w.involvedObject.name}`) + logger.debug(`checking pod ${w.involvedObject.namespace}/${w.involvedObject.name}`); if (podHasIssues(pod)) { uniqEventSources.add(w.involvedObject.uid); } @@ -361,7 +361,7 @@ export class Cluster implements ClusterModel, ClusterState { .reduce((sum, conditions) => sum + conditions.length, 0); return uniqEventSources.size + nodeNotificationCount; } catch (error) { - logger.error("Failed to fetch event count: " + JSON.stringify(error)) + logger.error("Failed to fetch event count: " + JSON.stringify(error)); return 0; } } @@ -379,7 +379,7 @@ export class Cluster implements ClusterModel, ClusterState { }; return toJS(model, { recurseEverything: true - }) + }); } // serializable cluster-state used for sync btw main <-> renderer @@ -399,17 +399,17 @@ export class Cluster implements ClusterModel, ClusterState { }; return toJS(state, { recurseEverything: true - }) + }); } @action setState(state: ClusterState) { - Object.assign(this, state) + Object.assign(this, state); } pushState(state = this.getState()) { logger.silly(`[CLUSTER]: push-state`, state); - broadcastMessage("cluster:state", this.id, state) + broadcastMessage("cluster:state", this.id, state); } // get cluster system meta, e.g. use in "logger" @@ -422,30 +422,30 @@ export class Cluster implements ClusterModel, ClusterState { online: this.online, accessible: this.accessible, disconnected: this.disconnected, - } + }; } protected async getAllowedNamespaces() { if (this.accessibleNamespaces.length) { - return this.accessibleNamespaces + return this.accessibleNamespaces; } - const api = this.getProxyKubeconfig().makeApiClient(CoreV1Api) + const api = this.getProxyKubeconfig().makeApiClient(CoreV1Api); try { - const namespaceList = await api.listNamespace() + const namespaceList = await api.listNamespace(); const nsAccessStatuses = await Promise.all( namespaceList.body.items.map(ns => this.canI({ namespace: ns.metadata.name, resource: "pods", verb: "list", })) - ) + ); return namespaceList.body.items .filter((ns, i) => nsAccessStatuses[i]) - .map(ns => ns.metadata.name) + .map(ns => ns.metadata.name); } catch (error) { - const ctx = this.getProxyKubeconfig().getContextObject(this.contextName) - if (ctx.namespace) return [ctx.namespace] + const ctx = this.getProxyKubeconfig().getContextObject(this.contextName); + if (ctx.namespace) return [ctx.namespace]; return []; } } @@ -462,12 +462,12 @@ export class Cluster implements ClusterModel, ClusterState { verb: "list", namespace: this.allowedNamespaces[0] })) - ) + ); return apiResources .filter((resource, i) => resourceAccessStatuses[i]) - .map(apiResource => apiResource.resource) + .map(apiResource => apiResource.resource); } catch (error) { - return [] + return []; } } } diff --git a/src/main/context-handler.ts b/src/main/context-handler.ts index a3cf6185dd..10f84ced6d 100644 --- a/src/main/context-handler.ts +++ b/src/main/context-handler.ts @@ -1,21 +1,21 @@ -import type { PrometheusProvider, PrometheusService } from "./prometheus/provider-registry" +import type { PrometheusProvider, PrometheusService } from "./prometheus/provider-registry"; import type { ClusterPreferences } from "../common/cluster-store"; -import type { Cluster } from "./cluster" -import type httpProxy from "http-proxy" +import type { Cluster } from "./cluster"; +import type httpProxy from "http-proxy"; import url, { UrlWithStringQuery } from "url"; -import { CoreV1Api } from "@kubernetes/client-node" -import { prometheusProviders } from "../common/prometheus-providers" -import logger from "./logger" -import { getFreePort } from "./port" -import { KubeAuthProxy } from "./kube-auth-proxy" +import { CoreV1Api } from "@kubernetes/client-node"; +import { prometheusProviders } from "../common/prometheus-providers"; +import logger from "./logger"; +import { getFreePort } from "./port"; +import { KubeAuthProxy } from "./kube-auth-proxy"; export class ContextHandler { public proxyPort: number; public clusterUrl: UrlWithStringQuery; - protected kubeAuthProxy: KubeAuthProxy - protected apiTarget: httpProxy.ServerOptions - protected prometheusProvider: string - protected prometheusPath: string + protected kubeAuthProxy: KubeAuthProxy; + protected apiTarget: httpProxy.ServerOptions; + protected prometheusProvider: string; + protected prometheusPath: string; constructor(protected cluster: Cluster) { this.clusterUrl = url.parse(cluster.apiUrl); @@ -26,64 +26,64 @@ export class ContextHandler { this.prometheusProvider = preferences.prometheusProvider?.type; this.prometheusPath = null; if (preferences.prometheus) { - const { namespace, service, port } = preferences.prometheus - this.prometheusPath = `${namespace}/services/${service}:${port}` + const { namespace, service, port } = preferences.prometheus; + this.prometheusPath = `${namespace}/services/${service}:${port}`; } } protected async resolvePrometheusPath(): Promise { - const { service, namespace, port } = await this.getPrometheusService() - return `${namespace}/services/${service}:${port}` + const { service, namespace, port } = await this.getPrometheusService(); + return `${namespace}/services/${service}:${port}`; } async getPrometheusProvider() { if (!this.prometheusProvider) { - const service = await this.getPrometheusService() - logger.info(`using ${service.id} as prometheus provider`) - this.prometheusProvider = service.id + const service = await this.getPrometheusService(); + logger.info(`using ${service.id} as prometheus provider`); + this.prometheusProvider = service.id; } - return prometheusProviders.find(p => p.id === this.prometheusProvider) + return prometheusProviders.find(p => p.id === this.prometheusProvider); } async getPrometheusService(): Promise { const providers = this.prometheusProvider ? prometheusProviders.filter(provider => provider.id == this.prometheusProvider) : prometheusProviders; const prometheusPromises: Promise[] = providers.map(async (provider: PrometheusProvider): Promise => { - const apiClient = this.cluster.getProxyKubeconfig().makeApiClient(CoreV1Api) - return await provider.getPrometheusService(apiClient) - }) - const resolvedPrometheusServices = await Promise.all(prometheusPromises) + const apiClient = this.cluster.getProxyKubeconfig().makeApiClient(CoreV1Api); + return await provider.getPrometheusService(apiClient); + }); + const resolvedPrometheusServices = await Promise.all(prometheusPromises); const service = resolvedPrometheusServices.filter(n => n)[0]; return service || { id: "lens", namespace: "lens-metrics", service: "prometheus", port: 80 - } + }; } async getPrometheusPath(): Promise { if (!this.prometheusPath) { - this.prometheusPath = await this.resolvePrometheusPath() + this.prometheusPath = await this.resolvePrometheusPath(); } return this.prometheusPath; } async resolveAuthProxyUrl() { const proxyPort = await this.ensurePort(); - const path = this.clusterUrl.path !== "/" ? this.clusterUrl.path : "" + const path = this.clusterUrl.path !== "/" ? this.clusterUrl.path : ""; return `http://127.0.0.1:${proxyPort}${path}`; } async getApiTarget(isWatchRequest = false): Promise { if (this.apiTarget && !isWatchRequest) { - return this.apiTarget + return this.apiTarget; } - const timeout = isWatchRequest ? 4 * 60 * 60 * 1000 : 30000 // 4 hours for watch request, 30 seconds for the rest - const apiTarget = await this.newApiTarget(timeout) + const timeout = isWatchRequest ? 4 * 60 * 60 * 1000 : 30000; // 4 hours for watch request, 30 seconds for the rest + const apiTarget = await this.newApiTarget(timeout); if (!isWatchRequest) { - this.apiTarget = apiTarget + this.apiTarget = apiTarget; } - return apiTarget + return apiTarget; } protected async newApiTarget(timeout: number): Promise { @@ -95,36 +95,36 @@ export class ContextHandler { headers: { "Host": this.clusterUrl.hostname, }, - } + }; } async ensurePort(): Promise { if (!this.proxyPort) { this.proxyPort = await getFreePort(); } - return this.proxyPort + return this.proxyPort; } async ensureServer() { if (!this.kubeAuthProxy) { await this.ensurePort(); - const proxyEnv = Object.assign({}, process.env) + const proxyEnv = Object.assign({}, process.env); if (this.cluster.preferences.httpsProxy) { - proxyEnv.HTTPS_PROXY = this.cluster.preferences.httpsProxy + proxyEnv.HTTPS_PROXY = this.cluster.preferences.httpsProxy; } - this.kubeAuthProxy = new KubeAuthProxy(this.cluster, this.proxyPort, proxyEnv) - await this.kubeAuthProxy.run() + this.kubeAuthProxy = new KubeAuthProxy(this.cluster, this.proxyPort, proxyEnv); + await this.kubeAuthProxy.run(); } } stopServer() { if (this.kubeAuthProxy) { - this.kubeAuthProxy.exit() - this.kubeAuthProxy = null + this.kubeAuthProxy.exit(); + this.kubeAuthProxy = null; } } get proxyLastError(): string { - return this.kubeAuthProxy?.lastError || "" + return this.kubeAuthProxy?.lastError || ""; } } diff --git a/src/main/exit-app.ts b/src/main/exit-app.ts index bf73e022f3..b58a6e4dfc 100644 --- a/src/main/exit-app.ts +++ b/src/main/exit-app.ts @@ -6,13 +6,13 @@ import logger from "./logger"; export function exitApp() { - const windowManager = WindowManager.getInstance() - const clusterManager = ClusterManager.getInstance() - appEventBus.emit({ name: "service", action: "close" }) + const windowManager = WindowManager.getInstance(); + const clusterManager = ClusterManager.getInstance(); + appEventBus.emit({ name: "service", action: "close" }); windowManager.hide(); clusterManager.stop(); logger.info('SERVICE:QUIT'); setTimeout(() => { - app.exit() - }, 1000) + app.exit(); + }, 1000); } \ No newline at end of file diff --git a/src/main/helm/helm-chart-manager.ts b/src/main/helm/helm-chart-manager.ts index e42f7a1aaf..42c1a30ed2 100644 --- a/src/main/helm/helm-chart-manager.ts +++ b/src/main/helm/helm-chart-manager.ts @@ -1,74 +1,74 @@ import fs from "fs"; import * as yaml from "js-yaml"; -import { HelmRepo, HelmRepoManager } from "./helm-repo-manager" +import { HelmRepo, HelmRepoManager } from "./helm-repo-manager"; import logger from "../logger"; -import { promiseExec } from "../promise-exec" -import { helmCli } from "./helm-cli" +import { promiseExec } from "../promise-exec"; +import { helmCli } from "./helm-cli"; type CachedYaml = { entries: any; // todo: types -} +}; export class HelmChartManager { - protected cache: any = {} - protected repo: HelmRepo + protected cache: any = {}; + protected repo: HelmRepo; constructor(repo: HelmRepo){ - this.cache = HelmRepoManager.cache - this.repo = repo + this.cache = HelmRepoManager.cache; + this.repo = repo; } public async chart(name: string) { - const charts = await this.charts() - return charts[name] + const charts = await this.charts(); + return charts[name]; } public async charts(): Promise { try { - const cachedYaml = await this.cachedYaml() - return cachedYaml["entries"] + const cachedYaml = await this.cachedYaml(); + return cachedYaml["entries"]; } catch(error) { - logger.error(error) - return [] + logger.error(error); + return []; } } public async getReadme(name: string, version = "") { - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); if(version && version != "") { - const { stdout, stderr} = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr)}) - return stdout + const { stdout, stderr} = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr);}); + return stdout; } else { - const { stdout, stderr} = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr)}) - return stdout + const { stdout, stderr} = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr);}); + return stdout; } } public async getValues(name: string, version = "") { - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); if(version && version != "") { - const { stdout, stderr} = await promiseExec(`"${helm}" show values ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr)}) + const { stdout, stderr} = await promiseExec(`"${helm}" show values ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr);}); - return stdout + return stdout; } else { - const { stdout, stderr} = await promiseExec(`"${helm}" show values ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr)}) + const { stdout, stderr} = await promiseExec(`"${helm}" show values ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr);}); - return stdout + return stdout; } } protected async cachedYaml(): Promise { if (!(this.repo.name in this.cache)) { - const cacheFile = await fs.promises.readFile(this.repo.cacheFilePath, 'utf-8') - const data = yaml.safeLoad(cacheFile) + const cacheFile = await fs.promises.readFile(this.repo.cacheFilePath, 'utf-8'); + const data = yaml.safeLoad(cacheFile); for(const key in data["entries"]) { data["entries"][key].forEach((version: any) => { - version['repo'] = this.repo.name - version['created'] = Date.parse(version.created).toString() - }) + version['repo'] = this.repo.name; + version['created'] = Date.parse(version.created).toString(); + }); } - this.cache[this.repo.name] = Buffer.from(JSON.stringify(data)) + this.cache[this.repo.name] = Buffer.from(JSON.stringify(data)); } - return JSON.parse(this.cache[this.repo.name].toString()) + return JSON.parse(this.cache[this.repo.name].toString()); } } diff --git a/src/main/helm/helm-cli.ts b/src/main/helm/helm-cli.ts index 1484ceacf1..34a3becc33 100644 --- a/src/main/helm/helm-cli.ts +++ b/src/main/helm/helm-cli.ts @@ -1,6 +1,6 @@ -import packageInfo from "../../../package.json" -import path from "path" -import { LensBinary, LensBinaryOpts } from "../lens-binary" +import packageInfo from "../../../package.json"; +import path from "path"; +import { LensBinary, LensBinaryOpts } from "../lens-binary"; import { isProduction } from "../../common/vars"; export class HelmCli extends LensBinary { @@ -11,24 +11,24 @@ export class HelmCli extends LensBinary { baseDir: baseDir, originalBinaryName: "helm", newBinaryName: "helm3" - } - super(opts) + }; + super(opts); } protected getTarName(): string | null { - return `${this.binaryName}-v${this.binaryVersion}-${this.platformName}-${this.arch}.tar.gz` + return `${this.binaryName}-v${this.binaryVersion}-${this.platformName}-${this.arch}.tar.gz`; } protected getUrl() { - return `https://get.helm.sh/helm-v${this.binaryVersion}-${this.platformName}-${this.arch}.tar.gz` + return `https://get.helm.sh/helm-v${this.binaryVersion}-${this.platformName}-${this.arch}.tar.gz`; } protected getBinaryPath() { - return path.join(this.dirname, this.binaryName) + return path.join(this.dirname, this.binaryName); } protected getOriginalBinaryPath() { - return path.join(this.dirname, this.platformName + "-" + this.arch, this.originalBinaryName) + return path.join(this.dirname, this.platformName + "-" + this.arch, this.originalBinaryName); } } diff --git a/src/main/helm/helm-release-manager.ts b/src/main/helm/helm-release-manager.ts index 80be023227..3a8b4707ba 100644 --- a/src/main/helm/helm-release-manager.ts +++ b/src/main/helm/helm-release-manager.ts @@ -1,7 +1,7 @@ import * as tempy from "tempy"; import fs from "fs"; import * as yaml from "js-yaml"; -import { promiseExec} from "../promise-exec" +import { promiseExec} from "../promise-exec"; import { helmCli } from "./helm-cli"; import { Cluster } from "../cluster"; import { toCamelCase } from "../../common/utils/camelCase"; @@ -9,103 +9,103 @@ import { toCamelCase } from "../../common/utils/camelCase"; export class HelmReleaseManager { public async listReleases(pathToKubeconfig: string, namespace?: string) { - const helm = await helmCli.binaryPath() - const namespaceFlag = namespace ? `-n ${namespace}` : "--all-namespaces" - const { stdout } = await promiseExec(`"${helm}" ls --output json ${namespaceFlag} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)}) + const helm = await helmCli.binaryPath(); + const namespaceFlag = namespace ? `-n ${namespace}` : "--all-namespaces"; + const { stdout } = await promiseExec(`"${helm}" ls --output json ${namespaceFlag} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); - const output = JSON.parse(stdout) + const output = JSON.parse(stdout); if (output.length == 0) { - return output + return output; } output.forEach((release: any, index: number) => { - output[index] = toCamelCase(release) + output[index] = toCamelCase(release); }); - return output + return output; } public async installChart(chart: string, values: any, name: string, namespace: string, version: string, pathToKubeconfig: string){ - const helm = await helmCli.binaryPath() - const fileName = tempy.file({name: "values.yaml"}) - await fs.promises.writeFile(fileName, yaml.safeDump(values)) + const helm = await helmCli.binaryPath(); + const fileName = tempy.file({name: "values.yaml"}); + await fs.promises.writeFile(fileName, yaml.safeDump(values)); try { - let generateName = "" + let generateName = ""; if (!name) { - generateName = "--generate-name" - name = "" + generateName = "--generate-name"; + name = ""; } - const { stdout, stderr } = await promiseExec(`"${helm}" install ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${pathToKubeconfig} ${generateName}`).catch((error) => { throw(error.stderr)}) - const releaseName = stdout.split("\n")[0].split(' ')[1].trim() + const { stdout, stderr } = await promiseExec(`"${helm}" install ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${pathToKubeconfig} ${generateName}`).catch((error) => { throw(error.stderr);}); + const releaseName = stdout.split("\n")[0].split(' ')[1].trim(); return { log: stdout, release: { name: releaseName, namespace: namespace } - } + }; } finally { - await fs.promises.unlink(fileName) + await fs.promises.unlink(fileName); } } public async upgradeRelease(name: string, chart: string, values: any, namespace: string, version: string, cluster: Cluster){ - const helm = await helmCli.binaryPath() - const fileName = tempy.file({name: "values.yaml"}) - await fs.promises.writeFile(fileName, yaml.safeDump(values)) + const helm = await helmCli.binaryPath(); + const fileName = tempy.file({name: "values.yaml"}); + await fs.promises.writeFile(fileName, yaml.safeDump(values)); try { - const { stdout, stderr } = await promiseExec(`"${helm}" upgrade ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr)}) + const { stdout, stderr } = await promiseExec(`"${helm}" upgrade ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr);}); return { log: stdout, release: this.getRelease(name, namespace, cluster) - } + }; } finally { - await fs.promises.unlink(fileName) + await fs.promises.unlink(fileName); } } public async getRelease(name: string, namespace: string, cluster: Cluster) { - const helm = await helmCli.binaryPath() - const {stdout, stderr} = await promiseExec(`"${helm}" status ${name} --output json --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr)}) - const release = JSON.parse(stdout) - release.resources = await this.getResources(name, namespace, cluster) - return release + const helm = await helmCli.binaryPath(); + const {stdout, stderr} = await promiseExec(`"${helm}" status ${name} --output json --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr);}); + const release = JSON.parse(stdout); + release.resources = await this.getResources(name, namespace, cluster); + return release; } public async deleteRelease(name: string, namespace: string, pathToKubeconfig: string) { - const helm = await helmCli.binaryPath() - const { stdout, stderr } = await promiseExec(`"${helm}" delete ${name} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)}) + const helm = await helmCli.binaryPath(); + const { stdout, stderr } = await promiseExec(`"${helm}" delete ${name} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); - return stdout + return stdout; } public async getValues(name: string, namespace: string, pathToKubeconfig: string) { - const helm = await helmCli.binaryPath() - const { stdout, stderr } = await promiseExec(`"${helm}" get values ${name} --all --output yaml --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)}) - return stdout + const helm = await helmCli.binaryPath(); + const { stdout, stderr } = await promiseExec(`"${helm}" get values ${name} --all --output yaml --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); + return stdout; } public async getHistory(name: string, namespace: string, pathToKubeconfig: string) { - const helm = await helmCli.binaryPath() - const {stdout, stderr} = await promiseExec(`"${helm}" history ${name} --output json --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)}) - return JSON.parse(stdout) + const helm = await helmCli.binaryPath(); + const {stdout, stderr} = await promiseExec(`"${helm}" history ${name} --output json --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); + return JSON.parse(stdout); } public async rollback(name: string, namespace: string, revision: number, pathToKubeconfig: string) { - const helm = await helmCli.binaryPath() - const {stdout, stderr} = await promiseExec(`"${helm}" rollback ${name} ${revision} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)}) - return stdout + const helm = await helmCli.binaryPath(); + const {stdout, stderr} = await promiseExec(`"${helm}" rollback ${name} ${revision} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); + return stdout; } protected async getResources(name: string, namespace: string, cluster: Cluster) { - const helm = await helmCli.binaryPath() - const kubectl = await cluster.kubeCtl.getPath() - const pathToKubeconfig = cluster.getProxyKubeconfigPath() + const helm = await helmCli.binaryPath(); + const kubectl = await cluster.kubeCtl.getPath(); + const pathToKubeconfig = cluster.getProxyKubeconfigPath(); const { stdout } = await promiseExec(`"${helm}" get manifest ${name} --namespace ${namespace} --kubeconfig ${pathToKubeconfig} | "${kubectl}" get -n ${namespace} --kubeconfig ${pathToKubeconfig} -f - -o=json`).catch((error) => { - return { stdout: JSON.stringify({items: []})} - }) - return stdout + return { stdout: JSON.stringify({items: []})}; + }); + return stdout; } } -export const releaseManager = new HelmReleaseManager() +export const releaseManager = new HelmReleaseManager(); diff --git a/src/main/helm/helm-repo-manager.ts b/src/main/helm/helm-repo-manager.ts index c2af9ea7ba..dff372a301 100644 --- a/src/main/helm/helm-repo-manager.ts +++ b/src/main/helm/helm-repo-manager.ts @@ -10,7 +10,7 @@ import logger from "../logger"; export type HelmEnv = Record & { HELM_REPOSITORY_CACHE?: string; HELM_REPOSITORY_CONFIG?: string; -} +}; export interface HelmRepoConfig { repositories: HelmRepo[] @@ -29,11 +29,11 @@ export interface HelmRepo { } export class HelmRepoManager extends Singleton { - static cache = {} // todo: remove implicit updates in helm-chart-manager.ts + static cache = {}; // todo: remove implicit updates in helm-chart-manager.ts protected repos: HelmRepo[]; - protected helmEnv: HelmEnv - protected initialized: boolean + protected helmEnv: HelmEnv; + protected initialized: boolean; async loadAvailableRepos(): Promise { const res = await customRequestPromise({ @@ -46,34 +46,34 @@ export class HelmRepoManager extends Singleton { } async init() { - helmCli.setLogger(logger) + helmCli.setLogger(logger); await helmCli.ensureBinary(); if (!this.initialized) { - this.helmEnv = await this.parseHelmEnv() - await this.update() - this.initialized = true + this.helmEnv = await this.parseHelmEnv(); + await this.update(); + this.initialized = true; } } protected async parseHelmEnv() { - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); const { stdout } = await promiseExec(`"${helm}" env`).catch((error) => { - throw(error.stderr) - }) - const lines = stdout.split(/\r?\n/) // split by new line feed - const env: HelmEnv = {} + throw(error.stderr); + }); + const lines = stdout.split(/\r?\n/); // split by new line feed + const env: HelmEnv = {}; lines.forEach((line: string) => { - const [key, value] = line.split("=") + const [key, value] = line.split("="); if (key && value) { - env[key] = value.replace(/"/g, "") // strip quotas + env[key] = value.replace(/"/g, ""); // strip quotas } - }) - return env + }); + return env; } public async repositories(): Promise { if (!this.initialized) { - await this.init() + await this.init(); } try { const repoConfigFile = this.helmEnv.HELM_REPOSITORY_CONFIG; @@ -91,41 +91,41 @@ export class HelmRepoManager extends Singleton { cacheFilePath: `${this.helmEnv.HELM_REPOSITORY_CACHE}/${repo.name}-index.yaml` })); } catch (error) { - logger.error(`[HELM]: repositories listing error "${error}"`) - return [] + logger.error(`[HELM]: repositories listing error "${error}"`); + return []; } } public async repository(name: string) { - const repositories = await this.repositories() + const repositories = await this.repositories(); return repositories.find(repo => repo.name == name); } public async update() { - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); const { stdout } = await promiseExec(`"${helm}" repo update`).catch((error) => { - return { stdout: error.stdout } - }) - return stdout + return { stdout: error.stdout }; + }); + return stdout; } public async addRepo({ name, url }: HelmRepo) { logger.info(`[HELM]: adding repo "${name}" from ${url}`); - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); const { stdout } = await promiseExec(`"${helm}" repo add ${name} ${url}`).catch((error) => { - throw(error.stderr) - }) - return stdout + throw(error.stderr); + }); + return stdout; } public async removeRepo({ name, url }: HelmRepo): Promise { logger.info(`[HELM]: removing repo "${name}" from ${url}`); - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); const { stdout, stderr } = await promiseExec(`"${helm}" repo remove ${name}`).catch((error) => { - throw(error.stderr) - }) - return stdout + throw(error.stderr); + }); + return stdout; } } -export const repoManager = HelmRepoManager.getInstance() +export const repoManager = HelmRepoManager.getInstance(); diff --git a/src/main/helm/helm-service.ts b/src/main/helm/helm-service.ts index 664a30358c..88ca4dda3e 100644 --- a/src/main/helm/helm-service.ts +++ b/src/main/helm/helm-service.ts @@ -6,93 +6,93 @@ import { releaseManager } from "./helm-release-manager"; class HelmService { public async installChart(cluster: Cluster, data: { chart: string; values: {}; name: string; namespace: string; version: string }) { - return await releaseManager.installChart(data.chart, data.values, data.name, data.namespace, data.version, cluster.getProxyKubeconfigPath()) + return await releaseManager.installChart(data.chart, data.values, data.name, data.namespace, data.version, cluster.getProxyKubeconfigPath()); } public async listCharts() { - const charts: any = {} - await repoManager.init() - const repositories = await repoManager.repositories() + const charts: any = {}; + await repoManager.init(); + const repositories = await repoManager.repositories(); for (const repo of repositories) { - charts[repo.name] = {} - const manager = new HelmChartManager(repo) - let entries = await manager.charts() - entries = this.excludeDeprecated(entries) + charts[repo.name] = {}; + const manager = new HelmChartManager(repo); + let entries = await manager.charts(); + entries = this.excludeDeprecated(entries); for (const key in entries) { - entries[key] = entries[key][0] + entries[key] = entries[key][0]; } - charts[repo.name] = entries + charts[repo.name] = entries; } - return charts + return charts; } public async getChart(repoName: string, chartName: string, version = "") { const result = { readme: "", versions: {} - } - const repo = await repoManager.repository(repoName) - const chartManager = new HelmChartManager(repo) - const chart = await chartManager.chart(chartName) - result.readme = await chartManager.getReadme(chartName, version) - result.versions = chart - return result + }; + const repo = await repoManager.repository(repoName); + const chartManager = new HelmChartManager(repo); + const chart = await chartManager.chart(chartName); + result.readme = await chartManager.getReadme(chartName, version); + result.versions = chart; + return result; } public async getChartValues(repoName: string, chartName: string, version = "") { - const repo = await repoManager.repository(repoName) - const chartManager = new HelmChartManager(repo) - return chartManager.getValues(chartName, version) + const repo = await repoManager.repository(repoName); + const chartManager = new HelmChartManager(repo); + return chartManager.getValues(chartName, version); } public async listReleases(cluster: Cluster, namespace: string = null) { - await repoManager.init() - return await releaseManager.listReleases(cluster.getProxyKubeconfigPath(), namespace) + await repoManager.init(); + return await releaseManager.listReleases(cluster.getProxyKubeconfigPath(), namespace); } public async getRelease(cluster: Cluster, releaseName: string, namespace: string) { - logger.debug("Fetch release") - return await releaseManager.getRelease(releaseName, namespace, cluster) + logger.debug("Fetch release"); + return await releaseManager.getRelease(releaseName, namespace, cluster); } public async getReleaseValues(cluster: Cluster, releaseName: string, namespace: string) { - logger.debug("Fetch release values") - return await releaseManager.getValues(releaseName, namespace, cluster.getProxyKubeconfigPath()) + logger.debug("Fetch release values"); + return await releaseManager.getValues(releaseName, namespace, cluster.getProxyKubeconfigPath()); } public async getReleaseHistory(cluster: Cluster, releaseName: string, namespace: string) { - logger.debug("Fetch release history") - return await releaseManager.getHistory(releaseName, namespace, cluster.getProxyKubeconfigPath()) + logger.debug("Fetch release history"); + return await releaseManager.getHistory(releaseName, namespace, cluster.getProxyKubeconfigPath()); } public async deleteRelease(cluster: Cluster, releaseName: string, namespace: string) { - logger.debug("Delete release") - return await releaseManager.deleteRelease(releaseName, namespace, cluster.getProxyKubeconfigPath()) + logger.debug("Delete release"); + return await releaseManager.deleteRelease(releaseName, namespace, cluster.getProxyKubeconfigPath()); } public async updateRelease(cluster: Cluster, releaseName: string, namespace: string, data: { chart: string; values: {}; version: string }) { - logger.debug("Upgrade release") - return await releaseManager.upgradeRelease(releaseName, data.chart, data.values, namespace, data.version, cluster) + logger.debug("Upgrade release"); + return await releaseManager.upgradeRelease(releaseName, data.chart, data.values, namespace, data.version, cluster); } public async rollback(cluster: Cluster, releaseName: string, namespace: string, revision: number) { - logger.debug("Rollback release") - const output = await releaseManager.rollback(releaseName, namespace, revision, cluster.getProxyKubeconfigPath()) - return { message: output } + logger.debug("Rollback release"); + const output = await releaseManager.rollback(releaseName, namespace, revision, cluster.getProxyKubeconfigPath()); + return { message: output }; } protected excludeDeprecated(entries: any) { for (const key in entries) { entries[key] = entries[key].filter((entry: any) => { if (Array.isArray(entry)) { - return entry[0]['deprecated'] != true + return entry[0]['deprecated'] != true; } - return entry["deprecated"] != true - }) + return entry["deprecated"] != true; + }); } - return entries + return entries; } } -export const helmService = new HelmService() +export const helmService = new HelmService(); diff --git a/src/main/index.ts b/src/main/index.ts index e360c2fe85..2087432d7b 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,25 +1,25 @@ // Main process -import "../common/system-ca" -import "../common/prometheus-providers" -import * as Mobx from "mobx" +import "../common/system-ca"; +import "../common/prometheus-providers"; +import * as Mobx from "mobx"; import * as LensExtensions from "../extensions/core-api"; -import { app, dialog } from "electron" +import { app, dialog } from "electron"; import { appName } from "../common/vars"; -import path from "path" -import { LensProxy } from "./lens-proxy" +import path from "path"; +import { LensProxy } from "./lens-proxy"; import { WindowManager } from "./window-manager"; import { ClusterManager } from "./cluster-manager"; -import { AppUpdater } from "./app-updater" -import { shellSync } from "./shell-sync" -import { getFreePort } from "./port" -import { mangleProxyEnv } from "./proxy-env" +import { AppUpdater } from "./app-updater"; +import { shellSync } from "./shell-sync"; +import { getFreePort } from "./port"; +import { mangleProxyEnv } from "./proxy-env"; import { registerFileProtocol } from "../common/register-protocol"; -import logger from "./logger" -import { clusterStore } from "../common/cluster-store" +import logger from "./logger"; +import { clusterStore } from "../common/cluster-store"; import { userStore } from "../common/user-store"; import { workspaceStore } from "../common/workspace-store"; -import { appEventBus } from "../common/event-bus" +import { appEventBus } from "../common/event-bus"; import { extensionLoader } from "../extensions/extension-loader"; import { extensionManager } from "../extensions/extension-manager"; import { extensionsStore } from "../extensions/extensions-store"; @@ -35,16 +35,16 @@ if (!process.env.CICD) { app.setPath("userData", workingDir); } -mangleProxyEnv() +mangleProxyEnv(); if (app.commandLine.getSwitchValue("proxy-server") !== "") { - process.env.HTTPS_PROXY = app.commandLine.getSwitchValue("proxy-server") + process.env.HTTPS_PROXY = app.commandLine.getSwitchValue("proxy-server"); } app.on("ready", async () => { - logger.info(`🚀 Starting Lens from "${workingDir}"`) + logger.info(`🚀 Starting Lens from "${workingDir}"`); await shellSync(); - const updater = new AppUpdater() + const updater = new AppUpdater(); updater.start(); registerFileProtocol("static", __static); @@ -59,10 +59,10 @@ app.on("ready", async () => { // find free port try { - proxyPort = await getFreePort() + proxyPort = await getFreePort(); } catch (error) { - logger.error(error) - dialog.showErrorBox("Lens Error", "Could not find a free port for the cluster proxy") + logger.error(error); + dialog.showErrorBox("Lens Error", "Could not find a free port for the cluster proxy"); app.exit(); } @@ -73,22 +73,22 @@ app.on("ready", async () => { try { proxyServer = LensProxy.create(proxyPort, clusterManager); } catch (error) { - logger.error(`Could not start proxy (127.0.0:${proxyPort}): ${error.message}`) - dialog.showErrorBox("Lens Error", `Could not start proxy (127.0.0:${proxyPort}): ${error.message || "unknown error"}`) + logger.error(`Could not start proxy (127.0.0:${proxyPort}): ${error.message}`); + dialog.showErrorBox("Lens Error", `Could not start proxy (127.0.0:${proxyPort}): ${error.message || "unknown error"}`); app.exit(); } - extensionLoader.init() + extensionLoader.init(); windowManager = WindowManager.getInstance(proxyPort); extensionLoader.initExtensions(await extensionManager.load()); // call after windowManager to see splash earlier setTimeout(() => { - appEventBus.emit({ name: "service", action: "start" }) - }, 1000) + appEventBus.emit({ name: "service", action: "start" }); + }, 1000); }); app.on("activate", (event, hasVisibleWindows) => { - logger.info('APP:ACTIVATE', { hasVisibleWindows }) + logger.info('APP:ACTIVATE', { hasVisibleWindows }); if (!hasVisibleWindows) { windowManager.initMainWindow(); } @@ -97,11 +97,11 @@ app.on("activate", (event, hasVisibleWindows) => { // Quit app on Cmd+Q (MacOS) app.on("will-quit", (event) => { logger.info('APP:QUIT'); - appEventBus.emit({name: "app", action: "close"}) + appEventBus.emit({name: "app", action: "close"}); event.preventDefault(); // prevent app's default shutdown (e.g. required for telemetry, etc.) clusterManager?.stop(); // close cluster connections return; // skip exit to make tray work, to quit go to app's global menu or tray's menu -}) +}); // Extensions-api runtime exports export const LensExtensionsApi = { @@ -111,4 +111,4 @@ export const LensExtensionsApi = { export { Mobx, LensExtensionsApi as LensExtensions, -} +}; diff --git a/src/main/kube-auth-proxy.ts b/src/main/kube-auth-proxy.ts index 5377ecb829..3ad76e52b0 100644 --- a/src/main/kube-auth-proxy.ts +++ b/src/main/kube-auth-proxy.ts @@ -1,10 +1,10 @@ -import { ChildProcess, spawn } from "child_process" +import { ChildProcess, spawn } from "child_process"; import { waitUntilUsed } from "tcp-port-used"; import { broadcastMessage } from "../common/ipc"; -import type { Cluster } from "./cluster" -import { Kubectl } from "./kubectl" -import logger from "./logger" -import * as url from "url" +import type { Cluster } from "./cluster"; +import { Kubectl } from "./kubectl"; +import logger from "./logger"; +import * as url from "url"; export interface KubeAuthProxyLog { data: string; @@ -12,19 +12,19 @@ export interface KubeAuthProxyLog { } export class KubeAuthProxy { - public lastError: string + public lastError: string; - protected cluster: Cluster - protected env: NodeJS.ProcessEnv = null - protected proxyProcess: ChildProcess - protected port: number - protected kubectl: Kubectl + protected cluster: Cluster; + protected env: NodeJS.ProcessEnv = null; + protected proxyProcess: ChildProcess; + protected port: number; + protected kubectl: Kubectl; constructor(cluster: Cluster, port: number, env: NodeJS.ProcessEnv) { - this.env = env - this.port = port - this.cluster = cluster - this.kubectl = Kubectl.bundled() + this.env = env; + this.port = port; + this.cluster = cluster; + this.kubectl = Kubectl.bundled(); } get acceptHosts() { @@ -36,7 +36,7 @@ export class KubeAuthProxy { return; } - const proxyBin = await this.kubectl.getPath() + const proxyBin = await this.kubectl.getPath(); const args = [ "proxy", "-p", `${this.port}`, @@ -44,63 +44,63 @@ export class KubeAuthProxy { "--context", `${this.cluster.contextName}`, "--accept-hosts", this.acceptHosts, "--reject-paths", "^[^/]" - ] + ]; if (process.env.DEBUG_PROXY === "true") { - args.push("-v", "9") + args.push("-v", "9"); } - logger.debug(`spawning kubectl proxy with args: ${args}`) - this.proxyProcess = spawn(proxyBin, args, { env: this.env, }) + logger.debug(`spawning kubectl proxy with args: ${args}`); + this.proxyProcess = spawn(proxyBin, args, { env: this.env, }); this.proxyProcess.on("error", (error) => { - this.sendIpcLogMessage({ data: error.message, error: true }) - this.exit() - }) + this.sendIpcLogMessage({ data: error.message, error: true }); + this.exit(); + }); this.proxyProcess.on("exit", (code) => { - this.sendIpcLogMessage({ data: `proxy exited with code: ${code}`, error: code > 0 }) + this.sendIpcLogMessage({ data: `proxy exited with code: ${code}`, error: code > 0 }); this.exit(); - }) + }); this.proxyProcess.stdout.on('data', (data) => { - let logItem = data.toString() + let logItem = data.toString(); if (logItem.startsWith("Starting to serve on")) { - logItem = "Authentication proxy started\n" + logItem = "Authentication proxy started\n"; } - this.sendIpcLogMessage({ data: logItem }) - }) + this.sendIpcLogMessage({ data: logItem }); + }); this.proxyProcess.stderr.on('data', (data) => { - this.lastError = this.parseError(data.toString()) - this.sendIpcLogMessage({ data: data.toString(), error: true }) - }) + this.lastError = this.parseError(data.toString()); + this.sendIpcLogMessage({ data: data.toString(), error: true }); + }); - return waitUntilUsed(this.port, 500, 10000) + return waitUntilUsed(this.port, 500, 10000); } protected parseError(data: string) { - const error = data.split("http: proxy error:").slice(1).join("").trim() - let errorMsg = error - const jsonError = error.split("Response: ")[1] + const error = data.split("http: proxy error:").slice(1).join("").trim(); + let errorMsg = error; + const jsonError = error.split("Response: ")[1]; if (jsonError) { try { - const parsedError = JSON.parse(jsonError) - errorMsg = parsedError.error_description || parsedError.error || jsonError + const parsedError = JSON.parse(jsonError); + errorMsg = parsedError.error_description || parsedError.error || jsonError; } catch (_) { - errorMsg = jsonError.trim() + errorMsg = jsonError.trim(); } } - return errorMsg + return errorMsg; } protected async sendIpcLogMessage(res: KubeAuthProxyLog) { - const channel = `kube-auth:${this.cluster.id}` + const channel = `kube-auth:${this.cluster.id}`; logger.info(`[KUBE-AUTH]: out-channel "${channel}"`, { ...res, meta: this.cluster.getMeta() }); - broadcastMessage(channel, res) + broadcastMessage(channel, res); } public exit() { if (!this.proxyProcess) return; - logger.debug("[KUBE-AUTH]: stopping local proxy", this.cluster.getMeta()) - this.proxyProcess.kill() + logger.debug("[KUBE-AUTH]: stopping local proxy", this.cluster.getMeta()); + this.proxyProcess.kill(); this.proxyProcess.removeAllListeners(); this.proxyProcess.stderr.removeAllListeners(); this.proxyProcess.stdout.removeAllListeners(); diff --git a/src/main/kubeconfig-manager.ts b/src/main/kubeconfig-manager.ts index fc84d00ddb..a8b3ae3fce 100644 --- a/src/main/kubeconfig-manager.ts +++ b/src/main/kubeconfig-manager.ts @@ -1,22 +1,22 @@ import type { KubeConfig } from "@kubernetes/client-node"; -import type { Cluster } from "./cluster" +import type { Cluster } from "./cluster"; import type { ContextHandler } from "./context-handler"; -import { app } from "electron" -import path from "path" -import fs from "fs-extra" -import { dumpConfigYaml, loadConfig } from "../common/kube-helpers" -import logger from "./logger" +import { app } from "electron"; +import path from "path"; +import fs from "fs-extra"; +import { dumpConfigYaml, loadConfig } from "../common/kube-helpers"; +import logger from "./logger"; export class KubeconfigManager { - protected configDir = app.getPath("temp") + protected configDir = app.getPath("temp"); protected tempFile: string; private constructor(protected cluster: Cluster, protected contextHandler: ContextHandler, protected port: number) { } static async create(cluster: Cluster, contextHandler: ContextHandler, port: number) { - const kcm = new KubeconfigManager(cluster, contextHandler, port) - await kcm.init() - return kcm + const kcm = new KubeconfigManager(cluster, contextHandler, port); + await kcm.init(); + return kcm; } protected async init() { @@ -24,7 +24,7 @@ export class KubeconfigManager { await this.contextHandler.ensurePort(); await this.createProxyKubeconfig(); } catch (err) { - logger.error(`Failed to created temp config for auth-proxy`, { err }) + logger.error(`Failed to created temp config for auth-proxy`, { err }); } } @@ -33,7 +33,7 @@ export class KubeconfigManager { } protected resolveProxyUrl() { - return `http://127.0.0.1:${this.port}/${this.cluster.id}` + return `http://127.0.0.1:${this.port}/${this.cluster.id}`; } /** @@ -78,11 +78,11 @@ export class KubeconfigManager { async unlink() { if (!this.tempFile) { - return + return; } - logger.info('Deleting temporary kubeconfig: ' + this.tempFile) - await fs.unlink(this.tempFile) - this.tempFile = undefined + logger.info('Deleting temporary kubeconfig: ' + this.tempFile); + await fs.unlink(this.tempFile); + this.tempFile = undefined; } } diff --git a/src/main/kubectl.ts b/src/main/kubectl.ts index 6b2f51476d..5d3f12746e 100644 --- a/src/main/kubectl.ts +++ b/src/main/kubectl.ts @@ -1,17 +1,17 @@ -import { app, remote } from "electron" -import path from "path" -import fs from "fs" -import { promiseExec } from "./promise-exec" -import logger from "./logger" -import { ensureDir, pathExists } from "fs-extra" -import * as lockFile from "proper-lockfile" -import { helmCli } from "./helm/helm-cli" -import { userStore } from "../common/user-store" +import { app, remote } from "electron"; +import path from "path"; +import fs from "fs"; +import { promiseExec } from "./promise-exec"; +import logger from "./logger"; +import { ensureDir, pathExists } from "fs-extra"; +import * as lockFile from "proper-lockfile"; +import { helmCli } from "./helm/helm-cli"; +import { userStore } from "../common/user-store"; import { customRequest } from "../common/request"; -import { getBundledKubectlVersion } from "../common/utils/app-version" +import { getBundledKubectlVersion } from "../common/utils/app-version"; import { isDevelopment, isWindows, isTestEnv } from "../common/vars"; -const bundledVersion = getBundledKubectlVersion() +const bundledVersion = getBundledKubectlVersion(); const kubectlMap: Map = new Map([ ["1.7", "1.8.15"], ["1.8", "1.9.10"], @@ -26,314 +26,314 @@ const kubectlMap: Map = new Map([ ["1.17", bundledVersion], ["1.18", "1.18.8"], ["1.19", "1.19.0"] -]) +]); const packageMirrors: Map = new Map([ ["default", "https://storage.googleapis.com/kubernetes-release/release"], ["china", "https://mirror.azure.cn/kubernetes/kubectl"] -]) +]); -let bundledPath: string -const initScriptVersionString = "# lens-initscript v3\n" +let bundledPath: string; +const initScriptVersionString = "# lens-initscript v3\n"; export function bundledKubectlPath(): string { - if (bundledPath) { return bundledPath } + if (bundledPath) { return bundledPath; } if (isDevelopment || isTestEnv) { - const platformName = isWindows ? "windows" : process.platform - bundledPath = path.join(process.cwd(), "binaries", "client", platformName, process.arch, "kubectl") + const platformName = isWindows ? "windows" : process.platform; + bundledPath = path.join(process.cwd(), "binaries", "client", platformName, process.arch, "kubectl"); } else { - bundledPath = path.join(process.resourcesPath, process.arch, "kubectl") + bundledPath = path.join(process.resourcesPath, process.arch, "kubectl"); } if (isWindows) { - bundledPath = `${bundledPath}.exe` + bundledPath = `${bundledPath}.exe`; } - return bundledPath + return bundledPath; } export class Kubectl { - public kubectlVersion: string - protected directory: string - protected url: string - protected path: string - protected dirname: string + public kubectlVersion: string; + protected directory: string; + protected url: string; + protected path: string; + protected dirname: string; static get kubectlDir() { - return path.join((app || remote.app).getPath("userData"), "binaries", "kubectl") + return path.join((app || remote.app).getPath("userData"), "binaries", "kubectl"); } - public static readonly bundledKubectlVersion: string = bundledVersion - public static invalidBundle = false + public static readonly bundledKubectlVersion: string = bundledVersion; + public static invalidBundle = false; private static bundledInstance: Kubectl; // Returns the single bundled Kubectl instance public static bundled() { - if (!Kubectl.bundledInstance) Kubectl.bundledInstance = new Kubectl(Kubectl.bundledKubectlVersion) - return Kubectl.bundledInstance + if (!Kubectl.bundledInstance) Kubectl.bundledInstance = new Kubectl(Kubectl.bundledKubectlVersion); + return Kubectl.bundledInstance; } constructor(clusterVersion: string) { - const versionParts = /^v?(\d+\.\d+)(.*)/.exec(clusterVersion) - const minorVersion = versionParts[1] + const versionParts = /^v?(\d+\.\d+)(.*)/.exec(clusterVersion); + const minorVersion = versionParts[1]; /* minorVersion is the first two digits of kube server version if the version map includes that, use that version, if not, fallback to the exact x.y.z of kube version */ if (kubectlMap.has(minorVersion)) { - this.kubectlVersion = kubectlMap.get(minorVersion) - logger.debug("Set kubectl version " + this.kubectlVersion + " for cluster version " + clusterVersion + " using version map") + this.kubectlVersion = kubectlMap.get(minorVersion); + logger.debug("Set kubectl version " + this.kubectlVersion + " for cluster version " + clusterVersion + " using version map"); } else { - this.kubectlVersion = versionParts[1] + versionParts[2] - logger.debug("Set kubectl version " + this.kubectlVersion + " for cluster version " + clusterVersion + " using fallback") + this.kubectlVersion = versionParts[1] + versionParts[2]; + logger.debug("Set kubectl version " + this.kubectlVersion + " for cluster version " + clusterVersion + " using fallback"); } - let arch = null + let arch = null; if (process.arch == "x64") { - arch = "amd64" + arch = "amd64"; } else if (process.arch == "x86" || process.arch == "ia32") { - arch = "386" + arch = "386"; } else { - arch = process.arch + arch = process.arch; } - const platformName = isWindows ? "windows" : process.platform - const binaryName = isWindows ? "kubectl.exe" : "kubectl" + const platformName = isWindows ? "windows" : process.platform; + const binaryName = isWindows ? "kubectl.exe" : "kubectl"; - this.url = `${this.getDownloadMirror()}/v${this.kubectlVersion}/bin/${platformName}/${arch}/${binaryName}` + this.url = `${this.getDownloadMirror()}/v${this.kubectlVersion}/bin/${platformName}/${arch}/${binaryName}`; - this.dirname = path.normalize(path.join(this.getDownloadDir(), this.kubectlVersion)) - this.path = path.join(this.dirname, binaryName) + this.dirname = path.normalize(path.join(this.getDownloadDir(), this.kubectlVersion)); + this.path = path.join(this.dirname, binaryName); } public getBundledPath() { - return bundledKubectlPath() + return bundledKubectlPath(); } public getPathFromPreferences() { - return userStore.preferences?.kubectlBinariesPath || this.getBundledPath() + return userStore.preferences?.kubectlBinariesPath || this.getBundledPath(); } protected getDownloadDir() { if (userStore.preferences?.downloadBinariesPath) { - return path.join(userStore.preferences.downloadBinariesPath, "kubectl") + return path.join(userStore.preferences.downloadBinariesPath, "kubectl"); } - return Kubectl.kubectlDir + return Kubectl.kubectlDir; } public async getPath(bundled = false): Promise { if (userStore.preferences?.downloadKubectlBinaries === false) { - return this.getPathFromPreferences() + return this.getPathFromPreferences(); } // return binary name if bundled path is not functional if (!await this.checkBinary(this.getBundledPath(), false)) { - Kubectl.invalidBundle = true - return path.basename(this.getBundledPath()) + Kubectl.invalidBundle = true; + return path.basename(this.getBundledPath()); } try { if (!await this.ensureKubectl()) { - logger.error("Failed to ensure kubectl, fallback to the bundled version") - return this.getBundledPath() + logger.error("Failed to ensure kubectl, fallback to the bundled version"); + return this.getBundledPath(); } - return this.path + return this.path; } catch (err) { - logger.error("Failed to ensure kubectl, fallback to the bundled version") - logger.error(err) - return this.getBundledPath() + logger.error("Failed to ensure kubectl, fallback to the bundled version"); + logger.error(err); + return this.getBundledPath(); } } public async binDir() { try { - await this.ensureKubectl() - await this.writeInitScripts() - return this.dirname + await this.ensureKubectl(); + await this.writeInitScripts(); + return this.dirname; } catch (err) { - logger.error(err) - return "" + logger.error(err); + return ""; } } public async checkBinary(path: string, checkVersion = true) { - const exists = await pathExists(path) + const exists = await pathExists(path); if (exists) { try { - const { stdout } = await promiseExec(`"${path}" version --client=true -o json`) - const output = JSON.parse(stdout) + const { stdout } = await promiseExec(`"${path}" version --client=true -o json`); + const output = JSON.parse(stdout); if (!checkVersion) { - return true + return true; } - let version: string = output.clientVersion.gitVersion + let version: string = output.clientVersion.gitVersion; if (version[0] === 'v') { - version = version.slice(1) + version = version.slice(1); } if (version === this.kubectlVersion) { - logger.debug(`Local kubectl is version ${this.kubectlVersion}`) - return true + logger.debug(`Local kubectl is version ${this.kubectlVersion}`); + return true; } - logger.error(`Local kubectl is version ${version}, expected ${this.kubectlVersion}, unlinking`) + logger.error(`Local kubectl is version ${version}, expected ${this.kubectlVersion}, unlinking`); } catch (err) { - logger.error(`Local kubectl failed to run properly (${err.message}), unlinking`) + logger.error(`Local kubectl failed to run properly (${err.message}), unlinking`); } - await fs.promises.unlink(this.path) + await fs.promises.unlink(this.path); } - return false + return false; } protected async checkBundled(): Promise { if (this.kubectlVersion === Kubectl.bundledKubectlVersion) { try { - const exist = await pathExists(this.path) + const exist = await pathExists(this.path); if (!exist) { - await fs.promises.copyFile(this.getBundledPath(), this.path) - await fs.promises.chmod(this.path, 0o755) + await fs.promises.copyFile(this.getBundledPath(), this.path); + await fs.promises.chmod(this.path, 0o755); } - return true + return true; } catch (err) { - logger.error("Could not copy the bundled kubectl to app-data: " + err) - return false + logger.error("Could not copy the bundled kubectl to app-data: " + err); + return false; } } else { - return false + return false; } } public async ensureKubectl(): Promise { if (userStore.preferences?.downloadKubectlBinaries === false) { - return true + return true; } if (Kubectl.invalidBundle) { - logger.error(`Detected invalid bundle binary, returning ...`) - return false + logger.error(`Detected invalid bundle binary, returning ...`); + return false; } - await ensureDir(this.dirname, 0o755) + await ensureDir(this.dirname, 0o755); return lockFile.lock(this.dirname).then(async (release) => { - logger.debug(`Acquired a lock for ${this.kubectlVersion}`) - const bundled = await this.checkBundled() - let isValid = await this.checkBinary(this.path, !bundled) + logger.debug(`Acquired a lock for ${this.kubectlVersion}`); + const bundled = await this.checkBundled(); + let isValid = await this.checkBinary(this.path, !bundled); if (!isValid && !bundled) { await this.downloadKubectl().catch((error) => { - logger.error(error) - logger.debug(`Releasing lock for ${this.kubectlVersion}`) - release() - return false + logger.error(error); + logger.debug(`Releasing lock for ${this.kubectlVersion}`); + release(); + return false; }); - isValid = !await this.checkBinary(this.path, false) + isValid = !await this.checkBinary(this.path, false); } if (!isValid) { - logger.debug(`Releasing lock for ${this.kubectlVersion}`) - release() - return false + logger.debug(`Releasing lock for ${this.kubectlVersion}`); + release(); + return false; } - logger.debug(`Releasing lock for ${this.kubectlVersion}`) - release() - return true + logger.debug(`Releasing lock for ${this.kubectlVersion}`); + release(); + return true; }).catch((e) => { - logger.error(`Failed to get a lock for ${this.kubectlVersion}`) - logger.error(e) - return false - }) + logger.error(`Failed to get a lock for ${this.kubectlVersion}`); + logger.error(e); + return false; + }); } public async downloadKubectl() { - await ensureDir(path.dirname(this.path), 0o755) + await ensureDir(path.dirname(this.path), 0o755); - logger.info(`Downloading kubectl ${this.kubectlVersion} from ${this.url} to ${this.path}`) + logger.info(`Downloading kubectl ${this.kubectlVersion} from ${this.url} to ${this.path}`); return new Promise((resolve, reject) => { const stream = customRequest({ url: this.url, gzip: true, }); - const file = fs.createWriteStream(this.path) + const file = fs.createWriteStream(this.path); stream.on("complete", () => { - logger.debug("kubectl binary download finished") - file.end() - }) + logger.debug("kubectl binary download finished"); + file.end(); + }); stream.on("error", (error) => { - logger.error(error) + logger.error(error); fs.unlink(this.path, () => { // do nothing - }) - reject(error) - }) + }); + reject(error); + }); file.on("close", () => { - logger.debug("kubectl binary download closed") + logger.debug("kubectl binary download closed"); fs.chmod(this.path, 0o755, (err) => { if (err) reject(err); - }) - resolve() - }) - stream.pipe(file) - }) + }); + resolve(); + }); + stream.pipe(file); + }); } protected async writeInitScripts() { - const kubectlPath = userStore.preferences?.downloadKubectlBinaries ? this.dirname : path.dirname(this.getPathFromPreferences()) - const helmPath = helmCli.getBinaryDir() + const kubectlPath = userStore.preferences?.downloadKubectlBinaries ? this.dirname : path.dirname(this.getPathFromPreferences()); + const helmPath = helmCli.getBinaryDir(); const fsPromises = fs.promises; - const bashScriptPath = path.join(this.dirname, '.bash_set_path') + const bashScriptPath = path.join(this.dirname, '.bash_set_path'); - let bashScript = "" + initScriptVersionString - bashScript += "tempkubeconfig=\"$KUBECONFIG\"\n" - bashScript += "test -f \"/etc/profile\" && . \"/etc/profile\"\n" - bashScript += "if test -f \"$HOME/.bash_profile\"; then\n" - bashScript += " . \"$HOME/.bash_profile\"\n" - bashScript += "elif test -f \"$HOME/.bash_login\"; then\n" - bashScript += " . \"$HOME/.bash_login\"\n" - bashScript += "elif test -f \"$HOME/.profile\"; then\n" - bashScript += " . \"$HOME/.profile\"\n" - bashScript += "fi\n" - bashScript += `export PATH="${helmPath}:${kubectlPath}:$PATH"\n` - bashScript += "export KUBECONFIG=\"$tempkubeconfig\"\n" + let bashScript = "" + initScriptVersionString; + bashScript += "tempkubeconfig=\"$KUBECONFIG\"\n"; + bashScript += "test -f \"/etc/profile\" && . \"/etc/profile\"\n"; + bashScript += "if test -f \"$HOME/.bash_profile\"; then\n"; + bashScript += " . \"$HOME/.bash_profile\"\n"; + bashScript += "elif test -f \"$HOME/.bash_login\"; then\n"; + bashScript += " . \"$HOME/.bash_login\"\n"; + bashScript += "elif test -f \"$HOME/.profile\"; then\n"; + bashScript += " . \"$HOME/.profile\"\n"; + bashScript += "fi\n"; + bashScript += `export PATH="${helmPath}:${kubectlPath}:$PATH"\n`; + bashScript += "export KUBECONFIG=\"$tempkubeconfig\"\n"; - bashScript += "NO_PROXY=\",${NO_PROXY:-localhost},\"\n" - bashScript += "NO_PROXY=\"${NO_PROXY//,localhost,/,}\"\n" - bashScript += "NO_PROXY=\"${NO_PROXY//,127.0.0.1,/,}\"\n" - bashScript += "NO_PROXY=\"localhost,127.0.0.1${NO_PROXY%,}\"\n" - bashScript += "export NO_PROXY\n" - bashScript += "unset tempkubeconfig\n" - await fsPromises.writeFile(bashScriptPath, bashScript.toString(), { mode: 0o644 }) + bashScript += "NO_PROXY=\",${NO_PROXY:-localhost},\"\n"; + bashScript += "NO_PROXY=\"${NO_PROXY//,localhost,/,}\"\n"; + bashScript += "NO_PROXY=\"${NO_PROXY//,127.0.0.1,/,}\"\n"; + bashScript += "NO_PROXY=\"localhost,127.0.0.1${NO_PROXY%,}\"\n"; + bashScript += "export NO_PROXY\n"; + bashScript += "unset tempkubeconfig\n"; + await fsPromises.writeFile(bashScriptPath, bashScript.toString(), { mode: 0o644 }); - const zshScriptPath = path.join(this.dirname, '.zlogin') + const zshScriptPath = path.join(this.dirname, '.zlogin'); - let zshScript = "" + initScriptVersionString + let zshScript = "" + initScriptVersionString; - zshScript += "tempkubeconfig=\"$KUBECONFIG\"\n" + zshScript += "tempkubeconfig=\"$KUBECONFIG\"\n"; // restore previous ZDOTDIR - zshScript += "export ZDOTDIR=\"$OLD_ZDOTDIR\"\n" + zshScript += "export ZDOTDIR=\"$OLD_ZDOTDIR\"\n"; // source all the files - zshScript += "test -f \"$OLD_ZDOTDIR/.zshenv\" && . \"$OLD_ZDOTDIR/.zshenv\"\n" - zshScript += "test -f \"$OLD_ZDOTDIR/.zprofile\" && . \"$OLD_ZDOTDIR/.zprofile\"\n" - zshScript += "test -f \"$OLD_ZDOTDIR/.zlogin\" && . \"$OLD_ZDOTDIR/.zlogin\"\n" - zshScript += "test -f \"$OLD_ZDOTDIR/.zshrc\" && . \"$OLD_ZDOTDIR/.zshrc\"\n" + zshScript += "test -f \"$OLD_ZDOTDIR/.zshenv\" && . \"$OLD_ZDOTDIR/.zshenv\"\n"; + zshScript += "test -f \"$OLD_ZDOTDIR/.zprofile\" && . \"$OLD_ZDOTDIR/.zprofile\"\n"; + zshScript += "test -f \"$OLD_ZDOTDIR/.zlogin\" && . \"$OLD_ZDOTDIR/.zlogin\"\n"; + zshScript += "test -f \"$OLD_ZDOTDIR/.zshrc\" && . \"$OLD_ZDOTDIR/.zshrc\"\n"; // voodoo to replace any previous occurrences of kubectl path in the PATH - zshScript += `kubectlpath=\"${kubectlPath}"\n` - zshScript += `helmpath=\"${helmPath}"\n` - zshScript += "p=\":$kubectlpath:\"\n" - zshScript += "d=\":$PATH:\"\n" - zshScript += "d=${d//$p/:}\n" - zshScript += "d=${d/#:/}\n" - zshScript += "export PATH=\"$helmpath:$kubectlpath:${d/%:/}\"\n" - zshScript += "export KUBECONFIG=\"$tempkubeconfig\"\n" - zshScript += "NO_PROXY=\",${NO_PROXY:-localhost},\"\n" - zshScript += "NO_PROXY=\"${NO_PROXY//,localhost,/,}\"\n" - zshScript += "NO_PROXY=\"${NO_PROXY//,127.0.0.1,/,}\"\n" - zshScript += "NO_PROXY=\"localhost,127.0.0.1${NO_PROXY%,}\"\n" - zshScript += "export NO_PROXY\n" - zshScript += "unset tempkubeconfig\n" - zshScript += "unset OLD_ZDOTDIR\n" - await fsPromises.writeFile(zshScriptPath, zshScript.toString(), { mode: 0o644 }) + zshScript += `kubectlpath=\"${kubectlPath}"\n`; + zshScript += `helmpath=\"${helmPath}"\n`; + zshScript += "p=\":$kubectlpath:\"\n"; + zshScript += "d=\":$PATH:\"\n"; + zshScript += "d=${d//$p/:}\n"; + zshScript += "d=${d/#:/}\n"; + zshScript += "export PATH=\"$helmpath:$kubectlpath:${d/%:/}\"\n"; + zshScript += "export KUBECONFIG=\"$tempkubeconfig\"\n"; + zshScript += "NO_PROXY=\",${NO_PROXY:-localhost},\"\n"; + zshScript += "NO_PROXY=\"${NO_PROXY//,localhost,/,}\"\n"; + zshScript += "NO_PROXY=\"${NO_PROXY//,127.0.0.1,/,}\"\n"; + zshScript += "NO_PROXY=\"localhost,127.0.0.1${NO_PROXY%,}\"\n"; + zshScript += "export NO_PROXY\n"; + zshScript += "unset tempkubeconfig\n"; + zshScript += "unset OLD_ZDOTDIR\n"; + await fsPromises.writeFile(zshScriptPath, zshScript.toString(), { mode: 0o644 }); } protected getDownloadMirror() { - const mirror = packageMirrors.get(userStore.preferences?.downloadMirror) + const mirror = packageMirrors.get(userStore.preferences?.downloadMirror); if (mirror) { - return mirror + return mirror; } - return packageMirrors.get("default") // MacOS packages are only available from default + return packageMirrors.get("default"); // MacOS packages are only available from default } } diff --git a/src/main/kubectl_spec.ts b/src/main/kubectl_spec.ts index ade999c082..9d5a5d1e1d 100644 --- a/src/main/kubectl_spec.ts +++ b/src/main/kubectl_spec.ts @@ -1,5 +1,5 @@ -import packageInfo from "../../package.json" -import path from "path" +import packageInfo from "../../package.json"; +import path from "path"; import { Kubectl } from "../../src/main/kubectl"; import { isWindows } from "../common/vars"; @@ -7,39 +7,39 @@ jest.mock("../common/user-store"); describe("kubectlVersion", () => { it("returns bundled version if exactly same version used", async () => { - const kubectl = new Kubectl(Kubectl.bundled().kubectlVersion) - expect(kubectl.kubectlVersion).toBe(Kubectl.bundled().kubectlVersion) - }) + const kubectl = new Kubectl(Kubectl.bundled().kubectlVersion); + expect(kubectl.kubectlVersion).toBe(Kubectl.bundled().kubectlVersion); + }); it("returns bundled version if same major.minor version is used", async () => { const { bundledKubectlVersion } = packageInfo.config; const kubectl = new Kubectl(bundledKubectlVersion); - expect(kubectl.kubectlVersion).toBe(Kubectl.bundled().kubectlVersion) - }) -}) + expect(kubectl.kubectlVersion).toBe(Kubectl.bundled().kubectlVersion); + }); +}); describe("getPath()", () => { it("returns path to downloaded kubectl binary", async () => { const { bundledKubectlVersion } = packageInfo.config; const kubectl = new Kubectl(bundledKubectlVersion); - const kubectlPath = await kubectl.getPath() - let binaryName = "kubectl" + const kubectlPath = await kubectl.getPath(); + let binaryName = "kubectl"; if (isWindows) { - binaryName += ".exe" + binaryName += ".exe"; } - const expectedPath = path.join(Kubectl.kubectlDir, Kubectl.bundledKubectlVersion, binaryName) - expect(kubectlPath).toBe(expectedPath) - }) + const expectedPath = path.join(Kubectl.kubectlDir, Kubectl.bundledKubectlVersion, binaryName); + expect(kubectlPath).toBe(expectedPath); + }); it("returns plain binary name if bundled kubectl is non-functional", async () => { const { bundledKubectlVersion } = packageInfo.config; const kubectl = new Kubectl(bundledKubectlVersion); - jest.spyOn(kubectl, "getBundledPath").mockReturnValue("/invalid/path/kubectl") - const kubectlPath = await kubectl.getPath() - let binaryName = "kubectl" + jest.spyOn(kubectl, "getBundledPath").mockReturnValue("/invalid/path/kubectl"); + const kubectlPath = await kubectl.getPath(); + let binaryName = "kubectl"; if (isWindows) { - binaryName += ".exe" + binaryName += ".exe"; } - expect(kubectlPath).toBe(binaryName) - }) -}) + expect(kubectlPath).toBe(binaryName); + }); +}); diff --git a/src/main/lens-api.ts b/src/main/lens-api.ts index a0a7361a68..fafeffce91 100644 --- a/src/main/lens-api.ts +++ b/src/main/lens-api.ts @@ -2,16 +2,16 @@ import http from "http"; export abstract class LensApi { protected respondJson(res: http.ServerResponse, content: {}, status = 200) { - this.respond(res, JSON.stringify(content), "application/json", status) + this.respond(res, JSON.stringify(content), "application/json", status); } protected respondText(res: http.ServerResponse, content: string, status = 200) { - this.respond(res, content, "text/plain", status) + this.respond(res, content, "text/plain", status); } protected respond(res: http.ServerResponse, content: string, contentType: string, status = 200) { - res.setHeader("Content-Type", contentType) - res.statusCode = status - res.end(content) + res.setHeader("Content-Type", contentType); + res.statusCode = status; + res.end(content); } } diff --git a/src/main/lens-binary.ts b/src/main/lens-binary.ts index dd6f2aa058..fc6b59ee74 100644 --- a/src/main/lens-binary.ts +++ b/src/main/lens-binary.ts @@ -1,10 +1,10 @@ -import path from "path" -import fs from "fs" -import request from "request" -import { ensureDir, pathExists } from "fs-extra" -import * as tar from "tar" +import path from "path"; +import fs from "fs"; +import request from "request"; +import { ensureDir, pathExists } from "fs-extra"; +import * as tar from "tar"; import { isWindows } from "../common/vars"; -import winston from "winston" +import winston from "winston"; export type LensBinaryOpts = { version: string; @@ -12,177 +12,177 @@ export type LensBinaryOpts = { originalBinaryName: string; newBinaryName?: string; requestOpts?: request.Options; -} +}; export class LensBinary { - public binaryVersion: string - protected directory: string - protected url: string + public binaryVersion: string; + protected directory: string; + protected url: string; protected path: string; protected tarPath: string; - protected dirname: string - protected binaryName: string - protected platformName: string - protected arch: string - protected originalBinaryName: string - protected requestOpts: request.Options - protected logger: Console | winston.Logger + protected dirname: string; + protected binaryName: string; + protected platformName: string; + protected arch: string; + protected originalBinaryName: string; + protected requestOpts: request.Options; + protected logger: Console | winston.Logger; constructor(opts: LensBinaryOpts) { - const baseDir = opts.baseDir - this.originalBinaryName = opts.originalBinaryName - this.binaryName = opts.newBinaryName || opts.originalBinaryName - this.binaryVersion = opts.version - this.requestOpts = opts.requestOpts - this.logger = console - let arch = null + const baseDir = opts.baseDir; + this.originalBinaryName = opts.originalBinaryName; + this.binaryName = opts.newBinaryName || opts.originalBinaryName; + this.binaryVersion = opts.version; + this.requestOpts = opts.requestOpts; + this.logger = console; + let arch = null; if (process.arch == "x64") { - arch = "amd64" + arch = "amd64"; } else if (process.arch == "x86" || process.arch == "ia32") { - arch = "386" + arch = "386"; } else { - arch = process.arch + arch = process.arch; } - this.arch = arch - this.platformName = isWindows ? "windows" : process.platform - this.dirname = path.normalize(path.join(baseDir, this.binaryName)) + this.arch = arch; + this.platformName = isWindows ? "windows" : process.platform; + this.dirname = path.normalize(path.join(baseDir, this.binaryName)); if (isWindows) { - this.binaryName = this.binaryName + ".exe" - this.originalBinaryName = this.originalBinaryName + ".exe" + this.binaryName = this.binaryName + ".exe"; + this.originalBinaryName = this.originalBinaryName + ".exe"; } - const tarName = this.getTarName() + const tarName = this.getTarName(); if (tarName) { - this.tarPath = path.join(this.dirname, tarName) + this.tarPath = path.join(this.dirname, tarName); } } public setLogger(logger: Console | winston.Logger) { - this.logger = logger + this.logger = logger; } protected binaryDir() { - throw new Error("binaryDir not implemented") + throw new Error("binaryDir not implemented"); } public async binaryPath() { - await this.ensureBinary() - return this.getBinaryPath() + await this.ensureBinary(); + return this.getBinaryPath(); } protected getTarName(): string | null { - return null + return null; } protected getUrl() { - return "" + return ""; } protected getBinaryPath() { - return "" + return ""; } protected getOriginalBinaryPath() { - return "" + return ""; } public getBinaryDir() { - return path.dirname(this.getBinaryPath()) + return path.dirname(this.getBinaryPath()); } public async binDir() { try { - await this.ensureBinary() - return this.dirname + await this.ensureBinary(); + return this.dirname; } catch (err) { - this.logger.error(err) - return "" + this.logger.error(err); + return ""; } } protected async checkBinary() { - const exists = await pathExists(this.getBinaryPath()) - return exists + const exists = await pathExists(this.getBinaryPath()); + return exists; } public async ensureBinary() { - const isValid = await this.checkBinary() + const isValid = await this.checkBinary(); if (!isValid) { await this.downloadBinary().catch((error) => { - this.logger.error(error) + this.logger.error(error); }); - if (this.tarPath) await this.untarBinary() - if (this.originalBinaryName != this.binaryName) await this.renameBinary() - this.logger.info(`${this.originalBinaryName} has been downloaded to ${this.getBinaryPath()}`) + if (this.tarPath) await this.untarBinary(); + if (this.originalBinaryName != this.binaryName) await this.renameBinary(); + this.logger.info(`${this.originalBinaryName} has been downloaded to ${this.getBinaryPath()}`); } } protected async untarBinary() { return new Promise((resolve, reject) => { - this.logger.debug(`Extracting ${this.originalBinaryName} binary`) + this.logger.debug(`Extracting ${this.originalBinaryName} binary`); tar.x({ file: this.tarPath, cwd: this.dirname }).then((_ => { - resolve() - })) - }) + resolve(); + })); + }); } protected async renameBinary() { return new Promise((resolve, reject) => { - this.logger.debug(`Renaming ${this.originalBinaryName} binary to ${this.binaryName}`) + this.logger.debug(`Renaming ${this.originalBinaryName} binary to ${this.binaryName}`); fs.rename(this.getOriginalBinaryPath(), this.getBinaryPath(), (err) => { if (err) { - reject(err) + reject(err); } else { - resolve() + resolve(); } - }) - }) + }); + }); } protected async downloadBinary() { - const binaryPath = this.tarPath || this.getBinaryPath() - await ensureDir(this.getBinaryDir(), 0o755) + const binaryPath = this.tarPath || this.getBinaryPath(); + await ensureDir(this.getBinaryDir(), 0o755); - const file = fs.createWriteStream(binaryPath) - const url = this.getUrl() + const file = fs.createWriteStream(binaryPath); + const url = this.getUrl(); - this.logger.info(`Downloading ${this.originalBinaryName} ${this.binaryVersion} from ${url} to ${binaryPath}`) + this.logger.info(`Downloading ${this.originalBinaryName} ${this.binaryVersion} from ${url} to ${binaryPath}`); const requestOpts: request.UriOptions & request.CoreOptions = { uri: url, gzip: true, ...this.requestOpts - } + }; - const stream = request(requestOpts) + const stream = request(requestOpts); stream.on("complete", () => { - this.logger.info(`Download of ${this.originalBinaryName} finished`) - file.end() - }) + this.logger.info(`Download of ${this.originalBinaryName} finished`); + file.end(); + }); stream.on("error", (error) => { - this.logger.error(error) + this.logger.error(error); fs.unlink(binaryPath, () => { // do nothing - }) - throw(error) - }) + }); + throw(error); + }); return new Promise((resolve, reject) => { file.on("close", () => { - this.logger.debug(`${this.originalBinaryName} binary download closed`) + this.logger.debug(`${this.originalBinaryName} binary download closed`); if (!this.tarPath) fs.chmod(binaryPath, 0o755, (err) => { if (err) reject(err); - }) - resolve() - }) - stream.pipe(file) - }) + }); + resolve(); + }); + stream.pipe(file); + }); } } diff --git a/src/main/lens-proxy.ts b/src/main/lens-proxy.ts index 7f0b14721d..03b1b15d29 100644 --- a/src/main/lens-proxy.ts +++ b/src/main/lens-proxy.ts @@ -3,27 +3,27 @@ import http from "http"; import spdy from "spdy"; import httpProxy from "http-proxy"; import url from "url"; -import * as WebSocket from "ws" -import { apiPrefix, apiKubePrefix } from "../common/vars" +import * as WebSocket from "ws"; +import { apiPrefix, apiKubePrefix } from "../common/vars"; import { openShell } from "./node-shell-session"; -import { Router } from "./router" -import { ClusterManager } from "./cluster-manager" +import { Router } from "./router"; +import { ClusterManager } from "./cluster-manager"; import { ContextHandler } from "./context-handler"; -import logger from "./logger" +import logger from "./logger"; export class LensProxy { - protected origin: string - protected proxyServer: http.Server - protected router: Router - protected closed = false - protected retryCounters = new Map() + protected origin: string; + protected proxyServer: http.Server; + protected router: Router; + protected closed = false; + protected retryCounters = new Map(); static create(port: number, clusterManager: ClusterManager) { return new LensProxy(port, clusterManager).listen(); } private constructor(protected port: number, protected clusterManager: ClusterManager) { - this.origin = `http://localhost:${port}` + this.origin = `http://localhost:${port}`; this.router = new Router(); } @@ -35,8 +35,8 @@ export class LensProxy { close() { logger.info("Closing proxy server"); - this.proxyServer.close() - this.closed = true + this.proxyServer.close(); + this.closed = true; } protected buildCustomProxy(): http.Server { @@ -47,66 +47,66 @@ export class LensProxy { protocols: ["http/1.1", "spdy/3.1"] } }, (req: http.IncomingMessage, res: http.ServerResponse) => { - this.handleRequest(proxy, req, res) - }) + this.handleRequest(proxy, req, res); + }); spdyProxy.on("upgrade", (req: http.IncomingMessage, socket: net.Socket, head: Buffer) => { if (req.url.startsWith(`${apiPrefix}?`)) { - this.handleWsUpgrade(req, socket, head) + this.handleWsUpgrade(req, socket, head); } else { - this.handleProxyUpgrade(proxy, req, socket, head) + this.handleProxyUpgrade(proxy, req, socket, head); } - }) + }); spdyProxy.on("error", (err) => { - logger.error("proxy error", err) - }) - return spdyProxy + logger.error("proxy error", err); + }); + return spdyProxy; } protected async handleProxyUpgrade(proxy: httpProxy, req: http.IncomingMessage, socket: net.Socket, head: Buffer) { - const cluster = this.clusterManager.getClusterForRequest(req) + const cluster = this.clusterManager.getClusterForRequest(req); if (cluster) { - const proxyUrl = await cluster.contextHandler.resolveAuthProxyUrl() + req.url.replace(apiKubePrefix, "") - const apiUrl = url.parse(cluster.apiUrl) - const pUrl = url.parse(proxyUrl) - const connectOpts = { port: parseInt(pUrl.port), host: pUrl.hostname } - const proxySocket = new net.Socket() + const proxyUrl = await cluster.contextHandler.resolveAuthProxyUrl() + req.url.replace(apiKubePrefix, ""); + const apiUrl = url.parse(cluster.apiUrl); + const pUrl = url.parse(proxyUrl); + const connectOpts = { port: parseInt(pUrl.port), host: pUrl.hostname }; + const proxySocket = new net.Socket(); proxySocket.connect(connectOpts, () => { - proxySocket.write(`${req.method} ${pUrl.path} HTTP/1.1\r\n`) - proxySocket.write(`Host: ${apiUrl.host}\r\n`) + proxySocket.write(`${req.method} ${pUrl.path} HTTP/1.1\r\n`); + proxySocket.write(`Host: ${apiUrl.host}\r\n`); for (let i = 0; i < req.rawHeaders.length; i += 2) { - const key = req.rawHeaders[i] + const key = req.rawHeaders[i]; if (key !== "Host" && key !== "Authorization") { - proxySocket.write(`${req.rawHeaders[i]}: ${req.rawHeaders[i+1]}\r\n`) + proxySocket.write(`${req.rawHeaders[i]}: ${req.rawHeaders[i+1]}\r\n`); } } - proxySocket.write("\r\n") - proxySocket.write(head) - }) + proxySocket.write("\r\n"); + proxySocket.write(head); + }); - proxySocket.setKeepAlive(true) - socket.setKeepAlive(true) - proxySocket.setTimeout(0) - socket.setTimeout(0) + proxySocket.setKeepAlive(true); + socket.setKeepAlive(true); + proxySocket.setTimeout(0); + socket.setTimeout(0); proxySocket.on('data', function (chunk) { - socket.write(chunk) - }) + socket.write(chunk); + }); proxySocket.on('end', function () { - socket.end() - }) + socket.end(); + }); proxySocket.on('error', function (err) { socket.write("HTTP/" + req.httpVersion + " 500 Connection error\r\n\r\n"); - socket.end() - }) + socket.end(); + }); socket.on('data', function (chunk) { - proxySocket.write(chunk) - }) + proxySocket.write(chunk); + }); socket.on('end', function () { - proxySocket.end() - }) + proxySocket.end(); + }); socket.on('error', function () { - proxySocket.end() - }) + proxySocket.end(); + }); } } @@ -120,29 +120,29 @@ export class LensProxy { logger.debug("Failed proxy to target: " + JSON.stringify(target, null, 2)); if (req.method === "GET" && (!res.statusCode || res.statusCode >= 500)) { const reqId = this.getRequestId(req); - const retryCount = this.retryCounters.get(reqId) || 0 - const timeoutMs = retryCount * 250 + const retryCount = this.retryCounters.get(reqId) || 0; + const timeoutMs = retryCount * 250; if (retryCount < 20) { - logger.debug(`Retrying proxy request to url: ${reqId}`) + logger.debug(`Retrying proxy request to url: ${reqId}`); setTimeout(() => { - this.retryCounters.set(reqId, retryCount + 1) - this.handleRequest(proxy, req, res) - }, timeoutMs) + this.retryCounters.set(reqId, retryCount + 1); + this.handleRequest(proxy, req, res); + }, timeoutMs); } } } try { - res.writeHead(500).end("Oops, something went wrong.") + res.writeHead(500).end("Oops, something went wrong."); } catch (e) { - logger.error(`[LENS-PROXY]: Failed to write headers: `, e) + logger.error(`[LENS-PROXY]: Failed to write headers: `, e); } - }) + }); return proxy; } protected createWsListener(): WebSocket.Server { - const ws = new WebSocket.Server({ noServer: true }) + const ws = new WebSocket.Server({ noServer: true }); return ws.on("connection", ((socket: WebSocket, req: http.IncomingMessage) => { const cluster = this.clusterManager.getClusterForRequest(req); const nodeParam = url.parse(req.url, true).query["node"]?.toString(); @@ -152,10 +152,10 @@ export class LensProxy { protected async getProxyTarget(req: http.IncomingMessage, contextHandler: ContextHandler): Promise { if (req.url.startsWith(apiKubePrefix)) { - delete req.headers.authorization - req.url = req.url.replace(apiKubePrefix, "") - const isWatchRequest = req.url.includes("watch=") - return await contextHandler.getApiTarget(isWatchRequest) + delete req.headers.authorization; + req.url = req.url.replace(apiKubePrefix, ""); + const isWatchRequest = req.url.includes("watch="); + return await contextHandler.getApiTarget(isWatchRequest); } } @@ -164,9 +164,9 @@ export class LensProxy { } protected async handleRequest(proxy: httpProxy, req: http.IncomingMessage, res: http.ServerResponse) { - const cluster = this.clusterManager.getClusterForRequest(req) + const cluster = this.clusterManager.getClusterForRequest(req); if (cluster) { - const proxyTarget = await this.getProxyTarget(req, cluster.contextHandler) + const proxyTarget = await this.getProxyTarget(req, cluster.contextHandler); if (proxyTarget) { // allow to fetch apis in "clusterId.localhost:port" from "localhost:port" res.setHeader("Access-Control-Allow-Origin", this.origin); diff --git a/src/main/logger.ts b/src/main/logger.ts index f4e2707c27..81d61e8002 100644 --- a/src/main/logger.ts +++ b/src/main/logger.ts @@ -1,13 +1,13 @@ import { app, remote } from "electron"; -import winston from "winston" +import winston from "winston"; import { isDebugging } from "../common/vars"; -const logLevel = process.env.LOG_LEVEL ? process.env.LOG_LEVEL : isDebugging ? "debug" : "info" +const logLevel = process.env.LOG_LEVEL ? process.env.LOG_LEVEL : isDebugging ? "debug" : "info"; const consoleOptions: winston.transports.ConsoleTransportOptions = { handleExceptions: false, level: logLevel, -} +}; const fileOptions: winston.transports.FileTransportOptions = { handleExceptions: false, @@ -17,7 +17,7 @@ const fileOptions: winston.transports.FileTransportOptions = { maxsize: 16 * 1024, maxFiles: 16, tailable: true, -} +}; const logger = winston.createLogger({ format: winston.format.combine( @@ -30,4 +30,4 @@ const logger = winston.createLogger({ ], }); -export default logger +export default logger; diff --git a/src/main/menu.ts b/src/main/menu.ts index 14525581b8..99a0d0bb55 100644 --- a/src/main/menu.ts +++ b/src/main/menu.ts @@ -1,4 +1,4 @@ -import { app, BrowserWindow, dialog, ipcMain, IpcMainEvent, Menu, MenuItem, MenuItemConstructorOptions, webContents, shell } from "electron" +import { app, BrowserWindow, dialog, ipcMain, IpcMainEvent, Menu, MenuItem, MenuItemConstructorOptions, webContents, shell } from "electron"; import { autorun } from "mobx"; import { WindowManager } from "./window-manager"; import { appName, isMac, isWindows, isTestEnv } from "../common/vars"; @@ -11,7 +11,7 @@ import { menuRegistry } from "../extensions/registries/menu-registry"; import logger from "./logger"; import { exitApp } from "./exit-app"; -export type MenuTopId = "mac" | "file" | "edit" | "view" | "help" +export type MenuTopId = "mac" | "file" | "edit" | "view" | "help"; export function initMenu(windowManager: WindowManager) { return autorun(() => buildMenu(windowManager), { @@ -25,14 +25,14 @@ export function showAbout(browserWindow: BrowserWindow) { `Electron: ${process.versions.electron}`, `Chrome: ${process.versions.chrome}`, `Copyright 2020 Mirantis, Inc.`, - ] + ]; dialog.showMessageBoxSync(browserWindow, { title: `${isWindows ? " ".repeat(2) : ""}${appName}`, type: "info", buttons: ["Close"], message: `Lens`, detail: appInfo.join("\r\n") - }) + }); } export function buildMenu(windowManager: WindowManager) { @@ -44,7 +44,7 @@ export function buildMenu(windowManager: WindowManager) { function activeClusterOnly(menuItems: MenuItemConstructorOptions[]) { if (!windowManager.activeClusterId) { menuItems.forEach(item => { - item.enabled = false + item.enabled = false; }); } return menuItems; @@ -61,7 +61,7 @@ export function buildMenu(windowManager: WindowManager) { { label: "About Lens", click(menuItem: MenuItem, browserWindow: BrowserWindow) { - showAbout(browserWindow) + showAbout(browserWindow); } }, { type: 'separator' }, @@ -69,14 +69,14 @@ export function buildMenu(windowManager: WindowManager) { label: 'Preferences', accelerator: 'CmdOrCtrl+,', click() { - navigate(preferencesURL()) + navigate(preferencesURL()); } }, { label: 'Extensions', accelerator: 'CmdOrCtrl+Shift+E', click() { - navigate(extensionsURL()) + navigate(extensionsURL()); } }, { type: 'separator' }, @@ -90,7 +90,7 @@ export function buildMenu(windowManager: WindowManager) { label: 'Quit', accelerator: 'Cmd+Q', click() { - exitApp() + exitApp(); } } ] @@ -103,7 +103,7 @@ export function buildMenu(windowManager: WindowManager) { label: 'Add Cluster', accelerator: 'CmdOrCtrl+Shift+A', click() { - navigate(addClusterURL()) + navigate(addClusterURL()); } }, ...activeClusterOnly([ @@ -115,7 +115,7 @@ export function buildMenu(windowManager: WindowManager) { params: { clusterId: windowManager.activeClusterId } - })) + })); } } ]), @@ -125,14 +125,14 @@ export function buildMenu(windowManager: WindowManager) { label: 'Preferences', accelerator: 'Ctrl+,', click() { - navigate(preferencesURL()) + navigate(preferencesURL()); } }, { label: 'Extensions', accelerator: 'Ctrl+Shift+E', click() { - navigate(extensionsURL()) + navigate(extensionsURL()); } } ]), @@ -147,7 +147,7 @@ export function buildMenu(windowManager: WindowManager) { label: 'Exit', accelerator: 'Alt+F4', click() { - exitApp() + exitApp(); } } ]) @@ -183,7 +183,7 @@ export function buildMenu(windowManager: WindowManager) { label: 'Forward', accelerator: 'CmdOrCtrl+]', click() { - webContents.getFocusedWebContents()?.goForward() + webContents.getFocusedWebContents()?.goForward(); } }, { @@ -209,7 +209,7 @@ export function buildMenu(windowManager: WindowManager) { { label: "What's new?", click() { - navigate(whatsNewURL()) + navigate(whatsNewURL()); }, }, { @@ -222,7 +222,7 @@ export function buildMenu(windowManager: WindowManager) { { label: "About Lens", click(menuItem: MenuItem, browserWindow: BrowserWindow) { - showAbout(browserWindow) + showAbout(browserWindow); } } ]) @@ -236,7 +236,7 @@ export function buildMenu(windowManager: WindowManager) { edit: editMenu, view: viewMenu, help: helpMenu, - } + }; // Modify menu from extensions-api menuRegistry.getItems().forEach(({ parentId, ...menuItem }) => { @@ -244,12 +244,12 @@ export function buildMenu(windowManager: WindowManager) { const topMenu = appMenu[parentId as MenuTopId].submenu as MenuItemConstructorOptions[]; topMenu.push(menuItem); } catch (err) { - logger.error(`[MENU]: can't register menu item, parentId=${parentId}`, { menuItem }) + logger.error(`[MENU]: can't register menu item, parentId=${parentId}`, { menuItem }); } - }) + }); if (!isMac) { - delete appMenu.mac + delete appMenu.mac; } const menu = Menu.buildFromTemplate(Object.values(appMenu)); @@ -259,9 +259,9 @@ export function buildMenu(windowManager: WindowManager) { // this is a workaround for the test environment (spectron) not being able to directly access // the application menus (https://github.com/electron-userland/spectron/issues/21) ipcMain.on('test-menu-item-click', (event: IpcMainEvent, ...names: string[]) => { - let menu: Menu = Menu.getApplicationMenu() + let menu: Menu = Menu.getApplicationMenu(); const parentLabels: string[] = []; - let menuItem: MenuItem + let menuItem: MenuItem; for (const name of names) { parentLabels.push(name); @@ -272,7 +272,7 @@ export function buildMenu(windowManager: WindowManager) { menu = menuItem.submenu; } - const menuPath: string = parentLabels.join(" -> ") + const menuPath: string = parentLabels.join(" -> "); if (!menuItem) { logger.info(`[MENU:test-menu-item-click] Cannot find menu item ${menuPath}`); return; diff --git a/src/main/node-shell-session.ts b/src/main/node-shell-session.ts index 9e97398327..3d48afebc5 100644 --- a/src/main/node-shell-session.ts +++ b/src/main/node-shell-session.ts @@ -1,36 +1,36 @@ -import * as WebSocket from "ws" -import * as pty from "node-pty" +import * as WebSocket from "ws"; +import * as pty from "node-pty"; import { ShellSession } from "./shell-session"; -import { v4 as uuid } from "uuid" -import * as k8s from "@kubernetes/client-node" -import { KubeConfig } from "@kubernetes/client-node" -import { Cluster } from "./cluster" +import { v4 as uuid } from "uuid"; +import * as k8s from "@kubernetes/client-node"; +import { KubeConfig } from "@kubernetes/client-node"; +import { Cluster } from "./cluster"; import logger from "./logger"; -import { appEventBus } from "../common/event-bus" +import { appEventBus } from "../common/event-bus"; export class NodeShellSession extends ShellSession { protected nodeName: string; - protected podId: string - protected kc: KubeConfig + protected podId: string; + protected kc: KubeConfig; constructor(socket: WebSocket, cluster: Cluster, nodeName: string) { - super(socket, cluster) - this.nodeName = nodeName - this.podId = `node-shell-${uuid()}` - this.kc = cluster.getProxyKubeconfig() + super(socket, cluster); + this.nodeName = nodeName; + this.podId = `node-shell-${uuid()}`; + this.kc = cluster.getProxyKubeconfig(); } public async open() { - const shell = await this.kubectl.getPath() - let args = [] + const shell = await this.kubectl.getPath(); + let args = []; if (this.createNodeShellPod(this.podId, this.nodeName)) { await this.waitForRunningPod(this.podId).catch((error) => { - this.exit(1001) - }) + this.exit(1001); + }); } - args = ["exec", "-i", "-t", "-n", "kube-system", this.podId, "--", "sh", "-c", "((clear && bash) || (clear && ash) || (clear && sh))"] + args = ["exec", "-i", "-t", "-n", "kube-system", this.podId, "--", "sh", "-c", "((clear && bash) || (clear && ash) || (clear && sh))"]; - const shellEnv = await this.getCachedShellEnv() + const shellEnv = await this.getCachedShellEnv(); this.shellProcess = pty.spawn(shell, args, { cols: 80, cwd: this.cwd() || shellEnv["HOME"], @@ -39,19 +39,19 @@ export class NodeShellSession extends ShellSession { rows: 30, }); this.running = true; - this.pipeStdout() - this.pipeStdin() - this.closeWebsocketOnProcessExit() - this.exitProcessOnWebsocketClose() + this.pipeStdout(); + this.pipeStdin(); + this.closeWebsocketOnProcessExit(); + this.exitProcessOnWebsocketClose(); - appEventBus.emit({name: "node-shell", action: "open"}) + appEventBus.emit({name: "node-shell", action: "open"}); } protected exit(code = 1000) { if (this.podId) { - this.deleteNodeShellPod() + this.deleteNodeShellPod(); } - super.exit(code) + super.exit(code); } protected async createNodeShellPod(podId: string, nodeName: string) { @@ -86,19 +86,19 @@ export class NodeShellSession extends ShellSession { } } as k8s.V1Pod; await k8sApi.createNamespacedPod("kube-system", pod).catch((error) => { - logger.error(error) - return false - }) - return true + logger.error(error); + return false; + }); + return true; } protected getKubeConfig() { if (this.kc) { - return this.kc + return this.kc; } this.kc = new k8s.KubeConfig(); - this.kc.loadFromFile(this.kubeconfigPath) - return this.kc + this.kc.loadFromFile(this.kubeconfigPath); + return this.kc; } protected waitForRunningPod(podId: string) { @@ -110,36 +110,36 @@ export class NodeShellSession extends ShellSession { // callback is called for each received object. (_type, obj) => { if (obj.metadata.name == podId && obj.status.phase === "Running") { - resolve(true) + resolve(true); } }, // done callback is called if the watch terminates normally (err) => { - logger.error(err) - reject(false) + logger.error(err); + reject(false); } ); setTimeout(() => { req.abort(); reject(false); }, 120 * 1000); - }) + }); } protected deleteNodeShellPod() { const kc = this.getKubeConfig(); const k8sApi = kc.makeApiClient(k8s.CoreV1Api); - k8sApi.deleteNamespacedPod(this.podId, "kube-system") + k8sApi.deleteNamespacedPod(this.podId, "kube-system"); } } export async function openShell(socket: WebSocket, cluster: Cluster, nodeName?: string): Promise { let shell: ShellSession; if (nodeName) { - shell = new NodeShellSession(socket, cluster, nodeName) + shell = new NodeShellSession(socket, cluster, nodeName); } else { shell = new ShellSession(socket, cluster); } - shell.open() + shell.open(); return shell; } diff --git a/src/main/port.ts b/src/main/port.ts index b253d3590a..6ba8f71695 100644 --- a/src/main/port.ts +++ b/src/main/port.ts @@ -1,15 +1,15 @@ -import net, { AddressInfo } from "net" -import logger from "./logger" +import net, { AddressInfo } from "net"; +import logger from "./logger"; // todo: check https://github.com/http-party/node-portfinder ? export async function getFreePort(): Promise { logger.debug("Lookup new free port.."); return new Promise((resolve, reject) => { - const server = net.createServer() - server.unref() + const server = net.createServer(); + server.unref(); server.on("listening", () => { - const port = (server.address() as AddressInfo).port + const port = (server.address() as AddressInfo).port; server.close(() => resolve(port)); logger.debug(`New port found: ${port}`); }); @@ -17,6 +17,6 @@ export async function getFreePort(): Promise { logger.error(`Can't resolve new port: "${error}"`); reject(error); }); - server.listen({ host: "127.0.0.1", port: 0 }) - }) + server.listen({ host: "127.0.0.1", port: 0 }); + }); } diff --git a/src/main/port_spec.ts b/src/main/port_spec.ts index c9be25e514..bf01eb5dde 100644 --- a/src/main/port_spec.ts +++ b/src/main/port_spec.ts @@ -1,5 +1,5 @@ -import { EventEmitter } from 'events' -import { getFreePort } from "./port" +import { EventEmitter } from 'events'; +import { getFreePort } from "./port"; let newPort = 0; @@ -8,24 +8,24 @@ jest.mock("net", () => { createServer() { return new class MockServer extends EventEmitter { listen = jest.fn(() => { - this.emit('listening') - return this - }) + this.emit('listening'); + return this; + }); address = () => { - newPort = Math.round(Math.random() * 10000) + newPort = Math.round(Math.random() * 10000); return { port: newPort - } - } - unref = jest.fn() - close = jest.fn(cb => cb()) - } + }; + }; + unref = jest.fn(); + close = jest.fn(cb => cb()); + }; }, - } + }; }); describe("getFreePort", () => { it("finds the next free port", async () => { return expect(getFreePort()).resolves.toEqual(newPort); - }) -}) + }); +}); diff --git a/src/main/prometheus/helm.ts b/src/main/prometheus/helm.ts index f1462931df..56d739c630 100644 --- a/src/main/prometheus/helm.ts +++ b/src/main/prometheus/helm.ts @@ -1,29 +1,29 @@ -import { PrometheusLens } from "./lens" -import { CoreV1Api } from "@kubernetes/client-node" +import { PrometheusLens } from "./lens"; +import { CoreV1Api } from "@kubernetes/client-node"; import { PrometheusService } from "./provider-registry"; -import logger from "../logger" +import logger from "../logger"; export class PrometheusHelm extends PrometheusLens { - id = "helm" - name = "Helm" - rateAccuracy = "5m" + id = "helm"; + name = "Helm"; + rateAccuracy = "5m"; public async getPrometheusService(client: CoreV1Api): Promise { - const labelSelector = "app=prometheus,component=server,heritage=Helm" + const labelSelector = "app=prometheus,component=server,heritage=Helm"; try { - const serviceList = await client.listServiceForAllNamespaces(false, "", null, labelSelector) - const service = serviceList.body.items[0] - if (!service) return + const serviceList = await client.listServiceForAllNamespaces(false, "", null, labelSelector); + const service = serviceList.body.items[0]; + if (!service) return; return { id: this.id, namespace: service.metadata.namespace, service: service.metadata.name, port: service.spec.ports[0].port - } + }; } catch(error) { - logger.warn(`PrometheusHelm: failed to list services: ${error.toString()}`) - return + logger.warn(`PrometheusHelm: failed to list services: ${error.toString()}`); + return; } } } diff --git a/src/main/prometheus/lens.ts b/src/main/prometheus/lens.ts index 4db70bf45d..76a459212d 100644 --- a/src/main/prometheus/lens.ts +++ b/src/main/prometheus/lens.ts @@ -1,24 +1,24 @@ import { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry"; import { CoreV1Api } from "@kubernetes/client-node"; -import logger from "../logger" +import logger from "../logger"; export class PrometheusLens implements PrometheusProvider { - id = "lens" - name = "Lens" - rateAccuracy = "1m" + id = "lens"; + name = "Lens"; + rateAccuracy = "1m"; public async getPrometheusService(client: CoreV1Api): Promise { try { - const resp = await client.readNamespacedService("prometheus", "lens-metrics") - const service = resp.body + const resp = await client.readNamespacedService("prometheus", "lens-metrics"); + const service = resp.body; return { id: this.id, namespace: service.metadata.namespace, service: service.metadata.name, port: service.spec.ports[0].port - } + }; } catch(error) { - logger.warn(`PrometheusLens: failed to list services: ${error.response.body.message}`) + logger.warn(`PrometheusLens: failed to list services: ${error.response.body.message}`); } } @@ -42,7 +42,7 @@ export class PrometheusLens implements PrometheusProvider { podCapacity: `sum(kube_node_status_capacity{node=~"${opts.nodes}", resource="pods"}) by (component)`, fsSize: `sum(node_filesystem_size_bytes{kubernetes_node=~"${opts.nodes}", mountpoint="/"}) by (kubernetes_node)`, fsUsage: `sum(node_filesystem_size_bytes{kubernetes_node=~"${opts.nodes}", mountpoint="/"} - node_filesystem_avail_bytes{kubernetes_node=~"${opts.nodes}", mountpoint="/"}) by (kubernetes_node)` - } + }; case 'nodes': return { memoryUsage: `sum (node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) by (kubernetes_node)`, @@ -51,7 +51,7 @@ export class PrometheusLens implements PrometheusProvider { cpuCapacity: `sum(kube_node_status_allocatable{resource="cpu"}) by (node)`, fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"}) by (kubernetes_node)`, fsUsage: `sum(node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) by (kubernetes_node)` - } + }; case 'pods': return { cpuUsage: `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, @@ -63,21 +63,21 @@ export class PrometheusLens implements PrometheusProvider { fsUsage: `sum(container_fs_usage_bytes{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}) by (${opts.selector})`, networkReceive: `sum(rate(container_network_receive_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, networkTransmit: `sum(rate(container_network_transmit_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})` - } + }; case 'pvc': return { diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`, diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)` - } + }; case 'ingress': const bytesSent = (ingress: string, statuses: string) => - `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)` + `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`; return { bytesSentSuccess: bytesSent(opts.igress, "^2\\\\d*"), bytesSentFailure: bytesSent(opts.ingres, "^5\\\\d*"), requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`, responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)` - } + }; } } } diff --git a/src/main/prometheus/operator.ts b/src/main/prometheus/operator.ts index 3d335ff554..8e27a4a6f3 100644 --- a/src/main/prometheus/operator.ts +++ b/src/main/prometheus/operator.ts @@ -3,30 +3,30 @@ import { CoreV1Api, V1Service } from "@kubernetes/client-node"; import logger from "../logger"; export class PrometheusOperator implements PrometheusProvider { - rateAccuracy = "1m" - id = "operator" - name = "Prometheus Operator" + rateAccuracy = "1m"; + id = "operator"; + name = "Prometheus Operator"; public async getPrometheusService(client: CoreV1Api): Promise { try { - let service: V1Service + let service: V1Service; for (const labelSelector of ["operated-prometheus=true", "self-monitor=true"]) { if (!service) { - const serviceList = await client.listServiceForAllNamespaces(null, null, null, labelSelector) - service = serviceList.body.items[0] + const serviceList = await client.listServiceForAllNamespaces(null, null, null, labelSelector); + service = serviceList.body.items[0]; } } - if (!service) return + if (!service) return; return { id: this.id, namespace: service.metadata.namespace, service: service.metadata.name, port: service.spec.ports[0].port - } + }; } catch(error) { - logger.warn(`PrometheusOperator: failed to list services: ${error.toString()}`) - return + logger.warn(`PrometheusOperator: failed to list services: ${error.toString()}`); + return; } } @@ -50,7 +50,7 @@ export class PrometheusOperator implements PrometheusProvider { podCapacity: `sum(kube_node_status_capacity{node=~"${opts.nodes}", resource="pods"})`, fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"})`, fsUsage: `sum(node_filesystem_size_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"} - node_filesystem_avail_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"})` - } + }; case 'nodes': return { memoryUsage: `sum((node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) * on (pod,namespace) group_left(node) kube_pod_info) by (node)`, @@ -59,7 +59,7 @@ export class PrometheusOperator implements PrometheusProvider { cpuCapacity: `sum(kube_node_status_allocatable{resource="cpu"}) by (node)`, fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info) by (node)`, fsUsage: `sum((node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) * on (pod,namespace) group_left(node) kube_pod_info) by (node)` - } + }; case 'pods': return { cpuUsage: `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",image!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, @@ -71,12 +71,12 @@ export class PrometheusOperator implements PrometheusProvider { fsUsage: `sum(container_fs_usage_bytes{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}) by (${opts.selector})`, networkReceive: `sum(rate(container_network_receive_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, networkTransmit: `sum(rate(container_network_transmit_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})` - } + }; case 'pvc': return { diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`, diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)` - } + }; case 'ingress': const bytesSent = (ingress: string, statuses: string) => `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`; @@ -85,7 +85,7 @@ export class PrometheusOperator implements PrometheusProvider { bytesSentFailure: bytesSent(opts.ingres, "^5\\\\d*"), requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`, responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)` - } + }; } } } diff --git a/src/main/prometheus/provider-registry.ts b/src/main/prometheus/provider-registry.ts index 0a4eb22e95..641b1b8cf2 100644 --- a/src/main/prometheus/provider-registry.ts +++ b/src/main/prometheus/provider-registry.ts @@ -1,4 +1,4 @@ -import { CoreV1Api } from "@kubernetes/client-node" +import { CoreV1Api } from "@kubernetes/client-node"; export type PrometheusClusterQuery = { memoryUsage: string; @@ -11,7 +11,7 @@ export type PrometheusClusterQuery = { cpuCapacity: string; podUsage: string; podCapacity: string; -} +}; export type PrometheusNodeQuery = { memoryUsage: string; @@ -20,7 +20,7 @@ export type PrometheusNodeQuery = { cpuCapacity: string; fsSize: string; fsUsage: string; -} +}; export type PrometheusPodQuery = { memoryUsage: string; @@ -32,32 +32,32 @@ export type PrometheusPodQuery = { fsUsage: string; networkReceive: string; networkTransmit: string; -} +}; export type PrometheusPvcQuery = { diskUsage: string; diskCapacity: string; -} +}; export type PrometheusIngressQuery = { bytesSentSuccess: string; bytesSentFailure: string; requestDurationSeconds: string; responseDurationSeconds: string; -} +}; export type PrometheusQueryOpts = { [key: string]: string | any; }; -export type PrometheusQuery = PrometheusNodeQuery | PrometheusClusterQuery | PrometheusPodQuery | PrometheusPvcQuery | PrometheusIngressQuery +export type PrometheusQuery = PrometheusNodeQuery | PrometheusClusterQuery | PrometheusPodQuery | PrometheusPvcQuery | PrometheusIngressQuery; export type PrometheusService = { id: string; namespace: string; service: string; port: number; -} +}; export interface PrometheusProvider { id: string; @@ -68,23 +68,23 @@ export interface PrometheusProvider { export type PrometheusProviderList = { [key: string]: PrometheusProvider; -} +}; export class PrometheusProviderRegistry { - private static prometheusProviders: PrometheusProviderList = {} + private static prometheusProviders: PrometheusProviderList = {}; static getProvider(type: string): PrometheusProvider { if (!this.prometheusProviders[type]) { throw "Unknown Prometheus provider"; } - return this.prometheusProviders[type] + return this.prometheusProviders[type]; } static registerProvider(key: string, provider: PrometheusProvider) { - this.prometheusProviders[key] = provider + this.prometheusProviders[key] = provider; } static getProviders(): PrometheusProvider[] { - return Object.values(this.prometheusProviders) + return Object.values(this.prometheusProviders); } } diff --git a/src/main/prometheus/stacklight.ts b/src/main/prometheus/stacklight.ts index 4cb946c81d..35394336d3 100644 --- a/src/main/prometheus/stacklight.ts +++ b/src/main/prometheus/stacklight.ts @@ -1,24 +1,24 @@ import { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry"; import { CoreV1Api } from "@kubernetes/client-node"; -import logger from "../logger" +import logger from "../logger"; export class PrometheusStacklight implements PrometheusProvider { - id = "stacklight" - name = "Stacklight" - rateAccuracy = "1m" + id = "stacklight"; + name = "Stacklight"; + rateAccuracy = "1m"; public async getPrometheusService(client: CoreV1Api): Promise { try { - const resp = await client.readNamespacedService("prometheus-server", "stacklight") - const service = resp.body + const resp = await client.readNamespacedService("prometheus-server", "stacklight"); + const service = resp.body; return { id: this.id, namespace: service.metadata.namespace, service: service.metadata.name, port: service.spec.ports[0].port - } + }; } catch(error) { - logger.warn(`PrometheusLens: failed to list services: ${error.response.body.message}`) + logger.warn(`PrometheusLens: failed to list services: ${error.response.body.message}`); } } @@ -42,7 +42,7 @@ export class PrometheusStacklight implements PrometheusProvider { podCapacity: `sum(kube_node_status_capacity{node=~"${opts.nodes}", resource="pods"}) by (component)`, fsSize: `sum(node_filesystem_size_bytes{node=~"${opts.nodes}", mountpoint="/"}) by (node)`, fsUsage: `sum(node_filesystem_size_bytes{node=~"${opts.nodes}", mountpoint="/"} - node_filesystem_avail_bytes{node=~"${opts.nodes}", mountpoint="/"}) by (node)` - } + }; case 'nodes': return { memoryUsage: `sum (node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) by (node)`, @@ -51,7 +51,7 @@ export class PrometheusStacklight implements PrometheusProvider { cpuCapacity: `sum(kube_node_status_allocatable{resource="cpu"}) by (node)`, fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"}) by (node)`, fsUsage: `sum(node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) by (node)` - } + }; case 'pods': return { cpuUsage: `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, @@ -63,21 +63,21 @@ export class PrometheusStacklight implements PrometheusProvider { fsUsage: `sum(container_fs_usage_bytes{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}) by (${opts.selector})`, networkReceive: `sum(rate(container_network_receive_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, networkTransmit: `sum(rate(container_network_transmit_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})` - } + }; case 'pvc': return { diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`, diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)` - } + }; case 'ingress': const bytesSent = (ingress: string, statuses: string) => - `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)` + `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`; return { bytesSentSuccess: bytesSent(opts.igress, "^2\\\\d*"), bytesSentFailure: bytesSent(opts.ingres, "^5\\\\d*"), requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`, responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)` - } + }; } } } diff --git a/src/main/promise-exec.ts b/src/main/promise-exec.ts index b3bc303165..426bca4c23 100644 --- a/src/main/promise-exec.ts +++ b/src/main/promise-exec.ts @@ -1,4 +1,4 @@ -import * as util from "util" +import * as util from "util"; import { exec } from "child_process"; -export const promiseExec = util.promisify(exec) +export const promiseExec = util.promisify(exec); diff --git a/src/main/proxy-env.ts b/src/main/proxy-env.ts index 04c62ef534..51c8286a7f 100644 --- a/src/main/proxy-env.ts +++ b/src/main/proxy-env.ts @@ -1,18 +1,18 @@ -import { app } from "electron" +import { app } from "electron"; -const switchValue = app.commandLine.getSwitchValue("proxy-server") +const switchValue = app.commandLine.getSwitchValue("proxy-server"); export function mangleProxyEnv() { - let httpsProxy = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || "" + let httpsProxy = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || ""; - delete process.env.HTTPS_PROXY - delete process.env.HTTP_PROXY + delete process.env.HTTPS_PROXY; + delete process.env.HTTP_PROXY; if (switchValue !== "") { - httpsProxy = switchValue + httpsProxy = switchValue; } if (httpsProxy !== "") { - process.env.APP_HTTPS_PROXY = httpsProxy + process.env.APP_HTTPS_PROXY = httpsProxy; } } diff --git a/src/main/resource-applier.ts b/src/main/resource-applier.ts index 41441a3f90..0f4647a60f 100644 --- a/src/main/resource-applier.ts +++ b/src/main/resource-applier.ts @@ -1,12 +1,12 @@ import type { Cluster } from "./cluster"; -import { KubernetesObject } from "@kubernetes/client-node" +import { KubernetesObject } from "@kubernetes/client-node"; import { exec } from "child_process"; import fs from "fs"; import * as yaml from "js-yaml"; import path from "path"; import * as tempy from "tempy"; -import logger from "./logger" -import { appEventBus } from "../common/event-bus" +import logger from "./logger"; +import { appEventBus } from "../common/event-bus"; import { cloneJsonObject } from "../common/utils"; export class ResourceApplier { @@ -15,58 +15,58 @@ export class ResourceApplier { async apply(resource: KubernetesObject | any): Promise { resource = this.sanitizeObject(resource); - appEventBus.emit({name: "resource", action: "apply"}) + appEventBus.emit({name: "resource", action: "apply"}); return await this.kubectlApply(yaml.safeDump(resource)); } protected async kubectlApply(content: string): Promise { const { kubeCtl } = this.cluster; - const kubectlPath = await kubeCtl.getPath() + const kubectlPath = await kubeCtl.getPath(); return new Promise((resolve, reject) => { - const fileName = tempy.file({ name: "resource.yaml" }) - fs.writeFileSync(fileName, content) - const cmd = `"${kubectlPath}" apply --kubeconfig "${this.cluster.getProxyKubeconfigPath()}" -o json -f "${fileName}"` + const fileName = tempy.file({ name: "resource.yaml" }); + fs.writeFileSync(fileName, content); + const cmd = `"${kubectlPath}" apply --kubeconfig "${this.cluster.getProxyKubeconfigPath()}" -o json -f "${fileName}"`; logger.debug("shooting manifests with: " + cmd); - const execEnv: NodeJS.ProcessEnv = Object.assign({}, process.env) - const httpsProxy = this.cluster.preferences?.httpsProxy + const execEnv: NodeJS.ProcessEnv = Object.assign({}, process.env); + const httpsProxy = this.cluster.preferences?.httpsProxy; if (httpsProxy) { - execEnv["HTTPS_PROXY"] = httpsProxy + execEnv["HTTPS_PROXY"] = httpsProxy; } exec(cmd, { env: execEnv }, (error, stdout, stderr) => { if (stderr != "") { - fs.unlinkSync(fileName) - reject(stderr) - return + fs.unlinkSync(fileName); + reject(stderr); + return; } - fs.unlinkSync(fileName) - resolve(JSON.parse(stdout)) - }) - }) + fs.unlinkSync(fileName); + resolve(JSON.parse(stdout)); + }); + }); } public async kubectlApplyAll(resources: string[]): Promise { const { kubeCtl } = this.cluster; - const kubectlPath = await kubeCtl.getPath() + const kubectlPath = await kubeCtl.getPath(); return new Promise((resolve, reject) => { - const tmpDir = tempy.directory() + const tmpDir = tempy.directory(); // Dump each resource into tmpDir resources.forEach((resource, index) => { fs.writeFileSync(path.join(tmpDir, `${index}.yaml`), resource); - }) - const cmd = `"${kubectlPath}" apply --kubeconfig "${this.cluster.getProxyKubeconfigPath()}" -o json -f "${tmpDir}"` + }); + const cmd = `"${kubectlPath}" apply --kubeconfig "${this.cluster.getProxyKubeconfigPath()}" -o json -f "${tmpDir}"`; console.log("shooting manifests with:", cmd); exec(cmd, (error, stdout, stderr) => { if (error) { reject("Error applying manifests:" + error); } if (stderr != "") { - reject(stderr) - return + reject(stderr); + return; } - resolve(stdout) - }) - }) + resolve(stdout); + }); + }); } protected sanitizeObject(resource: KubernetesObject | any) { diff --git a/src/main/router.ts b/src/main/router.ts index 230c93f09e..ed072836b9 100644 --- a/src/main/router.ts +++ b/src/main/router.ts @@ -1,12 +1,12 @@ -import Call from "@hapi/call" -import Subtext from "@hapi/subtext" -import http from "http" -import path from "path" -import { readFile } from "fs-extra" -import { Cluster } from "./cluster" +import Call from "@hapi/call"; +import Subtext from "@hapi/subtext"; +import http from "http"; +import path from "path"; +import { readFile } from "fs-extra"; +import { Cluster } from "./cluster"; import { apiPrefix, appName, publicPath, isDevelopment, webpackDevServerPort } from "../common/vars"; import { helmRoute, kubeconfigRoute, metricsRoute, portForwardRoute, resourceApplierRoute, watchRoute } from "./routes"; -import logger from "./logger" +import logger from "./logger"; export interface RouterRequestOpts { req: http.IncomingMessage; @@ -43,25 +43,25 @@ export class Router { public constructor() { this.router = new Call.Router(); - this.addRoutes() + this.addRoutes(); } public async route(cluster: Cluster, req: http.IncomingMessage, res: http.ServerResponse): Promise { const url = new URL(req.url, "http://localhost"); - const path = url.pathname - const method = req.method.toLowerCase() + const path = url.pathname; + const method = req.method.toLowerCase(); const matchingRoute = this.router.route(method, path); const routeFound = !matchingRoute.isBoom; if (routeFound) { const request = await this.getRequest({ req, res, cluster, url, params: matchingRoute.params }); - await matchingRoute.route(request) - return true + await matchingRoute.route(request); + return true; } return false; } protected async getRequest(opts: RouterRequestOpts): Promise { - const { req, res, url, cluster, params } = opts + const { req, res, url, cluster, params } = opts; const { payload } = await Subtext.parse(req, null, { parse: true, output: "data", @@ -76,7 +76,7 @@ export class Router { query: url.searchParams, payload: payload, params: params - } + }; } protected getMimeType(filename: string) { @@ -92,7 +92,7 @@ export class Router { woff2: "font/woff2", ttf: "font/ttf" }; - return mimeTypes[path.extname(filename).slice(1)] || "text/plain" + return mimeTypes[path.extname(filename).slice(1)] || "text/plain"; } async handleStaticFile(filePath: string, res: http.ServerResponse, req: http.IncomingMessage, retryCount = 0) { @@ -114,10 +114,10 @@ export class Router { res.end(); } catch (err) { if (retryCount > 5) { - logger.error("handleStaticFile:", err.toString()) - res.statusCode = 404 - res.end() - return + logger.error("handleStaticFile:", err.toString()); + res.statusCode = 404; + res.end(); + return; } this.handleStaticFile(`${publicPath}/${appName}.html`, res, req, Math.max(retryCount, 0) + 1); } @@ -131,32 +131,32 @@ export class Router { this.handleStaticFile(params.path, response, req); }); - this.router.add({ method: "get", path: `${apiPrefix}/kubeconfig/service-account/{namespace}/{account}` }, kubeconfigRoute.routeServiceAccountRoute.bind(kubeconfigRoute)) + this.router.add({ method: "get", path: `${apiPrefix}/kubeconfig/service-account/{namespace}/{account}` }, kubeconfigRoute.routeServiceAccountRoute.bind(kubeconfigRoute)); // Watch API - this.router.add({ method: "get", path: `${apiPrefix}/watch` }, watchRoute.routeWatch.bind(watchRoute)) + this.router.add({ method: "get", path: `${apiPrefix}/watch` }, watchRoute.routeWatch.bind(watchRoute)); // Metrics API - this.router.add({ method: "post", path: `${apiPrefix}/metrics` }, metricsRoute.routeMetrics.bind(metricsRoute)) + this.router.add({ method: "post", path: `${apiPrefix}/metrics` }, metricsRoute.routeMetrics.bind(metricsRoute)); // Port-forward API - this.router.add({ method: "post", path: `${apiPrefix}/pods/{namespace}/{resourceType}/{resourceName}/port-forward/{port}` }, portForwardRoute.routePortForward.bind(portForwardRoute)) + this.router.add({ method: "post", path: `${apiPrefix}/pods/{namespace}/{resourceType}/{resourceName}/port-forward/{port}` }, portForwardRoute.routePortForward.bind(portForwardRoute)); // Helm API - this.router.add({ method: "get", path: `${apiPrefix}/v2/charts` }, helmRoute.listCharts.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}` }, helmRoute.getChart.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}/values` }, helmRoute.getChartValues.bind(helmRoute)) + this.router.add({ method: "get", path: `${apiPrefix}/v2/charts` }, helmRoute.listCharts.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}` }, helmRoute.getChart.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}/values` }, helmRoute.getChartValues.bind(helmRoute)); - this.router.add({ method: "post", path: `${apiPrefix}/v2/releases` }, helmRoute.installChart.bind(helmRoute)) - this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.updateRelease.bind(helmRoute)) - this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}/rollback` }, helmRoute.rollbackRelease.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace?}` }, helmRoute.listReleases.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.getRelease.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/values` }, helmRoute.getReleaseValues.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/history` }, helmRoute.getReleaseHistory.bind(helmRoute)) - this.router.add({ method: "delete", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.deleteRelease.bind(helmRoute)) + this.router.add({ method: "post", path: `${apiPrefix}/v2/releases` }, helmRoute.installChart.bind(helmRoute)); + this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.updateRelease.bind(helmRoute)); + this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}/rollback` }, helmRoute.rollbackRelease.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace?}` }, helmRoute.listReleases.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.getRelease.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/values` }, helmRoute.getReleaseValues.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/history` }, helmRoute.getReleaseHistory.bind(helmRoute)); + this.router.add({ method: "delete", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.deleteRelease.bind(helmRoute)); // Resource Applier API - this.router.add({ method: "post", path: `${apiPrefix}/stack` }, resourceApplierRoute.applyResource.bind(resourceApplierRoute)) + this.router.add({ method: "post", path: `${apiPrefix}/stack` }, resourceApplierRoute.applyResource.bind(resourceApplierRoute)); } } diff --git a/src/main/routes/helm-route.ts b/src/main/routes/helm-route.ts index 0ffd7252d5..853f8ddded 100644 --- a/src/main/routes/helm-route.ts +++ b/src/main/routes/helm-route.ts @@ -1,114 +1,114 @@ -import { LensApiRequest } from "../router" -import { helmService } from "../helm/helm-service" -import { LensApi } from "../lens-api" -import logger from "../logger" +import { LensApiRequest } from "../router"; +import { helmService } from "../helm/helm-service"; +import { LensApi } from "../lens-api"; +import logger from "../logger"; class HelmApiRoute extends LensApi { public async listCharts(request: LensApiRequest) { - const { response } = request - const charts = await helmService.listCharts() - this.respondJson(response, charts) + const { response } = request; + const charts = await helmService.listCharts(); + this.respondJson(response, charts); } public async getChart(request: LensApiRequest) { - const { params, query, response } = request - const chart = await helmService.getChart(params.repo, params.chart, query.get("version")) - this.respondJson(response, chart) + const { params, query, response } = request; + const chart = await helmService.getChart(params.repo, params.chart, query.get("version")); + this.respondJson(response, chart); } public async getChartValues(request: LensApiRequest) { - const { params, query, response } = request - const values = await helmService.getChartValues(params.repo, params.chart, query.get("version")) - this.respondJson(response, values) + const { params, query, response } = request; + const values = await helmService.getChartValues(params.repo, params.chart, query.get("version")); + this.respondJson(response, values); } public async installChart(request: LensApiRequest) { - const { payload, cluster, response } = request + const { payload, cluster, response } = request; try { - const result = await helmService.installChart(cluster, payload) - this.respondJson(response, result, 201) + const result = await helmService.installChart(cluster, payload); + this.respondJson(response, result, 201); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } public async updateRelease(request: LensApiRequest) { - const { cluster, params, payload, response } = request + const { cluster, params, payload, response } = request; try { - const result = await helmService.updateRelease(cluster, params.release, params.namespace, payload ) - this.respondJson(response, result) + const result = await helmService.updateRelease(cluster, params.release, params.namespace, payload ); + this.respondJson(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } public async rollbackRelease(request: LensApiRequest) { - const { cluster, params, payload, response } = request + const { cluster, params, payload, response } = request; try { - const result = await helmService.rollback(cluster, params.release, params.namespace, payload.revision) - this.respondJson(response, result) + const result = await helmService.rollback(cluster, params.release, params.namespace, payload.revision); + this.respondJson(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error) + logger.debug(error); + this.respondText(response, error); } } public async listReleases(request: LensApiRequest) { - const { cluster, params, response } = request + const { cluster, params, response } = request; try { - const result = await helmService.listReleases(cluster, params.namespace) - this.respondJson(response, result) + const result = await helmService.listReleases(cluster, params.namespace); + this.respondJson(response, result); } catch(error) { - logger.debug(error) - this.respondText(response, error) + logger.debug(error); + this.respondText(response, error); } } public async getRelease(request: LensApiRequest) { - const { cluster, params, response } = request + const { cluster, params, response } = request; try { - const result = await helmService.getRelease(cluster, params.release, params.namespace) - this.respondJson(response, result) + const result = await helmService.getRelease(cluster, params.release, params.namespace); + this.respondJson(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } public async getReleaseValues(request: LensApiRequest) { - const { cluster, params, response } = request + const { cluster, params, response } = request; try { - const result = await helmService.getReleaseValues(cluster, params.release, params.namespace) - this.respondText(response, result) + const result = await helmService.getReleaseValues(cluster, params.release, params.namespace); + this.respondText(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } public async getReleaseHistory(request: LensApiRequest) { - const { cluster, params, response } = request + const { cluster, params, response } = request; try { - const result = await helmService.getReleaseHistory(cluster, params.release, params.namespace) - this.respondJson(response, result) + const result = await helmService.getReleaseHistory(cluster, params.release, params.namespace); + this.respondJson(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } public async deleteRelease(request: LensApiRequest) { - const { cluster, params, response } = request + const { cluster, params, response } = request; try { - const result = await helmService.deleteRelease(cluster, params.release, params.namespace) - this.respondJson(response, result) + const result = await helmService.deleteRelease(cluster, params.release, params.namespace); + this.respondJson(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } } -export const helmRoute = new HelmApiRoute() +export const helmRoute = new HelmApiRoute(); diff --git a/src/main/routes/index.ts b/src/main/routes/index.ts index 60a0423de4..5bc5b3f3dd 100644 --- a/src/main/routes/index.ts +++ b/src/main/routes/index.ts @@ -1,6 +1,6 @@ -export * from "./kubeconfig-route" -export * from "./metrics-route" -export * from "./port-forward-route" -export * from "./watch-route" -export * from "./helm-route" -export * from "./resource-applier-route" +export * from "./kubeconfig-route"; +export * from "./metrics-route"; +export * from "./port-forward-route"; +export * from "./watch-route"; +export * from "./helm-route"; +export * from "./resource-applier-route"; diff --git a/src/main/routes/kubeconfig-route.ts b/src/main/routes/kubeconfig-route.ts index 09f1f061cf..1c04b9525d 100644 --- a/src/main/routes/kubeconfig-route.ts +++ b/src/main/routes/kubeconfig-route.ts @@ -1,10 +1,10 @@ -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { Cluster } from "../cluster" -import { CoreV1Api, V1Secret } from "@kubernetes/client-node" +import { LensApiRequest } from "../router"; +import { LensApi } from "../lens-api"; +import { Cluster } from "../cluster"; +import { CoreV1Api, V1Secret } from "@kubernetes/client-node"; function generateKubeConfig(username: string, secret: V1Secret, cluster: Cluster) { - const tokenData = Buffer.from(secret.data["token"], "base64") + const tokenData = Buffer.from(secret.data["token"], "base64"); return { 'apiVersion': 'v1', 'kind': 'Config', @@ -36,23 +36,23 @@ function generateKubeConfig(username: string, secret: V1Secret, cluster: Cluster } ], 'current-context': cluster.contextName - } + }; } class KubeconfigRoute extends LensApi { public async routeServiceAccountRoute(request: LensApiRequest) { - const { params, response, cluster} = request + const { params, response, cluster} = request; const client = cluster.getProxyKubeconfig().makeApiClient(CoreV1Api); - const secretList = await client.listNamespacedSecret(params.namespace) + const secretList = await client.listNamespacedSecret(params.namespace); const secret = secretList.body.items.find(secret => { const { annotations } = secret.metadata; return annotations && annotations["kubernetes.io/service-account.name"] == params.account; }); const data = generateKubeConfig(params.account, secret, cluster); - this.respondJson(response, data) + this.respondJson(response, data); } } -export const kubeconfigRoute = new KubeconfigRoute() +export const kubeconfigRoute = new KubeconfigRoute(); diff --git a/src/main/routes/metrics-route.ts b/src/main/routes/metrics-route.ts index dc77f7fb9f..254abe188f 100644 --- a/src/main/routes/metrics-route.ts +++ b/src/main/routes/metrics-route.ts @@ -1,32 +1,32 @@ -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { Cluster } from "../cluster" -import _ from "lodash" +import { LensApiRequest } from "../router"; +import { LensApi } from "../lens-api"; +import { Cluster } from "../cluster"; +import _ from "lodash"; export type IMetricsQuery = string | string[] | { [metricName: string]: string; -} +}; // This is used for backoff retry tracking. -const MAX_ATTEMPTS = 5 -const ATTEMPTS = [...(_.fill(Array(MAX_ATTEMPTS - 1), false)), true] +const MAX_ATTEMPTS = 5; +const ATTEMPTS = [...(_.fill(Array(MAX_ATTEMPTS - 1), false)), true]; // prometheus metrics loader async function loadMetrics(promQueries: string[], cluster: Cluster, prometheusPath: string, queryParams: Record): Promise { - const queries = promQueries.map(p => p.trim()) - const loaders = new Map>() + const queries = promQueries.map(p => p.trim()); + const loaders = new Map>(); async function loadMetric(query: string): Promise { async function loadMetricHelper(): Promise { for (const [attempt, lastAttempt] of ATTEMPTS.entries()) { // retry try { - return await cluster.getMetrics(prometheusPath, { query, ...queryParams }) + return await cluster.getMetrics(prometheusPath, { query, ...queryParams }); } catch (error) { if (lastAttempt || error?.statusCode === 404) { return { status: error.toString(), data: { result: [] }, - } + }; } await new Promise(resolve => setTimeout(resolve, (attempt + 1) * 1000)); // add delay before repeating request @@ -34,41 +34,41 @@ async function loadMetrics(promQueries: string[], cluster: Cluster, prometheusPa } } - return loaders.get(query) ?? loaders.set(query, loadMetricHelper()).get(query) + return loaders.get(query) ?? loaders.set(query, loadMetricHelper()).get(query); } - return Promise.all(queries.map(loadMetric)) + return Promise.all(queries.map(loadMetric)); } class MetricsRoute extends LensApi { async routeMetrics({ response, cluster, payload, query }: LensApiRequest) { - const queryParams: IMetricsQuery = Object.fromEntries(query.entries()) + const queryParams: IMetricsQuery = Object.fromEntries(query.entries()); try { const [prometheusPath, prometheusProvider] = await Promise.all([ cluster.contextHandler.getPrometheusPath(), cluster.contextHandler.getPrometheusProvider() - ]) + ]); // return data in same structure as query if (typeof payload === "string") { - const [data] = await loadMetrics([payload], cluster, prometheusPath, queryParams) - this.respondJson(response, data) + const [data] = await loadMetrics([payload], cluster, prometheusPath, queryParams); + this.respondJson(response, data); } else if (Array.isArray(payload)) { - const data = await loadMetrics(payload, cluster, prometheusPath, queryParams) - this.respondJson(response, data) + const data = await loadMetrics(payload, cluster, prometheusPath, queryParams); + this.respondJson(response, data); } else { const queries = Object.entries(payload).map(([queryName, queryOpts]) => ( (prometheusProvider.getQueries(queryOpts) as Record)[queryName] - )) - const result = await loadMetrics(queries, cluster, prometheusPath, queryParams) - const data = Object.fromEntries(Object.keys(payload).map((metricName, i) => [metricName, result[i]])) - this.respondJson(response, data) + )); + const result = await loadMetrics(queries, cluster, prometheusPath, queryParams); + const data = Object.fromEntries(Object.keys(payload).map((metricName, i) => [metricName, result[i]])); + this.respondJson(response, data); } } catch { - this.respondJson(response, {}) + this.respondJson(response, {}); } } } -export const metricsRoute = new MetricsRoute() +export const metricsRoute = new MetricsRoute(); diff --git a/src/main/routes/port-forward-route.ts b/src/main/routes/port-forward-route.ts index 7ed79aa936..55402ff72f 100644 --- a/src/main/routes/port-forward-route.ts +++ b/src/main/routes/port-forward-route.ts @@ -1,14 +1,14 @@ -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { spawn, ChildProcessWithoutNullStreams } from "child_process" -import { Kubectl } from "../kubectl" -import { getFreePort } from "../port" -import { shell } from "electron" -import * as tcpPortUsed from "tcp-port-used" -import logger from "../logger" +import { LensApiRequest } from "../router"; +import { LensApi } from "../lens-api"; +import { spawn, ChildProcessWithoutNullStreams } from "child_process"; +import { Kubectl } from "../kubectl"; +import { getFreePort } from "../port"; +import { shell } from "electron"; +import * as tcpPortUsed from "tcp-port-used"; +import logger from "../logger"; class PortForward { - public static portForwards: PortForward[] = [] + public static portForwards: PortForward[] = []; static getPortforward(forward: {clusterId: string; kind: string; name: string; namespace: string; port: string}) { return PortForward.portForwards.find((pf) => { @@ -18,70 +18,70 @@ class PortForward { pf.name == forward.name && pf.namespace == forward.namespace && pf.port == forward.port - ) - }) + ); + }); } - public clusterId: string - public process: ChildProcessWithoutNullStreams - public kubeConfig: string - public kind: string - public namespace: string - public name: string - public port: string - public localPort: number + public clusterId: string; + public process: ChildProcessWithoutNullStreams; + public kubeConfig: string; + public kind: string; + public namespace: string; + public name: string; + public port: string; + public localPort: number; constructor(obj: any) { - Object.assign(this, obj) + Object.assign(this, obj); } public async start() { - this.localPort = await getFreePort() - const kubectlBin = await Kubectl.bundled().getPath() + this.localPort = await getFreePort(); + const kubectlBin = await Kubectl.bundled().getPath(); const args = [ "--kubeconfig", this.kubeConfig, "port-forward", "-n", this.namespace, `${this.kind}/${this.name}`, `${this.localPort}:${this.port}` - ] + ]; this.process = spawn(kubectlBin, args, { env: process.env - }) - PortForward.portForwards.push(this) + }); + PortForward.portForwards.push(this); this.process.on("exit", () => { - const index = PortForward.portForwards.indexOf(this) + const index = PortForward.portForwards.indexOf(this); if (index > -1) { - PortForward.portForwards.splice(index, 1) + PortForward.portForwards.splice(index, 1); } - }) + }); try { - await tcpPortUsed.waitUntilUsed(this.localPort, 500, 15000) - return true + await tcpPortUsed.waitUntilUsed(this.localPort, 500, 15000); + return true; } catch (error) { - this.process.kill() - return false + this.process.kill(); + return false; } } public open() { - shell.openExternal(`http://localhost:${this.localPort}`) + shell.openExternal(`http://localhost:${this.localPort}`); } } class PortForwardRoute extends LensApi { public async routePortForward(request: LensApiRequest) { - const { params, response, cluster} = request - const { namespace, port, resourceType, resourceName } = params + const { params, response, cluster} = request; + const { namespace, port, resourceType, resourceName } = params; let portForward = PortForward.getPortforward({ clusterId: cluster.id, kind: resourceType, name: resourceName, namespace: namespace, port: port - }) + }); if (!portForward) { - logger.info(`Creating a new port-forward ${namespace}/${resourceType}/${resourceName}:${port}`) + logger.info(`Creating a new port-forward ${namespace}/${resourceType}/${resourceName}:${port}`); portForward = new PortForward({ clusterId: cluster.id, kind: resourceType, @@ -89,20 +89,20 @@ class PortForwardRoute extends LensApi { name: resourceName, port: port, kubeConfig: cluster.getProxyKubeconfigPath() - }) - const started = await portForward.start() + }); + const started = await portForward.start(); if (!started) { this.respondJson(response, { message: "Failed to open port-forward" - }, 400) - return + }, 400); + return; } } - portForward.open() + portForward.open(); - this.respondJson(response, {}) + this.respondJson(response, {}); } } -export const portForwardRoute = new PortForwardRoute() +export const portForwardRoute = new PortForwardRoute(); diff --git a/src/main/routes/resource-applier-route.ts b/src/main/routes/resource-applier-route.ts index 56125af8f3..8bbfec0d9c 100644 --- a/src/main/routes/resource-applier-route.ts +++ b/src/main/routes/resource-applier-route.ts @@ -1,17 +1,17 @@ -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { ResourceApplier } from "../resource-applier" +import { LensApiRequest } from "../router"; +import { LensApi } from "../lens-api"; +import { ResourceApplier } from "../resource-applier"; class ResourceApplierApiRoute extends LensApi { public async applyResource(request: LensApiRequest) { - const { response, cluster, payload } = request + const { response, cluster, payload } = request; try { const resource = await new ResourceApplier(cluster).apply(payload); - this.respondJson(response, [resource], 200) + this.respondJson(response, [resource], 200); } catch (error) { - this.respondText(response, error, 422) + this.respondText(response, error, 422); } } } -export const resourceApplierRoute = new ResourceApplierApiRoute() +export const resourceApplierRoute = new ResourceApplierApiRoute(); diff --git a/src/main/routes/watch-route.ts b/src/main/routes/watch-route.ts index d88276eaac..dd42460a9d 100644 --- a/src/main/routes/watch-route.ts +++ b/src/main/routes/watch-route.ts @@ -1,53 +1,53 @@ -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { Watch, KubeConfig } from "@kubernetes/client-node" -import { ServerResponse } from "http" -import { Request } from "request" -import logger from "../logger" +import { LensApiRequest } from "../router"; +import { LensApi } from "../lens-api"; +import { Watch, KubeConfig } from "@kubernetes/client-node"; +import { ServerResponse } from "http"; +import { Request } from "request"; +import logger from "../logger"; class ApiWatcher { - private apiUrl: string - private response: ServerResponse - private watchRequest: Request - private watch: Watch - private processor: NodeJS.Timeout - private eventBuffer: any[] = [] + private apiUrl: string; + private response: ServerResponse; + private watchRequest: Request; + private watch: Watch; + private processor: NodeJS.Timeout; + private eventBuffer: any[] = []; constructor(apiUrl: string, kubeConfig: KubeConfig, response: ServerResponse) { - this.apiUrl = apiUrl - this.watch = new Watch(kubeConfig) - this.response = response + this.apiUrl = apiUrl; + this.watch = new Watch(kubeConfig); + this.response = response; } public async start() { if (this.processor) { - clearInterval(this.processor) + clearInterval(this.processor); } this.processor = setInterval(() => { - const events = this.eventBuffer.splice(0) - events.map(event => this.sendEvent(event)) - this.response.flushHeaders() - }, 50) - this.watchRequest = await this.watch.watch(this.apiUrl, {}, this.watchHandler.bind(this), this.doneHandler.bind(this)) + const events = this.eventBuffer.splice(0); + events.map(event => this.sendEvent(event)); + this.response.flushHeaders(); + }, 50); + this.watchRequest = await this.watch.watch(this.apiUrl, {}, this.watchHandler.bind(this), this.doneHandler.bind(this)); } public stop() { - if (!this.watchRequest) { return } + if (!this.watchRequest) { return; } if (this.processor) { - clearInterval(this.processor) + clearInterval(this.processor); } - logger.debug("Stopping watcher for api: " + this.apiUrl) + logger.debug("Stopping watcher for api: " + this.apiUrl); try { - this.watchRequest.abort() + this.watchRequest.abort(); this.sendEvent({ type: "STREAM_END", url: this.apiUrl, status: 410, - }) - logger.debug("watch aborted") + }); + logger.debug("watch aborted"); } catch (error) { - logger.error("Watch abort errored:" + error) + logger.error("Watch abort errored:" + error); } } @@ -55,12 +55,12 @@ class ApiWatcher { this.eventBuffer.push({ type: phase, object: obj - }) + }); } private doneHandler(error: Error) { - if (error) logger.warn("watch ended: " + error.toString()) - this.watchRequest.abort() + if (error) logger.warn("watch ended: " + error.toString()); + this.watchRequest.abort(); } private sendEvent(evt: any) { @@ -72,40 +72,40 @@ class ApiWatcher { class WatchRoute extends LensApi { public async routeWatch(request: LensApiRequest) { - const { params, response, cluster} = request - const apis: string[] = request.query.getAll("api") - const watchers: ApiWatcher[] = [] + const { params, response, cluster} = request; + const apis: string[] = request.query.getAll("api"); + const watchers: ApiWatcher[] = []; if (!apis.length) { this.respondJson(response, { message: "Empty request. Query params 'api' are not provided.", example: "?api=/api/v1/pods&api=/api/v1/nodes", - }, 400) - return + }, 400); + return; } - response.setHeader("Content-Type", "text/event-stream") - response.setHeader("Cache-Control", "no-cache") - response.setHeader("Connection", "keep-alive") - logger.debug("watch using kubeconfig:" + JSON.stringify(cluster.getProxyKubeconfig(), null, 2)) + response.setHeader("Content-Type", "text/event-stream"); + response.setHeader("Cache-Control", "no-cache"); + response.setHeader("Connection", "keep-alive"); + logger.debug("watch using kubeconfig:" + JSON.stringify(cluster.getProxyKubeconfig(), null, 2)); apis.forEach(apiUrl => { - const watcher = new ApiWatcher(apiUrl, cluster.getProxyKubeconfig(), response) - watcher.start() - watchers.push(watcher) - }) + const watcher = new ApiWatcher(apiUrl, cluster.getProxyKubeconfig(), response); + watcher.start(); + watchers.push(watcher); + }); request.raw.req.on("close", () => { - logger.debug("Watch request closed") - watchers.map(watcher => watcher.stop()) - }) + logger.debug("Watch request closed"); + watchers.map(watcher => watcher.stop()); + }); request.raw.req.on("end", () => { - logger.debug("Watch request ended") - watchers.map(watcher => watcher.stop()) - }) + logger.debug("Watch request ended"); + watchers.map(watcher => watcher.stop()); + }); } } -export const watchRoute = new WatchRoute() +export const watchRoute = new WatchRoute(); diff --git a/src/main/shell-session.ts b/src/main/shell-session.ts index 6ea9e4eede..42e0039047 100644 --- a/src/main/shell-session.ts +++ b/src/main/shell-session.ts @@ -1,23 +1,23 @@ -import * as pty from "node-pty" -import * as WebSocket from "ws" +import * as pty from "node-pty"; +import * as WebSocket from "ws"; import { EventEmitter } from "events"; -import path from "path" -import shellEnv from "shell-env" -import { app } from "electron" -import { Kubectl } from "./kubectl" -import { Cluster } from "./cluster" +import path from "path"; +import shellEnv from "shell-env"; +import { app } from "electron"; +import { Kubectl } from "./kubectl"; +import { Cluster } from "./cluster"; import { ClusterPreferences } from "../common/cluster-store"; -import { helmCli } from "./helm/helm-cli" +import { helmCli } from "./helm/helm-cli"; import { isWindows } from "../common/vars"; -import { appEventBus } from "../common/event-bus" +import { appEventBus } from "../common/event-bus"; import { userStore } from "../common/user-store"; export class ShellSession extends EventEmitter { - static shellEnvs: Map = new Map() + static shellEnvs: Map = new Map(); - protected websocket: WebSocket - protected shellProcess: pty.IPty - protected kubeconfigPath: string + protected websocket: WebSocket; + protected shellProcess: pty.IPty; + protected kubeconfigPath: string; protected nodeShellPod: string; protected kubectl: Kubectl; protected kubectlBinDir: string; @@ -28,22 +28,22 @@ export class ShellSession extends EventEmitter { protected clusterId: string; constructor(socket: WebSocket, cluster: Cluster) { - super() - this.websocket = socket - this.kubeconfigPath = cluster.getProxyKubeconfigPath() - this.kubectl = new Kubectl(cluster.version) - this.preferences = cluster.preferences || {} - this.clusterId = cluster.id + super(); + this.websocket = socket; + this.kubeconfigPath = cluster.getProxyKubeconfigPath(); + this.kubectl = new Kubectl(cluster.version); + this.preferences = cluster.preferences || {}; + this.clusterId = cluster.id; } public async open() { - this.kubectlBinDir = await this.kubectl.binDir() - const pathFromPreferences = userStore.preferences.kubectlBinariesPath || this.kubectl.getBundledPath() - this.kubectlPathDir = userStore.preferences.downloadKubectlBinaries ? this.kubectlBinDir : path.dirname(pathFromPreferences) - this.helmBinDir = helmCli.getBinaryDir() - const env = await this.getCachedShellEnv() - const shell = env.PTYSHELL - const args = await this.getShellArgs(shell) + this.kubectlBinDir = await this.kubectl.binDir(); + const pathFromPreferences = userStore.preferences.kubectlBinariesPath || this.kubectl.getBundledPath(); + this.kubectlPathDir = userStore.preferences.downloadKubectlBinaries ? this.kubectlBinDir : path.dirname(pathFromPreferences); + this.helmBinDir = helmCli.getBinaryDir(); + const env = await this.getCachedShellEnv(); + const shell = env.PTYSHELL; + const args = await this.getShellArgs(shell); this.shellProcess = pty.spawn(shell, args, { cols: 80, cwd: this.cwd() || env.HOME, @@ -53,138 +53,138 @@ export class ShellSession extends EventEmitter { }); this.running = true; - this.pipeStdout() - this.pipeStdin() - this.closeWebsocketOnProcessExit() - this.exitProcessOnWebsocketClose() + this.pipeStdout(); + this.pipeStdin(); + this.closeWebsocketOnProcessExit(); + this.exitProcessOnWebsocketClose(); - appEventBus.emit({name: "shell", action: "open"}) + appEventBus.emit({name: "shell", action: "open"}); } protected cwd(): string { if(!this.preferences || !this.preferences.terminalCWD || this.preferences.terminalCWD === "") { - return null + return null; } - return this.preferences.terminalCWD + return this.preferences.terminalCWD; } protected async getShellArgs(shell: string): Promise> { switch(path.basename(shell)) { case "powershell.exe": - return ["-NoExit", "-command", `& {Set-Location $Env:USERPROFILE; $Env:PATH="${this.helmBinDir};${this.kubectlPathDir};$Env:PATH"}`] + return ["-NoExit", "-command", `& {Set-Location $Env:USERPROFILE; $Env:PATH="${this.helmBinDir};${this.kubectlPathDir};$Env:PATH"}`]; case "bash": - return ["--init-file", path.join(this.kubectlBinDir, '.bash_set_path')] + return ["--init-file", path.join(this.kubectlBinDir, '.bash_set_path')]; case "fish": - return ["--login", "--init-command", `export PATH="${this.helmBinDir}:${this.kubectlPathDir}:$PATH"; export KUBECONFIG="${this.kubeconfigPath}"`] + return ["--login", "--init-command", `export PATH="${this.helmBinDir}:${this.kubectlPathDir}:$PATH"; export KUBECONFIG="${this.kubeconfigPath}"`]; case "zsh": - return ["--login"] + return ["--login"]; default: - return [] + return []; } } protected async getCachedShellEnv() { - let env = ShellSession.shellEnvs.get(this.clusterId) + let env = ShellSession.shellEnvs.get(this.clusterId); if (!env) { - env = await this.getShellEnv() - ShellSession.shellEnvs.set(this.clusterId, env) + env = await this.getShellEnv(); + ShellSession.shellEnvs.set(this.clusterId, env); } else { // refresh env in the background this.getShellEnv().then((shellEnv: any) => { - ShellSession.shellEnvs.set(this.clusterId, shellEnv) - }) + ShellSession.shellEnvs.set(this.clusterId, shellEnv); + }); } - return env + return env; } protected async getShellEnv() { - const env = JSON.parse(JSON.stringify(await shellEnv())) - const pathStr = [this.kubectlBinDir, this.helmBinDir, process.env.PATH].join(path.delimiter) + const env = JSON.parse(JSON.stringify(await shellEnv())); + const pathStr = [this.kubectlBinDir, this.helmBinDir, process.env.PATH].join(path.delimiter); if(isWindows) { - env["SystemRoot"] = process.env.SystemRoot - env["PTYSHELL"] = "powershell.exe" - env["PATH"] = pathStr + env["SystemRoot"] = process.env.SystemRoot; + env["PTYSHELL"] = "powershell.exe"; + env["PATH"] = pathStr; } else if(typeof(process.env.SHELL) != "undefined") { - env["PTYSHELL"] = process.env.SHELL - env["PATH"] = pathStr + env["PTYSHELL"] = process.env.SHELL; + env["PATH"] = pathStr; } else { - env["PTYSHELL"] = "" // blank runs the system default shell + env["PTYSHELL"] = ""; // blank runs the system default shell } if(path.basename(env["PTYSHELL"]) === "zsh") { - env["OLD_ZDOTDIR"] = env.ZDOTDIR || env.HOME - env["ZDOTDIR"] = this.kubectlBinDir + env["OLD_ZDOTDIR"] = env.ZDOTDIR || env.HOME; + env["ZDOTDIR"] = this.kubectlBinDir; } - env["PTYPID"] = process.pid.toString() - env["KUBECONFIG"] = this.kubeconfigPath - env["TERM_PROGRAM"] = app.getName() - env["TERM_PROGRAM_VERSION"] = app.getVersion() + env["PTYPID"] = process.pid.toString(); + env["KUBECONFIG"] = this.kubeconfigPath; + env["TERM_PROGRAM"] = app.getName(); + env["TERM_PROGRAM_VERSION"] = app.getVersion(); if (this.preferences.httpsProxy) { - env["HTTPS_PROXY"] = this.preferences.httpsProxy + env["HTTPS_PROXY"] = this.preferences.httpsProxy; } - const no_proxy = ["localhost", "127.0.0.1", env["NO_PROXY"]] - env["NO_PROXY"] = no_proxy.filter(address => !!address).join() + const no_proxy = ["localhost", "127.0.0.1", env["NO_PROXY"]]; + env["NO_PROXY"] = no_proxy.filter(address => !!address).join(); if (env.DEBUG) { // do not pass debug option to bash - delete env["DEBUG"] + delete env["DEBUG"]; } - return(env) + return(env); } protected pipeStdout() { // send shell output to websocket this.shellProcess.onData(((data: string) => { - this.sendResponse(data) + this.sendResponse(data); })); } protected pipeStdin() { // write websocket messages to shellProcess this.websocket.on("message", (data: string) => { - if (!this.running) { return } + if (!this.running) { return; } - const message = Buffer.from(data.slice(1, data.length), "base64").toString() + const message = Buffer.from(data.slice(1, data.length), "base64").toString(); switch (data[0]) { case "0": - this.shellProcess.write(message) + this.shellProcess.write(message); break; case "4": - const resizeMsgObj = JSON.parse(message) - this.shellProcess.resize(resizeMsgObj["Width"], resizeMsgObj["Height"]) + const resizeMsgObj = JSON.parse(message); + this.shellProcess.resize(resizeMsgObj["Width"], resizeMsgObj["Height"]); break; case "9": - this.emit('newToken', message) + this.emit('newToken', message); break; } - }) + }); } protected exit(code = 1000) { - if (this.websocket.readyState == this.websocket.OPEN) this.websocket.close(code) - this.emit('exit') + if (this.websocket.readyState == this.websocket.OPEN) this.websocket.close(code); + this.emit('exit'); } protected closeWebsocketOnProcessExit() { this.shellProcess.onExit(({ exitCode }) => { - this.running = false - let timeout = 0 + this.running = false; + let timeout = 0; if (exitCode > 0) { - this.sendResponse("Terminal will auto-close in 15 seconds ...") - timeout = 15*1000 + this.sendResponse("Terminal will auto-close in 15 seconds ..."); + timeout = 15*1000; } setTimeout(() => { - this.exit() - }, timeout) + this.exit(); + }, timeout); }); } protected exitProcessOnWebsocketClose() { this.websocket.on("close", () => { - this.killShellProcess() - }) + this.killShellProcess(); + }); } protected killShellProcess(){ @@ -192,17 +192,17 @@ export class ShellSession extends EventEmitter { // On Windows we need to kill the shell process by pid, since Lens won't respond after a while if using `this.shellProcess.kill()` if (isWindows) { try { - process.kill(this.shellProcess.pid) + process.kill(this.shellProcess.pid); } catch(e) { - return + return; } } else { - this.shellProcess.kill() + this.shellProcess.kill(); } } } protected sendResponse(msg: string) { - this.websocket.send("1" + Buffer.from(msg).toString("base64")) + this.websocket.send("1" + Buffer.from(msg).toString("base64")); } } diff --git a/src/main/shell-sync.ts b/src/main/shell-sync.ts index 373d0a36ba..46d5788c12 100644 --- a/src/main/shell-sync.ts +++ b/src/main/shell-sync.ts @@ -1,4 +1,4 @@ -import shellEnv from "shell-env" +import shellEnv from "shell-env"; import os from "os"; import { app } from "electron"; import logger from "./logger"; @@ -19,7 +19,7 @@ export async function shellSync() { try { envVars = await shellEnv(shell); } catch (error) { - logger.error(`shellEnv: ${error}`) + logger.error(`shellEnv: ${error}`); } const env: Env = JSON.parse(JSON.stringify(envVars)); @@ -27,12 +27,12 @@ export async function shellSync() { // the LANG env var expects an underscore instead of electron's dash env.LANG = `${app.getLocale().replace('-', '_')}.UTF-8`; } else if (!env.LANG.endsWith(".UTF-8")) { - env.LANG += ".UTF-8" + env.LANG += ".UTF-8"; } // Overwrite PATH on darwin if (process.env.NODE_ENV === "production" && process.platform === "darwin") { - process.env["PATH"] = env.PATH + process.env["PATH"] = env.PATH; } // The spread operator allows joining of objects. The precedence is last to first. diff --git a/src/main/tray.ts b/src/main/tray.ts index 268e006089..f84ea21896 100644 --- a/src/main/tray.ts +++ b/src/main/tray.ts @@ -1,6 +1,6 @@ -import path from "path" -import packageInfo from "../../package.json" -import { dialog, Menu, NativeImage, nativeTheme, Tray } from "electron" +import path from "path"; +import packageInfo from "../../package.json"; +import { dialog, Menu, NativeImage, nativeTheme, Tray } from "electron"; import { autorun } from "mobx"; import { showAbout } from "./menu"; import { AppUpdater } from "./app-updater"; @@ -24,7 +24,7 @@ export function getTrayIcon(isDark = nativeTheme.shouldUseDarkColors): string { __static, isDevelopment ? "../build/tray" : "icons", // copied within electron-builder extras `tray_icon${isDark ? "_dark" : ""}.png` - ) + ); } export function initTray(windowManager: WindowManager) { @@ -35,18 +35,18 @@ export function initTray(windowManager: WindowManager) { } catch (err) { logger.error(`[TRAY]: building failed: ${err}`); } - }) + }); return () => { dispose(); tray?.destroy(); tray = null; - } + }; } export function buildTray(icon: string | NativeImage, menu: Menu) { if (!tray) { - tray = new Tray(icon) - tray.setToolTip(packageInfo.description) + tray = new Tray(icon); + tray.setToolTip(packageInfo.description); tray.setIgnoreDoubleClickEvents(true); } @@ -70,7 +70,7 @@ export function createTrayMenu(windowManager: WindowManager): Menu { { label: "Open Lens", async click() { - await windowManager.ensureMainWindow() + await windowManager.ensureMainWindow(); }, }, { @@ -98,9 +98,9 @@ export function createTrayMenu(windowManager: WindowManager): Menu { clusterStore.setActive(clusterId); windowManager.navigate(clusterViewURL({ params: { clusterId } })); } - } + }; }) - } + }; }), }, { @@ -112,7 +112,7 @@ export function createTrayMenu(windowManager: WindowManager): Menu { dialog.showMessageBoxSync(browserWindow, { message: "No updates available", type: "info", - }) + }); } }, }, @@ -120,7 +120,7 @@ export function createTrayMenu(windowManager: WindowManager): Menu { { label: 'Quit App', click() { - exitApp() + exitApp(); } } ]); diff --git a/src/main/window-manager.ts b/src/main/window-manager.ts index 019ed270eb..00fbdd4243 100644 --- a/src/main/window-manager.ts +++ b/src/main/window-manager.ts @@ -1,9 +1,9 @@ import type { ClusterId } from "../common/cluster-store"; import { observable } from "mobx"; -import { app, BrowserWindow, dialog, shell, webContents } from "electron" -import windowStateKeeper from "electron-window-state" -import { appEventBus } from "../common/event-bus" -import { subscribeToBroadcast } from "../common/ipc" +import { app, BrowserWindow, dialog, shell, webContents } from "electron"; +import windowStateKeeper from "electron-window-state"; +import { appEventBus } from "../common/event-bus"; +import { subscribeToBroadcast } from "../common/ipc"; import { initMenu } from "./menu"; import { initTray } from "./tray"; import { Singleton } from "../common/utils"; @@ -26,7 +26,7 @@ export class WindowManager extends Singleton { } get mainUrl() { - return `http://localhost:${this.proxyPort}` + return `http://localhost:${this.proxyPort}`; } async initMainWindow(showSplash = true) { @@ -63,14 +63,14 @@ export class WindowManager extends Singleton { shell.openExternal(url); }); this.mainWindow.webContents.on("dom-ready", () => { - appEventBus.emit({name: "app", action: "dom-ready"}) - }) + appEventBus.emit({name: "app", action: "dom-ready"}); + }); this.mainWindow.on("focus", () => { - appEventBus.emit({name: "app", action: "focus"}) - }) + appEventBus.emit({name: "app", action: "focus"}); + }); this.mainWindow.on("blur", () => { - appEventBus.emit({name: "app", action: "blur"}) - }) + appEventBus.emit({name: "app", action: "blur"}); + }); // clean up this.mainWindow.on("closed", () => { @@ -78,16 +78,16 @@ export class WindowManager extends Singleton { this.mainWindow = null; this.splashWindow = null; app.dock?.hide(); // hide icon in dock (mac-os) - }) + }); } try { if (showSplash) await this.showSplash(); await this.mainWindow.loadURL(this.mainUrl); this.mainWindow.show(); this.splashWindow?.close(); - appEventBus.emit({ name: "app", action: "start" }) + appEventBus.emit({ name: "app", action: "start" }); } catch (err) { - dialog.showErrorBox("ERROR!", err.toString()) + dialog.showErrorBox("ERROR!", err.toString()); } } @@ -103,7 +103,7 @@ export class WindowManager extends Singleton { // track visible cluster from ui subscribeToBroadcast("cluster-view:current-id", (event, clusterId: ClusterId) => { this.activeClusterId = clusterId; - }) + }); } async ensureMainWindow(): Promise { @@ -126,11 +126,11 @@ export class WindowManager extends Singleton { channel: "renderer:navigate", frameId: frameId, data: [url], - }) + }); } reload() { - const frameId = clusterFrameMap.get(this.activeClusterId) + const frameId = clusterFrameMap.get(this.activeClusterId); if (frameId) { this.sendToView({ channel: "renderer:reload", frameId }); } else { @@ -169,7 +169,7 @@ export class WindowManager extends Singleton { this.splashWindow = null; Object.entries(this.disposers).forEach(([name, dispose]) => { dispose(); - delete this.disposers[name] + delete this.disposers[name]; }); } } diff --git a/src/migrations/cluster-store/2.0.0-beta.2.ts b/src/migrations/cluster-store/2.0.0-beta.2.ts index 8a01af5407..245e9c019c 100644 --- a/src/migrations/cluster-store/2.0.0-beta.2.ts +++ b/src/migrations/cluster-store/2.0.0-beta.2.ts @@ -13,4 +13,4 @@ export default migration({ store.set(contextName, { kubeConfig: value[1] }); } } -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/src/migrations/cluster-store/2.4.1.ts b/src/migrations/cluster-store/2.4.1.ts index 5789f6cc36..f9de1ed6d8 100644 --- a/src/migrations/cluster-store/2.4.1.ts +++ b/src/migrations/cluster-store/2.4.1.ts @@ -11,4 +11,4 @@ export default migration({ store.set(contextName, { kubeConfig: cluster.kubeConfig, icon: cluster.icon || null, preferences: cluster.preferences || {} }); } } -}) +}); diff --git a/src/migrations/cluster-store/2.6.0-beta.2.ts b/src/migrations/cluster-store/2.6.0-beta.2.ts index 0e13afe7a9..3114202ed1 100644 --- a/src/migrations/cluster-store/2.6.0-beta.2.ts +++ b/src/migrations/cluster-store/2.6.0-beta.2.ts @@ -6,7 +6,7 @@ export default migration({ run(store, log) { for (const value of store) { const clusterKey = value[0]; - if (clusterKey === "__internal__") continue + if (clusterKey === "__internal__") continue; const cluster = value[1]; if (!cluster.preferences) cluster.preferences = {}; if (cluster.icon) { @@ -16,4 +16,4 @@ export default migration({ store.set(clusterKey, { contextName: clusterKey, kubeConfig: value[1].kubeConfig, preferences: value[1].preferences }); } } -}) +}); diff --git a/src/migrations/cluster-store/2.6.0-beta.3.ts b/src/migrations/cluster-store/2.6.0-beta.3.ts index 11f1a3bce9..7f17440e60 100644 --- a/src/migrations/cluster-store/2.6.0-beta.3.ts +++ b/src/migrations/cluster-store/2.6.0-beta.3.ts @@ -1,38 +1,38 @@ import { migration } from "../migration-wrapper"; -import yaml from "js-yaml" +import yaml from "js-yaml"; export default migration({ version: "2.6.0-beta.3", run(store, log) { for (const value of store) { const clusterKey = value[0]; - if (clusterKey === "__internal__") continue + if (clusterKey === "__internal__") continue; const cluster = value[1]; - if (!cluster.kubeConfig) continue - const kubeConfig = yaml.safeLoad(cluster.kubeConfig) - if (!kubeConfig.hasOwnProperty('users')) continue - const userObj = kubeConfig.users[0] + if (!cluster.kubeConfig) continue; + const kubeConfig = yaml.safeLoad(cluster.kubeConfig); + if (!kubeConfig.hasOwnProperty('users')) continue; + const userObj = kubeConfig.users[0]; if (userObj) { - const user = userObj.user + const user = userObj.user; if (user["auth-provider"] && user["auth-provider"].config) { - const authConfig = user["auth-provider"].config + const authConfig = user["auth-provider"].config; if (authConfig["access-token"]) { - authConfig["access-token"] = `${authConfig["access-token"]}` + authConfig["access-token"] = `${authConfig["access-token"]}`; } if (authConfig.expiry) { - authConfig.expiry = `${authConfig.expiry}` + authConfig.expiry = `${authConfig.expiry}`; } - log(authConfig) - user["auth-provider"].config = authConfig + log(authConfig); + user["auth-provider"].config = authConfig; kubeConfig.users = [{ name: userObj.name, user: user - }] - cluster.kubeConfig = yaml.safeDump(kubeConfig) - store.set(clusterKey, cluster) + }]; + cluster.kubeConfig = yaml.safeDump(kubeConfig); + store.set(clusterKey, cluster); } } } } -}) +}); diff --git a/src/migrations/cluster-store/2.7.0-beta.0.ts b/src/migrations/cluster-store/2.7.0-beta.0.ts index 3e0ae9337f..f1af3de3c9 100644 --- a/src/migrations/cluster-store/2.7.0-beta.0.ts +++ b/src/migrations/cluster-store/2.7.0-beta.0.ts @@ -6,10 +6,10 @@ export default migration({ run(store, log) { for (const value of store) { const clusterKey = value[0]; - if (clusterKey === "__internal__") continue + if (clusterKey === "__internal__") continue; const cluster = value[1]; - cluster.workspace = "default" - store.set(clusterKey, cluster) + cluster.workspace = "default"; + store.set(clusterKey, cluster); } } -}) +}); diff --git a/src/migrations/cluster-store/2.7.0-beta.1.ts b/src/migrations/cluster-store/2.7.0-beta.1.ts index de9e4506d1..52e60ba527 100644 --- a/src/migrations/cluster-store/2.7.0-beta.1.ts +++ b/src/migrations/cluster-store/2.7.0-beta.1.ts @@ -1,25 +1,25 @@ // Add id for clusters and store them to array import { migration } from "../migration-wrapper"; -import { v4 as uuid } from "uuid" +import { v4 as uuid } from "uuid"; export default migration({ version: "2.7.0-beta.1", run(store, log) { - const clusters: any[] = [] + const clusters: any[] = []; for (const value of store) { const clusterKey = value[0]; - if (clusterKey === "__internal__") continue - if (clusterKey === "clusters") continue + if (clusterKey === "__internal__") continue; + if (clusterKey === "clusters") continue; const cluster = value[1]; - cluster.id = uuid() + cluster.id = uuid(); if (!cluster.preferences.clusterName) { - cluster.preferences.clusterName = clusterKey + cluster.preferences.clusterName = clusterKey; } - clusters.push(cluster) - store.delete(clusterKey) + clusters.push(cluster); + store.delete(clusterKey); } if (clusters.length > 0) { - store.set("clusters", clusters) + store.set("clusters", clusters); } } -}) +}); diff --git a/src/migrations/cluster-store/3.6.0-beta.1.ts b/src/migrations/cluster-store/3.6.0-beta.1.ts index 412c77ab96..c7e5889cd9 100644 --- a/src/migrations/cluster-store/3.6.0-beta.1.ts +++ b/src/migrations/cluster-store/3.6.0-beta.1.ts @@ -1,24 +1,24 @@ // Move embedded kubeconfig into separate file and add reference to it to cluster settings // convert file path cluster icons to their base64 encoded versions -import path from "path" -import { app, remote } from "electron" +import path from "path"; +import { app, remote } from "electron"; import { migration } from "../migration-wrapper"; -import fse from "fs-extra" +import fse from "fs-extra"; import { ClusterModel, ClusterStore } from "../../common/cluster-store"; import { loadConfig } from "../../common/kube-helpers"; export default migration({ version: "3.6.0-beta.1", run(store, printLog) { - const userDataPath = (app || remote.app).getPath("userData") + const userDataPath = (app || remote.app).getPath("userData"); const kubeConfigBase = ClusterStore.getCustomKubeConfigPath(""); const storedClusters: ClusterModel[] = store.get("clusters") || []; if (!storedClusters.length) return; fse.ensureDirSync(kubeConfigBase); - printLog("Number of clusters to migrate: ", storedClusters.length) + printLog("Number of clusters to migrate: ", storedClusters.length); const migratedClusters = storedClusters .map(cluster => { /** @@ -31,7 +31,7 @@ export default migration({ delete cluster.kubeConfig; } catch (error) { - printLog(`Failed to migrate Kubeconfig for cluster "${cluster.id}", removing cluster...`, error) + printLog(`Failed to migrate Kubeconfig for cluster "${cluster.id}", removing cluster...`, error); return undefined; } @@ -40,8 +40,8 @@ export default migration({ */ try { if (cluster.preferences?.icon) { - printLog(`migrating ${cluster.preferences.icon} for ${cluster.preferences.clusterName}`) - const iconPath = cluster.preferences.icon.replace("store://", "") + printLog(`migrating ${cluster.preferences.icon} for ${cluster.preferences.clusterName}`); + const iconPath = cluster.preferences.icon.replace("store://", ""); const fileData = fse.readFileSync(path.join(userDataPath, iconPath)); cluster.preferences.icon = `data:;base64,${fileData.toString('base64')}`; @@ -49,7 +49,7 @@ export default migration({ delete cluster.preferences?.icon; } } catch (error) { - printLog(`Failed to migrate cluster icon for cluster "${cluster.id}"`, error) + printLog(`Failed to migrate cluster icon for cluster "${cluster.id}"`, error); delete cluster.preferences.icon; } @@ -59,7 +59,7 @@ export default migration({ // "overwrite" the cluster configs if (migratedClusters.length > 0) { - store.set("clusters", migratedClusters) + store.set("clusters", migratedClusters); } } -}) +}); diff --git a/src/migrations/cluster-store/index.ts b/src/migrations/cluster-store/index.ts index f35e8f6c9c..c546fdaeda 100644 --- a/src/migrations/cluster-store/index.ts +++ b/src/migrations/cluster-store/index.ts @@ -1,13 +1,13 @@ // Cluster store migrations -import version200Beta2 from "./2.0.0-beta.2" -import version241 from "./2.4.1" -import version260Beta2 from "./2.6.0-beta.2" -import version260Beta3 from "./2.6.0-beta.3" -import version270Beta0 from "./2.7.0-beta.0" -import version270Beta1 from "./2.7.0-beta.1" -import version360Beta1 from "./3.6.0-beta.1" -import snap from "./snap" +import version200Beta2 from "./2.0.0-beta.2"; +import version241 from "./2.4.1"; +import version260Beta2 from "./2.6.0-beta.2"; +import version260Beta3 from "./2.6.0-beta.3"; +import version270Beta0 from "./2.7.0-beta.0"; +import version270Beta1 from "./2.7.0-beta.1"; +import version360Beta1 from "./3.6.0-beta.1"; +import snap from "./snap"; export default { ...version200Beta2, @@ -18,4 +18,4 @@ export default { ...version270Beta1, ...version360Beta1, ...snap -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/migrations/cluster-store/snap.ts b/src/migrations/cluster-store/snap.ts index a377ba4268..1136607cd7 100644 --- a/src/migrations/cluster-store/snap.ts +++ b/src/migrations/cluster-store/snap.ts @@ -3,31 +3,31 @@ import { migration } from "../migration-wrapper"; import { ClusterModel, ClusterStore } from "../../common/cluster-store"; import { getAppVersion } from "../../common/utils/app-version"; -import fs from "fs" +import fs from "fs"; export default migration({ version: getAppVersion(), // Run always after upgrade run(store, printLog) { if (!process.env["SNAP"]) return; - printLog("Migrating embedded kubeconfig paths") + printLog("Migrating embedded kubeconfig paths"); const storedClusters: ClusterModel[] = store.get("clusters") || []; if (!storedClusters.length) return; - printLog("Number of clusters to migrate: ", storedClusters.length) + printLog("Number of clusters to migrate: ", storedClusters.length); const migratedClusters = storedClusters .map(cluster => { /** * replace snap version with 'current' in kubeconfig path */ if (!fs.existsSync(cluster.kubeConfigPath)) { - const kubeconfigPath = cluster.kubeConfigPath.replace(/\/snap\/kontena-lens\/[0-9]*\//, "/snap/kontena-lens/current/") - cluster.kubeConfigPath = kubeconfigPath + const kubeconfigPath = cluster.kubeConfigPath.replace(/\/snap\/kontena-lens\/[0-9]*\//, "/snap/kontena-lens/current/"); + cluster.kubeConfigPath = kubeconfigPath; } return cluster; - }) + }); - store.set("clusters", migratedClusters) + store.set("clusters", migratedClusters); } -}) +}); diff --git a/src/migrations/user-store/2.1.0-beta.4.ts b/src/migrations/user-store/2.1.0-beta.4.ts index 24c4cde5e3..e8f6500b05 100644 --- a/src/migrations/user-store/2.1.0-beta.4.ts +++ b/src/migrations/user-store/2.1.0-beta.4.ts @@ -6,4 +6,4 @@ export default migration({ run(store) { store.set("lastSeenAppVersion", "0.0.0"); } -}) +}); diff --git a/src/migrations/user-store/index.ts b/src/migrations/user-store/index.ts index 895bc5ee18..e1e7b8ffc9 100644 --- a/src/migrations/user-store/index.ts +++ b/src/migrations/user-store/index.ts @@ -1,7 +1,7 @@ // User store migrations -import version210Beta4 from "./2.1.0-beta.4" +import version210Beta4 from "./2.1.0-beta.4"; export default { ...version210Beta4, -} +}; diff --git a/src/renderer/api/api-manager.ts b/src/renderer/api/api-manager.ts index a0d90f4a13..98dbe206c7 100644 --- a/src/renderer/api/api-manager.ts +++ b/src/renderer/api/api-manager.ts @@ -24,7 +24,7 @@ export class ApiManager { } protected resolveApi(api: string | KubeApi): KubeApi { - if (typeof api === "string") return this.getApi(api) + if (typeof api === "string") return this.getApi(api); return api; } @@ -41,7 +41,7 @@ export class ApiManager { registerStore(store: KubeObjectStore, apis: KubeApi[] = [store.api]) { apis.forEach(api => { this.stores.set(api, store); - }) + }); } getStore(api: string | KubeApi): KubeObjectStore { diff --git a/src/renderer/api/endpoints/cluster-role-binding.api.ts b/src/renderer/api/endpoints/cluster-role-binding.api.ts index 35e4ded7e7..d566717bff 100644 --- a/src/renderer/api/endpoints/cluster-role-binding.api.ts +++ b/src/renderer/api/endpoints/cluster-role-binding.api.ts @@ -2,9 +2,9 @@ import { RoleBinding } from "./role-binding.api"; import { KubeApi } from "../kube-api"; export class ClusterRoleBinding extends RoleBinding { - static kind = "ClusterRoleBinding" - static namespaced = false - static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings" + static kind = "ClusterRoleBinding"; + static namespaced = false; + static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings"; } export const clusterRoleBindingApi = new KubeApi({ diff --git a/src/renderer/api/endpoints/cluster-role.api.ts b/src/renderer/api/endpoints/cluster-role.api.ts index 8a99f7ad27..9e3c90ca2e 100644 --- a/src/renderer/api/endpoints/cluster-role.api.ts +++ b/src/renderer/api/endpoints/cluster-role.api.ts @@ -4,9 +4,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class ClusterRole extends Role { - static kind = "ClusterRole" - static namespaced = false - static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterroles" + static kind = "ClusterRole"; + static namespaced = false; + static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterroles"; } export const clusterRoleApi = new KubeApi({ diff --git a/src/renderer/api/endpoints/cluster.api.ts b/src/renderer/api/endpoints/cluster.api.ts index 4386f28184..43783e1c00 100644 --- a/src/renderer/api/endpoints/cluster.api.ts +++ b/src/renderer/api/endpoints/cluster.api.ts @@ -3,12 +3,12 @@ import { KubeObject } from "../kube-object"; import { KubeApi } from "../kube-api"; export class ClusterApi extends KubeApi { - static kind = "Cluster" - static namespaced = true + static kind = "Cluster"; + static namespaced = true; async getMetrics(nodeNames: string[], params?: IMetricsReqParams): Promise { const nodes = nodeNames.join("|"); - const opts = { category: "cluster", nodes: nodes } + const opts = { category: "cluster", nodes: nodes }; return metricsApi.getMetrics({ memoryUsage: opts, @@ -52,7 +52,7 @@ export interface IClusterMetrics { export class Cluster extends KubeObject { static kind = "Cluster"; - static apiBase = "/apis/cluster.k8s.io/v1alpha1/clusters" + static apiBase = "/apis/cluster.k8s.io/v1alpha1/clusters"; spec: { clusterNetwork?: { @@ -69,7 +69,7 @@ export class Cluster extends KubeObject { profile: string; }; }; - } + }; status?: { apiEndpoints: { host: string; @@ -84,7 +84,7 @@ export class Cluster extends KubeObject { }; errorMessage?: string; errorReason?: string; - } + }; getStatus() { if (this.metadata.deletionTimestamp) return ClusterStatus.REMOVING; diff --git a/src/renderer/api/endpoints/component-status.api.ts b/src/renderer/api/endpoints/component-status.api.ts index 7f7e04fe2a..fec4dda1da 100644 --- a/src/renderer/api/endpoints/component-status.api.ts +++ b/src/renderer/api/endpoints/component-status.api.ts @@ -8,11 +8,11 @@ export interface IComponentStatusCondition { } export class ComponentStatus extends KubeObject { - static kind = "ComponentStatus" - static namespaced = false - static apiBase = "/api/v1/componentstatuses" + static kind = "ComponentStatus"; + static namespaced = false; + static apiBase = "/api/v1/componentstatuses"; - conditions: IComponentStatusCondition[] + conditions: IComponentStatusCondition[]; getTruthyConditions() { return this.conditions.filter(c => c.status === "True"); diff --git a/src/renderer/api/endpoints/configmap.api.ts b/src/renderer/api/endpoints/configmap.api.ts index 59f3e3b090..042fb59d86 100644 --- a/src/renderer/api/endpoints/configmap.api.ts +++ b/src/renderer/api/endpoints/configmap.api.ts @@ -7,7 +7,7 @@ import { KubeApi } from "../kube-api"; export class ConfigMap extends KubeObject { static kind = "ConfigMap"; static namespaced = true; - static apiBase = "/api/v1/configmaps" + static apiBase = "/api/v1/configmaps"; constructor(data: KubeJsonApiData) { super(data); @@ -16,7 +16,7 @@ export class ConfigMap extends KubeObject { data: { [param: string]: string; - } + }; getKeys(): string[] { return Object.keys(this.data); diff --git a/src/renderer/api/endpoints/crd.api.ts b/src/renderer/api/endpoints/crd.api.ts index 1916d71f1b..02690a2afd 100644 --- a/src/renderer/api/endpoints/crd.api.ts +++ b/src/renderer/api/endpoints/crd.api.ts @@ -7,20 +7,20 @@ type AdditionalPrinterColumnsCommon = { type: "integer" | "number" | "string" | "boolean" | "date"; priority: number; description: string; -} +}; export type AdditionalPrinterColumnsV1 = AdditionalPrinterColumnsCommon & { jsonPath: string; -} +}; type AdditionalPrinterColumnsV1Beta = AdditionalPrinterColumnsCommon & { JSONPath: string; -} +}; export class CustomResourceDefinition extends KubeObject { static kind = "CustomResourceDefinition"; static namespaced = false; - static apiBase = "/apis/apiextensions.k8s.io/v1/customresourcedefinitions" + static apiBase = "/apis/apiextensions.k8s.io/v1/customresourcedefinitions"; spec: { group: string; @@ -45,7 +45,7 @@ export class CustomResourceDefinition extends KubeObject { webhook?: any; }; additionalPrinterColumns?: AdditionalPrinterColumnsV1Beta[]; // removed in v1 - } + }; status: { conditions: { lastTransitionTime: string; @@ -62,7 +62,7 @@ export class CustomResourceDefinition extends KubeObject { listKind: string; }; storedVersions: string[]; - } + }; getResourceUrl() { return crdResourcesURL({ @@ -70,25 +70,25 @@ export class CustomResourceDefinition extends KubeObject { group: this.getGroup(), name: this.getPluralName(), } - }) + }); } getResourceApiBase() { const { group } = this.spec; - return `/apis/${group}/${this.getVersion()}/${this.getPluralName()}` + return `/apis/${group}/${this.getVersion()}/${this.getPluralName()}`; } getPluralName() { - return this.getNames().plural + return this.getNames().plural; } getResourceKind() { - return this.spec.names.kind + return this.spec.names.kind; } getResourceTitle() { const name = this.getPluralName(); - return name[0].toUpperCase() + name.substr(1) + return name[0].toUpperCase() + name.substr(1); } getGroup() { @@ -141,7 +141,7 @@ export class CustomResourceDefinition extends KubeObject { ...condition, isReady: status === "True", tooltip: `${message || reason} (${lastTransitionTime})` - } + }; }); } } diff --git a/src/renderer/api/endpoints/cron-job.api.ts b/src/renderer/api/endpoints/cron-job.api.ts index b385647bb9..2cca8bfb3d 100644 --- a/src/renderer/api/endpoints/cron-job.api.ts +++ b/src/renderer/api/endpoints/cron-job.api.ts @@ -7,12 +7,12 @@ import { KubeApi } from "../kube-api"; @autobind() export class CronJob extends KubeObject { - static kind = "CronJob" - static namespaced = true - static apiBase = "/apis/batch/v1beta1/cronjobs" + static kind = "CronJob"; + static namespaced = true; + static apiBase = "/apis/batch/v1beta1/cronjobs"; - kind: string - apiVersion: string + kind: string; + apiVersion: string; metadata: { name: string; namespace: string; @@ -26,7 +26,7 @@ export class CronJob extends KubeObject { annotations: { [key: string]: string; }; - } + }; spec: { schedule: string; concurrencyPolicy: string; @@ -59,23 +59,23 @@ export class CronJob extends KubeObject { }; successfulJobsHistoryLimit: number; failedJobsHistoryLimit: number; - } + }; status: { lastScheduleTime?: string; - } + }; getSuspendFlag() { - return this.spec.suspend.toString() + return this.spec.suspend.toString(); } getLastScheduleTime() { - if (!this.status.lastScheduleTime) return "-" - const diff = moment().diff(this.status.lastScheduleTime) - return formatDuration(diff, true) + if (!this.status.lastScheduleTime) return "-"; + const diff = moment().diff(this.status.lastScheduleTime); + return formatDuration(diff, true); } getSchedule() { - return this.spec.schedule + return this.spec.schedule; } isNeverRun() { diff --git a/src/renderer/api/endpoints/daemon-set.api.ts b/src/renderer/api/endpoints/daemon-set.api.ts index d947293c1c..63fc6363e4 100644 --- a/src/renderer/api/endpoints/daemon-set.api.ts +++ b/src/renderer/api/endpoints/daemon-set.api.ts @@ -6,9 +6,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class DaemonSet extends WorkloadKubeObject { - static kind = "DaemonSet" - static namespaced = true - static apiBase = "/apis/apps/v1/daemonsets" + static kind = "DaemonSet"; + static namespaced = true; + static apiBase = "/apis/apps/v1/daemonsets"; spec: { selector: { @@ -51,7 +51,7 @@ export class DaemonSet extends WorkloadKubeObject { }; }; revisionHistoryLimit: number; - } + }; status: { currentNumberScheduled: number; numberMisscheduled: number; @@ -61,12 +61,12 @@ export class DaemonSet extends WorkloadKubeObject { updatedNumberScheduled: number; numberAvailable: number; numberUnavailable: number; - } + }; getImages() { - const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []) - const initContainers: IPodContainer[] = get(this, "spec.template.spec.initContainers", []) - return [...containers, ...initContainers].map(container => container.image) + const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []); + const initContainers: IPodContainer[] = get(this, "spec.template.spec.initContainers", []); + return [...containers, ...initContainers].map(container => container.image); } } diff --git a/src/renderer/api/endpoints/deployment.api.ts b/src/renderer/api/endpoints/deployment.api.ts index b21495ecc1..28ed71f86a 100644 --- a/src/renderer/api/endpoints/deployment.api.ts +++ b/src/renderer/api/endpoints/deployment.api.ts @@ -6,13 +6,13 @@ import { KubeApi } from "../kube-api"; export class DeploymentApi extends KubeApi { protected getScaleApiUrl(params: { namespace: string; name: string }) { - return this.getUrl(params) + "/scale" + return this.getUrl(params) + "/scale"; } getReplicas(params: { namespace: string; name: string }): Promise { return this.request .get(this.getScaleApiUrl(params)) - .then(({ status }: any) => status?.replicas) + .then(({ status }: any) => status?.replicas); } scale(params: { namespace: string; name: string }, replicas: number) { @@ -23,7 +23,7 @@ export class DeploymentApi extends KubeApi { replicas: replicas } } - }) + }); } restart(params: { namespace: string; name: string }) { @@ -42,15 +42,15 @@ export class DeploymentApi extends KubeApi { headers: { 'content-type': 'application/strategic-merge-patch+json' } - }) + }); } } @autobind() export class Deployment extends WorkloadKubeObject { - static kind = "Deployment" - static namespaced = true - static apiBase = "/apis/apps/v1/deployments" + static kind = "Deployment"; + static namespaced = true; + static apiBase = "/apis/apps/v1/deployments"; spec: { replicas: number; @@ -151,7 +151,7 @@ export class Deployment extends WorkloadKubeObject { maxSurge: number; }; }; - } + }; status: { observedGeneration: number; replicas: number; @@ -167,19 +167,19 @@ export class Deployment extends WorkloadKubeObject { reason: string; message: string; }[]; - } + }; getConditions(activeOnly = false) { - const { conditions } = this.status - if (!conditions) return [] + const { conditions } = this.status; + if (!conditions) return []; if (activeOnly) { - return conditions.filter(c => c.status === "True") + return conditions.filter(c => c.status === "True"); } - return conditions + return conditions; } getConditionsText(activeOnly = true) { - return this.getConditions(activeOnly).map(({ type }) => type).join(" ") + return this.getConditions(activeOnly).map(({ type }) => type).join(" "); } getReplicas() { diff --git a/src/renderer/api/endpoints/endpoint.api.ts b/src/renderer/api/endpoints/endpoint.api.ts index 4f4afc9b17..121836a637 100644 --- a/src/renderer/api/endpoints/endpoint.api.ts +++ b/src/renderer/api/endpoints/endpoint.api.ts @@ -42,22 +42,22 @@ export class EndpointAddress implements IEndpointAddress { }; constructor(data: IEndpointAddress) { - Object.assign(this, data) + Object.assign(this, data); } getId() { - return this.ip + return this.ip; } getName() { - return this.hostname + return this.hostname; } getTargetRef(): ITargetRef { if (this.targetRef) { - return Object.assign(this.targetRef, {apiVersion: "v1"}) + return Object.assign(this.targetRef, {apiVersion: "v1"}); } else { - return null + return null; } } } @@ -68,7 +68,7 @@ export class EndpointSubset implements IEndpointSubset { ports: IEndpointPort[]; constructor(data: IEndpointSubset) { - Object.assign(this, data) + Object.assign(this, data); } getAddresses(): EndpointAddress[] { @@ -83,26 +83,26 @@ export class EndpointSubset implements IEndpointSubset { toString(): string { if(!this.addresses) { - return "" + return ""; } return this.addresses.map(address => { if (!this.ports) { - return address.ip + return address.ip; } return this.ports.map(port => { - return `${address.ip}:${port.port}` - }).join(", ") - }).join(", ") + return `${address.ip}:${port.port}`; + }).join(", "); + }).join(", "); } } @autobind() export class Endpoint extends KubeObject { - static kind = "Endpoints" - static namespaced = true - static apiBase = "/api/v1/endpoints" + static kind = "Endpoints"; + static namespaced = true; + static apiBase = "/api/v1/endpoints"; - subsets: IEndpointSubset[] + subsets: IEndpointSubset[]; getEndpointSubsets(): EndpointSubset[] { const subsets = this.subsets || []; @@ -111,9 +111,9 @@ export class Endpoint extends KubeObject { toString(): string { if(this.subsets) { - return this.getEndpointSubsets().map(es => es.toString()).join(", ") + return this.getEndpointSubsets().map(es => es.toString()).join(", "); } else { - return "" + return ""; } } diff --git a/src/renderer/api/endpoints/events.api.ts b/src/renderer/api/endpoints/events.api.ts index 0608a3d44b..51dbf3c3b5 100644 --- a/src/renderer/api/endpoints/events.api.ts +++ b/src/renderer/api/endpoints/events.api.ts @@ -6,9 +6,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class KubeEvent extends KubeObject { - static kind = "Event" - static namespaced = true - static apiBase = "/api/v1/events" + static kind = "Event"; + static namespaced = true; + static apiBase = "/api/v1/events"; involvedObject: { kind: string; @@ -18,41 +18,41 @@ export class KubeEvent extends KubeObject { apiVersion: string; resourceVersion: string; fieldPath: string; - } - reason: string - message: string + }; + reason: string; + message: string; source: { component: string; host: string; - } - firstTimestamp: string - lastTimestamp: string - count: number - type: string - eventTime: null - reportingComponent: string - reportingInstance: string + }; + firstTimestamp: string; + lastTimestamp: string; + count: number; + type: string; + eventTime: null; + reportingComponent: string; + reportingInstance: string; isWarning() { return this.type === "Warning"; } getSource() { - const { component, host } = this.source - return `${component} ${host || ""}` + const { component, host } = this.source; + return `${component} ${host || ""}`; } getFirstSeenTime() { - const diff = moment().diff(this.firstTimestamp) - return formatDuration(diff, true) + const diff = moment().diff(this.firstTimestamp); + return formatDuration(diff, true); } getLastSeenTime() { - const diff = moment().diff(this.lastTimestamp) - return formatDuration(diff, true) + const diff = moment().diff(this.lastTimestamp); + return formatDuration(diff, true); } } export const eventApi = new KubeApi({ objectConstructor: KubeEvent, -}) +}); diff --git a/src/renderer/api/endpoints/helm-charts.api.ts b/src/renderer/api/endpoints/helm-charts.api.ts index 8943cd49df..e6328f136b 100644 --- a/src/renderer/api/endpoints/helm-charts.api.ts +++ b/src/renderer/api/endpoints/helm-charts.api.ts @@ -41,7 +41,7 @@ export const helmChartsApi = { return { readme, versions, - } + }; }); }, @@ -61,27 +61,27 @@ export class HelmChart { return new HelmChart(data); } - apiVersion: string - name: string - version: string - repo: string - kubeVersion?: string - created: string - description?: string - digest: string - keywords?: string[] - home?: string - sources?: string[] + apiVersion: string; + name: string; + version: string; + repo: string; + kubeVersion?: string; + created: string; + description?: string; + digest: string; + keywords?: string[]; + home?: string; + sources?: string[]; maintainers?: { name: string; email: string; url: string; - }[] - engine?: string - icon?: string - appVersion?: string - deprecated?: boolean - tillerVersion?: string + }[]; + engine?: string; + icon?: string; + appVersion?: string; + deprecated?: boolean; + tillerVersion?: string; getId() { return this.digest; diff --git a/src/renderer/api/endpoints/helm-releases.api.ts b/src/renderer/api/endpoints/helm-releases.api.ts index 9051936ac8..0ddbf1c734 100644 --- a/src/renderer/api/endpoints/helm-releases.api.ts +++ b/src/renderer/api/endpoints/helm-releases.api.ts @@ -82,7 +82,7 @@ export const helmReleasesApi = { return { ...details, resources - } + }; }); }, @@ -135,13 +135,13 @@ export class HelmRelease implements ItemObject { return new HelmRelease(data); } - appVersion: string - name: string - namespace: string - chart: string - status: string - updated: string - revision: string + appVersion: string; + name: string; + namespace: string; + chart: string; + status: string; + updated: string; + revision: string; getId() { return this.namespace + this.name; @@ -156,12 +156,12 @@ export class HelmRelease implements ItemObject { } getChart(withVersion = false) { - let chart = this.chart + let chart = this.chart; if(!withVersion && this.getVersion() != "" ) { - const search = new RegExp(`-${this.getVersion()}`) + const search = new RegExp(`-${this.getVersion()}`); chart = chart.replace(search, ""); } - return chart + return chart; } getRevision() { @@ -173,12 +173,12 @@ export class HelmRelease implements ItemObject { } getVersion() { - const versions = this.chart.match(/(v?\d+)[^-].*$/) + const versions = this.chart.match(/(v?\d+)[^-].*$/); if (versions) { - return versions[0] + return versions[0]; } else { - return "" + return ""; } } diff --git a/src/renderer/api/endpoints/hpa.api.ts b/src/renderer/api/endpoints/hpa.api.ts index f55f6d327f..79e6cada0f 100644 --- a/src/renderer/api/endpoints/hpa.api.ts +++ b/src/renderer/api/endpoints/hpa.api.ts @@ -20,7 +20,7 @@ export type IHpaMetricData = T & { currentAverageValue?: string; targetAverageUtilization?: number; targetAverageValue?: string; -} +}; export interface IHpaMetric { [kind: string]: IHpaMetricData; @@ -41,7 +41,7 @@ export interface IHpaMetric { export class HorizontalPodAutoscaler extends KubeObject { static kind = "HorizontalPodAutoscaler"; static namespaced = true; - static apiBase = "/apis/autoscaling/v2beta1/horizontalpodautoscalers" + static apiBase = "/apis/autoscaling/v2beta1/horizontalpodautoscalers"; spec: { scaleTargetRef: { @@ -52,7 +52,7 @@ export class HorizontalPodAutoscaler extends KubeObject { minReplicas: number; maxReplicas: number; metrics: IHpaMetric[]; - } + }; status: { currentReplicas: number; desiredReplicas: number; @@ -64,7 +64,7 @@ export class HorizontalPodAutoscaler extends KubeObject { status: string; type: string; }[]; - } + }; getMaxPods() { return this.spec.maxReplicas || 0; @@ -86,7 +86,7 @@ export class HorizontalPodAutoscaler extends KubeObject { ...condition, isReady: status === "True", tooltip: `${message || reason} (${lastTransitionTime})` - } + }; }); } @@ -102,7 +102,7 @@ export class HorizontalPodAutoscaler extends KubeObject { const { type, resource, pods, object, external } = metric; switch (type) { case HpaMetricType.Resource: - return resource.name + return resource.name; case HpaMetricType.Pods: return pods.metricName; case HpaMetricType.Object: @@ -128,7 +128,7 @@ export class HorizontalPodAutoscaler extends KubeObject { } if (target) { targetValue = target.targetAverageUtilization || target.targetAverageValue || target.targetValue; - if (target.targetAverageUtilization) targetValue += "%" + if (target.targetAverageUtilization) targetValue += "%"; } return `${currentValue} / ${targetValue}`; } diff --git a/src/renderer/api/endpoints/index.ts b/src/renderer/api/endpoints/index.ts index 337d193043..f1202b9122 100644 --- a/src/renderer/api/endpoints/index.ts +++ b/src/renderer/api/endpoints/index.ts @@ -1,35 +1,35 @@ // Kubernetes apis // Docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/ -export * from "./cluster.api" -export * from "./cluster-role.api" -export * from "./cluster-role-binding.api" -export * from "./configmap.api" -export * from "./crd.api" -export * from "./cron-job.api" -export * from "./daemon-set.api" -export * from "./deployment.api" -export * from "./endpoint.api" -export * from "./events.api" -export * from "./hpa.api" -export * from "./ingress.api" -export * from "./job.api" -export * from "./namespaces.api" -export * from "./network-policy.api" -export * from "./nodes.api" -export * from "./persistent-volume.api" -export * from "./persistent-volume-claims.api" -export * from "./pods.api" -export * from "./poddisruptionbudget.api" -export * from "./pod-metrics.api" -export * from "./podsecuritypolicy.api" -export * from "./replica-set.api" -export * from "./resource-quota.api" -export * from "./role.api" -export * from "./role-binding.api" -export * from "./secret.api" -export * from "./selfsubjectrulesreviews.api" -export * from "./service.api" -export * from "./service-accounts.api" -export * from "./stateful-set.api" -export * from "./storage-class.api" +export * from "./cluster.api"; +export * from "./cluster-role.api"; +export * from "./cluster-role-binding.api"; +export * from "./configmap.api"; +export * from "./crd.api"; +export * from "./cron-job.api"; +export * from "./daemon-set.api"; +export * from "./deployment.api"; +export * from "./endpoint.api"; +export * from "./events.api"; +export * from "./hpa.api"; +export * from "./ingress.api"; +export * from "./job.api"; +export * from "./namespaces.api"; +export * from "./network-policy.api"; +export * from "./nodes.api"; +export * from "./persistent-volume.api"; +export * from "./persistent-volume-claims.api"; +export * from "./pods.api"; +export * from "./poddisruptionbudget.api"; +export * from "./pod-metrics.api"; +export * from "./podsecuritypolicy.api"; +export * from "./replica-set.api"; +export * from "./resource-quota.api"; +export * from "./role.api"; +export * from "./role-binding.api"; +export * from "./secret.api"; +export * from "./selfsubjectrulesreviews.api"; +export * from "./service.api"; +export * from "./service-accounts.api"; +export * from "./stateful-set.api"; +export * from "./storage-class.api"; diff --git a/src/renderer/api/endpoints/ingress.api.ts b/src/renderer/api/endpoints/ingress.api.ts index 1f3e1659f0..0594e3446e 100644 --- a/src/renderer/api/endpoints/ingress.api.ts +++ b/src/renderer/api/endpoints/ingress.api.ts @@ -5,7 +5,7 @@ import { KubeApi } from "../kube-api"; export class IngressApi extends KubeApi { getMetrics(ingress: string, namespace: string): Promise { - const opts = { category: "ingress", ingress } + const opts = { category: "ingress", ingress }; return metricsApi.getMetrics({ bytesSentSuccess: opts, bytesSentFailure: opts, @@ -31,9 +31,9 @@ export interface ILoadBalancerIngress { } @autobind() export class Ingress extends KubeObject { - static kind = "Ingress" - static namespaced = true - static apiBase = "/apis/extensions/v1beta1/ingresses" + static kind = "Ingress"; + static namespaced = true; + static apiBase = "/apis/extensions/v1beta1/ingresses"; spec: { tls: { @@ -55,59 +55,59 @@ export class Ingress extends KubeObject { serviceName: string; servicePort: number; }; - } + }; status: { loadBalancer: { ingress: ILoadBalancerIngress[]; }; - } + }; getRoutes() { - const { spec: { tls, rules } } = this - if (!rules) return [] + const { spec: { tls, rules } } = this; + if (!rules) return []; - let protocol = "http" - const routes: string[] = [] + let protocol = "http"; + const routes: string[] = []; if (tls && tls.length > 0) { - protocol += "s" + protocol += "s"; } rules.map(rule => { - const host = rule.host ? rule.host : "*" + const host = rule.host ? rule.host : "*"; if (rule.http && rule.http.paths) { rule.http.paths.forEach(path => { - routes.push(protocol + "://" + host + (path.path || "/") + " ⇢ " + path.backend.serviceName + ":" + path.backend.servicePort) - }) + routes.push(protocol + "://" + host + (path.path || "/") + " ⇢ " + path.backend.serviceName + ":" + path.backend.servicePort); + }); } - }) + }); return routes; } getHosts() { - const { spec: { rules } } = this - if (!rules) return [] - return rules.filter(rule => rule.host).map(rule => rule.host) + const { spec: { rules } } = this; + if (!rules) return []; + return rules.filter(rule => rule.host).map(rule => rule.host); } getPorts() { - const ports: number[] = [] - const { spec: { tls, rules, backend } } = this - const httpPort = 80 - const tlsPort = 443 + const ports: number[] = []; + const { spec: { tls, rules, backend } } = this; + const httpPort = 80; + const tlsPort = 443; if (rules && rules.length > 0) { if (rules.some(rule => rule.hasOwnProperty("http"))) { - ports.push(httpPort) + ports.push(httpPort); } } else { if (backend && backend.servicePort) { - ports.push(backend.servicePort) + ports.push(backend.servicePort); } } if (tls && tls.length > 0) { - ports.push(tlsPort) + ports.push(tlsPort); } - return ports.join(", ") + return ports.join(", "); } getLoadBalancers() { @@ -115,7 +115,7 @@ export class Ingress extends KubeObject { return (loadBalancer.ingress ?? []).map(address => ( address.hostname || address.ip - )) + )); } } diff --git a/src/renderer/api/endpoints/job.api.ts b/src/renderer/api/endpoints/job.api.ts index 59e9e9ba8f..1dc78fdc94 100644 --- a/src/renderer/api/endpoints/job.api.ts +++ b/src/renderer/api/endpoints/job.api.ts @@ -7,9 +7,9 @@ import { JsonApiParams } from "../json-api"; @autobind() export class Job extends WorkloadKubeObject { - static kind = "Job" - static namespaced = true - static apiBase = "/apis/batch/v1/jobs" + static kind = "Job"; + static namespaced = true; + static apiBase = "/apis/batch/v1/jobs"; spec: { parallelism?: number; @@ -56,7 +56,7 @@ export class Job extends WorkloadKubeObject { serviceAccountName?: string; serviceAccount?: string; schedulerName?: string; - } + }; status: { conditions: { type: string; @@ -68,7 +68,7 @@ export class Job extends WorkloadKubeObject { startTime: string; completionTime: string; succeeded: number; - } + }; getDesiredCompletions() { return this.spec.completions || 0; @@ -91,15 +91,15 @@ export class Job extends WorkloadKubeObject { } getImages() { - const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []) - return [...containers].map(container => container.image) + const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []); + return [...containers].map(container => container.image); } delete() { const params: JsonApiParams = { query: { propagationPolicy: "Background" } - } - return super.delete(params) + }; + return super.delete(params); } } diff --git a/src/renderer/api/endpoints/metrics.api.ts b/src/renderer/api/endpoints/metrics.api.ts index 81d2f1d500..7f30487d44 100644 --- a/src/renderer/api/endpoints/metrics.api.ts +++ b/src/renderer/api/endpoints/metrics.api.ts @@ -66,7 +66,7 @@ export function normalizeMetrics(metrics: IMetrics, frames = 60): IMetrics { } as IMetricsResult], }, status: "", - } + }; } const { result } = metrics.data; @@ -78,7 +78,7 @@ export function normalizeMetrics(metrics: IMetrics, frames = 60): IMetrics { if (!res.values || !res.values.length) return; while (res.values.length < frames) { const timestamp = moment.unix(res.values[0][0]).subtract(1, "minute").unix(); - res.values.unshift([timestamp, "0"]) + res.values.unshift([timestamp, "0"]); } }); } @@ -103,7 +103,7 @@ export function getItemMetrics(metrics: { [key: string]: IMetrics }, itemName: s const itemMetrics = { ...metrics }; for (const metric in metrics) { if (!metrics[metric]?.data?.result) { - continue + continue; } const results = metrics[metric].data.result; const result = results.find(res => Object.values(res.metric)[0] == itemName); diff --git a/src/renderer/api/endpoints/namespaces.api.ts b/src/renderer/api/endpoints/namespaces.api.ts index c615789cd9..430565bf57 100644 --- a/src/renderer/api/endpoints/namespaces.api.ts +++ b/src/renderer/api/endpoints/namespaces.api.ts @@ -15,7 +15,7 @@ export class Namespace extends KubeObject { status?: { phase: string; - } + }; getStatus() { return this.status ? this.status.phase : "-"; diff --git a/src/renderer/api/endpoints/network-policy.api.ts b/src/renderer/api/endpoints/network-policy.api.ts index bfae6cbcdc..4ecd333854 100644 --- a/src/renderer/api/endpoints/network-policy.api.ts +++ b/src/renderer/api/endpoints/network-policy.api.ts @@ -37,9 +37,9 @@ export interface IPolicyEgress { @autobind() export class NetworkPolicy extends KubeObject { - static kind = "NetworkPolicy" - static namespaced = true - static apiBase = "/apis/networking.k8s.io/v1/networkpolicies" + static kind = "NetworkPolicy"; + static namespaced = true; + static apiBase = "/apis/networking.k8s.io/v1/networkpolicies"; spec: { podSelector: { @@ -51,13 +51,13 @@ export class NetworkPolicy extends KubeObject { policyTypes: string[]; ingress: IPolicyIngress[]; egress: IPolicyEgress[]; - } + }; getMatchLabels(): string[] { if (!this.spec.podSelector || !this.spec.podSelector.matchLabels) return []; return Object .entries(this.spec.podSelector.matchLabels) - .map(data => data.join(":")) + .map(data => data.join(":")); } getTypes(): string[] { diff --git a/src/renderer/api/endpoints/nodes.api.ts b/src/renderer/api/endpoints/nodes.api.ts index f8031a9824..c85cd8f9b0 100644 --- a/src/renderer/api/endpoints/nodes.api.ts +++ b/src/renderer/api/endpoints/nodes.api.ts @@ -5,7 +5,7 @@ import { KubeApi } from "../kube-api"; export class NodesApi extends KubeApi { getMetrics(): Promise { - const opts = { category: "nodes"} + const opts = { category: "nodes"}; return metricsApi.getMetrics({ memoryUsage: opts, @@ -30,9 +30,9 @@ export interface INodeMetrics { @autobind() export class Node extends KubeObject { - static kind = "Node" - static namespaced = false - static apiBase = "/api/v1/nodes" + static kind = "Node"; + static namespaced = false; + static apiBase = "/api/v1/nodes"; spec: { podCIDR: string; @@ -43,7 +43,7 @@ export class Node extends KubeObject { effect: string; }[]; unschedulable?: boolean; - } + }; status: { capacity: { cpu: string; @@ -83,15 +83,15 @@ export class Node extends KubeObject { names: string[]; sizeBytes: number; }[]; - } + }; getNodeConditionText() { - const { conditions } = this.status - if (!conditions) return "" + const { conditions } = this.status; + if (!conditions) return ""; return conditions.reduce((types, current) => { - if (current.status !== "True") return "" - return types += ` ${current.type}` - }, "") + if (current.status !== "True") return ""; + return types += ` ${current.type}`; + }, ""); } getTaints() { @@ -101,23 +101,23 @@ export class Node extends KubeObject { getRoleLabels() { const roleLabels = Object.keys(this.metadata.labels).filter(key => key.includes("node-role.kubernetes.io") - ).map(key => key.match(/([^/]+$)/)[0]) // all after last slash + ).map(key => key.match(/([^/]+$)/)[0]); // all after last slash if (this.metadata.labels["kubernetes.io/role"] != undefined) { - roleLabels.push(this.metadata.labels["kubernetes.io/role"]) + roleLabels.push(this.metadata.labels["kubernetes.io/role"]); } - return roleLabels.join(", ") + return roleLabels.join(", "); } getCpuCapacity() { - if (!this.status.capacity || !this.status.capacity.cpu) return 0 - return cpuUnitsToNumber(this.status.capacity.cpu) + if (!this.status.capacity || !this.status.capacity.cpu) return 0; + return cpuUnitsToNumber(this.status.capacity.cpu); } getMemoryCapacity() { - if (!this.status.capacity || !this.status.capacity.memory) return 0 - return unitsToBytes(this.status.capacity.memory) + if (!this.status.capacity || !this.status.capacity.memory) return 0; + return unitsToBytes(this.status.capacity.memory); } getConditions() { @@ -144,16 +144,16 @@ export class Node extends KubeObject { } getOperatingSystem(): string { - const label = this.getLabels().find(label => label.startsWith("kubernetes.io/os=")) + const label = this.getLabels().find(label => label.startsWith("kubernetes.io/os=")); if (label) { - return label.split("=", 2)[1] + return label.split("=", 2)[1]; } - return "linux" + return "linux"; } isUnschedulable() { - return this.spec.unschedulable + return this.spec.unschedulable; } } diff --git a/src/renderer/api/endpoints/persistent-volume-claims.api.ts b/src/renderer/api/endpoints/persistent-volume-claims.api.ts index 4e719c529b..9aa73bb0bc 100644 --- a/src/renderer/api/endpoints/persistent-volume-claims.api.ts +++ b/src/renderer/api/endpoints/persistent-volume-claims.api.ts @@ -23,9 +23,9 @@ export interface IPvcMetrics { @autobind() export class PersistentVolumeClaim extends KubeObject { - static kind = "PersistentVolumeClaim" - static namespaced = true - static apiBase = "/api/v1/persistentvolumeclaims" + static kind = "PersistentVolumeClaim"; + static namespaced = true; + static apiBase = "/api/v1/persistentvolumeclaims"; spec: { accessModes: string[]; @@ -45,19 +45,19 @@ export class PersistentVolumeClaim extends KubeObject { storage: string; // 8Gi }; }; - } + }; status: { phase: string; // Pending - } + }; getPods(allPods: Pod[]): Pod[] { - const pods = allPods.filter(pod => pod.getNs() === this.getNs()) + const pods = allPods.filter(pod => pod.getNs() === this.getNs()); return pods.filter(pod => { return pod.getVolumes().filter(volume => volume.persistentVolumeClaim && volume.persistentVolumeClaim.claimName === this.getName() - ).length > 0 - }) + ).length > 0; + }); } getStorage(): string { @@ -78,7 +78,7 @@ export class PersistentVolumeClaim extends KubeObject { getStatus(): string { if (this.status) return this.status.phase; - return "-" + return "-"; } } diff --git a/src/renderer/api/endpoints/persistent-volume.api.ts b/src/renderer/api/endpoints/persistent-volume.api.ts index 8ab2efbf89..5e31eeb028 100644 --- a/src/renderer/api/endpoints/persistent-volume.api.ts +++ b/src/renderer/api/endpoints/persistent-volume.api.ts @@ -5,9 +5,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class PersistentVolume extends KubeObject { - static kind = "PersistentVolume" - static namespaced = false - static apiBase = "/api/v1/persistentvolumes" + static kind = "PersistentVolume"; + static namespaced = false; + static apiBase = "/api/v1/persistentvolumes"; spec: { capacity: { @@ -38,17 +38,17 @@ export class PersistentVolume extends KubeObject { path: string; server: string; }; - } + }; status: { phase: string; reason?: string; - } + }; getCapacity(inBytes = false) { const capacity = this.spec.capacity; if (capacity) { - if (inBytes) return unitsToBytes(capacity.storage) + if (inBytes) return unitsToBytes(capacity.storage); return capacity.storage; } return 0; diff --git a/src/renderer/api/endpoints/pod-metrics.api.ts b/src/renderer/api/endpoints/pod-metrics.api.ts index 7e01a1a990..acf6e7b20f 100644 --- a/src/renderer/api/endpoints/pod-metrics.api.ts +++ b/src/renderer/api/endpoints/pod-metrics.api.ts @@ -2,19 +2,19 @@ import { KubeObject } from "../kube-object"; import { KubeApi } from "../kube-api"; export class PodMetrics extends KubeObject { - static kind = "Pod" - static namespaced = true - static apiBase = "/apis/metrics.k8s.io/v1beta1/pods" + static kind = "Pod"; + static namespaced = true; + static apiBase = "/apis/metrics.k8s.io/v1beta1/pods"; - timestamp: string - window: string + timestamp: string; + window: string; containers: { name: string; usage: { cpu: string; memory: string; }; - }[] + }[]; } export const podMetricsApi = new KubeApi({ diff --git a/src/renderer/api/endpoints/poddisruptionbudget.api.ts b/src/renderer/api/endpoints/poddisruptionbudget.api.ts index ea7e0575ff..b76260ae6f 100644 --- a/src/renderer/api/endpoints/poddisruptionbudget.api.ts +++ b/src/renderer/api/endpoints/poddisruptionbudget.api.ts @@ -12,13 +12,13 @@ export class PodDisruptionBudget extends KubeObject { minAvailable: string; maxUnavailable: string; selector: { matchLabels: { [app: string]: string } }; - } + }; status: { currentHealthy: number desiredHealthy: number disruptionsAllowed: number expectedPods: number - } + }; getSelectors() { const selector = this.spec.selector; diff --git a/src/renderer/api/endpoints/pods.api.ts b/src/renderer/api/endpoints/pods.api.ts index 92b7059272..a5c833b5fa 100644 --- a/src/renderer/api/endpoints/pods.api.ts +++ b/src/renderer/api/endpoints/pods.api.ts @@ -11,7 +11,7 @@ export class PodsApi extends KubeApi { getMetrics(pods: Pod[], namespace: string, selector = "pod, namespace"): Promise { const podSelector = pods.map(pod => pod.getName()).join("|"); - const opts = { category: "pods", pods: podSelector, namespace, selector } + const opts = { category: "pods", pods: podSelector, namespace, selector }; return metricsApi.getMetrics({ cpuUsage: opts, @@ -171,9 +171,9 @@ export interface IPodContainerStatus { @autobind() export class Pod extends WorkloadKubeObject { - static kind = "Pod" - static namespaced = true - static apiBase = "/api/v1/pods" + static kind = "Pod"; + static namespaced = true; + static apiBase = "/api/v1/pods"; spec: { volumes?: { @@ -215,7 +215,7 @@ export class Pod extends WorkloadKubeObject { tolerationSeconds: number; }[]; affinity: IAffinity; - } + }; status: { phase: string; conditions: { @@ -231,7 +231,7 @@ export class Pod extends WorkloadKubeObject { containerStatuses?: IPodContainerStatus[]; qosClass: string; reason?: string; - } + }; getInitContainers() { return this.spec.initContainers || []; @@ -246,11 +246,11 @@ export class Pod extends WorkloadKubeObject { } getRunningContainers() { - const statuses = this.getContainerStatuses() + const statuses = this.getContainerStatuses(); return this.getAllContainers().filter(container => { - return statuses.find(status => status.name === container.name && !!status.state["running"]) + return statuses.find(status => status.name === container.name && !!status.state["running"]); } - ) + ); } getContainerStatuses(includeInitContainers = true) { @@ -323,7 +323,7 @@ export class Pod extends WorkloadKubeObject { const { reason } = state.terminated; message = reason ? reason : "Terminated"; } - }) + }); } if (message) return message; return this.getStatusPhase(); @@ -348,32 +348,32 @@ export class Pod extends WorkloadKubeObject { } getNodeSelectors(): string[] { - const { nodeSelector } = this.spec - if (!nodeSelector) return [] - return Object.entries(nodeSelector).map(values => values.join(": ")) + const { nodeSelector } = this.spec; + if (!nodeSelector) return []; + return Object.entries(nodeSelector).map(values => values.join(": ")); } getTolerations() { - return this.spec.tolerations || [] + return this.spec.tolerations || []; } getAffinity(): IAffinity { - return this.spec.affinity + return this.spec.affinity; } hasIssues() { const notReady = !!this.getConditions().find(condition => { - return condition.type == "Ready" && condition.status !== "True" + return condition.type == "Ready" && condition.status !== "True"; }); const crashLoop = !!this.getContainerStatuses().find(condition => { - const waiting = condition.state.waiting - return (waiting && waiting.reason == "CrashLoopBackOff") - }) + const waiting = condition.state.waiting; + return (waiting && waiting.reason == "CrashLoopBackOff"); + }); return ( notReady || crashLoop || this.getStatusPhase() !== "Running" - ) + ); } getLivenessProbe(container: IPodContainer) { @@ -418,14 +418,14 @@ export class Pod extends WorkloadKubeObject { } getNodeName() { - return this.spec?.nodeName + return this.spec?.nodeName; } getSelectedNodeOs() { - if (!this.spec.nodeSelector) return - if (!this.spec.nodeSelector["kubernetes.io/os"] && !this.spec.nodeSelector["beta.kubernetes.io/os"]) return + if (!this.spec.nodeSelector) return; + if (!this.spec.nodeSelector["kubernetes.io/os"] && !this.spec.nodeSelector["beta.kubernetes.io/os"]) return; - return this.spec.nodeSelector["kubernetes.io/os"] || this.spec.nodeSelector["beta.kubernetes.io/os"] + return this.spec.nodeSelector["kubernetes.io/os"] || this.spec.nodeSelector["beta.kubernetes.io/os"]; } } diff --git a/src/renderer/api/endpoints/podsecuritypolicy.api.ts b/src/renderer/api/endpoints/podsecuritypolicy.api.ts index aa705c8748..c7981f65be 100644 --- a/src/renderer/api/endpoints/podsecuritypolicy.api.ts +++ b/src/renderer/api/endpoints/podsecuritypolicy.api.ts @@ -4,9 +4,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class PodSecurityPolicy extends KubeObject { - static kind = "PodSecurityPolicy" - static namespaced = false - static apiBase = "/apis/policy/v1beta1/podsecuritypolicies" + static kind = "PodSecurityPolicy"; + static namespaced = false; + static apiBase = "/apis/policy/v1beta1/podsecuritypolicies"; spec: { allowPrivilegeEscalation?: boolean; @@ -66,7 +66,7 @@ export class PodSecurityPolicy extends KubeObject { ranges: { max: number; min: number }[]; }; volumes?: string[]; - } + }; isPrivileged() { return !!this.spec.privileged; diff --git a/src/renderer/api/endpoints/replica-set.api.ts b/src/renderer/api/endpoints/replica-set.api.ts index dd06299644..d1081811e9 100644 --- a/src/renderer/api/endpoints/replica-set.api.ts +++ b/src/renderer/api/endpoints/replica-set.api.ts @@ -6,9 +6,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class ReplicaSet extends WorkloadKubeObject { - static kind = "ReplicaSet" - static namespaced = true - static apiBase = "/apis/apps/v1/replicasets" + static kind = "ReplicaSet"; + static namespaced = true; + static apiBase = "/apis/apps/v1/replicasets"; spec: { replicas?: number; @@ -37,18 +37,18 @@ export class ReplicaSet extends WorkloadKubeObject { terminationGracePeriodSeconds?: number; dnsPolicy?: string; schedulerName?: string; - } + }; status: { replicas: number; fullyLabeledReplicas: number; readyReplicas: number; availableReplicas: number; observedGeneration: number; - } + }; getImages() { - const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []) - return [...containers].map(container => container.image) + const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []); + return [...containers].map(container => container.image); } } diff --git a/src/renderer/api/endpoints/resource-applier.api.ts b/src/renderer/api/endpoints/resource-applier.api.ts index 088c7ed8f2..a2843a6262 100644 --- a/src/renderer/api/endpoints/resource-applier.api.ts +++ b/src/renderer/api/endpoints/resource-applier.api.ts @@ -1,4 +1,4 @@ -import jsYaml from "js-yaml" +import jsYaml from "js-yaml"; import { KubeObject } from "../kube-object"; import { KubeJsonApiData } from "../kube-json-api"; import { apiBase } from "../index"; @@ -21,7 +21,7 @@ export const resourceApplierApi = { if (api) { return new api.objectConstructor(obj); } else { - return new KubeObject(obj) + return new KubeObject(obj); } }); return items.length === 1 ? items[0] : items; diff --git a/src/renderer/api/endpoints/resource-quota.api.ts b/src/renderer/api/endpoints/resource-quota.api.ts index ce73d24595..a19e4025c5 100644 --- a/src/renderer/api/endpoints/resource-quota.api.ts +++ b/src/renderer/api/endpoints/resource-quota.api.ts @@ -31,13 +31,13 @@ export interface IResourceQuotaValues { } export class ResourceQuota extends KubeObject { - static kind = "ResourceQuota" - static namespaced = true - static apiBase = "/api/v1/resourcequotas" + static kind = "ResourceQuota"; + static namespaced = true; + static apiBase = "/api/v1/resourcequotas"; constructor(data: KubeJsonApiData) { super(data); - this.spec = this.spec || {} as any + this.spec = this.spec || {} as any; } spec: { @@ -49,12 +49,12 @@ export class ResourceQuota extends KubeObject { values: string[]; }[]; }; - } + }; status: { hard: IResourceQuotaValues; used: IResourceQuotaValues; - } + }; getScopeSelector() { const { matchExpressions = [] } = this.spec.scopeSelector || {}; diff --git a/src/renderer/api/endpoints/role-binding.api.ts b/src/renderer/api/endpoints/role-binding.api.ts index 455e2c6e4d..866656ee56 100644 --- a/src/renderer/api/endpoints/role-binding.api.ts +++ b/src/renderer/api/endpoints/role-binding.api.ts @@ -11,23 +11,23 @@ export interface IRoleBindingSubject { @autobind() export class RoleBinding extends KubeObject { - static kind = "RoleBinding" - static namespaced = true - static apiBase = "/apis/rbac.authorization.k8s.io/v1/rolebindings" + static kind = "RoleBinding"; + static namespaced = true; + static apiBase = "/apis/rbac.authorization.k8s.io/v1/rolebindings"; - subjects?: IRoleBindingSubject[] + subjects?: IRoleBindingSubject[]; roleRef: { kind: string; name: string; apiGroup?: string; - } + }; getSubjects() { return this.subjects || []; } getSubjectNames(): string { - return this.getSubjects().map(subject => subject.name).join(", ") + return this.getSubjects().map(subject => subject.name).join(", "); } } diff --git a/src/renderer/api/endpoints/role.api.ts b/src/renderer/api/endpoints/role.api.ts index 400761cfbe..c89834ed05 100644 --- a/src/renderer/api/endpoints/role.api.ts +++ b/src/renderer/api/endpoints/role.api.ts @@ -2,16 +2,16 @@ import { KubeObject } from "../kube-object"; import { KubeApi } from "../kube-api"; export class Role extends KubeObject { - static kind = "Role" - static namespaced = true - static apiBase = "/apis/rbac.authorization.k8s.io/v1/roles" + static kind = "Role"; + static namespaced = true; + static apiBase = "/apis/rbac.authorization.k8s.io/v1/roles"; rules: { verbs: string[]; apiGroups: string[]; resources: string[]; resourceNames?: string[]; - }[] + }[]; getRules() { return this.rules || []; diff --git a/src/renderer/api/endpoints/secret.api.ts b/src/renderer/api/endpoints/secret.api.ts index f2166abbe1..16262570df 100644 --- a/src/renderer/api/endpoints/secret.api.ts +++ b/src/renderer/api/endpoints/secret.api.ts @@ -21,15 +21,15 @@ export interface ISecretRef { @autobind() export class Secret extends KubeObject { - static kind = "Secret" - static namespaced = true - static apiBase = "/api/v1/secrets" + static kind = "Secret"; + static namespaced = true; + static apiBase = "/api/v1/secrets"; type: SecretType; data: { [prop: string]: string; token?: string; - } + }; constructor(data: KubeJsonApiData) { super(data); diff --git a/src/renderer/api/endpoints/selfsubjectrulesreviews.api.ts b/src/renderer/api/endpoints/selfsubjectrulesreviews.api.ts index 1beece3fc3..149a94e678 100644 --- a/src/renderer/api/endpoints/selfsubjectrulesreviews.api.ts +++ b/src/renderer/api/endpoints/selfsubjectrulesreviews.api.ts @@ -21,20 +21,20 @@ export interface ISelfSubjectReviewRule { } export class SelfSubjectRulesReview extends KubeObject { - static kind = "SelfSubjectRulesReview" - static namespaced = false - static apiBase = "/apis/authorization.k8s.io/v1/selfsubjectrulesreviews" + static kind = "SelfSubjectRulesReview"; + static namespaced = false; + static apiBase = "/apis/authorization.k8s.io/v1/selfsubjectrulesreviews"; spec: { // todo: add more types from api docs namespace?: string; - } + }; status: { resourceRules: ISelfSubjectReviewRule[]; nonResourceRules: ISelfSubjectReviewRule[]; incomplete: boolean; - } + }; getResourceRules() { const rules = this.status && this.status.resourceRules || []; @@ -58,7 +58,7 @@ export class SelfSubjectRulesReview extends KubeObject { const separator = apiGroup == "" ? "" : "."; return resource + separator + apiGroup; }) - } + }; } } diff --git a/src/renderer/api/endpoints/service-accounts.api.ts b/src/renderer/api/endpoints/service-accounts.api.ts index 4f3ae47014..9f449cdec4 100644 --- a/src/renderer/api/endpoints/service-accounts.api.ts +++ b/src/renderer/api/endpoints/service-accounts.api.ts @@ -6,14 +6,14 @@ import { KubeApi } from "../kube-api"; export class ServiceAccount extends KubeObject { static kind = "ServiceAccount"; static namespaced = true; - static apiBase = "/api/v1/serviceaccounts" + static apiBase = "/api/v1/serviceaccounts"; secrets?: { name: string; - }[] + }[]; imagePullSecrets?: { name: string; - }[] + }[]; getSecrets() { return this.secrets || []; diff --git a/src/renderer/api/endpoints/service.api.ts b/src/renderer/api/endpoints/service.api.ts index 49ac733220..5524e85263 100644 --- a/src/renderer/api/endpoints/service.api.ts +++ b/src/renderer/api/endpoints/service.api.ts @@ -17,7 +17,7 @@ export class ServicePort implements IServicePort { nodePort?: number; constructor(data: IServicePort) { - Object.assign(this, data) + Object.assign(this, data); } toString() { @@ -31,9 +31,9 @@ export class ServicePort implements IServicePort { @autobind() export class Service extends KubeObject { - static kind = "Service" - static namespaced = true - static apiBase = "/api/v1/services" + static kind = "Service"; + static namespaced = true; + static apiBase = "/api/v1/services"; spec: { type: string; @@ -44,7 +44,7 @@ export class Service extends KubeObject { selector: { [key: string]: string }; ports: ServicePort[]; externalIPs?: string[]; // https://kubernetes.io/docs/concepts/services-networking/service/#external-ips - } + }; status: { loadBalancer?: { @@ -53,7 +53,7 @@ export class Service extends KubeObject { hostname?: string; }[]; }; - } + }; getClusterIp() { return this.spec.clusterIP; @@ -62,7 +62,7 @@ export class Service extends KubeObject { getExternalIps() { const lb = this.getLoadBalancer(); if (lb && lb.ingress) { - return lb.ingress.map(val => val.ip || val.hostname) + return lb.ingress.map(val => val.ip || val.hostname); } return this.spec.externalIPs || []; } diff --git a/src/renderer/api/endpoints/stateful-set.api.ts b/src/renderer/api/endpoints/stateful-set.api.ts index c507e7df59..6a6f8c151d 100644 --- a/src/renderer/api/endpoints/stateful-set.api.ts +++ b/src/renderer/api/endpoints/stateful-set.api.ts @@ -6,9 +6,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class StatefulSet extends WorkloadKubeObject { - static kind = "StatefulSet" - static namespaced = true - static apiBase = "/apis/apps/v1/statefulsets" + static kind = "StatefulSet"; + static namespaced = true; + static apiBase = "/apis/apps/v1/statefulsets"; spec: { serviceName: string; @@ -62,7 +62,7 @@ export class StatefulSet extends WorkloadKubeObject { }; }; }[]; - } + }; status: { observedGeneration: number; replicas: number; @@ -70,11 +70,11 @@ export class StatefulSet extends WorkloadKubeObject { currentRevision: string; updateRevision: string; collisionCount: number; - } + }; getImages() { - const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []) - return [...containers].map(container => container.image) + const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []); + return [...containers].map(container => container.image); } } diff --git a/src/renderer/api/endpoints/storage-class.api.ts b/src/renderer/api/endpoints/storage-class.api.ts index cf05e13eaf..adb2059e4a 100644 --- a/src/renderer/api/endpoints/storage-class.api.ts +++ b/src/renderer/api/endpoints/storage-class.api.ts @@ -4,9 +4,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class StorageClass extends KubeObject { - static kind = "StorageClass" - static namespaced = false - static apiBase = "/apis/storage.k8s.io/v1/storageclasses" + static kind = "StorageClass"; + static namespaced = false; + static apiBase = "/apis/storage.k8s.io/v1/storageclasses"; provisioner: string; // e.g. "storage.k8s.io/v1" mountOptions?: string[]; @@ -14,22 +14,22 @@ export class StorageClass extends KubeObject { reclaimPolicy: string; parameters: { [param: string]: string; // every provisioner has own set of these parameters - } + }; isDefault() { const annotations = this.metadata.annotations || {}; return ( annotations["storageclass.kubernetes.io/is-default-class"] === "true" || annotations["storageclass.beta.kubernetes.io/is-default-class"] === "true" - ) + ); } getVolumeBindingMode() { - return this.volumeBindingMode || "-" + return this.volumeBindingMode || "-"; } getReclaimPolicy() { - return this.reclaimPolicy || "-" + return this.reclaimPolicy || "-"; } } diff --git a/src/renderer/api/json-api.ts b/src/renderer/api/json-api.ts index e42996c041..cc239a804e 100644 --- a/src/renderer/api/json-api.ts +++ b/src/renderer/api/json-api.ts @@ -110,23 +110,23 @@ export class JsonApi { } else { const error = new JsonApiErrorParsed(data, this.parseError(data, res)); this.onError.emit(error, res); - this.writeLog({ ...log, error }) + this.writeLog({ ...log, error }); throw error; } - }) + }); } protected parseError(error: JsonApiError | string, res: Response): string[] { if (typeof error === "string") { - return [error] + return [error]; } else if (Array.isArray(error.errors)) { - return error.errors.map(error => error.title) + return error.errors.map(error => error.title); } else if (error.message) { - return [error.message] + return [error.message]; } - return [res.statusText || "Error!"] + return [res.statusText || "Error!"]; } protected writeLog(log: JsonApiLog) { diff --git a/src/renderer/api/kube-api-parse.ts b/src/renderer/api/kube-api-parse.ts index c4c93562cf..0995fac24f 100644 --- a/src/renderer/api/kube-api-parse.ts +++ b/src/renderer/api/kube-api-parse.ts @@ -51,7 +51,7 @@ export function parseKubeApi(path: string): IKubeApiParsed { } else { switch (left.length) { case 4: - [apiGroup, apiVersion, resource, name] = left + [apiGroup, apiVersion, resource, name] = left; break; case 2: resource = left.pop(); @@ -79,11 +79,11 @@ export function parseKubeApi(path: string): IKubeApiParsed { */ if (left[0].includes('.') || left[1].match(/^v[0-9]/)) { [apiGroup, apiVersion] = left; - resource = left.slice(2).join("/") + resource = left.slice(2).join("/"); } else { apiGroup = ""; apiVersion = left[0]; - [resource, name] = left.slice(1) + [resource, name] = left.slice(1); } break; } @@ -93,7 +93,7 @@ export function parseKubeApi(path: string): IKubeApiParsed { const apiBase = [apiPrefix, apiGroup, apiVersion, resource].filter(v => v).join("/"); if (!apiBase) { - throw new Error(`invalid apiPath: ${path}`) + throw new Error(`invalid apiPath: ${path}`); } return { @@ -108,11 +108,11 @@ export function createKubeApiURL(ref: IKubeApiLinkRef): string { const { apiPrefix = "/apis", resource, apiVersion, name } = ref; let { namespace } = ref; if (namespace) { - namespace = `namespaces/${namespace}` + namespace = `namespaces/${namespace}`; } return [apiPrefix, apiVersion, namespace, resource, name] .filter(v => v) - .join("/") + .join("/"); } export function lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): string { @@ -124,9 +124,9 @@ export function lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): st if (!kind) return ""; // search in registered apis by 'kind' & 'apiVersion' - const api = apiManager.getApi(api => api.kind === kind && api.apiVersionWithGroup == apiVersion) + const api = apiManager.getApi(api => api.kind === kind && api.apiVersionWithGroup == apiVersion); if (api) { - return api.getUrl({ namespace, name }) + return api.getUrl({ namespace, name }); } // lookup api by generated resource link @@ -142,10 +142,10 @@ export function lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): st // resolve by kind only (hpa's might use refs to older versions of resources for example) const apiByKind = apiManager.getApi(api => api.kind === kind); if (apiByKind) { - return apiByKind.getUrl({ name, namespace }) + return apiByKind.getUrl({ name, namespace }); } // otherwise generate link with default prefix // resource still might exists in k8s, but api is not registered in the app - return createKubeApiURL({ apiVersion, name, namespace, resource }) + return createKubeApiURL({ apiVersion, name, namespace, resource }); } diff --git a/src/renderer/api/kube-api.ts b/src/renderer/api/kube-api.ts index c3c9698cfa..d4840d3620 100644 --- a/src/renderer/api/kube-api.ts +++ b/src/renderer/api/kube-api.ts @@ -1,6 +1,6 @@ // Base class for building all kubernetes apis -import merge from "lodash/merge" +import merge from "lodash/merge"; import { stringify } from "querystring"; import { IKubeObjectConstructor, KubeObject } from "./kube-object"; import { KubeJsonApi, KubeJsonApiData, KubeJsonApiDataList } from "./kube-json-api"; @@ -51,7 +51,7 @@ export function forCluster(cluster: IKubeApiCluster, kubeC return new KubeApi({ objectConstructor: kubeClass, request: request - }) + }); } export class KubeApi { @@ -62,14 +62,14 @@ export class KubeApi { return () => disposers.forEach(unwatch => unwatch()); } - readonly kind: string - readonly apiBase: string - readonly apiPrefix: string - readonly apiGroup: string - readonly apiVersion: string + readonly kind: string; + readonly apiBase: string; + readonly apiPrefix: string; + readonly apiGroup: string; + readonly apiVersion: string; readonly apiVersionPreferred?: string; - readonly apiResource: string - readonly isNamespaced: boolean + readonly apiResource: string; + readonly isNamespaced: boolean; public objectConstructor: IKubeObjectConstructor; protected request: KubeJsonApi; @@ -83,7 +83,7 @@ export class KubeApi { isNamespaced = options.objectConstructor?.namespaced } = options || {}; if (!options.apiBase) { - options.apiBase = objectConstructor.apiBase + options.apiBase = objectConstructor.apiBase; } const { apiBase, apiPrefix, apiGroup, apiVersion, apiVersionWithGroup, resource } = KubeApi.parseApi(options.apiBase); @@ -105,7 +105,7 @@ export class KubeApi { get apiVersionWithGroup() { return [this.apiGroup, this.apiVersionPreferred ?? this.apiVersion] .filter(Boolean) - .join("/") + .join("/"); } protected async checkPreferredVersion() { @@ -116,7 +116,7 @@ export class KubeApi { }); if (this.apiVersionPreferred) { - Object.defineProperty(this, "apiBase", { value: this.getUrl() }) + Object.defineProperty(this, "apiBase", { value: this.getUrl() }); apiManager.registerApi(this.apiBase, this); } } @@ -147,10 +147,10 @@ export class KubeApi { protected normalizeQuery(query: Partial = {}) { if (query.labelSelector) { - query.labelSelector = [query.labelSelector].flat().join(",") + query.labelSelector = [query.labelSelector].flat().join(","); } if (query.fieldSelector) { - query.fieldSelector = [query.fieldSelector].flat().join(",") + query.fieldSelector = [query.fieldSelector].flat().join(","); } return query; } @@ -170,7 +170,7 @@ export class KubeApi { kind: this.kind, apiVersion: apiVersion, ...item, - })) + })); } // custom apis might return array for list response, e.g. users, groups, etc. @@ -218,13 +218,13 @@ export class KubeApi { const apiUrl = this.getUrl({ namespace, name }); return this.request .put(apiUrl, { data }) - .then(this.parseResponse) + .then(this.parseResponse); } async delete({ name = "", namespace = "default" }) { await this.checkPreferredVersion(); const apiUrl = this.getUrl({ namespace, name }); - return this.request.del(apiUrl) + return this.request.del(apiUrl); } getWatchUrl(namespace = "", query: IKubeApiQueryParams = {}) { @@ -232,7 +232,7 @@ export class KubeApi { watch: 1, resourceVersion: this.getResourceVersion(namespace), ...query, - }) + }); } watch(): () => void { @@ -240,4 +240,4 @@ export class KubeApi { } } -export * from "./kube-api-parse" +export * from "./kube-api-parse"; diff --git a/src/renderer/api/kube-object-detail-registry.ts b/src/renderer/api/kube-object-detail-registry.ts index f844da9ef3..5246254532 100644 --- a/src/renderer/api/kube-object-detail-registry.ts +++ b/src/renderer/api/kube-object-detail-registry.ts @@ -1 +1 @@ -export { kubeObjectDetailRegistry } from "../../extensions/registries/kube-object-detail-registry" +export { kubeObjectDetailRegistry } from "../../extensions/registries/kube-object-detail-registry"; diff --git a/src/renderer/api/kube-object.ts b/src/renderer/api/kube-object.ts index 664f9a5c22..8d0e6123f3 100644 --- a/src/renderer/api/kube-object.ts +++ b/src/renderer/api/kube-object.ts @@ -65,20 +65,20 @@ export class KubeObject implements ItemObject { static stringifyLabels(labels: { [name: string]: string }): string[] { if (!labels) return []; - return Object.entries(labels).map(([name, value]) => `${name}=${value}`) + return Object.entries(labels).map(([name, value]) => `${name}=${value}`); } constructor(data: KubeJsonApiData) { Object.assign(this, data); } - apiVersion: string - kind: string + apiVersion: string; + kind: string; metadata: IKubeObjectMetadata; status?: any; // todo: type-safety support get selfLink() { - return this.metadata.selfLink + return this.metadata.selfLink; } getId() { @@ -131,18 +131,18 @@ export class KubeObject implements ItemObject { return refs.map(ownerRef => ({ ...ownerRef, namespace: this.getNs(), - })) + })); } getSearchFields() { - const { getName, getId, getNs, getAnnotations, getLabels } = this + const { getName, getId, getNs, getAnnotations, getLabels } = this; return [ getName(), getNs(), getId(), ...getLabels(), ...getAnnotations(true), - ] + ]; } toPlainObject(): object { diff --git a/src/renderer/api/kube-watch-api.ts b/src/renderer/api/kube-watch-api.ts index 56c3fc1c86..8ce44fb77c 100644 --- a/src/renderer/api/kube-watch-api.ts +++ b/src/renderer/api/kube-watch-api.ts @@ -1,7 +1,7 @@ // Kubernetes watch-api consumer import { computed, observable, reaction } from "mobx"; -import { stringify } from "querystring" +import { stringify } from "querystring"; import { autobind, EventEmitter } from "../utils"; import { KubeJsonApiData } from "./kube-json-api"; import type { KubeObjectStore } from "../kube-object.store"; @@ -61,13 +61,13 @@ export class KubeWatchApi { } protected getQuery(): Partial { - const { isAdmin, allowedNamespaces } = getHostedCluster() + const { isAdmin, allowedNamespaces } = getHostedCluster(); return { api: this.activeApis.map(api => { if (isAdmin) return api.getWatchUrl(); - return allowedNamespaces.map(namespace => api.getWatchUrl(namespace)) + return allowedNamespaces.map(namespace => api.getWatchUrl(namespace)); }).flat() - } + }; } // todo: maybe switch to websocket to avoid often reconnects @@ -119,11 +119,11 @@ export class KubeWatchApi { await api.refreshResourceVersion({ namespace }); this.reconnect(); } catch (error) { - console.error("failed to refresh resource version", error) + console.error("failed to refresh resource version", error); if (this.subscribers.size > 0) { setTimeout(() => { - this.onRouteEvent(event) - }, 1000) + this.onRouteEvent(event); + }, 1000); } } } diff --git a/src/renderer/api/terminal-api.ts b/src/renderer/api/terminal-api.ts index 0e8bba2df6..4f66544f86 100644 --- a/src/renderer/api/terminal-api.ts +++ b/src/renderer/api/terminal-api.ts @@ -1,7 +1,7 @@ import { stringify } from "querystring"; import { autobind, base64, EventEmitter } from "../utils"; import { WebSocketApi } from "./websocket-api"; -import isEqual from "lodash/isEqual" +import isEqual from "lodash/isEqual"; import { isDevelopment } from "../../common/vars"; export enum TerminalChannels { @@ -28,7 +28,7 @@ export type TerminalApiQuery = Record & { id: string; node?: string; type?: string | "node"; -} +}; export class TerminalApi extends WebSocketApi { protected size: { Width: number; Height: number }; @@ -51,7 +51,7 @@ export class TerminalApi extends WebSocketApi { const wss = `ws${protocol === "https:" ? "s" : ""}://`; const query: TerminalApiQuery = { id }; if (port) { - port = `:${port}` + port = `:${port}`; } if (node) { query.node = node; diff --git a/src/renderer/api/websocket-api.ts b/src/renderer/api/websocket-api.ts index cb94881035..934d6cded6 100644 --- a/src/renderer/api/websocket-api.ts +++ b/src/renderer/api/websocket-api.ts @@ -146,7 +146,7 @@ export class WebSocketApi { } protected _onError(evt: Event) { - this.writeLog('%cERROR', 'color:red;font-weight:bold;', evt) + this.writeLog('%cERROR', 'color:red;font-weight:bold;', evt); } protected _onClose(evt: CloseEvent) { diff --git a/src/renderer/api/workload-kube-object.ts b/src/renderer/api/workload-kube-object.ts index c18b8df6c4..51c0461f15 100644 --- a/src/renderer/api/workload-kube-object.ts +++ b/src/renderer/api/workload-kube-object.ts @@ -65,16 +65,16 @@ export class WorkloadKubeObject extends KubeObject { } getTolerations(): IToleration[] { - return get(this, "spec.template.spec.tolerations", []) + return get(this, "spec.template.spec.tolerations", []); } getAffinity(): IAffinity { - return get(this, "spec.template.spec.affinity") + return get(this, "spec.template.spec.affinity"); } getAffinityNumber() { - const affinity = this.getAffinity() - if (!affinity) return 0 - return Object.keys(affinity).length + const affinity = this.getAffinity(); + if (!affinity) return 0; + return Object.keys(affinity).length; } } \ No newline at end of file diff --git a/src/renderer/bootstrap.tsx b/src/renderer/bootstrap.tsx index cfadb5c379..7aa78f1682 100644 --- a/src/renderer/bootstrap.tsx +++ b/src/renderer/bootstrap.tsx @@ -1,9 +1,9 @@ -import "./components/app.scss" +import "./components/app.scss"; import React from "react"; -import * as Mobx from "mobx" -import * as MobxReact from "mobx-react" -import * as LensExtensions from "../extensions/extension-api" +import * as Mobx from "mobx"; +import * as MobxReact from "mobx-react"; +import * as LensExtensions from "../extensions/extension-api"; import { App } from "./components/app"; import { LensApp } from "./lens-app"; import { render, unmountComponentAtNode } from "react-dom"; @@ -18,20 +18,20 @@ import { extensionLoader } from "../extensions/extension-loader"; type AppComponent = React.ComponentType & { init?(): Promise; -} +}; export { React, Mobx, MobxReact, LensExtensions -} +}; export async function bootstrap(App: AppComponent) { - const rootElem = document.getElementById("app") + const rootElem = document.getElementById("app"); rootElem.classList.toggle("is-mac", isMac); - extensionLoader.init() + extensionLoader.init(); // preload common stores await Promise.all([ @@ -53,13 +53,13 @@ export async function bootstrap(App: AppComponent) { } window.addEventListener("message", (ev: MessageEvent) => { if (ev.data === "teardown") { - userStore.unregisterIpcListener() - workspaceStore.unregisterIpcListener() - clusterStore.unregisterIpcListener() - unmountComponentAtNode(rootElem) - window.location.href = "about:blank" + userStore.unregisterIpcListener(); + workspaceStore.unregisterIpcListener(); + clusterStore.unregisterIpcListener(); + unmountComponentAtNode(rootElem); + window.location.href = "about:blank"; } - }) + }); render(<> {isMac && } diff --git a/src/renderer/components/+404/index.ts b/src/renderer/components/+404/index.ts index 7314f53562..67433b02c3 100644 --- a/src/renderer/components/+404/index.ts +++ b/src/renderer/components/+404/index.ts @@ -1 +1 @@ -export * from "./not-found" +export * from "./not-found"; diff --git a/src/renderer/components/+add-cluster/add-cluster.route.ts b/src/renderer/components/+add-cluster/add-cluster.route.ts index ba3ffcd104..3f1e36be9e 100644 --- a/src/renderer/components/+add-cluster/add-cluster.route.ts +++ b/src/renderer/components/+add-cluster/add-cluster.route.ts @@ -3,6 +3,6 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const addClusterRoute: RouteProps = { path: "/add-cluster" -} +}; -export const addClusterURL = buildURL(addClusterRoute.path) +export const addClusterURL = buildURL(addClusterRoute.path); diff --git a/src/renderer/components/+add-cluster/add-cluster.tsx b/src/renderer/components/+add-cluster/add-cluster.tsx index 8acd3a51ea..abb28d090e 100644 --- a/src/renderer/components/+add-cluster/add-cluster.tsx +++ b/src/renderer/components/+add-cluster/add-cluster.tsx @@ -1,4 +1,4 @@ -import "./add-cluster.scss" +import "./add-cluster.scss"; import os from "os"; import React, { Fragment } from "react"; import { observer } from "mobx-react"; @@ -16,7 +16,7 @@ import { WizardLayout } from "../layout/wizard-layout"; import { kubeConfigDefaultPath, loadConfig, splitConfig, validateConfig, validateKubeConfig } from "../../../common/kube-helpers"; import { ClusterModel, ClusterStore, clusterStore } from "../../../common/cluster-store"; import { workspaceStore } from "../../../common/workspace-store"; -import { v4 as uuid } from "uuid" +import { v4 as uuid } from "uuid"; import { navigate } from "../../navigation"; import { userStore } from "../../../common/user-store"; import { clusterViewURL } from "../cluster-manager/cluster-view.route"; @@ -39,10 +39,10 @@ export class AddCluster extends React.Component { @observable selectedContexts = observable.array(); @observable sourceTab = KubeConfigSourceTab.FILE; @observable kubeConfigPath = ""; - @observable customConfig = "" - @observable proxyServer = "" - @observable isWaiting = false - @observable showSettings = false + @observable customConfig = ""; + @observable proxyServer = ""; + @observable isWaiting = false; + @observable showSettings = false; @observable dropAreaActive = false; componentDidMount() { @@ -84,7 +84,7 @@ export class AddCluster extends React.Component { break; case KubeConfigSourceTab.TEXT: try { - this.error = "" + this.error = ""; const contexts = this.getContexts(loadConfig(this.customConfig || "{}")); this.kubeContexts.replace(contexts); } catch (err) { @@ -94,7 +94,7 @@ export class AddCluster extends React.Component { } if (this.kubeContexts.size === 1) { - this.selectedContexts.push(this.kubeContexts.keys().next().value) + this.selectedContexts.push(this.kubeContexts.keys().next().value); } } @@ -102,8 +102,8 @@ export class AddCluster extends React.Component { const contexts = new Map(); splitConfig(config).forEach(config => { contexts.set(config.currentContext, config); - }) - return contexts + }); + return contexts; } selectKubeConfigDialog = async () => { @@ -117,18 +117,18 @@ export class AddCluster extends React.Component { if (!canceled && filePaths.length) { this.setKubeConfig(filePaths[0]); } - } + }; @action addClusters = () => { let newClusters: ClusterModel[] = []; try { if (!this.selectedContexts.length) { - this.error = Please select at least one cluster context + this.error = Please select at least one cluster context; return; } - this.error = "" - this.isWaiting = true + this.error = ""; + this.isWaiting = true; newClusters = this.selectedContexts.filter(context => { try { @@ -136,7 +136,7 @@ export class AddCluster extends React.Component { validateKubeConfig(kubeConfig); return true; } catch (err) { - this.error = String(err.message) + this.error = String(err.message); if (err instanceof ExecValidationNotFoundError ) { Notifications.error(Error while adding cluster(s): {this.error}); return false; @@ -159,8 +159,8 @@ export class AddCluster extends React.Component { clusterName: kubeConfig.currentContext, httpsProxy: this.proxyServer || undefined, }, - } - }) + }; + }); runInAction(() => { clusterStore.addClusters(...newClusters); @@ -175,7 +175,7 @@ export class AddCluster extends React.Component { ); } } - }) + }); this.refreshContexts(); } catch (err) { this.error = String(err); @@ -183,7 +183,7 @@ export class AddCluster extends React.Component { } finally { this.isWaiting = false; } - } + }; renderInfo() { return ( @@ -218,7 +218,7 @@ export class AddCluster extends React.Component { Lens app might not have all login shell env variables set automatically. - ) + ); } renderKubeConfigSource() { @@ -281,7 +281,7 @@ export class AddCluster extends React.Component { > )} > - ) + ); } renderContextSelector() { @@ -302,7 +302,7 @@ export class AddCluster extends React.Component { noOptionsMessage={() => _i18n._(t`No contexts available or they have been added already`)} onChange={({ value: ctx }: SelectOption) => { if (this.selectedContexts.includes(ctx)) { - this.selectedContexts.remove(ctx) + this.selectedContexts.remove(ctx); } else { this.selectedContexts.push(ctx); } @@ -315,7 +315,7 @@ export class AddCluster extends React.Component { )} > - ) + ); } onKubeConfigInputBlur = (evt: React.FocusEvent) => { @@ -328,13 +328,13 @@ export class AddCluster extends React.Component { this.setKubeConfig(userStore.kubeConfigPath); // revert to previous valid path } } - } + }; onKubeConfigTabChange = (tabId: KubeConfigSourceTab) => { this.sourceTab = tabId; this.error = ""; this.refreshContexts(); - } + }; protected formatContextLabel = ({ value: context }: SelectOption) => { const isNew = userStore.newContexts.has(context); @@ -345,11 +345,11 @@ export class AddCluster extends React.Component { {isNew && } {isSelected && } - ) + ); }; render() { - const addDisabled = this.selectedContexts.length === 0 + const addDisabled = this.selectedContexts.length === 0; return ( this.dropAreaActive = false, onDragOver: event => { event.preventDefault(); // enable onDrop()-callback - event.dataTransfer.dropEffect = "move" + event.dataTransfer.dropEffect = "move"; }, onDrop: event => { this.sourceTab = KubeConfigSourceTab.FILE; - this.dropAreaActive = false - this.setKubeConfig(event.dataTransfer.files[0].path) + this.dropAreaActive = false; + this.setKubeConfig(event.dataTransfer.files[0].path); } }} > @@ -407,6 +407,6 @@ export class AddCluster extends React.Component { /> - ) + ); } } diff --git a/src/renderer/components/+add-cluster/index.ts b/src/renderer/components/+add-cluster/index.ts index 42ab8bf944..1ddb3d069d 100644 --- a/src/renderer/components/+add-cluster/index.ts +++ b/src/renderer/components/+add-cluster/index.ts @@ -1,2 +1,2 @@ -export * from "./add-cluster" -export * from "./add-cluster.route" +export * from "./add-cluster"; +export * from "./add-cluster.route"; diff --git a/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx b/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx index a5531affa3..a446c4dd52 100644 --- a/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx +++ b/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx @@ -35,16 +35,16 @@ export class HelmChartDetails extends Component { } chartUpdater = autorun(() => { - this.selectedChart = null - const { chart: { name, repo, version } } = this.props + this.selectedChart = null; + const { chart: { name, repo, version } } = this.props; helmChartsApi.get(repo, name, version).then(result => { - this.readme = result.readme - this.chartVersions = result.versions - this.selectedChart = result.versions[0] + this.readme = result.readme; + this.chartVersions = result.versions; + this.selectedChart = result.versions[0]; }, error => { this.error = error; - }) + }); }); @autobind() @@ -55,7 +55,7 @@ export class HelmChartDetails extends Component { try { this.chartPromise?.cancel(); const { chart: { name, repo } } = this.props; - const { readme } = await (this.chartPromise = helmChartsApi.get(repo, name, version)) + const { readme } = await (this.chartPromise = helmChartsApi.get(repo, name, version)); this.readme = readme; } catch (error) { this.error = error; @@ -65,7 +65,7 @@ export class HelmChartDetails extends Component { @autobind() install() { createInstallChartTab(this.selectedChart); - this.props.hideDetails() + this.props.hideDetails(); } renderIntroduction() { @@ -112,14 +112,14 @@ export class HelmChartDetails extends Component { renderReadme() { if (this.readme === null) { - return + return ; } return ( - ) + ); } renderContent() { @@ -132,7 +132,7 @@ export class HelmChartDetails extends Component { {this.error} - ) + ); } return ( diff --git a/src/renderer/components/+apps-helm-charts/helm-chart.store.ts b/src/renderer/components/+apps-helm-charts/helm-chart.store.ts index 1d231c08dd..65e73b556f 100644 --- a/src/renderer/components/+apps-helm-charts/helm-chart.store.ts +++ b/src/renderer/components/+apps-helm-charts/helm-chart.store.ts @@ -1,9 +1,9 @@ -import semver from "semver" +import semver from "semver"; import { observable } from "mobx"; import { autobind } from "../../utils"; import { HelmChart, helmChartsApi } from "../../api/endpoints/helm-charts.api"; import { ItemStore } from "../../item.store"; -import flatten from "lodash/flatten" +import flatten from "lodash/flatten"; export interface IChartVersion { repo: string; @@ -24,7 +24,7 @@ export class HelmChartStore extends ItemStore { protected sortVersions = (versions: IChartVersion[]) => { return versions.sort((first, second) => { - return semver.compare(second.version, first.version) + return semver.compare(second.version, first.version); }); }; @@ -38,8 +38,8 @@ export class HelmChartStore extends ItemStore { return versions.map(chart => ({ repo: repo, version: chart.getVersion() - })) - }) + })); + }); }; if (!this.isLoaded) { await this.loadAll(); diff --git a/src/renderer/components/+apps-helm-charts/helm-charts.route.ts b/src/renderer/components/+apps-helm-charts/helm-charts.route.ts index 047ff656b6..abd0677de8 100644 --- a/src/renderer/components/+apps-helm-charts/helm-charts.route.ts +++ b/src/renderer/components/+apps-helm-charts/helm-charts.route.ts @@ -4,11 +4,11 @@ import { appsRoute } from "../+apps/apps.route"; export const helmChartsRoute: RouteProps = { path: appsRoute.path + "/charts/:repo?/:chartName?" -} +}; export interface IHelmChartsRouteParams { chartName?: string; repo?: string; } -export const helmChartsURL = buildURL(helmChartsRoute.path) \ No newline at end of file +export const helmChartsURL = buildURL(helmChartsRoute.path); \ No newline at end of file diff --git a/src/renderer/components/+apps-helm-charts/helm-charts.tsx b/src/renderer/components/+apps-helm-charts/helm-charts.tsx index 473d78194e..c8b5312800 100644 --- a/src/renderer/components/+apps-helm-charts/helm-charts.tsx +++ b/src/renderer/components/+apps-helm-charts/helm-charts.tsx @@ -28,13 +28,13 @@ export class HelmCharts extends Component { } get selectedChart() { - const { match: { params: { chartName, repo } } } = this.props + const { match: { params: { chartName, repo } } } = this.props; return helmChartStore.getByName(chartName, repo); } showDetails = (chart: HelmChart) => { if (!chart) { - navigation.merge(helmChartsURL()) + navigation.merge(helmChartsURL()); } else { navigation.merge(helmChartsURL({ @@ -42,13 +42,13 @@ export class HelmCharts extends Component { chartName: chart.getName(), repo: chart.getRepository(), } - })) + })); } - } + }; hideDetails = () => { this.showDetails(null); - } + }; render() { return ( diff --git a/src/renderer/components/+apps-releases/release-details.tsx b/src/renderer/components/+apps-releases/release-details.tsx index cb7c7b8069..a27db5dc83 100644 --- a/src/renderer/components/+apps-releases/release-details.tsx +++ b/src/renderer/components/+apps-releases/release-details.tsx @@ -77,7 +77,7 @@ export class ReleaseDetails extends Component { updateValues = async () => { const { release } = this.props; const name = release.getName(); - const namespace = release.getNs() + const namespace = release.getNs(); const data = { chart: release.getChart(), repo: await release.getRepo(), @@ -94,13 +94,13 @@ export class ReleaseDetails extends Component { Notifications.error(err); } this.saving = false; - } + }; upgradeVersion = () => { const { release, hideDetails } = this.props; createUpgradeChartTab(release); hideDetails(); - } + }; renderValues() { const { values, saving } = this; @@ -121,7 +121,7 @@ export class ReleaseDetails extends Component { /> - ) + ); } renderNotes() { @@ -222,13 +222,13 @@ export class ReleaseDetails extends Component { {this.renderResources()} - ) + ); } render() { - const { release, hideDetails } = this.props - const title = release ? Release: {release.getName()} : "" - const toolbar = + const { release, hideDetails } = this.props; + const title = release ? Release: {release.getName()} : ""; + const toolbar = ; return ( { > {this.renderContent()} - ) + ); } } diff --git a/src/renderer/components/+apps-releases/release-menu.tsx b/src/renderer/components/+apps-releases/release-menu.tsx index 0bdb94edd2..aae3f34b79 100644 --- a/src/renderer/components/+apps-releases/release-menu.tsx +++ b/src/renderer/components/+apps-releases/release-menu.tsx @@ -46,7 +46,7 @@ export class HelmReleaseMenu extends React.Component { )} > - ) + ); } render() { diff --git a/src/renderer/components/+apps-releases/release-rollback-dialog.tsx b/src/renderer/components/+apps-releases/release-rollback-dialog.tsx index 259394c2e1..f1c1841775 100644 --- a/src/renderer/components/+apps-releases/release-rollback-dialog.tsx +++ b/src/renderer/components/+apps-releases/release-rollback-dialog.tsx @@ -10,7 +10,7 @@ import { HelmRelease, helmReleasesApi, IReleaseRevision } from "../../api/endpoi import { releaseStore } from "./release.store"; import { Select, SelectOption } from "../select"; import { Notifications } from "../notifications"; -import orderBy from "lodash/orderBy" +import orderBy from "lodash/orderBy"; interface Props extends DialogProps { } @@ -46,7 +46,7 @@ export class ReleaseRollbackDialog extends React.Component { this.revisions.replace(releases); this.revision = this.revisions[0]; this.isLoading = false; - } + }; rollback = async () => { const revisionNumber = this.revision.revision; @@ -60,12 +60,12 @@ export class ReleaseRollbackDialog extends React.Component { close = () => { ReleaseRollbackDialog.close(); - } + }; renderContent() { const { revision, revisions } = this; if (!revision) { - return No revisions to rollback. + return No revisions to rollback.; } return ( @@ -78,13 +78,13 @@ export class ReleaseRollbackDialog extends React.Component { onChange={({ value }: SelectOption) => this.revision = value} /> - ) + ); } render() { const { ...dialogProps } = this.props; const releaseName = this.release ? this.release.getName() : ""; - const header = Rollback {releaseName} + const header = Rollback {releaseName}; return ( { - ) + ); } } diff --git a/src/renderer/components/+apps-releases/release.route.ts b/src/renderer/components/+apps-releases/release.route.ts index f874fefe67..a992383657 100644 --- a/src/renderer/components/+apps-releases/release.route.ts +++ b/src/renderer/components/+apps-releases/release.route.ts @@ -4,7 +4,7 @@ import { appsRoute } from "../+apps/apps.route"; export const releaseRoute: RouteProps = { path: appsRoute.path + "/releases/:namespace?/:name?" -} +}; export interface IReleaseRouteParams { name?: string; diff --git a/src/renderer/components/+apps-releases/release.store.ts b/src/renderer/components/+apps-releases/release.store.ts index 5120a63053..7fb438fd84 100644 --- a/src/renderer/components/+apps-releases/release.store.ts +++ b/src/renderer/components/+apps-releases/release.store.ts @@ -33,7 +33,7 @@ export class ReleaseStore extends ItemStore { this.loadAll(); } this.releaseSecrets = [...secrets]; - }) + }); } unwatch() { @@ -48,7 +48,7 @@ export class ReleaseStore extends ItemStore { const labels = { owner: "helm", name: release.getName() - } + }; return secretsStore.getByLabel(labels) .filter(secret => secret.getNs() == release.getNs())[0]; } @@ -58,7 +58,7 @@ export class ReleaseStore extends ItemStore { this.isLoading = true; let items; try { - const { isAdmin, allowedNamespaces } = getHostedCluster() + const { isAdmin, allowedNamespaces } = getHostedCluster(); items = await this.loadItems(!isAdmin ? allowedNamespaces : null); } finally { if (items) { diff --git a/src/renderer/components/+apps-releases/releases.tsx b/src/renderer/components/+apps-releases/releases.tsx index 234a812543..29dd11deb8 100644 --- a/src/renderer/components/+apps-releases/releases.tsx +++ b/src/renderer/components/+apps-releases/releases.tsx @@ -48,7 +48,7 @@ export class HelmReleases extends Component { showDetails = (item: HelmRelease) => { if (!item) { - navigation.merge(releaseURL()) + navigation.merge(releaseURL()); } else { navigation.merge(releaseURL({ @@ -56,13 +56,13 @@ export class HelmReleases extends Component { name: item.getName(), namespace: item.getNs() } - })) + })); } - } + }; hideDetails = () => { this.showDetails(null); - } + }; renderRemoveDialogMessage(selectedItems: HelmRelease[]) { const releaseNames = selectedItems.map(item => item.getName()).join(", "); @@ -73,7 +73,7 @@ export class HelmReleases extends Component { Note: StatefulSet Volumes won't be deleted automatically - ) + ); } render() { @@ -122,7 +122,7 @@ export class HelmReleases extends Component { release.appVersion, { title: release.getStatus(), className: kebabCase(release.getStatus()) }, release.getUpdated(), - ] + ]; }} renderItemMenu={(release: HelmRelease) => { return ( @@ -130,7 +130,7 @@ export class HelmReleases extends Component { release={release} removeConfirmationMessage={this.renderRemoveDialogMessage([release])} /> - ) + ); }} customizeRemoveDialog={(selectedItems: HelmRelease[]) => ({ message: this.renderRemoveDialogMessage(selectedItems) diff --git a/src/renderer/components/+apps/apps.tsx b/src/renderer/components/+apps/apps.tsx index 469765aa68..537d2c3caf 100644 --- a/src/renderer/components/+apps/apps.tsx +++ b/src/renderer/components/+apps/apps.tsx @@ -23,12 +23,12 @@ export class Apps extends React.Component { url: releaseURL({ query }), routePath: releaseRoute.path.toString(), }, - ] + ]; } render() { return ( - ) + ); } } diff --git a/src/renderer/components/+cluster-settings/cluster-settings.route.ts b/src/renderer/components/+cluster-settings/cluster-settings.route.ts index 3d1b1b2737..11a373dcdb 100644 --- a/src/renderer/components/+cluster-settings/cluster-settings.route.ts +++ b/src/renderer/components/+cluster-settings/cluster-settings.route.ts @@ -7,6 +7,6 @@ export interface IClusterSettingsRouteParams extends IClusterViewRouteParams { export const clusterSettingsRoute: RouteProps = { path: `/cluster/:clusterId/settings`, -} +}; -export const clusterSettingsURL = buildURL(clusterSettingsRoute.path) +export const clusterSettingsURL = buildURL(clusterSettingsRoute.path); diff --git a/src/renderer/components/+cluster-settings/cluster-settings.tsx b/src/renderer/components/+cluster-settings/cluster-settings.tsx index 55f4bb5ec4..6188e8867e 100644 --- a/src/renderer/components/+cluster-settings/cluster-settings.tsx +++ b/src/renderer/components/+cluster-settings/cluster-settings.tsx @@ -14,7 +14,7 @@ import { IClusterSettingsRouteParams } from "./cluster-settings.route"; import { clusterStore } from "../../../common/cluster-store"; import { PageLayout } from "../layout/page-layout"; import { requestMain } from "../../../common/ipc"; -import { clusterActivateHandler, clusterRefreshHandler } from "../../../common/cluster-ipc" +import { clusterActivateHandler, clusterRefreshHandler } from "../../../common/cluster-ipc"; interface Props extends RouteComponentProps { } @@ -22,7 +22,7 @@ interface Props extends RouteComponentProps { @observer export class ClusterSettings extends React.Component { get clusterId() { - return this.props.match.params.clusterId + return this.props.match.params.clusterId; } get cluster(): Cluster { @@ -37,18 +37,18 @@ export class ClusterSettings extends React.Component { reaction(() => this.clusterId, clusterId => clusterStore.setActive(clusterId), { fireImmediately: true, }) - ]) + ]); } refreshCluster = async () => { if (this.cluster) { - await requestMain(clusterActivateHandler, this.cluster.id) - await requestMain(clusterRefreshHandler, this.cluster.id) + await requestMain(clusterActivateHandler, this.cluster.id); + await requestMain(clusterRefreshHandler, this.cluster.id); } - } + }; render() { - const cluster = this.cluster + const cluster = this.cluster; if (!cluster) return null; const header = ( <> diff --git a/src/renderer/components/+cluster-settings/components/cluster-home-dir-setting.tsx b/src/renderer/components/+cluster-settings/components/cluster-home-dir-setting.tsx index 965333d4db..35c18cc5e5 100644 --- a/src/renderer/components/+cluster-settings/components/cluster-home-dir-setting.tsx +++ b/src/renderer/components/+cluster-settings/components/cluster-home-dir-setting.tsx @@ -27,7 +27,7 @@ export class ClusterHomeDirSetting extends React.Component { onChange = (value: string) => { this.directory = value; - } + }; render() { return ( diff --git a/src/renderer/components/+cluster-settings/components/cluster-icon-setting.tsx b/src/renderer/components/+cluster-settings/components/cluster-icon-setting.tsx index fb35778f6c..6f893a48fb 100644 --- a/src/renderer/components/+cluster-settings/components/cluster-icon-setting.tsx +++ b/src/renderer/components/+cluster-settings/components/cluster-icon-setting.tsx @@ -35,14 +35,14 @@ export class ClusterIconSetting extends React.Component { cluster.preferences.icon = undefined; } } catch (e) { - this.errorText = e.toString() - this.status = GeneralInputStatus.ERROR + this.errorText = e.toString(); + this.status = GeneralInputStatus.ERROR; } } getClearButton() { if (this.props.cluster.preferences.icon) { - return this.onIconPick([])}>Clear + return this.onIconPick([])}>Clear; } } diff --git a/src/renderer/components/+cluster-settings/components/cluster-name-setting.tsx b/src/renderer/components/+cluster-settings/components/cluster-name-setting.tsx index 54d76c08eb..631c6d54ef 100644 --- a/src/renderer/components/+cluster-settings/components/cluster-name-setting.tsx +++ b/src/renderer/components/+cluster-settings/components/cluster-name-setting.tsx @@ -28,7 +28,7 @@ export class ClusterNameSetting extends React.Component { onChange = (value: string) => { this.name = value; - } + }; render() { return ( diff --git a/src/renderer/components/+cluster-settings/components/cluster-prometheus-setting.tsx b/src/renderer/components/+cluster-settings/components/cluster-prometheus-setting.tsx index ff1f6fd62d..d3bc9b4e46 100644 --- a/src/renderer/components/+cluster-settings/components/cluster-prometheus-setting.tsx +++ b/src/renderer/components/+cluster-settings/components/cluster-prometheus-setting.tsx @@ -59,14 +59,14 @@ export class ClusterPrometheusSetting extends React.Component { service: parsed[1], port: parseInt(parsed[2]), prefix: apiPrefix - } - } + }; + }; onSaveProvider = () => { this.props.cluster.preferences.prometheusProvider = this.provider ? { type: this.provider } : null; - } + }; onSavePath = () => { this.props.cluster.preferences.prometheus = this.parsePrometheusPath(); diff --git a/src/renderer/components/+cluster-settings/components/cluster-proxy-setting.tsx b/src/renderer/components/+cluster-settings/components/cluster-proxy-setting.tsx index 8409cc5bde..d43f571495 100644 --- a/src/renderer/components/+cluster-settings/components/cluster-proxy-setting.tsx +++ b/src/renderer/components/+cluster-settings/components/cluster-proxy-setting.tsx @@ -28,7 +28,7 @@ export class ClusterProxySetting extends React.Component { onChange = (value: string) => { this.proxy = value; - } + }; render() { return ( diff --git a/src/renderer/components/+cluster-settings/components/install-feature.tsx b/src/renderer/components/+cluster-settings/components/install-feature.tsx index adfc8f2b5f..729dd2b1cd 100644 --- a/src/renderer/components/+cluster-settings/components/install-feature.tsx +++ b/src/renderer/components/+cluster-settings/components/install-feature.tsx @@ -19,21 +19,21 @@ export class InstallFeature extends React.Component { @observable message = ""; componentDidMount() { - const feature = this.props.feature - const cluster = this.props.cluster + const feature = this.props.feature; + const cluster = this.props.cluster; const statusUpdate = interval(20, () => { - feature.updateStatus(cluster) - }) - statusUpdate.start(true) + feature.updateStatus(cluster); + }); + statusUpdate.start(true); disposeOnUnmount(this, () => { - statusUpdate.stop() - }) + statusUpdate.stop(); + }); disposeOnUnmount(this, reaction(() => feature.status.installed, () => { this.loading = false; - this.message = "" + this.message = ""; }, { equals: comparer.structural }) ); } @@ -60,8 +60,8 @@ export class InstallFeature extends React.Component { accent disabled={disabled} onClick={this.runAction(async () => { - this.message = "Uninstalling feature ..." - feature.uninstall(cluster) + this.message = "Uninstalling feature ..."; + feature.uninstall(cluster); })} > Uninstall @@ -72,8 +72,8 @@ export class InstallFeature extends React.Component { primary disabled={disabled} onClick={this.runAction(async () =>{ - this.message = "Installing feature ..." - feature.install(cluster) + this.message = "Installing feature ..."; + feature.install(cluster); })} > Install diff --git a/src/renderer/components/+cluster-settings/components/remove-cluster-button.tsx b/src/renderer/components/+cluster-settings/components/remove-cluster-button.tsx index f407ee383a..5ae8d068f2 100644 --- a/src/renderer/components/+cluster-settings/components/remove-cluster-button.tsx +++ b/src/renderer/components/+cluster-settings/components/remove-cluster-button.tsx @@ -23,7 +23,7 @@ export class RemoveClusterButton extends React.Component { ok: async () => { await clusterStore.removeById(cluster.id); } - }) + }); } render() { diff --git a/src/renderer/components/+cluster-settings/features.tsx b/src/renderer/components/+cluster-settings/features.tsx index 74e6a28f13..271a6e69b1 100644 --- a/src/renderer/components/+cluster-settings/features.tsx +++ b/src/renderer/components/+cluster-settings/features.tsx @@ -22,7 +22,7 @@ export class Features extends React.Component { > - ) + ); })} ); diff --git a/src/renderer/components/+cluster-settings/index.ts b/src/renderer/components/+cluster-settings/index.ts index 75dd6e60ea..edab795e29 100644 --- a/src/renderer/components/+cluster-settings/index.ts +++ b/src/renderer/components/+cluster-settings/index.ts @@ -1,2 +1,2 @@ -export * from "./cluster-settings.route" -export * from "./cluster-settings" +export * from "./cluster-settings.route"; +export * from "./cluster-settings"; diff --git a/src/renderer/components/+cluster-settings/status.tsx b/src/renderer/components/+cluster-settings/status.tsx index 79fb62c860..319b42e104 100644 --- a/src/renderer/components/+cluster-settings/status.tsx +++ b/src/renderer/components/+cluster-settings/status.tsx @@ -14,7 +14,7 @@ export class Status extends React.Component { @autobind() openKubeconfig() { const { cluster } = this.props; - shell.showItemInFolder(cluster.kubeConfigPath) + shell.showItemInFolder(cluster.kubeConfigPath); } renderStatusRows() { diff --git a/src/renderer/components/+cluster/cluster-issues.tsx b/src/renderer/components/+cluster/cluster-issues.tsx index eea222b5c4..a2959cda20 100644 --- a/src/renderer/components/+cluster/cluster-issues.tsx +++ b/src/renderer/components/+cluster/cluster-issues.tsx @@ -1,4 +1,4 @@ -import "./cluster-issues.scss" +import "./cluster-issues.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -43,7 +43,7 @@ export class ClusterIssues extends React.Component { // Node bad conditions nodesStore.items.forEach(node => { - const { kind, selfLink, getId, getName } = node + const { kind, selfLink, getId, getName } = node; node.getWarningConditions().forEach(({ message }) => { warnings.push({ kind, @@ -51,8 +51,8 @@ export class ClusterIssues extends React.Component { getName, selfLink, message, - }) - }) + }); + }); }); // Warning events for Workloads @@ -67,7 +67,7 @@ export class ClusterIssues extends React.Component { kind, selfLink: lookupApiLink(involvedObject, error), }); - }) + }); return warnings; } diff --git a/src/renderer/components/+cluster/cluster-metrics.tsx b/src/renderer/components/+cluster/cluster-metrics.tsx index 077adde70a..12973b1514 100644 --- a/src/renderer/components/+cluster/cluster-metrics.tsx +++ b/src/renderer/components/+cluster/cluster-metrics.tsx @@ -72,7 +72,7 @@ export const ClusterMetrics = observer(() => { return ; } if (!memoryCapacity || !cpuCapacity) { - return + return ; } return ( { Specified limits are higher than node capacity! ); - } + }; const renderCharts = () => { const data = getMetricLastPoints(clusterStore.metrics); @@ -168,7 +168,7 @@ export const ClusterPieCharts = observer(() => { ); - } + }; const renderContent = () => { const { masterNodes, workerNodes } = nodesStore; @@ -194,11 +194,11 @@ export const ClusterPieCharts = observer(() => { return ; } return renderCharts(); - } + }; return ( {renderContent()} ); -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/src/renderer/components/+cluster/cluster.route.ts b/src/renderer/components/+cluster/cluster.route.ts index fbe1c47b86..f9cf7a390c 100644 --- a/src/renderer/components/+cluster/cluster.route.ts +++ b/src/renderer/components/+cluster/cluster.route.ts @@ -3,6 +3,6 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const clusterRoute: RouteProps = { path: "/cluster" -} +}; -export const clusterURL = buildURL(clusterRoute.path) +export const clusterURL = buildURL(clusterRoute.path); diff --git a/src/renderer/components/+cluster/cluster.store.ts b/src/renderer/components/+cluster/cluster.store.ts index 3af42297b0..63d8f07b3b 100644 --- a/src/renderer/components/+cluster/cluster.store.ts +++ b/src/renderer/components/+cluster/cluster.store.ts @@ -18,7 +18,7 @@ export enum MetricNodeRole { @autobind() export class ClusterStore extends KubeObjectStore { - api = clusterApi + api = clusterApi; @observable metrics: Partial = {}; @observable liveMetrics: Partial = {}; @@ -35,7 +35,7 @@ export class ClusterStore extends KubeObjectStore { Object.assign(this, storage.get()); reaction(() => { const { metricType, metricNodeRole } = this; - return { metricType, metricNodeRole } + return { metricType, metricNodeRole }; }, settings => storage.set(settings) ); @@ -85,9 +85,9 @@ export class ClusterStore extends KubeObjectStore { getMetricsValues(source: Partial): [number, string][] { switch (this.metricType) { case MetricType.CPU: - return normalizeMetrics(source.cpuUsage).data.result[0].values + return normalizeMetrics(source.cpuUsage).data.result[0].values; case MetricType.MEMORY: - return normalizeMetrics(source.memoryUsage).data.result[0].values + return normalizeMetrics(source.memoryUsage).data.result[0].values; default: return []; } diff --git a/src/renderer/components/+cluster/cluster.tsx b/src/renderer/components/+cluster/cluster.tsx index 9a1ce47123..588c483295 100644 --- a/src/renderer/components/+cluster/cluster.tsx +++ b/src/renderer/components/+cluster/cluster.tsx @@ -1,4 +1,4 @@ -import "./cluster.scss" +import "./cluster.scss"; import React from "react"; import { computed, reaction } from "mobx"; @@ -21,19 +21,19 @@ export class Cluster extends React.Component { private dependentStores = [nodesStore, podsStore]; private watchers = [ - interval(60, () => { getHostedCluster().available && clusterStore.getMetrics()}), - interval(20, () => { getHostedCluster().available && eventStore.loadAll()}) + interval(60, () => { getHostedCluster().available && clusterStore.getMetrics();}), + interval(20, () => { getHostedCluster().available && eventStore.loadAll();}) ]; @computed get isLoaded() { - return nodesStore.isLoaded && podsStore.isLoaded + return nodesStore.isLoaded && podsStore.isLoaded; } // todo: refactor async componentDidMount() { const { dependentStores } = this; if (!isAllowedResource("nodes")) { - dependentStores.splice(dependentStores.indexOf(nodesStore), 1) + dependentStores.splice(dependentStores.indexOf(nodesStore), 1); } this.watchers.forEach(watcher => watcher.start(true)); @@ -49,7 +49,7 @@ export class Cluster extends React.Component { () => clusterStore.metricNodeRole, () => this.watchers.forEach(watcher => watcher.restart()) ) - ]) + ]); } render() { @@ -67,6 +67,6 @@ export class Cluster extends React.Component { )} - ) + ); } } diff --git a/src/renderer/components/+cluster/index.ts b/src/renderer/components/+cluster/index.ts index 62a1be24fb..d9be64692d 100644 --- a/src/renderer/components/+cluster/index.ts +++ b/src/renderer/components/+cluster/index.ts @@ -1,2 +1,2 @@ -export * from "./cluster.route" +export * from "./cluster.route"; diff --git a/src/renderer/components/+config-autoscalers/hpa-details.tsx b/src/renderer/components/+config-autoscalers/hpa-details.tsx index a3461f629d..b068c28361 100644 --- a/src/renderer/components/+config-autoscalers/hpa-details.tsx +++ b/src/renderer/components/+config-autoscalers/hpa-details.tsx @@ -51,7 +51,7 @@ export class HpaDetails extends React.Component { ); } - } + }; return ( @@ -68,7 +68,7 @@ export class HpaDetails extends React.Component { {name} {values} - ) + ); }) } @@ -113,7 +113,7 @@ export class HpaDetails extends React.Component { tooltip={tooltip} className={cssNames({ [type.toLowerCase()]: isReady })} /> - ) + ); })} @@ -132,7 +132,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "HorizontalPodAutoscaler", @@ -141,4 +141,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+config-autoscalers/hpa.route.ts b/src/renderer/components/+config-autoscalers/hpa.route.ts index 0828db146b..404bab8f88 100644 --- a/src/renderer/components/+config-autoscalers/hpa.route.ts +++ b/src/renderer/components/+config-autoscalers/hpa.route.ts @@ -3,9 +3,9 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const hpaRoute: RouteProps = { path: "/hpa" -} +}; export interface IHpaRouteParams { } -export const hpaURL = buildURL(hpaRoute.path) +export const hpaURL = buildURL(hpaRoute.path); diff --git a/src/renderer/components/+config-autoscalers/hpa.store.ts b/src/renderer/components/+config-autoscalers/hpa.store.ts index 240f42a309..478c2ca563 100644 --- a/src/renderer/components/+config-autoscalers/hpa.store.ts +++ b/src/renderer/components/+config-autoscalers/hpa.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class HPAStore extends KubeObjectStore { - api = hpaApi + api = hpaApi; } export const hpaStore = new HPAStore(); diff --git a/src/renderer/components/+config-autoscalers/hpa.tsx b/src/renderer/components/+config-autoscalers/hpa.tsx index 01e18da2f5..f955ce098d 100644 --- a/src/renderer/components/+config-autoscalers/hpa.tsx +++ b/src/renderer/components/+config-autoscalers/hpa.tsx @@ -1,4 +1,4 @@ -import "./hpa.scss" +import "./hpa.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -78,7 +78,7 @@ export class HorizontalPodAutoscalers extends React.Component { tooltip={tooltip} className={cssNames(type.toLowerCase())} /> - ) + ); }) ]} /> diff --git a/src/renderer/components/+config-autoscalers/index.ts b/src/renderer/components/+config-autoscalers/index.ts index 4d3cedf89c..99d994add1 100644 --- a/src/renderer/components/+config-autoscalers/index.ts +++ b/src/renderer/components/+config-autoscalers/index.ts @@ -1,3 +1,3 @@ -export * from "./hpa" -export * from "./hpa-details" -export * from "./hpa.route" +export * from "./hpa"; +export * from "./hpa-details"; +export * from "./hpa.route"; diff --git a/src/renderer/components/+config-maps/config-map-details.tsx b/src/renderer/components/+config-maps/config-map-details.tsx index 0a890f6d04..bd796a2323 100644 --- a/src/renderer/components/+config-maps/config-map-details.tsx +++ b/src/renderer/components/+config-maps/config-map-details.tsx @@ -31,7 +31,7 @@ export class ConfigMapDetails extends React.Component { this.data.replace(configMap.data); // refresh } }) - ]) + ]); } save = async () => { @@ -47,7 +47,7 @@ export class ConfigMapDetails extends React.Component { } finally { this.isSaving = false; } - } + }; render() { const { object: configMap } = this.props; @@ -75,7 +75,7 @@ export class ConfigMapDetails extends React.Component { /> - ) + ); }) } } -}) +}); kubeObjectDetailRegistry.add({ kind: "ConfigMap", @@ -107,6 +107,6 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+config-maps/config-maps.route.ts b/src/renderer/components/+config-maps/config-maps.route.ts index 3f42cf7e76..1cffe95c34 100644 --- a/src/renderer/components/+config-maps/config-maps.route.ts +++ b/src/renderer/components/+config-maps/config-maps.route.ts @@ -3,7 +3,7 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const configMapsRoute: RouteProps = { path: "/configmaps" -} +}; export interface IConfigMapsRouteParams { } diff --git a/src/renderer/components/+config-maps/config-maps.store.ts b/src/renderer/components/+config-maps/config-maps.store.ts index d6dcc5f916..23a80a9f4a 100644 --- a/src/renderer/components/+config-maps/config-maps.store.ts +++ b/src/renderer/components/+config-maps/config-maps.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class ConfigMapsStore extends KubeObjectStore { - api = configMapApi + api = configMapApi; } export const configMapsStore = new ConfigMapsStore(); diff --git a/src/renderer/components/+config-maps/config-maps.tsx b/src/renderer/components/+config-maps/config-maps.tsx index 22cc4c354d..67b4fe8e0e 100644 --- a/src/renderer/components/+config-maps/config-maps.tsx +++ b/src/renderer/components/+config-maps/config-maps.tsx @@ -1,4 +1,4 @@ -import "./config-maps.scss" +import "./config-maps.scss"; import React from "react"; import { observer } from "mobx-react"; diff --git a/src/renderer/components/+config-maps/index.ts b/src/renderer/components/+config-maps/index.ts index 37b78f5097..4b22cfd4cb 100644 --- a/src/renderer/components/+config-maps/index.ts +++ b/src/renderer/components/+config-maps/index.ts @@ -1,3 +1,3 @@ -export * from "./config-maps.route" -export * from "./config-maps" -export * from "./config-map-details" +export * from "./config-maps.route"; +export * from "./config-maps"; +export * from "./config-map-details"; diff --git a/src/renderer/components/+config-pod-disruption-budgets/index.ts b/src/renderer/components/+config-pod-disruption-budgets/index.ts index e729464c0a..7528301703 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/index.ts +++ b/src/renderer/components/+config-pod-disruption-budgets/index.ts @@ -1,3 +1,3 @@ -export * from "./pod-disruption-budgets.route" -export * from "./pod-disruption-budgets" -export * from "./pod-disruption-budgets-details" +export * from "./pod-disruption-budgets.route"; +export * from "./pod-disruption-budgets"; +export * from "./pod-disruption-budgets-details"; diff --git a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx index 745d588be3..25925f6436 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx +++ b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx @@ -18,8 +18,8 @@ export class PodDisruptionBudgetDetails extends React.Component { render() { const { object: pdb } = this.props; - if (!pdb) return null - const { status, spec } = pdb + if (!pdb) return null; + const { status, spec } = pdb; const selectors = pdb.getSelectors(); return ( @@ -50,7 +50,7 @@ export class PodDisruptionBudgetDetails extends React.Component { - ) + ); } } @@ -60,4 +60,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.route.ts b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.route.ts index b35f30bb8b..ea443a841b 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.route.ts +++ b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.route.ts @@ -3,9 +3,9 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const pdbRoute: RouteProps = { path: "/poddisruptionbudgets" -} +}; export interface IPodDisruptionBudgetsRouteParams { } -export const pdbURL = buildURL(pdbRoute.path) +export const pdbURL = buildURL(pdbRoute.path); diff --git a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store.ts b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store.ts index 1eca71e1ba..0f0d79ab2d 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store.ts +++ b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class PodDisruptionBudgetsStore extends KubeObjectStore { - api = pdbApi + api = pdbApi; } export const podDisruptionBudgetsStore = new PodDisruptionBudgetsStore(); diff --git a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx index 275dcf0c7a..4a7bb04ddd 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx +++ b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx @@ -1,4 +1,4 @@ -import "./pod-disruption-budgets.scss" +import "./pod-disruption-budgets.scss"; import * as React from "react"; import { observer } from "mobx-react"; @@ -65,7 +65,7 @@ export class PodDisruptionBudgets extends React.Component { pdb.getCurrentHealthy(), pdb.getDesiredHealthy(), pdb.getAge(), - ] + ]; }} /> ); diff --git a/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx b/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx index 5dfa104537..3759958750 100644 --- a/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx +++ b/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx @@ -45,7 +45,7 @@ export class AddQuotaDialog extends React.Component { "count/deployments.extensions": "", }; - public defaultNamespace = "default" + public defaultNamespace = "default"; @observable quotaName = ""; @observable quotaSelectValue = ""; @@ -83,11 +83,11 @@ export class AddQuotaDialog extends React.Component { if (!this.quotaSelectValue) return; this.quotas[this.quotaSelectValue] = this.quotaInputValue; this.quotaInputValue = ""; - } + }; close = () => { AddQuotaDialog.close(); - } + }; reset = () => { this.quotaName = ""; @@ -95,7 +95,7 @@ export class AddQuotaDialog extends React.Component { this.quotaInputValue = ""; this.namespace = this.defaultNamespace; this.quotas = AddQuotaDialog.defaultQuotas; - } + }; addQuota = async () => { try { @@ -113,7 +113,7 @@ export class AddQuotaDialog extends React.Component { } catch (err) { Notifications.error(err); } - } + }; onInputQuota = (evt: React.KeyboardEvent) => { switch (evt.key) { @@ -122,7 +122,7 @@ export class AddQuotaDialog extends React.Component { evt.preventDefault(); // don't submit form break; } - } + }; render() { const { ...dialogProps } = this.props; @@ -193,12 +193,12 @@ export class AddQuotaDialog extends React.Component { {value} this.quotas[quota] = ""} /> - ) + ); })} - ) + ); } } \ No newline at end of file diff --git a/src/renderer/components/+config-resource-quotas/index.ts b/src/renderer/components/+config-resource-quotas/index.ts index 792f8946c3..79fa3d8f0c 100644 --- a/src/renderer/components/+config-resource-quotas/index.ts +++ b/src/renderer/components/+config-resource-quotas/index.ts @@ -1,3 +1,3 @@ -export * from "./resource-quotas.route" -export * from "./resource-quotas" -export * from "./resource-quota-details" +export * from "./resource-quotas.route"; +export * from "./resource-quotas"; +export * from "./resource-quota-details"; diff --git a/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx b/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx index 4a2ff08238..c8fc913531 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx +++ b/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx @@ -20,24 +20,24 @@ const onlyNumbers = /$[0-9]*^/g; function transformUnit(name: string, value: string): number { if (name.includes("memory") || name.includes("storage")) { - return unitsToBytes(value) + return unitsToBytes(value); } if (name.includes("cpu")) { - return cpuUnitsToNumber(value) + return cpuUnitsToNumber(value); } return metricUnitsToNumber(value); } function renderQuotas(quota: ResourceQuota): JSX.Element[] { - const { hard = {}, used = {} } = quota.status + const { hard = {}, used = {} } = quota.status; return Object.entries(hard) .filter(([name]) => used[name]) .map(([name, value]) => { - const current = transformUnit(name, used[name]) - const max = transformUnit(name, value) + const current = transformUnit(name, used[name]); + const max = transformUnit(name, value); const usage = max === 0 ? 100 : Math.ceil(current / max * 100); // special case 0 max as always 100% usage return ( @@ -52,8 +52,8 @@ function renderQuotas(quota: ResourceQuota): JSX.Element[] { } /> - ) - }) + ); + }); } @observer @@ -104,4 +104,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+config-resource-quotas/resource-quotas.route.ts b/src/renderer/components/+config-resource-quotas/resource-quotas.route.ts index ee6966da97..f36468f656 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quotas.route.ts +++ b/src/renderer/components/+config-resource-quotas/resource-quotas.route.ts @@ -3,7 +3,7 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const resourceQuotaRoute: RouteProps = { path: "/resourcequotas" -} +}; export interface IResourceQuotaRouteParams { } diff --git a/src/renderer/components/+config-resource-quotas/resource-quotas.store.ts b/src/renderer/components/+config-resource-quotas/resource-quotas.store.ts index b5450da9cd..554fec891a 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quotas.store.ts +++ b/src/renderer/components/+config-resource-quotas/resource-quotas.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class ResourceQuotasStore extends KubeObjectStore { - api = resourceQuotaApi + api = resourceQuotaApi; } export const resourceQuotaStore = new ResourceQuotasStore(); diff --git a/src/renderer/components/+config-secrets/add-secret-dialog.tsx b/src/renderer/components/+config-secrets/add-secret-dialog.tsx index dbc7a8cc7c..8519be5bda 100644 --- a/src/renderer/components/+config-secrets/add-secret-dialog.tsx +++ b/src/renderer/components/+config-secrets/add-secret-dialog.tsx @@ -1,4 +1,4 @@ -import "./add-secret-dialog.scss" +import "./add-secret-dialog.scss"; import React from "react"; import { observable } from "mobx"; @@ -58,7 +58,7 @@ export class AddSecretDialog extends React.Component { { key: "kubernetes.io/service-account.uid", required: true } ], }, - } + }; get types() { return Object.keys(this.secretTemplate) as SecretType[]; @@ -72,11 +72,11 @@ export class AddSecretDialog extends React.Component { reset = () => { this.name = ""; this.secret = this.secretTemplate; - } + }; close = () => { AddSecretDialog.close(); - } + }; private getDataFromFields = (fields: ISecretTemplateField[] = [], processValue?: (val: string) => string) => { return fields.reduce((data, field) => { @@ -85,8 +85,8 @@ export class AddSecretDialog extends React.Component { data[key] = processValue ? processValue(value) : value; } return data; - }, {}) - } + }, {}); + }; createSecret = async () => { const { name, namespace, type } = this; @@ -100,7 +100,7 @@ export class AddSecretDialog extends React.Component { annotations: this.getDataFromFields(annotations), labels: this.getDataFromFields(labels), } as IKubeObjectMetadata - } + }; try { const newSecret = await secretsApi.create({ namespace, name }, secret); showDetails(newSecret.selfLink); @@ -109,18 +109,18 @@ export class AddSecretDialog extends React.Component { } catch (err) { Notifications.error(err); } - } + }; addField = (field: ISecretField) => { const fields = this.secret[this.type][field] || []; fields.push({ key: "", value: "" }); this.secret[this.type][field] = fields; - } + }; removeField = (field: ISecretField, index: number) => { const fields = this.secret[this.type][field] || []; fields.splice(index, 1); - } + }; renderFields(field: ISecretField) { const fields = this.secret[this.type][field] || []; @@ -163,11 +163,11 @@ export class AddSecretDialog extends React.Component { onClick={() => this.removeField(field, index)} /> - ) + ); })} > - ) + ); } render() { @@ -216,6 +216,6 @@ export class AddSecretDialog extends React.Component { - ) + ); } } diff --git a/src/renderer/components/+config-secrets/index.ts b/src/renderer/components/+config-secrets/index.ts index cfea583cb3..33ef15e692 100644 --- a/src/renderer/components/+config-secrets/index.ts +++ b/src/renderer/components/+config-secrets/index.ts @@ -1,4 +1,4 @@ -export * from "./secrets.route" -export * from "./secrets" -export * from "./secret-details" +export * from "./secrets.route"; +export * from "./secrets"; +export * from "./secret-details"; diff --git a/src/renderer/components/+config-secrets/secret-details.tsx b/src/renderer/components/+config-secrets/secret-details.tsx index 5e10eee94c..5937737a5a 100644 --- a/src/renderer/components/+config-secrets/secret-details.tsx +++ b/src/renderer/components/+config-secrets/secret-details.tsx @@ -36,7 +36,7 @@ export class SecretDetails extends React.Component { this.revealSecret = {}; } }) - ]) + ]); } saveSecret = async () => { @@ -49,11 +49,11 @@ export class SecretDetails extends React.Component { Notifications.error(err); } this.isSaving = false; - } + }; editData = (name: string, value: string, encoded: boolean) => { this.data[name] = encoded ? value : base64.encode(value); - } + }; render() { const { object: secret } = this.props; @@ -97,7 +97,7 @@ export class SecretDetails extends React.Component { } - ) + ); }) } } -}) +}); diff --git a/src/renderer/components/+config-secrets/secrets.route.ts b/src/renderer/components/+config-secrets/secrets.route.ts index bd5f9a442d..a7eb422be5 100644 --- a/src/renderer/components/+config-secrets/secrets.route.ts +++ b/src/renderer/components/+config-secrets/secrets.route.ts @@ -3,7 +3,7 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const secretsRoute: RouteProps = { path: "/secrets" -} +}; export interface ISecretsRouteParams { } diff --git a/src/renderer/components/+config-secrets/secrets.store.ts b/src/renderer/components/+config-secrets/secrets.store.ts index df5a78b3ac..9dfc8cb6af 100644 --- a/src/renderer/components/+config-secrets/secrets.store.ts +++ b/src/renderer/components/+config-secrets/secrets.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class SecretsStore extends KubeObjectStore { - api = secretsApi + api = secretsApi; } export const secretsStore = new SecretsStore(); diff --git a/src/renderer/components/+config-secrets/secrets.tsx b/src/renderer/components/+config-secrets/secrets.tsx index bbcfd0b7cf..5149aa1002 100644 --- a/src/renderer/components/+config-secrets/secrets.tsx +++ b/src/renderer/components/+config-secrets/secrets.tsx @@ -1,4 +1,4 @@ -import "./secrets.scss" +import "./secrets.scss"; import React from "react"; import { observer } from "mobx-react"; diff --git a/src/renderer/components/+config/config.route.ts b/src/renderer/components/+config/config.route.ts index d747f49efd..8ea637c505 100644 --- a/src/renderer/components/+config/config.route.ts +++ b/src/renderer/components/+config/config.route.ts @@ -5,8 +5,8 @@ import { configMapsURL } from "../+config-maps/config-maps.route"; export const configRoute: RouteProps = { get path() { - return Config.tabRoutes.map(({ routePath }) => routePath).flat() + return Config.tabRoutes.map(({ routePath }) => routePath).flat(); } -} +}; export const configURL = (params?: IURLParams) => configMapsURL(params); diff --git a/src/renderer/components/+config/config.tsx b/src/renderer/components/+config/config.tsx index f738cb273e..70fa04d9b1 100644 --- a/src/renderer/components/+config/config.tsx +++ b/src/renderer/components/+config/config.tsx @@ -8,20 +8,20 @@ import { namespaceStore } from "../+namespaces/namespace.store"; import { resourceQuotaRoute, ResourceQuotas, resourceQuotaURL } from "../+config-resource-quotas"; import { pdbRoute, pdbURL, PodDisruptionBudgets } from "../+config-pod-disruption-budgets"; import { HorizontalPodAutoscalers, hpaRoute, hpaURL } from "../+config-autoscalers"; -import { isAllowedResource } from "../../../common/rbac" +import { isAllowedResource } from "../../../common/rbac"; @observer export class Config extends React.Component { static get tabRoutes(): TabLayoutRoute[] { - const query = namespaceStore.getContextParams() - const routes: TabLayoutRoute[] = [] + const query = namespaceStore.getContextParams(); + const routes: TabLayoutRoute[] = []; if (isAllowedResource("configmaps")) { routes.push({ title: ConfigMaps, component: ConfigMaps, url: configMapsURL({ query }), routePath: configMapsRoute.path.toString(), - }) + }); } if (isAllowedResource("secrets")) { routes.push({ @@ -29,7 +29,7 @@ export class Config extends React.Component { component: Secrets, url: secretsURL({ query }), routePath: secretsRoute.path.toString(), - }) + }); } if (isAllowedResource("resourcequotas")) { routes.push({ @@ -37,7 +37,7 @@ export class Config extends React.Component { component: ResourceQuotas, url: resourceQuotaURL({ query }), routePath: resourceQuotaRoute.path.toString(), - }) + }); } if (isAllowedResource("horizontalpodautoscalers")) { routes.push({ @@ -45,7 +45,7 @@ export class Config extends React.Component { component: HorizontalPodAutoscalers, url: hpaURL({ query }), routePath: hpaRoute.path.toString(), - }) + }); } if (isAllowedResource("poddisruptionbudgets")) { routes.push({ @@ -53,7 +53,7 @@ export class Config extends React.Component { component: PodDisruptionBudgets, url: pdbURL({ query }), routePath: pdbRoute.path.toString(), - }) + }); } return routes; } @@ -61,6 +61,6 @@ export class Config extends React.Component { render() { return ( - ) + ); } } diff --git a/src/renderer/components/+config/index.ts b/src/renderer/components/+config/index.ts index f3ab3691ce..dba36b66d6 100644 --- a/src/renderer/components/+config/index.ts +++ b/src/renderer/components/+config/index.ts @@ -1,2 +1,2 @@ -export * from "./config.route" -export * from "./config" +export * from "./config.route"; +export * from "./config"; diff --git a/src/renderer/components/+custom-resources/crd-details.tsx b/src/renderer/components/+custom-resources/crd-details.tsx index b921eb0d04..637a0de1b6 100644 --- a/src/renderer/components/+custom-resources/crd-details.tsx +++ b/src/renderer/components/+custom-resources/crd-details.tsx @@ -60,7 +60,7 @@ export class CRDDetails extends React.Component { Conditions} className="conditions" labelsOnly> { crd.getConditions().map(condition => { - const { type, message, lastTransitionTime, status } = condition + const { type, message, lastTransitionTime, status } = condition; return ( { - ) + ); }) } @@ -130,7 +130,7 @@ export class CRDDetails extends React.Component { > } - ) + ); } } @@ -140,4 +140,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+custom-resources/crd-list.tsx b/src/renderer/components/+custom-resources/crd-list.tsx index caf6129e58..bfad4d501c 100644 --- a/src/renderer/components/+custom-resources/crd-list.tsx +++ b/src/renderer/components/+custom-resources/crd-list.tsx @@ -1,4 +1,4 @@ -import "./crd-list.scss" +import "./crd-list.scss"; import React from "react"; import { Trans } from "@lingui/macro"; @@ -24,7 +24,7 @@ enum sortBy { @observer export class CrdList extends React.Component { @computed get groups() { - return navigation.searchParams.getAsArray("groups") + return navigation.searchParams.getAsArray("groups"); } onGroupChange(group: string) { @@ -32,7 +32,7 @@ export class CrdList extends React.Component { const index = groups.findIndex(item => item == group); if (index !== -1) groups.splice(index, 1); else groups.push(group); - setQueryParams({ groups }) + setQueryParams({ groups }); } render() { @@ -52,14 +52,14 @@ export class CrdList extends React.Component { searchFilters={Object.values(sortingCallbacks)} filterItems={[ (items: CustomResourceDefinition[]) => { - return selectedGroups.length ? items.filter(item => selectedGroups.includes(item.getGroup())) : items + return selectedGroups.length ? items.filter(item => selectedGroups.includes(item.getGroup())) : items; } ]} renderHeaderTitle={Custom Resources} customizeHeader={() => { let placeholder = All groups; - if (selectedGroups.length == 1) placeholder = <>Group: {selectedGroups[0]}> - if (selectedGroups.length >= 2) placeholder = <>Groups: {selectedGroups.join(", ")}> + if (selectedGroups.length == 1) placeholder = <>Group: {selectedGroups[0]}>; + if (selectedGroups.length >= 2) placeholder = <>Groups: {selectedGroups.join(", ")}>; return { // todo: move to global filters filters: ( @@ -77,11 +77,11 @@ export class CrdList extends React.Component { {group} {isSelected && } - ) + ); }} /> ) - } + }; }} renderTableHeader={[ { title: Resource, className: "kind", sortBy: sortBy.kind }, @@ -99,10 +99,10 @@ export class CrdList extends React.Component { crd.getVersion(), crd.getScope(), crd.getAge(), - ] + ]; }} /> - ) + ); } } diff --git a/src/renderer/components/+custom-resources/crd-resource-details.tsx b/src/renderer/components/+custom-resources/crd-resource-details.tsx index 883fba2fd4..d04962c0dc 100644 --- a/src/renderer/components/+custom-resources/crd-resource-details.tsx +++ b/src/renderer/components/+custom-resources/crd-resource-details.tsx @@ -19,7 +19,7 @@ interface Props extends KubeObjectDetailsProps { function convertSpecValue(value: any): any { if (Array.isArray(value)) { - return value.map(convertSpecValue) + return value.map(convertSpecValue); } if (typeof value === "object") { @@ -31,10 +31,10 @@ function convertSpecValue(value: any): any { className="box grow" value={JSON.stringify(value, null, 2)} /> - ) + ); } - return value + return value; } @observer @@ -48,13 +48,13 @@ export class CrdResourceDetails extends React.Component { {convertSpecValue(jsonPath.value(crd, jp.slice(1)))} - )) + )); } renderStatus(crd: CustomResourceDefinition, columns: AdditionalPrinterColumnsV1[]) { const showStatus = !columns.find(column => column.name == "Status") && crd.status?.conditions; if (!showStatus) { - return null + return null; } const conditions = crd.status.conditions @@ -66,13 +66,13 @@ export class CrdResourceDetails extends React.Component { className={cssNames({ disabled: status === "False" }, kind.toLowerCase())} tooltip={message} /> - )) + )); return ( Status} className="status" labelsOnly> {conditions} - ) + ); } render() { @@ -90,6 +90,6 @@ export class CrdResourceDetails extends React.Component { {this.renderAdditionalColumns(object, extraColumns)} {this.renderStatus(object, extraColumns)} - ) + ); } } diff --git a/src/renderer/components/+custom-resources/crd-resources.tsx b/src/renderer/components/+custom-resources/crd-resources.tsx index e36fef532d..6afe40ae3c 100644 --- a/src/renderer/components/+custom-resources/crd-resources.tsx +++ b/src/renderer/components/+custom-resources/crd-resources.tsx @@ -32,7 +32,7 @@ export class CrdResources extends React.Component { store.loadAll(); } }) - ]) + ]); } @computed get crd() { @@ -41,7 +41,7 @@ export class CrdResources extends React.Component { } @computed get store() { - if (!this.crd) return null + if (!this.crd) return null; return apiManager.getStore(this.crd.getResourceApiBase()); } @@ -54,10 +54,10 @@ export class CrdResources extends React.Component { [sortBy.name]: (item: KubeObject) => item.getName(), [sortBy.namespace]: (item: KubeObject) => item.getNs(), [sortBy.age]: (item: KubeObject) => item.metadata.creationTimestamp, - } + }; extraColumns.forEach(column => { - sortingCallbacks[column.name] = (item: KubeObject) => jsonPath.value(item, column.jsonPath.slice(1)) - }) + sortingCallbacks[column.name] = (item: KubeObject) => jsonPath.value(item, column.jsonPath.slice(1)); + }); return ( { title: name, className: name.toLowerCase(), sortBy: name - } + }; }), { title: Age, className: "age", sortBy: sortBy.age }, ]} @@ -92,6 +92,6 @@ export class CrdResources extends React.Component { crdInstance.getAge(), ]} /> - ) + ); } } diff --git a/src/renderer/components/+custom-resources/crd.route.ts b/src/renderer/components/+custom-resources/crd.route.ts index f9affeb903..fc819d6560 100644 --- a/src/renderer/components/+custom-resources/crd.route.ts +++ b/src/renderer/components/+custom-resources/crd.route.ts @@ -3,15 +3,15 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const crdRoute: RouteProps = { path: "/crd" -} +}; export const crdDefinitionsRoute: RouteProps = { path: crdRoute.path + "/definitions" -} +}; export const crdResourcesRoute: RouteProps = { path: crdRoute.path + "/:group/:name" -} +}; export interface ICRDListQuery { groups?: string; diff --git a/src/renderer/components/+custom-resources/crd.store.ts b/src/renderer/components/+custom-resources/crd.store.ts index e73bbd1fb7..54e1d3df66 100644 --- a/src/renderer/components/+custom-resources/crd.store.ts +++ b/src/renderer/components/+custom-resources/crd.store.ts @@ -20,20 +20,20 @@ function initStore(crd: CustomResourceDefinition) { @autobind() export class CRDStore extends KubeObjectStore { - api = crdApi + api = crdApi; constructor() { super(); // auto-init stores for crd-s - reaction(() => this.items.toJS(), items => items.forEach(initStore)) + reaction(() => this.items.toJS(), items => items.forEach(initStore)); } protected sortItems(items: CustomResourceDefinition[]) { return super.sortItems(items, [ crd => crd.getGroup(), crd => crd.getName(), - ]) + ]); } @computed get groups() { @@ -43,7 +43,7 @@ export class CRDStore extends KubeObjectStore { if (!groups[group]) groups[group] = []; groups[group].push(crd); return groups; - }, groups) + }, groups); } getByGroup(group: string, pluralName: string) { @@ -53,12 +53,12 @@ export class CRDStore extends KubeObjectStore { } getByObject(obj: KubeObject) { - if (!obj) return null + if (!obj) return null; const { kind, apiVersion } = obj; return this.items.find(crd => ( kind === crd.getResourceKind() && apiVersion === `${crd.getGroup()}/${crd.getVersion()}` - )) + )); } } diff --git a/src/renderer/components/+custom-resources/custom-resources.tsx b/src/renderer/components/+custom-resources/custom-resources.tsx index ee34809013..95a05e9f33 100644 --- a/src/renderer/components/+custom-resources/custom-resources.tsx +++ b/src/renderer/components/+custom-resources/custom-resources.tsx @@ -17,7 +17,7 @@ export class CustomResources extends React.Component { url: crdURL(), routePath: crdRoute.path.toString(), } - ] + ]; } render() { diff --git a/src/renderer/components/+events/event-details.tsx b/src/renderer/components/+events/event-details.tsx index b3d80ce318..3d6f51ab0b 100644 --- a/src/renderer/components/+events/event-details.tsx +++ b/src/renderer/components/+events/event-details.tsx @@ -70,7 +70,7 @@ export class EventDetails extends React.Component { - ) + ); } } @@ -80,4 +80,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+events/event.store.ts b/src/renderer/components/+events/event.store.ts index 3d8142a55f..484c9701c1 100644 --- a/src/renderer/components/+events/event.store.ts +++ b/src/renderer/components/+events/event.store.ts @@ -10,8 +10,8 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class EventStore extends KubeObjectStore { - api = eventApi - limit = 1000 + api = eventApi; + limit = 1000; protected bindWatchEventsUpdater() { return super.bindWatchEventsUpdater(5000); @@ -20,7 +20,7 @@ export class EventStore extends KubeObjectStore { protected sortItems(items: KubeEvent[]) { return super.sortItems(items, [ event => event.metadata.creationTimestamp - ], "desc") + ], "desc"); } getEventsByObject(obj: KubeObject): KubeEvent[] { diff --git a/src/renderer/components/+events/events.route.ts b/src/renderer/components/+events/events.route.ts index b7d96824f6..6ae3a9a10b 100644 --- a/src/renderer/components/+events/events.route.ts +++ b/src/renderer/components/+events/events.route.ts @@ -3,6 +3,6 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const eventRoute: RouteProps = { path: "/events" -} +}; export const eventsURL = buildURL(eventRoute.path); diff --git a/src/renderer/components/+events/events.tsx b/src/renderer/components/+events/events.tsx index 868da0836a..0a6aab3730 100644 --- a/src/renderer/components/+events/events.tsx +++ b/src/renderer/components/+events/events.tsx @@ -106,14 +106,14 @@ export class Events extends React.Component { event.getSource(), event.count, event.getAge(), - ] + ]; }} virtual={!compact} filterItems={[ items => compact ? items.slice(0, compactLimit) : items, ]} /> - ) + ); if (compact) { return events; } @@ -121,6 +121,6 @@ export class Events extends React.Component { {events} - ) + ); } } diff --git a/src/renderer/components/+events/kube-event-details.tsx b/src/renderer/components/+events/kube-event-details.tsx index 5b3e5f23b9..297c4e791f 100644 --- a/src/renderer/components/+events/kube-event-details.tsx +++ b/src/renderer/components/+events/kube-event-details.tsx @@ -26,7 +26,7 @@ export class KubeEventDetails extends React.Component { Events - ) + ); } return ( @@ -35,7 +35,7 @@ export class KubeEventDetails extends React.Component { {events.map(evt => { - const { message, count, lastTimestamp, involvedObject } = evt + const { message, count, lastTimestamp, involvedObject } = evt; return ( @@ -54,10 +54,10 @@ export class KubeEventDetails extends React.Component { {lastTimestamp} - ) + ); })} - ) + ); } } diff --git a/src/renderer/components/+events/kube-event-icon.tsx b/src/renderer/components/+events/kube-event-icon.tsx index 204dfd3a36..15a91ea5b3 100644 --- a/src/renderer/components/+events/kube-event-icon.tsx +++ b/src/renderer/components/+events/kube-event-icon.tsx @@ -45,6 +45,6 @@ export class KubeEventIcon extends React.Component { ) }} /> - ) + ); } } diff --git a/src/renderer/components/+extensions/extensions.route.ts b/src/renderer/components/+extensions/extensions.route.ts index 78c5579901..04708ca5d4 100644 --- a/src/renderer/components/+extensions/extensions.route.ts +++ b/src/renderer/components/+extensions/extensions.route.ts @@ -3,6 +3,6 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const extensionsRoute: RouteProps = { path: "/extensions" -} +}; -export const extensionsURL = buildURL(extensionsRoute.path) +export const extensionsURL = buildURL(extensionsRoute.path); diff --git a/src/renderer/components/+extensions/extensions.tsx b/src/renderer/components/+extensions/extensions.tsx index 34814393ae..875861a8dd 100644 --- a/src/renderer/components/+extensions/extensions.tsx +++ b/src/renderer/components/+extensions/extensions.tsx @@ -15,7 +15,7 @@ import { extensionManager } from "../../../extensions/extension-manager"; @observer export class Extensions extends React.Component { - @observable search = "" + @observable search = ""; @computed get extensions() { const searchText = this.search.toLowerCase(); @@ -24,8 +24,8 @@ export class Extensions extends React.Component { return [ name.toLowerCase().includes(searchText), description.toLowerCase().includes(searchText), - ].some(v => v) - }) + ].some(v => v); + }); } get extensionsPath() { @@ -55,7 +55,7 @@ export class Extensions extends React.Component { Check out documentation to learn more - ) + ); } renderExtensions() { @@ -66,7 +66,7 @@ export class Extensions extends React.Component { {search && No search results found} {!search && There are no extensions in {extensionsPath}} - ) + ); } return extensions.map(ext => { const { manifestPath: extId, isEnabled, manifest } = ext; @@ -88,8 +88,8 @@ export class Extensions extends React.Component { ext.isEnabled = false}>Disable )} - ) - }) + ); + }); } render() { diff --git a/src/renderer/components/+extensions/index.ts b/src/renderer/components/+extensions/index.ts index 8946a5f6fe..ff9343e704 100644 --- a/src/renderer/components/+extensions/index.ts +++ b/src/renderer/components/+extensions/index.ts @@ -1,2 +1,2 @@ -export * from "./extensions.route" -export * from "./extensions" +export * from "./extensions.route"; +export * from "./extensions"; diff --git a/src/renderer/components/+landing-page/index.tsx b/src/renderer/components/+landing-page/index.tsx index 36f2dce350..4bdb2a706c 100644 --- a/src/renderer/components/+landing-page/index.tsx +++ b/src/renderer/components/+landing-page/index.tsx @@ -1,2 +1,2 @@ -export * from "./landing-page.route" -export * from "./landing-page" \ No newline at end of file +export * from "./landing-page.route"; +export * from "./landing-page"; \ No newline at end of file diff --git a/src/renderer/components/+landing-page/landing-page.route.ts b/src/renderer/components/+landing-page/landing-page.route.ts index 344cc48033..5fa9f2321e 100644 --- a/src/renderer/components/+landing-page/landing-page.route.ts +++ b/src/renderer/components/+landing-page/landing-page.route.ts @@ -3,6 +3,6 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const landingRoute: RouteProps = { path: "/landing" -} +}; -export const landingURL = buildURL(landingRoute.path) +export const landingURL = buildURL(landingRoute.path); diff --git a/src/renderer/components/+landing-page/landing-page.tsx b/src/renderer/components/+landing-page/landing-page.tsx index 68d71701c5..5c1e34297c 100644 --- a/src/renderer/components/+landing-page/landing-page.tsx +++ b/src/renderer/components/+landing-page/landing-page.tsx @@ -1,4 +1,4 @@ -import "./landing-page.scss" +import "./landing-page.scss"; import React from "react"; import { observable } from "mobx"; import { observer } from "mobx-react"; @@ -37,6 +37,6 @@ export class LandingPage extends React.Component { )} - ) + ); } } diff --git a/src/renderer/components/+namespaces/add-namespace-dialog.tsx b/src/renderer/components/+namespaces/add-namespace-dialog.tsx index 8c09c80138..a31a44de94 100644 --- a/src/renderer/components/+namespaces/add-namespace-dialog.tsx +++ b/src/renderer/components/+namespaces/add-namespace-dialog.tsx @@ -1,4 +1,4 @@ -import "./add-namespace-dialog.scss" +import "./add-namespace-dialog.scss"; import React from "react"; import { observable } from "mobx"; @@ -33,7 +33,7 @@ export class AddNamespaceDialog extends React.Component { close = () => { AddNamespaceDialog.close(); - } + }; addNamespace = async () => { const { namespace } = this; @@ -45,7 +45,7 @@ export class AddNamespaceDialog extends React.Component { Notifications.error(err); onError && onError(err); } - } + }; render() { const { ...dialogProps } = this.props; @@ -74,6 +74,6 @@ export class AddNamespaceDialog extends React.Component { - ) + ); } } diff --git a/src/renderer/components/+namespaces/index.ts b/src/renderer/components/+namespaces/index.ts index d0b9647dc7..3a03949618 100644 --- a/src/renderer/components/+namespaces/index.ts +++ b/src/renderer/components/+namespaces/index.ts @@ -1,4 +1,4 @@ -export * from "./namespaces.route" -export * from "./namespaces" -export * from "./namespace-details" -export * from "./add-namespace-dialog" +export * from "./namespaces.route"; +export * from "./namespaces"; +export * from "./namespace-details"; +export * from "./add-namespace-dialog"; diff --git a/src/renderer/components/+namespaces/namespace-details.tsx b/src/renderer/components/+namespaces/namespace-details.tsx index a7e2abf2f3..7599562333 100644 --- a/src/renderer/components/+namespaces/namespace-details.tsx +++ b/src/renderer/components/+namespaces/namespace-details.tsx @@ -62,4 +62,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+namespaces/namespace-select.tsx b/src/renderer/components/+namespaces/namespace-select.tsx index 7657a25345..e1c64f8342 100644 --- a/src/renderer/components/+namespaces/namespace-select.tsx +++ b/src/renderer/components/+namespaces/namespace-select.tsx @@ -1,4 +1,4 @@ -import "./namespace-select.scss" +import "./namespace-select.scss"; import React from "react"; import { computed } from "mobx"; @@ -62,7 +62,7 @@ export class NamespaceSelect extends React.Component { {value} > ); - } + }; render() { const { className, showIcons, showClusterOption, clusterOptionLabel, customizeOptions, ...selectProps } = this.props; @@ -83,8 +83,8 @@ export class NamespaceSelectFilter extends React.Component { render() { const { contextNs, hasContext, toggleContext } = namespaceStore; let placeholder = All namespaces; - if (contextNs.length == 1) placeholder = Namespace: {contextNs[0]} - if (contextNs.length >= 2) placeholder = Namespaces: {contextNs.join(", ")} + if (contextNs.length == 1) placeholder = Namespace: {contextNs[0]}; + if (contextNs.length >= 2) placeholder = Namespaces: {contextNs.join(", ")}; return ( {namespace} {isSelected && } - ) + ); }} /> - ) + ); } } diff --git a/src/renderer/components/+namespaces/namespace.store.ts b/src/renderer/components/+namespaces/namespace.store.ts index 8874aa9233..dabde6b47d 100644 --- a/src/renderer/components/+namespaces/namespace.store.ts +++ b/src/renderer/components/+namespaces/namespace.store.ts @@ -36,20 +36,20 @@ export class NamespaceStore extends KubeObjectStore { getContextParams(): Partial { return { namespaces: this.contextNs - } + }; } protected updateUrl(namespaces: string[]) { - setQueryParams({ namespaces }, { replace: true }) + setQueryParams({ namespaces }, { replace: true }); } protected async loadItems(namespaces?: string[]) { if (!isAllowedResource("namespaces")) { if (namespaces) return namespaces.map(this.getDummyNamespace); - return [] + return []; } if (namespaces) { - return Promise.all(namespaces.map(name => this.api.get({ name }))) + return Promise.all(namespaces.map(name => this.api.get({ name }))); } else { return super.loadItems(); } @@ -65,7 +65,7 @@ export class NamespaceStore extends KubeObjectStore { resourceVersion: "", selfLink: `/api/v1/namespaces/${name}` } - }) + }); } setContext(namespaces: string[]) { diff --git a/src/renderer/components/+namespaces/namespaces.route.ts b/src/renderer/components/+namespaces/namespaces.route.ts index 9d901b6ada..38c2d575d9 100644 --- a/src/renderer/components/+namespaces/namespaces.route.ts +++ b/src/renderer/components/+namespaces/namespaces.route.ts @@ -3,9 +3,9 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const namespacesRoute: RouteProps = { path: "/namespaces" -} +}; export interface INamespacesRouteParams { } -export const namespacesURL = buildURL(namespacesRoute.path) +export const namespacesURL = buildURL(namespacesRoute.path); diff --git a/src/renderer/components/+namespaces/namespaces.tsx b/src/renderer/components/+namespaces/namespaces.tsx index 05ef3da964..f4bb96aa14 100644 --- a/src/renderer/components/+namespaces/namespaces.tsx +++ b/src/renderer/components/+namespaces/namespaces.tsx @@ -1,4 +1,4 @@ -import "./namespaces.scss" +import "./namespaces.scss"; import React from "react"; import { Trans } from "@lingui/macro"; @@ -64,6 +64,6 @@ export class Namespaces extends React.Component { /> - ) + ); } } diff --git a/src/renderer/components/+network-endpoints/endpoint-details.tsx b/src/renderer/components/+network-endpoints/endpoint-details.tsx index fa5ca675a3..df01cf612e 100644 --- a/src/renderer/components/+network-endpoints/endpoint-details.tsx +++ b/src/renderer/components/+network-endpoints/endpoint-details.tsx @@ -1,4 +1,4 @@ -import "./endpoint-details.scss" +import "./endpoint-details.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -28,7 +28,7 @@ export class EndpointDetails extends React.Component { endpoint.getEndpointSubsets().map((subset) => { return( - ) + ); }) } @@ -42,7 +42,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "Endpoints", apiVersions: ["v1"], @@ -50,4 +50,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx b/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx index 399c6ca5f1..0c3c5c0436 100644 --- a/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx +++ b/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx @@ -1,4 +1,4 @@ -import "./endpoint-subset-list.scss" +import "./endpoint-subset-list.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -23,14 +23,14 @@ export class EndpointSubsetList extends React.Component { getAddressTableRow(ip: string) { const { subset } = this.props; const address = subset.getAddresses().find(address => address.getId() == ip); - return this.renderAddressTableRow(address) + return this.renderAddressTableRow(address); } @autobind() getNotReadyAddressTableRow(ip: string) { const { subset} = this.props; const address = subset.getNotReadyAddresses().find(address => address.getId() == ip); - return this.renderAddressTableRow(address) + return this.renderAddressTableRow(address); } @autobind() @@ -56,7 +56,7 @@ export class EndpointSubsetList extends React.Component { } - ) + ); } @autobind() diff --git a/src/renderer/components/+network-endpoints/endpoints.route.ts b/src/renderer/components/+network-endpoints/endpoints.route.ts index 98ecb67bdb..f350b7868e 100644 --- a/src/renderer/components/+network-endpoints/endpoints.route.ts +++ b/src/renderer/components/+network-endpoints/endpoints.route.ts @@ -3,9 +3,9 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const endpointRoute: RouteProps = { path: "/endpoints" -} +}; export interface EndpointRouteParams { } -export const endpointURL = buildURL(endpointRoute.path) +export const endpointURL = buildURL(endpointRoute.path); diff --git a/src/renderer/components/+network-endpoints/endpoints.store.ts b/src/renderer/components/+network-endpoints/endpoints.store.ts index 5d4a6b6ff7..d61a12126e 100644 --- a/src/renderer/components/+network-endpoints/endpoints.store.ts +++ b/src/renderer/components/+network-endpoints/endpoints.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class EndpointStore extends KubeObjectStore { - api = endpointApi + api = endpointApi; } export const endpointStore = new EndpointStore(); diff --git a/src/renderer/components/+network-endpoints/endpoints.tsx b/src/renderer/components/+network-endpoints/endpoints.tsx index b32b19946c..b8862841cb 100644 --- a/src/renderer/components/+network-endpoints/endpoints.tsx +++ b/src/renderer/components/+network-endpoints/endpoints.tsx @@ -1,10 +1,10 @@ -import "./endpoints.scss" +import "./endpoints.scss"; -import React from "react" +import React from "react"; import { observer } from "mobx-react"; -import { RouteComponentProps } from "react-router-dom" -import { EndpointRouteParams } from "./endpoints.route" -import { Endpoint } from "../../api/endpoints/endpoint.api" +import { RouteComponentProps } from "react-router-dom"; +import { EndpointRouteParams } from "./endpoints.route"; +import { Endpoint } from "../../api/endpoints/endpoint.api"; import { endpointStore } from "./endpoints.store"; import { KubeObjectListLayout } from "../kube-object"; import { Trans } from "@lingui/macro"; @@ -55,6 +55,6 @@ export class Endpoints extends React.Component { } }} /> - ) + ); } } diff --git a/src/renderer/components/+network-endpoints/index.ts b/src/renderer/components/+network-endpoints/index.ts index 9a9da148d6..eb91009613 100644 --- a/src/renderer/components/+network-endpoints/index.ts +++ b/src/renderer/components/+network-endpoints/index.ts @@ -1,3 +1,3 @@ -export * from "./endpoints.route" -export * from "./endpoints" -export * from "./endpoint-details" +export * from "./endpoints.route"; +export * from "./endpoints"; +export * from "./endpoint-details"; diff --git a/src/renderer/components/+network-ingresses/index.ts b/src/renderer/components/+network-ingresses/index.ts index 46769f9275..3977538fc7 100644 --- a/src/renderer/components/+network-ingresses/index.ts +++ b/src/renderer/components/+network-ingresses/index.ts @@ -1,3 +1,3 @@ -export * from "./ingresses.route" -export * from "./ingresses" -export * from "./ingress-details" +export * from "./ingresses.route"; +export * from "./ingresses"; +export * from "./ingress-details"; diff --git a/src/renderer/components/+network-ingresses/ingress-charts.tsx b/src/renderer/components/+network-ingresses/ingress-charts.tsx index 89ceb86b3d..7ea16a92a3 100644 --- a/src/renderer/components/+network-ingresses/ingress-charts.tsx +++ b/src/renderer/components/+network-ingresses/ingress-charts.tsx @@ -94,4 +94,4 @@ export const IngressCharts = observer(() => { data={{ datasets: datasets[tabId] }} /> ); -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/src/renderer/components/+network-ingresses/ingress-details.tsx b/src/renderer/components/+network-ingresses/ingress-details.tsx index 5a4479672b..a258294abe 100644 --- a/src/renderer/components/+network-ingresses/ingress-details.tsx +++ b/src/renderer/components/+network-ingresses/ingress-details.tsx @@ -30,8 +30,8 @@ export class IngressDetails extends React.Component { } renderPaths(ingress: Ingress) { - const { spec: { rules } } = ingress - if (!rules || !rules.length) return null + const { spec: { rules } } = ingress; + if (!rules || !rules.length) return null; return rules.map((rule, index) => { return ( @@ -48,7 +48,7 @@ export class IngressDetails extends React.Component { { rule.http.paths.map((path, index) => { - const backend = `${path.backend.serviceName}:${path.backend.servicePort}` + const backend = `${path.backend.serviceName}:${path.backend.servicePort}`; return ( {path.path || ""} @@ -56,18 +56,18 @@ export class IngressDetails extends React.Component { {backend} - ) + ); }) } )} - ) - }) + ); + }); } renderIngressPoints(ingressPoints: ILoadBalancerIngress[]) { - if (!ingressPoints || ingressPoints.length === 0) return null + if (!ingressPoints || ingressPoints.length === 0) return null; return ( @@ -81,11 +81,11 @@ export class IngressDetails extends React.Component { {hostname ? hostname : "-"} {ip ? ip : "-"} - )}) + );}) }) - ) + ); } render() { @@ -94,7 +94,7 @@ export class IngressDetails extends React.Component { return null; } const { spec, status } = ingress; - const ingressPoints = status?.loadBalancer?.ingress + const ingressPoints = status?.loadBalancer?.ingress; const { metrics } = ingressStore; const metricTabs = [ Network, @@ -128,7 +128,7 @@ export class IngressDetails extends React.Component { Load-Balancer Ingress Points}/> {this.renderIngressPoints(ingressPoints)} - ) + ); } } @@ -138,7 +138,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "Ingress", apiVersions: ["extensions/v1beta1"], @@ -146,4 +146,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+network-ingresses/ingresses.route.ts b/src/renderer/components/+network-ingresses/ingresses.route.ts index 1c1f2941f4..827707bcef 100644 --- a/src/renderer/components/+network-ingresses/ingresses.route.ts +++ b/src/renderer/components/+network-ingresses/ingresses.route.ts @@ -3,9 +3,9 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const ingressRoute: RouteProps = { path: "/ingresses" -} +}; export interface IngressRouteParams { } -export const ingressURL = buildURL(ingressRoute.path) +export const ingressURL = buildURL(ingressRoute.path); diff --git a/src/renderer/components/+network-ingresses/ingresses.tsx b/src/renderer/components/+network-ingresses/ingresses.tsx index 2ecfeb1585..bba5615915 100644 --- a/src/renderer/components/+network-ingresses/ingresses.tsx +++ b/src/renderer/components/+network-ingresses/ingresses.tsx @@ -1,10 +1,10 @@ -import "./ingresses.scss" +import "./ingresses.scss"; -import React from "react" +import React from "react"; import { observer } from "mobx-react"; -import { RouteComponentProps } from "react-router-dom" -import { IngressRouteParams } from "./ingresses.route" -import { Ingress } from "../../api/endpoints/ingress.api" +import { RouteComponentProps } from "react-router-dom"; +import { IngressRouteParams } from "./ingresses.route"; +import { Ingress } from "../../api/endpoints/ingress.api"; import { ingressStore } from "./ingress.store"; import { KubeObjectListLayout } from "../kube-object"; import { Trans } from "@lingui/macro"; @@ -58,6 +58,6 @@ export class Ingresses extends React.Component { } }} /> - ) + ); } } diff --git a/src/renderer/components/+network-policies/index.ts b/src/renderer/components/+network-policies/index.ts index 0521db2765..f0092b8bcc 100644 --- a/src/renderer/components/+network-policies/index.ts +++ b/src/renderer/components/+network-policies/index.ts @@ -1,3 +1,3 @@ -export * from "./network-policies.route" -export * from "./network-policies" -export * from "./network-policy-details" +export * from "./network-policies.route"; +export * from "./network-policies"; +export * from "./network-policy-details"; diff --git a/src/renderer/components/+network-policies/network-policies.route.ts b/src/renderer/components/+network-policies/network-policies.route.ts index ab609200ce..16b507cd55 100644 --- a/src/renderer/components/+network-policies/network-policies.route.ts +++ b/src/renderer/components/+network-policies/network-policies.route.ts @@ -3,7 +3,7 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const networkPoliciesRoute: RouteProps = { path: "/network-policies" -} +}; export interface INetworkPoliciesRouteParams { } diff --git a/src/renderer/components/+network-policies/network-policies.tsx b/src/renderer/components/+network-policies/network-policies.tsx index f28917f653..b54b6a80aa 100644 --- a/src/renderer/components/+network-policies/network-policies.tsx +++ b/src/renderer/components/+network-policies/network-policies.tsx @@ -1,4 +1,4 @@ -import "./network-policies.scss" +import "./network-policies.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -49,6 +49,6 @@ export class NetworkPolicies extends React.Component { item.getAge(), ]} /> - ) + ); } } diff --git a/src/renderer/components/+network-policies/network-policy-details.tsx b/src/renderer/components/+network-policies/network-policy-details.tsx index 6f38f6d02b..ac9f1d7ba2 100644 --- a/src/renderer/components/+network-policies/network-policy-details.tsx +++ b/src/renderer/components/+network-policies/network-policy-details.tsx @@ -1,4 +1,4 @@ -import "./network-policy-details.scss" +import "./network-policy-details.scss"; import get from "lodash/get"; import React, { Fragment } from "react"; @@ -27,10 +27,10 @@ export class NetworkPolicyDetails extends React.Component { From}/> {from.map(item => Object.keys(item).map(key => { - const data = get(item, key) + const data = get(item, key); if (key === "ipBlock") { const { cidr, except } = data as IPolicyIpBlock; - if (!cidr) return + if (!cidr) return; return ( cidr: {cidr}, {" "} @@ -38,9 +38,9 @@ export class NetworkPolicyDetails extends React.Component { `except: ${except.join(", ")}` } - ) + ); } - const selector: IPolicySelector = data + const selector: IPolicySelector = data; if (selector.matchLabels) { return ( @@ -51,7 +51,7 @@ export class NetworkPolicyDetails extends React.Component { .join(", ") } - ) + ); } else { return ((empty)); @@ -69,10 +69,10 @@ export class NetworkPolicyDetails extends React.Component { <> To}/> {to.map(item => { - const { ipBlock } = item - if (!ipBlock) return - const { cidr, except } = ipBlock - if (!cidr) return + const { ipBlock } = item; + if (!ipBlock) return; + const { cidr, except } = ipBlock; + if (!cidr) return; return ( cidr: {cidr}, {" "} @@ -80,7 +80,7 @@ export class NetworkPolicyDetails extends React.Component { `except: ${except.join(", ")}` } - ) + ); })} > ); @@ -116,7 +116,7 @@ export class NetworkPolicyDetails extends React.Component { {this.renderIngressFrom(ingress)} - ) + ); })} > )} @@ -133,7 +133,7 @@ export class NetworkPolicyDetails extends React.Component { {this.renderEgressTo(egress)} - ) + ); })} > )} @@ -148,7 +148,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "NetworkPolicy", @@ -157,4 +157,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+network-policies/network-policy.store.ts b/src/renderer/components/+network-policies/network-policy.store.ts index 0f37de3ac0..e33a17fa09 100644 --- a/src/renderer/components/+network-policies/network-policy.store.ts +++ b/src/renderer/components/+network-policies/network-policy.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class NetworkPolicyStore extends KubeObjectStore { - api = networkPolicyApi + api = networkPolicyApi; } export const networkPolicyStore = new NetworkPolicyStore(); diff --git a/src/renderer/components/+network-services/index.ts b/src/renderer/components/+network-services/index.ts index 4f64dcf2c9..de2b4282d5 100644 --- a/src/renderer/components/+network-services/index.ts +++ b/src/renderer/components/+network-services/index.ts @@ -1,3 +1,3 @@ -export * from "./services.route" -export * from "./services" -export * from "./service-details" +export * from "./services.route"; +export * from "./services"; +export * from "./service-details"; diff --git a/src/renderer/components/+network-services/service-details-endpoint.tsx b/src/renderer/components/+network-services/service-details-endpoint.tsx index a16d1c2c0a..df0aac76ec 100644 --- a/src/renderer/components/+network-services/service-details-endpoint.tsx +++ b/src/renderer/components/+network-services/service-details-endpoint.tsx @@ -15,12 +15,12 @@ interface Props { @observer export class ServiceDetailsEndpoint extends React.Component { render() { - const { endpoint } = this.props + const { endpoint } = this.props; if (!endpoint && !endpointStore.isLoaded) return ( ); if (!endpoint) { - return null + return null; } return ( @@ -44,6 +44,6 @@ export class ServiceDetailsEndpoint extends React.Component { - ) + ); } } diff --git a/src/renderer/components/+network-services/service-details.tsx b/src/renderer/components/+network-services/service-details.tsx index e43f7fab0c..5d659cc7e1 100644 --- a/src/renderer/components/+network-services/service-details.tsx +++ b/src/renderer/components/+network-services/service-details.tsx @@ -1,4 +1,4 @@ -import "./service-details.scss" +import "./service-details.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -24,14 +24,14 @@ export class ServiceDetails extends React.Component { if (!endpointStore.isLoaded) { endpointStore.loadAll(); } - endpointApi.watch() + endpointApi.watch(); } render() { const { object: service } = this.props; if (!service) return; const { spec } = service; - const endpoint = endpointStore.getByName(service.getName(), service.getNs()) + const endpoint = endpointStore.getByName(service.getName(), service.getNs()); return ( @@ -89,7 +89,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "Service", @@ -98,4 +98,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+network-services/service-port-component.tsx b/src/renderer/components/+network-services/service-port-component.tsx index 252bf8eb16..8b3dba03c4 100644 --- a/src/renderer/components/+network-services/service-port-component.tsx +++ b/src/renderer/components/+network-services/service-port-component.tsx @@ -1,15 +1,15 @@ -import "./service-port-component.scss" +import "./service-port-component.scss"; import React from "react"; import { observer } from "mobx-react"; import { t } from "@lingui/macro"; import { Service, ServicePort } from "../../api/endpoints"; import { _i18n } from "../../i18n"; -import { apiBase } from "../../api" +import { apiBase } from "../../api"; import { observable } from "mobx"; import { cssNames } from "../../utils"; import { Notifications } from "../notifications"; -import { Spinner } from "../spinner" +import { Spinner } from "../spinner"; interface Props { service: Service; @@ -24,7 +24,7 @@ export class ServicePortComponent extends React.Component { const { service, port } = this.props; this.waiting = true; try { - await apiBase.post(`/pods/${service.getNs()}/service/${service.getName()}/port-forward/${port.port}`, {}) + await apiBase.post(`/pods/${service.getNs()}/service/${service.getName()}/port-forward/${port.port}`, {}); } catch(error) { Notifications.error(error); } finally { diff --git a/src/renderer/components/+network-services/services.route.ts b/src/renderer/components/+network-services/services.route.ts index 8cc42090a7..b23087829d 100644 --- a/src/renderer/components/+network-services/services.route.ts +++ b/src/renderer/components/+network-services/services.route.ts @@ -3,7 +3,7 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const servicesRoute: RouteProps = { path: "/services" -} +}; export interface IServicesRouteParams { } diff --git a/src/renderer/components/+network-services/services.store.ts b/src/renderer/components/+network-services/services.store.ts index d3e3c7b983..8c6d16d746 100644 --- a/src/renderer/components/+network-services/services.store.ts +++ b/src/renderer/components/+network-services/services.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class ServiceStore extends KubeObjectStore { - api = serviceApi + api = serviceApi; } export const serviceStore = new ServiceStore(); diff --git a/src/renderer/components/+network-services/services.tsx b/src/renderer/components/+network-services/services.tsx index ed7951a78b..0aacbb602e 100644 --- a/src/renderer/components/+network-services/services.tsx +++ b/src/renderer/components/+network-services/services.tsx @@ -1,4 +1,4 @@ -import "./services.scss" +import "./services.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -72,6 +72,6 @@ export class Services extends React.Component { { title: service.getStatus(), className: service.getStatus().toLowerCase() }, ]} /> - ) + ); } } diff --git a/src/renderer/components/+network/index.ts b/src/renderer/components/+network/index.ts index c5282c5b0e..9a58dc59a6 100644 --- a/src/renderer/components/+network/index.ts +++ b/src/renderer/components/+network/index.ts @@ -1,2 +1,2 @@ -export * from "./network.route" -export * from "./network" +export * from "./network.route"; +export * from "./network"; diff --git a/src/renderer/components/+network/network.route.ts b/src/renderer/components/+network/network.route.ts index c13f7cedf7..de36bfc77a 100644 --- a/src/renderer/components/+network/network.route.ts +++ b/src/renderer/components/+network/network.route.ts @@ -1,12 +1,12 @@ -import { RouteProps } from "react-router" +import { RouteProps } from "react-router"; import { Network } from "./network"; import { servicesURL } from "../+network-services"; import { IURLParams } from "../../../common/utils/buildUrl"; export const networkRoute: RouteProps = { get path() { - return Network.tabRoutes.map(({ routePath }) => routePath).flat() + return Network.tabRoutes.map(({ routePath }) => routePath).flat(); } -} +}; export const networkURL = (params?: IURLParams) => servicesURL(params); diff --git a/src/renderer/components/+network/network.tsx b/src/renderer/components/+network/network.tsx index 9e0b2d92c6..2cc99eb367 100644 --- a/src/renderer/components/+network/network.tsx +++ b/src/renderer/components/+network/network.tsx @@ -1,4 +1,4 @@ -import "./network.scss" +import "./network.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -14,7 +14,7 @@ import { isAllowedResource } from "../../../common/rbac"; @observer export class Network extends React.Component { static get tabRoutes(): TabLayoutRoute[] { - const query = namespaceStore.getContextParams() + const query = namespaceStore.getContextParams(); const routes: TabLayoutRoute[] = []; if (isAllowedResource("services")) { routes.push({ @@ -22,7 +22,7 @@ export class Network extends React.Component { component: Services, url: servicesURL({ query }), routePath: servicesRoute.path.toString(), - }) + }); } if (isAllowedResource("endpoints")) { routes.push({ @@ -30,7 +30,7 @@ export class Network extends React.Component { component: Endpoints, url: endpointURL({ query }), routePath: endpointRoute.path.toString(), - }) + }); } if (isAllowedResource("ingresses")) { routes.push({ @@ -38,7 +38,7 @@ export class Network extends React.Component { component: Ingresses, url: ingressURL({ query }), routePath: ingressRoute.path.toString(), - }) + }); } if (isAllowedResource("networkpolicies")) { routes.push({ @@ -46,14 +46,14 @@ export class Network extends React.Component { component: NetworkPolicies, url: networkPoliciesURL({ query }), routePath: networkPoliciesRoute.path.toString(), - }) + }); } - return routes + return routes; } render() { return ( - ) + ); } } diff --git a/src/renderer/components/+nodes/index.ts b/src/renderer/components/+nodes/index.ts index 4a77b1c63b..515a3d85f6 100644 --- a/src/renderer/components/+nodes/index.ts +++ b/src/renderer/components/+nodes/index.ts @@ -1,3 +1,3 @@ -export * from "./nodes" -export * from "./nodes.route" -export * from "./node-details" +export * from "./nodes"; +export * from "./nodes.route"; +export * from "./node-details"; diff --git a/src/renderer/components/+nodes/node-charts.tsx b/src/renderer/components/+nodes/node-charts.tsx index 4271181fcd..9f5e6ce6f8 100644 --- a/src/renderer/components/+nodes/node-charts.tsx +++ b/src/renderer/components/+nodes/node-charts.tsx @@ -140,7 +140,7 @@ export const NodeCharts = observer(() => { } } } - } + }; const options = [cpuOptions, memoryOptions, memoryOptions, podOptions]; @@ -151,4 +151,4 @@ export const NodeCharts = observer(() => { data={{ datasets: datasets[tabId] }} /> ); -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/src/renderer/components/+nodes/node-details.tsx b/src/renderer/components/+nodes/node-details.tsx index 1402b77be5..653fff8d2b 100644 --- a/src/renderer/components/+nodes/node-details.tsx +++ b/src/renderer/components/+nodes/node-details.tsx @@ -42,12 +42,12 @@ export class NodeDetails extends React.Component { render() { const { object: node } = this.props; if (!node) return; - const { status } = node - const { nodeInfo, addresses, capacity, allocatable } = status + const { status } = node; + const { nodeInfo, addresses, capacity, allocatable } = status; const conditions = node.getActiveConditions(); - const taints = node.getTaints() - const childPods = podsStore.getPodsByNode(node.getName()) - const metrics = nodesStore.nodeMetrics + const taints = node.getTaints(); + const childPods = podsStore.getPodsByNode(node.getName()); + const metrics = nodesStore.nodeMetrics; const metricTabs = [ CPU, Memory, @@ -120,7 +120,7 @@ export class NodeDetails extends React.Component { Conditions} className="conditions" labelsOnly> { conditions.map(condition => { - const { type } = condition + const { type } = condition; return ( { ) }} /> - ) + ); }) } @@ -150,7 +150,7 @@ export class NodeDetails extends React.Component { maxMemory={node.getMemoryCapacity()} /> - ) + ); } } @@ -160,7 +160,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "Node", @@ -169,4 +169,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+nodes/nodes.route.ts b/src/renderer/components/+nodes/nodes.route.ts index cf03a8733d..972bdababe 100644 --- a/src/renderer/components/+nodes/nodes.route.ts +++ b/src/renderer/components/+nodes/nodes.route.ts @@ -3,9 +3,9 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const nodesRoute: RouteProps = { path: "/nodes" -} +}; export interface INodesRouteParams { } -export const nodesURL = buildURL(nodesRoute.path) +export const nodesURL = buildURL(nodesRoute.path); diff --git a/src/renderer/components/+nodes/nodes.store.ts b/src/renderer/components/+nodes/nodes.store.ts index 8c04f55ad5..94fd3e4dd9 100644 --- a/src/renderer/components/+nodes/nodes.store.ts +++ b/src/renderer/components/+nodes/nodes.store.ts @@ -1,4 +1,4 @@ -import { action, computed, observable } from "mobx" +import { action, computed, observable } from "mobx"; import { clusterApi, IClusterMetrics, INodeMetrics, Node, nodesApi } from "../../api/endpoints"; import { autobind } from "../../utils"; import { KubeObjectStore } from "../../kube-object.store"; @@ -6,7 +6,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class NodesStore extends KubeObjectStore { - api = nodesApi + api = nodesApi; @observable metrics: Partial = {}; @observable nodeMetrics: Partial = null; @@ -30,11 +30,11 @@ export class NodesStore extends KubeObjectStore { } @computed get masterNodes() { - return this.items.filter(node => node.getRoleLabels().includes("master")) + return this.items.filter(node => node.getRoleLabels().includes("master")); } @computed get workerNodes() { - return this.items.filter(node => !node.getRoleLabels().includes("master")) + return this.items.filter(node => !node.getRoleLabels().includes("master")); } getLastMetricValues(node: Node, metricNames: string[]): number[] { @@ -50,7 +50,7 @@ export class NodesStore extends KubeObjectStore { result.metric.node, result.metric.instance, result.metric.kubernetes_node, - ].includes(nodeName) + ].includes(nodeName); }); return result ? parseFloat(result.values.slice(-1)[0][1]) : 0; } catch (e) { @@ -68,5 +68,5 @@ export class NodesStore extends KubeObjectStore { } } -export const nodesStore = new NodesStore() +export const nodesStore = new NodesStore(); apiManager.registerStore(nodesStore); diff --git a/src/renderer/components/+nodes/nodes.tsx b/src/renderer/components/+nodes/nodes.tsx index 9e7c295f6c..82efc4ce92 100644 --- a/src/renderer/components/+nodes/nodes.tsx +++ b/src/renderer/components/+nodes/nodes.tsx @@ -60,7 +60,7 @@ export class Nodes extends React.Component { children: _i18n._(t`CPU:`) + ` ${Math.ceil(usage * 100) / cores}\%, ` + _i18n._(t`cores:`) + ` ${cores}` }} /> - ) + ); } renderMemoryUsage(node: Node) { @@ -77,7 +77,7 @@ export class Nodes extends React.Component { children: _i18n._(t`Memory:`) + ` ${Math.ceil(usage * 100 / capacity)}%, ${bytesToUnits(usage, 3)}` }} /> - ) + ); } renderDiskUsage(node: Node): any { @@ -94,17 +94,17 @@ export class Nodes extends React.Component { children: _i18n._(t`Disk:`) + ` ${Math.ceil(usage * 100 / capacity)}%, ${bytesToUnits(usage, 3)}` }} /> - ) + ); } renderConditions(node: Node) { if (!node.status.conditions) { - return null + return null; } const conditions = node.getActiveConditions(); return conditions.map(condition => { - const { type } = condition - const tooltipId = `node-${node.getName()}-condition-${type}` + const { type } = condition; + const tooltipId = `node-${node.getName()}-condition-${type}`; return ( {type} @@ -116,8 +116,8 @@ export class Nodes extends React.Component { )} - ) - }) + ); + }); } render() { @@ -177,10 +177,10 @@ export class Nodes extends React.Component { node.status.nodeInfo.kubeletVersion, node.getAge(), this.renderConditions(node), - ] + ]; }} /> - ) + ); } } diff --git a/src/renderer/components/+pod-security-policies/index.ts b/src/renderer/components/+pod-security-policies/index.ts index d9401de3c8..d037873b5b 100644 --- a/src/renderer/components/+pod-security-policies/index.ts +++ b/src/renderer/components/+pod-security-policies/index.ts @@ -1,3 +1,3 @@ -export * from "./pod-security-policies.route" -export * from "./pod-security-policies" -export * from "./pod-security-policy-details" \ No newline at end of file +export * from "./pod-security-policies.route"; +export * from "./pod-security-policies"; +export * from "./pod-security-policy-details"; \ No newline at end of file diff --git a/src/renderer/components/+pod-security-policies/pod-security-policies.route.ts b/src/renderer/components/+pod-security-policies/pod-security-policies.route.ts index e69f711bea..8bee44985e 100644 --- a/src/renderer/components/+pod-security-policies/pod-security-policies.route.ts +++ b/src/renderer/components/+pod-security-policies/pod-security-policies.route.ts @@ -3,6 +3,6 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const podSecurityPoliciesRoute: RouteProps = { path: "/pod-security-policies" -} +}; -export const podSecurityPoliciesURL = buildURL(podSecurityPoliciesRoute.path) +export const podSecurityPoliciesURL = buildURL(podSecurityPoliciesRoute.path); diff --git a/src/renderer/components/+pod-security-policies/pod-security-policies.store.ts b/src/renderer/components/+pod-security-policies/pod-security-policies.store.ts index 2517dcc59a..53ecde3d9d 100644 --- a/src/renderer/components/+pod-security-policies/pod-security-policies.store.ts +++ b/src/renderer/components/+pod-security-policies/pod-security-policies.store.ts @@ -5,8 +5,8 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class PodSecurityPoliciesStore extends KubeObjectStore { - api = pspApi + api = pspApi; } -export const podSecurityPoliciesStore = new PodSecurityPoliciesStore() +export const podSecurityPoliciesStore = new PodSecurityPoliciesStore(); apiManager.registerStore(podSecurityPoliciesStore); diff --git a/src/renderer/components/+pod-security-policies/pod-security-policies.tsx b/src/renderer/components/+pod-security-policies/pod-security-policies.tsx index 8ad6b77101..779a3a75ff 100644 --- a/src/renderer/components/+pod-security-policies/pod-security-policies.tsx +++ b/src/renderer/components/+pod-security-policies/pod-security-policies.tsx @@ -49,9 +49,9 @@ export class PodSecurityPolicies extends React.Component { item.isPrivileged() ? Yes : No, item.getVolumes().join(", "), item.getAge(), - ] + ]; }} /> - ) + ); } } diff --git a/src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx b/src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx index 2c50a4b668..5e0b812346 100644 --- a/src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx +++ b/src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx @@ -33,12 +33,12 @@ export class PodSecurityPolicyDetails extends React.Component { {ranges && ( Ranges (Min-Max)} labelsOnly> {ranges.map(({ min, max }, index) => { - return + return ; })} )} > - ) + ); } render() { @@ -137,7 +137,7 @@ export class PodSecurityPolicyDetails extends React.Component { {hostPorts && ( Host Ports (Min-Max)} labelsOnly> {hostPorts.map(({ min, max }, index) => { - return + return ; })} )} @@ -156,7 +156,7 @@ export class PodSecurityPolicyDetails extends React.Component { {pathPrefix} {readOnly ? Yes : No} - ) + ); })} > @@ -205,7 +205,7 @@ export class PodSecurityPolicyDetails extends React.Component { )} - ) + ); } } @@ -215,4 +215,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+preferences/index.tsx b/src/renderer/components/+preferences/index.tsx index b4d669a029..7b4ae710ae 100644 --- a/src/renderer/components/+preferences/index.tsx +++ b/src/renderer/components/+preferences/index.tsx @@ -1,2 +1,2 @@ -export * from "./preferences.route" -export * from "./preferences" +export * from "./preferences.route"; +export * from "./preferences"; diff --git a/src/renderer/components/+preferences/kubectl-binaries.tsx b/src/renderer/components/+preferences/kubectl-binaries.tsx index 002ddfdcc3..3b0b258ab4 100644 --- a/src/renderer/components/+preferences/kubectl-binaries.tsx +++ b/src/renderer/components/+preferences/kubectl-binaries.tsx @@ -16,12 +16,12 @@ export const KubectlBinaries = observer(({ preferences }: { preferences: UserPre const downloadMirrorOptions: SelectOption[] = [ { value: "default", label: "Default (Google)" }, { value: "china", label: "China (Azure)" }, - ] + ]; const save = () => { preferences.downloadBinariesPath = downloadPath; preferences.kubectlBinariesPath = binariesPath; - } + }; return ( <> diff --git a/src/renderer/components/+preferences/preferences.route.ts b/src/renderer/components/+preferences/preferences.route.ts index 8fc7e70b0e..7c880bd5fc 100644 --- a/src/renderer/components/+preferences/preferences.route.ts +++ b/src/renderer/components/+preferences/preferences.route.ts @@ -3,6 +3,6 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const preferencesRoute: RouteProps = { path: "/preferences" -} +}; -export const preferencesURL = buildURL(preferencesRoute.path) +export const preferencesURL = buildURL(preferencesRoute.path); diff --git a/src/renderer/components/+preferences/preferences.tsx b/src/renderer/components/+preferences/preferences.tsx index 2fc58646df..78f2896a73 100644 --- a/src/renderer/components/+preferences/preferences.tsx +++ b/src/renderer/components/+preferences/preferences.tsx @@ -1,4 +1,4 @@ -import "./preferences.scss" +import "./preferences.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -30,14 +30,14 @@ export class Preferences extends React.Component { return themeStore.themes.map(theme => ({ label: theme.name, value: theme.id, - })) + })); } @computed get helmOptions(): SelectOption[] { return this.helmRepos.map(repo => ({ label: repo.name, value: repo, - })) + })); } async componentDidMount() { @@ -65,7 +65,7 @@ export class Preferences extends React.Component { await repoManager.addRepo(repo); this.helmAddedRepos.set(repo.name, repo); } catch (err) { - Notifications.error(Adding helm branch {repo.name} has failed: {String(err)}) + Notifications.error(Adding helm branch {repo.name} has failed: {String(err)}); } } @@ -76,20 +76,20 @@ export class Preferences extends React.Component { } catch (err) { Notifications.error( Removing helm branch {repo.name} has failed: {String(err)} - ) + ); } } onRepoSelect = async ({ value: repo }: SelectOption) => { const isAdded = this.helmAddedRepos.has(repo.name); if (isAdded) { - Notifications.ok(Helm branch {repo.name} already in use) + Notifications.ok(Helm branch {repo.name} already in use); return; } this.helmLoading = true; await this.addRepo(repo); this.helmLoading = false; - } + }; formatHelmOptionLabel = ({ value: repo }: SelectOption) => { const isAdded = this.helmAddedRepos.has(repo.name); @@ -98,8 +98,8 @@ export class Preferences extends React.Component { {repo.name} {isAdded && } - ) - } + ); + }; render() { const { preferences } = userStore; @@ -152,7 +152,7 @@ export class Preferences extends React.Component { {repo.url} - ) + ); })} @@ -185,7 +185,7 @@ export class Preferences extends React.Component { - ) + ); })} diff --git a/src/renderer/components/+storage-classes/index.ts b/src/renderer/components/+storage-classes/index.ts index 923c64adc9..3a0b106256 100644 --- a/src/renderer/components/+storage-classes/index.ts +++ b/src/renderer/components/+storage-classes/index.ts @@ -1,4 +1,4 @@ -export * from "./storage-classes.route" -export * from "./storage-classes" -export * from "./storage-class-details" +export * from "./storage-classes.route"; +export * from "./storage-classes"; +export * from "./storage-class-details"; diff --git a/src/renderer/components/+storage-classes/storage-class-details.tsx b/src/renderer/components/+storage-classes/storage-class-details.tsx index 0edbc6426b..312e2d7ea3 100644 --- a/src/renderer/components/+storage-classes/storage-class-details.tsx +++ b/src/renderer/components/+storage-classes/storage-class-details.tsx @@ -66,7 +66,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "StorageClass", @@ -75,4 +75,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+storage-classes/storage-class.store.ts b/src/renderer/components/+storage-classes/storage-class.store.ts index 9ff90bc921..9e388456a5 100644 --- a/src/renderer/components/+storage-classes/storage-class.store.ts +++ b/src/renderer/components/+storage-classes/storage-class.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class StorageClassStore extends KubeObjectStore { - api = storageClassApi + api = storageClassApi; } export const storageClassStore = new StorageClassStore(); diff --git a/src/renderer/components/+storage-classes/storage-classes.route.ts b/src/renderer/components/+storage-classes/storage-classes.route.ts index 2f809ef9f3..c75d7dd0b8 100644 --- a/src/renderer/components/+storage-classes/storage-classes.route.ts +++ b/src/renderer/components/+storage-classes/storage-classes.route.ts @@ -3,10 +3,10 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const storageClassesRoute: RouteProps = { path: "/storage-classes" -} +}; export interface IStorageClassesRouteParams { } -export const storageClassesURL = buildURL(storageClassesRoute.path) +export const storageClassesURL = buildURL(storageClassesRoute.path); diff --git a/src/renderer/components/+storage-classes/storage-classes.tsx b/src/renderer/components/+storage-classes/storage-classes.tsx index f75b48d691..b4133c8918 100644 --- a/src/renderer/components/+storage-classes/storage-classes.tsx +++ b/src/renderer/components/+storage-classes/storage-classes.tsx @@ -1,4 +1,4 @@ -import "./storage-classes.scss" +import "./storage-classes.scss"; import React from "react"; import { RouteComponentProps } from "react-router-dom"; @@ -55,6 +55,6 @@ export class StorageClasses extends React.Component { storageClass.getAge(), ]} /> - ) + ); } } diff --git a/src/renderer/components/+storage-volume-claims/index.ts b/src/renderer/components/+storage-volume-claims/index.ts index 3a8d9949b2..4f9055c1d7 100644 --- a/src/renderer/components/+storage-volume-claims/index.ts +++ b/src/renderer/components/+storage-volume-claims/index.ts @@ -1,4 +1,4 @@ -export * from "./volume-claims.route" -export * from "./volume-claims" -export * from "./volume-claim-details" +export * from "./volume-claims.route"; +export * from "./volume-claims"; +export * from "./volume-claim-details"; diff --git a/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx b/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx index c75251884d..5df839c979 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx +++ b/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx @@ -1,4 +1,4 @@ -import "./volume-claim-details.scss" +import "./volume-claim-details.scss"; import React, { Fragment } from "react"; import { reaction } from "mobx"; @@ -99,7 +99,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "PersistentVolumeClaim", @@ -108,4 +108,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx b/src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx index 112ec5c268..3b727f36eb 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx +++ b/src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx @@ -38,7 +38,7 @@ export const VolumeClaimDiskChart = observer(() => { borderColor: chartCapacityColor, data: capacity.map(([x, y]) => ({ x, y })) } - ] + ]; return ( { - api = pvcApi + api = pvcApi; @observable metrics: IPvcMetrics = null; @action diff --git a/src/renderer/components/+storage-volume-claims/volume-claims.route.ts b/src/renderer/components/+storage-volume-claims/volume-claims.route.ts index b579623369..0e49681bc3 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claims.route.ts +++ b/src/renderer/components/+storage-volume-claims/volume-claims.route.ts @@ -3,9 +3,9 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const volumeClaimsRoute: RouteProps = { path: "/persistent-volume-claims" -} +}; export interface IVolumeClaimsRouteParams { } -export const volumeClaimsURL = buildURL(volumeClaimsRoute.path) +export const volumeClaimsURL = buildURL(volumeClaimsRoute.path); diff --git a/src/renderer/components/+storage-volume-claims/volume-claims.tsx b/src/renderer/components/+storage-volume-claims/volume-claims.tsx index e0e789a2e5..84e8b9dd92 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claims.tsx +++ b/src/renderer/components/+storage-volume-claims/volume-claims.tsx @@ -1,4 +1,4 @@ -import "./volume-claims.scss" +import "./volume-claims.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -81,9 +81,9 @@ export class PersistentVolumeClaims extends React.Component { )), pvc.getAge(), { title: pvc.getStatus(), className: pvc.getStatus().toLowerCase() }, - ] + ]; }} /> - ) + ); } } diff --git a/src/renderer/components/+storage-volumes/index.ts b/src/renderer/components/+storage-volumes/index.ts index 743de7af98..895ab6444a 100644 --- a/src/renderer/components/+storage-volumes/index.ts +++ b/src/renderer/components/+storage-volumes/index.ts @@ -1,3 +1,3 @@ -export * from "./volumes.route" -export * from "./volumes" -export * from "./volume-details" +export * from "./volumes.route"; +export * from "./volumes"; +export * from "./volume-details"; diff --git a/src/renderer/components/+storage-volumes/volume-details.tsx b/src/renderer/components/+storage-volumes/volume-details.tsx index 0cbb6d3ddc..93ede8d04d 100644 --- a/src/renderer/components/+storage-volumes/volume-details.tsx +++ b/src/renderer/components/+storage-volumes/volume-details.tsx @@ -1,5 +1,5 @@ -import startCase from "lodash/startCase" -import "./volume-details.scss" +import startCase from "lodash/startCase"; +import "./volume-details.scss"; import React from "react"; import { Trans } from "@lingui/macro"; @@ -107,7 +107,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "PersistentVolume", @@ -116,4 +116,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+storage-volumes/volumes.route.ts b/src/renderer/components/+storage-volumes/volumes.route.ts index 42d4824c99..596f51f23e 100644 --- a/src/renderer/components/+storage-volumes/volumes.route.ts +++ b/src/renderer/components/+storage-volumes/volumes.route.ts @@ -3,7 +3,7 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const volumesRoute: RouteProps = { path: "/persistent-volumes" -} +}; export interface IVolumesRouteParams { } diff --git a/src/renderer/components/+storage-volumes/volumes.store.ts b/src/renderer/components/+storage-volumes/volumes.store.ts index f065c562c9..ea61525735 100644 --- a/src/renderer/components/+storage-volumes/volumes.store.ts +++ b/src/renderer/components/+storage-volumes/volumes.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class PersistentVolumesStore extends KubeObjectStore { - api = persistentVolumeApi + api = persistentVolumeApi; } export const volumesStore = new PersistentVolumesStore(); diff --git a/src/renderer/components/+storage-volumes/volumes.tsx b/src/renderer/components/+storage-volumes/volumes.tsx index c3b01e0b93..d67a9a9b09 100644 --- a/src/renderer/components/+storage-volumes/volumes.tsx +++ b/src/renderer/components/+storage-volumes/volumes.tsx @@ -1,4 +1,4 @@ -import "./volumes.scss" +import "./volumes.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -71,9 +71,9 @@ export class PersistentVolumes extends React.Component { ), volume.getAge(), { title: volume.getStatus(), className: volume.getStatus().toLowerCase() } - ] + ]; }} /> - ) + ); } } diff --git a/src/renderer/components/+storage/index.ts b/src/renderer/components/+storage/index.ts index eb218e9174..58bae55b33 100644 --- a/src/renderer/components/+storage/index.ts +++ b/src/renderer/components/+storage/index.ts @@ -1,2 +1,2 @@ -export * from "./storage.route" -export * from "./storage" +export * from "./storage.route"; +export * from "./storage"; diff --git a/src/renderer/components/+storage/storage.route.ts b/src/renderer/components/+storage/storage.route.ts index 6fe3bb6a0a..6ad17a4fdf 100644 --- a/src/renderer/components/+storage/storage.route.ts +++ b/src/renderer/components/+storage/storage.route.ts @@ -1,12 +1,12 @@ -import { RouteProps } from "react-router" +import { RouteProps } from "react-router"; import { volumeClaimsURL } from "../+storage-volume-claims"; import { Storage } from "./storage"; import { IURLParams } from "../../../common/utils/buildUrl"; export const storageRoute: RouteProps = { get path() { - return Storage.tabRoutes.map(({ routePath }) => routePath).flat() + return Storage.tabRoutes.map(({ routePath }) => routePath).flat(); } -} +}; export const storageURL = (params?: IURLParams) => volumeClaimsURL(params); diff --git a/src/renderer/components/+storage/storage.tsx b/src/renderer/components/+storage/storage.tsx index e8a105944b..97bd014760 100644 --- a/src/renderer/components/+storage/storage.tsx +++ b/src/renderer/components/+storage/storage.tsx @@ -1,4 +1,4 @@ -import "./storage.scss" +import "./storage.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -14,14 +14,14 @@ import { isAllowedResource } from "../../../common/rbac"; export class Storage extends React.Component { static get tabRoutes() { const tabRoutes: TabLayoutRoute[] = []; - const query = namespaceStore.getContextParams() + const query = namespaceStore.getContextParams(); tabRoutes.push({ title: Persistent Volume Claims, component: PersistentVolumeClaims, url: volumeClaimsURL({ query }), routePath: volumeClaimsRoute.path.toString(), - }) + }); if (isAllowedResource('persistentvolumes')) { tabRoutes.push({ @@ -38,7 +38,7 @@ export class Storage extends React.Component { component: StorageClasses, url: storageClassesURL(), routePath: storageClassesRoute.path.toString(), - }) + }); } return tabRoutes; } @@ -46,6 +46,6 @@ export class Storage extends React.Component { render() { return ( - ) + ); } } diff --git a/src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx b/src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx index 4225d7b96f..227b2d936e 100644 --- a/src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx +++ b/src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx @@ -1,4 +1,4 @@ -import "./add-role-binding-dialog.scss" +import "./add-role-binding-dialog.scss"; import React from "react"; import { computed, observable } from "mobx"; @@ -67,12 +67,12 @@ export class AddRoleBindingDialog extends React.Component { @computed get selectedBindings() { return [ ...this.selectedAccounts, - ] + ]; } close = () => { AddRoleBindingDialog.close(); - } + }; async loadData() { const stores = [ @@ -96,13 +96,13 @@ export class AddRoleBindingDialog extends React.Component { this.bindContext = role.getNs() || ""; } } - } + }; reset = () => { this.selectedRoleId = ""; this.bindContext = ""; this.selectedAccounts.clear(); - } + }; onBindContextChange = (namespace: string) => { this.bindContext = namespace; @@ -110,7 +110,7 @@ export class AddRoleBindingDialog extends React.Component { if (this.bindContext && this.bindContext !== roleContext) { this.selectedRoleId = ""; // reset previously selected role for specific context } - } + }; createBindings = async () => { const { selectedRole, bindContext: namespace, selectedBindings, bindingName, useRoleForBindingName } = this; @@ -121,7 +121,7 @@ export class AddRoleBindingDialog extends React.Component { name: item.getName(), kind: item.kind, namespace: item.getNs(), - } + }; } return item; }); @@ -152,7 +152,7 @@ export class AddRoleBindingDialog extends React.Component { }; @computed get roleOptions(): BindingSelectOption[] { - let roles = rolesStore.items as Role[] + let roles = rolesStore.items as Role[]; if (this.bindContext) { // show only cluster-roles or roles for selected context namespace roles = roles.filter(role => !role.getNs() || role.getNs() === this.bindContext); @@ -163,8 +163,8 @@ export class AddRoleBindingDialog extends React.Component { return { value: role.getId(), label: name + (namespace ? ` (${namespace})` : "") - } - }) + }; + }); } @computed get serviceAccountOptions(): BindingSelectOption[] { @@ -175,8 +175,8 @@ export class AddRoleBindingDialog extends React.Component { item: account, value: name, label: <> {name} ({namespace})> - } - }) + }; + }); } renderContents() { @@ -240,7 +240,7 @@ export class AddRoleBindingDialog extends React.Component { maxMenuHeight={200} /> > - ) + ); } render() { @@ -275,6 +275,6 @@ export class AddRoleBindingDialog extends React.Component { - ) + ); } } diff --git a/src/renderer/components/+user-management-roles-bindings/index.ts b/src/renderer/components/+user-management-roles-bindings/index.ts index ca90adf052..cb69a92323 100644 --- a/src/renderer/components/+user-management-roles-bindings/index.ts +++ b/src/renderer/components/+user-management-roles-bindings/index.ts @@ -1,3 +1,3 @@ -export * from "./role-bindings" -export * from "./role-binding-details" -export * from "./add-role-binding-dialog" +export * from "./role-bindings"; +export * from "./role-binding-details"; +export * from "./add-role-binding-dialog"; diff --git a/src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx b/src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx index afa1d1e43c..178aada344 100644 --- a/src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx +++ b/src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx @@ -1,4 +1,4 @@ -import "./role-binding-details.scss" +import "./role-binding-details.scss"; import React from "react"; import { t, Trans } from "@lingui/macro"; @@ -30,7 +30,7 @@ export class RoleBindingDetails extends React.Component { reaction(() => this.props.object, (obj) => { this.selectedSubjects.clear(); }) - ]) + ]); } selectSubject(subject: IRoleBindingSubject) { @@ -40,7 +40,7 @@ export class RoleBindingDetails extends React.Component { isSelected ? selectedSubjects.filter(sub => sub !== subject) // unselect : selectedSubjects.concat(subject) // select - ) + ); } @autobind() @@ -53,7 +53,7 @@ export class RoleBindingDetails extends React.Component { message: ( Remove selected bindings for {roleBinding.getName()}? ) - }) + }); } render() { @@ -106,7 +106,7 @@ export class RoleBindingDetails extends React.Component { {kind} {namespace || "-"} - ) + ); }) } @@ -119,7 +119,7 @@ export class RoleBindingDetails extends React.Component { removeTooltip={Remove selected bindings from ${name}} /> - ) + ); } } @@ -129,7 +129,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "RoleBinding", apiVersions: ["rbac.authorization.k8s.io/v1"], @@ -137,7 +137,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ @@ -146,7 +146,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "ClusterRoleBinding", apiVersions: ["rbac.authorization.k8s.io/v1"], @@ -154,4 +154,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+user-management-roles-bindings/role-bindings.store.ts b/src/renderer/components/+user-management-roles-bindings/role-bindings.store.ts index bbef0ebd31..ed3e1c0a4f 100644 --- a/src/renderer/components/+user-management-roles-bindings/role-bindings.store.ts +++ b/src/renderer/components/+user-management-roles-bindings/role-bindings.store.ts @@ -1,5 +1,5 @@ -import difference from "lodash/difference" -import uniqBy from "lodash/uniqBy" +import difference from "lodash/difference"; +import uniqBy from "lodash/uniqBy"; import { clusterRoleBindingApi, IRoleBindingSubject, RoleBinding, roleBindingApi } from "../../api/endpoints"; import { KubeObjectStore } from "../../kube-object.store"; import { autobind } from "../../utils"; @@ -7,40 +7,40 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class RoleBindingsStore extends KubeObjectStore { - api = clusterRoleBindingApi + api = clusterRoleBindingApi; subscribe() { - return super.subscribe([clusterRoleBindingApi, roleBindingApi]) + return super.subscribe([clusterRoleBindingApi, roleBindingApi]); } protected sortItems(items: RoleBinding[]) { return super.sortItems(items, [ roleBinding => roleBinding.kind, roleBinding => roleBinding.getName() - ]) + ]); } protected loadItem(params: { name: string; namespace?: string }) { - if (params.namespace) return roleBindingApi.get(params) - return clusterRoleBindingApi.get(params) + if (params.namespace) return roleBindingApi.get(params); + return clusterRoleBindingApi.get(params); } protected loadItems(namespaces?: string[]) { if (namespaces) { return Promise.all( namespaces.map(namespace => roleBindingApi.list({ namespace })) - ).then(items => items.flat()) + ).then(items => items.flat()); } else { return Promise.all([clusterRoleBindingApi.list(), roleBindingApi.list()]) - .then(items => items.flat()) + .then(items => items.flat()); } } protected async createItem(params: { name: string; namespace?: string }, data?: Partial) { if (params.namespace) { - return roleBindingApi.create(params, data) + return roleBindingApi.create(params, data); } else { - return clusterRoleBindingApi.create(params, data) + return clusterRoleBindingApi.create(params, data); } } @@ -55,7 +55,7 @@ export class RoleBindingsStore extends KubeObjectStore { if (addSubjects) { newSubjects = uniqBy(currentSubjects.concat(addSubjects), ({ kind, name, namespace }) => { return [kind, name, namespace].join("-"); - }) + }); } else if (removeSubjects) { newSubjects = difference(currentSubjects, removeSubjects); } diff --git a/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx b/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx index cb010a3c1b..7d9352e3bf 100644 --- a/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx +++ b/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx @@ -1,4 +1,4 @@ -import "./role-bindings.scss" +import "./role-bindings.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -58,6 +58,6 @@ export class RoleBindings extends React.Component { addTooltip: Create new RoleBinding, }} /> - ) + ); } } diff --git a/src/renderer/components/+user-management-roles/add-role-dialog.tsx b/src/renderer/components/+user-management-roles/add-role-dialog.tsx index 177386f72d..56766c816d 100644 --- a/src/renderer/components/+user-management-roles/add-role-dialog.tsx +++ b/src/renderer/components/+user-management-roles/add-role-dialog.tsx @@ -1,4 +1,4 @@ -import "./add-role-dialog.scss" +import "./add-role-dialog.scss"; import React from "react"; import { observable } from "mobx"; @@ -31,11 +31,11 @@ export class AddRoleDialog extends React.Component { close = () => { AddRoleDialog.close(); - } + }; reset = () => { - this.roleName = "" - } + this.roleName = ""; + }; createRole = async () => { try { @@ -46,7 +46,7 @@ export class AddRoleDialog extends React.Component { } catch (err) { Notifications.error(err.toString()); } - } + }; render() { const { ...dialogProps } = this.props; @@ -74,6 +74,6 @@ export class AddRoleDialog extends React.Component { - ) + ); } } diff --git a/src/renderer/components/+user-management-roles/index.ts b/src/renderer/components/+user-management-roles/index.ts index dd5752f4be..26eaea3b7f 100644 --- a/src/renderer/components/+user-management-roles/index.ts +++ b/src/renderer/components/+user-management-roles/index.ts @@ -1,3 +1,3 @@ -export * from "./roles" -export * from "./role-details" -export * from "./add-role-dialog" +export * from "./roles"; +export * from "./role-details"; +export * from "./add-role-dialog"; diff --git a/src/renderer/components/+user-management-roles/role-details.tsx b/src/renderer/components/+user-management-roles/role-details.tsx index fccc79eb9d..e69e6c46d7 100644 --- a/src/renderer/components/+user-management-roles/role-details.tsx +++ b/src/renderer/components/+user-management-roles/role-details.tsx @@ -1,4 +1,4 @@ -import "./role-details.scss" +import "./role-details.scss"; import React from "react"; import { Trans } from "@lingui/macro"; @@ -57,10 +57,10 @@ export class RoleDetails extends React.Component { > )} - ) + ); })} - ) + ); } } @@ -70,7 +70,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "Role", apiVersions: ["rbac.authorization.k8s.io/v1"], @@ -78,7 +78,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "ClusterRole", @@ -86,7 +86,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "ClusterRole", apiVersions: ["rbac.authorization.k8s.io/v1"], @@ -94,4 +94,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+user-management-roles/roles.store.ts b/src/renderer/components/+user-management-roles/roles.store.ts index e41171ee0c..d3f17e520c 100644 --- a/src/renderer/components/+user-management-roles/roles.store.ts +++ b/src/renderer/components/+user-management-roles/roles.store.ts @@ -5,40 +5,40 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class RolesStore extends KubeObjectStore { - api = clusterRoleApi + api = clusterRoleApi; subscribe() { - return super.subscribe([roleApi, clusterRoleApi]) + return super.subscribe([roleApi, clusterRoleApi]); } protected sortItems(items: Role[]) { return super.sortItems(items, [ role => role.kind, role => role.getName(), - ]) + ]); } protected loadItem(params: { name: string; namespace?: string }) { - if (params.namespace) return roleApi.get(params) - return clusterRoleApi.get(params) + if (params.namespace) return roleApi.get(params); + return clusterRoleApi.get(params); } protected loadItems(namespaces?: string[]): Promise { if (namespaces) { return Promise.all( namespaces.map(namespace => roleApi.list({ namespace })) - ).then(items => items.flat()) + ).then(items => items.flat()); } else { return Promise.all([clusterRoleApi.list(), roleApi.list()]) - .then(items => items.flat()) + .then(items => items.flat()); } } protected async createItem(params: { name: string; namespace?: string }, data?: Partial) { if (params.namespace) { - return roleApi.create(params, data) + return roleApi.create(params, data); } else { - return clusterRoleApi.create(params, data) + return clusterRoleApi.create(params, data); } } } diff --git a/src/renderer/components/+user-management-roles/roles.tsx b/src/renderer/components/+user-management-roles/roles.tsx index ca78c1d5d7..015ec2d630 100644 --- a/src/renderer/components/+user-management-roles/roles.tsx +++ b/src/renderer/components/+user-management-roles/roles.tsx @@ -1,4 +1,4 @@ -import "./roles.scss" +import "./roles.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -56,6 +56,6 @@ export class Roles extends React.Component { /> > - ) + ); } } diff --git a/src/renderer/components/+user-management-service-accounts/create-service-account-dialog.tsx b/src/renderer/components/+user-management-service-accounts/create-service-account-dialog.tsx index d84cc01e59..ce677c3353 100644 --- a/src/renderer/components/+user-management-service-accounts/create-service-account-dialog.tsx +++ b/src/renderer/components/+user-management-service-accounts/create-service-account-dialog.tsx @@ -22,8 +22,8 @@ interface Props extends Partial { export class CreateServiceAccountDialog extends React.Component { @observable static isOpen = false; - @observable name = "" - @observable namespace = "default" + @observable name = ""; + @observable namespace = "default"; static open() { CreateServiceAccountDialog.isOpen = true; @@ -35,7 +35,7 @@ export class CreateServiceAccountDialog extends React.Component { close = () => { CreateServiceAccountDialog.close(); - } + }; createAccount = async () => { const { name, namespace } = this; @@ -47,12 +47,12 @@ export class CreateServiceAccountDialog extends React.Component { } catch (err) { Notifications.error(err); } - } + }; render() { const { ...dialogProps } = this.props; const { name, namespace } = this; - const header = Create Service Account + const header = Create Service Account; return ( { - ) + ); } } \ No newline at end of file diff --git a/src/renderer/components/+user-management-service-accounts/index.ts b/src/renderer/components/+user-management-service-accounts/index.ts index fb40e7e15e..fd45e28288 100644 --- a/src/renderer/components/+user-management-service-accounts/index.ts +++ b/src/renderer/components/+user-management-service-accounts/index.ts @@ -1,3 +1,3 @@ -export * from "./service-accounts" -export * from "./service-accounts-details" -export * from "./create-service-account-dialog" \ No newline at end of file +export * from "./service-accounts"; +export * from "./service-accounts-details"; +export * from "./create-service-account-dialog"; \ No newline at end of file diff --git a/src/renderer/components/+user-management-service-accounts/service-accounts-details.tsx b/src/renderer/components/+user-management-service-accounts/service-accounts-details.tsx index 357baee9eb..d560cd9199 100644 --- a/src/renderer/components/+user-management-service-accounts/service-accounts-details.tsx +++ b/src/renderer/components/+user-management-service-accounts/service-accounts-details.tsx @@ -39,27 +39,27 @@ export class ServiceAccountsDetails extends React.Component { }); this.secrets = await Promise.all(secrets); const imagePullSecrets = serviceAccount.getImagePullSecrets().map(async({ name }) => { - return secretsStore.load({ name, namespace }).catch(_err => { return this.generateDummySecretObject(name) }); + return secretsStore.load({ name, namespace }).catch(_err => { return this.generateDummySecretObject(name); }); }); - this.imagePullSecrets = await Promise.all(imagePullSecrets) - }) + this.imagePullSecrets = await Promise.all(imagePullSecrets); + }); renderSecrets() { const { secrets } = this; if (!secrets) { - return + return ; } return secrets.map(secret => - ) + ); } renderImagePullSecrets() { const { imagePullSecrets } = this; if (!imagePullSecrets) { - return + return ; } - return this.renderSecretLinks(imagePullSecrets) + return this.renderSecretLinks(imagePullSecrets); } renderSecretLinks(secrets: Secret[]) { @@ -73,14 +73,14 @@ export class ServiceAccountsDetails extends React.Component { tooltip={Secret is not found} /> - ) + ); } return ( {secret.getName()} - ) - }) + ); + }); } generateDummySecretObject(name: string) { @@ -93,7 +93,7 @@ export class ServiceAccountsDetails extends React.Component { selfLink: null, resourceVersion: null } - }) + }); } render() { @@ -104,8 +104,8 @@ export class ServiceAccountsDetails extends React.Component { const tokens = secretsStore.items.filter(secret => secret.getNs() == serviceAccount.getNs() && secret.getAnnotations().some(annot => annot == `kubernetes.io/service-account.name: ${serviceAccount.getName()}`) - ) - const imagePullSecrets = serviceAccount.getImagePullSecrets() + ); + const imagePullSecrets = serviceAccount.getImagePullSecrets(); return ( @@ -126,7 +126,7 @@ export class ServiceAccountsDetails extends React.Component { {this.renderSecrets()} - ) + ); } } @@ -136,7 +136,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "ServiceAccount", apiVersions: ["v1"], @@ -144,4 +144,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+user-management-service-accounts/service-accounts-secret.tsx b/src/renderer/components/+user-management-service-accounts/service-accounts-secret.tsx index bc75d103f7..ad3eec3d2e 100644 --- a/src/renderer/components/+user-management-service-accounts/service-accounts-secret.tsx +++ b/src/renderer/components/+user-management-service-accounts/service-accounts-secret.tsx @@ -1,4 +1,4 @@ -import "./service-accounts-secret.scss" +import "./service-accounts-secret.scss"; import React from "react"; import moment from "moment"; @@ -18,11 +18,11 @@ interface State { export class ServiceAccountsSecret extends React.Component { public state: State = { showToken: false, - } + }; renderSecretValue() { - const { secret } = this.props - const { showToken } = this.state + const { secret } = this.props; + const { showToken } = this.state; return ( <> {!showToken && ( @@ -39,7 +39,7 @@ export class ServiceAccountsSecret extends React.Component { {secret.getToken()} )} > - ) + ); } render() { @@ -65,6 +65,6 @@ export class ServiceAccountsSecret extends React.Component { {type} - ) + ); } } \ No newline at end of file diff --git a/src/renderer/components/+user-management-service-accounts/service-accounts.store.ts b/src/renderer/components/+user-management-service-accounts/service-accounts.store.ts index ff958567ae..1d3faa6b1c 100644 --- a/src/renderer/components/+user-management-service-accounts/service-accounts.store.ts +++ b/src/renderer/components/+user-management-service-accounts/service-accounts.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class ServiceAccountsStore extends KubeObjectStore { - api = serviceAccountsApi + api = serviceAccountsApi; protected async createItem(params: { name: string; namespace?: string }) { await super.createItem(params); diff --git a/src/renderer/components/+user-management-service-accounts/service-accounts.tsx b/src/renderer/components/+user-management-service-accounts/service-accounts.tsx index 0455a5cdc0..d612dd2376 100644 --- a/src/renderer/components/+user-management-service-accounts/service-accounts.tsx +++ b/src/renderer/components/+user-management-service-accounts/service-accounts.tsx @@ -54,7 +54,7 @@ export class ServiceAccounts extends React.Component { account.getAge(), ]} renderItemMenu={(item: ServiceAccount) => { - return + return ; }} addRemoveButtons={{ onAdd: () => CreateServiceAccountDialog.open(), @@ -63,7 +63,7 @@ export class ServiceAccounts extends React.Component { /> > - ) + ); } } @@ -74,7 +74,7 @@ function ServiceAccountMenu(props: KubeObjectMenuProps) { Kubeconfig - ) + ); } kubeObjectMenuRegistry.add({ @@ -83,4 +83,4 @@ kubeObjectMenuRegistry.add({ components: { MenuItem: ServiceAccountMenu } -}) +}); diff --git a/src/renderer/components/+user-management/index.ts b/src/renderer/components/+user-management/index.ts index 8250079e60..6f29869b9b 100644 --- a/src/renderer/components/+user-management/index.ts +++ b/src/renderer/components/+user-management/index.ts @@ -1,2 +1,2 @@ -export * from "./user-management" -export * from "./user-management.route" \ No newline at end of file +export * from "./user-management"; +export * from "./user-management.route"; \ No newline at end of file diff --git a/src/renderer/components/+user-management/user-management.route.ts b/src/renderer/components/+user-management/user-management.route.ts index aa520fb128..9dc17cbbd8 100644 --- a/src/renderer/components/+user-management/user-management.route.ts +++ b/src/renderer/components/+user-management/user-management.route.ts @@ -1,23 +1,23 @@ import type { RouteProps } from "react-router"; import { buildURL, IURLParams } from "../../../common/utils/buildUrl"; -import { UserManagement } from "./user-management" +import { UserManagement } from "./user-management"; export const usersManagementRoute: RouteProps = { get path() { - return UserManagement.tabRoutes.map(({ routePath }) => routePath).flat() + return UserManagement.tabRoutes.map(({ routePath }) => routePath).flat(); } -} +}; // Routes export const serviceAccountsRoute: RouteProps = { path: "/service-accounts" -} +}; export const rolesRoute: RouteProps = { path: "/roles" -} +}; export const roleBindingsRoute: RouteProps = { path: "/role-bindings" -} +}; // Route params export interface IServiceAccountsRouteParams { @@ -31,6 +31,6 @@ export interface IRolesRouteParams { // URL-builders export const usersManagementURL = (params?: IURLParams) => serviceAccountsURL(params); -export const serviceAccountsURL = buildURL(serviceAccountsRoute.path) -export const roleBindingsURL = buildURL(roleBindingsRoute.path) -export const rolesURL = buildURL(rolesRoute.path) +export const serviceAccountsURL = buildURL(serviceAccountsRoute.path); +export const roleBindingsURL = buildURL(roleBindingsRoute.path); +export const rolesURL = buildURL(rolesRoute.path); diff --git a/src/renderer/components/+user-management/user-management.tsx b/src/renderer/components/+user-management/user-management.tsx index e7985fae6a..9c03390656 100644 --- a/src/renderer/components/+user-management/user-management.tsx +++ b/src/renderer/components/+user-management/user-management.tsx @@ -1,4 +1,4 @@ -import "./user-management.scss" +import "./user-management.scss"; import React from "react"; import { observer } from "mobx-react"; import { Trans } from "@lingui/macro"; @@ -15,7 +15,7 @@ import { isAllowedResource } from "../../../common/rbac"; export class UserManagement extends React.Component { static get tabRoutes() { const tabRoutes: TabLayoutRoute[] = []; - const query = namespaceStore.getContextParams() + const query = namespaceStore.getContextParams(); tabRoutes.push( { title: Service Accounts, @@ -35,14 +35,14 @@ export class UserManagement extends React.Component { url: rolesURL({ query }), routePath: rolesRoute.path.toString(), }, - ) + ); if (isAllowedResource("podsecuritypolicies")) { tabRoutes.push({ title: Pod Security Policies, component: PodSecurityPolicies, url: podSecurityPoliciesURL(), routePath: podSecurityPoliciesRoute.path.toString(), - }) + }); } return tabRoutes; } @@ -50,6 +50,6 @@ export class UserManagement extends React.Component { render() { return ( - ) + ); } } diff --git a/src/renderer/components/+whats-new/index.tsx b/src/renderer/components/+whats-new/index.tsx index 9f46112328..ebfdf6ff1b 100644 --- a/src/renderer/components/+whats-new/index.tsx +++ b/src/renderer/components/+whats-new/index.tsx @@ -1,2 +1,2 @@ -export * from "./whats-new.route" -export * from "./whats-new" +export * from "./whats-new.route"; +export * from "./whats-new"; diff --git a/src/renderer/components/+whats-new/whats-new.route.ts b/src/renderer/components/+whats-new/whats-new.route.ts index f989d676b7..e73fd20fca 100644 --- a/src/renderer/components/+whats-new/whats-new.route.ts +++ b/src/renderer/components/+whats-new/whats-new.route.ts @@ -3,6 +3,6 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const whatsNewRoute: RouteProps = { path: "/what-s-new" -} +}; -export const whatsNewURL = buildURL(whatsNewRoute.path) +export const whatsNewURL = buildURL(whatsNewRoute.path); diff --git a/src/renderer/components/+whats-new/whats-new.tsx b/src/renderer/components/+whats-new/whats-new.tsx index c63e8f25d1..9b0df95d70 100644 --- a/src/renderer/components/+whats-new/whats-new.tsx +++ b/src/renderer/components/+whats-new/whats-new.tsx @@ -1,13 +1,13 @@ -import "./whats-new.scss" +import "./whats-new.scss"; import fs from "fs"; import path from "path"; import React from "react"; import { observer } from "mobx-react"; -import { userStore } from "../../../common/user-store" +import { userStore } from "../../../common/user-store"; import { navigate } from "../../navigation"; import { Button } from "../button"; import { Trans } from "@lingui/macro"; -import marked from "marked" +import marked from "marked"; @observer export class WhatsNew extends React.Component { @@ -16,7 +16,7 @@ export class WhatsNew extends React.Component { ok = () => { navigate("/"); userStore.saveLastSeenAppVersion(); - } + }; render() { const logo = require("../../components/icon/lens-logo.svg"); diff --git a/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx b/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx index b540b6e8a6..cd8e038d90 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx @@ -30,7 +30,7 @@ export class CronJobDetails extends React.Component { render() { const { object: cronJob } = this.props; if (!cronJob) return null; - const childJobs = jobStore.getJobsByOwner(cronJob) + const childJobs = jobStore.getJobsByOwner(cronJob); return ( @@ -54,8 +54,8 @@ export class CronJobDetails extends React.Component { <> Jobs}/> {childJobs.map((job: Job) => { - const selectors = job.getSelectors() - const condition = job.getCondition() + const selectors = job.getSelectors(); + const condition = job.getCondition(); return ( @@ -77,12 +77,12 @@ export class CronJobDetails extends React.Component { } - )}) + );}) } > } - ) + ); } } @@ -92,7 +92,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "CronJob", apiVersions: ["batch/v1"], @@ -100,4 +100,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx b/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx index 8fa77bd194..5dda5989ae 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx @@ -39,18 +39,18 @@ export class CronJobTriggerDialog extends Component { close = () => { CronJobTriggerDialog.close(); - } + }; onOpen = async () => { const { cronjob } = this; this.jobName = cronjob ? cronjob.getName() + "-manual-" + Math.random().toString(36).slice(2, 7) : ""; this.jobName = this.jobName.slice(0, 63); this.ready = true; - } + }; onClose = () => { this.ready = false; - } + }; trigger = async () => { const { cronjob } = this; @@ -72,7 +72,7 @@ export class CronJobTriggerDialog extends Component { } catch (err) { Notifications.error(err); } - } + }; renderContents() { return ( @@ -91,7 +91,7 @@ export class CronJobTriggerDialog extends Component { /> > - ) + ); } render() { diff --git a/src/renderer/components/+workloads-cronjobs/cronjob.store.ts b/src/renderer/components/+workloads-cronjobs/cronjob.store.ts index b1370d2104..30915f733c 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjob.store.ts +++ b/src/renderer/components/+workloads-cronjobs/cronjob.store.ts @@ -6,19 +6,19 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class CronJobStore extends KubeObjectStore { - api = cronJobApi + api = cronJobApi; getStatuses(cronJobs?: CronJob[]) { - const status = { suspended: 0, scheduled: 0 } + const status = { suspended: 0, scheduled: 0 }; cronJobs.forEach(cronJob => { if (cronJob.spec.suspend) { - status.suspended++ + status.suspended++; } else { - status.scheduled++ + status.scheduled++; } - }) - return status + }); + return status; } getActiveJobsNum(cronJob: CronJob) { diff --git a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx index ab7609de81..b5cf6d328f 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx @@ -71,10 +71,10 @@ export class CronJobs extends React.Component { cronJob.getAge(), ]} renderItemMenu={(item: CronJob) => { - return + return ; }} /> - ) + ); } } @@ -85,7 +85,7 @@ export function CronJobMenu(props: KubeObjectMenuProps) { Trigger - ) + ); } kubeObjectMenuRegistry.add({ @@ -94,4 +94,4 @@ kubeObjectMenuRegistry.add({ components: { MenuItem: CronJobMenu } -}) +}); diff --git a/src/renderer/components/+workloads-cronjobs/index.ts b/src/renderer/components/+workloads-cronjobs/index.ts index 71c59dcfee..3884050448 100644 --- a/src/renderer/components/+workloads-cronjobs/index.ts +++ b/src/renderer/components/+workloads-cronjobs/index.ts @@ -1,2 +1,2 @@ -export * from "./cronjobs" -export * from "./cronjob-details" +export * from "./cronjobs"; +export * from "./cronjob-details"; diff --git a/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx b/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx index c234fc841c..9d678c8adf 100644 --- a/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx +++ b/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx @@ -43,12 +43,12 @@ export class DaemonSetDetails extends React.Component { render() { const { object: daemonSet } = this.props; if (!daemonSet) return null; - const { spec } = daemonSet + const { spec } = daemonSet; const selectors = daemonSet.getSelectors(); - const images = daemonSet.getImages() - const nodeSelector = daemonSet.getNodeSelectors() - const childPods = daemonSetStore.getChildPods(daemonSet) - const metrics = daemonSetStore.metrics + const images = daemonSet.getImages(); + const nodeSelector = daemonSet.getNodeSelectors(); + const childPods = daemonSetStore.getChildPods(daemonSet); + const metrics = daemonSetStore.metrics; return ( {podsStore.isLoaded && ( @@ -92,7 +92,7 @@ export class DaemonSetDetails extends React.Component {
(pageId?: string, params?: P, frameId?: number) { const windowManager = WindowManager.getInstance(); diff --git a/src/extensions/lens-renderer-extension.ts b/src/extensions/lens-renderer-extension.ts index 0fb346e1a1..56ed90684f 100644 --- a/src/extensions/lens-renderer-extension.ts +++ b/src/extensions/lens-renderer-extension.ts @@ -1,19 +1,19 @@ -import type { AppPreferenceRegistration, ClusterFeatureRegistration, KubeObjectDetailRegistration, KubeObjectMenuRegistration, KubeObjectStatusRegistration, PageMenuRegistration, PageRegistration, StatusBarRegistration, } from "./registries" +import type { AppPreferenceRegistration, ClusterFeatureRegistration, KubeObjectDetailRegistration, KubeObjectMenuRegistration, KubeObjectStatusRegistration, PageMenuRegistration, PageRegistration, StatusBarRegistration, } from "./registries"; import { observable } from "mobx"; -import { LensExtension } from "./lens-extension" -import { getExtensionPageUrl } from "./registries/page-registry" +import { LensExtension } from "./lens-extension"; +import { getExtensionPageUrl } from "./registries/page-registry"; export class LensRendererExtension extends LensExtension { - @observable.shallow globalPages: PageRegistration[] = [] - @observable.shallow clusterPages: PageRegistration[] = [] - @observable.shallow globalPageMenus: PageMenuRegistration[] = [] - @observable.shallow clusterPageMenus: PageMenuRegistration[] = [] - @observable.shallow kubeObjectStatusTexts: KubeObjectStatusRegistration[] = [] - @observable.shallow appPreferences: AppPreferenceRegistration[] = [] - @observable.shallow clusterFeatures: ClusterFeatureRegistration[] = [] - @observable.shallow statusBarItems: StatusBarRegistration[] = [] - @observable.shallow kubeObjectDetailItems: KubeObjectDetailRegistration[] = [] - @observable.shallow kubeObjectMenuItems: KubeObjectMenuRegistration[] = [] + @observable.shallow globalPages: PageRegistration[] = []; + @observable.shallow clusterPages: PageRegistration[] = []; + @observable.shallow globalPageMenus: PageMenuRegistration[] = []; + @observable.shallow clusterPageMenus: PageMenuRegistration[] = []; + @observable.shallow kubeObjectStatusTexts: KubeObjectStatusRegistration[] = []; + @observable.shallow appPreferences: AppPreferenceRegistration[] = []; + @observable.shallow clusterFeatures: ClusterFeatureRegistration[] = []; + @observable.shallow statusBarItems: StatusBarRegistration[] = []; + @observable.shallow kubeObjectDetailItems: KubeObjectDetailRegistration[] = []; + @observable.shallow kubeObjectMenuItems: KubeObjectMenuRegistration[] = []; async navigate(pageId?: string, params?: P) { const { navigate } = await import("../renderer/navigation"); diff --git a/src/extensions/registries/__tests__/page-registry.test.ts b/src/extensions/registries/__tests__/page-registry.test.ts index 47a5f82d9d..29e60dccc0 100644 --- a/src/extensions/registries/__tests__/page-registry.test.ts +++ b/src/extensions/registries/__tests__/page-registry.test.ts @@ -1,8 +1,8 @@ -import { getExtensionPageUrl, globalPageRegistry, PageRegistration } from "../page-registry" -import { LensExtension } from "../../lens-extension" +import { getExtensionPageUrl, globalPageRegistry, PageRegistration } from "../page-registry"; +import { LensExtension } from "../../lens-extension"; import React from "react"; -let ext: LensExtension = null +let ext: LensExtension = null; describe("getPageUrl", () => { beforeEach(async () => { @@ -14,25 +14,25 @@ describe("getPageUrl", () => { manifestPath: "/this/is/fake/package.json", isBundled: false, isEnabled: true - }) - }) + }); + }); it("returns a page url for extension", () => { - expect(getExtensionPageUrl({ extensionId: ext.name })).toBe("/extension/foo-bar") - }) + expect(getExtensionPageUrl({ extensionId: ext.name })).toBe("/extension/foo-bar"); + }); it("allows to pass base url as parameter", () => { - expect(getExtensionPageUrl({ extensionId: ext.name, pageId: "/test" })).toBe("/extension/foo-bar/test") - }) + expect(getExtensionPageUrl({ extensionId: ext.name, pageId: "/test" })).toBe("/extension/foo-bar/test"); + }); it("removes @", () => { - expect(getExtensionPageUrl({ extensionId: "@foo/bar" })).toBe("/extension/foo-bar") - }) + expect(getExtensionPageUrl({ extensionId: "@foo/bar" })).toBe("/extension/foo-bar"); + }); it("adds / prefix", () => { - expect(getExtensionPageUrl({ extensionId: ext.name, pageId: "test" })).toBe("/extension/foo-bar/test") - }) -}) + expect(getExtensionPageUrl({ extensionId: ext.name, pageId: "test" })).toBe("/extension/foo-bar/test"); + }); +}); describe("globalPageRegistry", () => { beforeEach(async () => { @@ -44,7 +44,7 @@ describe("globalPageRegistry", () => { manifestPath: "/this/is/fake/package.json", isBundled: false, isEnabled: true - }) + }); globalPageRegistry.add([ { id: "test-page", @@ -63,12 +63,12 @@ describe("globalPageRegistry", () => { Page: () => React.createElement('Default') } }, - ], ext) - }) + ], ext); + }); describe("getByPageMenuTarget", () => { it("matching to first registered page without id", () => { - const page = globalPageRegistry.getByPageMenuTarget({ extensionId: ext.name }) + const page = globalPageRegistry.getByPageMenuTarget({ extensionId: ext.name }); expect(page.id).toEqual(undefined); expect(page.extensionId).toEqual(ext.name); expect(page.routePath).toEqual(getExtensionPageUrl({ extensionId: ext.name })); @@ -78,16 +78,16 @@ describe("globalPageRegistry", () => { const page = globalPageRegistry.getByPageMenuTarget({ pageId: "test-page", extensionId: ext.name - }) - expect(page.id).toEqual("test-page") - }) + }); + expect(page.id).toEqual("test-page"); + }); it("returns null if target not found", () => { const page = globalPageRegistry.getByPageMenuTarget({ pageId: "wrong-page", extensionId: ext.name - }) - expect(page).toBeNull() - }) - }) -}) + }); + expect(page).toBeNull(); + }); + }); +}); diff --git a/src/extensions/registries/app-preference-registry.ts b/src/extensions/registries/app-preference-registry.ts index 6c54911f82..338f93b5bc 100644 --- a/src/extensions/registries/app-preference-registry.ts +++ b/src/extensions/registries/app-preference-registry.ts @@ -1,4 +1,4 @@ -import type React from "react" +import type React from "react"; import { BaseRegistry } from "./base-registry"; export interface AppPreferenceComponents { @@ -14,4 +14,4 @@ export interface AppPreferenceRegistration { export class AppPreferenceRegistry extends BaseRegistry { } -export const appPreferenceRegistry = new AppPreferenceRegistry() +export const appPreferenceRegistry = new AppPreferenceRegistry(); diff --git a/src/extensions/registries/base-registry.ts b/src/extensions/registries/base-registry.ts index e82c9d11bf..73dbd373f0 100644 --- a/src/extensions/registries/base-registry.ts +++ b/src/extensions/registries/base-registry.ts @@ -12,7 +12,7 @@ export class BaseRegistry { add(items: T | T[], ext?: LensExtension): () => void; // allow method overloading with required "ext" @action add(items: T | T[]) { - const normalizedItems = (Array.isArray(items) ? items : [items]) + const normalizedItems = (Array.isArray(items) ? items : [items]); this.items.push(...normalizedItems); return () => this.remove(...normalizedItems); } @@ -21,6 +21,6 @@ export class BaseRegistry { remove(...items: T[]) { items.forEach(item => { this.items.remove(item); // works because of {deep: false}; - }) + }); } } diff --git a/src/extensions/registries/cluster-feature-registry.ts b/src/extensions/registries/cluster-feature-registry.ts index 0e3363d0f0..5017ad27a6 100644 --- a/src/extensions/registries/cluster-feature-registry.ts +++ b/src/extensions/registries/cluster-feature-registry.ts @@ -1,4 +1,4 @@ -import type React from "react" +import type React from "react"; import { BaseRegistry } from "./base-registry"; import { ClusterFeature } from "../cluster-feature"; @@ -15,4 +15,4 @@ export interface ClusterFeatureRegistration { export class ClusterFeatureRegistry extends BaseRegistry { } -export const clusterFeatureRegistry = new ClusterFeatureRegistry() +export const clusterFeatureRegistry = new ClusterFeatureRegistry(); diff --git a/src/extensions/registries/index.ts b/src/extensions/registries/index.ts index cdcfb7124b..8e343742ec 100644 --- a/src/extensions/registries/index.ts +++ b/src/extensions/registries/index.ts @@ -1,11 +1,11 @@ // All registries managed by extensions api -export * from "./page-registry" -export * from "./page-menu-registry" -export * from "./menu-registry" -export * from "./app-preference-registry" -export * from "./status-bar-registry" +export * from "./page-registry"; +export * from "./page-menu-registry"; +export * from "./menu-registry"; +export * from "./app-preference-registry"; +export * from "./status-bar-registry"; export * from "./kube-object-detail-registry"; export * from "./kube-object-menu-registry"; -export * from "./cluster-feature-registry" -export * from "./kube-object-status-registry" +export * from "./cluster-feature-registry"; +export * from "./kube-object-status-registry"; diff --git a/src/extensions/registries/kube-object-detail-registry.ts b/src/extensions/registries/kube-object-detail-registry.ts index 32fea66b81..2638e82ade 100644 --- a/src/extensions/registries/kube-object-detail-registry.ts +++ b/src/extensions/registries/kube-object-detail-registry.ts @@ -1,4 +1,4 @@ -import React from "react" +import React from "react"; import { BaseRegistry } from "./base-registry"; export interface KubeObjectDetailComponents { @@ -15,15 +15,15 @@ export interface KubeObjectDetailRegistration { export class KubeObjectDetailRegistry extends BaseRegistry { getItemsForKind(kind: string, apiVersion: string) { const items = this.getItems().filter((item) => { - return item.kind === kind && item.apiVersions.includes(apiVersion) + return item.kind === kind && item.apiVersions.includes(apiVersion); }).map((item) => { if (item.priority === null) { - item.priority = 50 + item.priority = 50; } - return item - }) - return items.sort((a, b) => b.priority - a.priority) + return item; + }); + return items.sort((a, b) => b.priority - a.priority); } } -export const kubeObjectDetailRegistry = new KubeObjectDetailRegistry() +export const kubeObjectDetailRegistry = new KubeObjectDetailRegistry(); diff --git a/src/extensions/registries/kube-object-menu-registry.ts b/src/extensions/registries/kube-object-menu-registry.ts index 8f527d6a3d..25901f66ad 100644 --- a/src/extensions/registries/kube-object-menu-registry.ts +++ b/src/extensions/registries/kube-object-menu-registry.ts @@ -1,4 +1,4 @@ -import React from "react" +import React from "react"; import { BaseRegistry } from "./base-registry"; export interface KubeObjectMenuComponents { @@ -14,9 +14,9 @@ export interface KubeObjectMenuRegistration { export class KubeObjectMenuRegistry extends BaseRegistry { getItemsForKind(kind: string, apiVersion: string) { return this.getItems().filter((item) => { - return item.kind === kind && item.apiVersions.includes(apiVersion) - }) + return item.kind === kind && item.apiVersions.includes(apiVersion); + }); } } -export const kubeObjectMenuRegistry = new KubeObjectMenuRegistry() +export const kubeObjectMenuRegistry = new KubeObjectMenuRegistry(); diff --git a/src/extensions/registries/kube-object-status-registry.ts b/src/extensions/registries/kube-object-status-registry.ts index 74fd8145d2..5f7aab8d5d 100644 --- a/src/extensions/registries/kube-object-status-registry.ts +++ b/src/extensions/registries/kube-object-status-registry.ts @@ -10,8 +10,8 @@ export interface KubeObjectStatusRegistration { export class KubeObjectStatusRegistry extends BaseRegistry { getItemsForKind(kind: string, apiVersion: string) { return this.getItems().filter((item) => { - return item.kind === kind && item.apiVersions.includes(apiVersion) - }) + return item.kind === kind && item.apiVersions.includes(apiVersion); + }); } } diff --git a/src/extensions/registries/page-menu-registry.ts b/src/extensions/registries/page-menu-registry.ts index ebaaa42dbb..15f11139e6 100644 --- a/src/extensions/registries/page-menu-registry.ts +++ b/src/extensions/registries/page-menu-registry.ts @@ -29,8 +29,8 @@ export class PageMenuRegistry extends BaseRegistry({ extensionId, pageId = "", params }: PageMenuTarget): string { @@ -68,13 +68,13 @@ export class PageRegistry extends BaseRegistry ...page, extensionId: ext.name, routePath: getExtensionPageUrl({ extensionId: ext.name, pageId: page.id ?? page.routePath }), - })) + })); } catch (err) { logger.error(`[EXTENSION]: page-registration failed`, { items, extension: ext, error: String(err), - }) + }); } return super.add(registeredPages); } diff --git a/src/extensions/renderer-api/components.ts b/src/extensions/renderer-api/components.ts index c051ce13e3..242799c749 100644 --- a/src/extensions/renderer-api/components.ts +++ b/src/extensions/renderer-api/components.ts @@ -1,36 +1,36 @@ // Common UI components // layouts -export * from "../../renderer/components/layout/page-layout" -export * from "../../renderer/components/layout/wizard-layout" -export * from "../../renderer/components/layout/tab-layout" +export * from "../../renderer/components/layout/page-layout"; +export * from "../../renderer/components/layout/wizard-layout"; +export * from "../../renderer/components/layout/tab-layout"; // form-controls -export * from "../../renderer/components/button" -export * from "../../renderer/components/checkbox" -export * from "../../renderer/components/radio" -export * from "../../renderer/components/select" -export * from "../../renderer/components/slider" -export * from "../../renderer/components/input/input" +export * from "../../renderer/components/button"; +export * from "../../renderer/components/checkbox"; +export * from "../../renderer/components/radio"; +export * from "../../renderer/components/select"; +export * from "../../renderer/components/slider"; +export * from "../../renderer/components/input/input"; // other components -export * from "../../renderer/components/icon" -export * from "../../renderer/components/tooltip" -export * from "../../renderer/components/tabs" -export * from "../../renderer/components/table" -export * from "../../renderer/components/badge" -export * from "../../renderer/components/drawer" -export * from "../../renderer/components/dialog" +export * from "../../renderer/components/icon"; +export * from "../../renderer/components/tooltip"; +export * from "../../renderer/components/tabs"; +export * from "../../renderer/components/table"; +export * from "../../renderer/components/badge"; +export * from "../../renderer/components/drawer"; +export * from "../../renderer/components/dialog"; export * from "../../renderer/components/confirm-dialog"; -export * from "../../renderer/components/line-progress" -export * from "../../renderer/components/menu" -export * from "../../renderer/components/notifications" -export * from "../../renderer/components/spinner" -export * from "../../renderer/components/stepper" +export * from "../../renderer/components/line-progress"; +export * from "../../renderer/components/menu"; +export * from "../../renderer/components/notifications"; +export * from "../../renderer/components/spinner"; +export * from "../../renderer/components/stepper"; // kube helpers -export * from "../../renderer/components/kube-object" -export * from "../../renderer/components/+events/kube-event-details" +export * from "../../renderer/components/kube-object"; +export * from "../../renderer/components/+events/kube-event-details"; // specific exports export * from "../../renderer/components/status-brick"; diff --git a/src/extensions/renderer-api/index.ts b/src/extensions/renderer-api/index.ts index 009f49c366..c8e14c0951 100644 --- a/src/extensions/renderer-api/index.ts +++ b/src/extensions/renderer-api/index.ts @@ -1,14 +1,14 @@ // Lens-extensions apis, required in renderer process runtime // APIs -import * as Component from "./components" -import * as K8sApi from "./k8s-api" -import * as Navigation from "./navigation" -import * as Theme from "./theming" +import * as Component from "./components"; +import * as K8sApi from "./k8s-api"; +import * as Navigation from "./navigation"; +import * as Theme from "./theming"; export { Component, K8sApi, Navigation, Theme, -} +}; diff --git a/src/extensions/renderer-api/k8s-api.ts b/src/extensions/renderer-api/k8s-api.ts index 2a26b49cdd..fe04550fb7 100644 --- a/src/extensions/renderer-api/k8s-api.ts +++ b/src/extensions/renderer-api/k8s-api.ts @@ -1,6 +1,6 @@ -export { isAllowedResource } from "../../common/rbac" +export { isAllowedResource } from "../../common/rbac"; export { apiManager } from "../../renderer/api/api-manager"; -export { KubeObjectStore } from "../../renderer/kube-object.store" +export { KubeObjectStore } from "../../renderer/kube-object.store"; export { KubeApi, forCluster, IKubeApiCluster } from "../../renderer/api/kube-api"; export { KubeObject } from "../../renderer/api/kube-object"; export { Pod, podsApi, PodsApi, IPodContainer, IPodContainerStatus } from "../../renderer/api/endpoints"; @@ -31,33 +31,33 @@ export { RoleBinding, roleBindingApi } from "../../renderer/api/endpoints"; export { ClusterRole, clusterRoleApi } from "../../renderer/api/endpoints"; export { ClusterRoleBinding, clusterRoleBindingApi } from "../../renderer/api/endpoints"; export { CustomResourceDefinition, crdApi } from "../../renderer/api/endpoints"; -export { KubeObjectStatus, KubeObjectStatusLevel } from "./kube-object-status" +export { KubeObjectStatus, KubeObjectStatusLevel } from "./kube-object-status"; // stores -export type { EventStore } from "../../renderer/components/+events/event.store" -export type { PodsStore } from "../../renderer/components/+workloads-pods/pods.store" -export type { NodesStore } from "../../renderer/components/+nodes/nodes.store" -export type { DeploymentStore } from "../../renderer/components/+workloads-deployments/deployments.store" -export type { DaemonSetStore } from "../../renderer/components/+workloads-daemonsets/daemonsets.store" -export type { StatefulSetStore } from "../../renderer/components/+workloads-statefulsets/statefulset.store" -export type { JobStore } from "../../renderer/components/+workloads-jobs/job.store" -export type { CronJobStore } from "../../renderer/components/+workloads-cronjobs/cronjob.store" -export type { ConfigMapsStore } from "../../renderer/components/+config-maps/config-maps.store" -export type { SecretsStore } from "../../renderer/components/+config-secrets/secrets.store" -export type { ReplicaSetStore } from "../../renderer/components/+workloads-replicasets/replicasets.store" -export type { ResourceQuotasStore } from "../../renderer/components/+config-resource-quotas/resource-quotas.store" -export type { HPAStore } from "../../renderer/components/+config-autoscalers/hpa.store" -export type { PodDisruptionBudgetsStore } from "../../renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store" -export type { ServiceStore } from "../../renderer/components/+network-services/services.store" -export type { EndpointStore } from "../../renderer/components/+network-endpoints/endpoints.store" -export type { IngressStore } from "../../renderer/components/+network-ingresses/ingress.store" -export type { NetworkPolicyStore } from "../../renderer/components/+network-policies/network-policy.store" -export type { PersistentVolumesStore } from "../../renderer/components/+storage-volumes/volumes.store" -export type { VolumeClaimStore } from "../../renderer/components/+storage-volume-claims/volume-claim.store" -export type { StorageClassStore } from "../../renderer/components/+storage-classes/storage-class.store" -export type { NamespaceStore } from "../../renderer/components/+namespaces/namespace.store" -export type { ServiceAccountsStore } from "../../renderer/components/+user-management-service-accounts/service-accounts.store" -export type { RolesStore } from "../../renderer/components/+user-management-roles/roles.store" -export type { RoleBindingsStore } from "../../renderer/components/+user-management-roles-bindings/role-bindings.store" -export type { CRDStore } from "../../renderer/components/+custom-resources/crd.store" -export type { CRDResourceStore } from "../../renderer/components/+custom-resources/crd-resource.store" +export type { EventStore } from "../../renderer/components/+events/event.store"; +export type { PodsStore } from "../../renderer/components/+workloads-pods/pods.store"; +export type { NodesStore } from "../../renderer/components/+nodes/nodes.store"; +export type { DeploymentStore } from "../../renderer/components/+workloads-deployments/deployments.store"; +export type { DaemonSetStore } from "../../renderer/components/+workloads-daemonsets/daemonsets.store"; +export type { StatefulSetStore } from "../../renderer/components/+workloads-statefulsets/statefulset.store"; +export type { JobStore } from "../../renderer/components/+workloads-jobs/job.store"; +export type { CronJobStore } from "../../renderer/components/+workloads-cronjobs/cronjob.store"; +export type { ConfigMapsStore } from "../../renderer/components/+config-maps/config-maps.store"; +export type { SecretsStore } from "../../renderer/components/+config-secrets/secrets.store"; +export type { ReplicaSetStore } from "../../renderer/components/+workloads-replicasets/replicasets.store"; +export type { ResourceQuotasStore } from "../../renderer/components/+config-resource-quotas/resource-quotas.store"; +export type { HPAStore } from "../../renderer/components/+config-autoscalers/hpa.store"; +export type { PodDisruptionBudgetsStore } from "../../renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store"; +export type { ServiceStore } from "../../renderer/components/+network-services/services.store"; +export type { EndpointStore } from "../../renderer/components/+network-endpoints/endpoints.store"; +export type { IngressStore } from "../../renderer/components/+network-ingresses/ingress.store"; +export type { NetworkPolicyStore } from "../../renderer/components/+network-policies/network-policy.store"; +export type { PersistentVolumesStore } from "../../renderer/components/+storage-volumes/volumes.store"; +export type { VolumeClaimStore } from "../../renderer/components/+storage-volume-claims/volume-claim.store"; +export type { StorageClassStore } from "../../renderer/components/+storage-classes/storage-class.store"; +export type { NamespaceStore } from "../../renderer/components/+namespaces/namespace.store"; +export type { ServiceAccountsStore } from "../../renderer/components/+user-management-service-accounts/service-accounts.store"; +export type { RolesStore } from "../../renderer/components/+user-management-roles/roles.store"; +export type { RoleBindingsStore } from "../../renderer/components/+user-management-roles-bindings/role-bindings.store"; +export type { CRDStore } from "../../renderer/components/+custom-resources/crd.store"; +export type { CRDResourceStore } from "../../renderer/components/+custom-resources/crd-resource.store"; diff --git a/src/extensions/renderer-api/kube-object-status.ts b/src/extensions/renderer-api/kube-object-status.ts index 22994ee85d..f609d736fe 100644 --- a/src/extensions/renderer-api/kube-object-status.ts +++ b/src/extensions/renderer-api/kube-object-status.ts @@ -2,7 +2,7 @@ export type KubeObjectStatus = { level: KubeObjectStatusLevel; text: string; timestamp?: string; -} +}; export enum KubeObjectStatusLevel { INFO = 1, diff --git a/src/extensions/renderer-api/navigation.ts b/src/extensions/renderer-api/navigation.ts index f923f6e152..a1191a4b30 100644 --- a/src/extensions/renderer-api/navigation.ts +++ b/src/extensions/renderer-api/navigation.ts @@ -1,3 +1,3 @@ export { navigate } from "../../renderer/navigation"; -export { hideDetails, showDetails, getDetailsUrl } from "../../renderer/navigation" +export { hideDetails, showDetails, getDetailsUrl } from "../../renderer/navigation"; export { IURLParams } from "../../common/utils/buildUrl"; diff --git a/src/jest.setup.ts b/src/jest.setup.ts index 08727bc910..7b4732930e 100644 --- a/src/jest.setup.ts +++ b/src/jest.setup.ts @@ -1,4 +1,4 @@ -import fetchMock from "jest-fetch-mock" +import fetchMock from "jest-fetch-mock"; // rewire global.fetch to call 'fetchMock' fetchMock.enableMocks(); diff --git a/src/main/__test__/cluster.test.ts b/src/main/__test__/cluster.test.ts index 1fb92ed4bc..95177408af 100644 --- a/src/main/__test__/cluster.test.ts +++ b/src/main/__test__/cluster.test.ts @@ -21,35 +21,35 @@ jest.mock("winston", () => ({ Console: jest.fn(), File: jest.fn(), } -})) +})); -jest.mock("../../common/ipc") -jest.mock("../context-handler") -jest.mock("request") -jest.mock("request-promise-native") +jest.mock("../../common/ipc"); +jest.mock("../context-handler"); +jest.mock("request"); +jest.mock("request-promise-native"); import { Console } from "console"; import mockFs from "mock-fs"; import { workspaceStore } from "../../common/workspace-store"; -import { Cluster } from "../cluster" +import { Cluster } from "../cluster"; import { ContextHandler } from "../context-handler"; import { getFreePort } from "../port"; import { V1ResourceAttributes } from "@kubernetes/client-node"; import { apiResources } from "../../common/rbac"; -import request from "request-promise-native" +import request from "request-promise-native"; import { Kubectl } from "../kubectl"; -const mockedRequest = request as jest.MockedFunction +const mockedRequest = request as jest.MockedFunction; -console = new Console(process.stdout, process.stderr) // fix mockFS +console = new Console(process.stdout, process.stderr); // fix mockFS describe("create clusters", () => { beforeEach(() => { - jest.clearAllMocks() - }) + jest.clearAllMocks(); + }); - let c: Cluster + let c: Cluster; beforeEach(() => { const mockOpts = { @@ -74,68 +74,68 @@ describe("create clusters", () => { kind: "Config", preferences: {}, }) - } - mockFs(mockOpts) - jest.spyOn(Kubectl.prototype, "ensureKubectl").mockReturnValue(Promise.resolve(true)) + }; + mockFs(mockOpts); + jest.spyOn(Kubectl.prototype, "ensureKubectl").mockReturnValue(Promise.resolve(true)); c = new Cluster({ id: "foo", contextName: "minikube", kubeConfigPath: "minikube-config.yml", workspace: workspaceStore.currentWorkspaceId - }) - }) + }); + }); afterEach(() => { - mockFs.restore() - }) + mockFs.restore(); + }); it("should be able to create a cluster from a cluster model and apiURL should be decoded", () => { - expect(c.apiUrl).toBe("https://192.168.64.3:8443") - }) + expect(c.apiUrl).toBe("https://192.168.64.3:8443"); + }); it("reconnect should not throw if contextHandler is missing", () => { - expect(() => c.reconnect()).not.toThrowError() - }) + expect(() => c.reconnect()).not.toThrowError(); + }); it("disconnect should not throw if contextHandler is missing", () => { - expect(() => c.disconnect()).not.toThrowError() - }) + expect(() => c.disconnect()).not.toThrowError(); + }); it("init should not throw if everything is in order", async () => { - await c.init(await getFreePort()) + await c.init(await getFreePort()); expect(logger.info).toBeCalledWith(expect.stringContaining("init success"), { id: "foo", apiUrl: "https://192.168.64.3:8443", context: "minikube", - }) - }) + }); + }); it("activating cluster should try to connect to cluster and do a refresh", async () => { - const port = await getFreePort() + const port = await getFreePort(); jest.spyOn(ContextHandler.prototype, "ensureServer"); - const mockListNSs = jest.fn() + const mockListNSs = jest.fn(); const mockKC = { makeApiClient() { return { listNamespace: mockListNSs, - } + }; } - } - jest.spyOn(Cluster.prototype, "isClusterAdmin").mockReturnValue(Promise.resolve(true)) + }; + jest.spyOn(Cluster.prototype, "isClusterAdmin").mockReturnValue(Promise.resolve(true)); jest.spyOn(Cluster.prototype, "canI") .mockImplementationOnce((attr: V1ResourceAttributes): Promise => { - expect(attr.namespace).toBe("default") - expect(attr.resource).toBe("pods") - expect(attr.verb).toBe("list") - return Promise.resolve(true) + expect(attr.namespace).toBe("default"); + expect(attr.resource).toBe("pods"); + expect(attr.verb).toBe("list"); + return Promise.resolve(true); }) .mockImplementation((attr: V1ResourceAttributes): Promise => { - expect(attr.namespace).toBe("default") - expect(attr.verb).toBe("list") - return Promise.resolve(true) - }) - jest.spyOn(Cluster.prototype, "getProxyKubeconfig").mockReturnValue(mockKC as any) + expect(attr.namespace).toBe("default"); + expect(attr.verb).toBe("list"); + return Promise.resolve(true); + }); + jest.spyOn(Cluster.prototype, "getProxyKubeconfig").mockReturnValue(mockKC as any); mockListNSs.mockImplementationOnce(() => ({ body: { items: [{ @@ -144,36 +144,36 @@ describe("create clusters", () => { } }] } - })) + })); mockedRequest.mockImplementationOnce(((uri: any, _options: any) => { - expect(uri).toBe(`http://localhost:${port}/api-kube/version`) - return Promise.resolve({ gitVersion: "1.2.3" }) - }) as any) + expect(uri).toBe(`http://localhost:${port}/api-kube/version`); + return Promise.resolve({ gitVersion: "1.2.3" }); + }) as any); const c = new class extends Cluster { // only way to mock protected methods, without these we leak promises protected bindEvents() { - return + return; } protected async ensureKubectl() { - return Promise.resolve(true) + return Promise.resolve(true); } }({ id: "foo", contextName: "minikube", kubeConfigPath: "minikube-config.yml", workspace: workspaceStore.currentWorkspaceId - }) - await c.init(port) - await c.activate() + }); + await c.init(port); + await c.activate(); - expect(ContextHandler.prototype.ensureServer).toBeCalled() - expect(mockedRequest).toBeCalled() - expect(c.accessible).toBe(true) - expect(c.allowedNamespaces.length).toBe(1) - expect(c.allowedResources.length).toBe(apiResources.length) - c.disconnect() - jest.resetAllMocks() - }) -}) + expect(ContextHandler.prototype.ensureServer).toBeCalled(); + expect(mockedRequest).toBeCalled(); + expect(c.accessible).toBe(true); + expect(c.allowedNamespaces.length).toBe(1); + expect(c.allowedResources.length).toBe(apiResources.length); + c.disconnect(); + jest.resetAllMocks(); + }); +}); diff --git a/src/main/__test__/kube-auth-proxy.test.ts b/src/main/__test__/kube-auth-proxy.test.ts index 8ef1f058e7..dbb3e308e3 100644 --- a/src/main/__test__/kube-auth-proxy.test.ts +++ b/src/main/__test__/kube-auth-proxy.test.ts @@ -21,109 +21,109 @@ jest.mock("winston", () => ({ Console: jest.fn(), File: jest.fn(), } -})) +})); -jest.mock("../../common/ipc") -jest.mock("child_process") -jest.mock("tcp-port-used") +jest.mock("../../common/ipc"); +jest.mock("child_process"); +jest.mock("tcp-port-used"); -import { Cluster } from "../cluster" -import { KubeAuthProxy } from "../kube-auth-proxy" -import { getFreePort } from "../port" -import { broadcastMessage } from "../../common/ipc" -import { ChildProcess, spawn, SpawnOptions } from "child_process" -import { bundledKubectlPath, Kubectl } from "../kubectl" +import { Cluster } from "../cluster"; +import { KubeAuthProxy } from "../kube-auth-proxy"; +import { getFreePort } from "../port"; +import { broadcastMessage } from "../../common/ipc"; +import { ChildProcess, spawn, SpawnOptions } from "child_process"; +import { bundledKubectlPath, Kubectl } from "../kubectl"; import { mock, MockProxy } from 'jest-mock-extended'; import { waitUntilUsed } from 'tcp-port-used'; -import { Readable } from "stream" +import { Readable } from "stream"; -const mockBroadcastIpc = broadcastMessage as jest.MockedFunction -const mockSpawn = spawn as jest.MockedFunction -const mockWaitUntilUsed = waitUntilUsed as jest.MockedFunction +const mockBroadcastIpc = broadcastMessage as jest.MockedFunction; +const mockSpawn = spawn as jest.MockedFunction; +const mockWaitUntilUsed = waitUntilUsed as jest.MockedFunction; describe("kube auth proxy tests", () => { beforeEach(() => { - jest.clearAllMocks() - }) + jest.clearAllMocks(); + }); it("calling exit multiple times shouldn't throw", async () => { - const port = await getFreePort() - const kap = new KubeAuthProxy(new Cluster({ id: "foobar", kubeConfigPath: "fake-path.yml" }), port, {}) - kap.exit() - kap.exit() - kap.exit() - }) + const port = await getFreePort(); + const kap = new KubeAuthProxy(new Cluster({ id: "foobar", kubeConfigPath: "fake-path.yml" }), port, {}); + kap.exit(); + kap.exit(); + kap.exit(); + }); describe("spawn tests", () => { - let port: number - let mockedCP: MockProxy - let listeners: Record void> - let proxy: KubeAuthProxy + let port: number; + let mockedCP: MockProxy; + let listeners: Record void>; + let proxy: KubeAuthProxy; beforeEach(async () => { - port = await getFreePort() - mockedCP = mock() - listeners = {} + port = await getFreePort(); + mockedCP = mock(); + listeners = {}; - jest.spyOn(Kubectl.prototype, "checkBinary").mockReturnValueOnce(Promise.resolve(true)) - jest.spyOn(Kubectl.prototype, "ensureKubectl").mockReturnValueOnce(Promise.resolve(false)) + jest.spyOn(Kubectl.prototype, "checkBinary").mockReturnValueOnce(Promise.resolve(true)); + jest.spyOn(Kubectl.prototype, "ensureKubectl").mockReturnValueOnce(Promise.resolve(false)); mockedCP.on.mockImplementation((event: string, listener: (message: any, sendHandle: any) => void): ChildProcess => { - listeners[event] = listener - return mockedCP - }) - mockedCP.stderr = mock() + listeners[event] = listener; + return mockedCP; + }); + mockedCP.stderr = mock(); mockedCP.stderr.on.mockImplementation((event: string, listener: (message: any, sendHandle: any) => void): Readable => { - listeners[`stderr/${event}`] = listener - return mockedCP.stderr - }) - mockedCP.stdout = mock() + listeners[`stderr/${event}`] = listener; + return mockedCP.stderr; + }); + mockedCP.stdout = mock(); mockedCP.stdout.on.mockImplementation((event: string, listener: (message: any, sendHandle: any) => void): Readable => { - listeners[`stdout/${event}`] = listener - return mockedCP.stdout - }) + listeners[`stdout/${event}`] = listener; + return mockedCP.stdout; + }); mockSpawn.mockImplementationOnce((command: string, args: readonly string[], options: SpawnOptions): ChildProcess => { - expect(command).toBe(bundledKubectlPath()) - return mockedCP - }) - mockWaitUntilUsed.mockReturnValueOnce(Promise.resolve()) - const cluster = new Cluster({ id: "foobar", kubeConfigPath: "fake-path.yml" }) - jest.spyOn(cluster, "apiUrl", "get").mockReturnValue("https://fake.k8s.internal") - proxy = new KubeAuthProxy(cluster, port, {}) - }) + expect(command).toBe(bundledKubectlPath()); + return mockedCP; + }); + mockWaitUntilUsed.mockReturnValueOnce(Promise.resolve()); + const cluster = new Cluster({ id: "foobar", kubeConfigPath: "fake-path.yml" }); + jest.spyOn(cluster, "apiUrl", "get").mockReturnValue("https://fake.k8s.internal"); + proxy = new KubeAuthProxy(cluster, port, {}); + }); it("should call spawn and broadcast errors", async () => { - await proxy.run() - listeners["error"]({ message: "foobarbat" }) + await proxy.run(); + listeners["error"]({ message: "foobarbat" }); - expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "foobarbat", error: true }) - }) + expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "foobarbat", error: true }); + }); it("should call spawn and broadcast exit", async () => { - await proxy.run() - listeners["exit"](0) + await proxy.run(); + listeners["exit"](0); - expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "proxy exited with code: 0", error: false }) - }) + expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "proxy exited with code: 0", error: false }); + }); it("should call spawn and broadcast errors from stderr", async () => { - await proxy.run() - listeners["stderr/data"]("an error") + await proxy.run(); + listeners["stderr/data"]("an error"); - expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "an error", error: true }) - }) + expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "an error", error: true }); + }); it("should call spawn and broadcast stdout serving info", async () => { - await proxy.run() - listeners["stdout/data"]("Starting to serve on") + await proxy.run(); + listeners["stdout/data"]("Starting to serve on"); - expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "Authentication proxy started\n" }) - }) + expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "Authentication proxy started\n" }); + }); it("should call spawn and broadcast stdout other info", async () => { - await proxy.run() - listeners["stdout/data"]("some info") + await proxy.run(); + listeners["stdout/data"]("some info"); - expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "some info" }) - }) - }) -}) + expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "some info" }); + }); + }); +}); diff --git a/src/main/__test__/kubeconfig-manager.test.ts b/src/main/__test__/kubeconfig-manager.test.ts index a0a4060111..152a13055d 100644 --- a/src/main/__test__/kubeconfig-manager.test.ts +++ b/src/main/__test__/kubeconfig-manager.test.ts @@ -21,24 +21,24 @@ jest.mock("winston", () => ({ Console: jest.fn(), File: jest.fn(), } -})) +})); -import { KubeconfigManager } from "../kubeconfig-manager" -import mockFs from "mock-fs" +import { KubeconfigManager } from "../kubeconfig-manager"; +import mockFs from "mock-fs"; import { Cluster } from "../cluster"; import { workspaceStore } from "../../common/workspace-store"; import { ContextHandler } from "../context-handler"; import { getFreePort } from "../port"; -import fse from "fs-extra" +import fse from "fs-extra"; import { loadYaml } from "@kubernetes/client-node"; import { Console } from "console"; -console = new Console(process.stdout, process.stderr) // fix mockFS +console = new Console(process.stdout, process.stderr); // fix mockFS describe("kubeconfig manager tests", () => { beforeEach(() => { - jest.clearAllMocks() - }) + jest.clearAllMocks(); + }); beforeEach(() => { const mockOpts = { @@ -63,13 +63,13 @@ describe("kubeconfig manager tests", () => { kind: "Config", preferences: {}, }) - } - mockFs(mockOpts) - }) + }; + mockFs(mockOpts); + }); afterEach(() => { - mockFs.restore() - }) + mockFs.restore(); + }); it("should create 'temp' kube config with proxy", async () => { const cluster = new Cluster({ @@ -77,19 +77,19 @@ describe("kubeconfig manager tests", () => { contextName: "minikube", kubeConfigPath: "minikube-config.yml", workspace: workspaceStore.currentWorkspaceId - }) - const contextHandler = new ContextHandler(cluster) - const port = await getFreePort() - const kubeConfManager = await KubeconfigManager.create(cluster, contextHandler, port) + }); + const contextHandler = new ContextHandler(cluster); + const port = await getFreePort(); + const kubeConfManager = await KubeconfigManager.create(cluster, contextHandler, port); - expect(logger.error).not.toBeCalled() - expect(kubeConfManager.getPath()).toBe("tmp/kubeconfig-foo") - const file = await fse.readFile(kubeConfManager.getPath()) - const yml = loadYaml(file.toString()) - expect(yml["current-context"]).toBe("minikube") - expect(yml["clusters"][0]["cluster"]["server"]).toBe(`http://127.0.0.1:${port}/foo`) - expect(yml["users"][0]["name"]).toBe("proxy") - }) + expect(logger.error).not.toBeCalled(); + expect(kubeConfManager.getPath()).toBe("tmp/kubeconfig-foo"); + const file = await fse.readFile(kubeConfManager.getPath()); + const yml = loadYaml(file.toString()); + expect(yml["current-context"]).toBe("minikube"); + expect(yml["clusters"][0]["cluster"]["server"]).toBe(`http://127.0.0.1:${port}/foo`); + expect(yml["users"][0]["name"]).toBe("proxy"); + }); it("should remove 'temp' kube config on unlink and remove reference from inside class", async () => { const cluster = new Cluster({ @@ -97,16 +97,16 @@ describe("kubeconfig manager tests", () => { contextName: "minikube", kubeConfigPath: "minikube-config.yml", workspace: workspaceStore.currentWorkspaceId - }) - const contextHandler = new ContextHandler(cluster) - const port = await getFreePort() - const kubeConfManager = await KubeconfigManager.create(cluster, contextHandler, port) + }); + const contextHandler = new ContextHandler(cluster); + const port = await getFreePort(); + const kubeConfManager = await KubeconfigManager.create(cluster, contextHandler, port); - const configPath = kubeConfManager.getPath() - expect(await fse.pathExists(configPath)).toBe(true) - await kubeConfManager.unlink() - expect(await fse.pathExists(configPath)).toBe(false) - await kubeConfManager.unlink() // doesn't throw - expect(kubeConfManager.getPath()).toBeUndefined() - }) -}) + const configPath = kubeConfManager.getPath(); + expect(await fse.pathExists(configPath)).toBe(true); + await kubeConfManager.unlink(); + expect(await fse.pathExists(configPath)).toBe(false); + await kubeConfManager.unlink(); // doesn't throw + expect(kubeConfManager.getPath()).toBeUndefined(); + }); +}); diff --git a/src/main/app-updater.ts b/src/main/app-updater.ts index 3613c3ef18..c7b6659149 100644 --- a/src/main/app-updater.ts +++ b/src/main/app-updater.ts @@ -1,19 +1,19 @@ -import { autoUpdater } from "electron-updater" -import logger from "./logger" +import { autoUpdater } from "electron-updater"; +import logger from "./logger"; export class AppUpdater { - static readonly defaultUpdateIntervalMs = 1000 * 60 * 60 * 24 // once a day + static readonly defaultUpdateIntervalMs = 1000 * 60 * 60 * 24; // once a day static checkForUpdates() { - return autoUpdater.checkForUpdatesAndNotify() + return autoUpdater.checkForUpdatesAndNotify(); } constructor(protected updateInterval = AppUpdater.defaultUpdateIntervalMs) { - autoUpdater.logger = logger + autoUpdater.logger = logger; } public start() { - setInterval(AppUpdater.checkForUpdates, this.updateInterval) + setInterval(AppUpdater.checkForUpdates, this.updateInterval); return AppUpdater.checkForUpdates(); } } diff --git a/src/main/cluster-detectors/base-cluster-detector.ts b/src/main/cluster-detectors/base-cluster-detector.ts index 8663313005..f73cc2ac81 100644 --- a/src/main/cluster-detectors/base-cluster-detector.ts +++ b/src/main/cluster-detectors/base-cluster-detector.ts @@ -1,21 +1,21 @@ -import request, { RequestPromiseOptions } from "request-promise-native" +import request, { RequestPromiseOptions } from "request-promise-native"; import { Cluster } from "../cluster"; export type ClusterDetectionResult = { value: string | number | boolean accuracy: number -} +}; export class BaseClusterDetector { - cluster: Cluster - key: string + cluster: Cluster; + key: string; constructor(cluster: Cluster) { - this.cluster = cluster + this.cluster = cluster; } detect(): Promise { - return null + return null; } protected async k8sRequest(path: string, options: RequestPromiseOptions = {}): Promise { @@ -28,6 +28,6 @@ export class BaseClusterDetector { Host: `${this.cluster.id}.${new URL(this.cluster.kubeProxyUrl).host}`, // required in ClusterManager.getClusterForRequest() ...(options.headers || {}), }, - }) + }); } } \ No newline at end of file diff --git a/src/main/cluster-detectors/cluster-id-detector.ts b/src/main/cluster-detectors/cluster-id-detector.ts index 558e52d43c..8419ae9db4 100644 --- a/src/main/cluster-detectors/cluster-id-detector.ts +++ b/src/main/cluster-detectors/cluster-id-detector.ts @@ -1,23 +1,23 @@ import { BaseClusterDetector } from "./base-cluster-detector"; -import { createHash } from "crypto" +import { createHash } from "crypto"; import { ClusterMetadataKey } from "../cluster"; export class ClusterIdDetector extends BaseClusterDetector { - key = ClusterMetadataKey.CLUSTER_ID + key = ClusterMetadataKey.CLUSTER_ID; public async detect() { - let id: string + let id: string; try { - id = await this.getDefaultNamespaceId() + id = await this.getDefaultNamespaceId(); } catch(_) { - id = this.cluster.apiUrl + id = this.cluster.apiUrl; } - const value = createHash("sha256").update(id).digest("hex") - return { value: value, accuracy: 100 } + const value = createHash("sha256").update(id).digest("hex"); + return { value: value, accuracy: 100 }; } protected async getDefaultNamespaceId() { - const response = await this.k8sRequest("/api/v1/namespaces/default") - return response.metadata.uid + const response = await this.k8sRequest("/api/v1/namespaces/default"); + return response.metadata.uid; } } \ No newline at end of file diff --git a/src/main/cluster-detectors/detector-registry.ts b/src/main/cluster-detectors/detector-registry.ts index 577fdf2d85..d4abe01304 100644 --- a/src/main/cluster-detectors/detector-registry.ts +++ b/src/main/cluster-detectors/detector-registry.ts @@ -12,34 +12,34 @@ export class DetectorRegistry { registry = observable.array([], { deep: false }); add(detectorClass: typeof BaseClusterDetector) { - this.registry.push(detectorClass) + this.registry.push(detectorClass); } async detectForCluster(cluster: Cluster): Promise { - const results: {[key: string]: ClusterDetectionResult } = {} + const results: {[key: string]: ClusterDetectionResult } = {}; for (const detectorClass of this.registry) { - const detector = new detectorClass(cluster) + const detector = new detectorClass(cluster); try { - const data = await detector.detect() + const data = await detector.detect(); if (!data) continue; - const existingValue = results[detector.key] + const existingValue = results[detector.key]; if (existingValue && existingValue.accuracy > data.accuracy) continue; // previous value exists and is more accurate - results[detector.key] = data + results[detector.key] = data; } catch (e) { // detector raised error, do nothing } } - const metadata: ClusterMetadata = {} + const metadata: ClusterMetadata = {}; for (const [key, result] of Object.entries(results)) { - metadata[key] = result.value + metadata[key] = result.value; } - return metadata + return metadata; } } -export const detectorRegistry = new DetectorRegistry() -detectorRegistry.add(ClusterIdDetector) -detectorRegistry.add(LastSeenDetector) -detectorRegistry.add(VersionDetector) -detectorRegistry.add(DistributionDetector) -detectorRegistry.add(NodesCountDetector) \ No newline at end of file +export const detectorRegistry = new DetectorRegistry(); +detectorRegistry.add(ClusterIdDetector); +detectorRegistry.add(LastSeenDetector); +detectorRegistry.add(VersionDetector); +detectorRegistry.add(DistributionDetector); +detectorRegistry.add(NodesCountDetector); \ No newline at end of file diff --git a/src/main/cluster-detectors/distribution-detector.ts b/src/main/cluster-detectors/distribution-detector.ts index b5895f8a71..181425cb26 100644 --- a/src/main/cluster-detectors/distribution-detector.ts +++ b/src/main/cluster-detectors/distribution-detector.ts @@ -2,79 +2,79 @@ import { BaseClusterDetector } from "./base-cluster-detector"; import { ClusterMetadataKey } from "../cluster"; export class DistributionDetector extends BaseClusterDetector { - key = ClusterMetadataKey.DISTRIBUTION - version: string + key = ClusterMetadataKey.DISTRIBUTION; + version: string; public async detect() { - this.version = await this.getKubernetesVersion() + this.version = await this.getKubernetesVersion(); if (await this.isRancher()) { - return { value: "rancher", accuracy: 80} + return { value: "rancher", accuracy: 80}; } if (this.isGKE()) { - return { value: "gke", accuracy: 80} + return { value: "gke", accuracy: 80}; } if (this.isEKS()) { - return { value: "eks", accuracy: 80} + return { value: "eks", accuracy: 80}; } if (this.isIKS()) { - return { value: "iks", accuracy: 80} + return { value: "iks", accuracy: 80}; } if (this.isAKS()) { - return { value: "aks", accuracy: 80} + return { value: "aks", accuracy: 80}; } if (this.isDigitalOcean()) { - return { value: "digitalocean", accuracy: 90} + return { value: "digitalocean", accuracy: 90}; } if (this.isMinikube()) { - return { value: "minikube", accuracy: 80} + return { value: "minikube", accuracy: 80}; } if (this.isCustom()) { - return { value: "custom", accuracy: 10} + return { value: "custom", accuracy: 10}; } - return { value: "unknown", accuracy: 10} + return { value: "unknown", accuracy: 10}; } public async getKubernetesVersion() { - if (this.cluster.version) return this.cluster.version + if (this.cluster.version) return this.cluster.version; - const response = await this.k8sRequest("/version") - return response.gitVersion + const response = await this.k8sRequest("/version"); + return response.gitVersion; } protected isGKE() { - return this.version.includes("gke") + return this.version.includes("gke"); } protected isEKS() { - return this.version.includes("eks") + return this.version.includes("eks"); } protected isIKS() { - return this.version.includes("IKS") + return this.version.includes("IKS"); } protected isAKS() { - return this.cluster.apiUrl.endsWith("azmk8s.io") + return this.cluster.apiUrl.endsWith("azmk8s.io"); } protected isDigitalOcean() { - return this.cluster.apiUrl.endsWith("k8s.ondigitalocean.com") + return this.cluster.apiUrl.endsWith("k8s.ondigitalocean.com"); } protected isMinikube() { - return this.cluster.contextName.startsWith("minikube") + return this.cluster.contextName.startsWith("minikube"); } protected isCustom() { - return this.version.includes("+") + return this.version.includes("+"); } protected async isRancher() { try { - const response = await this.k8sRequest("") - return response.data.find((api: any) => api?.apiVersion?.group === "meta.cattle.io") !== undefined + const response = await this.k8sRequest(""); + return response.data.find((api: any) => api?.apiVersion?.group === "meta.cattle.io") !== undefined; } catch (e) { - return false + return false; } } } \ No newline at end of file diff --git a/src/main/cluster-detectors/last-seen-detector.ts b/src/main/cluster-detectors/last-seen-detector.ts index 0c231116fe..d56483625a 100644 --- a/src/main/cluster-detectors/last-seen-detector.ts +++ b/src/main/cluster-detectors/last-seen-detector.ts @@ -2,12 +2,12 @@ import { BaseClusterDetector } from "./base-cluster-detector"; import { ClusterMetadataKey } from "../cluster"; export class LastSeenDetector extends BaseClusterDetector { - key = ClusterMetadataKey.LAST_SEEN + key = ClusterMetadataKey.LAST_SEEN; public async detect() { if (!this.cluster.accessible) return null; - await this.k8sRequest("/version") - return { value: new Date().toJSON(), accuracy: 100 } + await this.k8sRequest("/version"); + return { value: new Date().toJSON(), accuracy: 100 }; } } \ No newline at end of file diff --git a/src/main/cluster-detectors/nodes-count-detector.ts b/src/main/cluster-detectors/nodes-count-detector.ts index 858ff43d9f..ba5fc93583 100644 --- a/src/main/cluster-detectors/nodes-count-detector.ts +++ b/src/main/cluster-detectors/nodes-count-detector.ts @@ -2,16 +2,16 @@ import { BaseClusterDetector } from "./base-cluster-detector"; import { ClusterMetadataKey } from "../cluster"; export class NodesCountDetector extends BaseClusterDetector { - key = ClusterMetadataKey.NODES_COUNT + key = ClusterMetadataKey.NODES_COUNT; public async detect() { if (!this.cluster.accessible) return null; - const nodeCount = await this.getNodeCount() - return { value: nodeCount, accuracy: 100} + const nodeCount = await this.getNodeCount(); + return { value: nodeCount, accuracy: 100}; } protected async getNodeCount(): Promise { - const response = await this.k8sRequest("/api/v1/nodes") - return response.items.length + const response = await this.k8sRequest("/api/v1/nodes"); + return response.items.length; } } \ No newline at end of file diff --git a/src/main/cluster-detectors/version-detector.ts b/src/main/cluster-detectors/version-detector.ts index 4092b40b42..e59e6291b9 100644 --- a/src/main/cluster-detectors/version-detector.ts +++ b/src/main/cluster-detectors/version-detector.ts @@ -2,16 +2,16 @@ import { BaseClusterDetector } from "./base-cluster-detector"; import { ClusterMetadataKey } from "../cluster"; export class VersionDetector extends BaseClusterDetector { - key = ClusterMetadataKey.VERSION - value: string + key = ClusterMetadataKey.VERSION; + value: string; public async detect() { - const version = await this.getKubernetesVersion() - return { value: version, accuracy: 100} + const version = await this.getKubernetesVersion(); + return { value: version, accuracy: 100}; } public async getKubernetesVersion() { - const response = await this.k8sRequest("/version") - return response.gitVersion + const response = await this.k8sRequest("/version"); + return response.gitVersion; } } \ No newline at end of file diff --git a/src/main/cluster-manager.ts b/src/main/cluster-manager.ts index 1a479e724e..9b2e88ef89 100644 --- a/src/main/cluster-manager.ts +++ b/src/main/cluster-manager.ts @@ -1,16 +1,16 @@ import "../common/cluster-ipc"; -import type http from "http" -import { ipcMain } from "electron" +import type http from "http"; +import { ipcMain } from "electron"; import { autorun } from "mobx"; -import { clusterStore, getClusterIdFromHost } from "../common/cluster-store" -import { Cluster } from "./cluster" +import { clusterStore, getClusterIdFromHost } from "../common/cluster-store"; +import { Cluster } from "./cluster"; import logger from "./logger"; import { apiKubePrefix } from "../common/vars"; import { Singleton } from "../common/utils"; export class ClusterManager extends Singleton { constructor(public readonly port: number) { - super() + super(); // auto-init clusters autorun(() => { clusterStore.enabledClustersList.forEach(cluster => { @@ -34,52 +34,52 @@ export class ClusterManager extends Singleton { delay: 250 }); - ipcMain.on("network:offline", () => { this.onNetworkOffline() }) - ipcMain.on("network:online", () => { this.onNetworkOnline() }) + ipcMain.on("network:offline", () => { this.onNetworkOffline(); }); + ipcMain.on("network:online", () => { this.onNetworkOnline(); }); } protected onNetworkOffline() { - logger.info("[CLUSTER-MANAGER]: network is offline") + logger.info("[CLUSTER-MANAGER]: network is offline"); clusterStore.enabledClustersList.forEach((cluster) => { if (!cluster.disconnected) { - cluster.online = false - cluster.accessible = false - cluster.refreshConnectionStatus().catch((e) => e) + cluster.online = false; + cluster.accessible = false; + cluster.refreshConnectionStatus().catch((e) => e); } - }) + }); } protected onNetworkOnline() { - logger.info("[CLUSTER-MANAGER]: network is online") + logger.info("[CLUSTER-MANAGER]: network is online"); clusterStore.enabledClustersList.forEach((cluster) => { if (!cluster.disconnected) { - cluster.refreshConnectionStatus().catch((e) => e) + cluster.refreshConnectionStatus().catch((e) => e); } - }) + }); } stop() { clusterStore.clusters.forEach((cluster: Cluster) => { cluster.disconnect(); - }) + }); } getClusterForRequest(req: http.IncomingMessage): Cluster { - let cluster: Cluster = null + let cluster: Cluster = null; // lens-server is connecting to 127.0.0.1:/ if (req.headers.host.startsWith("127.0.0.1")) { - const clusterId = req.url.split("/")[1] - cluster = clusterStore.getById(clusterId) + const clusterId = req.url.split("/")[1]; + cluster = clusterStore.getById(clusterId); if (cluster) { // we need to swap path prefix so that request is proxied to kube api - req.url = req.url.replace(`/${clusterId}`, apiKubePrefix) + req.url = req.url.replace(`/${clusterId}`, apiKubePrefix); } } else if (req.headers["x-cluster-id"]) { - cluster = clusterStore.getById(req.headers["x-cluster-id"].toString()) + cluster = clusterStore.getById(req.headers["x-cluster-id"].toString()); } else { const clusterId = getClusterIdFromHost(req.headers.host); - cluster = clusterStore.getById(clusterId) + cluster = clusterStore.getById(clusterId); } return cluster; diff --git a/src/main/cluster.ts b/src/main/cluster.ts index a2b71a865b..e2831e8c3f 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -1,18 +1,18 @@ -import { ipcMain } from "electron" -import type { ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences } from "../common/cluster-store" +import { ipcMain } from "electron"; +import type { ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences } from "../common/cluster-store"; import type { IMetricsReqParams } from "../renderer/api/endpoints/metrics.api"; import type { WorkspaceId } from "../common/workspace-store"; import { action, computed, observable, reaction, toJS, when } from "mobx"; import { apiKubePrefix } from "../common/vars"; import { broadcastMessage } from "../common/ipc"; -import { ContextHandler } from "./context-handler" -import { AuthorizationV1Api, CoreV1Api, KubeConfig, V1ResourceAttributes } from "@kubernetes/client-node" +import { ContextHandler } from "./context-handler"; +import { AuthorizationV1Api, CoreV1Api, KubeConfig, V1ResourceAttributes } from "@kubernetes/client-node"; import { Kubectl } from "./kubectl"; -import { KubeconfigManager } from "./kubeconfig-manager" -import { getNodeWarningConditions, loadConfig, podHasIssues } from "../common/kube-helpers" -import request, { RequestPromiseOptions } from "request-promise-native" +import { KubeconfigManager } from "./kubeconfig-manager"; +import { getNodeWarningConditions, loadConfig, podHasIssues } from "../common/kube-helpers"; +import request, { RequestPromiseOptions } from "request-promise-native"; import { apiResources } from "../common/rbac"; -import logger from "./logger" +import logger from "./logger"; import { VersionDetector } from "./cluster-detectors/version-detector"; import { detectorRegistry } from "./cluster-detectors/detector-registry"; @@ -32,7 +32,7 @@ export enum ClusterMetadataKey { export type ClusterRefreshOptions = { refreshMetadata?: boolean -} +}; export interface ClusterState { initialized: boolean; @@ -50,7 +50,7 @@ export interface ClusterState { export class Cluster implements ClusterModel, ClusterState { public id: ClusterId; - public kubeCtl: Kubectl + public kubeCtl: Kubectl; public contextHandler: ContextHandler; public ownerRef: string; protected kubeconfigManager: KubeconfigManager; @@ -86,23 +86,23 @@ export class Cluster implements ClusterModel, ClusterState { } @computed get name() { - return this.preferences.clusterName || this.contextName + return this.preferences.clusterName || this.contextName; } get version(): string { - return String(this.metadata?.version) || "" + return String(this.metadata?.version) || ""; } constructor(model: ClusterModel) { this.updateModel(model); - const kubeconfig = this.getKubeconfig() + const kubeconfig = this.getKubeconfig(); if (kubeconfig.getContextObject(this.contextName)) { - this.apiUrl = kubeconfig.getCluster(kubeconfig.getContextObject(this.contextName).cluster).server + this.apiUrl = kubeconfig.getCluster(kubeconfig.getContextObject(this.contextName).cluster).server; } } get isManaged(): boolean { - return !!this.ownerRef + return !!this.ownerRef; } @action @@ -131,16 +131,16 @@ export class Cluster implements ClusterModel, ClusterState { } protected bindEvents() { - logger.info(`[CLUSTER]: bind events`, this.getMeta()) - const refreshTimer = setInterval(() => !this.disconnected && this.refresh(), 30000) // every 30s - const refreshMetadataTimer = setInterval(() => !this.disconnected && this.refreshMetadata(), 900000) // every 15 minutes + logger.info(`[CLUSTER]: bind events`, this.getMeta()); + const refreshTimer = setInterval(() => !this.disconnected && this.refresh(), 30000); // every 30s + const refreshMetadataTimer = setInterval(() => !this.disconnected && this.refreshMetadata(), 900000); // every 15 minutes if (ipcMain) { this.eventDisposers.push( reaction(() => this.getState(), () => this.pushState()), () => { - clearInterval(refreshTimer) - clearInterval(refreshMetadataTimer) + clearInterval(refreshTimer); + clearInterval(refreshMetadataTimer); }, ); } @@ -165,20 +165,20 @@ export class Cluster implements ClusterModel, ClusterState { if (this.disconnected || !this.accessible) { await this.reconnect(); } - await this.refreshConnectionStatus() + await this.refreshConnectionStatus(); if (this.accessible) { - await this.refreshAllowedResources() - this.isAdmin = await this.isClusterAdmin() - this.ready = true - this.ensureKubectl() + await this.refreshAllowedResources(); + this.isAdmin = await this.isClusterAdmin(); + this.ready = true; + this.ensureKubectl(); } - this.activated = true + this.activated = true; return this.pushState(); } protected async ensureKubectl() { - this.kubeCtl = new Kubectl(this.version) - return this.kubeCtl.ensureKubectl() // download kubectl in background, so it's not blocking dashboard + this.kubeCtl = new Kubectl(this.version); + return this.kubeCtl.ensureKubectl(); // download kubectl in background, so it's not blocking dashboard } @action @@ -214,9 +214,9 @@ export class Cluster implements ClusterModel, ClusterState { this.refreshAllowedResources(), ]); if (opts.refreshMetadata) { - this.refreshMetadata() + this.refreshMetadata(); } - this.ready = true + this.ready = true; } this.pushState(); } @@ -224,9 +224,9 @@ export class Cluster implements ClusterModel, ClusterState { @action async refreshMetadata() { logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta()); - const metadata = await detectorRegistry.detectForCluster(this) - const existingMetadata = this.metadata - this.metadata = Object.assign(existingMetadata, metadata) + const metadata = await detectorRegistry.detectForCluster(this); + const existingMetadata = this.metadata; + this.metadata = Object.assign(existingMetadata, metadata); } @action @@ -256,16 +256,16 @@ export class Cluster implements ClusterModel, ClusterState { } getProxyKubeconfigPath(): string { - return this.kubeconfigManager.getPath() + return this.kubeconfigManager.getPath(); } protected async k8sRequest(path: string, options: RequestPromiseOptions = {}): Promise { - options.headers ??= {} - options.json ??= true - options.timeout ??= 30000 - options.headers.Host = `${this.id}.${new URL(this.kubeProxyUrl).host}` // required in ClusterManager.getClusterForRequest() + options.headers ??= {}; + options.json ??= true; + options.timeout ??= 30000; + options.headers.Host = `${this.id}.${new URL(this.kubeProxyUrl).host}`; // required in ClusterManager.getClusterForRequest() - return request(this.kubeProxyUrl + path, options) + return request(this.kubeProxyUrl + path, options); } getMetrics(prometheusPath: string, queryParams: IMetricsReqParams & { query: string }) { @@ -276,17 +276,17 @@ export class Cluster implements ClusterModel, ClusterState { resolveWithFullResponse: false, json: true, qs: queryParams, - }) + }); } protected async getConnectionStatus(): Promise { try { - const versionDetector = new VersionDetector(this) - const versionData = await versionDetector.detect() - this.metadata.version = versionData.value + const versionDetector = new VersionDetector(this); + const versionData = await versionDetector.detect(); + this.metadata.version = versionData.value; return ClusterStatus.AccessGranted; } catch (error) { - logger.error(`Failed to connect cluster "${this.contextName}": ${error}`) + logger.error(`Failed to connect cluster "${this.contextName}": ${error}`); if (error.statusCode) { if (error.statusCode >= 400 && error.statusCode < 500) { this.failureReason = "Invalid credentials"; @@ -310,17 +310,17 @@ export class Cluster implements ClusterModel, ClusterState { } async canI(resourceAttributes: V1ResourceAttributes): Promise { - const authApi = this.getProxyKubeconfig().makeApiClient(AuthorizationV1Api) + const authApi = this.getProxyKubeconfig().makeApiClient(AuthorizationV1Api); try { const accessReview = await authApi.createSelfSubjectAccessReview({ apiVersion: "authorization.k8s.io/v1", kind: "SelfSubjectAccessReview", spec: { resourceAttributes } - }) - return accessReview.body.status.allowed + }); + return accessReview.body.status.allowed; } catch (error) { - logger.error(`failed to request selfSubjectAccessReview: ${error}`) - return false + logger.error(`failed to request selfSubjectAccessReview: ${error}`); + return false; } } @@ -329,7 +329,7 @@ export class Cluster implements ClusterModel, ClusterState { namespace: "kube-system", resource: "*", verb: "create", - }) + }); } protected async getEventCount(): Promise { @@ -345,7 +345,7 @@ export class Cluster implements ClusterModel, ClusterState { if (w.involvedObject.kind === 'Pod') { try { const { body: pod } = await client.readNamespacedPod(w.involvedObject.name, w.involvedObject.namespace); - logger.debug(`checking pod ${w.involvedObject.namespace}/${w.involvedObject.name}`) + logger.debug(`checking pod ${w.involvedObject.namespace}/${w.involvedObject.name}`); if (podHasIssues(pod)) { uniqEventSources.add(w.involvedObject.uid); } @@ -361,7 +361,7 @@ export class Cluster implements ClusterModel, ClusterState { .reduce((sum, conditions) => sum + conditions.length, 0); return uniqEventSources.size + nodeNotificationCount; } catch (error) { - logger.error("Failed to fetch event count: " + JSON.stringify(error)) + logger.error("Failed to fetch event count: " + JSON.stringify(error)); return 0; } } @@ -379,7 +379,7 @@ export class Cluster implements ClusterModel, ClusterState { }; return toJS(model, { recurseEverything: true - }) + }); } // serializable cluster-state used for sync btw main <-> renderer @@ -399,17 +399,17 @@ export class Cluster implements ClusterModel, ClusterState { }; return toJS(state, { recurseEverything: true - }) + }); } @action setState(state: ClusterState) { - Object.assign(this, state) + Object.assign(this, state); } pushState(state = this.getState()) { logger.silly(`[CLUSTER]: push-state`, state); - broadcastMessage("cluster:state", this.id, state) + broadcastMessage("cluster:state", this.id, state); } // get cluster system meta, e.g. use in "logger" @@ -422,30 +422,30 @@ export class Cluster implements ClusterModel, ClusterState { online: this.online, accessible: this.accessible, disconnected: this.disconnected, - } + }; } protected async getAllowedNamespaces() { if (this.accessibleNamespaces.length) { - return this.accessibleNamespaces + return this.accessibleNamespaces; } - const api = this.getProxyKubeconfig().makeApiClient(CoreV1Api) + const api = this.getProxyKubeconfig().makeApiClient(CoreV1Api); try { - const namespaceList = await api.listNamespace() + const namespaceList = await api.listNamespace(); const nsAccessStatuses = await Promise.all( namespaceList.body.items.map(ns => this.canI({ namespace: ns.metadata.name, resource: "pods", verb: "list", })) - ) + ); return namespaceList.body.items .filter((ns, i) => nsAccessStatuses[i]) - .map(ns => ns.metadata.name) + .map(ns => ns.metadata.name); } catch (error) { - const ctx = this.getProxyKubeconfig().getContextObject(this.contextName) - if (ctx.namespace) return [ctx.namespace] + const ctx = this.getProxyKubeconfig().getContextObject(this.contextName); + if (ctx.namespace) return [ctx.namespace]; return []; } } @@ -462,12 +462,12 @@ export class Cluster implements ClusterModel, ClusterState { verb: "list", namespace: this.allowedNamespaces[0] })) - ) + ); return apiResources .filter((resource, i) => resourceAccessStatuses[i]) - .map(apiResource => apiResource.resource) + .map(apiResource => apiResource.resource); } catch (error) { - return [] + return []; } } } diff --git a/src/main/context-handler.ts b/src/main/context-handler.ts index a3cf6185dd..10f84ced6d 100644 --- a/src/main/context-handler.ts +++ b/src/main/context-handler.ts @@ -1,21 +1,21 @@ -import type { PrometheusProvider, PrometheusService } from "./prometheus/provider-registry" +import type { PrometheusProvider, PrometheusService } from "./prometheus/provider-registry"; import type { ClusterPreferences } from "../common/cluster-store"; -import type { Cluster } from "./cluster" -import type httpProxy from "http-proxy" +import type { Cluster } from "./cluster"; +import type httpProxy from "http-proxy"; import url, { UrlWithStringQuery } from "url"; -import { CoreV1Api } from "@kubernetes/client-node" -import { prometheusProviders } from "../common/prometheus-providers" -import logger from "./logger" -import { getFreePort } from "./port" -import { KubeAuthProxy } from "./kube-auth-proxy" +import { CoreV1Api } from "@kubernetes/client-node"; +import { prometheusProviders } from "../common/prometheus-providers"; +import logger from "./logger"; +import { getFreePort } from "./port"; +import { KubeAuthProxy } from "./kube-auth-proxy"; export class ContextHandler { public proxyPort: number; public clusterUrl: UrlWithStringQuery; - protected kubeAuthProxy: KubeAuthProxy - protected apiTarget: httpProxy.ServerOptions - protected prometheusProvider: string - protected prometheusPath: string + protected kubeAuthProxy: KubeAuthProxy; + protected apiTarget: httpProxy.ServerOptions; + protected prometheusProvider: string; + protected prometheusPath: string; constructor(protected cluster: Cluster) { this.clusterUrl = url.parse(cluster.apiUrl); @@ -26,64 +26,64 @@ export class ContextHandler { this.prometheusProvider = preferences.prometheusProvider?.type; this.prometheusPath = null; if (preferences.prometheus) { - const { namespace, service, port } = preferences.prometheus - this.prometheusPath = `${namespace}/services/${service}:${port}` + const { namespace, service, port } = preferences.prometheus; + this.prometheusPath = `${namespace}/services/${service}:${port}`; } } protected async resolvePrometheusPath(): Promise { - const { service, namespace, port } = await this.getPrometheusService() - return `${namespace}/services/${service}:${port}` + const { service, namespace, port } = await this.getPrometheusService(); + return `${namespace}/services/${service}:${port}`; } async getPrometheusProvider() { if (!this.prometheusProvider) { - const service = await this.getPrometheusService() - logger.info(`using ${service.id} as prometheus provider`) - this.prometheusProvider = service.id + const service = await this.getPrometheusService(); + logger.info(`using ${service.id} as prometheus provider`); + this.prometheusProvider = service.id; } - return prometheusProviders.find(p => p.id === this.prometheusProvider) + return prometheusProviders.find(p => p.id === this.prometheusProvider); } async getPrometheusService(): Promise { const providers = this.prometheusProvider ? prometheusProviders.filter(provider => provider.id == this.prometheusProvider) : prometheusProviders; const prometheusPromises: Promise[] = providers.map(async (provider: PrometheusProvider): Promise => { - const apiClient = this.cluster.getProxyKubeconfig().makeApiClient(CoreV1Api) - return await provider.getPrometheusService(apiClient) - }) - const resolvedPrometheusServices = await Promise.all(prometheusPromises) + const apiClient = this.cluster.getProxyKubeconfig().makeApiClient(CoreV1Api); + return await provider.getPrometheusService(apiClient); + }); + const resolvedPrometheusServices = await Promise.all(prometheusPromises); const service = resolvedPrometheusServices.filter(n => n)[0]; return service || { id: "lens", namespace: "lens-metrics", service: "prometheus", port: 80 - } + }; } async getPrometheusPath(): Promise { if (!this.prometheusPath) { - this.prometheusPath = await this.resolvePrometheusPath() + this.prometheusPath = await this.resolvePrometheusPath(); } return this.prometheusPath; } async resolveAuthProxyUrl() { const proxyPort = await this.ensurePort(); - const path = this.clusterUrl.path !== "/" ? this.clusterUrl.path : "" + const path = this.clusterUrl.path !== "/" ? this.clusterUrl.path : ""; return `http://127.0.0.1:${proxyPort}${path}`; } async getApiTarget(isWatchRequest = false): Promise { if (this.apiTarget && !isWatchRequest) { - return this.apiTarget + return this.apiTarget; } - const timeout = isWatchRequest ? 4 * 60 * 60 * 1000 : 30000 // 4 hours for watch request, 30 seconds for the rest - const apiTarget = await this.newApiTarget(timeout) + const timeout = isWatchRequest ? 4 * 60 * 60 * 1000 : 30000; // 4 hours for watch request, 30 seconds for the rest + const apiTarget = await this.newApiTarget(timeout); if (!isWatchRequest) { - this.apiTarget = apiTarget + this.apiTarget = apiTarget; } - return apiTarget + return apiTarget; } protected async newApiTarget(timeout: number): Promise { @@ -95,36 +95,36 @@ export class ContextHandler { headers: { "Host": this.clusterUrl.hostname, }, - } + }; } async ensurePort(): Promise { if (!this.proxyPort) { this.proxyPort = await getFreePort(); } - return this.proxyPort + return this.proxyPort; } async ensureServer() { if (!this.kubeAuthProxy) { await this.ensurePort(); - const proxyEnv = Object.assign({}, process.env) + const proxyEnv = Object.assign({}, process.env); if (this.cluster.preferences.httpsProxy) { - proxyEnv.HTTPS_PROXY = this.cluster.preferences.httpsProxy + proxyEnv.HTTPS_PROXY = this.cluster.preferences.httpsProxy; } - this.kubeAuthProxy = new KubeAuthProxy(this.cluster, this.proxyPort, proxyEnv) - await this.kubeAuthProxy.run() + this.kubeAuthProxy = new KubeAuthProxy(this.cluster, this.proxyPort, proxyEnv); + await this.kubeAuthProxy.run(); } } stopServer() { if (this.kubeAuthProxy) { - this.kubeAuthProxy.exit() - this.kubeAuthProxy = null + this.kubeAuthProxy.exit(); + this.kubeAuthProxy = null; } } get proxyLastError(): string { - return this.kubeAuthProxy?.lastError || "" + return this.kubeAuthProxy?.lastError || ""; } } diff --git a/src/main/exit-app.ts b/src/main/exit-app.ts index bf73e022f3..b58a6e4dfc 100644 --- a/src/main/exit-app.ts +++ b/src/main/exit-app.ts @@ -6,13 +6,13 @@ import logger from "./logger"; export function exitApp() { - const windowManager = WindowManager.getInstance() - const clusterManager = ClusterManager.getInstance() - appEventBus.emit({ name: "service", action: "close" }) + const windowManager = WindowManager.getInstance(); + const clusterManager = ClusterManager.getInstance(); + appEventBus.emit({ name: "service", action: "close" }); windowManager.hide(); clusterManager.stop(); logger.info('SERVICE:QUIT'); setTimeout(() => { - app.exit() - }, 1000) + app.exit(); + }, 1000); } \ No newline at end of file diff --git a/src/main/helm/helm-chart-manager.ts b/src/main/helm/helm-chart-manager.ts index e42f7a1aaf..42c1a30ed2 100644 --- a/src/main/helm/helm-chart-manager.ts +++ b/src/main/helm/helm-chart-manager.ts @@ -1,74 +1,74 @@ import fs from "fs"; import * as yaml from "js-yaml"; -import { HelmRepo, HelmRepoManager } from "./helm-repo-manager" +import { HelmRepo, HelmRepoManager } from "./helm-repo-manager"; import logger from "../logger"; -import { promiseExec } from "../promise-exec" -import { helmCli } from "./helm-cli" +import { promiseExec } from "../promise-exec"; +import { helmCli } from "./helm-cli"; type CachedYaml = { entries: any; // todo: types -} +}; export class HelmChartManager { - protected cache: any = {} - protected repo: HelmRepo + protected cache: any = {}; + protected repo: HelmRepo; constructor(repo: HelmRepo){ - this.cache = HelmRepoManager.cache - this.repo = repo + this.cache = HelmRepoManager.cache; + this.repo = repo; } public async chart(name: string) { - const charts = await this.charts() - return charts[name] + const charts = await this.charts(); + return charts[name]; } public async charts(): Promise { try { - const cachedYaml = await this.cachedYaml() - return cachedYaml["entries"] + const cachedYaml = await this.cachedYaml(); + return cachedYaml["entries"]; } catch(error) { - logger.error(error) - return [] + logger.error(error); + return []; } } public async getReadme(name: string, version = "") { - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); if(version && version != "") { - const { stdout, stderr} = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr)}) - return stdout + const { stdout, stderr} = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr);}); + return stdout; } else { - const { stdout, stderr} = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr)}) - return stdout + const { stdout, stderr} = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr);}); + return stdout; } } public async getValues(name: string, version = "") { - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); if(version && version != "") { - const { stdout, stderr} = await promiseExec(`"${helm}" show values ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr)}) + const { stdout, stderr} = await promiseExec(`"${helm}" show values ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr);}); - return stdout + return stdout; } else { - const { stdout, stderr} = await promiseExec(`"${helm}" show values ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr)}) + const { stdout, stderr} = await promiseExec(`"${helm}" show values ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr);}); - return stdout + return stdout; } } protected async cachedYaml(): Promise { if (!(this.repo.name in this.cache)) { - const cacheFile = await fs.promises.readFile(this.repo.cacheFilePath, 'utf-8') - const data = yaml.safeLoad(cacheFile) + const cacheFile = await fs.promises.readFile(this.repo.cacheFilePath, 'utf-8'); + const data = yaml.safeLoad(cacheFile); for(const key in data["entries"]) { data["entries"][key].forEach((version: any) => { - version['repo'] = this.repo.name - version['created'] = Date.parse(version.created).toString() - }) + version['repo'] = this.repo.name; + version['created'] = Date.parse(version.created).toString(); + }); } - this.cache[this.repo.name] = Buffer.from(JSON.stringify(data)) + this.cache[this.repo.name] = Buffer.from(JSON.stringify(data)); } - return JSON.parse(this.cache[this.repo.name].toString()) + return JSON.parse(this.cache[this.repo.name].toString()); } } diff --git a/src/main/helm/helm-cli.ts b/src/main/helm/helm-cli.ts index 1484ceacf1..34a3becc33 100644 --- a/src/main/helm/helm-cli.ts +++ b/src/main/helm/helm-cli.ts @@ -1,6 +1,6 @@ -import packageInfo from "../../../package.json" -import path from "path" -import { LensBinary, LensBinaryOpts } from "../lens-binary" +import packageInfo from "../../../package.json"; +import path from "path"; +import { LensBinary, LensBinaryOpts } from "../lens-binary"; import { isProduction } from "../../common/vars"; export class HelmCli extends LensBinary { @@ -11,24 +11,24 @@ export class HelmCli extends LensBinary { baseDir: baseDir, originalBinaryName: "helm", newBinaryName: "helm3" - } - super(opts) + }; + super(opts); } protected getTarName(): string | null { - return `${this.binaryName}-v${this.binaryVersion}-${this.platformName}-${this.arch}.tar.gz` + return `${this.binaryName}-v${this.binaryVersion}-${this.platformName}-${this.arch}.tar.gz`; } protected getUrl() { - return `https://get.helm.sh/helm-v${this.binaryVersion}-${this.platformName}-${this.arch}.tar.gz` + return `https://get.helm.sh/helm-v${this.binaryVersion}-${this.platformName}-${this.arch}.tar.gz`; } protected getBinaryPath() { - return path.join(this.dirname, this.binaryName) + return path.join(this.dirname, this.binaryName); } protected getOriginalBinaryPath() { - return path.join(this.dirname, this.platformName + "-" + this.arch, this.originalBinaryName) + return path.join(this.dirname, this.platformName + "-" + this.arch, this.originalBinaryName); } } diff --git a/src/main/helm/helm-release-manager.ts b/src/main/helm/helm-release-manager.ts index 80be023227..3a8b4707ba 100644 --- a/src/main/helm/helm-release-manager.ts +++ b/src/main/helm/helm-release-manager.ts @@ -1,7 +1,7 @@ import * as tempy from "tempy"; import fs from "fs"; import * as yaml from "js-yaml"; -import { promiseExec} from "../promise-exec" +import { promiseExec} from "../promise-exec"; import { helmCli } from "./helm-cli"; import { Cluster } from "../cluster"; import { toCamelCase } from "../../common/utils/camelCase"; @@ -9,103 +9,103 @@ import { toCamelCase } from "../../common/utils/camelCase"; export class HelmReleaseManager { public async listReleases(pathToKubeconfig: string, namespace?: string) { - const helm = await helmCli.binaryPath() - const namespaceFlag = namespace ? `-n ${namespace}` : "--all-namespaces" - const { stdout } = await promiseExec(`"${helm}" ls --output json ${namespaceFlag} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)}) + const helm = await helmCli.binaryPath(); + const namespaceFlag = namespace ? `-n ${namespace}` : "--all-namespaces"; + const { stdout } = await promiseExec(`"${helm}" ls --output json ${namespaceFlag} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); - const output = JSON.parse(stdout) + const output = JSON.parse(stdout); if (output.length == 0) { - return output + return output; } output.forEach((release: any, index: number) => { - output[index] = toCamelCase(release) + output[index] = toCamelCase(release); }); - return output + return output; } public async installChart(chart: string, values: any, name: string, namespace: string, version: string, pathToKubeconfig: string){ - const helm = await helmCli.binaryPath() - const fileName = tempy.file({name: "values.yaml"}) - await fs.promises.writeFile(fileName, yaml.safeDump(values)) + const helm = await helmCli.binaryPath(); + const fileName = tempy.file({name: "values.yaml"}); + await fs.promises.writeFile(fileName, yaml.safeDump(values)); try { - let generateName = "" + let generateName = ""; if (!name) { - generateName = "--generate-name" - name = "" + generateName = "--generate-name"; + name = ""; } - const { stdout, stderr } = await promiseExec(`"${helm}" install ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${pathToKubeconfig} ${generateName}`).catch((error) => { throw(error.stderr)}) - const releaseName = stdout.split("\n")[0].split(' ')[1].trim() + const { stdout, stderr } = await promiseExec(`"${helm}" install ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${pathToKubeconfig} ${generateName}`).catch((error) => { throw(error.stderr);}); + const releaseName = stdout.split("\n")[0].split(' ')[1].trim(); return { log: stdout, release: { name: releaseName, namespace: namespace } - } + }; } finally { - await fs.promises.unlink(fileName) + await fs.promises.unlink(fileName); } } public async upgradeRelease(name: string, chart: string, values: any, namespace: string, version: string, cluster: Cluster){ - const helm = await helmCli.binaryPath() - const fileName = tempy.file({name: "values.yaml"}) - await fs.promises.writeFile(fileName, yaml.safeDump(values)) + const helm = await helmCli.binaryPath(); + const fileName = tempy.file({name: "values.yaml"}); + await fs.promises.writeFile(fileName, yaml.safeDump(values)); try { - const { stdout, stderr } = await promiseExec(`"${helm}" upgrade ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr)}) + const { stdout, stderr } = await promiseExec(`"${helm}" upgrade ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr);}); return { log: stdout, release: this.getRelease(name, namespace, cluster) - } + }; } finally { - await fs.promises.unlink(fileName) + await fs.promises.unlink(fileName); } } public async getRelease(name: string, namespace: string, cluster: Cluster) { - const helm = await helmCli.binaryPath() - const {stdout, stderr} = await promiseExec(`"${helm}" status ${name} --output json --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr)}) - const release = JSON.parse(stdout) - release.resources = await this.getResources(name, namespace, cluster) - return release + const helm = await helmCli.binaryPath(); + const {stdout, stderr} = await promiseExec(`"${helm}" status ${name} --output json --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr);}); + const release = JSON.parse(stdout); + release.resources = await this.getResources(name, namespace, cluster); + return release; } public async deleteRelease(name: string, namespace: string, pathToKubeconfig: string) { - const helm = await helmCli.binaryPath() - const { stdout, stderr } = await promiseExec(`"${helm}" delete ${name} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)}) + const helm = await helmCli.binaryPath(); + const { stdout, stderr } = await promiseExec(`"${helm}" delete ${name} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); - return stdout + return stdout; } public async getValues(name: string, namespace: string, pathToKubeconfig: string) { - const helm = await helmCli.binaryPath() - const { stdout, stderr } = await promiseExec(`"${helm}" get values ${name} --all --output yaml --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)}) - return stdout + const helm = await helmCli.binaryPath(); + const { stdout, stderr } = await promiseExec(`"${helm}" get values ${name} --all --output yaml --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); + return stdout; } public async getHistory(name: string, namespace: string, pathToKubeconfig: string) { - const helm = await helmCli.binaryPath() - const {stdout, stderr} = await promiseExec(`"${helm}" history ${name} --output json --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)}) - return JSON.parse(stdout) + const helm = await helmCli.binaryPath(); + const {stdout, stderr} = await promiseExec(`"${helm}" history ${name} --output json --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); + return JSON.parse(stdout); } public async rollback(name: string, namespace: string, revision: number, pathToKubeconfig: string) { - const helm = await helmCli.binaryPath() - const {stdout, stderr} = await promiseExec(`"${helm}" rollback ${name} ${revision} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)}) - return stdout + const helm = await helmCli.binaryPath(); + const {stdout, stderr} = await promiseExec(`"${helm}" rollback ${name} ${revision} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); + return stdout; } protected async getResources(name: string, namespace: string, cluster: Cluster) { - const helm = await helmCli.binaryPath() - const kubectl = await cluster.kubeCtl.getPath() - const pathToKubeconfig = cluster.getProxyKubeconfigPath() + const helm = await helmCli.binaryPath(); + const kubectl = await cluster.kubeCtl.getPath(); + const pathToKubeconfig = cluster.getProxyKubeconfigPath(); const { stdout } = await promiseExec(`"${helm}" get manifest ${name} --namespace ${namespace} --kubeconfig ${pathToKubeconfig} | "${kubectl}" get -n ${namespace} --kubeconfig ${pathToKubeconfig} -f - -o=json`).catch((error) => { - return { stdout: JSON.stringify({items: []})} - }) - return stdout + return { stdout: JSON.stringify({items: []})}; + }); + return stdout; } } -export const releaseManager = new HelmReleaseManager() +export const releaseManager = new HelmReleaseManager(); diff --git a/src/main/helm/helm-repo-manager.ts b/src/main/helm/helm-repo-manager.ts index c2af9ea7ba..dff372a301 100644 --- a/src/main/helm/helm-repo-manager.ts +++ b/src/main/helm/helm-repo-manager.ts @@ -10,7 +10,7 @@ import logger from "../logger"; export type HelmEnv = Record & { HELM_REPOSITORY_CACHE?: string; HELM_REPOSITORY_CONFIG?: string; -} +}; export interface HelmRepoConfig { repositories: HelmRepo[] @@ -29,11 +29,11 @@ export interface HelmRepo { } export class HelmRepoManager extends Singleton { - static cache = {} // todo: remove implicit updates in helm-chart-manager.ts + static cache = {}; // todo: remove implicit updates in helm-chart-manager.ts protected repos: HelmRepo[]; - protected helmEnv: HelmEnv - protected initialized: boolean + protected helmEnv: HelmEnv; + protected initialized: boolean; async loadAvailableRepos(): Promise { const res = await customRequestPromise({ @@ -46,34 +46,34 @@ export class HelmRepoManager extends Singleton { } async init() { - helmCli.setLogger(logger) + helmCli.setLogger(logger); await helmCli.ensureBinary(); if (!this.initialized) { - this.helmEnv = await this.parseHelmEnv() - await this.update() - this.initialized = true + this.helmEnv = await this.parseHelmEnv(); + await this.update(); + this.initialized = true; } } protected async parseHelmEnv() { - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); const { stdout } = await promiseExec(`"${helm}" env`).catch((error) => { - throw(error.stderr) - }) - const lines = stdout.split(/\r?\n/) // split by new line feed - const env: HelmEnv = {} + throw(error.stderr); + }); + const lines = stdout.split(/\r?\n/); // split by new line feed + const env: HelmEnv = {}; lines.forEach((line: string) => { - const [key, value] = line.split("=") + const [key, value] = line.split("="); if (key && value) { - env[key] = value.replace(/"/g, "") // strip quotas + env[key] = value.replace(/"/g, ""); // strip quotas } - }) - return env + }); + return env; } public async repositories(): Promise { if (!this.initialized) { - await this.init() + await this.init(); } try { const repoConfigFile = this.helmEnv.HELM_REPOSITORY_CONFIG; @@ -91,41 +91,41 @@ export class HelmRepoManager extends Singleton { cacheFilePath: `${this.helmEnv.HELM_REPOSITORY_CACHE}/${repo.name}-index.yaml` })); } catch (error) { - logger.error(`[HELM]: repositories listing error "${error}"`) - return [] + logger.error(`[HELM]: repositories listing error "${error}"`); + return []; } } public async repository(name: string) { - const repositories = await this.repositories() + const repositories = await this.repositories(); return repositories.find(repo => repo.name == name); } public async update() { - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); const { stdout } = await promiseExec(`"${helm}" repo update`).catch((error) => { - return { stdout: error.stdout } - }) - return stdout + return { stdout: error.stdout }; + }); + return stdout; } public async addRepo({ name, url }: HelmRepo) { logger.info(`[HELM]: adding repo "${name}" from ${url}`); - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); const { stdout } = await promiseExec(`"${helm}" repo add ${name} ${url}`).catch((error) => { - throw(error.stderr) - }) - return stdout + throw(error.stderr); + }); + return stdout; } public async removeRepo({ name, url }: HelmRepo): Promise { logger.info(`[HELM]: removing repo "${name}" from ${url}`); - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); const { stdout, stderr } = await promiseExec(`"${helm}" repo remove ${name}`).catch((error) => { - throw(error.stderr) - }) - return stdout + throw(error.stderr); + }); + return stdout; } } -export const repoManager = HelmRepoManager.getInstance() +export const repoManager = HelmRepoManager.getInstance(); diff --git a/src/main/helm/helm-service.ts b/src/main/helm/helm-service.ts index 664a30358c..88ca4dda3e 100644 --- a/src/main/helm/helm-service.ts +++ b/src/main/helm/helm-service.ts @@ -6,93 +6,93 @@ import { releaseManager } from "./helm-release-manager"; class HelmService { public async installChart(cluster: Cluster, data: { chart: string; values: {}; name: string; namespace: string; version: string }) { - return await releaseManager.installChart(data.chart, data.values, data.name, data.namespace, data.version, cluster.getProxyKubeconfigPath()) + return await releaseManager.installChart(data.chart, data.values, data.name, data.namespace, data.version, cluster.getProxyKubeconfigPath()); } public async listCharts() { - const charts: any = {} - await repoManager.init() - const repositories = await repoManager.repositories() + const charts: any = {}; + await repoManager.init(); + const repositories = await repoManager.repositories(); for (const repo of repositories) { - charts[repo.name] = {} - const manager = new HelmChartManager(repo) - let entries = await manager.charts() - entries = this.excludeDeprecated(entries) + charts[repo.name] = {}; + const manager = new HelmChartManager(repo); + let entries = await manager.charts(); + entries = this.excludeDeprecated(entries); for (const key in entries) { - entries[key] = entries[key][0] + entries[key] = entries[key][0]; } - charts[repo.name] = entries + charts[repo.name] = entries; } - return charts + return charts; } public async getChart(repoName: string, chartName: string, version = "") { const result = { readme: "", versions: {} - } - const repo = await repoManager.repository(repoName) - const chartManager = new HelmChartManager(repo) - const chart = await chartManager.chart(chartName) - result.readme = await chartManager.getReadme(chartName, version) - result.versions = chart - return result + }; + const repo = await repoManager.repository(repoName); + const chartManager = new HelmChartManager(repo); + const chart = await chartManager.chart(chartName); + result.readme = await chartManager.getReadme(chartName, version); + result.versions = chart; + return result; } public async getChartValues(repoName: string, chartName: string, version = "") { - const repo = await repoManager.repository(repoName) - const chartManager = new HelmChartManager(repo) - return chartManager.getValues(chartName, version) + const repo = await repoManager.repository(repoName); + const chartManager = new HelmChartManager(repo); + return chartManager.getValues(chartName, version); } public async listReleases(cluster: Cluster, namespace: string = null) { - await repoManager.init() - return await releaseManager.listReleases(cluster.getProxyKubeconfigPath(), namespace) + await repoManager.init(); + return await releaseManager.listReleases(cluster.getProxyKubeconfigPath(), namespace); } public async getRelease(cluster: Cluster, releaseName: string, namespace: string) { - logger.debug("Fetch release") - return await releaseManager.getRelease(releaseName, namespace, cluster) + logger.debug("Fetch release"); + return await releaseManager.getRelease(releaseName, namespace, cluster); } public async getReleaseValues(cluster: Cluster, releaseName: string, namespace: string) { - logger.debug("Fetch release values") - return await releaseManager.getValues(releaseName, namespace, cluster.getProxyKubeconfigPath()) + logger.debug("Fetch release values"); + return await releaseManager.getValues(releaseName, namespace, cluster.getProxyKubeconfigPath()); } public async getReleaseHistory(cluster: Cluster, releaseName: string, namespace: string) { - logger.debug("Fetch release history") - return await releaseManager.getHistory(releaseName, namespace, cluster.getProxyKubeconfigPath()) + logger.debug("Fetch release history"); + return await releaseManager.getHistory(releaseName, namespace, cluster.getProxyKubeconfigPath()); } public async deleteRelease(cluster: Cluster, releaseName: string, namespace: string) { - logger.debug("Delete release") - return await releaseManager.deleteRelease(releaseName, namespace, cluster.getProxyKubeconfigPath()) + logger.debug("Delete release"); + return await releaseManager.deleteRelease(releaseName, namespace, cluster.getProxyKubeconfigPath()); } public async updateRelease(cluster: Cluster, releaseName: string, namespace: string, data: { chart: string; values: {}; version: string }) { - logger.debug("Upgrade release") - return await releaseManager.upgradeRelease(releaseName, data.chart, data.values, namespace, data.version, cluster) + logger.debug("Upgrade release"); + return await releaseManager.upgradeRelease(releaseName, data.chart, data.values, namespace, data.version, cluster); } public async rollback(cluster: Cluster, releaseName: string, namespace: string, revision: number) { - logger.debug("Rollback release") - const output = await releaseManager.rollback(releaseName, namespace, revision, cluster.getProxyKubeconfigPath()) - return { message: output } + logger.debug("Rollback release"); + const output = await releaseManager.rollback(releaseName, namespace, revision, cluster.getProxyKubeconfigPath()); + return { message: output }; } protected excludeDeprecated(entries: any) { for (const key in entries) { entries[key] = entries[key].filter((entry: any) => { if (Array.isArray(entry)) { - return entry[0]['deprecated'] != true + return entry[0]['deprecated'] != true; } - return entry["deprecated"] != true - }) + return entry["deprecated"] != true; + }); } - return entries + return entries; } } -export const helmService = new HelmService() +export const helmService = new HelmService(); diff --git a/src/main/index.ts b/src/main/index.ts index e360c2fe85..2087432d7b 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,25 +1,25 @@ // Main process -import "../common/system-ca" -import "../common/prometheus-providers" -import * as Mobx from "mobx" +import "../common/system-ca"; +import "../common/prometheus-providers"; +import * as Mobx from "mobx"; import * as LensExtensions from "../extensions/core-api"; -import { app, dialog } from "electron" +import { app, dialog } from "electron"; import { appName } from "../common/vars"; -import path from "path" -import { LensProxy } from "./lens-proxy" +import path from "path"; +import { LensProxy } from "./lens-proxy"; import { WindowManager } from "./window-manager"; import { ClusterManager } from "./cluster-manager"; -import { AppUpdater } from "./app-updater" -import { shellSync } from "./shell-sync" -import { getFreePort } from "./port" -import { mangleProxyEnv } from "./proxy-env" +import { AppUpdater } from "./app-updater"; +import { shellSync } from "./shell-sync"; +import { getFreePort } from "./port"; +import { mangleProxyEnv } from "./proxy-env"; import { registerFileProtocol } from "../common/register-protocol"; -import logger from "./logger" -import { clusterStore } from "../common/cluster-store" +import logger from "./logger"; +import { clusterStore } from "../common/cluster-store"; import { userStore } from "../common/user-store"; import { workspaceStore } from "../common/workspace-store"; -import { appEventBus } from "../common/event-bus" +import { appEventBus } from "../common/event-bus"; import { extensionLoader } from "../extensions/extension-loader"; import { extensionManager } from "../extensions/extension-manager"; import { extensionsStore } from "../extensions/extensions-store"; @@ -35,16 +35,16 @@ if (!process.env.CICD) { app.setPath("userData", workingDir); } -mangleProxyEnv() +mangleProxyEnv(); if (app.commandLine.getSwitchValue("proxy-server") !== "") { - process.env.HTTPS_PROXY = app.commandLine.getSwitchValue("proxy-server") + process.env.HTTPS_PROXY = app.commandLine.getSwitchValue("proxy-server"); } app.on("ready", async () => { - logger.info(`🚀 Starting Lens from "${workingDir}"`) + logger.info(`🚀 Starting Lens from "${workingDir}"`); await shellSync(); - const updater = new AppUpdater() + const updater = new AppUpdater(); updater.start(); registerFileProtocol("static", __static); @@ -59,10 +59,10 @@ app.on("ready", async () => { // find free port try { - proxyPort = await getFreePort() + proxyPort = await getFreePort(); } catch (error) { - logger.error(error) - dialog.showErrorBox("Lens Error", "Could not find a free port for the cluster proxy") + logger.error(error); + dialog.showErrorBox("Lens Error", "Could not find a free port for the cluster proxy"); app.exit(); } @@ -73,22 +73,22 @@ app.on("ready", async () => { try { proxyServer = LensProxy.create(proxyPort, clusterManager); } catch (error) { - logger.error(`Could not start proxy (127.0.0:${proxyPort}): ${error.message}`) - dialog.showErrorBox("Lens Error", `Could not start proxy (127.0.0:${proxyPort}): ${error.message || "unknown error"}`) + logger.error(`Could not start proxy (127.0.0:${proxyPort}): ${error.message}`); + dialog.showErrorBox("Lens Error", `Could not start proxy (127.0.0:${proxyPort}): ${error.message || "unknown error"}`); app.exit(); } - extensionLoader.init() + extensionLoader.init(); windowManager = WindowManager.getInstance(proxyPort); extensionLoader.initExtensions(await extensionManager.load()); // call after windowManager to see splash earlier setTimeout(() => { - appEventBus.emit({ name: "service", action: "start" }) - }, 1000) + appEventBus.emit({ name: "service", action: "start" }); + }, 1000); }); app.on("activate", (event, hasVisibleWindows) => { - logger.info('APP:ACTIVATE', { hasVisibleWindows }) + logger.info('APP:ACTIVATE', { hasVisibleWindows }); if (!hasVisibleWindows) { windowManager.initMainWindow(); } @@ -97,11 +97,11 @@ app.on("activate", (event, hasVisibleWindows) => { // Quit app on Cmd+Q (MacOS) app.on("will-quit", (event) => { logger.info('APP:QUIT'); - appEventBus.emit({name: "app", action: "close"}) + appEventBus.emit({name: "app", action: "close"}); event.preventDefault(); // prevent app's default shutdown (e.g. required for telemetry, etc.) clusterManager?.stop(); // close cluster connections return; // skip exit to make tray work, to quit go to app's global menu or tray's menu -}) +}); // Extensions-api runtime exports export const LensExtensionsApi = { @@ -111,4 +111,4 @@ export const LensExtensionsApi = { export { Mobx, LensExtensionsApi as LensExtensions, -} +}; diff --git a/src/main/kube-auth-proxy.ts b/src/main/kube-auth-proxy.ts index 5377ecb829..3ad76e52b0 100644 --- a/src/main/kube-auth-proxy.ts +++ b/src/main/kube-auth-proxy.ts @@ -1,10 +1,10 @@ -import { ChildProcess, spawn } from "child_process" +import { ChildProcess, spawn } from "child_process"; import { waitUntilUsed } from "tcp-port-used"; import { broadcastMessage } from "../common/ipc"; -import type { Cluster } from "./cluster" -import { Kubectl } from "./kubectl" -import logger from "./logger" -import * as url from "url" +import type { Cluster } from "./cluster"; +import { Kubectl } from "./kubectl"; +import logger from "./logger"; +import * as url from "url"; export interface KubeAuthProxyLog { data: string; @@ -12,19 +12,19 @@ export interface KubeAuthProxyLog { } export class KubeAuthProxy { - public lastError: string + public lastError: string; - protected cluster: Cluster - protected env: NodeJS.ProcessEnv = null - protected proxyProcess: ChildProcess - protected port: number - protected kubectl: Kubectl + protected cluster: Cluster; + protected env: NodeJS.ProcessEnv = null; + protected proxyProcess: ChildProcess; + protected port: number; + protected kubectl: Kubectl; constructor(cluster: Cluster, port: number, env: NodeJS.ProcessEnv) { - this.env = env - this.port = port - this.cluster = cluster - this.kubectl = Kubectl.bundled() + this.env = env; + this.port = port; + this.cluster = cluster; + this.kubectl = Kubectl.bundled(); } get acceptHosts() { @@ -36,7 +36,7 @@ export class KubeAuthProxy { return; } - const proxyBin = await this.kubectl.getPath() + const proxyBin = await this.kubectl.getPath(); const args = [ "proxy", "-p", `${this.port}`, @@ -44,63 +44,63 @@ export class KubeAuthProxy { "--context", `${this.cluster.contextName}`, "--accept-hosts", this.acceptHosts, "--reject-paths", "^[^/]" - ] + ]; if (process.env.DEBUG_PROXY === "true") { - args.push("-v", "9") + args.push("-v", "9"); } - logger.debug(`spawning kubectl proxy with args: ${args}`) - this.proxyProcess = spawn(proxyBin, args, { env: this.env, }) + logger.debug(`spawning kubectl proxy with args: ${args}`); + this.proxyProcess = spawn(proxyBin, args, { env: this.env, }); this.proxyProcess.on("error", (error) => { - this.sendIpcLogMessage({ data: error.message, error: true }) - this.exit() - }) + this.sendIpcLogMessage({ data: error.message, error: true }); + this.exit(); + }); this.proxyProcess.on("exit", (code) => { - this.sendIpcLogMessage({ data: `proxy exited with code: ${code}`, error: code > 0 }) + this.sendIpcLogMessage({ data: `proxy exited with code: ${code}`, error: code > 0 }); this.exit(); - }) + }); this.proxyProcess.stdout.on('data', (data) => { - let logItem = data.toString() + let logItem = data.toString(); if (logItem.startsWith("Starting to serve on")) { - logItem = "Authentication proxy started\n" + logItem = "Authentication proxy started\n"; } - this.sendIpcLogMessage({ data: logItem }) - }) + this.sendIpcLogMessage({ data: logItem }); + }); this.proxyProcess.stderr.on('data', (data) => { - this.lastError = this.parseError(data.toString()) - this.sendIpcLogMessage({ data: data.toString(), error: true }) - }) + this.lastError = this.parseError(data.toString()); + this.sendIpcLogMessage({ data: data.toString(), error: true }); + }); - return waitUntilUsed(this.port, 500, 10000) + return waitUntilUsed(this.port, 500, 10000); } protected parseError(data: string) { - const error = data.split("http: proxy error:").slice(1).join("").trim() - let errorMsg = error - const jsonError = error.split("Response: ")[1] + const error = data.split("http: proxy error:").slice(1).join("").trim(); + let errorMsg = error; + const jsonError = error.split("Response: ")[1]; if (jsonError) { try { - const parsedError = JSON.parse(jsonError) - errorMsg = parsedError.error_description || parsedError.error || jsonError + const parsedError = JSON.parse(jsonError); + errorMsg = parsedError.error_description || parsedError.error || jsonError; } catch (_) { - errorMsg = jsonError.trim() + errorMsg = jsonError.trim(); } } - return errorMsg + return errorMsg; } protected async sendIpcLogMessage(res: KubeAuthProxyLog) { - const channel = `kube-auth:${this.cluster.id}` + const channel = `kube-auth:${this.cluster.id}`; logger.info(`[KUBE-AUTH]: out-channel "${channel}"`, { ...res, meta: this.cluster.getMeta() }); - broadcastMessage(channel, res) + broadcastMessage(channel, res); } public exit() { if (!this.proxyProcess) return; - logger.debug("[KUBE-AUTH]: stopping local proxy", this.cluster.getMeta()) - this.proxyProcess.kill() + logger.debug("[KUBE-AUTH]: stopping local proxy", this.cluster.getMeta()); + this.proxyProcess.kill(); this.proxyProcess.removeAllListeners(); this.proxyProcess.stderr.removeAllListeners(); this.proxyProcess.stdout.removeAllListeners(); diff --git a/src/main/kubeconfig-manager.ts b/src/main/kubeconfig-manager.ts index fc84d00ddb..a8b3ae3fce 100644 --- a/src/main/kubeconfig-manager.ts +++ b/src/main/kubeconfig-manager.ts @@ -1,22 +1,22 @@ import type { KubeConfig } from "@kubernetes/client-node"; -import type { Cluster } from "./cluster" +import type { Cluster } from "./cluster"; import type { ContextHandler } from "./context-handler"; -import { app } from "electron" -import path from "path" -import fs from "fs-extra" -import { dumpConfigYaml, loadConfig } from "../common/kube-helpers" -import logger from "./logger" +import { app } from "electron"; +import path from "path"; +import fs from "fs-extra"; +import { dumpConfigYaml, loadConfig } from "../common/kube-helpers"; +import logger from "./logger"; export class KubeconfigManager { - protected configDir = app.getPath("temp") + protected configDir = app.getPath("temp"); protected tempFile: string; private constructor(protected cluster: Cluster, protected contextHandler: ContextHandler, protected port: number) { } static async create(cluster: Cluster, contextHandler: ContextHandler, port: number) { - const kcm = new KubeconfigManager(cluster, contextHandler, port) - await kcm.init() - return kcm + const kcm = new KubeconfigManager(cluster, contextHandler, port); + await kcm.init(); + return kcm; } protected async init() { @@ -24,7 +24,7 @@ export class KubeconfigManager { await this.contextHandler.ensurePort(); await this.createProxyKubeconfig(); } catch (err) { - logger.error(`Failed to created temp config for auth-proxy`, { err }) + logger.error(`Failed to created temp config for auth-proxy`, { err }); } } @@ -33,7 +33,7 @@ export class KubeconfigManager { } protected resolveProxyUrl() { - return `http://127.0.0.1:${this.port}/${this.cluster.id}` + return `http://127.0.0.1:${this.port}/${this.cluster.id}`; } /** @@ -78,11 +78,11 @@ export class KubeconfigManager { async unlink() { if (!this.tempFile) { - return + return; } - logger.info('Deleting temporary kubeconfig: ' + this.tempFile) - await fs.unlink(this.tempFile) - this.tempFile = undefined + logger.info('Deleting temporary kubeconfig: ' + this.tempFile); + await fs.unlink(this.tempFile); + this.tempFile = undefined; } } diff --git a/src/main/kubectl.ts b/src/main/kubectl.ts index 6b2f51476d..5d3f12746e 100644 --- a/src/main/kubectl.ts +++ b/src/main/kubectl.ts @@ -1,17 +1,17 @@ -import { app, remote } from "electron" -import path from "path" -import fs from "fs" -import { promiseExec } from "./promise-exec" -import logger from "./logger" -import { ensureDir, pathExists } from "fs-extra" -import * as lockFile from "proper-lockfile" -import { helmCli } from "./helm/helm-cli" -import { userStore } from "../common/user-store" +import { app, remote } from "electron"; +import path from "path"; +import fs from "fs"; +import { promiseExec } from "./promise-exec"; +import logger from "./logger"; +import { ensureDir, pathExists } from "fs-extra"; +import * as lockFile from "proper-lockfile"; +import { helmCli } from "./helm/helm-cli"; +import { userStore } from "../common/user-store"; import { customRequest } from "../common/request"; -import { getBundledKubectlVersion } from "../common/utils/app-version" +import { getBundledKubectlVersion } from "../common/utils/app-version"; import { isDevelopment, isWindows, isTestEnv } from "../common/vars"; -const bundledVersion = getBundledKubectlVersion() +const bundledVersion = getBundledKubectlVersion(); const kubectlMap: Map = new Map([ ["1.7", "1.8.15"], ["1.8", "1.9.10"], @@ -26,314 +26,314 @@ const kubectlMap: Map = new Map([ ["1.17", bundledVersion], ["1.18", "1.18.8"], ["1.19", "1.19.0"] -]) +]); const packageMirrors: Map = new Map([ ["default", "https://storage.googleapis.com/kubernetes-release/release"], ["china", "https://mirror.azure.cn/kubernetes/kubectl"] -]) +]); -let bundledPath: string -const initScriptVersionString = "# lens-initscript v3\n" +let bundledPath: string; +const initScriptVersionString = "# lens-initscript v3\n"; export function bundledKubectlPath(): string { - if (bundledPath) { return bundledPath } + if (bundledPath) { return bundledPath; } if (isDevelopment || isTestEnv) { - const platformName = isWindows ? "windows" : process.platform - bundledPath = path.join(process.cwd(), "binaries", "client", platformName, process.arch, "kubectl") + const platformName = isWindows ? "windows" : process.platform; + bundledPath = path.join(process.cwd(), "binaries", "client", platformName, process.arch, "kubectl"); } else { - bundledPath = path.join(process.resourcesPath, process.arch, "kubectl") + bundledPath = path.join(process.resourcesPath, process.arch, "kubectl"); } if (isWindows) { - bundledPath = `${bundledPath}.exe` + bundledPath = `${bundledPath}.exe`; } - return bundledPath + return bundledPath; } export class Kubectl { - public kubectlVersion: string - protected directory: string - protected url: string - protected path: string - protected dirname: string + public kubectlVersion: string; + protected directory: string; + protected url: string; + protected path: string; + protected dirname: string; static get kubectlDir() { - return path.join((app || remote.app).getPath("userData"), "binaries", "kubectl") + return path.join((app || remote.app).getPath("userData"), "binaries", "kubectl"); } - public static readonly bundledKubectlVersion: string = bundledVersion - public static invalidBundle = false + public static readonly bundledKubectlVersion: string = bundledVersion; + public static invalidBundle = false; private static bundledInstance: Kubectl; // Returns the single bundled Kubectl instance public static bundled() { - if (!Kubectl.bundledInstance) Kubectl.bundledInstance = new Kubectl(Kubectl.bundledKubectlVersion) - return Kubectl.bundledInstance + if (!Kubectl.bundledInstance) Kubectl.bundledInstance = new Kubectl(Kubectl.bundledKubectlVersion); + return Kubectl.bundledInstance; } constructor(clusterVersion: string) { - const versionParts = /^v?(\d+\.\d+)(.*)/.exec(clusterVersion) - const minorVersion = versionParts[1] + const versionParts = /^v?(\d+\.\d+)(.*)/.exec(clusterVersion); + const minorVersion = versionParts[1]; /* minorVersion is the first two digits of kube server version if the version map includes that, use that version, if not, fallback to the exact x.y.z of kube version */ if (kubectlMap.has(minorVersion)) { - this.kubectlVersion = kubectlMap.get(minorVersion) - logger.debug("Set kubectl version " + this.kubectlVersion + " for cluster version " + clusterVersion + " using version map") + this.kubectlVersion = kubectlMap.get(minorVersion); + logger.debug("Set kubectl version " + this.kubectlVersion + " for cluster version " + clusterVersion + " using version map"); } else { - this.kubectlVersion = versionParts[1] + versionParts[2] - logger.debug("Set kubectl version " + this.kubectlVersion + " for cluster version " + clusterVersion + " using fallback") + this.kubectlVersion = versionParts[1] + versionParts[2]; + logger.debug("Set kubectl version " + this.kubectlVersion + " for cluster version " + clusterVersion + " using fallback"); } - let arch = null + let arch = null; if (process.arch == "x64") { - arch = "amd64" + arch = "amd64"; } else if (process.arch == "x86" || process.arch == "ia32") { - arch = "386" + arch = "386"; } else { - arch = process.arch + arch = process.arch; } - const platformName = isWindows ? "windows" : process.platform - const binaryName = isWindows ? "kubectl.exe" : "kubectl" + const platformName = isWindows ? "windows" : process.platform; + const binaryName = isWindows ? "kubectl.exe" : "kubectl"; - this.url = `${this.getDownloadMirror()}/v${this.kubectlVersion}/bin/${platformName}/${arch}/${binaryName}` + this.url = `${this.getDownloadMirror()}/v${this.kubectlVersion}/bin/${platformName}/${arch}/${binaryName}`; - this.dirname = path.normalize(path.join(this.getDownloadDir(), this.kubectlVersion)) - this.path = path.join(this.dirname, binaryName) + this.dirname = path.normalize(path.join(this.getDownloadDir(), this.kubectlVersion)); + this.path = path.join(this.dirname, binaryName); } public getBundledPath() { - return bundledKubectlPath() + return bundledKubectlPath(); } public getPathFromPreferences() { - return userStore.preferences?.kubectlBinariesPath || this.getBundledPath() + return userStore.preferences?.kubectlBinariesPath || this.getBundledPath(); } protected getDownloadDir() { if (userStore.preferences?.downloadBinariesPath) { - return path.join(userStore.preferences.downloadBinariesPath, "kubectl") + return path.join(userStore.preferences.downloadBinariesPath, "kubectl"); } - return Kubectl.kubectlDir + return Kubectl.kubectlDir; } public async getPath(bundled = false): Promise { if (userStore.preferences?.downloadKubectlBinaries === false) { - return this.getPathFromPreferences() + return this.getPathFromPreferences(); } // return binary name if bundled path is not functional if (!await this.checkBinary(this.getBundledPath(), false)) { - Kubectl.invalidBundle = true - return path.basename(this.getBundledPath()) + Kubectl.invalidBundle = true; + return path.basename(this.getBundledPath()); } try { if (!await this.ensureKubectl()) { - logger.error("Failed to ensure kubectl, fallback to the bundled version") - return this.getBundledPath() + logger.error("Failed to ensure kubectl, fallback to the bundled version"); + return this.getBundledPath(); } - return this.path + return this.path; } catch (err) { - logger.error("Failed to ensure kubectl, fallback to the bundled version") - logger.error(err) - return this.getBundledPath() + logger.error("Failed to ensure kubectl, fallback to the bundled version"); + logger.error(err); + return this.getBundledPath(); } } public async binDir() { try { - await this.ensureKubectl() - await this.writeInitScripts() - return this.dirname + await this.ensureKubectl(); + await this.writeInitScripts(); + return this.dirname; } catch (err) { - logger.error(err) - return "" + logger.error(err); + return ""; } } public async checkBinary(path: string, checkVersion = true) { - const exists = await pathExists(path) + const exists = await pathExists(path); if (exists) { try { - const { stdout } = await promiseExec(`"${path}" version --client=true -o json`) - const output = JSON.parse(stdout) + const { stdout } = await promiseExec(`"${path}" version --client=true -o json`); + const output = JSON.parse(stdout); if (!checkVersion) { - return true + return true; } - let version: string = output.clientVersion.gitVersion + let version: string = output.clientVersion.gitVersion; if (version[0] === 'v') { - version = version.slice(1) + version = version.slice(1); } if (version === this.kubectlVersion) { - logger.debug(`Local kubectl is version ${this.kubectlVersion}`) - return true + logger.debug(`Local kubectl is version ${this.kubectlVersion}`); + return true; } - logger.error(`Local kubectl is version ${version}, expected ${this.kubectlVersion}, unlinking`) + logger.error(`Local kubectl is version ${version}, expected ${this.kubectlVersion}, unlinking`); } catch (err) { - logger.error(`Local kubectl failed to run properly (${err.message}), unlinking`) + logger.error(`Local kubectl failed to run properly (${err.message}), unlinking`); } - await fs.promises.unlink(this.path) + await fs.promises.unlink(this.path); } - return false + return false; } protected async checkBundled(): Promise { if (this.kubectlVersion === Kubectl.bundledKubectlVersion) { try { - const exist = await pathExists(this.path) + const exist = await pathExists(this.path); if (!exist) { - await fs.promises.copyFile(this.getBundledPath(), this.path) - await fs.promises.chmod(this.path, 0o755) + await fs.promises.copyFile(this.getBundledPath(), this.path); + await fs.promises.chmod(this.path, 0o755); } - return true + return true; } catch (err) { - logger.error("Could not copy the bundled kubectl to app-data: " + err) - return false + logger.error("Could not copy the bundled kubectl to app-data: " + err); + return false; } } else { - return false + return false; } } public async ensureKubectl(): Promise { if (userStore.preferences?.downloadKubectlBinaries === false) { - return true + return true; } if (Kubectl.invalidBundle) { - logger.error(`Detected invalid bundle binary, returning ...`) - return false + logger.error(`Detected invalid bundle binary, returning ...`); + return false; } - await ensureDir(this.dirname, 0o755) + await ensureDir(this.dirname, 0o755); return lockFile.lock(this.dirname).then(async (release) => { - logger.debug(`Acquired a lock for ${this.kubectlVersion}`) - const bundled = await this.checkBundled() - let isValid = await this.checkBinary(this.path, !bundled) + logger.debug(`Acquired a lock for ${this.kubectlVersion}`); + const bundled = await this.checkBundled(); + let isValid = await this.checkBinary(this.path, !bundled); if (!isValid && !bundled) { await this.downloadKubectl().catch((error) => { - logger.error(error) - logger.debug(`Releasing lock for ${this.kubectlVersion}`) - release() - return false + logger.error(error); + logger.debug(`Releasing lock for ${this.kubectlVersion}`); + release(); + return false; }); - isValid = !await this.checkBinary(this.path, false) + isValid = !await this.checkBinary(this.path, false); } if (!isValid) { - logger.debug(`Releasing lock for ${this.kubectlVersion}`) - release() - return false + logger.debug(`Releasing lock for ${this.kubectlVersion}`); + release(); + return false; } - logger.debug(`Releasing lock for ${this.kubectlVersion}`) - release() - return true + logger.debug(`Releasing lock for ${this.kubectlVersion}`); + release(); + return true; }).catch((e) => { - logger.error(`Failed to get a lock for ${this.kubectlVersion}`) - logger.error(e) - return false - }) + logger.error(`Failed to get a lock for ${this.kubectlVersion}`); + logger.error(e); + return false; + }); } public async downloadKubectl() { - await ensureDir(path.dirname(this.path), 0o755) + await ensureDir(path.dirname(this.path), 0o755); - logger.info(`Downloading kubectl ${this.kubectlVersion} from ${this.url} to ${this.path}`) + logger.info(`Downloading kubectl ${this.kubectlVersion} from ${this.url} to ${this.path}`); return new Promise((resolve, reject) => { const stream = customRequest({ url: this.url, gzip: true, }); - const file = fs.createWriteStream(this.path) + const file = fs.createWriteStream(this.path); stream.on("complete", () => { - logger.debug("kubectl binary download finished") - file.end() - }) + logger.debug("kubectl binary download finished"); + file.end(); + }); stream.on("error", (error) => { - logger.error(error) + logger.error(error); fs.unlink(this.path, () => { // do nothing - }) - reject(error) - }) + }); + reject(error); + }); file.on("close", () => { - logger.debug("kubectl binary download closed") + logger.debug("kubectl binary download closed"); fs.chmod(this.path, 0o755, (err) => { if (err) reject(err); - }) - resolve() - }) - stream.pipe(file) - }) + }); + resolve(); + }); + stream.pipe(file); + }); } protected async writeInitScripts() { - const kubectlPath = userStore.preferences?.downloadKubectlBinaries ? this.dirname : path.dirname(this.getPathFromPreferences()) - const helmPath = helmCli.getBinaryDir() + const kubectlPath = userStore.preferences?.downloadKubectlBinaries ? this.dirname : path.dirname(this.getPathFromPreferences()); + const helmPath = helmCli.getBinaryDir(); const fsPromises = fs.promises; - const bashScriptPath = path.join(this.dirname, '.bash_set_path') + const bashScriptPath = path.join(this.dirname, '.bash_set_path'); - let bashScript = "" + initScriptVersionString - bashScript += "tempkubeconfig=\"$KUBECONFIG\"\n" - bashScript += "test -f \"/etc/profile\" && . \"/etc/profile\"\n" - bashScript += "if test -f \"$HOME/.bash_profile\"; then\n" - bashScript += " . \"$HOME/.bash_profile\"\n" - bashScript += "elif test -f \"$HOME/.bash_login\"; then\n" - bashScript += " . \"$HOME/.bash_login\"\n" - bashScript += "elif test -f \"$HOME/.profile\"; then\n" - bashScript += " . \"$HOME/.profile\"\n" - bashScript += "fi\n" - bashScript += `export PATH="${helmPath}:${kubectlPath}:$PATH"\n` - bashScript += "export KUBECONFIG=\"$tempkubeconfig\"\n" + let bashScript = "" + initScriptVersionString; + bashScript += "tempkubeconfig=\"$KUBECONFIG\"\n"; + bashScript += "test -f \"/etc/profile\" && . \"/etc/profile\"\n"; + bashScript += "if test -f \"$HOME/.bash_profile\"; then\n"; + bashScript += " . \"$HOME/.bash_profile\"\n"; + bashScript += "elif test -f \"$HOME/.bash_login\"; then\n"; + bashScript += " . \"$HOME/.bash_login\"\n"; + bashScript += "elif test -f \"$HOME/.profile\"; then\n"; + bashScript += " . \"$HOME/.profile\"\n"; + bashScript += "fi\n"; + bashScript += `export PATH="${helmPath}:${kubectlPath}:$PATH"\n`; + bashScript += "export KUBECONFIG=\"$tempkubeconfig\"\n"; - bashScript += "NO_PROXY=\",${NO_PROXY:-localhost},\"\n" - bashScript += "NO_PROXY=\"${NO_PROXY//,localhost,/,}\"\n" - bashScript += "NO_PROXY=\"${NO_PROXY//,127.0.0.1,/,}\"\n" - bashScript += "NO_PROXY=\"localhost,127.0.0.1${NO_PROXY%,}\"\n" - bashScript += "export NO_PROXY\n" - bashScript += "unset tempkubeconfig\n" - await fsPromises.writeFile(bashScriptPath, bashScript.toString(), { mode: 0o644 }) + bashScript += "NO_PROXY=\",${NO_PROXY:-localhost},\"\n"; + bashScript += "NO_PROXY=\"${NO_PROXY//,localhost,/,}\"\n"; + bashScript += "NO_PROXY=\"${NO_PROXY//,127.0.0.1,/,}\"\n"; + bashScript += "NO_PROXY=\"localhost,127.0.0.1${NO_PROXY%,}\"\n"; + bashScript += "export NO_PROXY\n"; + bashScript += "unset tempkubeconfig\n"; + await fsPromises.writeFile(bashScriptPath, bashScript.toString(), { mode: 0o644 }); - const zshScriptPath = path.join(this.dirname, '.zlogin') + const zshScriptPath = path.join(this.dirname, '.zlogin'); - let zshScript = "" + initScriptVersionString + let zshScript = "" + initScriptVersionString; - zshScript += "tempkubeconfig=\"$KUBECONFIG\"\n" + zshScript += "tempkubeconfig=\"$KUBECONFIG\"\n"; // restore previous ZDOTDIR - zshScript += "export ZDOTDIR=\"$OLD_ZDOTDIR\"\n" + zshScript += "export ZDOTDIR=\"$OLD_ZDOTDIR\"\n"; // source all the files - zshScript += "test -f \"$OLD_ZDOTDIR/.zshenv\" && . \"$OLD_ZDOTDIR/.zshenv\"\n" - zshScript += "test -f \"$OLD_ZDOTDIR/.zprofile\" && . \"$OLD_ZDOTDIR/.zprofile\"\n" - zshScript += "test -f \"$OLD_ZDOTDIR/.zlogin\" && . \"$OLD_ZDOTDIR/.zlogin\"\n" - zshScript += "test -f \"$OLD_ZDOTDIR/.zshrc\" && . \"$OLD_ZDOTDIR/.zshrc\"\n" + zshScript += "test -f \"$OLD_ZDOTDIR/.zshenv\" && . \"$OLD_ZDOTDIR/.zshenv\"\n"; + zshScript += "test -f \"$OLD_ZDOTDIR/.zprofile\" && . \"$OLD_ZDOTDIR/.zprofile\"\n"; + zshScript += "test -f \"$OLD_ZDOTDIR/.zlogin\" && . \"$OLD_ZDOTDIR/.zlogin\"\n"; + zshScript += "test -f \"$OLD_ZDOTDIR/.zshrc\" && . \"$OLD_ZDOTDIR/.zshrc\"\n"; // voodoo to replace any previous occurrences of kubectl path in the PATH - zshScript += `kubectlpath=\"${kubectlPath}"\n` - zshScript += `helmpath=\"${helmPath}"\n` - zshScript += "p=\":$kubectlpath:\"\n" - zshScript += "d=\":$PATH:\"\n" - zshScript += "d=${d//$p/:}\n" - zshScript += "d=${d/#:/}\n" - zshScript += "export PATH=\"$helmpath:$kubectlpath:${d/%:/}\"\n" - zshScript += "export KUBECONFIG=\"$tempkubeconfig\"\n" - zshScript += "NO_PROXY=\",${NO_PROXY:-localhost},\"\n" - zshScript += "NO_PROXY=\"${NO_PROXY//,localhost,/,}\"\n" - zshScript += "NO_PROXY=\"${NO_PROXY//,127.0.0.1,/,}\"\n" - zshScript += "NO_PROXY=\"localhost,127.0.0.1${NO_PROXY%,}\"\n" - zshScript += "export NO_PROXY\n" - zshScript += "unset tempkubeconfig\n" - zshScript += "unset OLD_ZDOTDIR\n" - await fsPromises.writeFile(zshScriptPath, zshScript.toString(), { mode: 0o644 }) + zshScript += `kubectlpath=\"${kubectlPath}"\n`; + zshScript += `helmpath=\"${helmPath}"\n`; + zshScript += "p=\":$kubectlpath:\"\n"; + zshScript += "d=\":$PATH:\"\n"; + zshScript += "d=${d//$p/:}\n"; + zshScript += "d=${d/#:/}\n"; + zshScript += "export PATH=\"$helmpath:$kubectlpath:${d/%:/}\"\n"; + zshScript += "export KUBECONFIG=\"$tempkubeconfig\"\n"; + zshScript += "NO_PROXY=\",${NO_PROXY:-localhost},\"\n"; + zshScript += "NO_PROXY=\"${NO_PROXY//,localhost,/,}\"\n"; + zshScript += "NO_PROXY=\"${NO_PROXY//,127.0.0.1,/,}\"\n"; + zshScript += "NO_PROXY=\"localhost,127.0.0.1${NO_PROXY%,}\"\n"; + zshScript += "export NO_PROXY\n"; + zshScript += "unset tempkubeconfig\n"; + zshScript += "unset OLD_ZDOTDIR\n"; + await fsPromises.writeFile(zshScriptPath, zshScript.toString(), { mode: 0o644 }); } protected getDownloadMirror() { - const mirror = packageMirrors.get(userStore.preferences?.downloadMirror) + const mirror = packageMirrors.get(userStore.preferences?.downloadMirror); if (mirror) { - return mirror + return mirror; } - return packageMirrors.get("default") // MacOS packages are only available from default + return packageMirrors.get("default"); // MacOS packages are only available from default } } diff --git a/src/main/kubectl_spec.ts b/src/main/kubectl_spec.ts index ade999c082..9d5a5d1e1d 100644 --- a/src/main/kubectl_spec.ts +++ b/src/main/kubectl_spec.ts @@ -1,5 +1,5 @@ -import packageInfo from "../../package.json" -import path from "path" +import packageInfo from "../../package.json"; +import path from "path"; import { Kubectl } from "../../src/main/kubectl"; import { isWindows } from "../common/vars"; @@ -7,39 +7,39 @@ jest.mock("../common/user-store"); describe("kubectlVersion", () => { it("returns bundled version if exactly same version used", async () => { - const kubectl = new Kubectl(Kubectl.bundled().kubectlVersion) - expect(kubectl.kubectlVersion).toBe(Kubectl.bundled().kubectlVersion) - }) + const kubectl = new Kubectl(Kubectl.bundled().kubectlVersion); + expect(kubectl.kubectlVersion).toBe(Kubectl.bundled().kubectlVersion); + }); it("returns bundled version if same major.minor version is used", async () => { const { bundledKubectlVersion } = packageInfo.config; const kubectl = new Kubectl(bundledKubectlVersion); - expect(kubectl.kubectlVersion).toBe(Kubectl.bundled().kubectlVersion) - }) -}) + expect(kubectl.kubectlVersion).toBe(Kubectl.bundled().kubectlVersion); + }); +}); describe("getPath()", () => { it("returns path to downloaded kubectl binary", async () => { const { bundledKubectlVersion } = packageInfo.config; const kubectl = new Kubectl(bundledKubectlVersion); - const kubectlPath = await kubectl.getPath() - let binaryName = "kubectl" + const kubectlPath = await kubectl.getPath(); + let binaryName = "kubectl"; if (isWindows) { - binaryName += ".exe" + binaryName += ".exe"; } - const expectedPath = path.join(Kubectl.kubectlDir, Kubectl.bundledKubectlVersion, binaryName) - expect(kubectlPath).toBe(expectedPath) - }) + const expectedPath = path.join(Kubectl.kubectlDir, Kubectl.bundledKubectlVersion, binaryName); + expect(kubectlPath).toBe(expectedPath); + }); it("returns plain binary name if bundled kubectl is non-functional", async () => { const { bundledKubectlVersion } = packageInfo.config; const kubectl = new Kubectl(bundledKubectlVersion); - jest.spyOn(kubectl, "getBundledPath").mockReturnValue("/invalid/path/kubectl") - const kubectlPath = await kubectl.getPath() - let binaryName = "kubectl" + jest.spyOn(kubectl, "getBundledPath").mockReturnValue("/invalid/path/kubectl"); + const kubectlPath = await kubectl.getPath(); + let binaryName = "kubectl"; if (isWindows) { - binaryName += ".exe" + binaryName += ".exe"; } - expect(kubectlPath).toBe(binaryName) - }) -}) + expect(kubectlPath).toBe(binaryName); + }); +}); diff --git a/src/main/lens-api.ts b/src/main/lens-api.ts index a0a7361a68..fafeffce91 100644 --- a/src/main/lens-api.ts +++ b/src/main/lens-api.ts @@ -2,16 +2,16 @@ import http from "http"; export abstract class LensApi { protected respondJson(res: http.ServerResponse, content: {}, status = 200) { - this.respond(res, JSON.stringify(content), "application/json", status) + this.respond(res, JSON.stringify(content), "application/json", status); } protected respondText(res: http.ServerResponse, content: string, status = 200) { - this.respond(res, content, "text/plain", status) + this.respond(res, content, "text/plain", status); } protected respond(res: http.ServerResponse, content: string, contentType: string, status = 200) { - res.setHeader("Content-Type", contentType) - res.statusCode = status - res.end(content) + res.setHeader("Content-Type", contentType); + res.statusCode = status; + res.end(content); } } diff --git a/src/main/lens-binary.ts b/src/main/lens-binary.ts index dd6f2aa058..fc6b59ee74 100644 --- a/src/main/lens-binary.ts +++ b/src/main/lens-binary.ts @@ -1,10 +1,10 @@ -import path from "path" -import fs from "fs" -import request from "request" -import { ensureDir, pathExists } from "fs-extra" -import * as tar from "tar" +import path from "path"; +import fs from "fs"; +import request from "request"; +import { ensureDir, pathExists } from "fs-extra"; +import * as tar from "tar"; import { isWindows } from "../common/vars"; -import winston from "winston" +import winston from "winston"; export type LensBinaryOpts = { version: string; @@ -12,177 +12,177 @@ export type LensBinaryOpts = { originalBinaryName: string; newBinaryName?: string; requestOpts?: request.Options; -} +}; export class LensBinary { - public binaryVersion: string - protected directory: string - protected url: string + public binaryVersion: string; + protected directory: string; + protected url: string; protected path: string; protected tarPath: string; - protected dirname: string - protected binaryName: string - protected platformName: string - protected arch: string - protected originalBinaryName: string - protected requestOpts: request.Options - protected logger: Console | winston.Logger + protected dirname: string; + protected binaryName: string; + protected platformName: string; + protected arch: string; + protected originalBinaryName: string; + protected requestOpts: request.Options; + protected logger: Console | winston.Logger; constructor(opts: LensBinaryOpts) { - const baseDir = opts.baseDir - this.originalBinaryName = opts.originalBinaryName - this.binaryName = opts.newBinaryName || opts.originalBinaryName - this.binaryVersion = opts.version - this.requestOpts = opts.requestOpts - this.logger = console - let arch = null + const baseDir = opts.baseDir; + this.originalBinaryName = opts.originalBinaryName; + this.binaryName = opts.newBinaryName || opts.originalBinaryName; + this.binaryVersion = opts.version; + this.requestOpts = opts.requestOpts; + this.logger = console; + let arch = null; if (process.arch == "x64") { - arch = "amd64" + arch = "amd64"; } else if (process.arch == "x86" || process.arch == "ia32") { - arch = "386" + arch = "386"; } else { - arch = process.arch + arch = process.arch; } - this.arch = arch - this.platformName = isWindows ? "windows" : process.platform - this.dirname = path.normalize(path.join(baseDir, this.binaryName)) + this.arch = arch; + this.platformName = isWindows ? "windows" : process.platform; + this.dirname = path.normalize(path.join(baseDir, this.binaryName)); if (isWindows) { - this.binaryName = this.binaryName + ".exe" - this.originalBinaryName = this.originalBinaryName + ".exe" + this.binaryName = this.binaryName + ".exe"; + this.originalBinaryName = this.originalBinaryName + ".exe"; } - const tarName = this.getTarName() + const tarName = this.getTarName(); if (tarName) { - this.tarPath = path.join(this.dirname, tarName) + this.tarPath = path.join(this.dirname, tarName); } } public setLogger(logger: Console | winston.Logger) { - this.logger = logger + this.logger = logger; } protected binaryDir() { - throw new Error("binaryDir not implemented") + throw new Error("binaryDir not implemented"); } public async binaryPath() { - await this.ensureBinary() - return this.getBinaryPath() + await this.ensureBinary(); + return this.getBinaryPath(); } protected getTarName(): string | null { - return null + return null; } protected getUrl() { - return "" + return ""; } protected getBinaryPath() { - return "" + return ""; } protected getOriginalBinaryPath() { - return "" + return ""; } public getBinaryDir() { - return path.dirname(this.getBinaryPath()) + return path.dirname(this.getBinaryPath()); } public async binDir() { try { - await this.ensureBinary() - return this.dirname + await this.ensureBinary(); + return this.dirname; } catch (err) { - this.logger.error(err) - return "" + this.logger.error(err); + return ""; } } protected async checkBinary() { - const exists = await pathExists(this.getBinaryPath()) - return exists + const exists = await pathExists(this.getBinaryPath()); + return exists; } public async ensureBinary() { - const isValid = await this.checkBinary() + const isValid = await this.checkBinary(); if (!isValid) { await this.downloadBinary().catch((error) => { - this.logger.error(error) + this.logger.error(error); }); - if (this.tarPath) await this.untarBinary() - if (this.originalBinaryName != this.binaryName) await this.renameBinary() - this.logger.info(`${this.originalBinaryName} has been downloaded to ${this.getBinaryPath()}`) + if (this.tarPath) await this.untarBinary(); + if (this.originalBinaryName != this.binaryName) await this.renameBinary(); + this.logger.info(`${this.originalBinaryName} has been downloaded to ${this.getBinaryPath()}`); } } protected async untarBinary() { return new Promise((resolve, reject) => { - this.logger.debug(`Extracting ${this.originalBinaryName} binary`) + this.logger.debug(`Extracting ${this.originalBinaryName} binary`); tar.x({ file: this.tarPath, cwd: this.dirname }).then((_ => { - resolve() - })) - }) + resolve(); + })); + }); } protected async renameBinary() { return new Promise((resolve, reject) => { - this.logger.debug(`Renaming ${this.originalBinaryName} binary to ${this.binaryName}`) + this.logger.debug(`Renaming ${this.originalBinaryName} binary to ${this.binaryName}`); fs.rename(this.getOriginalBinaryPath(), this.getBinaryPath(), (err) => { if (err) { - reject(err) + reject(err); } else { - resolve() + resolve(); } - }) - }) + }); + }); } protected async downloadBinary() { - const binaryPath = this.tarPath || this.getBinaryPath() - await ensureDir(this.getBinaryDir(), 0o755) + const binaryPath = this.tarPath || this.getBinaryPath(); + await ensureDir(this.getBinaryDir(), 0o755); - const file = fs.createWriteStream(binaryPath) - const url = this.getUrl() + const file = fs.createWriteStream(binaryPath); + const url = this.getUrl(); - this.logger.info(`Downloading ${this.originalBinaryName} ${this.binaryVersion} from ${url} to ${binaryPath}`) + this.logger.info(`Downloading ${this.originalBinaryName} ${this.binaryVersion} from ${url} to ${binaryPath}`); const requestOpts: request.UriOptions & request.CoreOptions = { uri: url, gzip: true, ...this.requestOpts - } + }; - const stream = request(requestOpts) + const stream = request(requestOpts); stream.on("complete", () => { - this.logger.info(`Download of ${this.originalBinaryName} finished`) - file.end() - }) + this.logger.info(`Download of ${this.originalBinaryName} finished`); + file.end(); + }); stream.on("error", (error) => { - this.logger.error(error) + this.logger.error(error); fs.unlink(binaryPath, () => { // do nothing - }) - throw(error) - }) + }); + throw(error); + }); return new Promise((resolve, reject) => { file.on("close", () => { - this.logger.debug(`${this.originalBinaryName} binary download closed`) + this.logger.debug(`${this.originalBinaryName} binary download closed`); if (!this.tarPath) fs.chmod(binaryPath, 0o755, (err) => { if (err) reject(err); - }) - resolve() - }) - stream.pipe(file) - }) + }); + resolve(); + }); + stream.pipe(file); + }); } } diff --git a/src/main/lens-proxy.ts b/src/main/lens-proxy.ts index 7f0b14721d..03b1b15d29 100644 --- a/src/main/lens-proxy.ts +++ b/src/main/lens-proxy.ts @@ -3,27 +3,27 @@ import http from "http"; import spdy from "spdy"; import httpProxy from "http-proxy"; import url from "url"; -import * as WebSocket from "ws" -import { apiPrefix, apiKubePrefix } from "../common/vars" +import * as WebSocket from "ws"; +import { apiPrefix, apiKubePrefix } from "../common/vars"; import { openShell } from "./node-shell-session"; -import { Router } from "./router" -import { ClusterManager } from "./cluster-manager" +import { Router } from "./router"; +import { ClusterManager } from "./cluster-manager"; import { ContextHandler } from "./context-handler"; -import logger from "./logger" +import logger from "./logger"; export class LensProxy { - protected origin: string - protected proxyServer: http.Server - protected router: Router - protected closed = false - protected retryCounters = new Map() + protected origin: string; + protected proxyServer: http.Server; + protected router: Router; + protected closed = false; + protected retryCounters = new Map(); static create(port: number, clusterManager: ClusterManager) { return new LensProxy(port, clusterManager).listen(); } private constructor(protected port: number, protected clusterManager: ClusterManager) { - this.origin = `http://localhost:${port}` + this.origin = `http://localhost:${port}`; this.router = new Router(); } @@ -35,8 +35,8 @@ export class LensProxy { close() { logger.info("Closing proxy server"); - this.proxyServer.close() - this.closed = true + this.proxyServer.close(); + this.closed = true; } protected buildCustomProxy(): http.Server { @@ -47,66 +47,66 @@ export class LensProxy { protocols: ["http/1.1", "spdy/3.1"] } }, (req: http.IncomingMessage, res: http.ServerResponse) => { - this.handleRequest(proxy, req, res) - }) + this.handleRequest(proxy, req, res); + }); spdyProxy.on("upgrade", (req: http.IncomingMessage, socket: net.Socket, head: Buffer) => { if (req.url.startsWith(`${apiPrefix}?`)) { - this.handleWsUpgrade(req, socket, head) + this.handleWsUpgrade(req, socket, head); } else { - this.handleProxyUpgrade(proxy, req, socket, head) + this.handleProxyUpgrade(proxy, req, socket, head); } - }) + }); spdyProxy.on("error", (err) => { - logger.error("proxy error", err) - }) - return spdyProxy + logger.error("proxy error", err); + }); + return spdyProxy; } protected async handleProxyUpgrade(proxy: httpProxy, req: http.IncomingMessage, socket: net.Socket, head: Buffer) { - const cluster = this.clusterManager.getClusterForRequest(req) + const cluster = this.clusterManager.getClusterForRequest(req); if (cluster) { - const proxyUrl = await cluster.contextHandler.resolveAuthProxyUrl() + req.url.replace(apiKubePrefix, "") - const apiUrl = url.parse(cluster.apiUrl) - const pUrl = url.parse(proxyUrl) - const connectOpts = { port: parseInt(pUrl.port), host: pUrl.hostname } - const proxySocket = new net.Socket() + const proxyUrl = await cluster.contextHandler.resolveAuthProxyUrl() + req.url.replace(apiKubePrefix, ""); + const apiUrl = url.parse(cluster.apiUrl); + const pUrl = url.parse(proxyUrl); + const connectOpts = { port: parseInt(pUrl.port), host: pUrl.hostname }; + const proxySocket = new net.Socket(); proxySocket.connect(connectOpts, () => { - proxySocket.write(`${req.method} ${pUrl.path} HTTP/1.1\r\n`) - proxySocket.write(`Host: ${apiUrl.host}\r\n`) + proxySocket.write(`${req.method} ${pUrl.path} HTTP/1.1\r\n`); + proxySocket.write(`Host: ${apiUrl.host}\r\n`); for (let i = 0; i < req.rawHeaders.length; i += 2) { - const key = req.rawHeaders[i] + const key = req.rawHeaders[i]; if (key !== "Host" && key !== "Authorization") { - proxySocket.write(`${req.rawHeaders[i]}: ${req.rawHeaders[i+1]}\r\n`) + proxySocket.write(`${req.rawHeaders[i]}: ${req.rawHeaders[i+1]}\r\n`); } } - proxySocket.write("\r\n") - proxySocket.write(head) - }) + proxySocket.write("\r\n"); + proxySocket.write(head); + }); - proxySocket.setKeepAlive(true) - socket.setKeepAlive(true) - proxySocket.setTimeout(0) - socket.setTimeout(0) + proxySocket.setKeepAlive(true); + socket.setKeepAlive(true); + proxySocket.setTimeout(0); + socket.setTimeout(0); proxySocket.on('data', function (chunk) { - socket.write(chunk) - }) + socket.write(chunk); + }); proxySocket.on('end', function () { - socket.end() - }) + socket.end(); + }); proxySocket.on('error', function (err) { socket.write("HTTP/" + req.httpVersion + " 500 Connection error\r\n\r\n"); - socket.end() - }) + socket.end(); + }); socket.on('data', function (chunk) { - proxySocket.write(chunk) - }) + proxySocket.write(chunk); + }); socket.on('end', function () { - proxySocket.end() - }) + proxySocket.end(); + }); socket.on('error', function () { - proxySocket.end() - }) + proxySocket.end(); + }); } } @@ -120,29 +120,29 @@ export class LensProxy { logger.debug("Failed proxy to target: " + JSON.stringify(target, null, 2)); if (req.method === "GET" && (!res.statusCode || res.statusCode >= 500)) { const reqId = this.getRequestId(req); - const retryCount = this.retryCounters.get(reqId) || 0 - const timeoutMs = retryCount * 250 + const retryCount = this.retryCounters.get(reqId) || 0; + const timeoutMs = retryCount * 250; if (retryCount < 20) { - logger.debug(`Retrying proxy request to url: ${reqId}`) + logger.debug(`Retrying proxy request to url: ${reqId}`); setTimeout(() => { - this.retryCounters.set(reqId, retryCount + 1) - this.handleRequest(proxy, req, res) - }, timeoutMs) + this.retryCounters.set(reqId, retryCount + 1); + this.handleRequest(proxy, req, res); + }, timeoutMs); } } } try { - res.writeHead(500).end("Oops, something went wrong.") + res.writeHead(500).end("Oops, something went wrong."); } catch (e) { - logger.error(`[LENS-PROXY]: Failed to write headers: `, e) + logger.error(`[LENS-PROXY]: Failed to write headers: `, e); } - }) + }); return proxy; } protected createWsListener(): WebSocket.Server { - const ws = new WebSocket.Server({ noServer: true }) + const ws = new WebSocket.Server({ noServer: true }); return ws.on("connection", ((socket: WebSocket, req: http.IncomingMessage) => { const cluster = this.clusterManager.getClusterForRequest(req); const nodeParam = url.parse(req.url, true).query["node"]?.toString(); @@ -152,10 +152,10 @@ export class LensProxy { protected async getProxyTarget(req: http.IncomingMessage, contextHandler: ContextHandler): Promise { if (req.url.startsWith(apiKubePrefix)) { - delete req.headers.authorization - req.url = req.url.replace(apiKubePrefix, "") - const isWatchRequest = req.url.includes("watch=") - return await contextHandler.getApiTarget(isWatchRequest) + delete req.headers.authorization; + req.url = req.url.replace(apiKubePrefix, ""); + const isWatchRequest = req.url.includes("watch="); + return await contextHandler.getApiTarget(isWatchRequest); } } @@ -164,9 +164,9 @@ export class LensProxy { } protected async handleRequest(proxy: httpProxy, req: http.IncomingMessage, res: http.ServerResponse) { - const cluster = this.clusterManager.getClusterForRequest(req) + const cluster = this.clusterManager.getClusterForRequest(req); if (cluster) { - const proxyTarget = await this.getProxyTarget(req, cluster.contextHandler) + const proxyTarget = await this.getProxyTarget(req, cluster.contextHandler); if (proxyTarget) { // allow to fetch apis in "clusterId.localhost:port" from "localhost:port" res.setHeader("Access-Control-Allow-Origin", this.origin); diff --git a/src/main/logger.ts b/src/main/logger.ts index f4e2707c27..81d61e8002 100644 --- a/src/main/logger.ts +++ b/src/main/logger.ts @@ -1,13 +1,13 @@ import { app, remote } from "electron"; -import winston from "winston" +import winston from "winston"; import { isDebugging } from "../common/vars"; -const logLevel = process.env.LOG_LEVEL ? process.env.LOG_LEVEL : isDebugging ? "debug" : "info" +const logLevel = process.env.LOG_LEVEL ? process.env.LOG_LEVEL : isDebugging ? "debug" : "info"; const consoleOptions: winston.transports.ConsoleTransportOptions = { handleExceptions: false, level: logLevel, -} +}; const fileOptions: winston.transports.FileTransportOptions = { handleExceptions: false, @@ -17,7 +17,7 @@ const fileOptions: winston.transports.FileTransportOptions = { maxsize: 16 * 1024, maxFiles: 16, tailable: true, -} +}; const logger = winston.createLogger({ format: winston.format.combine( @@ -30,4 +30,4 @@ const logger = winston.createLogger({ ], }); -export default logger +export default logger; diff --git a/src/main/menu.ts b/src/main/menu.ts index 14525581b8..99a0d0bb55 100644 --- a/src/main/menu.ts +++ b/src/main/menu.ts @@ -1,4 +1,4 @@ -import { app, BrowserWindow, dialog, ipcMain, IpcMainEvent, Menu, MenuItem, MenuItemConstructorOptions, webContents, shell } from "electron" +import { app, BrowserWindow, dialog, ipcMain, IpcMainEvent, Menu, MenuItem, MenuItemConstructorOptions, webContents, shell } from "electron"; import { autorun } from "mobx"; import { WindowManager } from "./window-manager"; import { appName, isMac, isWindows, isTestEnv } from "../common/vars"; @@ -11,7 +11,7 @@ import { menuRegistry } from "../extensions/registries/menu-registry"; import logger from "./logger"; import { exitApp } from "./exit-app"; -export type MenuTopId = "mac" | "file" | "edit" | "view" | "help" +export type MenuTopId = "mac" | "file" | "edit" | "view" | "help"; export function initMenu(windowManager: WindowManager) { return autorun(() => buildMenu(windowManager), { @@ -25,14 +25,14 @@ export function showAbout(browserWindow: BrowserWindow) { `Electron: ${process.versions.electron}`, `Chrome: ${process.versions.chrome}`, `Copyright 2020 Mirantis, Inc.`, - ] + ]; dialog.showMessageBoxSync(browserWindow, { title: `${isWindows ? " ".repeat(2) : ""}${appName}`, type: "info", buttons: ["Close"], message: `Lens`, detail: appInfo.join("\r\n") - }) + }); } export function buildMenu(windowManager: WindowManager) { @@ -44,7 +44,7 @@ export function buildMenu(windowManager: WindowManager) { function activeClusterOnly(menuItems: MenuItemConstructorOptions[]) { if (!windowManager.activeClusterId) { menuItems.forEach(item => { - item.enabled = false + item.enabled = false; }); } return menuItems; @@ -61,7 +61,7 @@ export function buildMenu(windowManager: WindowManager) { { label: "About Lens", click(menuItem: MenuItem, browserWindow: BrowserWindow) { - showAbout(browserWindow) + showAbout(browserWindow); } }, { type: 'separator' }, @@ -69,14 +69,14 @@ export function buildMenu(windowManager: WindowManager) { label: 'Preferences', accelerator: 'CmdOrCtrl+,', click() { - navigate(preferencesURL()) + navigate(preferencesURL()); } }, { label: 'Extensions', accelerator: 'CmdOrCtrl+Shift+E', click() { - navigate(extensionsURL()) + navigate(extensionsURL()); } }, { type: 'separator' }, @@ -90,7 +90,7 @@ export function buildMenu(windowManager: WindowManager) { label: 'Quit', accelerator: 'Cmd+Q', click() { - exitApp() + exitApp(); } } ] @@ -103,7 +103,7 @@ export function buildMenu(windowManager: WindowManager) { label: 'Add Cluster', accelerator: 'CmdOrCtrl+Shift+A', click() { - navigate(addClusterURL()) + navigate(addClusterURL()); } }, ...activeClusterOnly([ @@ -115,7 +115,7 @@ export function buildMenu(windowManager: WindowManager) { params: { clusterId: windowManager.activeClusterId } - })) + })); } } ]), @@ -125,14 +125,14 @@ export function buildMenu(windowManager: WindowManager) { label: 'Preferences', accelerator: 'Ctrl+,', click() { - navigate(preferencesURL()) + navigate(preferencesURL()); } }, { label: 'Extensions', accelerator: 'Ctrl+Shift+E', click() { - navigate(extensionsURL()) + navigate(extensionsURL()); } } ]), @@ -147,7 +147,7 @@ export function buildMenu(windowManager: WindowManager) { label: 'Exit', accelerator: 'Alt+F4', click() { - exitApp() + exitApp(); } } ]) @@ -183,7 +183,7 @@ export function buildMenu(windowManager: WindowManager) { label: 'Forward', accelerator: 'CmdOrCtrl+]', click() { - webContents.getFocusedWebContents()?.goForward() + webContents.getFocusedWebContents()?.goForward(); } }, { @@ -209,7 +209,7 @@ export function buildMenu(windowManager: WindowManager) { { label: "What's new?", click() { - navigate(whatsNewURL()) + navigate(whatsNewURL()); }, }, { @@ -222,7 +222,7 @@ export function buildMenu(windowManager: WindowManager) { { label: "About Lens", click(menuItem: MenuItem, browserWindow: BrowserWindow) { - showAbout(browserWindow) + showAbout(browserWindow); } } ]) @@ -236,7 +236,7 @@ export function buildMenu(windowManager: WindowManager) { edit: editMenu, view: viewMenu, help: helpMenu, - } + }; // Modify menu from extensions-api menuRegistry.getItems().forEach(({ parentId, ...menuItem }) => { @@ -244,12 +244,12 @@ export function buildMenu(windowManager: WindowManager) { const topMenu = appMenu[parentId as MenuTopId].submenu as MenuItemConstructorOptions[]; topMenu.push(menuItem); } catch (err) { - logger.error(`[MENU]: can't register menu item, parentId=${parentId}`, { menuItem }) + logger.error(`[MENU]: can't register menu item, parentId=${parentId}`, { menuItem }); } - }) + }); if (!isMac) { - delete appMenu.mac + delete appMenu.mac; } const menu = Menu.buildFromTemplate(Object.values(appMenu)); @@ -259,9 +259,9 @@ export function buildMenu(windowManager: WindowManager) { // this is a workaround for the test environment (spectron) not being able to directly access // the application menus (https://github.com/electron-userland/spectron/issues/21) ipcMain.on('test-menu-item-click', (event: IpcMainEvent, ...names: string[]) => { - let menu: Menu = Menu.getApplicationMenu() + let menu: Menu = Menu.getApplicationMenu(); const parentLabels: string[] = []; - let menuItem: MenuItem + let menuItem: MenuItem; for (const name of names) { parentLabels.push(name); @@ -272,7 +272,7 @@ export function buildMenu(windowManager: WindowManager) { menu = menuItem.submenu; } - const menuPath: string = parentLabels.join(" -> ") + const menuPath: string = parentLabels.join(" -> "); if (!menuItem) { logger.info(`[MENU:test-menu-item-click] Cannot find menu item ${menuPath}`); return; diff --git a/src/main/node-shell-session.ts b/src/main/node-shell-session.ts index 9e97398327..3d48afebc5 100644 --- a/src/main/node-shell-session.ts +++ b/src/main/node-shell-session.ts @@ -1,36 +1,36 @@ -import * as WebSocket from "ws" -import * as pty from "node-pty" +import * as WebSocket from "ws"; +import * as pty from "node-pty"; import { ShellSession } from "./shell-session"; -import { v4 as uuid } from "uuid" -import * as k8s from "@kubernetes/client-node" -import { KubeConfig } from "@kubernetes/client-node" -import { Cluster } from "./cluster" +import { v4 as uuid } from "uuid"; +import * as k8s from "@kubernetes/client-node"; +import { KubeConfig } from "@kubernetes/client-node"; +import { Cluster } from "./cluster"; import logger from "./logger"; -import { appEventBus } from "../common/event-bus" +import { appEventBus } from "../common/event-bus"; export class NodeShellSession extends ShellSession { protected nodeName: string; - protected podId: string - protected kc: KubeConfig + protected podId: string; + protected kc: KubeConfig; constructor(socket: WebSocket, cluster: Cluster, nodeName: string) { - super(socket, cluster) - this.nodeName = nodeName - this.podId = `node-shell-${uuid()}` - this.kc = cluster.getProxyKubeconfig() + super(socket, cluster); + this.nodeName = nodeName; + this.podId = `node-shell-${uuid()}`; + this.kc = cluster.getProxyKubeconfig(); } public async open() { - const shell = await this.kubectl.getPath() - let args = [] + const shell = await this.kubectl.getPath(); + let args = []; if (this.createNodeShellPod(this.podId, this.nodeName)) { await this.waitForRunningPod(this.podId).catch((error) => { - this.exit(1001) - }) + this.exit(1001); + }); } - args = ["exec", "-i", "-t", "-n", "kube-system", this.podId, "--", "sh", "-c", "((clear && bash) || (clear && ash) || (clear && sh))"] + args = ["exec", "-i", "-t", "-n", "kube-system", this.podId, "--", "sh", "-c", "((clear && bash) || (clear && ash) || (clear && sh))"]; - const shellEnv = await this.getCachedShellEnv() + const shellEnv = await this.getCachedShellEnv(); this.shellProcess = pty.spawn(shell, args, { cols: 80, cwd: this.cwd() || shellEnv["HOME"], @@ -39,19 +39,19 @@ export class NodeShellSession extends ShellSession { rows: 30, }); this.running = true; - this.pipeStdout() - this.pipeStdin() - this.closeWebsocketOnProcessExit() - this.exitProcessOnWebsocketClose() + this.pipeStdout(); + this.pipeStdin(); + this.closeWebsocketOnProcessExit(); + this.exitProcessOnWebsocketClose(); - appEventBus.emit({name: "node-shell", action: "open"}) + appEventBus.emit({name: "node-shell", action: "open"}); } protected exit(code = 1000) { if (this.podId) { - this.deleteNodeShellPod() + this.deleteNodeShellPod(); } - super.exit(code) + super.exit(code); } protected async createNodeShellPod(podId: string, nodeName: string) { @@ -86,19 +86,19 @@ export class NodeShellSession extends ShellSession { } } as k8s.V1Pod; await k8sApi.createNamespacedPod("kube-system", pod).catch((error) => { - logger.error(error) - return false - }) - return true + logger.error(error); + return false; + }); + return true; } protected getKubeConfig() { if (this.kc) { - return this.kc + return this.kc; } this.kc = new k8s.KubeConfig(); - this.kc.loadFromFile(this.kubeconfigPath) - return this.kc + this.kc.loadFromFile(this.kubeconfigPath); + return this.kc; } protected waitForRunningPod(podId: string) { @@ -110,36 +110,36 @@ export class NodeShellSession extends ShellSession { // callback is called for each received object. (_type, obj) => { if (obj.metadata.name == podId && obj.status.phase === "Running") { - resolve(true) + resolve(true); } }, // done callback is called if the watch terminates normally (err) => { - logger.error(err) - reject(false) + logger.error(err); + reject(false); } ); setTimeout(() => { req.abort(); reject(false); }, 120 * 1000); - }) + }); } protected deleteNodeShellPod() { const kc = this.getKubeConfig(); const k8sApi = kc.makeApiClient(k8s.CoreV1Api); - k8sApi.deleteNamespacedPod(this.podId, "kube-system") + k8sApi.deleteNamespacedPod(this.podId, "kube-system"); } } export async function openShell(socket: WebSocket, cluster: Cluster, nodeName?: string): Promise { let shell: ShellSession; if (nodeName) { - shell = new NodeShellSession(socket, cluster, nodeName) + shell = new NodeShellSession(socket, cluster, nodeName); } else { shell = new ShellSession(socket, cluster); } - shell.open() + shell.open(); return shell; } diff --git a/src/main/port.ts b/src/main/port.ts index b253d3590a..6ba8f71695 100644 --- a/src/main/port.ts +++ b/src/main/port.ts @@ -1,15 +1,15 @@ -import net, { AddressInfo } from "net" -import logger from "./logger" +import net, { AddressInfo } from "net"; +import logger from "./logger"; // todo: check https://github.com/http-party/node-portfinder ? export async function getFreePort(): Promise { logger.debug("Lookup new free port.."); return new Promise((resolve, reject) => { - const server = net.createServer() - server.unref() + const server = net.createServer(); + server.unref(); server.on("listening", () => { - const port = (server.address() as AddressInfo).port + const port = (server.address() as AddressInfo).port; server.close(() => resolve(port)); logger.debug(`New port found: ${port}`); }); @@ -17,6 +17,6 @@ export async function getFreePort(): Promise { logger.error(`Can't resolve new port: "${error}"`); reject(error); }); - server.listen({ host: "127.0.0.1", port: 0 }) - }) + server.listen({ host: "127.0.0.1", port: 0 }); + }); } diff --git a/src/main/port_spec.ts b/src/main/port_spec.ts index c9be25e514..bf01eb5dde 100644 --- a/src/main/port_spec.ts +++ b/src/main/port_spec.ts @@ -1,5 +1,5 @@ -import { EventEmitter } from 'events' -import { getFreePort } from "./port" +import { EventEmitter } from 'events'; +import { getFreePort } from "./port"; let newPort = 0; @@ -8,24 +8,24 @@ jest.mock("net", () => { createServer() { return new class MockServer extends EventEmitter { listen = jest.fn(() => { - this.emit('listening') - return this - }) + this.emit('listening'); + return this; + }); address = () => { - newPort = Math.round(Math.random() * 10000) + newPort = Math.round(Math.random() * 10000); return { port: newPort - } - } - unref = jest.fn() - close = jest.fn(cb => cb()) - } + }; + }; + unref = jest.fn(); + close = jest.fn(cb => cb()); + }; }, - } + }; }); describe("getFreePort", () => { it("finds the next free port", async () => { return expect(getFreePort()).resolves.toEqual(newPort); - }) -}) + }); +}); diff --git a/src/main/prometheus/helm.ts b/src/main/prometheus/helm.ts index f1462931df..56d739c630 100644 --- a/src/main/prometheus/helm.ts +++ b/src/main/prometheus/helm.ts @@ -1,29 +1,29 @@ -import { PrometheusLens } from "./lens" -import { CoreV1Api } from "@kubernetes/client-node" +import { PrometheusLens } from "./lens"; +import { CoreV1Api } from "@kubernetes/client-node"; import { PrometheusService } from "./provider-registry"; -import logger from "../logger" +import logger from "../logger"; export class PrometheusHelm extends PrometheusLens { - id = "helm" - name = "Helm" - rateAccuracy = "5m" + id = "helm"; + name = "Helm"; + rateAccuracy = "5m"; public async getPrometheusService(client: CoreV1Api): Promise { - const labelSelector = "app=prometheus,component=server,heritage=Helm" + const labelSelector = "app=prometheus,component=server,heritage=Helm"; try { - const serviceList = await client.listServiceForAllNamespaces(false, "", null, labelSelector) - const service = serviceList.body.items[0] - if (!service) return + const serviceList = await client.listServiceForAllNamespaces(false, "", null, labelSelector); + const service = serviceList.body.items[0]; + if (!service) return; return { id: this.id, namespace: service.metadata.namespace, service: service.metadata.name, port: service.spec.ports[0].port - } + }; } catch(error) { - logger.warn(`PrometheusHelm: failed to list services: ${error.toString()}`) - return + logger.warn(`PrometheusHelm: failed to list services: ${error.toString()}`); + return; } } } diff --git a/src/main/prometheus/lens.ts b/src/main/prometheus/lens.ts index 4db70bf45d..76a459212d 100644 --- a/src/main/prometheus/lens.ts +++ b/src/main/prometheus/lens.ts @@ -1,24 +1,24 @@ import { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry"; import { CoreV1Api } from "@kubernetes/client-node"; -import logger from "../logger" +import logger from "../logger"; export class PrometheusLens implements PrometheusProvider { - id = "lens" - name = "Lens" - rateAccuracy = "1m" + id = "lens"; + name = "Lens"; + rateAccuracy = "1m"; public async getPrometheusService(client: CoreV1Api): Promise { try { - const resp = await client.readNamespacedService("prometheus", "lens-metrics") - const service = resp.body + const resp = await client.readNamespacedService("prometheus", "lens-metrics"); + const service = resp.body; return { id: this.id, namespace: service.metadata.namespace, service: service.metadata.name, port: service.spec.ports[0].port - } + }; } catch(error) { - logger.warn(`PrometheusLens: failed to list services: ${error.response.body.message}`) + logger.warn(`PrometheusLens: failed to list services: ${error.response.body.message}`); } } @@ -42,7 +42,7 @@ export class PrometheusLens implements PrometheusProvider { podCapacity: `sum(kube_node_status_capacity{node=~"${opts.nodes}", resource="pods"}) by (component)`, fsSize: `sum(node_filesystem_size_bytes{kubernetes_node=~"${opts.nodes}", mountpoint="/"}) by (kubernetes_node)`, fsUsage: `sum(node_filesystem_size_bytes{kubernetes_node=~"${opts.nodes}", mountpoint="/"} - node_filesystem_avail_bytes{kubernetes_node=~"${opts.nodes}", mountpoint="/"}) by (kubernetes_node)` - } + }; case 'nodes': return { memoryUsage: `sum (node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) by (kubernetes_node)`, @@ -51,7 +51,7 @@ export class PrometheusLens implements PrometheusProvider { cpuCapacity: `sum(kube_node_status_allocatable{resource="cpu"}) by (node)`, fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"}) by (kubernetes_node)`, fsUsage: `sum(node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) by (kubernetes_node)` - } + }; case 'pods': return { cpuUsage: `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, @@ -63,21 +63,21 @@ export class PrometheusLens implements PrometheusProvider { fsUsage: `sum(container_fs_usage_bytes{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}) by (${opts.selector})`, networkReceive: `sum(rate(container_network_receive_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, networkTransmit: `sum(rate(container_network_transmit_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})` - } + }; case 'pvc': return { diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`, diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)` - } + }; case 'ingress': const bytesSent = (ingress: string, statuses: string) => - `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)` + `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`; return { bytesSentSuccess: bytesSent(opts.igress, "^2\\\\d*"), bytesSentFailure: bytesSent(opts.ingres, "^5\\\\d*"), requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`, responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)` - } + }; } } } diff --git a/src/main/prometheus/operator.ts b/src/main/prometheus/operator.ts index 3d335ff554..8e27a4a6f3 100644 --- a/src/main/prometheus/operator.ts +++ b/src/main/prometheus/operator.ts @@ -3,30 +3,30 @@ import { CoreV1Api, V1Service } from "@kubernetes/client-node"; import logger from "../logger"; export class PrometheusOperator implements PrometheusProvider { - rateAccuracy = "1m" - id = "operator" - name = "Prometheus Operator" + rateAccuracy = "1m"; + id = "operator"; + name = "Prometheus Operator"; public async getPrometheusService(client: CoreV1Api): Promise { try { - let service: V1Service + let service: V1Service; for (const labelSelector of ["operated-prometheus=true", "self-monitor=true"]) { if (!service) { - const serviceList = await client.listServiceForAllNamespaces(null, null, null, labelSelector) - service = serviceList.body.items[0] + const serviceList = await client.listServiceForAllNamespaces(null, null, null, labelSelector); + service = serviceList.body.items[0]; } } - if (!service) return + if (!service) return; return { id: this.id, namespace: service.metadata.namespace, service: service.metadata.name, port: service.spec.ports[0].port - } + }; } catch(error) { - logger.warn(`PrometheusOperator: failed to list services: ${error.toString()}`) - return + logger.warn(`PrometheusOperator: failed to list services: ${error.toString()}`); + return; } } @@ -50,7 +50,7 @@ export class PrometheusOperator implements PrometheusProvider { podCapacity: `sum(kube_node_status_capacity{node=~"${opts.nodes}", resource="pods"})`, fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"})`, fsUsage: `sum(node_filesystem_size_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"} - node_filesystem_avail_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"})` - } + }; case 'nodes': return { memoryUsage: `sum((node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) * on (pod,namespace) group_left(node) kube_pod_info) by (node)`, @@ -59,7 +59,7 @@ export class PrometheusOperator implements PrometheusProvider { cpuCapacity: `sum(kube_node_status_allocatable{resource="cpu"}) by (node)`, fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info) by (node)`, fsUsage: `sum((node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) * on (pod,namespace) group_left(node) kube_pod_info) by (node)` - } + }; case 'pods': return { cpuUsage: `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",image!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, @@ -71,12 +71,12 @@ export class PrometheusOperator implements PrometheusProvider { fsUsage: `sum(container_fs_usage_bytes{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}) by (${opts.selector})`, networkReceive: `sum(rate(container_network_receive_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, networkTransmit: `sum(rate(container_network_transmit_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})` - } + }; case 'pvc': return { diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`, diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)` - } + }; case 'ingress': const bytesSent = (ingress: string, statuses: string) => `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`; @@ -85,7 +85,7 @@ export class PrometheusOperator implements PrometheusProvider { bytesSentFailure: bytesSent(opts.ingres, "^5\\\\d*"), requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`, responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)` - } + }; } } } diff --git a/src/main/prometheus/provider-registry.ts b/src/main/prometheus/provider-registry.ts index 0a4eb22e95..641b1b8cf2 100644 --- a/src/main/prometheus/provider-registry.ts +++ b/src/main/prometheus/provider-registry.ts @@ -1,4 +1,4 @@ -import { CoreV1Api } from "@kubernetes/client-node" +import { CoreV1Api } from "@kubernetes/client-node"; export type PrometheusClusterQuery = { memoryUsage: string; @@ -11,7 +11,7 @@ export type PrometheusClusterQuery = { cpuCapacity: string; podUsage: string; podCapacity: string; -} +}; export type PrometheusNodeQuery = { memoryUsage: string; @@ -20,7 +20,7 @@ export type PrometheusNodeQuery = { cpuCapacity: string; fsSize: string; fsUsage: string; -} +}; export type PrometheusPodQuery = { memoryUsage: string; @@ -32,32 +32,32 @@ export type PrometheusPodQuery = { fsUsage: string; networkReceive: string; networkTransmit: string; -} +}; export type PrometheusPvcQuery = { diskUsage: string; diskCapacity: string; -} +}; export type PrometheusIngressQuery = { bytesSentSuccess: string; bytesSentFailure: string; requestDurationSeconds: string; responseDurationSeconds: string; -} +}; export type PrometheusQueryOpts = { [key: string]: string | any; }; -export type PrometheusQuery = PrometheusNodeQuery | PrometheusClusterQuery | PrometheusPodQuery | PrometheusPvcQuery | PrometheusIngressQuery +export type PrometheusQuery = PrometheusNodeQuery | PrometheusClusterQuery | PrometheusPodQuery | PrometheusPvcQuery | PrometheusIngressQuery; export type PrometheusService = { id: string; namespace: string; service: string; port: number; -} +}; export interface PrometheusProvider { id: string; @@ -68,23 +68,23 @@ export interface PrometheusProvider { export type PrometheusProviderList = { [key: string]: PrometheusProvider; -} +}; export class PrometheusProviderRegistry { - private static prometheusProviders: PrometheusProviderList = {} + private static prometheusProviders: PrometheusProviderList = {}; static getProvider(type: string): PrometheusProvider { if (!this.prometheusProviders[type]) { throw "Unknown Prometheus provider"; } - return this.prometheusProviders[type] + return this.prometheusProviders[type]; } static registerProvider(key: string, provider: PrometheusProvider) { - this.prometheusProviders[key] = provider + this.prometheusProviders[key] = provider; } static getProviders(): PrometheusProvider[] { - return Object.values(this.prometheusProviders) + return Object.values(this.prometheusProviders); } } diff --git a/src/main/prometheus/stacklight.ts b/src/main/prometheus/stacklight.ts index 4cb946c81d..35394336d3 100644 --- a/src/main/prometheus/stacklight.ts +++ b/src/main/prometheus/stacklight.ts @@ -1,24 +1,24 @@ import { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry"; import { CoreV1Api } from "@kubernetes/client-node"; -import logger from "../logger" +import logger from "../logger"; export class PrometheusStacklight implements PrometheusProvider { - id = "stacklight" - name = "Stacklight" - rateAccuracy = "1m" + id = "stacklight"; + name = "Stacklight"; + rateAccuracy = "1m"; public async getPrometheusService(client: CoreV1Api): Promise { try { - const resp = await client.readNamespacedService("prometheus-server", "stacklight") - const service = resp.body + const resp = await client.readNamespacedService("prometheus-server", "stacklight"); + const service = resp.body; return { id: this.id, namespace: service.metadata.namespace, service: service.metadata.name, port: service.spec.ports[0].port - } + }; } catch(error) { - logger.warn(`PrometheusLens: failed to list services: ${error.response.body.message}`) + logger.warn(`PrometheusLens: failed to list services: ${error.response.body.message}`); } } @@ -42,7 +42,7 @@ export class PrometheusStacklight implements PrometheusProvider { podCapacity: `sum(kube_node_status_capacity{node=~"${opts.nodes}", resource="pods"}) by (component)`, fsSize: `sum(node_filesystem_size_bytes{node=~"${opts.nodes}", mountpoint="/"}) by (node)`, fsUsage: `sum(node_filesystem_size_bytes{node=~"${opts.nodes}", mountpoint="/"} - node_filesystem_avail_bytes{node=~"${opts.nodes}", mountpoint="/"}) by (node)` - } + }; case 'nodes': return { memoryUsage: `sum (node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) by (node)`, @@ -51,7 +51,7 @@ export class PrometheusStacklight implements PrometheusProvider { cpuCapacity: `sum(kube_node_status_allocatable{resource="cpu"}) by (node)`, fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"}) by (node)`, fsUsage: `sum(node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) by (node)` - } + }; case 'pods': return { cpuUsage: `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, @@ -63,21 +63,21 @@ export class PrometheusStacklight implements PrometheusProvider { fsUsage: `sum(container_fs_usage_bytes{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}) by (${opts.selector})`, networkReceive: `sum(rate(container_network_receive_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, networkTransmit: `sum(rate(container_network_transmit_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})` - } + }; case 'pvc': return { diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`, diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)` - } + }; case 'ingress': const bytesSent = (ingress: string, statuses: string) => - `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)` + `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`; return { bytesSentSuccess: bytesSent(opts.igress, "^2\\\\d*"), bytesSentFailure: bytesSent(opts.ingres, "^5\\\\d*"), requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`, responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)` - } + }; } } } diff --git a/src/main/promise-exec.ts b/src/main/promise-exec.ts index b3bc303165..426bca4c23 100644 --- a/src/main/promise-exec.ts +++ b/src/main/promise-exec.ts @@ -1,4 +1,4 @@ -import * as util from "util" +import * as util from "util"; import { exec } from "child_process"; -export const promiseExec = util.promisify(exec) +export const promiseExec = util.promisify(exec); diff --git a/src/main/proxy-env.ts b/src/main/proxy-env.ts index 04c62ef534..51c8286a7f 100644 --- a/src/main/proxy-env.ts +++ b/src/main/proxy-env.ts @@ -1,18 +1,18 @@ -import { app } from "electron" +import { app } from "electron"; -const switchValue = app.commandLine.getSwitchValue("proxy-server") +const switchValue = app.commandLine.getSwitchValue("proxy-server"); export function mangleProxyEnv() { - let httpsProxy = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || "" + let httpsProxy = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || ""; - delete process.env.HTTPS_PROXY - delete process.env.HTTP_PROXY + delete process.env.HTTPS_PROXY; + delete process.env.HTTP_PROXY; if (switchValue !== "") { - httpsProxy = switchValue + httpsProxy = switchValue; } if (httpsProxy !== "") { - process.env.APP_HTTPS_PROXY = httpsProxy + process.env.APP_HTTPS_PROXY = httpsProxy; } } diff --git a/src/main/resource-applier.ts b/src/main/resource-applier.ts index 41441a3f90..0f4647a60f 100644 --- a/src/main/resource-applier.ts +++ b/src/main/resource-applier.ts @@ -1,12 +1,12 @@ import type { Cluster } from "./cluster"; -import { KubernetesObject } from "@kubernetes/client-node" +import { KubernetesObject } from "@kubernetes/client-node"; import { exec } from "child_process"; import fs from "fs"; import * as yaml from "js-yaml"; import path from "path"; import * as tempy from "tempy"; -import logger from "./logger" -import { appEventBus } from "../common/event-bus" +import logger from "./logger"; +import { appEventBus } from "../common/event-bus"; import { cloneJsonObject } from "../common/utils"; export class ResourceApplier { @@ -15,58 +15,58 @@ export class ResourceApplier { async apply(resource: KubernetesObject | any): Promise { resource = this.sanitizeObject(resource); - appEventBus.emit({name: "resource", action: "apply"}) + appEventBus.emit({name: "resource", action: "apply"}); return await this.kubectlApply(yaml.safeDump(resource)); } protected async kubectlApply(content: string): Promise { const { kubeCtl } = this.cluster; - const kubectlPath = await kubeCtl.getPath() + const kubectlPath = await kubeCtl.getPath(); return new Promise((resolve, reject) => { - const fileName = tempy.file({ name: "resource.yaml" }) - fs.writeFileSync(fileName, content) - const cmd = `"${kubectlPath}" apply --kubeconfig "${this.cluster.getProxyKubeconfigPath()}" -o json -f "${fileName}"` + const fileName = tempy.file({ name: "resource.yaml" }); + fs.writeFileSync(fileName, content); + const cmd = `"${kubectlPath}" apply --kubeconfig "${this.cluster.getProxyKubeconfigPath()}" -o json -f "${fileName}"`; logger.debug("shooting manifests with: " + cmd); - const execEnv: NodeJS.ProcessEnv = Object.assign({}, process.env) - const httpsProxy = this.cluster.preferences?.httpsProxy + const execEnv: NodeJS.ProcessEnv = Object.assign({}, process.env); + const httpsProxy = this.cluster.preferences?.httpsProxy; if (httpsProxy) { - execEnv["HTTPS_PROXY"] = httpsProxy + execEnv["HTTPS_PROXY"] = httpsProxy; } exec(cmd, { env: execEnv }, (error, stdout, stderr) => { if (stderr != "") { - fs.unlinkSync(fileName) - reject(stderr) - return + fs.unlinkSync(fileName); + reject(stderr); + return; } - fs.unlinkSync(fileName) - resolve(JSON.parse(stdout)) - }) - }) + fs.unlinkSync(fileName); + resolve(JSON.parse(stdout)); + }); + }); } public async kubectlApplyAll(resources: string[]): Promise { const { kubeCtl } = this.cluster; - const kubectlPath = await kubeCtl.getPath() + const kubectlPath = await kubeCtl.getPath(); return new Promise((resolve, reject) => { - const tmpDir = tempy.directory() + const tmpDir = tempy.directory(); // Dump each resource into tmpDir resources.forEach((resource, index) => { fs.writeFileSync(path.join(tmpDir, `${index}.yaml`), resource); - }) - const cmd = `"${kubectlPath}" apply --kubeconfig "${this.cluster.getProxyKubeconfigPath()}" -o json -f "${tmpDir}"` + }); + const cmd = `"${kubectlPath}" apply --kubeconfig "${this.cluster.getProxyKubeconfigPath()}" -o json -f "${tmpDir}"`; console.log("shooting manifests with:", cmd); exec(cmd, (error, stdout, stderr) => { if (error) { reject("Error applying manifests:" + error); } if (stderr != "") { - reject(stderr) - return + reject(stderr); + return; } - resolve(stdout) - }) - }) + resolve(stdout); + }); + }); } protected sanitizeObject(resource: KubernetesObject | any) { diff --git a/src/main/router.ts b/src/main/router.ts index 230c93f09e..ed072836b9 100644 --- a/src/main/router.ts +++ b/src/main/router.ts @@ -1,12 +1,12 @@ -import Call from "@hapi/call" -import Subtext from "@hapi/subtext" -import http from "http" -import path from "path" -import { readFile } from "fs-extra" -import { Cluster } from "./cluster" +import Call from "@hapi/call"; +import Subtext from "@hapi/subtext"; +import http from "http"; +import path from "path"; +import { readFile } from "fs-extra"; +import { Cluster } from "./cluster"; import { apiPrefix, appName, publicPath, isDevelopment, webpackDevServerPort } from "../common/vars"; import { helmRoute, kubeconfigRoute, metricsRoute, portForwardRoute, resourceApplierRoute, watchRoute } from "./routes"; -import logger from "./logger" +import logger from "./logger"; export interface RouterRequestOpts { req: http.IncomingMessage; @@ -43,25 +43,25 @@ export class Router { public constructor() { this.router = new Call.Router(); - this.addRoutes() + this.addRoutes(); } public async route(cluster: Cluster, req: http.IncomingMessage, res: http.ServerResponse): Promise { const url = new URL(req.url, "http://localhost"); - const path = url.pathname - const method = req.method.toLowerCase() + const path = url.pathname; + const method = req.method.toLowerCase(); const matchingRoute = this.router.route(method, path); const routeFound = !matchingRoute.isBoom; if (routeFound) { const request = await this.getRequest({ req, res, cluster, url, params: matchingRoute.params }); - await matchingRoute.route(request) - return true + await matchingRoute.route(request); + return true; } return false; } protected async getRequest(opts: RouterRequestOpts): Promise { - const { req, res, url, cluster, params } = opts + const { req, res, url, cluster, params } = opts; const { payload } = await Subtext.parse(req, null, { parse: true, output: "data", @@ -76,7 +76,7 @@ export class Router { query: url.searchParams, payload: payload, params: params - } + }; } protected getMimeType(filename: string) { @@ -92,7 +92,7 @@ export class Router { woff2: "font/woff2", ttf: "font/ttf" }; - return mimeTypes[path.extname(filename).slice(1)] || "text/plain" + return mimeTypes[path.extname(filename).slice(1)] || "text/plain"; } async handleStaticFile(filePath: string, res: http.ServerResponse, req: http.IncomingMessage, retryCount = 0) { @@ -114,10 +114,10 @@ export class Router { res.end(); } catch (err) { if (retryCount > 5) { - logger.error("handleStaticFile:", err.toString()) - res.statusCode = 404 - res.end() - return + logger.error("handleStaticFile:", err.toString()); + res.statusCode = 404; + res.end(); + return; } this.handleStaticFile(`${publicPath}/${appName}.html`, res, req, Math.max(retryCount, 0) + 1); } @@ -131,32 +131,32 @@ export class Router { this.handleStaticFile(params.path, response, req); }); - this.router.add({ method: "get", path: `${apiPrefix}/kubeconfig/service-account/{namespace}/{account}` }, kubeconfigRoute.routeServiceAccountRoute.bind(kubeconfigRoute)) + this.router.add({ method: "get", path: `${apiPrefix}/kubeconfig/service-account/{namespace}/{account}` }, kubeconfigRoute.routeServiceAccountRoute.bind(kubeconfigRoute)); // Watch API - this.router.add({ method: "get", path: `${apiPrefix}/watch` }, watchRoute.routeWatch.bind(watchRoute)) + this.router.add({ method: "get", path: `${apiPrefix}/watch` }, watchRoute.routeWatch.bind(watchRoute)); // Metrics API - this.router.add({ method: "post", path: `${apiPrefix}/metrics` }, metricsRoute.routeMetrics.bind(metricsRoute)) + this.router.add({ method: "post", path: `${apiPrefix}/metrics` }, metricsRoute.routeMetrics.bind(metricsRoute)); // Port-forward API - this.router.add({ method: "post", path: `${apiPrefix}/pods/{namespace}/{resourceType}/{resourceName}/port-forward/{port}` }, portForwardRoute.routePortForward.bind(portForwardRoute)) + this.router.add({ method: "post", path: `${apiPrefix}/pods/{namespace}/{resourceType}/{resourceName}/port-forward/{port}` }, portForwardRoute.routePortForward.bind(portForwardRoute)); // Helm API - this.router.add({ method: "get", path: `${apiPrefix}/v2/charts` }, helmRoute.listCharts.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}` }, helmRoute.getChart.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}/values` }, helmRoute.getChartValues.bind(helmRoute)) + this.router.add({ method: "get", path: `${apiPrefix}/v2/charts` }, helmRoute.listCharts.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}` }, helmRoute.getChart.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}/values` }, helmRoute.getChartValues.bind(helmRoute)); - this.router.add({ method: "post", path: `${apiPrefix}/v2/releases` }, helmRoute.installChart.bind(helmRoute)) - this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.updateRelease.bind(helmRoute)) - this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}/rollback` }, helmRoute.rollbackRelease.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace?}` }, helmRoute.listReleases.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.getRelease.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/values` }, helmRoute.getReleaseValues.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/history` }, helmRoute.getReleaseHistory.bind(helmRoute)) - this.router.add({ method: "delete", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.deleteRelease.bind(helmRoute)) + this.router.add({ method: "post", path: `${apiPrefix}/v2/releases` }, helmRoute.installChart.bind(helmRoute)); + this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.updateRelease.bind(helmRoute)); + this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}/rollback` }, helmRoute.rollbackRelease.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace?}` }, helmRoute.listReleases.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.getRelease.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/values` }, helmRoute.getReleaseValues.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/history` }, helmRoute.getReleaseHistory.bind(helmRoute)); + this.router.add({ method: "delete", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.deleteRelease.bind(helmRoute)); // Resource Applier API - this.router.add({ method: "post", path: `${apiPrefix}/stack` }, resourceApplierRoute.applyResource.bind(resourceApplierRoute)) + this.router.add({ method: "post", path: `${apiPrefix}/stack` }, resourceApplierRoute.applyResource.bind(resourceApplierRoute)); } } diff --git a/src/main/routes/helm-route.ts b/src/main/routes/helm-route.ts index 0ffd7252d5..853f8ddded 100644 --- a/src/main/routes/helm-route.ts +++ b/src/main/routes/helm-route.ts @@ -1,114 +1,114 @@ -import { LensApiRequest } from "../router" -import { helmService } from "../helm/helm-service" -import { LensApi } from "../lens-api" -import logger from "../logger" +import { LensApiRequest } from "../router"; +import { helmService } from "../helm/helm-service"; +import { LensApi } from "../lens-api"; +import logger from "../logger"; class HelmApiRoute extends LensApi { public async listCharts(request: LensApiRequest) { - const { response } = request - const charts = await helmService.listCharts() - this.respondJson(response, charts) + const { response } = request; + const charts = await helmService.listCharts(); + this.respondJson(response, charts); } public async getChart(request: LensApiRequest) { - const { params, query, response } = request - const chart = await helmService.getChart(params.repo, params.chart, query.get("version")) - this.respondJson(response, chart) + const { params, query, response } = request; + const chart = await helmService.getChart(params.repo, params.chart, query.get("version")); + this.respondJson(response, chart); } public async getChartValues(request: LensApiRequest) { - const { params, query, response } = request - const values = await helmService.getChartValues(params.repo, params.chart, query.get("version")) - this.respondJson(response, values) + const { params, query, response } = request; + const values = await helmService.getChartValues(params.repo, params.chart, query.get("version")); + this.respondJson(response, values); } public async installChart(request: LensApiRequest) { - const { payload, cluster, response } = request + const { payload, cluster, response } = request; try { - const result = await helmService.installChart(cluster, payload) - this.respondJson(response, result, 201) + const result = await helmService.installChart(cluster, payload); + this.respondJson(response, result, 201); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } public async updateRelease(request: LensApiRequest) { - const { cluster, params, payload, response } = request + const { cluster, params, payload, response } = request; try { - const result = await helmService.updateRelease(cluster, params.release, params.namespace, payload ) - this.respondJson(response, result) + const result = await helmService.updateRelease(cluster, params.release, params.namespace, payload ); + this.respondJson(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } public async rollbackRelease(request: LensApiRequest) { - const { cluster, params, payload, response } = request + const { cluster, params, payload, response } = request; try { - const result = await helmService.rollback(cluster, params.release, params.namespace, payload.revision) - this.respondJson(response, result) + const result = await helmService.rollback(cluster, params.release, params.namespace, payload.revision); + this.respondJson(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error) + logger.debug(error); + this.respondText(response, error); } } public async listReleases(request: LensApiRequest) { - const { cluster, params, response } = request + const { cluster, params, response } = request; try { - const result = await helmService.listReleases(cluster, params.namespace) - this.respondJson(response, result) + const result = await helmService.listReleases(cluster, params.namespace); + this.respondJson(response, result); } catch(error) { - logger.debug(error) - this.respondText(response, error) + logger.debug(error); + this.respondText(response, error); } } public async getRelease(request: LensApiRequest) { - const { cluster, params, response } = request + const { cluster, params, response } = request; try { - const result = await helmService.getRelease(cluster, params.release, params.namespace) - this.respondJson(response, result) + const result = await helmService.getRelease(cluster, params.release, params.namespace); + this.respondJson(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } public async getReleaseValues(request: LensApiRequest) { - const { cluster, params, response } = request + const { cluster, params, response } = request; try { - const result = await helmService.getReleaseValues(cluster, params.release, params.namespace) - this.respondText(response, result) + const result = await helmService.getReleaseValues(cluster, params.release, params.namespace); + this.respondText(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } public async getReleaseHistory(request: LensApiRequest) { - const { cluster, params, response } = request + const { cluster, params, response } = request; try { - const result = await helmService.getReleaseHistory(cluster, params.release, params.namespace) - this.respondJson(response, result) + const result = await helmService.getReleaseHistory(cluster, params.release, params.namespace); + this.respondJson(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } public async deleteRelease(request: LensApiRequest) { - const { cluster, params, response } = request + const { cluster, params, response } = request; try { - const result = await helmService.deleteRelease(cluster, params.release, params.namespace) - this.respondJson(response, result) + const result = await helmService.deleteRelease(cluster, params.release, params.namespace); + this.respondJson(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } } -export const helmRoute = new HelmApiRoute() +export const helmRoute = new HelmApiRoute(); diff --git a/src/main/routes/index.ts b/src/main/routes/index.ts index 60a0423de4..5bc5b3f3dd 100644 --- a/src/main/routes/index.ts +++ b/src/main/routes/index.ts @@ -1,6 +1,6 @@ -export * from "./kubeconfig-route" -export * from "./metrics-route" -export * from "./port-forward-route" -export * from "./watch-route" -export * from "./helm-route" -export * from "./resource-applier-route" +export * from "./kubeconfig-route"; +export * from "./metrics-route"; +export * from "./port-forward-route"; +export * from "./watch-route"; +export * from "./helm-route"; +export * from "./resource-applier-route"; diff --git a/src/main/routes/kubeconfig-route.ts b/src/main/routes/kubeconfig-route.ts index 09f1f061cf..1c04b9525d 100644 --- a/src/main/routes/kubeconfig-route.ts +++ b/src/main/routes/kubeconfig-route.ts @@ -1,10 +1,10 @@ -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { Cluster } from "../cluster" -import { CoreV1Api, V1Secret } from "@kubernetes/client-node" +import { LensApiRequest } from "../router"; +import { LensApi } from "../lens-api"; +import { Cluster } from "../cluster"; +import { CoreV1Api, V1Secret } from "@kubernetes/client-node"; function generateKubeConfig(username: string, secret: V1Secret, cluster: Cluster) { - const tokenData = Buffer.from(secret.data["token"], "base64") + const tokenData = Buffer.from(secret.data["token"], "base64"); return { 'apiVersion': 'v1', 'kind': 'Config', @@ -36,23 +36,23 @@ function generateKubeConfig(username: string, secret: V1Secret, cluster: Cluster } ], 'current-context': cluster.contextName - } + }; } class KubeconfigRoute extends LensApi { public async routeServiceAccountRoute(request: LensApiRequest) { - const { params, response, cluster} = request + const { params, response, cluster} = request; const client = cluster.getProxyKubeconfig().makeApiClient(CoreV1Api); - const secretList = await client.listNamespacedSecret(params.namespace) + const secretList = await client.listNamespacedSecret(params.namespace); const secret = secretList.body.items.find(secret => { const { annotations } = secret.metadata; return annotations && annotations["kubernetes.io/service-account.name"] == params.account; }); const data = generateKubeConfig(params.account, secret, cluster); - this.respondJson(response, data) + this.respondJson(response, data); } } -export const kubeconfigRoute = new KubeconfigRoute() +export const kubeconfigRoute = new KubeconfigRoute(); diff --git a/src/main/routes/metrics-route.ts b/src/main/routes/metrics-route.ts index dc77f7fb9f..254abe188f 100644 --- a/src/main/routes/metrics-route.ts +++ b/src/main/routes/metrics-route.ts @@ -1,32 +1,32 @@ -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { Cluster } from "../cluster" -import _ from "lodash" +import { LensApiRequest } from "../router"; +import { LensApi } from "../lens-api"; +import { Cluster } from "../cluster"; +import _ from "lodash"; export type IMetricsQuery = string | string[] | { [metricName: string]: string; -} +}; // This is used for backoff retry tracking. -const MAX_ATTEMPTS = 5 -const ATTEMPTS = [...(_.fill(Array(MAX_ATTEMPTS - 1), false)), true] +const MAX_ATTEMPTS = 5; +const ATTEMPTS = [...(_.fill(Array(MAX_ATTEMPTS - 1), false)), true]; // prometheus metrics loader async function loadMetrics(promQueries: string[], cluster: Cluster, prometheusPath: string, queryParams: Record): Promise { - const queries = promQueries.map(p => p.trim()) - const loaders = new Map>() + const queries = promQueries.map(p => p.trim()); + const loaders = new Map>(); async function loadMetric(query: string): Promise { async function loadMetricHelper(): Promise { for (const [attempt, lastAttempt] of ATTEMPTS.entries()) { // retry try { - return await cluster.getMetrics(prometheusPath, { query, ...queryParams }) + return await cluster.getMetrics(prometheusPath, { query, ...queryParams }); } catch (error) { if (lastAttempt || error?.statusCode === 404) { return { status: error.toString(), data: { result: [] }, - } + }; } await new Promise(resolve => setTimeout(resolve, (attempt + 1) * 1000)); // add delay before repeating request @@ -34,41 +34,41 @@ async function loadMetrics(promQueries: string[], cluster: Cluster, prometheusPa } } - return loaders.get(query) ?? loaders.set(query, loadMetricHelper()).get(query) + return loaders.get(query) ?? loaders.set(query, loadMetricHelper()).get(query); } - return Promise.all(queries.map(loadMetric)) + return Promise.all(queries.map(loadMetric)); } class MetricsRoute extends LensApi { async routeMetrics({ response, cluster, payload, query }: LensApiRequest) { - const queryParams: IMetricsQuery = Object.fromEntries(query.entries()) + const queryParams: IMetricsQuery = Object.fromEntries(query.entries()); try { const [prometheusPath, prometheusProvider] = await Promise.all([ cluster.contextHandler.getPrometheusPath(), cluster.contextHandler.getPrometheusProvider() - ]) + ]); // return data in same structure as query if (typeof payload === "string") { - const [data] = await loadMetrics([payload], cluster, prometheusPath, queryParams) - this.respondJson(response, data) + const [data] = await loadMetrics([payload], cluster, prometheusPath, queryParams); + this.respondJson(response, data); } else if (Array.isArray(payload)) { - const data = await loadMetrics(payload, cluster, prometheusPath, queryParams) - this.respondJson(response, data) + const data = await loadMetrics(payload, cluster, prometheusPath, queryParams); + this.respondJson(response, data); } else { const queries = Object.entries(payload).map(([queryName, queryOpts]) => ( (prometheusProvider.getQueries(queryOpts) as Record)[queryName] - )) - const result = await loadMetrics(queries, cluster, prometheusPath, queryParams) - const data = Object.fromEntries(Object.keys(payload).map((metricName, i) => [metricName, result[i]])) - this.respondJson(response, data) + )); + const result = await loadMetrics(queries, cluster, prometheusPath, queryParams); + const data = Object.fromEntries(Object.keys(payload).map((metricName, i) => [metricName, result[i]])); + this.respondJson(response, data); } } catch { - this.respondJson(response, {}) + this.respondJson(response, {}); } } } -export const metricsRoute = new MetricsRoute() +export const metricsRoute = new MetricsRoute(); diff --git a/src/main/routes/port-forward-route.ts b/src/main/routes/port-forward-route.ts index 7ed79aa936..55402ff72f 100644 --- a/src/main/routes/port-forward-route.ts +++ b/src/main/routes/port-forward-route.ts @@ -1,14 +1,14 @@ -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { spawn, ChildProcessWithoutNullStreams } from "child_process" -import { Kubectl } from "../kubectl" -import { getFreePort } from "../port" -import { shell } from "electron" -import * as tcpPortUsed from "tcp-port-used" -import logger from "../logger" +import { LensApiRequest } from "../router"; +import { LensApi } from "../lens-api"; +import { spawn, ChildProcessWithoutNullStreams } from "child_process"; +import { Kubectl } from "../kubectl"; +import { getFreePort } from "../port"; +import { shell } from "electron"; +import * as tcpPortUsed from "tcp-port-used"; +import logger from "../logger"; class PortForward { - public static portForwards: PortForward[] = [] + public static portForwards: PortForward[] = []; static getPortforward(forward: {clusterId: string; kind: string; name: string; namespace: string; port: string}) { return PortForward.portForwards.find((pf) => { @@ -18,70 +18,70 @@ class PortForward { pf.name == forward.name && pf.namespace == forward.namespace && pf.port == forward.port - ) - }) + ); + }); } - public clusterId: string - public process: ChildProcessWithoutNullStreams - public kubeConfig: string - public kind: string - public namespace: string - public name: string - public port: string - public localPort: number + public clusterId: string; + public process: ChildProcessWithoutNullStreams; + public kubeConfig: string; + public kind: string; + public namespace: string; + public name: string; + public port: string; + public localPort: number; constructor(obj: any) { - Object.assign(this, obj) + Object.assign(this, obj); } public async start() { - this.localPort = await getFreePort() - const kubectlBin = await Kubectl.bundled().getPath() + this.localPort = await getFreePort(); + const kubectlBin = await Kubectl.bundled().getPath(); const args = [ "--kubeconfig", this.kubeConfig, "port-forward", "-n", this.namespace, `${this.kind}/${this.name}`, `${this.localPort}:${this.port}` - ] + ]; this.process = spawn(kubectlBin, args, { env: process.env - }) - PortForward.portForwards.push(this) + }); + PortForward.portForwards.push(this); this.process.on("exit", () => { - const index = PortForward.portForwards.indexOf(this) + const index = PortForward.portForwards.indexOf(this); if (index > -1) { - PortForward.portForwards.splice(index, 1) + PortForward.portForwards.splice(index, 1); } - }) + }); try { - await tcpPortUsed.waitUntilUsed(this.localPort, 500, 15000) - return true + await tcpPortUsed.waitUntilUsed(this.localPort, 500, 15000); + return true; } catch (error) { - this.process.kill() - return false + this.process.kill(); + return false; } } public open() { - shell.openExternal(`http://localhost:${this.localPort}`) + shell.openExternal(`http://localhost:${this.localPort}`); } } class PortForwardRoute extends LensApi { public async routePortForward(request: LensApiRequest) { - const { params, response, cluster} = request - const { namespace, port, resourceType, resourceName } = params + const { params, response, cluster} = request; + const { namespace, port, resourceType, resourceName } = params; let portForward = PortForward.getPortforward({ clusterId: cluster.id, kind: resourceType, name: resourceName, namespace: namespace, port: port - }) + }); if (!portForward) { - logger.info(`Creating a new port-forward ${namespace}/${resourceType}/${resourceName}:${port}`) + logger.info(`Creating a new port-forward ${namespace}/${resourceType}/${resourceName}:${port}`); portForward = new PortForward({ clusterId: cluster.id, kind: resourceType, @@ -89,20 +89,20 @@ class PortForwardRoute extends LensApi { name: resourceName, port: port, kubeConfig: cluster.getProxyKubeconfigPath() - }) - const started = await portForward.start() + }); + const started = await portForward.start(); if (!started) { this.respondJson(response, { message: "Failed to open port-forward" - }, 400) - return + }, 400); + return; } } - portForward.open() + portForward.open(); - this.respondJson(response, {}) + this.respondJson(response, {}); } } -export const portForwardRoute = new PortForwardRoute() +export const portForwardRoute = new PortForwardRoute(); diff --git a/src/main/routes/resource-applier-route.ts b/src/main/routes/resource-applier-route.ts index 56125af8f3..8bbfec0d9c 100644 --- a/src/main/routes/resource-applier-route.ts +++ b/src/main/routes/resource-applier-route.ts @@ -1,17 +1,17 @@ -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { ResourceApplier } from "../resource-applier" +import { LensApiRequest } from "../router"; +import { LensApi } from "../lens-api"; +import { ResourceApplier } from "../resource-applier"; class ResourceApplierApiRoute extends LensApi { public async applyResource(request: LensApiRequest) { - const { response, cluster, payload } = request + const { response, cluster, payload } = request; try { const resource = await new ResourceApplier(cluster).apply(payload); - this.respondJson(response, [resource], 200) + this.respondJson(response, [resource], 200); } catch (error) { - this.respondText(response, error, 422) + this.respondText(response, error, 422); } } } -export const resourceApplierRoute = new ResourceApplierApiRoute() +export const resourceApplierRoute = new ResourceApplierApiRoute(); diff --git a/src/main/routes/watch-route.ts b/src/main/routes/watch-route.ts index d88276eaac..dd42460a9d 100644 --- a/src/main/routes/watch-route.ts +++ b/src/main/routes/watch-route.ts @@ -1,53 +1,53 @@ -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { Watch, KubeConfig } from "@kubernetes/client-node" -import { ServerResponse } from "http" -import { Request } from "request" -import logger from "../logger" +import { LensApiRequest } from "../router"; +import { LensApi } from "../lens-api"; +import { Watch, KubeConfig } from "@kubernetes/client-node"; +import { ServerResponse } from "http"; +import { Request } from "request"; +import logger from "../logger"; class ApiWatcher { - private apiUrl: string - private response: ServerResponse - private watchRequest: Request - private watch: Watch - private processor: NodeJS.Timeout - private eventBuffer: any[] = [] + private apiUrl: string; + private response: ServerResponse; + private watchRequest: Request; + private watch: Watch; + private processor: NodeJS.Timeout; + private eventBuffer: any[] = []; constructor(apiUrl: string, kubeConfig: KubeConfig, response: ServerResponse) { - this.apiUrl = apiUrl - this.watch = new Watch(kubeConfig) - this.response = response + this.apiUrl = apiUrl; + this.watch = new Watch(kubeConfig); + this.response = response; } public async start() { if (this.processor) { - clearInterval(this.processor) + clearInterval(this.processor); } this.processor = setInterval(() => { - const events = this.eventBuffer.splice(0) - events.map(event => this.sendEvent(event)) - this.response.flushHeaders() - }, 50) - this.watchRequest = await this.watch.watch(this.apiUrl, {}, this.watchHandler.bind(this), this.doneHandler.bind(this)) + const events = this.eventBuffer.splice(0); + events.map(event => this.sendEvent(event)); + this.response.flushHeaders(); + }, 50); + this.watchRequest = await this.watch.watch(this.apiUrl, {}, this.watchHandler.bind(this), this.doneHandler.bind(this)); } public stop() { - if (!this.watchRequest) { return } + if (!this.watchRequest) { return; } if (this.processor) { - clearInterval(this.processor) + clearInterval(this.processor); } - logger.debug("Stopping watcher for api: " + this.apiUrl) + logger.debug("Stopping watcher for api: " + this.apiUrl); try { - this.watchRequest.abort() + this.watchRequest.abort(); this.sendEvent({ type: "STREAM_END", url: this.apiUrl, status: 410, - }) - logger.debug("watch aborted") + }); + logger.debug("watch aborted"); } catch (error) { - logger.error("Watch abort errored:" + error) + logger.error("Watch abort errored:" + error); } } @@ -55,12 +55,12 @@ class ApiWatcher { this.eventBuffer.push({ type: phase, object: obj - }) + }); } private doneHandler(error: Error) { - if (error) logger.warn("watch ended: " + error.toString()) - this.watchRequest.abort() + if (error) logger.warn("watch ended: " + error.toString()); + this.watchRequest.abort(); } private sendEvent(evt: any) { @@ -72,40 +72,40 @@ class ApiWatcher { class WatchRoute extends LensApi { public async routeWatch(request: LensApiRequest) { - const { params, response, cluster} = request - const apis: string[] = request.query.getAll("api") - const watchers: ApiWatcher[] = [] + const { params, response, cluster} = request; + const apis: string[] = request.query.getAll("api"); + const watchers: ApiWatcher[] = []; if (!apis.length) { this.respondJson(response, { message: "Empty request. Query params 'api' are not provided.", example: "?api=/api/v1/pods&api=/api/v1/nodes", - }, 400) - return + }, 400); + return; } - response.setHeader("Content-Type", "text/event-stream") - response.setHeader("Cache-Control", "no-cache") - response.setHeader("Connection", "keep-alive") - logger.debug("watch using kubeconfig:" + JSON.stringify(cluster.getProxyKubeconfig(), null, 2)) + response.setHeader("Content-Type", "text/event-stream"); + response.setHeader("Cache-Control", "no-cache"); + response.setHeader("Connection", "keep-alive"); + logger.debug("watch using kubeconfig:" + JSON.stringify(cluster.getProxyKubeconfig(), null, 2)); apis.forEach(apiUrl => { - const watcher = new ApiWatcher(apiUrl, cluster.getProxyKubeconfig(), response) - watcher.start() - watchers.push(watcher) - }) + const watcher = new ApiWatcher(apiUrl, cluster.getProxyKubeconfig(), response); + watcher.start(); + watchers.push(watcher); + }); request.raw.req.on("close", () => { - logger.debug("Watch request closed") - watchers.map(watcher => watcher.stop()) - }) + logger.debug("Watch request closed"); + watchers.map(watcher => watcher.stop()); + }); request.raw.req.on("end", () => { - logger.debug("Watch request ended") - watchers.map(watcher => watcher.stop()) - }) + logger.debug("Watch request ended"); + watchers.map(watcher => watcher.stop()); + }); } } -export const watchRoute = new WatchRoute() +export const watchRoute = new WatchRoute(); diff --git a/src/main/shell-session.ts b/src/main/shell-session.ts index 6ea9e4eede..42e0039047 100644 --- a/src/main/shell-session.ts +++ b/src/main/shell-session.ts @@ -1,23 +1,23 @@ -import * as pty from "node-pty" -import * as WebSocket from "ws" +import * as pty from "node-pty"; +import * as WebSocket from "ws"; import { EventEmitter } from "events"; -import path from "path" -import shellEnv from "shell-env" -import { app } from "electron" -import { Kubectl } from "./kubectl" -import { Cluster } from "./cluster" +import path from "path"; +import shellEnv from "shell-env"; +import { app } from "electron"; +import { Kubectl } from "./kubectl"; +import { Cluster } from "./cluster"; import { ClusterPreferences } from "../common/cluster-store"; -import { helmCli } from "./helm/helm-cli" +import { helmCli } from "./helm/helm-cli"; import { isWindows } from "../common/vars"; -import { appEventBus } from "../common/event-bus" +import { appEventBus } from "../common/event-bus"; import { userStore } from "../common/user-store"; export class ShellSession extends EventEmitter { - static shellEnvs: Map = new Map() + static shellEnvs: Map = new Map(); - protected websocket: WebSocket - protected shellProcess: pty.IPty - protected kubeconfigPath: string + protected websocket: WebSocket; + protected shellProcess: pty.IPty; + protected kubeconfigPath: string; protected nodeShellPod: string; protected kubectl: Kubectl; protected kubectlBinDir: string; @@ -28,22 +28,22 @@ export class ShellSession extends EventEmitter { protected clusterId: string; constructor(socket: WebSocket, cluster: Cluster) { - super() - this.websocket = socket - this.kubeconfigPath = cluster.getProxyKubeconfigPath() - this.kubectl = new Kubectl(cluster.version) - this.preferences = cluster.preferences || {} - this.clusterId = cluster.id + super(); + this.websocket = socket; + this.kubeconfigPath = cluster.getProxyKubeconfigPath(); + this.kubectl = new Kubectl(cluster.version); + this.preferences = cluster.preferences || {}; + this.clusterId = cluster.id; } public async open() { - this.kubectlBinDir = await this.kubectl.binDir() - const pathFromPreferences = userStore.preferences.kubectlBinariesPath || this.kubectl.getBundledPath() - this.kubectlPathDir = userStore.preferences.downloadKubectlBinaries ? this.kubectlBinDir : path.dirname(pathFromPreferences) - this.helmBinDir = helmCli.getBinaryDir() - const env = await this.getCachedShellEnv() - const shell = env.PTYSHELL - const args = await this.getShellArgs(shell) + this.kubectlBinDir = await this.kubectl.binDir(); + const pathFromPreferences = userStore.preferences.kubectlBinariesPath || this.kubectl.getBundledPath(); + this.kubectlPathDir = userStore.preferences.downloadKubectlBinaries ? this.kubectlBinDir : path.dirname(pathFromPreferences); + this.helmBinDir = helmCli.getBinaryDir(); + const env = await this.getCachedShellEnv(); + const shell = env.PTYSHELL; + const args = await this.getShellArgs(shell); this.shellProcess = pty.spawn(shell, args, { cols: 80, cwd: this.cwd() || env.HOME, @@ -53,138 +53,138 @@ export class ShellSession extends EventEmitter { }); this.running = true; - this.pipeStdout() - this.pipeStdin() - this.closeWebsocketOnProcessExit() - this.exitProcessOnWebsocketClose() + this.pipeStdout(); + this.pipeStdin(); + this.closeWebsocketOnProcessExit(); + this.exitProcessOnWebsocketClose(); - appEventBus.emit({name: "shell", action: "open"}) + appEventBus.emit({name: "shell", action: "open"}); } protected cwd(): string { if(!this.preferences || !this.preferences.terminalCWD || this.preferences.terminalCWD === "") { - return null + return null; } - return this.preferences.terminalCWD + return this.preferences.terminalCWD; } protected async getShellArgs(shell: string): Promise> { switch(path.basename(shell)) { case "powershell.exe": - return ["-NoExit", "-command", `& {Set-Location $Env:USERPROFILE; $Env:PATH="${this.helmBinDir};${this.kubectlPathDir};$Env:PATH"}`] + return ["-NoExit", "-command", `& {Set-Location $Env:USERPROFILE; $Env:PATH="${this.helmBinDir};${this.kubectlPathDir};$Env:PATH"}`]; case "bash": - return ["--init-file", path.join(this.kubectlBinDir, '.bash_set_path')] + return ["--init-file", path.join(this.kubectlBinDir, '.bash_set_path')]; case "fish": - return ["--login", "--init-command", `export PATH="${this.helmBinDir}:${this.kubectlPathDir}:$PATH"; export KUBECONFIG="${this.kubeconfigPath}"`] + return ["--login", "--init-command", `export PATH="${this.helmBinDir}:${this.kubectlPathDir}:$PATH"; export KUBECONFIG="${this.kubeconfigPath}"`]; case "zsh": - return ["--login"] + return ["--login"]; default: - return [] + return []; } } protected async getCachedShellEnv() { - let env = ShellSession.shellEnvs.get(this.clusterId) + let env = ShellSession.shellEnvs.get(this.clusterId); if (!env) { - env = await this.getShellEnv() - ShellSession.shellEnvs.set(this.clusterId, env) + env = await this.getShellEnv(); + ShellSession.shellEnvs.set(this.clusterId, env); } else { // refresh env in the background this.getShellEnv().then((shellEnv: any) => { - ShellSession.shellEnvs.set(this.clusterId, shellEnv) - }) + ShellSession.shellEnvs.set(this.clusterId, shellEnv); + }); } - return env + return env; } protected async getShellEnv() { - const env = JSON.parse(JSON.stringify(await shellEnv())) - const pathStr = [this.kubectlBinDir, this.helmBinDir, process.env.PATH].join(path.delimiter) + const env = JSON.parse(JSON.stringify(await shellEnv())); + const pathStr = [this.kubectlBinDir, this.helmBinDir, process.env.PATH].join(path.delimiter); if(isWindows) { - env["SystemRoot"] = process.env.SystemRoot - env["PTYSHELL"] = "powershell.exe" - env["PATH"] = pathStr + env["SystemRoot"] = process.env.SystemRoot; + env["PTYSHELL"] = "powershell.exe"; + env["PATH"] = pathStr; } else if(typeof(process.env.SHELL) != "undefined") { - env["PTYSHELL"] = process.env.SHELL - env["PATH"] = pathStr + env["PTYSHELL"] = process.env.SHELL; + env["PATH"] = pathStr; } else { - env["PTYSHELL"] = "" // blank runs the system default shell + env["PTYSHELL"] = ""; // blank runs the system default shell } if(path.basename(env["PTYSHELL"]) === "zsh") { - env["OLD_ZDOTDIR"] = env.ZDOTDIR || env.HOME - env["ZDOTDIR"] = this.kubectlBinDir + env["OLD_ZDOTDIR"] = env.ZDOTDIR || env.HOME; + env["ZDOTDIR"] = this.kubectlBinDir; } - env["PTYPID"] = process.pid.toString() - env["KUBECONFIG"] = this.kubeconfigPath - env["TERM_PROGRAM"] = app.getName() - env["TERM_PROGRAM_VERSION"] = app.getVersion() + env["PTYPID"] = process.pid.toString(); + env["KUBECONFIG"] = this.kubeconfigPath; + env["TERM_PROGRAM"] = app.getName(); + env["TERM_PROGRAM_VERSION"] = app.getVersion(); if (this.preferences.httpsProxy) { - env["HTTPS_PROXY"] = this.preferences.httpsProxy + env["HTTPS_PROXY"] = this.preferences.httpsProxy; } - const no_proxy = ["localhost", "127.0.0.1", env["NO_PROXY"]] - env["NO_PROXY"] = no_proxy.filter(address => !!address).join() + const no_proxy = ["localhost", "127.0.0.1", env["NO_PROXY"]]; + env["NO_PROXY"] = no_proxy.filter(address => !!address).join(); if (env.DEBUG) { // do not pass debug option to bash - delete env["DEBUG"] + delete env["DEBUG"]; } - return(env) + return(env); } protected pipeStdout() { // send shell output to websocket this.shellProcess.onData(((data: string) => { - this.sendResponse(data) + this.sendResponse(data); })); } protected pipeStdin() { // write websocket messages to shellProcess this.websocket.on("message", (data: string) => { - if (!this.running) { return } + if (!this.running) { return; } - const message = Buffer.from(data.slice(1, data.length), "base64").toString() + const message = Buffer.from(data.slice(1, data.length), "base64").toString(); switch (data[0]) { case "0": - this.shellProcess.write(message) + this.shellProcess.write(message); break; case "4": - const resizeMsgObj = JSON.parse(message) - this.shellProcess.resize(resizeMsgObj["Width"], resizeMsgObj["Height"]) + const resizeMsgObj = JSON.parse(message); + this.shellProcess.resize(resizeMsgObj["Width"], resizeMsgObj["Height"]); break; case "9": - this.emit('newToken', message) + this.emit('newToken', message); break; } - }) + }); } protected exit(code = 1000) { - if (this.websocket.readyState == this.websocket.OPEN) this.websocket.close(code) - this.emit('exit') + if (this.websocket.readyState == this.websocket.OPEN) this.websocket.close(code); + this.emit('exit'); } protected closeWebsocketOnProcessExit() { this.shellProcess.onExit(({ exitCode }) => { - this.running = false - let timeout = 0 + this.running = false; + let timeout = 0; if (exitCode > 0) { - this.sendResponse("Terminal will auto-close in 15 seconds ...") - timeout = 15*1000 + this.sendResponse("Terminal will auto-close in 15 seconds ..."); + timeout = 15*1000; } setTimeout(() => { - this.exit() - }, timeout) + this.exit(); + }, timeout); }); } protected exitProcessOnWebsocketClose() { this.websocket.on("close", () => { - this.killShellProcess() - }) + this.killShellProcess(); + }); } protected killShellProcess(){ @@ -192,17 +192,17 @@ export class ShellSession extends EventEmitter { // On Windows we need to kill the shell process by pid, since Lens won't respond after a while if using `this.shellProcess.kill()` if (isWindows) { try { - process.kill(this.shellProcess.pid) + process.kill(this.shellProcess.pid); } catch(e) { - return + return; } } else { - this.shellProcess.kill() + this.shellProcess.kill(); } } } protected sendResponse(msg: string) { - this.websocket.send("1" + Buffer.from(msg).toString("base64")) + this.websocket.send("1" + Buffer.from(msg).toString("base64")); } } diff --git a/src/main/shell-sync.ts b/src/main/shell-sync.ts index 373d0a36ba..46d5788c12 100644 --- a/src/main/shell-sync.ts +++ b/src/main/shell-sync.ts @@ -1,4 +1,4 @@ -import shellEnv from "shell-env" +import shellEnv from "shell-env"; import os from "os"; import { app } from "electron"; import logger from "./logger"; @@ -19,7 +19,7 @@ export async function shellSync() { try { envVars = await shellEnv(shell); } catch (error) { - logger.error(`shellEnv: ${error}`) + logger.error(`shellEnv: ${error}`); } const env: Env = JSON.parse(JSON.stringify(envVars)); @@ -27,12 +27,12 @@ export async function shellSync() { // the LANG env var expects an underscore instead of electron's dash env.LANG = `${app.getLocale().replace('-', '_')}.UTF-8`; } else if (!env.LANG.endsWith(".UTF-8")) { - env.LANG += ".UTF-8" + env.LANG += ".UTF-8"; } // Overwrite PATH on darwin if (process.env.NODE_ENV === "production" && process.platform === "darwin") { - process.env["PATH"] = env.PATH + process.env["PATH"] = env.PATH; } // The spread operator allows joining of objects. The precedence is last to first. diff --git a/src/main/tray.ts b/src/main/tray.ts index 268e006089..f84ea21896 100644 --- a/src/main/tray.ts +++ b/src/main/tray.ts @@ -1,6 +1,6 @@ -import path from "path" -import packageInfo from "../../package.json" -import { dialog, Menu, NativeImage, nativeTheme, Tray } from "electron" +import path from "path"; +import packageInfo from "../../package.json"; +import { dialog, Menu, NativeImage, nativeTheme, Tray } from "electron"; import { autorun } from "mobx"; import { showAbout } from "./menu"; import { AppUpdater } from "./app-updater"; @@ -24,7 +24,7 @@ export function getTrayIcon(isDark = nativeTheme.shouldUseDarkColors): string { __static, isDevelopment ? "../build/tray" : "icons", // copied within electron-builder extras `tray_icon${isDark ? "_dark" : ""}.png` - ) + ); } export function initTray(windowManager: WindowManager) { @@ -35,18 +35,18 @@ export function initTray(windowManager: WindowManager) { } catch (err) { logger.error(`[TRAY]: building failed: ${err}`); } - }) + }); return () => { dispose(); tray?.destroy(); tray = null; - } + }; } export function buildTray(icon: string | NativeImage, menu: Menu) { if (!tray) { - tray = new Tray(icon) - tray.setToolTip(packageInfo.description) + tray = new Tray(icon); + tray.setToolTip(packageInfo.description); tray.setIgnoreDoubleClickEvents(true); } @@ -70,7 +70,7 @@ export function createTrayMenu(windowManager: WindowManager): Menu { { label: "Open Lens", async click() { - await windowManager.ensureMainWindow() + await windowManager.ensureMainWindow(); }, }, { @@ -98,9 +98,9 @@ export function createTrayMenu(windowManager: WindowManager): Menu { clusterStore.setActive(clusterId); windowManager.navigate(clusterViewURL({ params: { clusterId } })); } - } + }; }) - } + }; }), }, { @@ -112,7 +112,7 @@ export function createTrayMenu(windowManager: WindowManager): Menu { dialog.showMessageBoxSync(browserWindow, { message: "No updates available", type: "info", - }) + }); } }, }, @@ -120,7 +120,7 @@ export function createTrayMenu(windowManager: WindowManager): Menu { { label: 'Quit App', click() { - exitApp() + exitApp(); } } ]); diff --git a/src/main/window-manager.ts b/src/main/window-manager.ts index 019ed270eb..00fbdd4243 100644 --- a/src/main/window-manager.ts +++ b/src/main/window-manager.ts @@ -1,9 +1,9 @@ import type { ClusterId } from "../common/cluster-store"; import { observable } from "mobx"; -import { app, BrowserWindow, dialog, shell, webContents } from "electron" -import windowStateKeeper from "electron-window-state" -import { appEventBus } from "../common/event-bus" -import { subscribeToBroadcast } from "../common/ipc" +import { app, BrowserWindow, dialog, shell, webContents } from "electron"; +import windowStateKeeper from "electron-window-state"; +import { appEventBus } from "../common/event-bus"; +import { subscribeToBroadcast } from "../common/ipc"; import { initMenu } from "./menu"; import { initTray } from "./tray"; import { Singleton } from "../common/utils"; @@ -26,7 +26,7 @@ export class WindowManager extends Singleton { } get mainUrl() { - return `http://localhost:${this.proxyPort}` + return `http://localhost:${this.proxyPort}`; } async initMainWindow(showSplash = true) { @@ -63,14 +63,14 @@ export class WindowManager extends Singleton { shell.openExternal(url); }); this.mainWindow.webContents.on("dom-ready", () => { - appEventBus.emit({name: "app", action: "dom-ready"}) - }) + appEventBus.emit({name: "app", action: "dom-ready"}); + }); this.mainWindow.on("focus", () => { - appEventBus.emit({name: "app", action: "focus"}) - }) + appEventBus.emit({name: "app", action: "focus"}); + }); this.mainWindow.on("blur", () => { - appEventBus.emit({name: "app", action: "blur"}) - }) + appEventBus.emit({name: "app", action: "blur"}); + }); // clean up this.mainWindow.on("closed", () => { @@ -78,16 +78,16 @@ export class WindowManager extends Singleton { this.mainWindow = null; this.splashWindow = null; app.dock?.hide(); // hide icon in dock (mac-os) - }) + }); } try { if (showSplash) await this.showSplash(); await this.mainWindow.loadURL(this.mainUrl); this.mainWindow.show(); this.splashWindow?.close(); - appEventBus.emit({ name: "app", action: "start" }) + appEventBus.emit({ name: "app", action: "start" }); } catch (err) { - dialog.showErrorBox("ERROR!", err.toString()) + dialog.showErrorBox("ERROR!", err.toString()); } } @@ -103,7 +103,7 @@ export class WindowManager extends Singleton { // track visible cluster from ui subscribeToBroadcast("cluster-view:current-id", (event, clusterId: ClusterId) => { this.activeClusterId = clusterId; - }) + }); } async ensureMainWindow(): Promise { @@ -126,11 +126,11 @@ export class WindowManager extends Singleton { channel: "renderer:navigate", frameId: frameId, data: [url], - }) + }); } reload() { - const frameId = clusterFrameMap.get(this.activeClusterId) + const frameId = clusterFrameMap.get(this.activeClusterId); if (frameId) { this.sendToView({ channel: "renderer:reload", frameId }); } else { @@ -169,7 +169,7 @@ export class WindowManager extends Singleton { this.splashWindow = null; Object.entries(this.disposers).forEach(([name, dispose]) => { dispose(); - delete this.disposers[name] + delete this.disposers[name]; }); } } diff --git a/src/migrations/cluster-store/2.0.0-beta.2.ts b/src/migrations/cluster-store/2.0.0-beta.2.ts index 8a01af5407..245e9c019c 100644 --- a/src/migrations/cluster-store/2.0.0-beta.2.ts +++ b/src/migrations/cluster-store/2.0.0-beta.2.ts @@ -13,4 +13,4 @@ export default migration({ store.set(contextName, { kubeConfig: value[1] }); } } -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/src/migrations/cluster-store/2.4.1.ts b/src/migrations/cluster-store/2.4.1.ts index 5789f6cc36..f9de1ed6d8 100644 --- a/src/migrations/cluster-store/2.4.1.ts +++ b/src/migrations/cluster-store/2.4.1.ts @@ -11,4 +11,4 @@ export default migration({ store.set(contextName, { kubeConfig: cluster.kubeConfig, icon: cluster.icon || null, preferences: cluster.preferences || {} }); } } -}) +}); diff --git a/src/migrations/cluster-store/2.6.0-beta.2.ts b/src/migrations/cluster-store/2.6.0-beta.2.ts index 0e13afe7a9..3114202ed1 100644 --- a/src/migrations/cluster-store/2.6.0-beta.2.ts +++ b/src/migrations/cluster-store/2.6.0-beta.2.ts @@ -6,7 +6,7 @@ export default migration({ run(store, log) { for (const value of store) { const clusterKey = value[0]; - if (clusterKey === "__internal__") continue + if (clusterKey === "__internal__") continue; const cluster = value[1]; if (!cluster.preferences) cluster.preferences = {}; if (cluster.icon) { @@ -16,4 +16,4 @@ export default migration({ store.set(clusterKey, { contextName: clusterKey, kubeConfig: value[1].kubeConfig, preferences: value[1].preferences }); } } -}) +}); diff --git a/src/migrations/cluster-store/2.6.0-beta.3.ts b/src/migrations/cluster-store/2.6.0-beta.3.ts index 11f1a3bce9..7f17440e60 100644 --- a/src/migrations/cluster-store/2.6.0-beta.3.ts +++ b/src/migrations/cluster-store/2.6.0-beta.3.ts @@ -1,38 +1,38 @@ import { migration } from "../migration-wrapper"; -import yaml from "js-yaml" +import yaml from "js-yaml"; export default migration({ version: "2.6.0-beta.3", run(store, log) { for (const value of store) { const clusterKey = value[0]; - if (clusterKey === "__internal__") continue + if (clusterKey === "__internal__") continue; const cluster = value[1]; - if (!cluster.kubeConfig) continue - const kubeConfig = yaml.safeLoad(cluster.kubeConfig) - if (!kubeConfig.hasOwnProperty('users')) continue - const userObj = kubeConfig.users[0] + if (!cluster.kubeConfig) continue; + const kubeConfig = yaml.safeLoad(cluster.kubeConfig); + if (!kubeConfig.hasOwnProperty('users')) continue; + const userObj = kubeConfig.users[0]; if (userObj) { - const user = userObj.user + const user = userObj.user; if (user["auth-provider"] && user["auth-provider"].config) { - const authConfig = user["auth-provider"].config + const authConfig = user["auth-provider"].config; if (authConfig["access-token"]) { - authConfig["access-token"] = `${authConfig["access-token"]}` + authConfig["access-token"] = `${authConfig["access-token"]}`; } if (authConfig.expiry) { - authConfig.expiry = `${authConfig.expiry}` + authConfig.expiry = `${authConfig.expiry}`; } - log(authConfig) - user["auth-provider"].config = authConfig + log(authConfig); + user["auth-provider"].config = authConfig; kubeConfig.users = [{ name: userObj.name, user: user - }] - cluster.kubeConfig = yaml.safeDump(kubeConfig) - store.set(clusterKey, cluster) + }]; + cluster.kubeConfig = yaml.safeDump(kubeConfig); + store.set(clusterKey, cluster); } } } } -}) +}); diff --git a/src/migrations/cluster-store/2.7.0-beta.0.ts b/src/migrations/cluster-store/2.7.0-beta.0.ts index 3e0ae9337f..f1af3de3c9 100644 --- a/src/migrations/cluster-store/2.7.0-beta.0.ts +++ b/src/migrations/cluster-store/2.7.0-beta.0.ts @@ -6,10 +6,10 @@ export default migration({ run(store, log) { for (const value of store) { const clusterKey = value[0]; - if (clusterKey === "__internal__") continue + if (clusterKey === "__internal__") continue; const cluster = value[1]; - cluster.workspace = "default" - store.set(clusterKey, cluster) + cluster.workspace = "default"; + store.set(clusterKey, cluster); } } -}) +}); diff --git a/src/migrations/cluster-store/2.7.0-beta.1.ts b/src/migrations/cluster-store/2.7.0-beta.1.ts index de9e4506d1..52e60ba527 100644 --- a/src/migrations/cluster-store/2.7.0-beta.1.ts +++ b/src/migrations/cluster-store/2.7.0-beta.1.ts @@ -1,25 +1,25 @@ // Add id for clusters and store them to array import { migration } from "../migration-wrapper"; -import { v4 as uuid } from "uuid" +import { v4 as uuid } from "uuid"; export default migration({ version: "2.7.0-beta.1", run(store, log) { - const clusters: any[] = [] + const clusters: any[] = []; for (const value of store) { const clusterKey = value[0]; - if (clusterKey === "__internal__") continue - if (clusterKey === "clusters") continue + if (clusterKey === "__internal__") continue; + if (clusterKey === "clusters") continue; const cluster = value[1]; - cluster.id = uuid() + cluster.id = uuid(); if (!cluster.preferences.clusterName) { - cluster.preferences.clusterName = clusterKey + cluster.preferences.clusterName = clusterKey; } - clusters.push(cluster) - store.delete(clusterKey) + clusters.push(cluster); + store.delete(clusterKey); } if (clusters.length > 0) { - store.set("clusters", clusters) + store.set("clusters", clusters); } } -}) +}); diff --git a/src/migrations/cluster-store/3.6.0-beta.1.ts b/src/migrations/cluster-store/3.6.0-beta.1.ts index 412c77ab96..c7e5889cd9 100644 --- a/src/migrations/cluster-store/3.6.0-beta.1.ts +++ b/src/migrations/cluster-store/3.6.0-beta.1.ts @@ -1,24 +1,24 @@ // Move embedded kubeconfig into separate file and add reference to it to cluster settings // convert file path cluster icons to their base64 encoded versions -import path from "path" -import { app, remote } from "electron" +import path from "path"; +import { app, remote } from "electron"; import { migration } from "../migration-wrapper"; -import fse from "fs-extra" +import fse from "fs-extra"; import { ClusterModel, ClusterStore } from "../../common/cluster-store"; import { loadConfig } from "../../common/kube-helpers"; export default migration({ version: "3.6.0-beta.1", run(store, printLog) { - const userDataPath = (app || remote.app).getPath("userData") + const userDataPath = (app || remote.app).getPath("userData"); const kubeConfigBase = ClusterStore.getCustomKubeConfigPath(""); const storedClusters: ClusterModel[] = store.get("clusters") || []; if (!storedClusters.length) return; fse.ensureDirSync(kubeConfigBase); - printLog("Number of clusters to migrate: ", storedClusters.length) + printLog("Number of clusters to migrate: ", storedClusters.length); const migratedClusters = storedClusters .map(cluster => { /** @@ -31,7 +31,7 @@ export default migration({ delete cluster.kubeConfig; } catch (error) { - printLog(`Failed to migrate Kubeconfig for cluster "${cluster.id}", removing cluster...`, error) + printLog(`Failed to migrate Kubeconfig for cluster "${cluster.id}", removing cluster...`, error); return undefined; } @@ -40,8 +40,8 @@ export default migration({ */ try { if (cluster.preferences?.icon) { - printLog(`migrating ${cluster.preferences.icon} for ${cluster.preferences.clusterName}`) - const iconPath = cluster.preferences.icon.replace("store://", "") + printLog(`migrating ${cluster.preferences.icon} for ${cluster.preferences.clusterName}`); + const iconPath = cluster.preferences.icon.replace("store://", ""); const fileData = fse.readFileSync(path.join(userDataPath, iconPath)); cluster.preferences.icon = `data:;base64,${fileData.toString('base64')}`; @@ -49,7 +49,7 @@ export default migration({ delete cluster.preferences?.icon; } } catch (error) { - printLog(`Failed to migrate cluster icon for cluster "${cluster.id}"`, error) + printLog(`Failed to migrate cluster icon for cluster "${cluster.id}"`, error); delete cluster.preferences.icon; } @@ -59,7 +59,7 @@ export default migration({ // "overwrite" the cluster configs if (migratedClusters.length > 0) { - store.set("clusters", migratedClusters) + store.set("clusters", migratedClusters); } } -}) +}); diff --git a/src/migrations/cluster-store/index.ts b/src/migrations/cluster-store/index.ts index f35e8f6c9c..c546fdaeda 100644 --- a/src/migrations/cluster-store/index.ts +++ b/src/migrations/cluster-store/index.ts @@ -1,13 +1,13 @@ // Cluster store migrations -import version200Beta2 from "./2.0.0-beta.2" -import version241 from "./2.4.1" -import version260Beta2 from "./2.6.0-beta.2" -import version260Beta3 from "./2.6.0-beta.3" -import version270Beta0 from "./2.7.0-beta.0" -import version270Beta1 from "./2.7.0-beta.1" -import version360Beta1 from "./3.6.0-beta.1" -import snap from "./snap" +import version200Beta2 from "./2.0.0-beta.2"; +import version241 from "./2.4.1"; +import version260Beta2 from "./2.6.0-beta.2"; +import version260Beta3 from "./2.6.0-beta.3"; +import version270Beta0 from "./2.7.0-beta.0"; +import version270Beta1 from "./2.7.0-beta.1"; +import version360Beta1 from "./3.6.0-beta.1"; +import snap from "./snap"; export default { ...version200Beta2, @@ -18,4 +18,4 @@ export default { ...version270Beta1, ...version360Beta1, ...snap -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/migrations/cluster-store/snap.ts b/src/migrations/cluster-store/snap.ts index a377ba4268..1136607cd7 100644 --- a/src/migrations/cluster-store/snap.ts +++ b/src/migrations/cluster-store/snap.ts @@ -3,31 +3,31 @@ import { migration } from "../migration-wrapper"; import { ClusterModel, ClusterStore } from "../../common/cluster-store"; import { getAppVersion } from "../../common/utils/app-version"; -import fs from "fs" +import fs from "fs"; export default migration({ version: getAppVersion(), // Run always after upgrade run(store, printLog) { if (!process.env["SNAP"]) return; - printLog("Migrating embedded kubeconfig paths") + printLog("Migrating embedded kubeconfig paths"); const storedClusters: ClusterModel[] = store.get("clusters") || []; if (!storedClusters.length) return; - printLog("Number of clusters to migrate: ", storedClusters.length) + printLog("Number of clusters to migrate: ", storedClusters.length); const migratedClusters = storedClusters .map(cluster => { /** * replace snap version with 'current' in kubeconfig path */ if (!fs.existsSync(cluster.kubeConfigPath)) { - const kubeconfigPath = cluster.kubeConfigPath.replace(/\/snap\/kontena-lens\/[0-9]*\//, "/snap/kontena-lens/current/") - cluster.kubeConfigPath = kubeconfigPath + const kubeconfigPath = cluster.kubeConfigPath.replace(/\/snap\/kontena-lens\/[0-9]*\//, "/snap/kontena-lens/current/"); + cluster.kubeConfigPath = kubeconfigPath; } return cluster; - }) + }); - store.set("clusters", migratedClusters) + store.set("clusters", migratedClusters); } -}) +}); diff --git a/src/migrations/user-store/2.1.0-beta.4.ts b/src/migrations/user-store/2.1.0-beta.4.ts index 24c4cde5e3..e8f6500b05 100644 --- a/src/migrations/user-store/2.1.0-beta.4.ts +++ b/src/migrations/user-store/2.1.0-beta.4.ts @@ -6,4 +6,4 @@ export default migration({ run(store) { store.set("lastSeenAppVersion", "0.0.0"); } -}) +}); diff --git a/src/migrations/user-store/index.ts b/src/migrations/user-store/index.ts index 895bc5ee18..e1e7b8ffc9 100644 --- a/src/migrations/user-store/index.ts +++ b/src/migrations/user-store/index.ts @@ -1,7 +1,7 @@ // User store migrations -import version210Beta4 from "./2.1.0-beta.4" +import version210Beta4 from "./2.1.0-beta.4"; export default { ...version210Beta4, -} +}; diff --git a/src/renderer/api/api-manager.ts b/src/renderer/api/api-manager.ts index a0d90f4a13..98dbe206c7 100644 --- a/src/renderer/api/api-manager.ts +++ b/src/renderer/api/api-manager.ts @@ -24,7 +24,7 @@ export class ApiManager { } protected resolveApi(api: string | KubeApi): KubeApi { - if (typeof api === "string") return this.getApi(api) + if (typeof api === "string") return this.getApi(api); return api; } @@ -41,7 +41,7 @@ export class ApiManager { registerStore(store: KubeObjectStore, apis: KubeApi[] = [store.api]) { apis.forEach(api => { this.stores.set(api, store); - }) + }); } getStore(api: string | KubeApi): KubeObjectStore { diff --git a/src/renderer/api/endpoints/cluster-role-binding.api.ts b/src/renderer/api/endpoints/cluster-role-binding.api.ts index 35e4ded7e7..d566717bff 100644 --- a/src/renderer/api/endpoints/cluster-role-binding.api.ts +++ b/src/renderer/api/endpoints/cluster-role-binding.api.ts @@ -2,9 +2,9 @@ import { RoleBinding } from "./role-binding.api"; import { KubeApi } from "../kube-api"; export class ClusterRoleBinding extends RoleBinding { - static kind = "ClusterRoleBinding" - static namespaced = false - static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings" + static kind = "ClusterRoleBinding"; + static namespaced = false; + static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings"; } export const clusterRoleBindingApi = new KubeApi({ diff --git a/src/renderer/api/endpoints/cluster-role.api.ts b/src/renderer/api/endpoints/cluster-role.api.ts index 8a99f7ad27..9e3c90ca2e 100644 --- a/src/renderer/api/endpoints/cluster-role.api.ts +++ b/src/renderer/api/endpoints/cluster-role.api.ts @@ -4,9 +4,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class ClusterRole extends Role { - static kind = "ClusterRole" - static namespaced = false - static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterroles" + static kind = "ClusterRole"; + static namespaced = false; + static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterroles"; } export const clusterRoleApi = new KubeApi({ diff --git a/src/renderer/api/endpoints/cluster.api.ts b/src/renderer/api/endpoints/cluster.api.ts index 4386f28184..43783e1c00 100644 --- a/src/renderer/api/endpoints/cluster.api.ts +++ b/src/renderer/api/endpoints/cluster.api.ts @@ -3,12 +3,12 @@ import { KubeObject } from "../kube-object"; import { KubeApi } from "../kube-api"; export class ClusterApi extends KubeApi { - static kind = "Cluster" - static namespaced = true + static kind = "Cluster"; + static namespaced = true; async getMetrics(nodeNames: string[], params?: IMetricsReqParams): Promise { const nodes = nodeNames.join("|"); - const opts = { category: "cluster", nodes: nodes } + const opts = { category: "cluster", nodes: nodes }; return metricsApi.getMetrics({ memoryUsage: opts, @@ -52,7 +52,7 @@ export interface IClusterMetrics { export class Cluster extends KubeObject { static kind = "Cluster"; - static apiBase = "/apis/cluster.k8s.io/v1alpha1/clusters" + static apiBase = "/apis/cluster.k8s.io/v1alpha1/clusters"; spec: { clusterNetwork?: { @@ -69,7 +69,7 @@ export class Cluster extends KubeObject { profile: string; }; }; - } + }; status?: { apiEndpoints: { host: string; @@ -84,7 +84,7 @@ export class Cluster extends KubeObject { }; errorMessage?: string; errorReason?: string; - } + }; getStatus() { if (this.metadata.deletionTimestamp) return ClusterStatus.REMOVING; diff --git a/src/renderer/api/endpoints/component-status.api.ts b/src/renderer/api/endpoints/component-status.api.ts index 7f7e04fe2a..fec4dda1da 100644 --- a/src/renderer/api/endpoints/component-status.api.ts +++ b/src/renderer/api/endpoints/component-status.api.ts @@ -8,11 +8,11 @@ export interface IComponentStatusCondition { } export class ComponentStatus extends KubeObject { - static kind = "ComponentStatus" - static namespaced = false - static apiBase = "/api/v1/componentstatuses" + static kind = "ComponentStatus"; + static namespaced = false; + static apiBase = "/api/v1/componentstatuses"; - conditions: IComponentStatusCondition[] + conditions: IComponentStatusCondition[]; getTruthyConditions() { return this.conditions.filter(c => c.status === "True"); diff --git a/src/renderer/api/endpoints/configmap.api.ts b/src/renderer/api/endpoints/configmap.api.ts index 59f3e3b090..042fb59d86 100644 --- a/src/renderer/api/endpoints/configmap.api.ts +++ b/src/renderer/api/endpoints/configmap.api.ts @@ -7,7 +7,7 @@ import { KubeApi } from "../kube-api"; export class ConfigMap extends KubeObject { static kind = "ConfigMap"; static namespaced = true; - static apiBase = "/api/v1/configmaps" + static apiBase = "/api/v1/configmaps"; constructor(data: KubeJsonApiData) { super(data); @@ -16,7 +16,7 @@ export class ConfigMap extends KubeObject { data: { [param: string]: string; - } + }; getKeys(): string[] { return Object.keys(this.data); diff --git a/src/renderer/api/endpoints/crd.api.ts b/src/renderer/api/endpoints/crd.api.ts index 1916d71f1b..02690a2afd 100644 --- a/src/renderer/api/endpoints/crd.api.ts +++ b/src/renderer/api/endpoints/crd.api.ts @@ -7,20 +7,20 @@ type AdditionalPrinterColumnsCommon = { type: "integer" | "number" | "string" | "boolean" | "date"; priority: number; description: string; -} +}; export type AdditionalPrinterColumnsV1 = AdditionalPrinterColumnsCommon & { jsonPath: string; -} +}; type AdditionalPrinterColumnsV1Beta = AdditionalPrinterColumnsCommon & { JSONPath: string; -} +}; export class CustomResourceDefinition extends KubeObject { static kind = "CustomResourceDefinition"; static namespaced = false; - static apiBase = "/apis/apiextensions.k8s.io/v1/customresourcedefinitions" + static apiBase = "/apis/apiextensions.k8s.io/v1/customresourcedefinitions"; spec: { group: string; @@ -45,7 +45,7 @@ export class CustomResourceDefinition extends KubeObject { webhook?: any; }; additionalPrinterColumns?: AdditionalPrinterColumnsV1Beta[]; // removed in v1 - } + }; status: { conditions: { lastTransitionTime: string; @@ -62,7 +62,7 @@ export class CustomResourceDefinition extends KubeObject { listKind: string; }; storedVersions: string[]; - } + }; getResourceUrl() { return crdResourcesURL({ @@ -70,25 +70,25 @@ export class CustomResourceDefinition extends KubeObject { group: this.getGroup(), name: this.getPluralName(), } - }) + }); } getResourceApiBase() { const { group } = this.spec; - return `/apis/${group}/${this.getVersion()}/${this.getPluralName()}` + return `/apis/${group}/${this.getVersion()}/${this.getPluralName()}`; } getPluralName() { - return this.getNames().plural + return this.getNames().plural; } getResourceKind() { - return this.spec.names.kind + return this.spec.names.kind; } getResourceTitle() { const name = this.getPluralName(); - return name[0].toUpperCase() + name.substr(1) + return name[0].toUpperCase() + name.substr(1); } getGroup() { @@ -141,7 +141,7 @@ export class CustomResourceDefinition extends KubeObject { ...condition, isReady: status === "True", tooltip: `${message || reason} (${lastTransitionTime})` - } + }; }); } } diff --git a/src/renderer/api/endpoints/cron-job.api.ts b/src/renderer/api/endpoints/cron-job.api.ts index b385647bb9..2cca8bfb3d 100644 --- a/src/renderer/api/endpoints/cron-job.api.ts +++ b/src/renderer/api/endpoints/cron-job.api.ts @@ -7,12 +7,12 @@ import { KubeApi } from "../kube-api"; @autobind() export class CronJob extends KubeObject { - static kind = "CronJob" - static namespaced = true - static apiBase = "/apis/batch/v1beta1/cronjobs" + static kind = "CronJob"; + static namespaced = true; + static apiBase = "/apis/batch/v1beta1/cronjobs"; - kind: string - apiVersion: string + kind: string; + apiVersion: string; metadata: { name: string; namespace: string; @@ -26,7 +26,7 @@ export class CronJob extends KubeObject { annotations: { [key: string]: string; }; - } + }; spec: { schedule: string; concurrencyPolicy: string; @@ -59,23 +59,23 @@ export class CronJob extends KubeObject { }; successfulJobsHistoryLimit: number; failedJobsHistoryLimit: number; - } + }; status: { lastScheduleTime?: string; - } + }; getSuspendFlag() { - return this.spec.suspend.toString() + return this.spec.suspend.toString(); } getLastScheduleTime() { - if (!this.status.lastScheduleTime) return "-" - const diff = moment().diff(this.status.lastScheduleTime) - return formatDuration(diff, true) + if (!this.status.lastScheduleTime) return "-"; + const diff = moment().diff(this.status.lastScheduleTime); + return formatDuration(diff, true); } getSchedule() { - return this.spec.schedule + return this.spec.schedule; } isNeverRun() { diff --git a/src/renderer/api/endpoints/daemon-set.api.ts b/src/renderer/api/endpoints/daemon-set.api.ts index d947293c1c..63fc6363e4 100644 --- a/src/renderer/api/endpoints/daemon-set.api.ts +++ b/src/renderer/api/endpoints/daemon-set.api.ts @@ -6,9 +6,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class DaemonSet extends WorkloadKubeObject { - static kind = "DaemonSet" - static namespaced = true - static apiBase = "/apis/apps/v1/daemonsets" + static kind = "DaemonSet"; + static namespaced = true; + static apiBase = "/apis/apps/v1/daemonsets"; spec: { selector: { @@ -51,7 +51,7 @@ export class DaemonSet extends WorkloadKubeObject { }; }; revisionHistoryLimit: number; - } + }; status: { currentNumberScheduled: number; numberMisscheduled: number; @@ -61,12 +61,12 @@ export class DaemonSet extends WorkloadKubeObject { updatedNumberScheduled: number; numberAvailable: number; numberUnavailable: number; - } + }; getImages() { - const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []) - const initContainers: IPodContainer[] = get(this, "spec.template.spec.initContainers", []) - return [...containers, ...initContainers].map(container => container.image) + const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []); + const initContainers: IPodContainer[] = get(this, "spec.template.spec.initContainers", []); + return [...containers, ...initContainers].map(container => container.image); } } diff --git a/src/renderer/api/endpoints/deployment.api.ts b/src/renderer/api/endpoints/deployment.api.ts index b21495ecc1..28ed71f86a 100644 --- a/src/renderer/api/endpoints/deployment.api.ts +++ b/src/renderer/api/endpoints/deployment.api.ts @@ -6,13 +6,13 @@ import { KubeApi } from "../kube-api"; export class DeploymentApi extends KubeApi { protected getScaleApiUrl(params: { namespace: string; name: string }) { - return this.getUrl(params) + "/scale" + return this.getUrl(params) + "/scale"; } getReplicas(params: { namespace: string; name: string }): Promise { return this.request .get(this.getScaleApiUrl(params)) - .then(({ status }: any) => status?.replicas) + .then(({ status }: any) => status?.replicas); } scale(params: { namespace: string; name: string }, replicas: number) { @@ -23,7 +23,7 @@ export class DeploymentApi extends KubeApi { replicas: replicas } } - }) + }); } restart(params: { namespace: string; name: string }) { @@ -42,15 +42,15 @@ export class DeploymentApi extends KubeApi { headers: { 'content-type': 'application/strategic-merge-patch+json' } - }) + }); } } @autobind() export class Deployment extends WorkloadKubeObject { - static kind = "Deployment" - static namespaced = true - static apiBase = "/apis/apps/v1/deployments" + static kind = "Deployment"; + static namespaced = true; + static apiBase = "/apis/apps/v1/deployments"; spec: { replicas: number; @@ -151,7 +151,7 @@ export class Deployment extends WorkloadKubeObject { maxSurge: number; }; }; - } + }; status: { observedGeneration: number; replicas: number; @@ -167,19 +167,19 @@ export class Deployment extends WorkloadKubeObject { reason: string; message: string; }[]; - } + }; getConditions(activeOnly = false) { - const { conditions } = this.status - if (!conditions) return [] + const { conditions } = this.status; + if (!conditions) return []; if (activeOnly) { - return conditions.filter(c => c.status === "True") + return conditions.filter(c => c.status === "True"); } - return conditions + return conditions; } getConditionsText(activeOnly = true) { - return this.getConditions(activeOnly).map(({ type }) => type).join(" ") + return this.getConditions(activeOnly).map(({ type }) => type).join(" "); } getReplicas() { diff --git a/src/renderer/api/endpoints/endpoint.api.ts b/src/renderer/api/endpoints/endpoint.api.ts index 4f4afc9b17..121836a637 100644 --- a/src/renderer/api/endpoints/endpoint.api.ts +++ b/src/renderer/api/endpoints/endpoint.api.ts @@ -42,22 +42,22 @@ export class EndpointAddress implements IEndpointAddress { }; constructor(data: IEndpointAddress) { - Object.assign(this, data) + Object.assign(this, data); } getId() { - return this.ip + return this.ip; } getName() { - return this.hostname + return this.hostname; } getTargetRef(): ITargetRef { if (this.targetRef) { - return Object.assign(this.targetRef, {apiVersion: "v1"}) + return Object.assign(this.targetRef, {apiVersion: "v1"}); } else { - return null + return null; } } } @@ -68,7 +68,7 @@ export class EndpointSubset implements IEndpointSubset { ports: IEndpointPort[]; constructor(data: IEndpointSubset) { - Object.assign(this, data) + Object.assign(this, data); } getAddresses(): EndpointAddress[] { @@ -83,26 +83,26 @@ export class EndpointSubset implements IEndpointSubset { toString(): string { if(!this.addresses) { - return "" + return ""; } return this.addresses.map(address => { if (!this.ports) { - return address.ip + return address.ip; } return this.ports.map(port => { - return `${address.ip}:${port.port}` - }).join(", ") - }).join(", ") + return `${address.ip}:${port.port}`; + }).join(", "); + }).join(", "); } } @autobind() export class Endpoint extends KubeObject { - static kind = "Endpoints" - static namespaced = true - static apiBase = "/api/v1/endpoints" + static kind = "Endpoints"; + static namespaced = true; + static apiBase = "/api/v1/endpoints"; - subsets: IEndpointSubset[] + subsets: IEndpointSubset[]; getEndpointSubsets(): EndpointSubset[] { const subsets = this.subsets || []; @@ -111,9 +111,9 @@ export class Endpoint extends KubeObject { toString(): string { if(this.subsets) { - return this.getEndpointSubsets().map(es => es.toString()).join(", ") + return this.getEndpointSubsets().map(es => es.toString()).join(", "); } else { - return "" + return ""; } } diff --git a/src/renderer/api/endpoints/events.api.ts b/src/renderer/api/endpoints/events.api.ts index 0608a3d44b..51dbf3c3b5 100644 --- a/src/renderer/api/endpoints/events.api.ts +++ b/src/renderer/api/endpoints/events.api.ts @@ -6,9 +6,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class KubeEvent extends KubeObject { - static kind = "Event" - static namespaced = true - static apiBase = "/api/v1/events" + static kind = "Event"; + static namespaced = true; + static apiBase = "/api/v1/events"; involvedObject: { kind: string; @@ -18,41 +18,41 @@ export class KubeEvent extends KubeObject { apiVersion: string; resourceVersion: string; fieldPath: string; - } - reason: string - message: string + }; + reason: string; + message: string; source: { component: string; host: string; - } - firstTimestamp: string - lastTimestamp: string - count: number - type: string - eventTime: null - reportingComponent: string - reportingInstance: string + }; + firstTimestamp: string; + lastTimestamp: string; + count: number; + type: string; + eventTime: null; + reportingComponent: string; + reportingInstance: string; isWarning() { return this.type === "Warning"; } getSource() { - const { component, host } = this.source - return `${component} ${host || ""}` + const { component, host } = this.source; + return `${component} ${host || ""}`; } getFirstSeenTime() { - const diff = moment().diff(this.firstTimestamp) - return formatDuration(diff, true) + const diff = moment().diff(this.firstTimestamp); + return formatDuration(diff, true); } getLastSeenTime() { - const diff = moment().diff(this.lastTimestamp) - return formatDuration(diff, true) + const diff = moment().diff(this.lastTimestamp); + return formatDuration(diff, true); } } export const eventApi = new KubeApi({ objectConstructor: KubeEvent, -}) +}); diff --git a/src/renderer/api/endpoints/helm-charts.api.ts b/src/renderer/api/endpoints/helm-charts.api.ts index 8943cd49df..e6328f136b 100644 --- a/src/renderer/api/endpoints/helm-charts.api.ts +++ b/src/renderer/api/endpoints/helm-charts.api.ts @@ -41,7 +41,7 @@ export const helmChartsApi = { return { readme, versions, - } + }; }); }, @@ -61,27 +61,27 @@ export class HelmChart { return new HelmChart(data); } - apiVersion: string - name: string - version: string - repo: string - kubeVersion?: string - created: string - description?: string - digest: string - keywords?: string[] - home?: string - sources?: string[] + apiVersion: string; + name: string; + version: string; + repo: string; + kubeVersion?: string; + created: string; + description?: string; + digest: string; + keywords?: string[]; + home?: string; + sources?: string[]; maintainers?: { name: string; email: string; url: string; - }[] - engine?: string - icon?: string - appVersion?: string - deprecated?: boolean - tillerVersion?: string + }[]; + engine?: string; + icon?: string; + appVersion?: string; + deprecated?: boolean; + tillerVersion?: string; getId() { return this.digest; diff --git a/src/renderer/api/endpoints/helm-releases.api.ts b/src/renderer/api/endpoints/helm-releases.api.ts index 9051936ac8..0ddbf1c734 100644 --- a/src/renderer/api/endpoints/helm-releases.api.ts +++ b/src/renderer/api/endpoints/helm-releases.api.ts @@ -82,7 +82,7 @@ export const helmReleasesApi = { return { ...details, resources - } + }; }); }, @@ -135,13 +135,13 @@ export class HelmRelease implements ItemObject { return new HelmRelease(data); } - appVersion: string - name: string - namespace: string - chart: string - status: string - updated: string - revision: string + appVersion: string; + name: string; + namespace: string; + chart: string; + status: string; + updated: string; + revision: string; getId() { return this.namespace + this.name; @@ -156,12 +156,12 @@ export class HelmRelease implements ItemObject { } getChart(withVersion = false) { - let chart = this.chart + let chart = this.chart; if(!withVersion && this.getVersion() != "" ) { - const search = new RegExp(`-${this.getVersion()}`) + const search = new RegExp(`-${this.getVersion()}`); chart = chart.replace(search, ""); } - return chart + return chart; } getRevision() { @@ -173,12 +173,12 @@ export class HelmRelease implements ItemObject { } getVersion() { - const versions = this.chart.match(/(v?\d+)[^-].*$/) + const versions = this.chart.match(/(v?\d+)[^-].*$/); if (versions) { - return versions[0] + return versions[0]; } else { - return "" + return ""; } } diff --git a/src/renderer/api/endpoints/hpa.api.ts b/src/renderer/api/endpoints/hpa.api.ts index f55f6d327f..79e6cada0f 100644 --- a/src/renderer/api/endpoints/hpa.api.ts +++ b/src/renderer/api/endpoints/hpa.api.ts @@ -20,7 +20,7 @@ export type IHpaMetricData = T & { currentAverageValue?: string; targetAverageUtilization?: number; targetAverageValue?: string; -} +}; export interface IHpaMetric { [kind: string]: IHpaMetricData; @@ -41,7 +41,7 @@ export interface IHpaMetric { export class HorizontalPodAutoscaler extends KubeObject { static kind = "HorizontalPodAutoscaler"; static namespaced = true; - static apiBase = "/apis/autoscaling/v2beta1/horizontalpodautoscalers" + static apiBase = "/apis/autoscaling/v2beta1/horizontalpodautoscalers"; spec: { scaleTargetRef: { @@ -52,7 +52,7 @@ export class HorizontalPodAutoscaler extends KubeObject { minReplicas: number; maxReplicas: number; metrics: IHpaMetric[]; - } + }; status: { currentReplicas: number; desiredReplicas: number; @@ -64,7 +64,7 @@ export class HorizontalPodAutoscaler extends KubeObject { status: string; type: string; }[]; - } + }; getMaxPods() { return this.spec.maxReplicas || 0; @@ -86,7 +86,7 @@ export class HorizontalPodAutoscaler extends KubeObject { ...condition, isReady: status === "True", tooltip: `${message || reason} (${lastTransitionTime})` - } + }; }); } @@ -102,7 +102,7 @@ export class HorizontalPodAutoscaler extends KubeObject { const { type, resource, pods, object, external } = metric; switch (type) { case HpaMetricType.Resource: - return resource.name + return resource.name; case HpaMetricType.Pods: return pods.metricName; case HpaMetricType.Object: @@ -128,7 +128,7 @@ export class HorizontalPodAutoscaler extends KubeObject { } if (target) { targetValue = target.targetAverageUtilization || target.targetAverageValue || target.targetValue; - if (target.targetAverageUtilization) targetValue += "%" + if (target.targetAverageUtilization) targetValue += "%"; } return `${currentValue} / ${targetValue}`; } diff --git a/src/renderer/api/endpoints/index.ts b/src/renderer/api/endpoints/index.ts index 337d193043..f1202b9122 100644 --- a/src/renderer/api/endpoints/index.ts +++ b/src/renderer/api/endpoints/index.ts @@ -1,35 +1,35 @@ // Kubernetes apis // Docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/ -export * from "./cluster.api" -export * from "./cluster-role.api" -export * from "./cluster-role-binding.api" -export * from "./configmap.api" -export * from "./crd.api" -export * from "./cron-job.api" -export * from "./daemon-set.api" -export * from "./deployment.api" -export * from "./endpoint.api" -export * from "./events.api" -export * from "./hpa.api" -export * from "./ingress.api" -export * from "./job.api" -export * from "./namespaces.api" -export * from "./network-policy.api" -export * from "./nodes.api" -export * from "./persistent-volume.api" -export * from "./persistent-volume-claims.api" -export * from "./pods.api" -export * from "./poddisruptionbudget.api" -export * from "./pod-metrics.api" -export * from "./podsecuritypolicy.api" -export * from "./replica-set.api" -export * from "./resource-quota.api" -export * from "./role.api" -export * from "./role-binding.api" -export * from "./secret.api" -export * from "./selfsubjectrulesreviews.api" -export * from "./service.api" -export * from "./service-accounts.api" -export * from "./stateful-set.api" -export * from "./storage-class.api" +export * from "./cluster.api"; +export * from "./cluster-role.api"; +export * from "./cluster-role-binding.api"; +export * from "./configmap.api"; +export * from "./crd.api"; +export * from "./cron-job.api"; +export * from "./daemon-set.api"; +export * from "./deployment.api"; +export * from "./endpoint.api"; +export * from "./events.api"; +export * from "./hpa.api"; +export * from "./ingress.api"; +export * from "./job.api"; +export * from "./namespaces.api"; +export * from "./network-policy.api"; +export * from "./nodes.api"; +export * from "./persistent-volume.api"; +export * from "./persistent-volume-claims.api"; +export * from "./pods.api"; +export * from "./poddisruptionbudget.api"; +export * from "./pod-metrics.api"; +export * from "./podsecuritypolicy.api"; +export * from "./replica-set.api"; +export * from "./resource-quota.api"; +export * from "./role.api"; +export * from "./role-binding.api"; +export * from "./secret.api"; +export * from "./selfsubjectrulesreviews.api"; +export * from "./service.api"; +export * from "./service-accounts.api"; +export * from "./stateful-set.api"; +export * from "./storage-class.api"; diff --git a/src/renderer/api/endpoints/ingress.api.ts b/src/renderer/api/endpoints/ingress.api.ts index 1f3e1659f0..0594e3446e 100644 --- a/src/renderer/api/endpoints/ingress.api.ts +++ b/src/renderer/api/endpoints/ingress.api.ts @@ -5,7 +5,7 @@ import { KubeApi } from "../kube-api"; export class IngressApi extends KubeApi { getMetrics(ingress: string, namespace: string): Promise { - const opts = { category: "ingress", ingress } + const opts = { category: "ingress", ingress }; return metricsApi.getMetrics({ bytesSentSuccess: opts, bytesSentFailure: opts, @@ -31,9 +31,9 @@ export interface ILoadBalancerIngress { } @autobind() export class Ingress extends KubeObject { - static kind = "Ingress" - static namespaced = true - static apiBase = "/apis/extensions/v1beta1/ingresses" + static kind = "Ingress"; + static namespaced = true; + static apiBase = "/apis/extensions/v1beta1/ingresses"; spec: { tls: { @@ -55,59 +55,59 @@ export class Ingress extends KubeObject { serviceName: string; servicePort: number; }; - } + }; status: { loadBalancer: { ingress: ILoadBalancerIngress[]; }; - } + }; getRoutes() { - const { spec: { tls, rules } } = this - if (!rules) return [] + const { spec: { tls, rules } } = this; + if (!rules) return []; - let protocol = "http" - const routes: string[] = [] + let protocol = "http"; + const routes: string[] = []; if (tls && tls.length > 0) { - protocol += "s" + protocol += "s"; } rules.map(rule => { - const host = rule.host ? rule.host : "*" + const host = rule.host ? rule.host : "*"; if (rule.http && rule.http.paths) { rule.http.paths.forEach(path => { - routes.push(protocol + "://" + host + (path.path || "/") + " ⇢ " + path.backend.serviceName + ":" + path.backend.servicePort) - }) + routes.push(protocol + "://" + host + (path.path || "/") + " ⇢ " + path.backend.serviceName + ":" + path.backend.servicePort); + }); } - }) + }); return routes; } getHosts() { - const { spec: { rules } } = this - if (!rules) return [] - return rules.filter(rule => rule.host).map(rule => rule.host) + const { spec: { rules } } = this; + if (!rules) return []; + return rules.filter(rule => rule.host).map(rule => rule.host); } getPorts() { - const ports: number[] = [] - const { spec: { tls, rules, backend } } = this - const httpPort = 80 - const tlsPort = 443 + const ports: number[] = []; + const { spec: { tls, rules, backend } } = this; + const httpPort = 80; + const tlsPort = 443; if (rules && rules.length > 0) { if (rules.some(rule => rule.hasOwnProperty("http"))) { - ports.push(httpPort) + ports.push(httpPort); } } else { if (backend && backend.servicePort) { - ports.push(backend.servicePort) + ports.push(backend.servicePort); } } if (tls && tls.length > 0) { - ports.push(tlsPort) + ports.push(tlsPort); } - return ports.join(", ") + return ports.join(", "); } getLoadBalancers() { @@ -115,7 +115,7 @@ export class Ingress extends KubeObject { return (loadBalancer.ingress ?? []).map(address => ( address.hostname || address.ip - )) + )); } } diff --git a/src/renderer/api/endpoints/job.api.ts b/src/renderer/api/endpoints/job.api.ts index 59e9e9ba8f..1dc78fdc94 100644 --- a/src/renderer/api/endpoints/job.api.ts +++ b/src/renderer/api/endpoints/job.api.ts @@ -7,9 +7,9 @@ import { JsonApiParams } from "../json-api"; @autobind() export class Job extends WorkloadKubeObject { - static kind = "Job" - static namespaced = true - static apiBase = "/apis/batch/v1/jobs" + static kind = "Job"; + static namespaced = true; + static apiBase = "/apis/batch/v1/jobs"; spec: { parallelism?: number; @@ -56,7 +56,7 @@ export class Job extends WorkloadKubeObject { serviceAccountName?: string; serviceAccount?: string; schedulerName?: string; - } + }; status: { conditions: { type: string; @@ -68,7 +68,7 @@ export class Job extends WorkloadKubeObject { startTime: string; completionTime: string; succeeded: number; - } + }; getDesiredCompletions() { return this.spec.completions || 0; @@ -91,15 +91,15 @@ export class Job extends WorkloadKubeObject { } getImages() { - const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []) - return [...containers].map(container => container.image) + const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []); + return [...containers].map(container => container.image); } delete() { const params: JsonApiParams = { query: { propagationPolicy: "Background" } - } - return super.delete(params) + }; + return super.delete(params); } } diff --git a/src/renderer/api/endpoints/metrics.api.ts b/src/renderer/api/endpoints/metrics.api.ts index 81d2f1d500..7f30487d44 100644 --- a/src/renderer/api/endpoints/metrics.api.ts +++ b/src/renderer/api/endpoints/metrics.api.ts @@ -66,7 +66,7 @@ export function normalizeMetrics(metrics: IMetrics, frames = 60): IMetrics { } as IMetricsResult], }, status: "", - } + }; } const { result } = metrics.data; @@ -78,7 +78,7 @@ export function normalizeMetrics(metrics: IMetrics, frames = 60): IMetrics { if (!res.values || !res.values.length) return; while (res.values.length < frames) { const timestamp = moment.unix(res.values[0][0]).subtract(1, "minute").unix(); - res.values.unshift([timestamp, "0"]) + res.values.unshift([timestamp, "0"]); } }); } @@ -103,7 +103,7 @@ export function getItemMetrics(metrics: { [key: string]: IMetrics }, itemName: s const itemMetrics = { ...metrics }; for (const metric in metrics) { if (!metrics[metric]?.data?.result) { - continue + continue; } const results = metrics[metric].data.result; const result = results.find(res => Object.values(res.metric)[0] == itemName); diff --git a/src/renderer/api/endpoints/namespaces.api.ts b/src/renderer/api/endpoints/namespaces.api.ts index c615789cd9..430565bf57 100644 --- a/src/renderer/api/endpoints/namespaces.api.ts +++ b/src/renderer/api/endpoints/namespaces.api.ts @@ -15,7 +15,7 @@ export class Namespace extends KubeObject { status?: { phase: string; - } + }; getStatus() { return this.status ? this.status.phase : "-"; diff --git a/src/renderer/api/endpoints/network-policy.api.ts b/src/renderer/api/endpoints/network-policy.api.ts index bfae6cbcdc..4ecd333854 100644 --- a/src/renderer/api/endpoints/network-policy.api.ts +++ b/src/renderer/api/endpoints/network-policy.api.ts @@ -37,9 +37,9 @@ export interface IPolicyEgress { @autobind() export class NetworkPolicy extends KubeObject { - static kind = "NetworkPolicy" - static namespaced = true - static apiBase = "/apis/networking.k8s.io/v1/networkpolicies" + static kind = "NetworkPolicy"; + static namespaced = true; + static apiBase = "/apis/networking.k8s.io/v1/networkpolicies"; spec: { podSelector: { @@ -51,13 +51,13 @@ export class NetworkPolicy extends KubeObject { policyTypes: string[]; ingress: IPolicyIngress[]; egress: IPolicyEgress[]; - } + }; getMatchLabels(): string[] { if (!this.spec.podSelector || !this.spec.podSelector.matchLabels) return []; return Object .entries(this.spec.podSelector.matchLabels) - .map(data => data.join(":")) + .map(data => data.join(":")); } getTypes(): string[] { diff --git a/src/renderer/api/endpoints/nodes.api.ts b/src/renderer/api/endpoints/nodes.api.ts index f8031a9824..c85cd8f9b0 100644 --- a/src/renderer/api/endpoints/nodes.api.ts +++ b/src/renderer/api/endpoints/nodes.api.ts @@ -5,7 +5,7 @@ import { KubeApi } from "../kube-api"; export class NodesApi extends KubeApi { getMetrics(): Promise { - const opts = { category: "nodes"} + const opts = { category: "nodes"}; return metricsApi.getMetrics({ memoryUsage: opts, @@ -30,9 +30,9 @@ export interface INodeMetrics { @autobind() export class Node extends KubeObject { - static kind = "Node" - static namespaced = false - static apiBase = "/api/v1/nodes" + static kind = "Node"; + static namespaced = false; + static apiBase = "/api/v1/nodes"; spec: { podCIDR: string; @@ -43,7 +43,7 @@ export class Node extends KubeObject { effect: string; }[]; unschedulable?: boolean; - } + }; status: { capacity: { cpu: string; @@ -83,15 +83,15 @@ export class Node extends KubeObject { names: string[]; sizeBytes: number; }[]; - } + }; getNodeConditionText() { - const { conditions } = this.status - if (!conditions) return "" + const { conditions } = this.status; + if (!conditions) return ""; return conditions.reduce((types, current) => { - if (current.status !== "True") return "" - return types += ` ${current.type}` - }, "") + if (current.status !== "True") return ""; + return types += ` ${current.type}`; + }, ""); } getTaints() { @@ -101,23 +101,23 @@ export class Node extends KubeObject { getRoleLabels() { const roleLabels = Object.keys(this.metadata.labels).filter(key => key.includes("node-role.kubernetes.io") - ).map(key => key.match(/([^/]+$)/)[0]) // all after last slash + ).map(key => key.match(/([^/]+$)/)[0]); // all after last slash if (this.metadata.labels["kubernetes.io/role"] != undefined) { - roleLabels.push(this.metadata.labels["kubernetes.io/role"]) + roleLabels.push(this.metadata.labels["kubernetes.io/role"]); } - return roleLabels.join(", ") + return roleLabels.join(", "); } getCpuCapacity() { - if (!this.status.capacity || !this.status.capacity.cpu) return 0 - return cpuUnitsToNumber(this.status.capacity.cpu) + if (!this.status.capacity || !this.status.capacity.cpu) return 0; + return cpuUnitsToNumber(this.status.capacity.cpu); } getMemoryCapacity() { - if (!this.status.capacity || !this.status.capacity.memory) return 0 - return unitsToBytes(this.status.capacity.memory) + if (!this.status.capacity || !this.status.capacity.memory) return 0; + return unitsToBytes(this.status.capacity.memory); } getConditions() { @@ -144,16 +144,16 @@ export class Node extends KubeObject { } getOperatingSystem(): string { - const label = this.getLabels().find(label => label.startsWith("kubernetes.io/os=")) + const label = this.getLabels().find(label => label.startsWith("kubernetes.io/os=")); if (label) { - return label.split("=", 2)[1] + return label.split("=", 2)[1]; } - return "linux" + return "linux"; } isUnschedulable() { - return this.spec.unschedulable + return this.spec.unschedulable; } } diff --git a/src/renderer/api/endpoints/persistent-volume-claims.api.ts b/src/renderer/api/endpoints/persistent-volume-claims.api.ts index 4e719c529b..9aa73bb0bc 100644 --- a/src/renderer/api/endpoints/persistent-volume-claims.api.ts +++ b/src/renderer/api/endpoints/persistent-volume-claims.api.ts @@ -23,9 +23,9 @@ export interface IPvcMetrics { @autobind() export class PersistentVolumeClaim extends KubeObject { - static kind = "PersistentVolumeClaim" - static namespaced = true - static apiBase = "/api/v1/persistentvolumeclaims" + static kind = "PersistentVolumeClaim"; + static namespaced = true; + static apiBase = "/api/v1/persistentvolumeclaims"; spec: { accessModes: string[]; @@ -45,19 +45,19 @@ export class PersistentVolumeClaim extends KubeObject { storage: string; // 8Gi }; }; - } + }; status: { phase: string; // Pending - } + }; getPods(allPods: Pod[]): Pod[] { - const pods = allPods.filter(pod => pod.getNs() === this.getNs()) + const pods = allPods.filter(pod => pod.getNs() === this.getNs()); return pods.filter(pod => { return pod.getVolumes().filter(volume => volume.persistentVolumeClaim && volume.persistentVolumeClaim.claimName === this.getName() - ).length > 0 - }) + ).length > 0; + }); } getStorage(): string { @@ -78,7 +78,7 @@ export class PersistentVolumeClaim extends KubeObject { getStatus(): string { if (this.status) return this.status.phase; - return "-" + return "-"; } } diff --git a/src/renderer/api/endpoints/persistent-volume.api.ts b/src/renderer/api/endpoints/persistent-volume.api.ts index 8ab2efbf89..5e31eeb028 100644 --- a/src/renderer/api/endpoints/persistent-volume.api.ts +++ b/src/renderer/api/endpoints/persistent-volume.api.ts @@ -5,9 +5,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class PersistentVolume extends KubeObject { - static kind = "PersistentVolume" - static namespaced = false - static apiBase = "/api/v1/persistentvolumes" + static kind = "PersistentVolume"; + static namespaced = false; + static apiBase = "/api/v1/persistentvolumes"; spec: { capacity: { @@ -38,17 +38,17 @@ export class PersistentVolume extends KubeObject { path: string; server: string; }; - } + }; status: { phase: string; reason?: string; - } + }; getCapacity(inBytes = false) { const capacity = this.spec.capacity; if (capacity) { - if (inBytes) return unitsToBytes(capacity.storage) + if (inBytes) return unitsToBytes(capacity.storage); return capacity.storage; } return 0; diff --git a/src/renderer/api/endpoints/pod-metrics.api.ts b/src/renderer/api/endpoints/pod-metrics.api.ts index 7e01a1a990..acf6e7b20f 100644 --- a/src/renderer/api/endpoints/pod-metrics.api.ts +++ b/src/renderer/api/endpoints/pod-metrics.api.ts @@ -2,19 +2,19 @@ import { KubeObject } from "../kube-object"; import { KubeApi } from "../kube-api"; export class PodMetrics extends KubeObject { - static kind = "Pod" - static namespaced = true - static apiBase = "/apis/metrics.k8s.io/v1beta1/pods" + static kind = "Pod"; + static namespaced = true; + static apiBase = "/apis/metrics.k8s.io/v1beta1/pods"; - timestamp: string - window: string + timestamp: string; + window: string; containers: { name: string; usage: { cpu: string; memory: string; }; - }[] + }[]; } export const podMetricsApi = new KubeApi({ diff --git a/src/renderer/api/endpoints/poddisruptionbudget.api.ts b/src/renderer/api/endpoints/poddisruptionbudget.api.ts index ea7e0575ff..b76260ae6f 100644 --- a/src/renderer/api/endpoints/poddisruptionbudget.api.ts +++ b/src/renderer/api/endpoints/poddisruptionbudget.api.ts @@ -12,13 +12,13 @@ export class PodDisruptionBudget extends KubeObject { minAvailable: string; maxUnavailable: string; selector: { matchLabels: { [app: string]: string } }; - } + }; status: { currentHealthy: number desiredHealthy: number disruptionsAllowed: number expectedPods: number - } + }; getSelectors() { const selector = this.spec.selector; diff --git a/src/renderer/api/endpoints/pods.api.ts b/src/renderer/api/endpoints/pods.api.ts index 92b7059272..a5c833b5fa 100644 --- a/src/renderer/api/endpoints/pods.api.ts +++ b/src/renderer/api/endpoints/pods.api.ts @@ -11,7 +11,7 @@ export class PodsApi extends KubeApi { getMetrics(pods: Pod[], namespace: string, selector = "pod, namespace"): Promise { const podSelector = pods.map(pod => pod.getName()).join("|"); - const opts = { category: "pods", pods: podSelector, namespace, selector } + const opts = { category: "pods", pods: podSelector, namespace, selector }; return metricsApi.getMetrics({ cpuUsage: opts, @@ -171,9 +171,9 @@ export interface IPodContainerStatus { @autobind() export class Pod extends WorkloadKubeObject { - static kind = "Pod" - static namespaced = true - static apiBase = "/api/v1/pods" + static kind = "Pod"; + static namespaced = true; + static apiBase = "/api/v1/pods"; spec: { volumes?: { @@ -215,7 +215,7 @@ export class Pod extends WorkloadKubeObject { tolerationSeconds: number; }[]; affinity: IAffinity; - } + }; status: { phase: string; conditions: { @@ -231,7 +231,7 @@ export class Pod extends WorkloadKubeObject { containerStatuses?: IPodContainerStatus[]; qosClass: string; reason?: string; - } + }; getInitContainers() { return this.spec.initContainers || []; @@ -246,11 +246,11 @@ export class Pod extends WorkloadKubeObject { } getRunningContainers() { - const statuses = this.getContainerStatuses() + const statuses = this.getContainerStatuses(); return this.getAllContainers().filter(container => { - return statuses.find(status => status.name === container.name && !!status.state["running"]) + return statuses.find(status => status.name === container.name && !!status.state["running"]); } - ) + ); } getContainerStatuses(includeInitContainers = true) { @@ -323,7 +323,7 @@ export class Pod extends WorkloadKubeObject { const { reason } = state.terminated; message = reason ? reason : "Terminated"; } - }) + }); } if (message) return message; return this.getStatusPhase(); @@ -348,32 +348,32 @@ export class Pod extends WorkloadKubeObject { } getNodeSelectors(): string[] { - const { nodeSelector } = this.spec - if (!nodeSelector) return [] - return Object.entries(nodeSelector).map(values => values.join(": ")) + const { nodeSelector } = this.spec; + if (!nodeSelector) return []; + return Object.entries(nodeSelector).map(values => values.join(": ")); } getTolerations() { - return this.spec.tolerations || [] + return this.spec.tolerations || []; } getAffinity(): IAffinity { - return this.spec.affinity + return this.spec.affinity; } hasIssues() { const notReady = !!this.getConditions().find(condition => { - return condition.type == "Ready" && condition.status !== "True" + return condition.type == "Ready" && condition.status !== "True"; }); const crashLoop = !!this.getContainerStatuses().find(condition => { - const waiting = condition.state.waiting - return (waiting && waiting.reason == "CrashLoopBackOff") - }) + const waiting = condition.state.waiting; + return (waiting && waiting.reason == "CrashLoopBackOff"); + }); return ( notReady || crashLoop || this.getStatusPhase() !== "Running" - ) + ); } getLivenessProbe(container: IPodContainer) { @@ -418,14 +418,14 @@ export class Pod extends WorkloadKubeObject { } getNodeName() { - return this.spec?.nodeName + return this.spec?.nodeName; } getSelectedNodeOs() { - if (!this.spec.nodeSelector) return - if (!this.spec.nodeSelector["kubernetes.io/os"] && !this.spec.nodeSelector["beta.kubernetes.io/os"]) return + if (!this.spec.nodeSelector) return; + if (!this.spec.nodeSelector["kubernetes.io/os"] && !this.spec.nodeSelector["beta.kubernetes.io/os"]) return; - return this.spec.nodeSelector["kubernetes.io/os"] || this.spec.nodeSelector["beta.kubernetes.io/os"] + return this.spec.nodeSelector["kubernetes.io/os"] || this.spec.nodeSelector["beta.kubernetes.io/os"]; } } diff --git a/src/renderer/api/endpoints/podsecuritypolicy.api.ts b/src/renderer/api/endpoints/podsecuritypolicy.api.ts index aa705c8748..c7981f65be 100644 --- a/src/renderer/api/endpoints/podsecuritypolicy.api.ts +++ b/src/renderer/api/endpoints/podsecuritypolicy.api.ts @@ -4,9 +4,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class PodSecurityPolicy extends KubeObject { - static kind = "PodSecurityPolicy" - static namespaced = false - static apiBase = "/apis/policy/v1beta1/podsecuritypolicies" + static kind = "PodSecurityPolicy"; + static namespaced = false; + static apiBase = "/apis/policy/v1beta1/podsecuritypolicies"; spec: { allowPrivilegeEscalation?: boolean; @@ -66,7 +66,7 @@ export class PodSecurityPolicy extends KubeObject { ranges: { max: number; min: number }[]; }; volumes?: string[]; - } + }; isPrivileged() { return !!this.spec.privileged; diff --git a/src/renderer/api/endpoints/replica-set.api.ts b/src/renderer/api/endpoints/replica-set.api.ts index dd06299644..d1081811e9 100644 --- a/src/renderer/api/endpoints/replica-set.api.ts +++ b/src/renderer/api/endpoints/replica-set.api.ts @@ -6,9 +6,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class ReplicaSet extends WorkloadKubeObject { - static kind = "ReplicaSet" - static namespaced = true - static apiBase = "/apis/apps/v1/replicasets" + static kind = "ReplicaSet"; + static namespaced = true; + static apiBase = "/apis/apps/v1/replicasets"; spec: { replicas?: number; @@ -37,18 +37,18 @@ export class ReplicaSet extends WorkloadKubeObject { terminationGracePeriodSeconds?: number; dnsPolicy?: string; schedulerName?: string; - } + }; status: { replicas: number; fullyLabeledReplicas: number; readyReplicas: number; availableReplicas: number; observedGeneration: number; - } + }; getImages() { - const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []) - return [...containers].map(container => container.image) + const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []); + return [...containers].map(container => container.image); } } diff --git a/src/renderer/api/endpoints/resource-applier.api.ts b/src/renderer/api/endpoints/resource-applier.api.ts index 088c7ed8f2..a2843a6262 100644 --- a/src/renderer/api/endpoints/resource-applier.api.ts +++ b/src/renderer/api/endpoints/resource-applier.api.ts @@ -1,4 +1,4 @@ -import jsYaml from "js-yaml" +import jsYaml from "js-yaml"; import { KubeObject } from "../kube-object"; import { KubeJsonApiData } from "../kube-json-api"; import { apiBase } from "../index"; @@ -21,7 +21,7 @@ export const resourceApplierApi = { if (api) { return new api.objectConstructor(obj); } else { - return new KubeObject(obj) + return new KubeObject(obj); } }); return items.length === 1 ? items[0] : items; diff --git a/src/renderer/api/endpoints/resource-quota.api.ts b/src/renderer/api/endpoints/resource-quota.api.ts index ce73d24595..a19e4025c5 100644 --- a/src/renderer/api/endpoints/resource-quota.api.ts +++ b/src/renderer/api/endpoints/resource-quota.api.ts @@ -31,13 +31,13 @@ export interface IResourceQuotaValues { } export class ResourceQuota extends KubeObject { - static kind = "ResourceQuota" - static namespaced = true - static apiBase = "/api/v1/resourcequotas" + static kind = "ResourceQuota"; + static namespaced = true; + static apiBase = "/api/v1/resourcequotas"; constructor(data: KubeJsonApiData) { super(data); - this.spec = this.spec || {} as any + this.spec = this.spec || {} as any; } spec: { @@ -49,12 +49,12 @@ export class ResourceQuota extends KubeObject { values: string[]; }[]; }; - } + }; status: { hard: IResourceQuotaValues; used: IResourceQuotaValues; - } + }; getScopeSelector() { const { matchExpressions = [] } = this.spec.scopeSelector || {}; diff --git a/src/renderer/api/endpoints/role-binding.api.ts b/src/renderer/api/endpoints/role-binding.api.ts index 455e2c6e4d..866656ee56 100644 --- a/src/renderer/api/endpoints/role-binding.api.ts +++ b/src/renderer/api/endpoints/role-binding.api.ts @@ -11,23 +11,23 @@ export interface IRoleBindingSubject { @autobind() export class RoleBinding extends KubeObject { - static kind = "RoleBinding" - static namespaced = true - static apiBase = "/apis/rbac.authorization.k8s.io/v1/rolebindings" + static kind = "RoleBinding"; + static namespaced = true; + static apiBase = "/apis/rbac.authorization.k8s.io/v1/rolebindings"; - subjects?: IRoleBindingSubject[] + subjects?: IRoleBindingSubject[]; roleRef: { kind: string; name: string; apiGroup?: string; - } + }; getSubjects() { return this.subjects || []; } getSubjectNames(): string { - return this.getSubjects().map(subject => subject.name).join(", ") + return this.getSubjects().map(subject => subject.name).join(", "); } } diff --git a/src/renderer/api/endpoints/role.api.ts b/src/renderer/api/endpoints/role.api.ts index 400761cfbe..c89834ed05 100644 --- a/src/renderer/api/endpoints/role.api.ts +++ b/src/renderer/api/endpoints/role.api.ts @@ -2,16 +2,16 @@ import { KubeObject } from "../kube-object"; import { KubeApi } from "../kube-api"; export class Role extends KubeObject { - static kind = "Role" - static namespaced = true - static apiBase = "/apis/rbac.authorization.k8s.io/v1/roles" + static kind = "Role"; + static namespaced = true; + static apiBase = "/apis/rbac.authorization.k8s.io/v1/roles"; rules: { verbs: string[]; apiGroups: string[]; resources: string[]; resourceNames?: string[]; - }[] + }[]; getRules() { return this.rules || []; diff --git a/src/renderer/api/endpoints/secret.api.ts b/src/renderer/api/endpoints/secret.api.ts index f2166abbe1..16262570df 100644 --- a/src/renderer/api/endpoints/secret.api.ts +++ b/src/renderer/api/endpoints/secret.api.ts @@ -21,15 +21,15 @@ export interface ISecretRef { @autobind() export class Secret extends KubeObject { - static kind = "Secret" - static namespaced = true - static apiBase = "/api/v1/secrets" + static kind = "Secret"; + static namespaced = true; + static apiBase = "/api/v1/secrets"; type: SecretType; data: { [prop: string]: string; token?: string; - } + }; constructor(data: KubeJsonApiData) { super(data); diff --git a/src/renderer/api/endpoints/selfsubjectrulesreviews.api.ts b/src/renderer/api/endpoints/selfsubjectrulesreviews.api.ts index 1beece3fc3..149a94e678 100644 --- a/src/renderer/api/endpoints/selfsubjectrulesreviews.api.ts +++ b/src/renderer/api/endpoints/selfsubjectrulesreviews.api.ts @@ -21,20 +21,20 @@ export interface ISelfSubjectReviewRule { } export class SelfSubjectRulesReview extends KubeObject { - static kind = "SelfSubjectRulesReview" - static namespaced = false - static apiBase = "/apis/authorization.k8s.io/v1/selfsubjectrulesreviews" + static kind = "SelfSubjectRulesReview"; + static namespaced = false; + static apiBase = "/apis/authorization.k8s.io/v1/selfsubjectrulesreviews"; spec: { // todo: add more types from api docs namespace?: string; - } + }; status: { resourceRules: ISelfSubjectReviewRule[]; nonResourceRules: ISelfSubjectReviewRule[]; incomplete: boolean; - } + }; getResourceRules() { const rules = this.status && this.status.resourceRules || []; @@ -58,7 +58,7 @@ export class SelfSubjectRulesReview extends KubeObject { const separator = apiGroup == "" ? "" : "."; return resource + separator + apiGroup; }) - } + }; } } diff --git a/src/renderer/api/endpoints/service-accounts.api.ts b/src/renderer/api/endpoints/service-accounts.api.ts index 4f3ae47014..9f449cdec4 100644 --- a/src/renderer/api/endpoints/service-accounts.api.ts +++ b/src/renderer/api/endpoints/service-accounts.api.ts @@ -6,14 +6,14 @@ import { KubeApi } from "../kube-api"; export class ServiceAccount extends KubeObject { static kind = "ServiceAccount"; static namespaced = true; - static apiBase = "/api/v1/serviceaccounts" + static apiBase = "/api/v1/serviceaccounts"; secrets?: { name: string; - }[] + }[]; imagePullSecrets?: { name: string; - }[] + }[]; getSecrets() { return this.secrets || []; diff --git a/src/renderer/api/endpoints/service.api.ts b/src/renderer/api/endpoints/service.api.ts index 49ac733220..5524e85263 100644 --- a/src/renderer/api/endpoints/service.api.ts +++ b/src/renderer/api/endpoints/service.api.ts @@ -17,7 +17,7 @@ export class ServicePort implements IServicePort { nodePort?: number; constructor(data: IServicePort) { - Object.assign(this, data) + Object.assign(this, data); } toString() { @@ -31,9 +31,9 @@ export class ServicePort implements IServicePort { @autobind() export class Service extends KubeObject { - static kind = "Service" - static namespaced = true - static apiBase = "/api/v1/services" + static kind = "Service"; + static namespaced = true; + static apiBase = "/api/v1/services"; spec: { type: string; @@ -44,7 +44,7 @@ export class Service extends KubeObject { selector: { [key: string]: string }; ports: ServicePort[]; externalIPs?: string[]; // https://kubernetes.io/docs/concepts/services-networking/service/#external-ips - } + }; status: { loadBalancer?: { @@ -53,7 +53,7 @@ export class Service extends KubeObject { hostname?: string; }[]; }; - } + }; getClusterIp() { return this.spec.clusterIP; @@ -62,7 +62,7 @@ export class Service extends KubeObject { getExternalIps() { const lb = this.getLoadBalancer(); if (lb && lb.ingress) { - return lb.ingress.map(val => val.ip || val.hostname) + return lb.ingress.map(val => val.ip || val.hostname); } return this.spec.externalIPs || []; } diff --git a/src/renderer/api/endpoints/stateful-set.api.ts b/src/renderer/api/endpoints/stateful-set.api.ts index c507e7df59..6a6f8c151d 100644 --- a/src/renderer/api/endpoints/stateful-set.api.ts +++ b/src/renderer/api/endpoints/stateful-set.api.ts @@ -6,9 +6,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class StatefulSet extends WorkloadKubeObject { - static kind = "StatefulSet" - static namespaced = true - static apiBase = "/apis/apps/v1/statefulsets" + static kind = "StatefulSet"; + static namespaced = true; + static apiBase = "/apis/apps/v1/statefulsets"; spec: { serviceName: string; @@ -62,7 +62,7 @@ export class StatefulSet extends WorkloadKubeObject { }; }; }[]; - } + }; status: { observedGeneration: number; replicas: number; @@ -70,11 +70,11 @@ export class StatefulSet extends WorkloadKubeObject { currentRevision: string; updateRevision: string; collisionCount: number; - } + }; getImages() { - const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []) - return [...containers].map(container => container.image) + const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []); + return [...containers].map(container => container.image); } } diff --git a/src/renderer/api/endpoints/storage-class.api.ts b/src/renderer/api/endpoints/storage-class.api.ts index cf05e13eaf..adb2059e4a 100644 --- a/src/renderer/api/endpoints/storage-class.api.ts +++ b/src/renderer/api/endpoints/storage-class.api.ts @@ -4,9 +4,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class StorageClass extends KubeObject { - static kind = "StorageClass" - static namespaced = false - static apiBase = "/apis/storage.k8s.io/v1/storageclasses" + static kind = "StorageClass"; + static namespaced = false; + static apiBase = "/apis/storage.k8s.io/v1/storageclasses"; provisioner: string; // e.g. "storage.k8s.io/v1" mountOptions?: string[]; @@ -14,22 +14,22 @@ export class StorageClass extends KubeObject { reclaimPolicy: string; parameters: { [param: string]: string; // every provisioner has own set of these parameters - } + }; isDefault() { const annotations = this.metadata.annotations || {}; return ( annotations["storageclass.kubernetes.io/is-default-class"] === "true" || annotations["storageclass.beta.kubernetes.io/is-default-class"] === "true" - ) + ); } getVolumeBindingMode() { - return this.volumeBindingMode || "-" + return this.volumeBindingMode || "-"; } getReclaimPolicy() { - return this.reclaimPolicy || "-" + return this.reclaimPolicy || "-"; } } diff --git a/src/renderer/api/json-api.ts b/src/renderer/api/json-api.ts index e42996c041..cc239a804e 100644 --- a/src/renderer/api/json-api.ts +++ b/src/renderer/api/json-api.ts @@ -110,23 +110,23 @@ export class JsonApi { } else { const error = new JsonApiErrorParsed(data, this.parseError(data, res)); this.onError.emit(error, res); - this.writeLog({ ...log, error }) + this.writeLog({ ...log, error }); throw error; } - }) + }); } protected parseError(error: JsonApiError | string, res: Response): string[] { if (typeof error === "string") { - return [error] + return [error]; } else if (Array.isArray(error.errors)) { - return error.errors.map(error => error.title) + return error.errors.map(error => error.title); } else if (error.message) { - return [error.message] + return [error.message]; } - return [res.statusText || "Error!"] + return [res.statusText || "Error!"]; } protected writeLog(log: JsonApiLog) { diff --git a/src/renderer/api/kube-api-parse.ts b/src/renderer/api/kube-api-parse.ts index c4c93562cf..0995fac24f 100644 --- a/src/renderer/api/kube-api-parse.ts +++ b/src/renderer/api/kube-api-parse.ts @@ -51,7 +51,7 @@ export function parseKubeApi(path: string): IKubeApiParsed { } else { switch (left.length) { case 4: - [apiGroup, apiVersion, resource, name] = left + [apiGroup, apiVersion, resource, name] = left; break; case 2: resource = left.pop(); @@ -79,11 +79,11 @@ export function parseKubeApi(path: string): IKubeApiParsed { */ if (left[0].includes('.') || left[1].match(/^v[0-9]/)) { [apiGroup, apiVersion] = left; - resource = left.slice(2).join("/") + resource = left.slice(2).join("/"); } else { apiGroup = ""; apiVersion = left[0]; - [resource, name] = left.slice(1) + [resource, name] = left.slice(1); } break; } @@ -93,7 +93,7 @@ export function parseKubeApi(path: string): IKubeApiParsed { const apiBase = [apiPrefix, apiGroup, apiVersion, resource].filter(v => v).join("/"); if (!apiBase) { - throw new Error(`invalid apiPath: ${path}`) + throw new Error(`invalid apiPath: ${path}`); } return { @@ -108,11 +108,11 @@ export function createKubeApiURL(ref: IKubeApiLinkRef): string { const { apiPrefix = "/apis", resource, apiVersion, name } = ref; let { namespace } = ref; if (namespace) { - namespace = `namespaces/${namespace}` + namespace = `namespaces/${namespace}`; } return [apiPrefix, apiVersion, namespace, resource, name] .filter(v => v) - .join("/") + .join("/"); } export function lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): string { @@ -124,9 +124,9 @@ export function lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): st if (!kind) return ""; // search in registered apis by 'kind' & 'apiVersion' - const api = apiManager.getApi(api => api.kind === kind && api.apiVersionWithGroup == apiVersion) + const api = apiManager.getApi(api => api.kind === kind && api.apiVersionWithGroup == apiVersion); if (api) { - return api.getUrl({ namespace, name }) + return api.getUrl({ namespace, name }); } // lookup api by generated resource link @@ -142,10 +142,10 @@ export function lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): st // resolve by kind only (hpa's might use refs to older versions of resources for example) const apiByKind = apiManager.getApi(api => api.kind === kind); if (apiByKind) { - return apiByKind.getUrl({ name, namespace }) + return apiByKind.getUrl({ name, namespace }); } // otherwise generate link with default prefix // resource still might exists in k8s, but api is not registered in the app - return createKubeApiURL({ apiVersion, name, namespace, resource }) + return createKubeApiURL({ apiVersion, name, namespace, resource }); } diff --git a/src/renderer/api/kube-api.ts b/src/renderer/api/kube-api.ts index c3c9698cfa..d4840d3620 100644 --- a/src/renderer/api/kube-api.ts +++ b/src/renderer/api/kube-api.ts @@ -1,6 +1,6 @@ // Base class for building all kubernetes apis -import merge from "lodash/merge" +import merge from "lodash/merge"; import { stringify } from "querystring"; import { IKubeObjectConstructor, KubeObject } from "./kube-object"; import { KubeJsonApi, KubeJsonApiData, KubeJsonApiDataList } from "./kube-json-api"; @@ -51,7 +51,7 @@ export function forCluster(cluster: IKubeApiCluster, kubeC return new KubeApi({ objectConstructor: kubeClass, request: request - }) + }); } export class KubeApi { @@ -62,14 +62,14 @@ export class KubeApi { return () => disposers.forEach(unwatch => unwatch()); } - readonly kind: string - readonly apiBase: string - readonly apiPrefix: string - readonly apiGroup: string - readonly apiVersion: string + readonly kind: string; + readonly apiBase: string; + readonly apiPrefix: string; + readonly apiGroup: string; + readonly apiVersion: string; readonly apiVersionPreferred?: string; - readonly apiResource: string - readonly isNamespaced: boolean + readonly apiResource: string; + readonly isNamespaced: boolean; public objectConstructor: IKubeObjectConstructor; protected request: KubeJsonApi; @@ -83,7 +83,7 @@ export class KubeApi { isNamespaced = options.objectConstructor?.namespaced } = options || {}; if (!options.apiBase) { - options.apiBase = objectConstructor.apiBase + options.apiBase = objectConstructor.apiBase; } const { apiBase, apiPrefix, apiGroup, apiVersion, apiVersionWithGroup, resource } = KubeApi.parseApi(options.apiBase); @@ -105,7 +105,7 @@ export class KubeApi { get apiVersionWithGroup() { return [this.apiGroup, this.apiVersionPreferred ?? this.apiVersion] .filter(Boolean) - .join("/") + .join("/"); } protected async checkPreferredVersion() { @@ -116,7 +116,7 @@ export class KubeApi { }); if (this.apiVersionPreferred) { - Object.defineProperty(this, "apiBase", { value: this.getUrl() }) + Object.defineProperty(this, "apiBase", { value: this.getUrl() }); apiManager.registerApi(this.apiBase, this); } } @@ -147,10 +147,10 @@ export class KubeApi { protected normalizeQuery(query: Partial = {}) { if (query.labelSelector) { - query.labelSelector = [query.labelSelector].flat().join(",") + query.labelSelector = [query.labelSelector].flat().join(","); } if (query.fieldSelector) { - query.fieldSelector = [query.fieldSelector].flat().join(",") + query.fieldSelector = [query.fieldSelector].flat().join(","); } return query; } @@ -170,7 +170,7 @@ export class KubeApi { kind: this.kind, apiVersion: apiVersion, ...item, - })) + })); } // custom apis might return array for list response, e.g. users, groups, etc. @@ -218,13 +218,13 @@ export class KubeApi { const apiUrl = this.getUrl({ namespace, name }); return this.request .put(apiUrl, { data }) - .then(this.parseResponse) + .then(this.parseResponse); } async delete({ name = "", namespace = "default" }) { await this.checkPreferredVersion(); const apiUrl = this.getUrl({ namespace, name }); - return this.request.del(apiUrl) + return this.request.del(apiUrl); } getWatchUrl(namespace = "", query: IKubeApiQueryParams = {}) { @@ -232,7 +232,7 @@ export class KubeApi { watch: 1, resourceVersion: this.getResourceVersion(namespace), ...query, - }) + }); } watch(): () => void { @@ -240,4 +240,4 @@ export class KubeApi { } } -export * from "./kube-api-parse" +export * from "./kube-api-parse"; diff --git a/src/renderer/api/kube-object-detail-registry.ts b/src/renderer/api/kube-object-detail-registry.ts index f844da9ef3..5246254532 100644 --- a/src/renderer/api/kube-object-detail-registry.ts +++ b/src/renderer/api/kube-object-detail-registry.ts @@ -1 +1 @@ -export { kubeObjectDetailRegistry } from "../../extensions/registries/kube-object-detail-registry" +export { kubeObjectDetailRegistry } from "../../extensions/registries/kube-object-detail-registry"; diff --git a/src/renderer/api/kube-object.ts b/src/renderer/api/kube-object.ts index 664f9a5c22..8d0e6123f3 100644 --- a/src/renderer/api/kube-object.ts +++ b/src/renderer/api/kube-object.ts @@ -65,20 +65,20 @@ export class KubeObject implements ItemObject { static stringifyLabels(labels: { [name: string]: string }): string[] { if (!labels) return []; - return Object.entries(labels).map(([name, value]) => `${name}=${value}`) + return Object.entries(labels).map(([name, value]) => `${name}=${value}`); } constructor(data: KubeJsonApiData) { Object.assign(this, data); } - apiVersion: string - kind: string + apiVersion: string; + kind: string; metadata: IKubeObjectMetadata; status?: any; // todo: type-safety support get selfLink() { - return this.metadata.selfLink + return this.metadata.selfLink; } getId() { @@ -131,18 +131,18 @@ export class KubeObject implements ItemObject { return refs.map(ownerRef => ({ ...ownerRef, namespace: this.getNs(), - })) + })); } getSearchFields() { - const { getName, getId, getNs, getAnnotations, getLabels } = this + const { getName, getId, getNs, getAnnotations, getLabels } = this; return [ getName(), getNs(), getId(), ...getLabels(), ...getAnnotations(true), - ] + ]; } toPlainObject(): object { diff --git a/src/renderer/api/kube-watch-api.ts b/src/renderer/api/kube-watch-api.ts index 56c3fc1c86..8ce44fb77c 100644 --- a/src/renderer/api/kube-watch-api.ts +++ b/src/renderer/api/kube-watch-api.ts @@ -1,7 +1,7 @@ // Kubernetes watch-api consumer import { computed, observable, reaction } from "mobx"; -import { stringify } from "querystring" +import { stringify } from "querystring"; import { autobind, EventEmitter } from "../utils"; import { KubeJsonApiData } from "./kube-json-api"; import type { KubeObjectStore } from "../kube-object.store"; @@ -61,13 +61,13 @@ export class KubeWatchApi { } protected getQuery(): Partial { - const { isAdmin, allowedNamespaces } = getHostedCluster() + const { isAdmin, allowedNamespaces } = getHostedCluster(); return { api: this.activeApis.map(api => { if (isAdmin) return api.getWatchUrl(); - return allowedNamespaces.map(namespace => api.getWatchUrl(namespace)) + return allowedNamespaces.map(namespace => api.getWatchUrl(namespace)); }).flat() - } + }; } // todo: maybe switch to websocket to avoid often reconnects @@ -119,11 +119,11 @@ export class KubeWatchApi { await api.refreshResourceVersion({ namespace }); this.reconnect(); } catch (error) { - console.error("failed to refresh resource version", error) + console.error("failed to refresh resource version", error); if (this.subscribers.size > 0) { setTimeout(() => { - this.onRouteEvent(event) - }, 1000) + this.onRouteEvent(event); + }, 1000); } } } diff --git a/src/renderer/api/terminal-api.ts b/src/renderer/api/terminal-api.ts index 0e8bba2df6..4f66544f86 100644 --- a/src/renderer/api/terminal-api.ts +++ b/src/renderer/api/terminal-api.ts @@ -1,7 +1,7 @@ import { stringify } from "querystring"; import { autobind, base64, EventEmitter } from "../utils"; import { WebSocketApi } from "./websocket-api"; -import isEqual from "lodash/isEqual" +import isEqual from "lodash/isEqual"; import { isDevelopment } from "../../common/vars"; export enum TerminalChannels { @@ -28,7 +28,7 @@ export type TerminalApiQuery = Record & { id: string; node?: string; type?: string | "node"; -} +}; export class TerminalApi extends WebSocketApi { protected size: { Width: number; Height: number }; @@ -51,7 +51,7 @@ export class TerminalApi extends WebSocketApi { const wss = `ws${protocol === "https:" ? "s" : ""}://`; const query: TerminalApiQuery = { id }; if (port) { - port = `:${port}` + port = `:${port}`; } if (node) { query.node = node; diff --git a/src/renderer/api/websocket-api.ts b/src/renderer/api/websocket-api.ts index cb94881035..934d6cded6 100644 --- a/src/renderer/api/websocket-api.ts +++ b/src/renderer/api/websocket-api.ts @@ -146,7 +146,7 @@ export class WebSocketApi { } protected _onError(evt: Event) { - this.writeLog('%cERROR', 'color:red;font-weight:bold;', evt) + this.writeLog('%cERROR', 'color:red;font-weight:bold;', evt); } protected _onClose(evt: CloseEvent) { diff --git a/src/renderer/api/workload-kube-object.ts b/src/renderer/api/workload-kube-object.ts index c18b8df6c4..51c0461f15 100644 --- a/src/renderer/api/workload-kube-object.ts +++ b/src/renderer/api/workload-kube-object.ts @@ -65,16 +65,16 @@ export class WorkloadKubeObject extends KubeObject { } getTolerations(): IToleration[] { - return get(this, "spec.template.spec.tolerations", []) + return get(this, "spec.template.spec.tolerations", []); } getAffinity(): IAffinity { - return get(this, "spec.template.spec.affinity") + return get(this, "spec.template.spec.affinity"); } getAffinityNumber() { - const affinity = this.getAffinity() - if (!affinity) return 0 - return Object.keys(affinity).length + const affinity = this.getAffinity(); + if (!affinity) return 0; + return Object.keys(affinity).length; } } \ No newline at end of file diff --git a/src/renderer/bootstrap.tsx b/src/renderer/bootstrap.tsx index cfadb5c379..7aa78f1682 100644 --- a/src/renderer/bootstrap.tsx +++ b/src/renderer/bootstrap.tsx @@ -1,9 +1,9 @@ -import "./components/app.scss" +import "./components/app.scss"; import React from "react"; -import * as Mobx from "mobx" -import * as MobxReact from "mobx-react" -import * as LensExtensions from "../extensions/extension-api" +import * as Mobx from "mobx"; +import * as MobxReact from "mobx-react"; +import * as LensExtensions from "../extensions/extension-api"; import { App } from "./components/app"; import { LensApp } from "./lens-app"; import { render, unmountComponentAtNode } from "react-dom"; @@ -18,20 +18,20 @@ import { extensionLoader } from "../extensions/extension-loader"; type AppComponent = React.ComponentType & { init?(): Promise; -} +}; export { React, Mobx, MobxReact, LensExtensions -} +}; export async function bootstrap(App: AppComponent) { - const rootElem = document.getElementById("app") + const rootElem = document.getElementById("app"); rootElem.classList.toggle("is-mac", isMac); - extensionLoader.init() + extensionLoader.init(); // preload common stores await Promise.all([ @@ -53,13 +53,13 @@ export async function bootstrap(App: AppComponent) { } window.addEventListener("message", (ev: MessageEvent) => { if (ev.data === "teardown") { - userStore.unregisterIpcListener() - workspaceStore.unregisterIpcListener() - clusterStore.unregisterIpcListener() - unmountComponentAtNode(rootElem) - window.location.href = "about:blank" + userStore.unregisterIpcListener(); + workspaceStore.unregisterIpcListener(); + clusterStore.unregisterIpcListener(); + unmountComponentAtNode(rootElem); + window.location.href = "about:blank"; } - }) + }); render(<> {isMac && } diff --git a/src/renderer/components/+404/index.ts b/src/renderer/components/+404/index.ts index 7314f53562..67433b02c3 100644 --- a/src/renderer/components/+404/index.ts +++ b/src/renderer/components/+404/index.ts @@ -1 +1 @@ -export * from "./not-found" +export * from "./not-found"; diff --git a/src/renderer/components/+add-cluster/add-cluster.route.ts b/src/renderer/components/+add-cluster/add-cluster.route.ts index ba3ffcd104..3f1e36be9e 100644 --- a/src/renderer/components/+add-cluster/add-cluster.route.ts +++ b/src/renderer/components/+add-cluster/add-cluster.route.ts @@ -3,6 +3,6 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const addClusterRoute: RouteProps = { path: "/add-cluster" -} +}; -export const addClusterURL = buildURL(addClusterRoute.path) +export const addClusterURL = buildURL(addClusterRoute.path); diff --git a/src/renderer/components/+add-cluster/add-cluster.tsx b/src/renderer/components/+add-cluster/add-cluster.tsx index 8acd3a51ea..abb28d090e 100644 --- a/src/renderer/components/+add-cluster/add-cluster.tsx +++ b/src/renderer/components/+add-cluster/add-cluster.tsx @@ -1,4 +1,4 @@ -import "./add-cluster.scss" +import "./add-cluster.scss"; import os from "os"; import React, { Fragment } from "react"; import { observer } from "mobx-react"; @@ -16,7 +16,7 @@ import { WizardLayout } from "../layout/wizard-layout"; import { kubeConfigDefaultPath, loadConfig, splitConfig, validateConfig, validateKubeConfig } from "../../../common/kube-helpers"; import { ClusterModel, ClusterStore, clusterStore } from "../../../common/cluster-store"; import { workspaceStore } from "../../../common/workspace-store"; -import { v4 as uuid } from "uuid" +import { v4 as uuid } from "uuid"; import { navigate } from "../../navigation"; import { userStore } from "../../../common/user-store"; import { clusterViewURL } from "../cluster-manager/cluster-view.route"; @@ -39,10 +39,10 @@ export class AddCluster extends React.Component { @observable selectedContexts = observable.array(); @observable sourceTab = KubeConfigSourceTab.FILE; @observable kubeConfigPath = ""; - @observable customConfig = "" - @observable proxyServer = "" - @observable isWaiting = false - @observable showSettings = false + @observable customConfig = ""; + @observable proxyServer = ""; + @observable isWaiting = false; + @observable showSettings = false; @observable dropAreaActive = false; componentDidMount() { @@ -84,7 +84,7 @@ export class AddCluster extends React.Component { break; case KubeConfigSourceTab.TEXT: try { - this.error = "" + this.error = ""; const contexts = this.getContexts(loadConfig(this.customConfig || "{}")); this.kubeContexts.replace(contexts); } catch (err) { @@ -94,7 +94,7 @@ export class AddCluster extends React.Component { } if (this.kubeContexts.size === 1) { - this.selectedContexts.push(this.kubeContexts.keys().next().value) + this.selectedContexts.push(this.kubeContexts.keys().next().value); } } @@ -102,8 +102,8 @@ export class AddCluster extends React.Component { const contexts = new Map(); splitConfig(config).forEach(config => { contexts.set(config.currentContext, config); - }) - return contexts + }); + return contexts; } selectKubeConfigDialog = async () => { @@ -117,18 +117,18 @@ export class AddCluster extends React.Component { if (!canceled && filePaths.length) { this.setKubeConfig(filePaths[0]); } - } + }; @action addClusters = () => { let newClusters: ClusterModel[] = []; try { if (!this.selectedContexts.length) { - this.error = Please select at least one cluster context + this.error = Please select at least one cluster context; return; } - this.error = "" - this.isWaiting = true + this.error = ""; + this.isWaiting = true; newClusters = this.selectedContexts.filter(context => { try { @@ -136,7 +136,7 @@ export class AddCluster extends React.Component { validateKubeConfig(kubeConfig); return true; } catch (err) { - this.error = String(err.message) + this.error = String(err.message); if (err instanceof ExecValidationNotFoundError ) { Notifications.error(Error while adding cluster(s): {this.error}); return false; @@ -159,8 +159,8 @@ export class AddCluster extends React.Component { clusterName: kubeConfig.currentContext, httpsProxy: this.proxyServer || undefined, }, - } - }) + }; + }); runInAction(() => { clusterStore.addClusters(...newClusters); @@ -175,7 +175,7 @@ export class AddCluster extends React.Component { ); } } - }) + }); this.refreshContexts(); } catch (err) { this.error = String(err); @@ -183,7 +183,7 @@ export class AddCluster extends React.Component { } finally { this.isWaiting = false; } - } + }; renderInfo() { return ( @@ -218,7 +218,7 @@ export class AddCluster extends React.Component { Lens app might not have all login shell env variables set automatically. - ) + ); } renderKubeConfigSource() { @@ -281,7 +281,7 @@ export class AddCluster extends React.Component { > )} > - ) + ); } renderContextSelector() { @@ -302,7 +302,7 @@ export class AddCluster extends React.Component { noOptionsMessage={() => _i18n._(t`No contexts available or they have been added already`)} onChange={({ value: ctx }: SelectOption) => { if (this.selectedContexts.includes(ctx)) { - this.selectedContexts.remove(ctx) + this.selectedContexts.remove(ctx); } else { this.selectedContexts.push(ctx); } @@ -315,7 +315,7 @@ export class AddCluster extends React.Component { )} > - ) + ); } onKubeConfigInputBlur = (evt: React.FocusEvent) => { @@ -328,13 +328,13 @@ export class AddCluster extends React.Component { this.setKubeConfig(userStore.kubeConfigPath); // revert to previous valid path } } - } + }; onKubeConfigTabChange = (tabId: KubeConfigSourceTab) => { this.sourceTab = tabId; this.error = ""; this.refreshContexts(); - } + }; protected formatContextLabel = ({ value: context }: SelectOption) => { const isNew = userStore.newContexts.has(context); @@ -345,11 +345,11 @@ export class AddCluster extends React.Component { {isNew && } {isSelected && } - ) + ); }; render() { - const addDisabled = this.selectedContexts.length === 0 + const addDisabled = this.selectedContexts.length === 0; return ( this.dropAreaActive = false, onDragOver: event => { event.preventDefault(); // enable onDrop()-callback - event.dataTransfer.dropEffect = "move" + event.dataTransfer.dropEffect = "move"; }, onDrop: event => { this.sourceTab = KubeConfigSourceTab.FILE; - this.dropAreaActive = false - this.setKubeConfig(event.dataTransfer.files[0].path) + this.dropAreaActive = false; + this.setKubeConfig(event.dataTransfer.files[0].path); } }} > @@ -407,6 +407,6 @@ export class AddCluster extends React.Component { /> - ) + ); } } diff --git a/src/renderer/components/+add-cluster/index.ts b/src/renderer/components/+add-cluster/index.ts index 42ab8bf944..1ddb3d069d 100644 --- a/src/renderer/components/+add-cluster/index.ts +++ b/src/renderer/components/+add-cluster/index.ts @@ -1,2 +1,2 @@ -export * from "./add-cluster" -export * from "./add-cluster.route" +export * from "./add-cluster"; +export * from "./add-cluster.route"; diff --git a/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx b/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx index a5531affa3..a446c4dd52 100644 --- a/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx +++ b/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx @@ -35,16 +35,16 @@ export class HelmChartDetails extends Component { } chartUpdater = autorun(() => { - this.selectedChart = null - const { chart: { name, repo, version } } = this.props + this.selectedChart = null; + const { chart: { name, repo, version } } = this.props; helmChartsApi.get(repo, name, version).then(result => { - this.readme = result.readme - this.chartVersions = result.versions - this.selectedChart = result.versions[0] + this.readme = result.readme; + this.chartVersions = result.versions; + this.selectedChart = result.versions[0]; }, error => { this.error = error; - }) + }); }); @autobind() @@ -55,7 +55,7 @@ export class HelmChartDetails extends Component { try { this.chartPromise?.cancel(); const { chart: { name, repo } } = this.props; - const { readme } = await (this.chartPromise = helmChartsApi.get(repo, name, version)) + const { readme } = await (this.chartPromise = helmChartsApi.get(repo, name, version)); this.readme = readme; } catch (error) { this.error = error; @@ -65,7 +65,7 @@ export class HelmChartDetails extends Component { @autobind() install() { createInstallChartTab(this.selectedChart); - this.props.hideDetails() + this.props.hideDetails(); } renderIntroduction() { @@ -112,14 +112,14 @@ export class HelmChartDetails extends Component { renderReadme() { if (this.readme === null) { - return + return ; } return ( - ) + ); } renderContent() { @@ -132,7 +132,7 @@ export class HelmChartDetails extends Component { {this.error} - ) + ); } return ( diff --git a/src/renderer/components/+apps-helm-charts/helm-chart.store.ts b/src/renderer/components/+apps-helm-charts/helm-chart.store.ts index 1d231c08dd..65e73b556f 100644 --- a/src/renderer/components/+apps-helm-charts/helm-chart.store.ts +++ b/src/renderer/components/+apps-helm-charts/helm-chart.store.ts @@ -1,9 +1,9 @@ -import semver from "semver" +import semver from "semver"; import { observable } from "mobx"; import { autobind } from "../../utils"; import { HelmChart, helmChartsApi } from "../../api/endpoints/helm-charts.api"; import { ItemStore } from "../../item.store"; -import flatten from "lodash/flatten" +import flatten from "lodash/flatten"; export interface IChartVersion { repo: string; @@ -24,7 +24,7 @@ export class HelmChartStore extends ItemStore { protected sortVersions = (versions: IChartVersion[]) => { return versions.sort((first, second) => { - return semver.compare(second.version, first.version) + return semver.compare(second.version, first.version); }); }; @@ -38,8 +38,8 @@ export class HelmChartStore extends ItemStore { return versions.map(chart => ({ repo: repo, version: chart.getVersion() - })) - }) + })); + }); }; if (!this.isLoaded) { await this.loadAll(); diff --git a/src/renderer/components/+apps-helm-charts/helm-charts.route.ts b/src/renderer/components/+apps-helm-charts/helm-charts.route.ts index 047ff656b6..abd0677de8 100644 --- a/src/renderer/components/+apps-helm-charts/helm-charts.route.ts +++ b/src/renderer/components/+apps-helm-charts/helm-charts.route.ts @@ -4,11 +4,11 @@ import { appsRoute } from "../+apps/apps.route"; export const helmChartsRoute: RouteProps = { path: appsRoute.path + "/charts/:repo?/:chartName?" -} +}; export interface IHelmChartsRouteParams { chartName?: string; repo?: string; } -export const helmChartsURL = buildURL(helmChartsRoute.path) \ No newline at end of file +export const helmChartsURL = buildURL(helmChartsRoute.path); \ No newline at end of file diff --git a/src/renderer/components/+apps-helm-charts/helm-charts.tsx b/src/renderer/components/+apps-helm-charts/helm-charts.tsx index 473d78194e..c8b5312800 100644 --- a/src/renderer/components/+apps-helm-charts/helm-charts.tsx +++ b/src/renderer/components/+apps-helm-charts/helm-charts.tsx @@ -28,13 +28,13 @@ export class HelmCharts extends Component { } get selectedChart() { - const { match: { params: { chartName, repo } } } = this.props + const { match: { params: { chartName, repo } } } = this.props; return helmChartStore.getByName(chartName, repo); } showDetails = (chart: HelmChart) => { if (!chart) { - navigation.merge(helmChartsURL()) + navigation.merge(helmChartsURL()); } else { navigation.merge(helmChartsURL({ @@ -42,13 +42,13 @@ export class HelmCharts extends Component { chartName: chart.getName(), repo: chart.getRepository(), } - })) + })); } - } + }; hideDetails = () => { this.showDetails(null); - } + }; render() { return ( diff --git a/src/renderer/components/+apps-releases/release-details.tsx b/src/renderer/components/+apps-releases/release-details.tsx index cb7c7b8069..a27db5dc83 100644 --- a/src/renderer/components/+apps-releases/release-details.tsx +++ b/src/renderer/components/+apps-releases/release-details.tsx @@ -77,7 +77,7 @@ export class ReleaseDetails extends Component { updateValues = async () => { const { release } = this.props; const name = release.getName(); - const namespace = release.getNs() + const namespace = release.getNs(); const data = { chart: release.getChart(), repo: await release.getRepo(), @@ -94,13 +94,13 @@ export class ReleaseDetails extends Component { Notifications.error(err); } this.saving = false; - } + }; upgradeVersion = () => { const { release, hideDetails } = this.props; createUpgradeChartTab(release); hideDetails(); - } + }; renderValues() { const { values, saving } = this; @@ -121,7 +121,7 @@ export class ReleaseDetails extends Component { /> - ) + ); } renderNotes() { @@ -222,13 +222,13 @@ export class ReleaseDetails extends Component { {this.renderResources()} - ) + ); } render() { - const { release, hideDetails } = this.props - const title = release ? Release: {release.getName()} : "" - const toolbar = + const { release, hideDetails } = this.props; + const title = release ? Release: {release.getName()} : ""; + const toolbar = ; return ( { > {this.renderContent()} - ) + ); } } diff --git a/src/renderer/components/+apps-releases/release-menu.tsx b/src/renderer/components/+apps-releases/release-menu.tsx index 0bdb94edd2..aae3f34b79 100644 --- a/src/renderer/components/+apps-releases/release-menu.tsx +++ b/src/renderer/components/+apps-releases/release-menu.tsx @@ -46,7 +46,7 @@ export class HelmReleaseMenu extends React.Component { )} > - ) + ); } render() { diff --git a/src/renderer/components/+apps-releases/release-rollback-dialog.tsx b/src/renderer/components/+apps-releases/release-rollback-dialog.tsx index 259394c2e1..f1c1841775 100644 --- a/src/renderer/components/+apps-releases/release-rollback-dialog.tsx +++ b/src/renderer/components/+apps-releases/release-rollback-dialog.tsx @@ -10,7 +10,7 @@ import { HelmRelease, helmReleasesApi, IReleaseRevision } from "../../api/endpoi import { releaseStore } from "./release.store"; import { Select, SelectOption } from "../select"; import { Notifications } from "../notifications"; -import orderBy from "lodash/orderBy" +import orderBy from "lodash/orderBy"; interface Props extends DialogProps { } @@ -46,7 +46,7 @@ export class ReleaseRollbackDialog extends React.Component { this.revisions.replace(releases); this.revision = this.revisions[0]; this.isLoading = false; - } + }; rollback = async () => { const revisionNumber = this.revision.revision; @@ -60,12 +60,12 @@ export class ReleaseRollbackDialog extends React.Component { close = () => { ReleaseRollbackDialog.close(); - } + }; renderContent() { const { revision, revisions } = this; if (!revision) { - return No revisions to rollback. + return No revisions to rollback.; } return ( @@ -78,13 +78,13 @@ export class ReleaseRollbackDialog extends React.Component { onChange={({ value }: SelectOption) => this.revision = value} /> - ) + ); } render() { const { ...dialogProps } = this.props; const releaseName = this.release ? this.release.getName() : ""; - const header = Rollback {releaseName} + const header = Rollback {releaseName}; return ( { - ) + ); } } diff --git a/src/renderer/components/+apps-releases/release.route.ts b/src/renderer/components/+apps-releases/release.route.ts index f874fefe67..a992383657 100644 --- a/src/renderer/components/+apps-releases/release.route.ts +++ b/src/renderer/components/+apps-releases/release.route.ts @@ -4,7 +4,7 @@ import { appsRoute } from "../+apps/apps.route"; export const releaseRoute: RouteProps = { path: appsRoute.path + "/releases/:namespace?/:name?" -} +}; export interface IReleaseRouteParams { name?: string; diff --git a/src/renderer/components/+apps-releases/release.store.ts b/src/renderer/components/+apps-releases/release.store.ts index 5120a63053..7fb438fd84 100644 --- a/src/renderer/components/+apps-releases/release.store.ts +++ b/src/renderer/components/+apps-releases/release.store.ts @@ -33,7 +33,7 @@ export class ReleaseStore extends ItemStore { this.loadAll(); } this.releaseSecrets = [...secrets]; - }) + }); } unwatch() { @@ -48,7 +48,7 @@ export class ReleaseStore extends ItemStore { const labels = { owner: "helm", name: release.getName() - } + }; return secretsStore.getByLabel(labels) .filter(secret => secret.getNs() == release.getNs())[0]; } @@ -58,7 +58,7 @@ export class ReleaseStore extends ItemStore { this.isLoading = true; let items; try { - const { isAdmin, allowedNamespaces } = getHostedCluster() + const { isAdmin, allowedNamespaces } = getHostedCluster(); items = await this.loadItems(!isAdmin ? allowedNamespaces : null); } finally { if (items) { diff --git a/src/renderer/components/+apps-releases/releases.tsx b/src/renderer/components/+apps-releases/releases.tsx index 234a812543..29dd11deb8 100644 --- a/src/renderer/components/+apps-releases/releases.tsx +++ b/src/renderer/components/+apps-releases/releases.tsx @@ -48,7 +48,7 @@ export class HelmReleases extends Component { showDetails = (item: HelmRelease) => { if (!item) { - navigation.merge(releaseURL()) + navigation.merge(releaseURL()); } else { navigation.merge(releaseURL({ @@ -56,13 +56,13 @@ export class HelmReleases extends Component { name: item.getName(), namespace: item.getNs() } - })) + })); } - } + }; hideDetails = () => { this.showDetails(null); - } + }; renderRemoveDialogMessage(selectedItems: HelmRelease[]) { const releaseNames = selectedItems.map(item => item.getName()).join(", "); @@ -73,7 +73,7 @@ export class HelmReleases extends Component { Note: StatefulSet Volumes won't be deleted automatically - ) + ); } render() { @@ -122,7 +122,7 @@ export class HelmReleases extends Component { release.appVersion, { title: release.getStatus(), className: kebabCase(release.getStatus()) }, release.getUpdated(), - ] + ]; }} renderItemMenu={(release: HelmRelease) => { return ( @@ -130,7 +130,7 @@ export class HelmReleases extends Component { release={release} removeConfirmationMessage={this.renderRemoveDialogMessage([release])} /> - ) + ); }} customizeRemoveDialog={(selectedItems: HelmRelease[]) => ({ message: this.renderRemoveDialogMessage(selectedItems) diff --git a/src/renderer/components/+apps/apps.tsx b/src/renderer/components/+apps/apps.tsx index 469765aa68..537d2c3caf 100644 --- a/src/renderer/components/+apps/apps.tsx +++ b/src/renderer/components/+apps/apps.tsx @@ -23,12 +23,12 @@ export class Apps extends React.Component { url: releaseURL({ query }), routePath: releaseRoute.path.toString(), }, - ] + ]; } render() { return ( - ) + ); } } diff --git a/src/renderer/components/+cluster-settings/cluster-settings.route.ts b/src/renderer/components/+cluster-settings/cluster-settings.route.ts index 3d1b1b2737..11a373dcdb 100644 --- a/src/renderer/components/+cluster-settings/cluster-settings.route.ts +++ b/src/renderer/components/+cluster-settings/cluster-settings.route.ts @@ -7,6 +7,6 @@ export interface IClusterSettingsRouteParams extends IClusterViewRouteParams { export const clusterSettingsRoute: RouteProps = { path: `/cluster/:clusterId/settings`, -} +}; -export const clusterSettingsURL = buildURL(clusterSettingsRoute.path) +export const clusterSettingsURL = buildURL(clusterSettingsRoute.path); diff --git a/src/renderer/components/+cluster-settings/cluster-settings.tsx b/src/renderer/components/+cluster-settings/cluster-settings.tsx index 55f4bb5ec4..6188e8867e 100644 --- a/src/renderer/components/+cluster-settings/cluster-settings.tsx +++ b/src/renderer/components/+cluster-settings/cluster-settings.tsx @@ -14,7 +14,7 @@ import { IClusterSettingsRouteParams } from "./cluster-settings.route"; import { clusterStore } from "../../../common/cluster-store"; import { PageLayout } from "../layout/page-layout"; import { requestMain } from "../../../common/ipc"; -import { clusterActivateHandler, clusterRefreshHandler } from "../../../common/cluster-ipc" +import { clusterActivateHandler, clusterRefreshHandler } from "../../../common/cluster-ipc"; interface Props extends RouteComponentProps { } @@ -22,7 +22,7 @@ interface Props extends RouteComponentProps { @observer export class ClusterSettings extends React.Component { get clusterId() { - return this.props.match.params.clusterId + return this.props.match.params.clusterId; } get cluster(): Cluster { @@ -37,18 +37,18 @@ export class ClusterSettings extends React.Component { reaction(() => this.clusterId, clusterId => clusterStore.setActive(clusterId), { fireImmediately: true, }) - ]) + ]); } refreshCluster = async () => { if (this.cluster) { - await requestMain(clusterActivateHandler, this.cluster.id) - await requestMain(clusterRefreshHandler, this.cluster.id) + await requestMain(clusterActivateHandler, this.cluster.id); + await requestMain(clusterRefreshHandler, this.cluster.id); } - } + }; render() { - const cluster = this.cluster + const cluster = this.cluster; if (!cluster) return null; const header = ( <> diff --git a/src/renderer/components/+cluster-settings/components/cluster-home-dir-setting.tsx b/src/renderer/components/+cluster-settings/components/cluster-home-dir-setting.tsx index 965333d4db..35c18cc5e5 100644 --- a/src/renderer/components/+cluster-settings/components/cluster-home-dir-setting.tsx +++ b/src/renderer/components/+cluster-settings/components/cluster-home-dir-setting.tsx @@ -27,7 +27,7 @@ export class ClusterHomeDirSetting extends React.Component { onChange = (value: string) => { this.directory = value; - } + }; render() { return ( diff --git a/src/renderer/components/+cluster-settings/components/cluster-icon-setting.tsx b/src/renderer/components/+cluster-settings/components/cluster-icon-setting.tsx index fb35778f6c..6f893a48fb 100644 --- a/src/renderer/components/+cluster-settings/components/cluster-icon-setting.tsx +++ b/src/renderer/components/+cluster-settings/components/cluster-icon-setting.tsx @@ -35,14 +35,14 @@ export class ClusterIconSetting extends React.Component { cluster.preferences.icon = undefined; } } catch (e) { - this.errorText = e.toString() - this.status = GeneralInputStatus.ERROR + this.errorText = e.toString(); + this.status = GeneralInputStatus.ERROR; } } getClearButton() { if (this.props.cluster.preferences.icon) { - return this.onIconPick([])}>Clear + return this.onIconPick([])}>Clear; } } diff --git a/src/renderer/components/+cluster-settings/components/cluster-name-setting.tsx b/src/renderer/components/+cluster-settings/components/cluster-name-setting.tsx index 54d76c08eb..631c6d54ef 100644 --- a/src/renderer/components/+cluster-settings/components/cluster-name-setting.tsx +++ b/src/renderer/components/+cluster-settings/components/cluster-name-setting.tsx @@ -28,7 +28,7 @@ export class ClusterNameSetting extends React.Component { onChange = (value: string) => { this.name = value; - } + }; render() { return ( diff --git a/src/renderer/components/+cluster-settings/components/cluster-prometheus-setting.tsx b/src/renderer/components/+cluster-settings/components/cluster-prometheus-setting.tsx index ff1f6fd62d..d3bc9b4e46 100644 --- a/src/renderer/components/+cluster-settings/components/cluster-prometheus-setting.tsx +++ b/src/renderer/components/+cluster-settings/components/cluster-prometheus-setting.tsx @@ -59,14 +59,14 @@ export class ClusterPrometheusSetting extends React.Component { service: parsed[1], port: parseInt(parsed[2]), prefix: apiPrefix - } - } + }; + }; onSaveProvider = () => { this.props.cluster.preferences.prometheusProvider = this.provider ? { type: this.provider } : null; - } + }; onSavePath = () => { this.props.cluster.preferences.prometheus = this.parsePrometheusPath(); diff --git a/src/renderer/components/+cluster-settings/components/cluster-proxy-setting.tsx b/src/renderer/components/+cluster-settings/components/cluster-proxy-setting.tsx index 8409cc5bde..d43f571495 100644 --- a/src/renderer/components/+cluster-settings/components/cluster-proxy-setting.tsx +++ b/src/renderer/components/+cluster-settings/components/cluster-proxy-setting.tsx @@ -28,7 +28,7 @@ export class ClusterProxySetting extends React.Component { onChange = (value: string) => { this.proxy = value; - } + }; render() { return ( diff --git a/src/renderer/components/+cluster-settings/components/install-feature.tsx b/src/renderer/components/+cluster-settings/components/install-feature.tsx index adfc8f2b5f..729dd2b1cd 100644 --- a/src/renderer/components/+cluster-settings/components/install-feature.tsx +++ b/src/renderer/components/+cluster-settings/components/install-feature.tsx @@ -19,21 +19,21 @@ export class InstallFeature extends React.Component { @observable message = ""; componentDidMount() { - const feature = this.props.feature - const cluster = this.props.cluster + const feature = this.props.feature; + const cluster = this.props.cluster; const statusUpdate = interval(20, () => { - feature.updateStatus(cluster) - }) - statusUpdate.start(true) + feature.updateStatus(cluster); + }); + statusUpdate.start(true); disposeOnUnmount(this, () => { - statusUpdate.stop() - }) + statusUpdate.stop(); + }); disposeOnUnmount(this, reaction(() => feature.status.installed, () => { this.loading = false; - this.message = "" + this.message = ""; }, { equals: comparer.structural }) ); } @@ -60,8 +60,8 @@ export class InstallFeature extends React.Component { accent disabled={disabled} onClick={this.runAction(async () => { - this.message = "Uninstalling feature ..." - feature.uninstall(cluster) + this.message = "Uninstalling feature ..."; + feature.uninstall(cluster); })} > Uninstall @@ -72,8 +72,8 @@ export class InstallFeature extends React.Component { primary disabled={disabled} onClick={this.runAction(async () =>{ - this.message = "Installing feature ..." - feature.install(cluster) + this.message = "Installing feature ..."; + feature.install(cluster); })} > Install diff --git a/src/renderer/components/+cluster-settings/components/remove-cluster-button.tsx b/src/renderer/components/+cluster-settings/components/remove-cluster-button.tsx index f407ee383a..5ae8d068f2 100644 --- a/src/renderer/components/+cluster-settings/components/remove-cluster-button.tsx +++ b/src/renderer/components/+cluster-settings/components/remove-cluster-button.tsx @@ -23,7 +23,7 @@ export class RemoveClusterButton extends React.Component { ok: async () => { await clusterStore.removeById(cluster.id); } - }) + }); } render() { diff --git a/src/renderer/components/+cluster-settings/features.tsx b/src/renderer/components/+cluster-settings/features.tsx index 74e6a28f13..271a6e69b1 100644 --- a/src/renderer/components/+cluster-settings/features.tsx +++ b/src/renderer/components/+cluster-settings/features.tsx @@ -22,7 +22,7 @@ export class Features extends React.Component { > - ) + ); })} ); diff --git a/src/renderer/components/+cluster-settings/index.ts b/src/renderer/components/+cluster-settings/index.ts index 75dd6e60ea..edab795e29 100644 --- a/src/renderer/components/+cluster-settings/index.ts +++ b/src/renderer/components/+cluster-settings/index.ts @@ -1,2 +1,2 @@ -export * from "./cluster-settings.route" -export * from "./cluster-settings" +export * from "./cluster-settings.route"; +export * from "./cluster-settings"; diff --git a/src/renderer/components/+cluster-settings/status.tsx b/src/renderer/components/+cluster-settings/status.tsx index 79fb62c860..319b42e104 100644 --- a/src/renderer/components/+cluster-settings/status.tsx +++ b/src/renderer/components/+cluster-settings/status.tsx @@ -14,7 +14,7 @@ export class Status extends React.Component { @autobind() openKubeconfig() { const { cluster } = this.props; - shell.showItemInFolder(cluster.kubeConfigPath) + shell.showItemInFolder(cluster.kubeConfigPath); } renderStatusRows() { diff --git a/src/renderer/components/+cluster/cluster-issues.tsx b/src/renderer/components/+cluster/cluster-issues.tsx index eea222b5c4..a2959cda20 100644 --- a/src/renderer/components/+cluster/cluster-issues.tsx +++ b/src/renderer/components/+cluster/cluster-issues.tsx @@ -1,4 +1,4 @@ -import "./cluster-issues.scss" +import "./cluster-issues.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -43,7 +43,7 @@ export class ClusterIssues extends React.Component { // Node bad conditions nodesStore.items.forEach(node => { - const { kind, selfLink, getId, getName } = node + const { kind, selfLink, getId, getName } = node; node.getWarningConditions().forEach(({ message }) => { warnings.push({ kind, @@ -51,8 +51,8 @@ export class ClusterIssues extends React.Component { getName, selfLink, message, - }) - }) + }); + }); }); // Warning events for Workloads @@ -67,7 +67,7 @@ export class ClusterIssues extends React.Component { kind, selfLink: lookupApiLink(involvedObject, error), }); - }) + }); return warnings; } diff --git a/src/renderer/components/+cluster/cluster-metrics.tsx b/src/renderer/components/+cluster/cluster-metrics.tsx index 077adde70a..12973b1514 100644 --- a/src/renderer/components/+cluster/cluster-metrics.tsx +++ b/src/renderer/components/+cluster/cluster-metrics.tsx @@ -72,7 +72,7 @@ export const ClusterMetrics = observer(() => { return ; } if (!memoryCapacity || !cpuCapacity) { - return + return ; } return ( { Specified limits are higher than node capacity! ); - } + }; const renderCharts = () => { const data = getMetricLastPoints(clusterStore.metrics); @@ -168,7 +168,7 @@ export const ClusterPieCharts = observer(() => { ); - } + }; const renderContent = () => { const { masterNodes, workerNodes } = nodesStore; @@ -194,11 +194,11 @@ export const ClusterPieCharts = observer(() => { return ; } return renderCharts(); - } + }; return ( {renderContent()} ); -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/src/renderer/components/+cluster/cluster.route.ts b/src/renderer/components/+cluster/cluster.route.ts index fbe1c47b86..f9cf7a390c 100644 --- a/src/renderer/components/+cluster/cluster.route.ts +++ b/src/renderer/components/+cluster/cluster.route.ts @@ -3,6 +3,6 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const clusterRoute: RouteProps = { path: "/cluster" -} +}; -export const clusterURL = buildURL(clusterRoute.path) +export const clusterURL = buildURL(clusterRoute.path); diff --git a/src/renderer/components/+cluster/cluster.store.ts b/src/renderer/components/+cluster/cluster.store.ts index 3af42297b0..63d8f07b3b 100644 --- a/src/renderer/components/+cluster/cluster.store.ts +++ b/src/renderer/components/+cluster/cluster.store.ts @@ -18,7 +18,7 @@ export enum MetricNodeRole { @autobind() export class ClusterStore extends KubeObjectStore { - api = clusterApi + api = clusterApi; @observable metrics: Partial = {}; @observable liveMetrics: Partial = {}; @@ -35,7 +35,7 @@ export class ClusterStore extends KubeObjectStore { Object.assign(this, storage.get()); reaction(() => { const { metricType, metricNodeRole } = this; - return { metricType, metricNodeRole } + return { metricType, metricNodeRole }; }, settings => storage.set(settings) ); @@ -85,9 +85,9 @@ export class ClusterStore extends KubeObjectStore { getMetricsValues(source: Partial): [number, string][] { switch (this.metricType) { case MetricType.CPU: - return normalizeMetrics(source.cpuUsage).data.result[0].values + return normalizeMetrics(source.cpuUsage).data.result[0].values; case MetricType.MEMORY: - return normalizeMetrics(source.memoryUsage).data.result[0].values + return normalizeMetrics(source.memoryUsage).data.result[0].values; default: return []; } diff --git a/src/renderer/components/+cluster/cluster.tsx b/src/renderer/components/+cluster/cluster.tsx index 9a1ce47123..588c483295 100644 --- a/src/renderer/components/+cluster/cluster.tsx +++ b/src/renderer/components/+cluster/cluster.tsx @@ -1,4 +1,4 @@ -import "./cluster.scss" +import "./cluster.scss"; import React from "react"; import { computed, reaction } from "mobx"; @@ -21,19 +21,19 @@ export class Cluster extends React.Component { private dependentStores = [nodesStore, podsStore]; private watchers = [ - interval(60, () => { getHostedCluster().available && clusterStore.getMetrics()}), - interval(20, () => { getHostedCluster().available && eventStore.loadAll()}) + interval(60, () => { getHostedCluster().available && clusterStore.getMetrics();}), + interval(20, () => { getHostedCluster().available && eventStore.loadAll();}) ]; @computed get isLoaded() { - return nodesStore.isLoaded && podsStore.isLoaded + return nodesStore.isLoaded && podsStore.isLoaded; } // todo: refactor async componentDidMount() { const { dependentStores } = this; if (!isAllowedResource("nodes")) { - dependentStores.splice(dependentStores.indexOf(nodesStore), 1) + dependentStores.splice(dependentStores.indexOf(nodesStore), 1); } this.watchers.forEach(watcher => watcher.start(true)); @@ -49,7 +49,7 @@ export class Cluster extends React.Component { () => clusterStore.metricNodeRole, () => this.watchers.forEach(watcher => watcher.restart()) ) - ]) + ]); } render() { @@ -67,6 +67,6 @@ export class Cluster extends React.Component { )} - ) + ); } } diff --git a/src/renderer/components/+cluster/index.ts b/src/renderer/components/+cluster/index.ts index 62a1be24fb..d9be64692d 100644 --- a/src/renderer/components/+cluster/index.ts +++ b/src/renderer/components/+cluster/index.ts @@ -1,2 +1,2 @@ -export * from "./cluster.route" +export * from "./cluster.route"; diff --git a/src/renderer/components/+config-autoscalers/hpa-details.tsx b/src/renderer/components/+config-autoscalers/hpa-details.tsx index a3461f629d..b068c28361 100644 --- a/src/renderer/components/+config-autoscalers/hpa-details.tsx +++ b/src/renderer/components/+config-autoscalers/hpa-details.tsx @@ -51,7 +51,7 @@ export class HpaDetails extends React.Component { ); } - } + }; return ( @@ -68,7 +68,7 @@ export class HpaDetails extends React.Component { {name} {values} - ) + ); }) } @@ -113,7 +113,7 @@ export class HpaDetails extends React.Component { tooltip={tooltip} className={cssNames({ [type.toLowerCase()]: isReady })} /> - ) + ); })} @@ -132,7 +132,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "HorizontalPodAutoscaler", @@ -141,4 +141,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+config-autoscalers/hpa.route.ts b/src/renderer/components/+config-autoscalers/hpa.route.ts index 0828db146b..404bab8f88 100644 --- a/src/renderer/components/+config-autoscalers/hpa.route.ts +++ b/src/renderer/components/+config-autoscalers/hpa.route.ts @@ -3,9 +3,9 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const hpaRoute: RouteProps = { path: "/hpa" -} +}; export interface IHpaRouteParams { } -export const hpaURL = buildURL(hpaRoute.path) +export const hpaURL = buildURL(hpaRoute.path); diff --git a/src/renderer/components/+config-autoscalers/hpa.store.ts b/src/renderer/components/+config-autoscalers/hpa.store.ts index 240f42a309..478c2ca563 100644 --- a/src/renderer/components/+config-autoscalers/hpa.store.ts +++ b/src/renderer/components/+config-autoscalers/hpa.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class HPAStore extends KubeObjectStore { - api = hpaApi + api = hpaApi; } export const hpaStore = new HPAStore(); diff --git a/src/renderer/components/+config-autoscalers/hpa.tsx b/src/renderer/components/+config-autoscalers/hpa.tsx index 01e18da2f5..f955ce098d 100644 --- a/src/renderer/components/+config-autoscalers/hpa.tsx +++ b/src/renderer/components/+config-autoscalers/hpa.tsx @@ -1,4 +1,4 @@ -import "./hpa.scss" +import "./hpa.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -78,7 +78,7 @@ export class HorizontalPodAutoscalers extends React.Component { tooltip={tooltip} className={cssNames(type.toLowerCase())} /> - ) + ); }) ]} /> diff --git a/src/renderer/components/+config-autoscalers/index.ts b/src/renderer/components/+config-autoscalers/index.ts index 4d3cedf89c..99d994add1 100644 --- a/src/renderer/components/+config-autoscalers/index.ts +++ b/src/renderer/components/+config-autoscalers/index.ts @@ -1,3 +1,3 @@ -export * from "./hpa" -export * from "./hpa-details" -export * from "./hpa.route" +export * from "./hpa"; +export * from "./hpa-details"; +export * from "./hpa.route"; diff --git a/src/renderer/components/+config-maps/config-map-details.tsx b/src/renderer/components/+config-maps/config-map-details.tsx index 0a890f6d04..bd796a2323 100644 --- a/src/renderer/components/+config-maps/config-map-details.tsx +++ b/src/renderer/components/+config-maps/config-map-details.tsx @@ -31,7 +31,7 @@ export class ConfigMapDetails extends React.Component { this.data.replace(configMap.data); // refresh } }) - ]) + ]); } save = async () => { @@ -47,7 +47,7 @@ export class ConfigMapDetails extends React.Component { } finally { this.isSaving = false; } - } + }; render() { const { object: configMap } = this.props; @@ -75,7 +75,7 @@ export class ConfigMapDetails extends React.Component { /> - ) + ); }) } } -}) +}); kubeObjectDetailRegistry.add({ kind: "ConfigMap", @@ -107,6 +107,6 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+config-maps/config-maps.route.ts b/src/renderer/components/+config-maps/config-maps.route.ts index 3f42cf7e76..1cffe95c34 100644 --- a/src/renderer/components/+config-maps/config-maps.route.ts +++ b/src/renderer/components/+config-maps/config-maps.route.ts @@ -3,7 +3,7 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const configMapsRoute: RouteProps = { path: "/configmaps" -} +}; export interface IConfigMapsRouteParams { } diff --git a/src/renderer/components/+config-maps/config-maps.store.ts b/src/renderer/components/+config-maps/config-maps.store.ts index d6dcc5f916..23a80a9f4a 100644 --- a/src/renderer/components/+config-maps/config-maps.store.ts +++ b/src/renderer/components/+config-maps/config-maps.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class ConfigMapsStore extends KubeObjectStore { - api = configMapApi + api = configMapApi; } export const configMapsStore = new ConfigMapsStore(); diff --git a/src/renderer/components/+config-maps/config-maps.tsx b/src/renderer/components/+config-maps/config-maps.tsx index 22cc4c354d..67b4fe8e0e 100644 --- a/src/renderer/components/+config-maps/config-maps.tsx +++ b/src/renderer/components/+config-maps/config-maps.tsx @@ -1,4 +1,4 @@ -import "./config-maps.scss" +import "./config-maps.scss"; import React from "react"; import { observer } from "mobx-react"; diff --git a/src/renderer/components/+config-maps/index.ts b/src/renderer/components/+config-maps/index.ts index 37b78f5097..4b22cfd4cb 100644 --- a/src/renderer/components/+config-maps/index.ts +++ b/src/renderer/components/+config-maps/index.ts @@ -1,3 +1,3 @@ -export * from "./config-maps.route" -export * from "./config-maps" -export * from "./config-map-details" +export * from "./config-maps.route"; +export * from "./config-maps"; +export * from "./config-map-details"; diff --git a/src/renderer/components/+config-pod-disruption-budgets/index.ts b/src/renderer/components/+config-pod-disruption-budgets/index.ts index e729464c0a..7528301703 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/index.ts +++ b/src/renderer/components/+config-pod-disruption-budgets/index.ts @@ -1,3 +1,3 @@ -export * from "./pod-disruption-budgets.route" -export * from "./pod-disruption-budgets" -export * from "./pod-disruption-budgets-details" +export * from "./pod-disruption-budgets.route"; +export * from "./pod-disruption-budgets"; +export * from "./pod-disruption-budgets-details"; diff --git a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx index 745d588be3..25925f6436 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx +++ b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets-details.tsx @@ -18,8 +18,8 @@ export class PodDisruptionBudgetDetails extends React.Component { render() { const { object: pdb } = this.props; - if (!pdb) return null - const { status, spec } = pdb + if (!pdb) return null; + const { status, spec } = pdb; const selectors = pdb.getSelectors(); return ( @@ -50,7 +50,7 @@ export class PodDisruptionBudgetDetails extends React.Component { - ) + ); } } @@ -60,4 +60,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.route.ts b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.route.ts index b35f30bb8b..ea443a841b 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.route.ts +++ b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.route.ts @@ -3,9 +3,9 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const pdbRoute: RouteProps = { path: "/poddisruptionbudgets" -} +}; export interface IPodDisruptionBudgetsRouteParams { } -export const pdbURL = buildURL(pdbRoute.path) +export const pdbURL = buildURL(pdbRoute.path); diff --git a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store.ts b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store.ts index 1eca71e1ba..0f0d79ab2d 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store.ts +++ b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class PodDisruptionBudgetsStore extends KubeObjectStore { - api = pdbApi + api = pdbApi; } export const podDisruptionBudgetsStore = new PodDisruptionBudgetsStore(); diff --git a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx index 275dcf0c7a..4a7bb04ddd 100644 --- a/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx +++ b/src/renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.tsx @@ -1,4 +1,4 @@ -import "./pod-disruption-budgets.scss" +import "./pod-disruption-budgets.scss"; import * as React from "react"; import { observer } from "mobx-react"; @@ -65,7 +65,7 @@ export class PodDisruptionBudgets extends React.Component { pdb.getCurrentHealthy(), pdb.getDesiredHealthy(), pdb.getAge(), - ] + ]; }} /> ); diff --git a/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx b/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx index 5dfa104537..3759958750 100644 --- a/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx +++ b/src/renderer/components/+config-resource-quotas/add-quota-dialog.tsx @@ -45,7 +45,7 @@ export class AddQuotaDialog extends React.Component { "count/deployments.extensions": "", }; - public defaultNamespace = "default" + public defaultNamespace = "default"; @observable quotaName = ""; @observable quotaSelectValue = ""; @@ -83,11 +83,11 @@ export class AddQuotaDialog extends React.Component { if (!this.quotaSelectValue) return; this.quotas[this.quotaSelectValue] = this.quotaInputValue; this.quotaInputValue = ""; - } + }; close = () => { AddQuotaDialog.close(); - } + }; reset = () => { this.quotaName = ""; @@ -95,7 +95,7 @@ export class AddQuotaDialog extends React.Component { this.quotaInputValue = ""; this.namespace = this.defaultNamespace; this.quotas = AddQuotaDialog.defaultQuotas; - } + }; addQuota = async () => { try { @@ -113,7 +113,7 @@ export class AddQuotaDialog extends React.Component { } catch (err) { Notifications.error(err); } - } + }; onInputQuota = (evt: React.KeyboardEvent) => { switch (evt.key) { @@ -122,7 +122,7 @@ export class AddQuotaDialog extends React.Component { evt.preventDefault(); // don't submit form break; } - } + }; render() { const { ...dialogProps } = this.props; @@ -193,12 +193,12 @@ export class AddQuotaDialog extends React.Component { {value} this.quotas[quota] = ""} /> - ) + ); })} - ) + ); } } \ No newline at end of file diff --git a/src/renderer/components/+config-resource-quotas/index.ts b/src/renderer/components/+config-resource-quotas/index.ts index 792f8946c3..79fa3d8f0c 100644 --- a/src/renderer/components/+config-resource-quotas/index.ts +++ b/src/renderer/components/+config-resource-quotas/index.ts @@ -1,3 +1,3 @@ -export * from "./resource-quotas.route" -export * from "./resource-quotas" -export * from "./resource-quota-details" +export * from "./resource-quotas.route"; +export * from "./resource-quotas"; +export * from "./resource-quota-details"; diff --git a/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx b/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx index 4a2ff08238..c8fc913531 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx +++ b/src/renderer/components/+config-resource-quotas/resource-quota-details.tsx @@ -20,24 +20,24 @@ const onlyNumbers = /$[0-9]*^/g; function transformUnit(name: string, value: string): number { if (name.includes("memory") || name.includes("storage")) { - return unitsToBytes(value) + return unitsToBytes(value); } if (name.includes("cpu")) { - return cpuUnitsToNumber(value) + return cpuUnitsToNumber(value); } return metricUnitsToNumber(value); } function renderQuotas(quota: ResourceQuota): JSX.Element[] { - const { hard = {}, used = {} } = quota.status + const { hard = {}, used = {} } = quota.status; return Object.entries(hard) .filter(([name]) => used[name]) .map(([name, value]) => { - const current = transformUnit(name, used[name]) - const max = transformUnit(name, value) + const current = transformUnit(name, used[name]); + const max = transformUnit(name, value); const usage = max === 0 ? 100 : Math.ceil(current / max * 100); // special case 0 max as always 100% usage return ( @@ -52,8 +52,8 @@ function renderQuotas(quota: ResourceQuota): JSX.Element[] { } /> - ) - }) + ); + }); } @observer @@ -104,4 +104,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+config-resource-quotas/resource-quotas.route.ts b/src/renderer/components/+config-resource-quotas/resource-quotas.route.ts index ee6966da97..f36468f656 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quotas.route.ts +++ b/src/renderer/components/+config-resource-quotas/resource-quotas.route.ts @@ -3,7 +3,7 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const resourceQuotaRoute: RouteProps = { path: "/resourcequotas" -} +}; export interface IResourceQuotaRouteParams { } diff --git a/src/renderer/components/+config-resource-quotas/resource-quotas.store.ts b/src/renderer/components/+config-resource-quotas/resource-quotas.store.ts index b5450da9cd..554fec891a 100644 --- a/src/renderer/components/+config-resource-quotas/resource-quotas.store.ts +++ b/src/renderer/components/+config-resource-quotas/resource-quotas.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class ResourceQuotasStore extends KubeObjectStore { - api = resourceQuotaApi + api = resourceQuotaApi; } export const resourceQuotaStore = new ResourceQuotasStore(); diff --git a/src/renderer/components/+config-secrets/add-secret-dialog.tsx b/src/renderer/components/+config-secrets/add-secret-dialog.tsx index dbc7a8cc7c..8519be5bda 100644 --- a/src/renderer/components/+config-secrets/add-secret-dialog.tsx +++ b/src/renderer/components/+config-secrets/add-secret-dialog.tsx @@ -1,4 +1,4 @@ -import "./add-secret-dialog.scss" +import "./add-secret-dialog.scss"; import React from "react"; import { observable } from "mobx"; @@ -58,7 +58,7 @@ export class AddSecretDialog extends React.Component { { key: "kubernetes.io/service-account.uid", required: true } ], }, - } + }; get types() { return Object.keys(this.secretTemplate) as SecretType[]; @@ -72,11 +72,11 @@ export class AddSecretDialog extends React.Component { reset = () => { this.name = ""; this.secret = this.secretTemplate; - } + }; close = () => { AddSecretDialog.close(); - } + }; private getDataFromFields = (fields: ISecretTemplateField[] = [], processValue?: (val: string) => string) => { return fields.reduce((data, field) => { @@ -85,8 +85,8 @@ export class AddSecretDialog extends React.Component { data[key] = processValue ? processValue(value) : value; } return data; - }, {}) - } + }, {}); + }; createSecret = async () => { const { name, namespace, type } = this; @@ -100,7 +100,7 @@ export class AddSecretDialog extends React.Component { annotations: this.getDataFromFields(annotations), labels: this.getDataFromFields(labels), } as IKubeObjectMetadata - } + }; try { const newSecret = await secretsApi.create({ namespace, name }, secret); showDetails(newSecret.selfLink); @@ -109,18 +109,18 @@ export class AddSecretDialog extends React.Component { } catch (err) { Notifications.error(err); } - } + }; addField = (field: ISecretField) => { const fields = this.secret[this.type][field] || []; fields.push({ key: "", value: "" }); this.secret[this.type][field] = fields; - } + }; removeField = (field: ISecretField, index: number) => { const fields = this.secret[this.type][field] || []; fields.splice(index, 1); - } + }; renderFields(field: ISecretField) { const fields = this.secret[this.type][field] || []; @@ -163,11 +163,11 @@ export class AddSecretDialog extends React.Component { onClick={() => this.removeField(field, index)} /> - ) + ); })} > - ) + ); } render() { @@ -216,6 +216,6 @@ export class AddSecretDialog extends React.Component { - ) + ); } } diff --git a/src/renderer/components/+config-secrets/index.ts b/src/renderer/components/+config-secrets/index.ts index cfea583cb3..33ef15e692 100644 --- a/src/renderer/components/+config-secrets/index.ts +++ b/src/renderer/components/+config-secrets/index.ts @@ -1,4 +1,4 @@ -export * from "./secrets.route" -export * from "./secrets" -export * from "./secret-details" +export * from "./secrets.route"; +export * from "./secrets"; +export * from "./secret-details"; diff --git a/src/renderer/components/+config-secrets/secret-details.tsx b/src/renderer/components/+config-secrets/secret-details.tsx index 5e10eee94c..5937737a5a 100644 --- a/src/renderer/components/+config-secrets/secret-details.tsx +++ b/src/renderer/components/+config-secrets/secret-details.tsx @@ -36,7 +36,7 @@ export class SecretDetails extends React.Component { this.revealSecret = {}; } }) - ]) + ]); } saveSecret = async () => { @@ -49,11 +49,11 @@ export class SecretDetails extends React.Component { Notifications.error(err); } this.isSaving = false; - } + }; editData = (name: string, value: string, encoded: boolean) => { this.data[name] = encoded ? value : base64.encode(value); - } + }; render() { const { object: secret } = this.props; @@ -97,7 +97,7 @@ export class SecretDetails extends React.Component { } - ) + ); }) } } -}) +}); diff --git a/src/renderer/components/+config-secrets/secrets.route.ts b/src/renderer/components/+config-secrets/secrets.route.ts index bd5f9a442d..a7eb422be5 100644 --- a/src/renderer/components/+config-secrets/secrets.route.ts +++ b/src/renderer/components/+config-secrets/secrets.route.ts @@ -3,7 +3,7 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const secretsRoute: RouteProps = { path: "/secrets" -} +}; export interface ISecretsRouteParams { } diff --git a/src/renderer/components/+config-secrets/secrets.store.ts b/src/renderer/components/+config-secrets/secrets.store.ts index df5a78b3ac..9dfc8cb6af 100644 --- a/src/renderer/components/+config-secrets/secrets.store.ts +++ b/src/renderer/components/+config-secrets/secrets.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class SecretsStore extends KubeObjectStore { - api = secretsApi + api = secretsApi; } export const secretsStore = new SecretsStore(); diff --git a/src/renderer/components/+config-secrets/secrets.tsx b/src/renderer/components/+config-secrets/secrets.tsx index bbcfd0b7cf..5149aa1002 100644 --- a/src/renderer/components/+config-secrets/secrets.tsx +++ b/src/renderer/components/+config-secrets/secrets.tsx @@ -1,4 +1,4 @@ -import "./secrets.scss" +import "./secrets.scss"; import React from "react"; import { observer } from "mobx-react"; diff --git a/src/renderer/components/+config/config.route.ts b/src/renderer/components/+config/config.route.ts index d747f49efd..8ea637c505 100644 --- a/src/renderer/components/+config/config.route.ts +++ b/src/renderer/components/+config/config.route.ts @@ -5,8 +5,8 @@ import { configMapsURL } from "../+config-maps/config-maps.route"; export const configRoute: RouteProps = { get path() { - return Config.tabRoutes.map(({ routePath }) => routePath).flat() + return Config.tabRoutes.map(({ routePath }) => routePath).flat(); } -} +}; export const configURL = (params?: IURLParams) => configMapsURL(params); diff --git a/src/renderer/components/+config/config.tsx b/src/renderer/components/+config/config.tsx index f738cb273e..70fa04d9b1 100644 --- a/src/renderer/components/+config/config.tsx +++ b/src/renderer/components/+config/config.tsx @@ -8,20 +8,20 @@ import { namespaceStore } from "../+namespaces/namespace.store"; import { resourceQuotaRoute, ResourceQuotas, resourceQuotaURL } from "../+config-resource-quotas"; import { pdbRoute, pdbURL, PodDisruptionBudgets } from "../+config-pod-disruption-budgets"; import { HorizontalPodAutoscalers, hpaRoute, hpaURL } from "../+config-autoscalers"; -import { isAllowedResource } from "../../../common/rbac" +import { isAllowedResource } from "../../../common/rbac"; @observer export class Config extends React.Component { static get tabRoutes(): TabLayoutRoute[] { - const query = namespaceStore.getContextParams() - const routes: TabLayoutRoute[] = [] + const query = namespaceStore.getContextParams(); + const routes: TabLayoutRoute[] = []; if (isAllowedResource("configmaps")) { routes.push({ title: ConfigMaps, component: ConfigMaps, url: configMapsURL({ query }), routePath: configMapsRoute.path.toString(), - }) + }); } if (isAllowedResource("secrets")) { routes.push({ @@ -29,7 +29,7 @@ export class Config extends React.Component { component: Secrets, url: secretsURL({ query }), routePath: secretsRoute.path.toString(), - }) + }); } if (isAllowedResource("resourcequotas")) { routes.push({ @@ -37,7 +37,7 @@ export class Config extends React.Component { component: ResourceQuotas, url: resourceQuotaURL({ query }), routePath: resourceQuotaRoute.path.toString(), - }) + }); } if (isAllowedResource("horizontalpodautoscalers")) { routes.push({ @@ -45,7 +45,7 @@ export class Config extends React.Component { component: HorizontalPodAutoscalers, url: hpaURL({ query }), routePath: hpaRoute.path.toString(), - }) + }); } if (isAllowedResource("poddisruptionbudgets")) { routes.push({ @@ -53,7 +53,7 @@ export class Config extends React.Component { component: PodDisruptionBudgets, url: pdbURL({ query }), routePath: pdbRoute.path.toString(), - }) + }); } return routes; } @@ -61,6 +61,6 @@ export class Config extends React.Component { render() { return ( - ) + ); } } diff --git a/src/renderer/components/+config/index.ts b/src/renderer/components/+config/index.ts index f3ab3691ce..dba36b66d6 100644 --- a/src/renderer/components/+config/index.ts +++ b/src/renderer/components/+config/index.ts @@ -1,2 +1,2 @@ -export * from "./config.route" -export * from "./config" +export * from "./config.route"; +export * from "./config"; diff --git a/src/renderer/components/+custom-resources/crd-details.tsx b/src/renderer/components/+custom-resources/crd-details.tsx index b921eb0d04..637a0de1b6 100644 --- a/src/renderer/components/+custom-resources/crd-details.tsx +++ b/src/renderer/components/+custom-resources/crd-details.tsx @@ -60,7 +60,7 @@ export class CRDDetails extends React.Component { Conditions} className="conditions" labelsOnly> { crd.getConditions().map(condition => { - const { type, message, lastTransitionTime, status } = condition + const { type, message, lastTransitionTime, status } = condition; return ( { - ) + ); }) } @@ -130,7 +130,7 @@ export class CRDDetails extends React.Component { > } - ) + ); } } @@ -140,4 +140,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+custom-resources/crd-list.tsx b/src/renderer/components/+custom-resources/crd-list.tsx index caf6129e58..bfad4d501c 100644 --- a/src/renderer/components/+custom-resources/crd-list.tsx +++ b/src/renderer/components/+custom-resources/crd-list.tsx @@ -1,4 +1,4 @@ -import "./crd-list.scss" +import "./crd-list.scss"; import React from "react"; import { Trans } from "@lingui/macro"; @@ -24,7 +24,7 @@ enum sortBy { @observer export class CrdList extends React.Component { @computed get groups() { - return navigation.searchParams.getAsArray("groups") + return navigation.searchParams.getAsArray("groups"); } onGroupChange(group: string) { @@ -32,7 +32,7 @@ export class CrdList extends React.Component { const index = groups.findIndex(item => item == group); if (index !== -1) groups.splice(index, 1); else groups.push(group); - setQueryParams({ groups }) + setQueryParams({ groups }); } render() { @@ -52,14 +52,14 @@ export class CrdList extends React.Component { searchFilters={Object.values(sortingCallbacks)} filterItems={[ (items: CustomResourceDefinition[]) => { - return selectedGroups.length ? items.filter(item => selectedGroups.includes(item.getGroup())) : items + return selectedGroups.length ? items.filter(item => selectedGroups.includes(item.getGroup())) : items; } ]} renderHeaderTitle={Custom Resources} customizeHeader={() => { let placeholder = All groups; - if (selectedGroups.length == 1) placeholder = <>Group: {selectedGroups[0]}> - if (selectedGroups.length >= 2) placeholder = <>Groups: {selectedGroups.join(", ")}> + if (selectedGroups.length == 1) placeholder = <>Group: {selectedGroups[0]}>; + if (selectedGroups.length >= 2) placeholder = <>Groups: {selectedGroups.join(", ")}>; return { // todo: move to global filters filters: ( @@ -77,11 +77,11 @@ export class CrdList extends React.Component { {group} {isSelected && } - ) + ); }} /> ) - } + }; }} renderTableHeader={[ { title: Resource, className: "kind", sortBy: sortBy.kind }, @@ -99,10 +99,10 @@ export class CrdList extends React.Component { crd.getVersion(), crd.getScope(), crd.getAge(), - ] + ]; }} /> - ) + ); } } diff --git a/src/renderer/components/+custom-resources/crd-resource-details.tsx b/src/renderer/components/+custom-resources/crd-resource-details.tsx index 883fba2fd4..d04962c0dc 100644 --- a/src/renderer/components/+custom-resources/crd-resource-details.tsx +++ b/src/renderer/components/+custom-resources/crd-resource-details.tsx @@ -19,7 +19,7 @@ interface Props extends KubeObjectDetailsProps { function convertSpecValue(value: any): any { if (Array.isArray(value)) { - return value.map(convertSpecValue) + return value.map(convertSpecValue); } if (typeof value === "object") { @@ -31,10 +31,10 @@ function convertSpecValue(value: any): any { className="box grow" value={JSON.stringify(value, null, 2)} /> - ) + ); } - return value + return value; } @observer @@ -48,13 +48,13 @@ export class CrdResourceDetails extends React.Component { {convertSpecValue(jsonPath.value(crd, jp.slice(1)))} - )) + )); } renderStatus(crd: CustomResourceDefinition, columns: AdditionalPrinterColumnsV1[]) { const showStatus = !columns.find(column => column.name == "Status") && crd.status?.conditions; if (!showStatus) { - return null + return null; } const conditions = crd.status.conditions @@ -66,13 +66,13 @@ export class CrdResourceDetails extends React.Component { className={cssNames({ disabled: status === "False" }, kind.toLowerCase())} tooltip={message} /> - )) + )); return ( Status} className="status" labelsOnly> {conditions} - ) + ); } render() { @@ -90,6 +90,6 @@ export class CrdResourceDetails extends React.Component { {this.renderAdditionalColumns(object, extraColumns)} {this.renderStatus(object, extraColumns)} - ) + ); } } diff --git a/src/renderer/components/+custom-resources/crd-resources.tsx b/src/renderer/components/+custom-resources/crd-resources.tsx index e36fef532d..6afe40ae3c 100644 --- a/src/renderer/components/+custom-resources/crd-resources.tsx +++ b/src/renderer/components/+custom-resources/crd-resources.tsx @@ -32,7 +32,7 @@ export class CrdResources extends React.Component { store.loadAll(); } }) - ]) + ]); } @computed get crd() { @@ -41,7 +41,7 @@ export class CrdResources extends React.Component { } @computed get store() { - if (!this.crd) return null + if (!this.crd) return null; return apiManager.getStore(this.crd.getResourceApiBase()); } @@ -54,10 +54,10 @@ export class CrdResources extends React.Component { [sortBy.name]: (item: KubeObject) => item.getName(), [sortBy.namespace]: (item: KubeObject) => item.getNs(), [sortBy.age]: (item: KubeObject) => item.metadata.creationTimestamp, - } + }; extraColumns.forEach(column => { - sortingCallbacks[column.name] = (item: KubeObject) => jsonPath.value(item, column.jsonPath.slice(1)) - }) + sortingCallbacks[column.name] = (item: KubeObject) => jsonPath.value(item, column.jsonPath.slice(1)); + }); return ( { title: name, className: name.toLowerCase(), sortBy: name - } + }; }), { title: Age, className: "age", sortBy: sortBy.age }, ]} @@ -92,6 +92,6 @@ export class CrdResources extends React.Component { crdInstance.getAge(), ]} /> - ) + ); } } diff --git a/src/renderer/components/+custom-resources/crd.route.ts b/src/renderer/components/+custom-resources/crd.route.ts index f9affeb903..fc819d6560 100644 --- a/src/renderer/components/+custom-resources/crd.route.ts +++ b/src/renderer/components/+custom-resources/crd.route.ts @@ -3,15 +3,15 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const crdRoute: RouteProps = { path: "/crd" -} +}; export const crdDefinitionsRoute: RouteProps = { path: crdRoute.path + "/definitions" -} +}; export const crdResourcesRoute: RouteProps = { path: crdRoute.path + "/:group/:name" -} +}; export interface ICRDListQuery { groups?: string; diff --git a/src/renderer/components/+custom-resources/crd.store.ts b/src/renderer/components/+custom-resources/crd.store.ts index e73bbd1fb7..54e1d3df66 100644 --- a/src/renderer/components/+custom-resources/crd.store.ts +++ b/src/renderer/components/+custom-resources/crd.store.ts @@ -20,20 +20,20 @@ function initStore(crd: CustomResourceDefinition) { @autobind() export class CRDStore extends KubeObjectStore { - api = crdApi + api = crdApi; constructor() { super(); // auto-init stores for crd-s - reaction(() => this.items.toJS(), items => items.forEach(initStore)) + reaction(() => this.items.toJS(), items => items.forEach(initStore)); } protected sortItems(items: CustomResourceDefinition[]) { return super.sortItems(items, [ crd => crd.getGroup(), crd => crd.getName(), - ]) + ]); } @computed get groups() { @@ -43,7 +43,7 @@ export class CRDStore extends KubeObjectStore { if (!groups[group]) groups[group] = []; groups[group].push(crd); return groups; - }, groups) + }, groups); } getByGroup(group: string, pluralName: string) { @@ -53,12 +53,12 @@ export class CRDStore extends KubeObjectStore { } getByObject(obj: KubeObject) { - if (!obj) return null + if (!obj) return null; const { kind, apiVersion } = obj; return this.items.find(crd => ( kind === crd.getResourceKind() && apiVersion === `${crd.getGroup()}/${crd.getVersion()}` - )) + )); } } diff --git a/src/renderer/components/+custom-resources/custom-resources.tsx b/src/renderer/components/+custom-resources/custom-resources.tsx index ee34809013..95a05e9f33 100644 --- a/src/renderer/components/+custom-resources/custom-resources.tsx +++ b/src/renderer/components/+custom-resources/custom-resources.tsx @@ -17,7 +17,7 @@ export class CustomResources extends React.Component { url: crdURL(), routePath: crdRoute.path.toString(), } - ] + ]; } render() { diff --git a/src/renderer/components/+events/event-details.tsx b/src/renderer/components/+events/event-details.tsx index b3d80ce318..3d6f51ab0b 100644 --- a/src/renderer/components/+events/event-details.tsx +++ b/src/renderer/components/+events/event-details.tsx @@ -70,7 +70,7 @@ export class EventDetails extends React.Component { - ) + ); } } @@ -80,4 +80,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+events/event.store.ts b/src/renderer/components/+events/event.store.ts index 3d8142a55f..484c9701c1 100644 --- a/src/renderer/components/+events/event.store.ts +++ b/src/renderer/components/+events/event.store.ts @@ -10,8 +10,8 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class EventStore extends KubeObjectStore { - api = eventApi - limit = 1000 + api = eventApi; + limit = 1000; protected bindWatchEventsUpdater() { return super.bindWatchEventsUpdater(5000); @@ -20,7 +20,7 @@ export class EventStore extends KubeObjectStore { protected sortItems(items: KubeEvent[]) { return super.sortItems(items, [ event => event.metadata.creationTimestamp - ], "desc") + ], "desc"); } getEventsByObject(obj: KubeObject): KubeEvent[] { diff --git a/src/renderer/components/+events/events.route.ts b/src/renderer/components/+events/events.route.ts index b7d96824f6..6ae3a9a10b 100644 --- a/src/renderer/components/+events/events.route.ts +++ b/src/renderer/components/+events/events.route.ts @@ -3,6 +3,6 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const eventRoute: RouteProps = { path: "/events" -} +}; export const eventsURL = buildURL(eventRoute.path); diff --git a/src/renderer/components/+events/events.tsx b/src/renderer/components/+events/events.tsx index 868da0836a..0a6aab3730 100644 --- a/src/renderer/components/+events/events.tsx +++ b/src/renderer/components/+events/events.tsx @@ -106,14 +106,14 @@ export class Events extends React.Component { event.getSource(), event.count, event.getAge(), - ] + ]; }} virtual={!compact} filterItems={[ items => compact ? items.slice(0, compactLimit) : items, ]} /> - ) + ); if (compact) { return events; } @@ -121,6 +121,6 @@ export class Events extends React.Component { {events} - ) + ); } } diff --git a/src/renderer/components/+events/kube-event-details.tsx b/src/renderer/components/+events/kube-event-details.tsx index 5b3e5f23b9..297c4e791f 100644 --- a/src/renderer/components/+events/kube-event-details.tsx +++ b/src/renderer/components/+events/kube-event-details.tsx @@ -26,7 +26,7 @@ export class KubeEventDetails extends React.Component { Events - ) + ); } return ( @@ -35,7 +35,7 @@ export class KubeEventDetails extends React.Component { {events.map(evt => { - const { message, count, lastTimestamp, involvedObject } = evt + const { message, count, lastTimestamp, involvedObject } = evt; return ( @@ -54,10 +54,10 @@ export class KubeEventDetails extends React.Component { {lastTimestamp} - ) + ); })} - ) + ); } } diff --git a/src/renderer/components/+events/kube-event-icon.tsx b/src/renderer/components/+events/kube-event-icon.tsx index 204dfd3a36..15a91ea5b3 100644 --- a/src/renderer/components/+events/kube-event-icon.tsx +++ b/src/renderer/components/+events/kube-event-icon.tsx @@ -45,6 +45,6 @@ export class KubeEventIcon extends React.Component { ) }} /> - ) + ); } } diff --git a/src/renderer/components/+extensions/extensions.route.ts b/src/renderer/components/+extensions/extensions.route.ts index 78c5579901..04708ca5d4 100644 --- a/src/renderer/components/+extensions/extensions.route.ts +++ b/src/renderer/components/+extensions/extensions.route.ts @@ -3,6 +3,6 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const extensionsRoute: RouteProps = { path: "/extensions" -} +}; -export const extensionsURL = buildURL(extensionsRoute.path) +export const extensionsURL = buildURL(extensionsRoute.path); diff --git a/src/renderer/components/+extensions/extensions.tsx b/src/renderer/components/+extensions/extensions.tsx index 34814393ae..875861a8dd 100644 --- a/src/renderer/components/+extensions/extensions.tsx +++ b/src/renderer/components/+extensions/extensions.tsx @@ -15,7 +15,7 @@ import { extensionManager } from "../../../extensions/extension-manager"; @observer export class Extensions extends React.Component { - @observable search = "" + @observable search = ""; @computed get extensions() { const searchText = this.search.toLowerCase(); @@ -24,8 +24,8 @@ export class Extensions extends React.Component { return [ name.toLowerCase().includes(searchText), description.toLowerCase().includes(searchText), - ].some(v => v) - }) + ].some(v => v); + }); } get extensionsPath() { @@ -55,7 +55,7 @@ export class Extensions extends React.Component { Check out documentation to learn more - ) + ); } renderExtensions() { @@ -66,7 +66,7 @@ export class Extensions extends React.Component { {search && No search results found} {!search && There are no extensions in {extensionsPath}} - ) + ); } return extensions.map(ext => { const { manifestPath: extId, isEnabled, manifest } = ext; @@ -88,8 +88,8 @@ export class Extensions extends React.Component { ext.isEnabled = false}>Disable )} - ) - }) + ); + }); } render() { diff --git a/src/renderer/components/+extensions/index.ts b/src/renderer/components/+extensions/index.ts index 8946a5f6fe..ff9343e704 100644 --- a/src/renderer/components/+extensions/index.ts +++ b/src/renderer/components/+extensions/index.ts @@ -1,2 +1,2 @@ -export * from "./extensions.route" -export * from "./extensions" +export * from "./extensions.route"; +export * from "./extensions"; diff --git a/src/renderer/components/+landing-page/index.tsx b/src/renderer/components/+landing-page/index.tsx index 36f2dce350..4bdb2a706c 100644 --- a/src/renderer/components/+landing-page/index.tsx +++ b/src/renderer/components/+landing-page/index.tsx @@ -1,2 +1,2 @@ -export * from "./landing-page.route" -export * from "./landing-page" \ No newline at end of file +export * from "./landing-page.route"; +export * from "./landing-page"; \ No newline at end of file diff --git a/src/renderer/components/+landing-page/landing-page.route.ts b/src/renderer/components/+landing-page/landing-page.route.ts index 344cc48033..5fa9f2321e 100644 --- a/src/renderer/components/+landing-page/landing-page.route.ts +++ b/src/renderer/components/+landing-page/landing-page.route.ts @@ -3,6 +3,6 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const landingRoute: RouteProps = { path: "/landing" -} +}; -export const landingURL = buildURL(landingRoute.path) +export const landingURL = buildURL(landingRoute.path); diff --git a/src/renderer/components/+landing-page/landing-page.tsx b/src/renderer/components/+landing-page/landing-page.tsx index 68d71701c5..5c1e34297c 100644 --- a/src/renderer/components/+landing-page/landing-page.tsx +++ b/src/renderer/components/+landing-page/landing-page.tsx @@ -1,4 +1,4 @@ -import "./landing-page.scss" +import "./landing-page.scss"; import React from "react"; import { observable } from "mobx"; import { observer } from "mobx-react"; @@ -37,6 +37,6 @@ export class LandingPage extends React.Component { )} - ) + ); } } diff --git a/src/renderer/components/+namespaces/add-namespace-dialog.tsx b/src/renderer/components/+namespaces/add-namespace-dialog.tsx index 8c09c80138..a31a44de94 100644 --- a/src/renderer/components/+namespaces/add-namespace-dialog.tsx +++ b/src/renderer/components/+namespaces/add-namespace-dialog.tsx @@ -1,4 +1,4 @@ -import "./add-namespace-dialog.scss" +import "./add-namespace-dialog.scss"; import React from "react"; import { observable } from "mobx"; @@ -33,7 +33,7 @@ export class AddNamespaceDialog extends React.Component { close = () => { AddNamespaceDialog.close(); - } + }; addNamespace = async () => { const { namespace } = this; @@ -45,7 +45,7 @@ export class AddNamespaceDialog extends React.Component { Notifications.error(err); onError && onError(err); } - } + }; render() { const { ...dialogProps } = this.props; @@ -74,6 +74,6 @@ export class AddNamespaceDialog extends React.Component { - ) + ); } } diff --git a/src/renderer/components/+namespaces/index.ts b/src/renderer/components/+namespaces/index.ts index d0b9647dc7..3a03949618 100644 --- a/src/renderer/components/+namespaces/index.ts +++ b/src/renderer/components/+namespaces/index.ts @@ -1,4 +1,4 @@ -export * from "./namespaces.route" -export * from "./namespaces" -export * from "./namespace-details" -export * from "./add-namespace-dialog" +export * from "./namespaces.route"; +export * from "./namespaces"; +export * from "./namespace-details"; +export * from "./add-namespace-dialog"; diff --git a/src/renderer/components/+namespaces/namespace-details.tsx b/src/renderer/components/+namespaces/namespace-details.tsx index a7e2abf2f3..7599562333 100644 --- a/src/renderer/components/+namespaces/namespace-details.tsx +++ b/src/renderer/components/+namespaces/namespace-details.tsx @@ -62,4 +62,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+namespaces/namespace-select.tsx b/src/renderer/components/+namespaces/namespace-select.tsx index 7657a25345..e1c64f8342 100644 --- a/src/renderer/components/+namespaces/namespace-select.tsx +++ b/src/renderer/components/+namespaces/namespace-select.tsx @@ -1,4 +1,4 @@ -import "./namespace-select.scss" +import "./namespace-select.scss"; import React from "react"; import { computed } from "mobx"; @@ -62,7 +62,7 @@ export class NamespaceSelect extends React.Component { {value} > ); - } + }; render() { const { className, showIcons, showClusterOption, clusterOptionLabel, customizeOptions, ...selectProps } = this.props; @@ -83,8 +83,8 @@ export class NamespaceSelectFilter extends React.Component { render() { const { contextNs, hasContext, toggleContext } = namespaceStore; let placeholder = All namespaces; - if (contextNs.length == 1) placeholder = Namespace: {contextNs[0]} - if (contextNs.length >= 2) placeholder = Namespaces: {contextNs.join(", ")} + if (contextNs.length == 1) placeholder = Namespace: {contextNs[0]}; + if (contextNs.length >= 2) placeholder = Namespaces: {contextNs.join(", ")}; return ( {namespace} {isSelected && } - ) + ); }} /> - ) + ); } } diff --git a/src/renderer/components/+namespaces/namespace.store.ts b/src/renderer/components/+namespaces/namespace.store.ts index 8874aa9233..dabde6b47d 100644 --- a/src/renderer/components/+namespaces/namespace.store.ts +++ b/src/renderer/components/+namespaces/namespace.store.ts @@ -36,20 +36,20 @@ export class NamespaceStore extends KubeObjectStore { getContextParams(): Partial { return { namespaces: this.contextNs - } + }; } protected updateUrl(namespaces: string[]) { - setQueryParams({ namespaces }, { replace: true }) + setQueryParams({ namespaces }, { replace: true }); } protected async loadItems(namespaces?: string[]) { if (!isAllowedResource("namespaces")) { if (namespaces) return namespaces.map(this.getDummyNamespace); - return [] + return []; } if (namespaces) { - return Promise.all(namespaces.map(name => this.api.get({ name }))) + return Promise.all(namespaces.map(name => this.api.get({ name }))); } else { return super.loadItems(); } @@ -65,7 +65,7 @@ export class NamespaceStore extends KubeObjectStore { resourceVersion: "", selfLink: `/api/v1/namespaces/${name}` } - }) + }); } setContext(namespaces: string[]) { diff --git a/src/renderer/components/+namespaces/namespaces.route.ts b/src/renderer/components/+namespaces/namespaces.route.ts index 9d901b6ada..38c2d575d9 100644 --- a/src/renderer/components/+namespaces/namespaces.route.ts +++ b/src/renderer/components/+namespaces/namespaces.route.ts @@ -3,9 +3,9 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const namespacesRoute: RouteProps = { path: "/namespaces" -} +}; export interface INamespacesRouteParams { } -export const namespacesURL = buildURL(namespacesRoute.path) +export const namespacesURL = buildURL(namespacesRoute.path); diff --git a/src/renderer/components/+namespaces/namespaces.tsx b/src/renderer/components/+namespaces/namespaces.tsx index 05ef3da964..f4bb96aa14 100644 --- a/src/renderer/components/+namespaces/namespaces.tsx +++ b/src/renderer/components/+namespaces/namespaces.tsx @@ -1,4 +1,4 @@ -import "./namespaces.scss" +import "./namespaces.scss"; import React from "react"; import { Trans } from "@lingui/macro"; @@ -64,6 +64,6 @@ export class Namespaces extends React.Component { /> - ) + ); } } diff --git a/src/renderer/components/+network-endpoints/endpoint-details.tsx b/src/renderer/components/+network-endpoints/endpoint-details.tsx index fa5ca675a3..df01cf612e 100644 --- a/src/renderer/components/+network-endpoints/endpoint-details.tsx +++ b/src/renderer/components/+network-endpoints/endpoint-details.tsx @@ -1,4 +1,4 @@ -import "./endpoint-details.scss" +import "./endpoint-details.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -28,7 +28,7 @@ export class EndpointDetails extends React.Component { endpoint.getEndpointSubsets().map((subset) => { return( - ) + ); }) } @@ -42,7 +42,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "Endpoints", apiVersions: ["v1"], @@ -50,4 +50,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx b/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx index 399c6ca5f1..0c3c5c0436 100644 --- a/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx +++ b/src/renderer/components/+network-endpoints/endpoint-subset-list.tsx @@ -1,4 +1,4 @@ -import "./endpoint-subset-list.scss" +import "./endpoint-subset-list.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -23,14 +23,14 @@ export class EndpointSubsetList extends React.Component { getAddressTableRow(ip: string) { const { subset } = this.props; const address = subset.getAddresses().find(address => address.getId() == ip); - return this.renderAddressTableRow(address) + return this.renderAddressTableRow(address); } @autobind() getNotReadyAddressTableRow(ip: string) { const { subset} = this.props; const address = subset.getNotReadyAddresses().find(address => address.getId() == ip); - return this.renderAddressTableRow(address) + return this.renderAddressTableRow(address); } @autobind() @@ -56,7 +56,7 @@ export class EndpointSubsetList extends React.Component { } - ) + ); } @autobind() diff --git a/src/renderer/components/+network-endpoints/endpoints.route.ts b/src/renderer/components/+network-endpoints/endpoints.route.ts index 98ecb67bdb..f350b7868e 100644 --- a/src/renderer/components/+network-endpoints/endpoints.route.ts +++ b/src/renderer/components/+network-endpoints/endpoints.route.ts @@ -3,9 +3,9 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const endpointRoute: RouteProps = { path: "/endpoints" -} +}; export interface EndpointRouteParams { } -export const endpointURL = buildURL(endpointRoute.path) +export const endpointURL = buildURL(endpointRoute.path); diff --git a/src/renderer/components/+network-endpoints/endpoints.store.ts b/src/renderer/components/+network-endpoints/endpoints.store.ts index 5d4a6b6ff7..d61a12126e 100644 --- a/src/renderer/components/+network-endpoints/endpoints.store.ts +++ b/src/renderer/components/+network-endpoints/endpoints.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class EndpointStore extends KubeObjectStore { - api = endpointApi + api = endpointApi; } export const endpointStore = new EndpointStore(); diff --git a/src/renderer/components/+network-endpoints/endpoints.tsx b/src/renderer/components/+network-endpoints/endpoints.tsx index b32b19946c..b8862841cb 100644 --- a/src/renderer/components/+network-endpoints/endpoints.tsx +++ b/src/renderer/components/+network-endpoints/endpoints.tsx @@ -1,10 +1,10 @@ -import "./endpoints.scss" +import "./endpoints.scss"; -import React from "react" +import React from "react"; import { observer } from "mobx-react"; -import { RouteComponentProps } from "react-router-dom" -import { EndpointRouteParams } from "./endpoints.route" -import { Endpoint } from "../../api/endpoints/endpoint.api" +import { RouteComponentProps } from "react-router-dom"; +import { EndpointRouteParams } from "./endpoints.route"; +import { Endpoint } from "../../api/endpoints/endpoint.api"; import { endpointStore } from "./endpoints.store"; import { KubeObjectListLayout } from "../kube-object"; import { Trans } from "@lingui/macro"; @@ -55,6 +55,6 @@ export class Endpoints extends React.Component { } }} /> - ) + ); } } diff --git a/src/renderer/components/+network-endpoints/index.ts b/src/renderer/components/+network-endpoints/index.ts index 9a9da148d6..eb91009613 100644 --- a/src/renderer/components/+network-endpoints/index.ts +++ b/src/renderer/components/+network-endpoints/index.ts @@ -1,3 +1,3 @@ -export * from "./endpoints.route" -export * from "./endpoints" -export * from "./endpoint-details" +export * from "./endpoints.route"; +export * from "./endpoints"; +export * from "./endpoint-details"; diff --git a/src/renderer/components/+network-ingresses/index.ts b/src/renderer/components/+network-ingresses/index.ts index 46769f9275..3977538fc7 100644 --- a/src/renderer/components/+network-ingresses/index.ts +++ b/src/renderer/components/+network-ingresses/index.ts @@ -1,3 +1,3 @@ -export * from "./ingresses.route" -export * from "./ingresses" -export * from "./ingress-details" +export * from "./ingresses.route"; +export * from "./ingresses"; +export * from "./ingress-details"; diff --git a/src/renderer/components/+network-ingresses/ingress-charts.tsx b/src/renderer/components/+network-ingresses/ingress-charts.tsx index 89ceb86b3d..7ea16a92a3 100644 --- a/src/renderer/components/+network-ingresses/ingress-charts.tsx +++ b/src/renderer/components/+network-ingresses/ingress-charts.tsx @@ -94,4 +94,4 @@ export const IngressCharts = observer(() => { data={{ datasets: datasets[tabId] }} /> ); -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/src/renderer/components/+network-ingresses/ingress-details.tsx b/src/renderer/components/+network-ingresses/ingress-details.tsx index 5a4479672b..a258294abe 100644 --- a/src/renderer/components/+network-ingresses/ingress-details.tsx +++ b/src/renderer/components/+network-ingresses/ingress-details.tsx @@ -30,8 +30,8 @@ export class IngressDetails extends React.Component { } renderPaths(ingress: Ingress) { - const { spec: { rules } } = ingress - if (!rules || !rules.length) return null + const { spec: { rules } } = ingress; + if (!rules || !rules.length) return null; return rules.map((rule, index) => { return ( @@ -48,7 +48,7 @@ export class IngressDetails extends React.Component { { rule.http.paths.map((path, index) => { - const backend = `${path.backend.serviceName}:${path.backend.servicePort}` + const backend = `${path.backend.serviceName}:${path.backend.servicePort}`; return ( {path.path || ""} @@ -56,18 +56,18 @@ export class IngressDetails extends React.Component { {backend} - ) + ); }) } )} - ) - }) + ); + }); } renderIngressPoints(ingressPoints: ILoadBalancerIngress[]) { - if (!ingressPoints || ingressPoints.length === 0) return null + if (!ingressPoints || ingressPoints.length === 0) return null; return ( @@ -81,11 +81,11 @@ export class IngressDetails extends React.Component { {hostname ? hostname : "-"} {ip ? ip : "-"} - )}) + );}) }) - ) + ); } render() { @@ -94,7 +94,7 @@ export class IngressDetails extends React.Component { return null; } const { spec, status } = ingress; - const ingressPoints = status?.loadBalancer?.ingress + const ingressPoints = status?.loadBalancer?.ingress; const { metrics } = ingressStore; const metricTabs = [ Network, @@ -128,7 +128,7 @@ export class IngressDetails extends React.Component { Load-Balancer Ingress Points}/> {this.renderIngressPoints(ingressPoints)} - ) + ); } } @@ -138,7 +138,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "Ingress", apiVersions: ["extensions/v1beta1"], @@ -146,4 +146,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+network-ingresses/ingresses.route.ts b/src/renderer/components/+network-ingresses/ingresses.route.ts index 1c1f2941f4..827707bcef 100644 --- a/src/renderer/components/+network-ingresses/ingresses.route.ts +++ b/src/renderer/components/+network-ingresses/ingresses.route.ts @@ -3,9 +3,9 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const ingressRoute: RouteProps = { path: "/ingresses" -} +}; export interface IngressRouteParams { } -export const ingressURL = buildURL(ingressRoute.path) +export const ingressURL = buildURL(ingressRoute.path); diff --git a/src/renderer/components/+network-ingresses/ingresses.tsx b/src/renderer/components/+network-ingresses/ingresses.tsx index 2ecfeb1585..bba5615915 100644 --- a/src/renderer/components/+network-ingresses/ingresses.tsx +++ b/src/renderer/components/+network-ingresses/ingresses.tsx @@ -1,10 +1,10 @@ -import "./ingresses.scss" +import "./ingresses.scss"; -import React from "react" +import React from "react"; import { observer } from "mobx-react"; -import { RouteComponentProps } from "react-router-dom" -import { IngressRouteParams } from "./ingresses.route" -import { Ingress } from "../../api/endpoints/ingress.api" +import { RouteComponentProps } from "react-router-dom"; +import { IngressRouteParams } from "./ingresses.route"; +import { Ingress } from "../../api/endpoints/ingress.api"; import { ingressStore } from "./ingress.store"; import { KubeObjectListLayout } from "../kube-object"; import { Trans } from "@lingui/macro"; @@ -58,6 +58,6 @@ export class Ingresses extends React.Component { } }} /> - ) + ); } } diff --git a/src/renderer/components/+network-policies/index.ts b/src/renderer/components/+network-policies/index.ts index 0521db2765..f0092b8bcc 100644 --- a/src/renderer/components/+network-policies/index.ts +++ b/src/renderer/components/+network-policies/index.ts @@ -1,3 +1,3 @@ -export * from "./network-policies.route" -export * from "./network-policies" -export * from "./network-policy-details" +export * from "./network-policies.route"; +export * from "./network-policies"; +export * from "./network-policy-details"; diff --git a/src/renderer/components/+network-policies/network-policies.route.ts b/src/renderer/components/+network-policies/network-policies.route.ts index ab609200ce..16b507cd55 100644 --- a/src/renderer/components/+network-policies/network-policies.route.ts +++ b/src/renderer/components/+network-policies/network-policies.route.ts @@ -3,7 +3,7 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const networkPoliciesRoute: RouteProps = { path: "/network-policies" -} +}; export interface INetworkPoliciesRouteParams { } diff --git a/src/renderer/components/+network-policies/network-policies.tsx b/src/renderer/components/+network-policies/network-policies.tsx index f28917f653..b54b6a80aa 100644 --- a/src/renderer/components/+network-policies/network-policies.tsx +++ b/src/renderer/components/+network-policies/network-policies.tsx @@ -1,4 +1,4 @@ -import "./network-policies.scss" +import "./network-policies.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -49,6 +49,6 @@ export class NetworkPolicies extends React.Component { item.getAge(), ]} /> - ) + ); } } diff --git a/src/renderer/components/+network-policies/network-policy-details.tsx b/src/renderer/components/+network-policies/network-policy-details.tsx index 6f38f6d02b..ac9f1d7ba2 100644 --- a/src/renderer/components/+network-policies/network-policy-details.tsx +++ b/src/renderer/components/+network-policies/network-policy-details.tsx @@ -1,4 +1,4 @@ -import "./network-policy-details.scss" +import "./network-policy-details.scss"; import get from "lodash/get"; import React, { Fragment } from "react"; @@ -27,10 +27,10 @@ export class NetworkPolicyDetails extends React.Component { From}/> {from.map(item => Object.keys(item).map(key => { - const data = get(item, key) + const data = get(item, key); if (key === "ipBlock") { const { cidr, except } = data as IPolicyIpBlock; - if (!cidr) return + if (!cidr) return; return ( cidr: {cidr}, {" "} @@ -38,9 +38,9 @@ export class NetworkPolicyDetails extends React.Component { `except: ${except.join(", ")}` } - ) + ); } - const selector: IPolicySelector = data + const selector: IPolicySelector = data; if (selector.matchLabels) { return ( @@ -51,7 +51,7 @@ export class NetworkPolicyDetails extends React.Component { .join(", ") } - ) + ); } else { return ((empty)); @@ -69,10 +69,10 @@ export class NetworkPolicyDetails extends React.Component { <> To}/> {to.map(item => { - const { ipBlock } = item - if (!ipBlock) return - const { cidr, except } = ipBlock - if (!cidr) return + const { ipBlock } = item; + if (!ipBlock) return; + const { cidr, except } = ipBlock; + if (!cidr) return; return ( cidr: {cidr}, {" "} @@ -80,7 +80,7 @@ export class NetworkPolicyDetails extends React.Component { `except: ${except.join(", ")}` } - ) + ); })} > ); @@ -116,7 +116,7 @@ export class NetworkPolicyDetails extends React.Component { {this.renderIngressFrom(ingress)} - ) + ); })} > )} @@ -133,7 +133,7 @@ export class NetworkPolicyDetails extends React.Component { {this.renderEgressTo(egress)} - ) + ); })} > )} @@ -148,7 +148,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "NetworkPolicy", @@ -157,4 +157,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+network-policies/network-policy.store.ts b/src/renderer/components/+network-policies/network-policy.store.ts index 0f37de3ac0..e33a17fa09 100644 --- a/src/renderer/components/+network-policies/network-policy.store.ts +++ b/src/renderer/components/+network-policies/network-policy.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class NetworkPolicyStore extends KubeObjectStore { - api = networkPolicyApi + api = networkPolicyApi; } export const networkPolicyStore = new NetworkPolicyStore(); diff --git a/src/renderer/components/+network-services/index.ts b/src/renderer/components/+network-services/index.ts index 4f64dcf2c9..de2b4282d5 100644 --- a/src/renderer/components/+network-services/index.ts +++ b/src/renderer/components/+network-services/index.ts @@ -1,3 +1,3 @@ -export * from "./services.route" -export * from "./services" -export * from "./service-details" +export * from "./services.route"; +export * from "./services"; +export * from "./service-details"; diff --git a/src/renderer/components/+network-services/service-details-endpoint.tsx b/src/renderer/components/+network-services/service-details-endpoint.tsx index a16d1c2c0a..df0aac76ec 100644 --- a/src/renderer/components/+network-services/service-details-endpoint.tsx +++ b/src/renderer/components/+network-services/service-details-endpoint.tsx @@ -15,12 +15,12 @@ interface Props { @observer export class ServiceDetailsEndpoint extends React.Component { render() { - const { endpoint } = this.props + const { endpoint } = this.props; if (!endpoint && !endpointStore.isLoaded) return ( ); if (!endpoint) { - return null + return null; } return ( @@ -44,6 +44,6 @@ export class ServiceDetailsEndpoint extends React.Component { - ) + ); } } diff --git a/src/renderer/components/+network-services/service-details.tsx b/src/renderer/components/+network-services/service-details.tsx index e43f7fab0c..5d659cc7e1 100644 --- a/src/renderer/components/+network-services/service-details.tsx +++ b/src/renderer/components/+network-services/service-details.tsx @@ -1,4 +1,4 @@ -import "./service-details.scss" +import "./service-details.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -24,14 +24,14 @@ export class ServiceDetails extends React.Component { if (!endpointStore.isLoaded) { endpointStore.loadAll(); } - endpointApi.watch() + endpointApi.watch(); } render() { const { object: service } = this.props; if (!service) return; const { spec } = service; - const endpoint = endpointStore.getByName(service.getName(), service.getNs()) + const endpoint = endpointStore.getByName(service.getName(), service.getNs()); return ( @@ -89,7 +89,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "Service", @@ -98,4 +98,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+network-services/service-port-component.tsx b/src/renderer/components/+network-services/service-port-component.tsx index 252bf8eb16..8b3dba03c4 100644 --- a/src/renderer/components/+network-services/service-port-component.tsx +++ b/src/renderer/components/+network-services/service-port-component.tsx @@ -1,15 +1,15 @@ -import "./service-port-component.scss" +import "./service-port-component.scss"; import React from "react"; import { observer } from "mobx-react"; import { t } from "@lingui/macro"; import { Service, ServicePort } from "../../api/endpoints"; import { _i18n } from "../../i18n"; -import { apiBase } from "../../api" +import { apiBase } from "../../api"; import { observable } from "mobx"; import { cssNames } from "../../utils"; import { Notifications } from "../notifications"; -import { Spinner } from "../spinner" +import { Spinner } from "../spinner"; interface Props { service: Service; @@ -24,7 +24,7 @@ export class ServicePortComponent extends React.Component { const { service, port } = this.props; this.waiting = true; try { - await apiBase.post(`/pods/${service.getNs()}/service/${service.getName()}/port-forward/${port.port}`, {}) + await apiBase.post(`/pods/${service.getNs()}/service/${service.getName()}/port-forward/${port.port}`, {}); } catch(error) { Notifications.error(error); } finally { diff --git a/src/renderer/components/+network-services/services.route.ts b/src/renderer/components/+network-services/services.route.ts index 8cc42090a7..b23087829d 100644 --- a/src/renderer/components/+network-services/services.route.ts +++ b/src/renderer/components/+network-services/services.route.ts @@ -3,7 +3,7 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const servicesRoute: RouteProps = { path: "/services" -} +}; export interface IServicesRouteParams { } diff --git a/src/renderer/components/+network-services/services.store.ts b/src/renderer/components/+network-services/services.store.ts index d3e3c7b983..8c6d16d746 100644 --- a/src/renderer/components/+network-services/services.store.ts +++ b/src/renderer/components/+network-services/services.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class ServiceStore extends KubeObjectStore { - api = serviceApi + api = serviceApi; } export const serviceStore = new ServiceStore(); diff --git a/src/renderer/components/+network-services/services.tsx b/src/renderer/components/+network-services/services.tsx index ed7951a78b..0aacbb602e 100644 --- a/src/renderer/components/+network-services/services.tsx +++ b/src/renderer/components/+network-services/services.tsx @@ -1,4 +1,4 @@ -import "./services.scss" +import "./services.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -72,6 +72,6 @@ export class Services extends React.Component { { title: service.getStatus(), className: service.getStatus().toLowerCase() }, ]} /> - ) + ); } } diff --git a/src/renderer/components/+network/index.ts b/src/renderer/components/+network/index.ts index c5282c5b0e..9a58dc59a6 100644 --- a/src/renderer/components/+network/index.ts +++ b/src/renderer/components/+network/index.ts @@ -1,2 +1,2 @@ -export * from "./network.route" -export * from "./network" +export * from "./network.route"; +export * from "./network"; diff --git a/src/renderer/components/+network/network.route.ts b/src/renderer/components/+network/network.route.ts index c13f7cedf7..de36bfc77a 100644 --- a/src/renderer/components/+network/network.route.ts +++ b/src/renderer/components/+network/network.route.ts @@ -1,12 +1,12 @@ -import { RouteProps } from "react-router" +import { RouteProps } from "react-router"; import { Network } from "./network"; import { servicesURL } from "../+network-services"; import { IURLParams } from "../../../common/utils/buildUrl"; export const networkRoute: RouteProps = { get path() { - return Network.tabRoutes.map(({ routePath }) => routePath).flat() + return Network.tabRoutes.map(({ routePath }) => routePath).flat(); } -} +}; export const networkURL = (params?: IURLParams) => servicesURL(params); diff --git a/src/renderer/components/+network/network.tsx b/src/renderer/components/+network/network.tsx index 9e0b2d92c6..2cc99eb367 100644 --- a/src/renderer/components/+network/network.tsx +++ b/src/renderer/components/+network/network.tsx @@ -1,4 +1,4 @@ -import "./network.scss" +import "./network.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -14,7 +14,7 @@ import { isAllowedResource } from "../../../common/rbac"; @observer export class Network extends React.Component { static get tabRoutes(): TabLayoutRoute[] { - const query = namespaceStore.getContextParams() + const query = namespaceStore.getContextParams(); const routes: TabLayoutRoute[] = []; if (isAllowedResource("services")) { routes.push({ @@ -22,7 +22,7 @@ export class Network extends React.Component { component: Services, url: servicesURL({ query }), routePath: servicesRoute.path.toString(), - }) + }); } if (isAllowedResource("endpoints")) { routes.push({ @@ -30,7 +30,7 @@ export class Network extends React.Component { component: Endpoints, url: endpointURL({ query }), routePath: endpointRoute.path.toString(), - }) + }); } if (isAllowedResource("ingresses")) { routes.push({ @@ -38,7 +38,7 @@ export class Network extends React.Component { component: Ingresses, url: ingressURL({ query }), routePath: ingressRoute.path.toString(), - }) + }); } if (isAllowedResource("networkpolicies")) { routes.push({ @@ -46,14 +46,14 @@ export class Network extends React.Component { component: NetworkPolicies, url: networkPoliciesURL({ query }), routePath: networkPoliciesRoute.path.toString(), - }) + }); } - return routes + return routes; } render() { return ( - ) + ); } } diff --git a/src/renderer/components/+nodes/index.ts b/src/renderer/components/+nodes/index.ts index 4a77b1c63b..515a3d85f6 100644 --- a/src/renderer/components/+nodes/index.ts +++ b/src/renderer/components/+nodes/index.ts @@ -1,3 +1,3 @@ -export * from "./nodes" -export * from "./nodes.route" -export * from "./node-details" +export * from "./nodes"; +export * from "./nodes.route"; +export * from "./node-details"; diff --git a/src/renderer/components/+nodes/node-charts.tsx b/src/renderer/components/+nodes/node-charts.tsx index 4271181fcd..9f5e6ce6f8 100644 --- a/src/renderer/components/+nodes/node-charts.tsx +++ b/src/renderer/components/+nodes/node-charts.tsx @@ -140,7 +140,7 @@ export const NodeCharts = observer(() => { } } } - } + }; const options = [cpuOptions, memoryOptions, memoryOptions, podOptions]; @@ -151,4 +151,4 @@ export const NodeCharts = observer(() => { data={{ datasets: datasets[tabId] }} /> ); -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/src/renderer/components/+nodes/node-details.tsx b/src/renderer/components/+nodes/node-details.tsx index 1402b77be5..653fff8d2b 100644 --- a/src/renderer/components/+nodes/node-details.tsx +++ b/src/renderer/components/+nodes/node-details.tsx @@ -42,12 +42,12 @@ export class NodeDetails extends React.Component { render() { const { object: node } = this.props; if (!node) return; - const { status } = node - const { nodeInfo, addresses, capacity, allocatable } = status + const { status } = node; + const { nodeInfo, addresses, capacity, allocatable } = status; const conditions = node.getActiveConditions(); - const taints = node.getTaints() - const childPods = podsStore.getPodsByNode(node.getName()) - const metrics = nodesStore.nodeMetrics + const taints = node.getTaints(); + const childPods = podsStore.getPodsByNode(node.getName()); + const metrics = nodesStore.nodeMetrics; const metricTabs = [ CPU, Memory, @@ -120,7 +120,7 @@ export class NodeDetails extends React.Component { Conditions} className="conditions" labelsOnly> { conditions.map(condition => { - const { type } = condition + const { type } = condition; return ( { ) }} /> - ) + ); }) } @@ -150,7 +150,7 @@ export class NodeDetails extends React.Component { maxMemory={node.getMemoryCapacity()} /> - ) + ); } } @@ -160,7 +160,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "Node", @@ -169,4 +169,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+nodes/nodes.route.ts b/src/renderer/components/+nodes/nodes.route.ts index cf03a8733d..972bdababe 100644 --- a/src/renderer/components/+nodes/nodes.route.ts +++ b/src/renderer/components/+nodes/nodes.route.ts @@ -3,9 +3,9 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const nodesRoute: RouteProps = { path: "/nodes" -} +}; export interface INodesRouteParams { } -export const nodesURL = buildURL(nodesRoute.path) +export const nodesURL = buildURL(nodesRoute.path); diff --git a/src/renderer/components/+nodes/nodes.store.ts b/src/renderer/components/+nodes/nodes.store.ts index 8c04f55ad5..94fd3e4dd9 100644 --- a/src/renderer/components/+nodes/nodes.store.ts +++ b/src/renderer/components/+nodes/nodes.store.ts @@ -1,4 +1,4 @@ -import { action, computed, observable } from "mobx" +import { action, computed, observable } from "mobx"; import { clusterApi, IClusterMetrics, INodeMetrics, Node, nodesApi } from "../../api/endpoints"; import { autobind } from "../../utils"; import { KubeObjectStore } from "../../kube-object.store"; @@ -6,7 +6,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class NodesStore extends KubeObjectStore { - api = nodesApi + api = nodesApi; @observable metrics: Partial = {}; @observable nodeMetrics: Partial = null; @@ -30,11 +30,11 @@ export class NodesStore extends KubeObjectStore { } @computed get masterNodes() { - return this.items.filter(node => node.getRoleLabels().includes("master")) + return this.items.filter(node => node.getRoleLabels().includes("master")); } @computed get workerNodes() { - return this.items.filter(node => !node.getRoleLabels().includes("master")) + return this.items.filter(node => !node.getRoleLabels().includes("master")); } getLastMetricValues(node: Node, metricNames: string[]): number[] { @@ -50,7 +50,7 @@ export class NodesStore extends KubeObjectStore { result.metric.node, result.metric.instance, result.metric.kubernetes_node, - ].includes(nodeName) + ].includes(nodeName); }); return result ? parseFloat(result.values.slice(-1)[0][1]) : 0; } catch (e) { @@ -68,5 +68,5 @@ export class NodesStore extends KubeObjectStore { } } -export const nodesStore = new NodesStore() +export const nodesStore = new NodesStore(); apiManager.registerStore(nodesStore); diff --git a/src/renderer/components/+nodes/nodes.tsx b/src/renderer/components/+nodes/nodes.tsx index 9e7c295f6c..82efc4ce92 100644 --- a/src/renderer/components/+nodes/nodes.tsx +++ b/src/renderer/components/+nodes/nodes.tsx @@ -60,7 +60,7 @@ export class Nodes extends React.Component { children: _i18n._(t`CPU:`) + ` ${Math.ceil(usage * 100) / cores}\%, ` + _i18n._(t`cores:`) + ` ${cores}` }} /> - ) + ); } renderMemoryUsage(node: Node) { @@ -77,7 +77,7 @@ export class Nodes extends React.Component { children: _i18n._(t`Memory:`) + ` ${Math.ceil(usage * 100 / capacity)}%, ${bytesToUnits(usage, 3)}` }} /> - ) + ); } renderDiskUsage(node: Node): any { @@ -94,17 +94,17 @@ export class Nodes extends React.Component { children: _i18n._(t`Disk:`) + ` ${Math.ceil(usage * 100 / capacity)}%, ${bytesToUnits(usage, 3)}` }} /> - ) + ); } renderConditions(node: Node) { if (!node.status.conditions) { - return null + return null; } const conditions = node.getActiveConditions(); return conditions.map(condition => { - const { type } = condition - const tooltipId = `node-${node.getName()}-condition-${type}` + const { type } = condition; + const tooltipId = `node-${node.getName()}-condition-${type}`; return ( {type} @@ -116,8 +116,8 @@ export class Nodes extends React.Component { )} - ) - }) + ); + }); } render() { @@ -177,10 +177,10 @@ export class Nodes extends React.Component { node.status.nodeInfo.kubeletVersion, node.getAge(), this.renderConditions(node), - ] + ]; }} /> - ) + ); } } diff --git a/src/renderer/components/+pod-security-policies/index.ts b/src/renderer/components/+pod-security-policies/index.ts index d9401de3c8..d037873b5b 100644 --- a/src/renderer/components/+pod-security-policies/index.ts +++ b/src/renderer/components/+pod-security-policies/index.ts @@ -1,3 +1,3 @@ -export * from "./pod-security-policies.route" -export * from "./pod-security-policies" -export * from "./pod-security-policy-details" \ No newline at end of file +export * from "./pod-security-policies.route"; +export * from "./pod-security-policies"; +export * from "./pod-security-policy-details"; \ No newline at end of file diff --git a/src/renderer/components/+pod-security-policies/pod-security-policies.route.ts b/src/renderer/components/+pod-security-policies/pod-security-policies.route.ts index e69f711bea..8bee44985e 100644 --- a/src/renderer/components/+pod-security-policies/pod-security-policies.route.ts +++ b/src/renderer/components/+pod-security-policies/pod-security-policies.route.ts @@ -3,6 +3,6 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const podSecurityPoliciesRoute: RouteProps = { path: "/pod-security-policies" -} +}; -export const podSecurityPoliciesURL = buildURL(podSecurityPoliciesRoute.path) +export const podSecurityPoliciesURL = buildURL(podSecurityPoliciesRoute.path); diff --git a/src/renderer/components/+pod-security-policies/pod-security-policies.store.ts b/src/renderer/components/+pod-security-policies/pod-security-policies.store.ts index 2517dcc59a..53ecde3d9d 100644 --- a/src/renderer/components/+pod-security-policies/pod-security-policies.store.ts +++ b/src/renderer/components/+pod-security-policies/pod-security-policies.store.ts @@ -5,8 +5,8 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class PodSecurityPoliciesStore extends KubeObjectStore { - api = pspApi + api = pspApi; } -export const podSecurityPoliciesStore = new PodSecurityPoliciesStore() +export const podSecurityPoliciesStore = new PodSecurityPoliciesStore(); apiManager.registerStore(podSecurityPoliciesStore); diff --git a/src/renderer/components/+pod-security-policies/pod-security-policies.tsx b/src/renderer/components/+pod-security-policies/pod-security-policies.tsx index 8ad6b77101..779a3a75ff 100644 --- a/src/renderer/components/+pod-security-policies/pod-security-policies.tsx +++ b/src/renderer/components/+pod-security-policies/pod-security-policies.tsx @@ -49,9 +49,9 @@ export class PodSecurityPolicies extends React.Component { item.isPrivileged() ? Yes : No, item.getVolumes().join(", "), item.getAge(), - ] + ]; }} /> - ) + ); } } diff --git a/src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx b/src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx index 2c50a4b668..5e0b812346 100644 --- a/src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx +++ b/src/renderer/components/+pod-security-policies/pod-security-policy-details.tsx @@ -33,12 +33,12 @@ export class PodSecurityPolicyDetails extends React.Component { {ranges && ( Ranges (Min-Max)} labelsOnly> {ranges.map(({ min, max }, index) => { - return + return ; })} )} > - ) + ); } render() { @@ -137,7 +137,7 @@ export class PodSecurityPolicyDetails extends React.Component { {hostPorts && ( Host Ports (Min-Max)} labelsOnly> {hostPorts.map(({ min, max }, index) => { - return + return ; })} )} @@ -156,7 +156,7 @@ export class PodSecurityPolicyDetails extends React.Component { {pathPrefix} {readOnly ? Yes : No} - ) + ); })} > @@ -205,7 +205,7 @@ export class PodSecurityPolicyDetails extends React.Component { )} - ) + ); } } @@ -215,4 +215,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+preferences/index.tsx b/src/renderer/components/+preferences/index.tsx index b4d669a029..7b4ae710ae 100644 --- a/src/renderer/components/+preferences/index.tsx +++ b/src/renderer/components/+preferences/index.tsx @@ -1,2 +1,2 @@ -export * from "./preferences.route" -export * from "./preferences" +export * from "./preferences.route"; +export * from "./preferences"; diff --git a/src/renderer/components/+preferences/kubectl-binaries.tsx b/src/renderer/components/+preferences/kubectl-binaries.tsx index 002ddfdcc3..3b0b258ab4 100644 --- a/src/renderer/components/+preferences/kubectl-binaries.tsx +++ b/src/renderer/components/+preferences/kubectl-binaries.tsx @@ -16,12 +16,12 @@ export const KubectlBinaries = observer(({ preferences }: { preferences: UserPre const downloadMirrorOptions: SelectOption[] = [ { value: "default", label: "Default (Google)" }, { value: "china", label: "China (Azure)" }, - ] + ]; const save = () => { preferences.downloadBinariesPath = downloadPath; preferences.kubectlBinariesPath = binariesPath; - } + }; return ( <> diff --git a/src/renderer/components/+preferences/preferences.route.ts b/src/renderer/components/+preferences/preferences.route.ts index 8fc7e70b0e..7c880bd5fc 100644 --- a/src/renderer/components/+preferences/preferences.route.ts +++ b/src/renderer/components/+preferences/preferences.route.ts @@ -3,6 +3,6 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const preferencesRoute: RouteProps = { path: "/preferences" -} +}; -export const preferencesURL = buildURL(preferencesRoute.path) +export const preferencesURL = buildURL(preferencesRoute.path); diff --git a/src/renderer/components/+preferences/preferences.tsx b/src/renderer/components/+preferences/preferences.tsx index 2fc58646df..78f2896a73 100644 --- a/src/renderer/components/+preferences/preferences.tsx +++ b/src/renderer/components/+preferences/preferences.tsx @@ -1,4 +1,4 @@ -import "./preferences.scss" +import "./preferences.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -30,14 +30,14 @@ export class Preferences extends React.Component { return themeStore.themes.map(theme => ({ label: theme.name, value: theme.id, - })) + })); } @computed get helmOptions(): SelectOption[] { return this.helmRepos.map(repo => ({ label: repo.name, value: repo, - })) + })); } async componentDidMount() { @@ -65,7 +65,7 @@ export class Preferences extends React.Component { await repoManager.addRepo(repo); this.helmAddedRepos.set(repo.name, repo); } catch (err) { - Notifications.error(Adding helm branch {repo.name} has failed: {String(err)}) + Notifications.error(Adding helm branch {repo.name} has failed: {String(err)}); } } @@ -76,20 +76,20 @@ export class Preferences extends React.Component { } catch (err) { Notifications.error( Removing helm branch {repo.name} has failed: {String(err)} - ) + ); } } onRepoSelect = async ({ value: repo }: SelectOption) => { const isAdded = this.helmAddedRepos.has(repo.name); if (isAdded) { - Notifications.ok(Helm branch {repo.name} already in use) + Notifications.ok(Helm branch {repo.name} already in use); return; } this.helmLoading = true; await this.addRepo(repo); this.helmLoading = false; - } + }; formatHelmOptionLabel = ({ value: repo }: SelectOption) => { const isAdded = this.helmAddedRepos.has(repo.name); @@ -98,8 +98,8 @@ export class Preferences extends React.Component { {repo.name} {isAdded && } - ) - } + ); + }; render() { const { preferences } = userStore; @@ -152,7 +152,7 @@ export class Preferences extends React.Component { {repo.url} - ) + ); })} @@ -185,7 +185,7 @@ export class Preferences extends React.Component { - ) + ); })} diff --git a/src/renderer/components/+storage-classes/index.ts b/src/renderer/components/+storage-classes/index.ts index 923c64adc9..3a0b106256 100644 --- a/src/renderer/components/+storage-classes/index.ts +++ b/src/renderer/components/+storage-classes/index.ts @@ -1,4 +1,4 @@ -export * from "./storage-classes.route" -export * from "./storage-classes" -export * from "./storage-class-details" +export * from "./storage-classes.route"; +export * from "./storage-classes"; +export * from "./storage-class-details"; diff --git a/src/renderer/components/+storage-classes/storage-class-details.tsx b/src/renderer/components/+storage-classes/storage-class-details.tsx index 0edbc6426b..312e2d7ea3 100644 --- a/src/renderer/components/+storage-classes/storage-class-details.tsx +++ b/src/renderer/components/+storage-classes/storage-class-details.tsx @@ -66,7 +66,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "StorageClass", @@ -75,4 +75,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+storage-classes/storage-class.store.ts b/src/renderer/components/+storage-classes/storage-class.store.ts index 9ff90bc921..9e388456a5 100644 --- a/src/renderer/components/+storage-classes/storage-class.store.ts +++ b/src/renderer/components/+storage-classes/storage-class.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class StorageClassStore extends KubeObjectStore { - api = storageClassApi + api = storageClassApi; } export const storageClassStore = new StorageClassStore(); diff --git a/src/renderer/components/+storage-classes/storage-classes.route.ts b/src/renderer/components/+storage-classes/storage-classes.route.ts index 2f809ef9f3..c75d7dd0b8 100644 --- a/src/renderer/components/+storage-classes/storage-classes.route.ts +++ b/src/renderer/components/+storage-classes/storage-classes.route.ts @@ -3,10 +3,10 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const storageClassesRoute: RouteProps = { path: "/storage-classes" -} +}; export interface IStorageClassesRouteParams { } -export const storageClassesURL = buildURL(storageClassesRoute.path) +export const storageClassesURL = buildURL(storageClassesRoute.path); diff --git a/src/renderer/components/+storage-classes/storage-classes.tsx b/src/renderer/components/+storage-classes/storage-classes.tsx index f75b48d691..b4133c8918 100644 --- a/src/renderer/components/+storage-classes/storage-classes.tsx +++ b/src/renderer/components/+storage-classes/storage-classes.tsx @@ -1,4 +1,4 @@ -import "./storage-classes.scss" +import "./storage-classes.scss"; import React from "react"; import { RouteComponentProps } from "react-router-dom"; @@ -55,6 +55,6 @@ export class StorageClasses extends React.Component { storageClass.getAge(), ]} /> - ) + ); } } diff --git a/src/renderer/components/+storage-volume-claims/index.ts b/src/renderer/components/+storage-volume-claims/index.ts index 3a8d9949b2..4f9055c1d7 100644 --- a/src/renderer/components/+storage-volume-claims/index.ts +++ b/src/renderer/components/+storage-volume-claims/index.ts @@ -1,4 +1,4 @@ -export * from "./volume-claims.route" -export * from "./volume-claims" -export * from "./volume-claim-details" +export * from "./volume-claims.route"; +export * from "./volume-claims"; +export * from "./volume-claim-details"; diff --git a/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx b/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx index c75251884d..5df839c979 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx +++ b/src/renderer/components/+storage-volume-claims/volume-claim-details.tsx @@ -1,4 +1,4 @@ -import "./volume-claim-details.scss" +import "./volume-claim-details.scss"; import React, { Fragment } from "react"; import { reaction } from "mobx"; @@ -99,7 +99,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "PersistentVolumeClaim", @@ -108,4 +108,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx b/src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx index 112ec5c268..3b727f36eb 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx +++ b/src/renderer/components/+storage-volume-claims/volume-claim-disk-chart.tsx @@ -38,7 +38,7 @@ export const VolumeClaimDiskChart = observer(() => { borderColor: chartCapacityColor, data: capacity.map(([x, y]) => ({ x, y })) } - ] + ]; return ( { - api = pvcApi + api = pvcApi; @observable metrics: IPvcMetrics = null; @action diff --git a/src/renderer/components/+storage-volume-claims/volume-claims.route.ts b/src/renderer/components/+storage-volume-claims/volume-claims.route.ts index b579623369..0e49681bc3 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claims.route.ts +++ b/src/renderer/components/+storage-volume-claims/volume-claims.route.ts @@ -3,9 +3,9 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const volumeClaimsRoute: RouteProps = { path: "/persistent-volume-claims" -} +}; export interface IVolumeClaimsRouteParams { } -export const volumeClaimsURL = buildURL(volumeClaimsRoute.path) +export const volumeClaimsURL = buildURL(volumeClaimsRoute.path); diff --git a/src/renderer/components/+storage-volume-claims/volume-claims.tsx b/src/renderer/components/+storage-volume-claims/volume-claims.tsx index e0e789a2e5..84e8b9dd92 100644 --- a/src/renderer/components/+storage-volume-claims/volume-claims.tsx +++ b/src/renderer/components/+storage-volume-claims/volume-claims.tsx @@ -1,4 +1,4 @@ -import "./volume-claims.scss" +import "./volume-claims.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -81,9 +81,9 @@ export class PersistentVolumeClaims extends React.Component { )), pvc.getAge(), { title: pvc.getStatus(), className: pvc.getStatus().toLowerCase() }, - ] + ]; }} /> - ) + ); } } diff --git a/src/renderer/components/+storage-volumes/index.ts b/src/renderer/components/+storage-volumes/index.ts index 743de7af98..895ab6444a 100644 --- a/src/renderer/components/+storage-volumes/index.ts +++ b/src/renderer/components/+storage-volumes/index.ts @@ -1,3 +1,3 @@ -export * from "./volumes.route" -export * from "./volumes" -export * from "./volume-details" +export * from "./volumes.route"; +export * from "./volumes"; +export * from "./volume-details"; diff --git a/src/renderer/components/+storage-volumes/volume-details.tsx b/src/renderer/components/+storage-volumes/volume-details.tsx index 0cbb6d3ddc..93ede8d04d 100644 --- a/src/renderer/components/+storage-volumes/volume-details.tsx +++ b/src/renderer/components/+storage-volumes/volume-details.tsx @@ -1,5 +1,5 @@ -import startCase from "lodash/startCase" -import "./volume-details.scss" +import startCase from "lodash/startCase"; +import "./volume-details.scss"; import React from "react"; import { Trans } from "@lingui/macro"; @@ -107,7 +107,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "PersistentVolume", @@ -116,4 +116,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+storage-volumes/volumes.route.ts b/src/renderer/components/+storage-volumes/volumes.route.ts index 42d4824c99..596f51f23e 100644 --- a/src/renderer/components/+storage-volumes/volumes.route.ts +++ b/src/renderer/components/+storage-volumes/volumes.route.ts @@ -3,7 +3,7 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const volumesRoute: RouteProps = { path: "/persistent-volumes" -} +}; export interface IVolumesRouteParams { } diff --git a/src/renderer/components/+storage-volumes/volumes.store.ts b/src/renderer/components/+storage-volumes/volumes.store.ts index f065c562c9..ea61525735 100644 --- a/src/renderer/components/+storage-volumes/volumes.store.ts +++ b/src/renderer/components/+storage-volumes/volumes.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class PersistentVolumesStore extends KubeObjectStore { - api = persistentVolumeApi + api = persistentVolumeApi; } export const volumesStore = new PersistentVolumesStore(); diff --git a/src/renderer/components/+storage-volumes/volumes.tsx b/src/renderer/components/+storage-volumes/volumes.tsx index c3b01e0b93..d67a9a9b09 100644 --- a/src/renderer/components/+storage-volumes/volumes.tsx +++ b/src/renderer/components/+storage-volumes/volumes.tsx @@ -1,4 +1,4 @@ -import "./volumes.scss" +import "./volumes.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -71,9 +71,9 @@ export class PersistentVolumes extends React.Component { ), volume.getAge(), { title: volume.getStatus(), className: volume.getStatus().toLowerCase() } - ] + ]; }} /> - ) + ); } } diff --git a/src/renderer/components/+storage/index.ts b/src/renderer/components/+storage/index.ts index eb218e9174..58bae55b33 100644 --- a/src/renderer/components/+storage/index.ts +++ b/src/renderer/components/+storage/index.ts @@ -1,2 +1,2 @@ -export * from "./storage.route" -export * from "./storage" +export * from "./storage.route"; +export * from "./storage"; diff --git a/src/renderer/components/+storage/storage.route.ts b/src/renderer/components/+storage/storage.route.ts index 6fe3bb6a0a..6ad17a4fdf 100644 --- a/src/renderer/components/+storage/storage.route.ts +++ b/src/renderer/components/+storage/storage.route.ts @@ -1,12 +1,12 @@ -import { RouteProps } from "react-router" +import { RouteProps } from "react-router"; import { volumeClaimsURL } from "../+storage-volume-claims"; import { Storage } from "./storage"; import { IURLParams } from "../../../common/utils/buildUrl"; export const storageRoute: RouteProps = { get path() { - return Storage.tabRoutes.map(({ routePath }) => routePath).flat() + return Storage.tabRoutes.map(({ routePath }) => routePath).flat(); } -} +}; export const storageURL = (params?: IURLParams) => volumeClaimsURL(params); diff --git a/src/renderer/components/+storage/storage.tsx b/src/renderer/components/+storage/storage.tsx index e8a105944b..97bd014760 100644 --- a/src/renderer/components/+storage/storage.tsx +++ b/src/renderer/components/+storage/storage.tsx @@ -1,4 +1,4 @@ -import "./storage.scss" +import "./storage.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -14,14 +14,14 @@ import { isAllowedResource } from "../../../common/rbac"; export class Storage extends React.Component { static get tabRoutes() { const tabRoutes: TabLayoutRoute[] = []; - const query = namespaceStore.getContextParams() + const query = namespaceStore.getContextParams(); tabRoutes.push({ title: Persistent Volume Claims, component: PersistentVolumeClaims, url: volumeClaimsURL({ query }), routePath: volumeClaimsRoute.path.toString(), - }) + }); if (isAllowedResource('persistentvolumes')) { tabRoutes.push({ @@ -38,7 +38,7 @@ export class Storage extends React.Component { component: StorageClasses, url: storageClassesURL(), routePath: storageClassesRoute.path.toString(), - }) + }); } return tabRoutes; } @@ -46,6 +46,6 @@ export class Storage extends React.Component { render() { return ( - ) + ); } } diff --git a/src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx b/src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx index 4225d7b96f..227b2d936e 100644 --- a/src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx +++ b/src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx @@ -1,4 +1,4 @@ -import "./add-role-binding-dialog.scss" +import "./add-role-binding-dialog.scss"; import React from "react"; import { computed, observable } from "mobx"; @@ -67,12 +67,12 @@ export class AddRoleBindingDialog extends React.Component { @computed get selectedBindings() { return [ ...this.selectedAccounts, - ] + ]; } close = () => { AddRoleBindingDialog.close(); - } + }; async loadData() { const stores = [ @@ -96,13 +96,13 @@ export class AddRoleBindingDialog extends React.Component { this.bindContext = role.getNs() || ""; } } - } + }; reset = () => { this.selectedRoleId = ""; this.bindContext = ""; this.selectedAccounts.clear(); - } + }; onBindContextChange = (namespace: string) => { this.bindContext = namespace; @@ -110,7 +110,7 @@ export class AddRoleBindingDialog extends React.Component { if (this.bindContext && this.bindContext !== roleContext) { this.selectedRoleId = ""; // reset previously selected role for specific context } - } + }; createBindings = async () => { const { selectedRole, bindContext: namespace, selectedBindings, bindingName, useRoleForBindingName } = this; @@ -121,7 +121,7 @@ export class AddRoleBindingDialog extends React.Component { name: item.getName(), kind: item.kind, namespace: item.getNs(), - } + }; } return item; }); @@ -152,7 +152,7 @@ export class AddRoleBindingDialog extends React.Component { }; @computed get roleOptions(): BindingSelectOption[] { - let roles = rolesStore.items as Role[] + let roles = rolesStore.items as Role[]; if (this.bindContext) { // show only cluster-roles or roles for selected context namespace roles = roles.filter(role => !role.getNs() || role.getNs() === this.bindContext); @@ -163,8 +163,8 @@ export class AddRoleBindingDialog extends React.Component { return { value: role.getId(), label: name + (namespace ? ` (${namespace})` : "") - } - }) + }; + }); } @computed get serviceAccountOptions(): BindingSelectOption[] { @@ -175,8 +175,8 @@ export class AddRoleBindingDialog extends React.Component { item: account, value: name, label: <> {name} ({namespace})> - } - }) + }; + }); } renderContents() { @@ -240,7 +240,7 @@ export class AddRoleBindingDialog extends React.Component { maxMenuHeight={200} /> > - ) + ); } render() { @@ -275,6 +275,6 @@ export class AddRoleBindingDialog extends React.Component { - ) + ); } } diff --git a/src/renderer/components/+user-management-roles-bindings/index.ts b/src/renderer/components/+user-management-roles-bindings/index.ts index ca90adf052..cb69a92323 100644 --- a/src/renderer/components/+user-management-roles-bindings/index.ts +++ b/src/renderer/components/+user-management-roles-bindings/index.ts @@ -1,3 +1,3 @@ -export * from "./role-bindings" -export * from "./role-binding-details" -export * from "./add-role-binding-dialog" +export * from "./role-bindings"; +export * from "./role-binding-details"; +export * from "./add-role-binding-dialog"; diff --git a/src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx b/src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx index afa1d1e43c..178aada344 100644 --- a/src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx +++ b/src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx @@ -1,4 +1,4 @@ -import "./role-binding-details.scss" +import "./role-binding-details.scss"; import React from "react"; import { t, Trans } from "@lingui/macro"; @@ -30,7 +30,7 @@ export class RoleBindingDetails extends React.Component { reaction(() => this.props.object, (obj) => { this.selectedSubjects.clear(); }) - ]) + ]); } selectSubject(subject: IRoleBindingSubject) { @@ -40,7 +40,7 @@ export class RoleBindingDetails extends React.Component { isSelected ? selectedSubjects.filter(sub => sub !== subject) // unselect : selectedSubjects.concat(subject) // select - ) + ); } @autobind() @@ -53,7 +53,7 @@ export class RoleBindingDetails extends React.Component { message: ( Remove selected bindings for {roleBinding.getName()}? ) - }) + }); } render() { @@ -106,7 +106,7 @@ export class RoleBindingDetails extends React.Component { {kind} {namespace || "-"} - ) + ); }) } @@ -119,7 +119,7 @@ export class RoleBindingDetails extends React.Component { removeTooltip={Remove selected bindings from ${name}} /> - ) + ); } } @@ -129,7 +129,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "RoleBinding", apiVersions: ["rbac.authorization.k8s.io/v1"], @@ -137,7 +137,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ @@ -146,7 +146,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "ClusterRoleBinding", apiVersions: ["rbac.authorization.k8s.io/v1"], @@ -154,4 +154,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+user-management-roles-bindings/role-bindings.store.ts b/src/renderer/components/+user-management-roles-bindings/role-bindings.store.ts index bbef0ebd31..ed3e1c0a4f 100644 --- a/src/renderer/components/+user-management-roles-bindings/role-bindings.store.ts +++ b/src/renderer/components/+user-management-roles-bindings/role-bindings.store.ts @@ -1,5 +1,5 @@ -import difference from "lodash/difference" -import uniqBy from "lodash/uniqBy" +import difference from "lodash/difference"; +import uniqBy from "lodash/uniqBy"; import { clusterRoleBindingApi, IRoleBindingSubject, RoleBinding, roleBindingApi } from "../../api/endpoints"; import { KubeObjectStore } from "../../kube-object.store"; import { autobind } from "../../utils"; @@ -7,40 +7,40 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class RoleBindingsStore extends KubeObjectStore { - api = clusterRoleBindingApi + api = clusterRoleBindingApi; subscribe() { - return super.subscribe([clusterRoleBindingApi, roleBindingApi]) + return super.subscribe([clusterRoleBindingApi, roleBindingApi]); } protected sortItems(items: RoleBinding[]) { return super.sortItems(items, [ roleBinding => roleBinding.kind, roleBinding => roleBinding.getName() - ]) + ]); } protected loadItem(params: { name: string; namespace?: string }) { - if (params.namespace) return roleBindingApi.get(params) - return clusterRoleBindingApi.get(params) + if (params.namespace) return roleBindingApi.get(params); + return clusterRoleBindingApi.get(params); } protected loadItems(namespaces?: string[]) { if (namespaces) { return Promise.all( namespaces.map(namespace => roleBindingApi.list({ namespace })) - ).then(items => items.flat()) + ).then(items => items.flat()); } else { return Promise.all([clusterRoleBindingApi.list(), roleBindingApi.list()]) - .then(items => items.flat()) + .then(items => items.flat()); } } protected async createItem(params: { name: string; namespace?: string }, data?: Partial) { if (params.namespace) { - return roleBindingApi.create(params, data) + return roleBindingApi.create(params, data); } else { - return clusterRoleBindingApi.create(params, data) + return clusterRoleBindingApi.create(params, data); } } @@ -55,7 +55,7 @@ export class RoleBindingsStore extends KubeObjectStore { if (addSubjects) { newSubjects = uniqBy(currentSubjects.concat(addSubjects), ({ kind, name, namespace }) => { return [kind, name, namespace].join("-"); - }) + }); } else if (removeSubjects) { newSubjects = difference(currentSubjects, removeSubjects); } diff --git a/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx b/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx index cb010a3c1b..7d9352e3bf 100644 --- a/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx +++ b/src/renderer/components/+user-management-roles-bindings/role-bindings.tsx @@ -1,4 +1,4 @@ -import "./role-bindings.scss" +import "./role-bindings.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -58,6 +58,6 @@ export class RoleBindings extends React.Component { addTooltip: Create new RoleBinding, }} /> - ) + ); } } diff --git a/src/renderer/components/+user-management-roles/add-role-dialog.tsx b/src/renderer/components/+user-management-roles/add-role-dialog.tsx index 177386f72d..56766c816d 100644 --- a/src/renderer/components/+user-management-roles/add-role-dialog.tsx +++ b/src/renderer/components/+user-management-roles/add-role-dialog.tsx @@ -1,4 +1,4 @@ -import "./add-role-dialog.scss" +import "./add-role-dialog.scss"; import React from "react"; import { observable } from "mobx"; @@ -31,11 +31,11 @@ export class AddRoleDialog extends React.Component { close = () => { AddRoleDialog.close(); - } + }; reset = () => { - this.roleName = "" - } + this.roleName = ""; + }; createRole = async () => { try { @@ -46,7 +46,7 @@ export class AddRoleDialog extends React.Component { } catch (err) { Notifications.error(err.toString()); } - } + }; render() { const { ...dialogProps } = this.props; @@ -74,6 +74,6 @@ export class AddRoleDialog extends React.Component { - ) + ); } } diff --git a/src/renderer/components/+user-management-roles/index.ts b/src/renderer/components/+user-management-roles/index.ts index dd5752f4be..26eaea3b7f 100644 --- a/src/renderer/components/+user-management-roles/index.ts +++ b/src/renderer/components/+user-management-roles/index.ts @@ -1,3 +1,3 @@ -export * from "./roles" -export * from "./role-details" -export * from "./add-role-dialog" +export * from "./roles"; +export * from "./role-details"; +export * from "./add-role-dialog"; diff --git a/src/renderer/components/+user-management-roles/role-details.tsx b/src/renderer/components/+user-management-roles/role-details.tsx index fccc79eb9d..e69e6c46d7 100644 --- a/src/renderer/components/+user-management-roles/role-details.tsx +++ b/src/renderer/components/+user-management-roles/role-details.tsx @@ -1,4 +1,4 @@ -import "./role-details.scss" +import "./role-details.scss"; import React from "react"; import { Trans } from "@lingui/macro"; @@ -57,10 +57,10 @@ export class RoleDetails extends React.Component { > )} - ) + ); })} - ) + ); } } @@ -70,7 +70,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "Role", apiVersions: ["rbac.authorization.k8s.io/v1"], @@ -78,7 +78,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "ClusterRole", @@ -86,7 +86,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "ClusterRole", apiVersions: ["rbac.authorization.k8s.io/v1"], @@ -94,4 +94,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+user-management-roles/roles.store.ts b/src/renderer/components/+user-management-roles/roles.store.ts index e41171ee0c..d3f17e520c 100644 --- a/src/renderer/components/+user-management-roles/roles.store.ts +++ b/src/renderer/components/+user-management-roles/roles.store.ts @@ -5,40 +5,40 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class RolesStore extends KubeObjectStore { - api = clusterRoleApi + api = clusterRoleApi; subscribe() { - return super.subscribe([roleApi, clusterRoleApi]) + return super.subscribe([roleApi, clusterRoleApi]); } protected sortItems(items: Role[]) { return super.sortItems(items, [ role => role.kind, role => role.getName(), - ]) + ]); } protected loadItem(params: { name: string; namespace?: string }) { - if (params.namespace) return roleApi.get(params) - return clusterRoleApi.get(params) + if (params.namespace) return roleApi.get(params); + return clusterRoleApi.get(params); } protected loadItems(namespaces?: string[]): Promise { if (namespaces) { return Promise.all( namespaces.map(namespace => roleApi.list({ namespace })) - ).then(items => items.flat()) + ).then(items => items.flat()); } else { return Promise.all([clusterRoleApi.list(), roleApi.list()]) - .then(items => items.flat()) + .then(items => items.flat()); } } protected async createItem(params: { name: string; namespace?: string }, data?: Partial) { if (params.namespace) { - return roleApi.create(params, data) + return roleApi.create(params, data); } else { - return clusterRoleApi.create(params, data) + return clusterRoleApi.create(params, data); } } } diff --git a/src/renderer/components/+user-management-roles/roles.tsx b/src/renderer/components/+user-management-roles/roles.tsx index ca78c1d5d7..015ec2d630 100644 --- a/src/renderer/components/+user-management-roles/roles.tsx +++ b/src/renderer/components/+user-management-roles/roles.tsx @@ -1,4 +1,4 @@ -import "./roles.scss" +import "./roles.scss"; import React from "react"; import { observer } from "mobx-react"; @@ -56,6 +56,6 @@ export class Roles extends React.Component { /> > - ) + ); } } diff --git a/src/renderer/components/+user-management-service-accounts/create-service-account-dialog.tsx b/src/renderer/components/+user-management-service-accounts/create-service-account-dialog.tsx index d84cc01e59..ce677c3353 100644 --- a/src/renderer/components/+user-management-service-accounts/create-service-account-dialog.tsx +++ b/src/renderer/components/+user-management-service-accounts/create-service-account-dialog.tsx @@ -22,8 +22,8 @@ interface Props extends Partial { export class CreateServiceAccountDialog extends React.Component { @observable static isOpen = false; - @observable name = "" - @observable namespace = "default" + @observable name = ""; + @observable namespace = "default"; static open() { CreateServiceAccountDialog.isOpen = true; @@ -35,7 +35,7 @@ export class CreateServiceAccountDialog extends React.Component { close = () => { CreateServiceAccountDialog.close(); - } + }; createAccount = async () => { const { name, namespace } = this; @@ -47,12 +47,12 @@ export class CreateServiceAccountDialog extends React.Component { } catch (err) { Notifications.error(err); } - } + }; render() { const { ...dialogProps } = this.props; const { name, namespace } = this; - const header = Create Service Account + const header = Create Service Account; return ( { - ) + ); } } \ No newline at end of file diff --git a/src/renderer/components/+user-management-service-accounts/index.ts b/src/renderer/components/+user-management-service-accounts/index.ts index fb40e7e15e..fd45e28288 100644 --- a/src/renderer/components/+user-management-service-accounts/index.ts +++ b/src/renderer/components/+user-management-service-accounts/index.ts @@ -1,3 +1,3 @@ -export * from "./service-accounts" -export * from "./service-accounts-details" -export * from "./create-service-account-dialog" \ No newline at end of file +export * from "./service-accounts"; +export * from "./service-accounts-details"; +export * from "./create-service-account-dialog"; \ No newline at end of file diff --git a/src/renderer/components/+user-management-service-accounts/service-accounts-details.tsx b/src/renderer/components/+user-management-service-accounts/service-accounts-details.tsx index 357baee9eb..d560cd9199 100644 --- a/src/renderer/components/+user-management-service-accounts/service-accounts-details.tsx +++ b/src/renderer/components/+user-management-service-accounts/service-accounts-details.tsx @@ -39,27 +39,27 @@ export class ServiceAccountsDetails extends React.Component { }); this.secrets = await Promise.all(secrets); const imagePullSecrets = serviceAccount.getImagePullSecrets().map(async({ name }) => { - return secretsStore.load({ name, namespace }).catch(_err => { return this.generateDummySecretObject(name) }); + return secretsStore.load({ name, namespace }).catch(_err => { return this.generateDummySecretObject(name); }); }); - this.imagePullSecrets = await Promise.all(imagePullSecrets) - }) + this.imagePullSecrets = await Promise.all(imagePullSecrets); + }); renderSecrets() { const { secrets } = this; if (!secrets) { - return + return ; } return secrets.map(secret => - ) + ); } renderImagePullSecrets() { const { imagePullSecrets } = this; if (!imagePullSecrets) { - return + return ; } - return this.renderSecretLinks(imagePullSecrets) + return this.renderSecretLinks(imagePullSecrets); } renderSecretLinks(secrets: Secret[]) { @@ -73,14 +73,14 @@ export class ServiceAccountsDetails extends React.Component { tooltip={Secret is not found} /> - ) + ); } return ( {secret.getName()} - ) - }) + ); + }); } generateDummySecretObject(name: string) { @@ -93,7 +93,7 @@ export class ServiceAccountsDetails extends React.Component { selfLink: null, resourceVersion: null } - }) + }); } render() { @@ -104,8 +104,8 @@ export class ServiceAccountsDetails extends React.Component { const tokens = secretsStore.items.filter(secret => secret.getNs() == serviceAccount.getNs() && secret.getAnnotations().some(annot => annot == `kubernetes.io/service-account.name: ${serviceAccount.getName()}`) - ) - const imagePullSecrets = serviceAccount.getImagePullSecrets() + ); + const imagePullSecrets = serviceAccount.getImagePullSecrets(); return ( @@ -126,7 +126,7 @@ export class ServiceAccountsDetails extends React.Component { {this.renderSecrets()} - ) + ); } } @@ -136,7 +136,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "ServiceAccount", apiVersions: ["v1"], @@ -144,4 +144,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+user-management-service-accounts/service-accounts-secret.tsx b/src/renderer/components/+user-management-service-accounts/service-accounts-secret.tsx index bc75d103f7..ad3eec3d2e 100644 --- a/src/renderer/components/+user-management-service-accounts/service-accounts-secret.tsx +++ b/src/renderer/components/+user-management-service-accounts/service-accounts-secret.tsx @@ -1,4 +1,4 @@ -import "./service-accounts-secret.scss" +import "./service-accounts-secret.scss"; import React from "react"; import moment from "moment"; @@ -18,11 +18,11 @@ interface State { export class ServiceAccountsSecret extends React.Component { public state: State = { showToken: false, - } + }; renderSecretValue() { - const { secret } = this.props - const { showToken } = this.state + const { secret } = this.props; + const { showToken } = this.state; return ( <> {!showToken && ( @@ -39,7 +39,7 @@ export class ServiceAccountsSecret extends React.Component { {secret.getToken()} )} > - ) + ); } render() { @@ -65,6 +65,6 @@ export class ServiceAccountsSecret extends React.Component { {type} - ) + ); } } \ No newline at end of file diff --git a/src/renderer/components/+user-management-service-accounts/service-accounts.store.ts b/src/renderer/components/+user-management-service-accounts/service-accounts.store.ts index ff958567ae..1d3faa6b1c 100644 --- a/src/renderer/components/+user-management-service-accounts/service-accounts.store.ts +++ b/src/renderer/components/+user-management-service-accounts/service-accounts.store.ts @@ -5,7 +5,7 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class ServiceAccountsStore extends KubeObjectStore { - api = serviceAccountsApi + api = serviceAccountsApi; protected async createItem(params: { name: string; namespace?: string }) { await super.createItem(params); diff --git a/src/renderer/components/+user-management-service-accounts/service-accounts.tsx b/src/renderer/components/+user-management-service-accounts/service-accounts.tsx index 0455a5cdc0..d612dd2376 100644 --- a/src/renderer/components/+user-management-service-accounts/service-accounts.tsx +++ b/src/renderer/components/+user-management-service-accounts/service-accounts.tsx @@ -54,7 +54,7 @@ export class ServiceAccounts extends React.Component { account.getAge(), ]} renderItemMenu={(item: ServiceAccount) => { - return + return ; }} addRemoveButtons={{ onAdd: () => CreateServiceAccountDialog.open(), @@ -63,7 +63,7 @@ export class ServiceAccounts extends React.Component { /> > - ) + ); } } @@ -74,7 +74,7 @@ function ServiceAccountMenu(props: KubeObjectMenuProps) { Kubeconfig - ) + ); } kubeObjectMenuRegistry.add({ @@ -83,4 +83,4 @@ kubeObjectMenuRegistry.add({ components: { MenuItem: ServiceAccountMenu } -}) +}); diff --git a/src/renderer/components/+user-management/index.ts b/src/renderer/components/+user-management/index.ts index 8250079e60..6f29869b9b 100644 --- a/src/renderer/components/+user-management/index.ts +++ b/src/renderer/components/+user-management/index.ts @@ -1,2 +1,2 @@ -export * from "./user-management" -export * from "./user-management.route" \ No newline at end of file +export * from "./user-management"; +export * from "./user-management.route"; \ No newline at end of file diff --git a/src/renderer/components/+user-management/user-management.route.ts b/src/renderer/components/+user-management/user-management.route.ts index aa520fb128..9dc17cbbd8 100644 --- a/src/renderer/components/+user-management/user-management.route.ts +++ b/src/renderer/components/+user-management/user-management.route.ts @@ -1,23 +1,23 @@ import type { RouteProps } from "react-router"; import { buildURL, IURLParams } from "../../../common/utils/buildUrl"; -import { UserManagement } from "./user-management" +import { UserManagement } from "./user-management"; export const usersManagementRoute: RouteProps = { get path() { - return UserManagement.tabRoutes.map(({ routePath }) => routePath).flat() + return UserManagement.tabRoutes.map(({ routePath }) => routePath).flat(); } -} +}; // Routes export const serviceAccountsRoute: RouteProps = { path: "/service-accounts" -} +}; export const rolesRoute: RouteProps = { path: "/roles" -} +}; export const roleBindingsRoute: RouteProps = { path: "/role-bindings" -} +}; // Route params export interface IServiceAccountsRouteParams { @@ -31,6 +31,6 @@ export interface IRolesRouteParams { // URL-builders export const usersManagementURL = (params?: IURLParams) => serviceAccountsURL(params); -export const serviceAccountsURL = buildURL(serviceAccountsRoute.path) -export const roleBindingsURL = buildURL(roleBindingsRoute.path) -export const rolesURL = buildURL(rolesRoute.path) +export const serviceAccountsURL = buildURL(serviceAccountsRoute.path); +export const roleBindingsURL = buildURL(roleBindingsRoute.path); +export const rolesURL = buildURL(rolesRoute.path); diff --git a/src/renderer/components/+user-management/user-management.tsx b/src/renderer/components/+user-management/user-management.tsx index e7985fae6a..9c03390656 100644 --- a/src/renderer/components/+user-management/user-management.tsx +++ b/src/renderer/components/+user-management/user-management.tsx @@ -1,4 +1,4 @@ -import "./user-management.scss" +import "./user-management.scss"; import React from "react"; import { observer } from "mobx-react"; import { Trans } from "@lingui/macro"; @@ -15,7 +15,7 @@ import { isAllowedResource } from "../../../common/rbac"; export class UserManagement extends React.Component { static get tabRoutes() { const tabRoutes: TabLayoutRoute[] = []; - const query = namespaceStore.getContextParams() + const query = namespaceStore.getContextParams(); tabRoutes.push( { title: Service Accounts, @@ -35,14 +35,14 @@ export class UserManagement extends React.Component { url: rolesURL({ query }), routePath: rolesRoute.path.toString(), }, - ) + ); if (isAllowedResource("podsecuritypolicies")) { tabRoutes.push({ title: Pod Security Policies, component: PodSecurityPolicies, url: podSecurityPoliciesURL(), routePath: podSecurityPoliciesRoute.path.toString(), - }) + }); } return tabRoutes; } @@ -50,6 +50,6 @@ export class UserManagement extends React.Component { render() { return ( - ) + ); } } diff --git a/src/renderer/components/+whats-new/index.tsx b/src/renderer/components/+whats-new/index.tsx index 9f46112328..ebfdf6ff1b 100644 --- a/src/renderer/components/+whats-new/index.tsx +++ b/src/renderer/components/+whats-new/index.tsx @@ -1,2 +1,2 @@ -export * from "./whats-new.route" -export * from "./whats-new" +export * from "./whats-new.route"; +export * from "./whats-new"; diff --git a/src/renderer/components/+whats-new/whats-new.route.ts b/src/renderer/components/+whats-new/whats-new.route.ts index f989d676b7..e73fd20fca 100644 --- a/src/renderer/components/+whats-new/whats-new.route.ts +++ b/src/renderer/components/+whats-new/whats-new.route.ts @@ -3,6 +3,6 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const whatsNewRoute: RouteProps = { path: "/what-s-new" -} +}; -export const whatsNewURL = buildURL(whatsNewRoute.path) +export const whatsNewURL = buildURL(whatsNewRoute.path); diff --git a/src/renderer/components/+whats-new/whats-new.tsx b/src/renderer/components/+whats-new/whats-new.tsx index c63e8f25d1..9b0df95d70 100644 --- a/src/renderer/components/+whats-new/whats-new.tsx +++ b/src/renderer/components/+whats-new/whats-new.tsx @@ -1,13 +1,13 @@ -import "./whats-new.scss" +import "./whats-new.scss"; import fs from "fs"; import path from "path"; import React from "react"; import { observer } from "mobx-react"; -import { userStore } from "../../../common/user-store" +import { userStore } from "../../../common/user-store"; import { navigate } from "../../navigation"; import { Button } from "../button"; import { Trans } from "@lingui/macro"; -import marked from "marked" +import marked from "marked"; @observer export class WhatsNew extends React.Component { @@ -16,7 +16,7 @@ export class WhatsNew extends React.Component { ok = () => { navigate("/"); userStore.saveLastSeenAppVersion(); - } + }; render() { const logo = require("../../components/icon/lens-logo.svg"); diff --git a/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx b/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx index b540b6e8a6..cd8e038d90 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjob-details.tsx @@ -30,7 +30,7 @@ export class CronJobDetails extends React.Component { render() { const { object: cronJob } = this.props; if (!cronJob) return null; - const childJobs = jobStore.getJobsByOwner(cronJob) + const childJobs = jobStore.getJobsByOwner(cronJob); return ( @@ -54,8 +54,8 @@ export class CronJobDetails extends React.Component { <> Jobs}/> {childJobs.map((job: Job) => { - const selectors = job.getSelectors() - const condition = job.getCondition() + const selectors = job.getSelectors(); + const condition = job.getCondition(); return ( @@ -77,12 +77,12 @@ export class CronJobDetails extends React.Component { } - )}) + );}) } > } - ) + ); } } @@ -92,7 +92,7 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); kubeObjectDetailRegistry.add({ kind: "CronJob", apiVersions: ["batch/v1"], @@ -100,4 +100,4 @@ kubeObjectDetailRegistry.add({ components: { Details: (props) => } -}) +}); diff --git a/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx b/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx index 8fa77bd194..5dda5989ae 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjob-trigger-dialog.tsx @@ -39,18 +39,18 @@ export class CronJobTriggerDialog extends Component { close = () => { CronJobTriggerDialog.close(); - } + }; onOpen = async () => { const { cronjob } = this; this.jobName = cronjob ? cronjob.getName() + "-manual-" + Math.random().toString(36).slice(2, 7) : ""; this.jobName = this.jobName.slice(0, 63); this.ready = true; - } + }; onClose = () => { this.ready = false; - } + }; trigger = async () => { const { cronjob } = this; @@ -72,7 +72,7 @@ export class CronJobTriggerDialog extends Component { } catch (err) { Notifications.error(err); } - } + }; renderContents() { return ( @@ -91,7 +91,7 @@ export class CronJobTriggerDialog extends Component { /> > - ) + ); } render() { diff --git a/src/renderer/components/+workloads-cronjobs/cronjob.store.ts b/src/renderer/components/+workloads-cronjobs/cronjob.store.ts index b1370d2104..30915f733c 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjob.store.ts +++ b/src/renderer/components/+workloads-cronjobs/cronjob.store.ts @@ -6,19 +6,19 @@ import { apiManager } from "../../api/api-manager"; @autobind() export class CronJobStore extends KubeObjectStore { - api = cronJobApi + api = cronJobApi; getStatuses(cronJobs?: CronJob[]) { - const status = { suspended: 0, scheduled: 0 } + const status = { suspended: 0, scheduled: 0 }; cronJobs.forEach(cronJob => { if (cronJob.spec.suspend) { - status.suspended++ + status.suspended++; } else { - status.scheduled++ + status.scheduled++; } - }) - return status + }); + return status; } getActiveJobsNum(cronJob: CronJob) { diff --git a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx index ab7609de81..b5cf6d328f 100644 --- a/src/renderer/components/+workloads-cronjobs/cronjobs.tsx +++ b/src/renderer/components/+workloads-cronjobs/cronjobs.tsx @@ -71,10 +71,10 @@ export class CronJobs extends React.Component { cronJob.getAge(), ]} renderItemMenu={(item: CronJob) => { - return + return ; }} /> - ) + ); } } @@ -85,7 +85,7 @@ export function CronJobMenu(props: KubeObjectMenuProps) { Trigger - ) + ); } kubeObjectMenuRegistry.add({ @@ -94,4 +94,4 @@ kubeObjectMenuRegistry.add({ components: { MenuItem: CronJobMenu } -}) +}); diff --git a/src/renderer/components/+workloads-cronjobs/index.ts b/src/renderer/components/+workloads-cronjobs/index.ts index 71c59dcfee..3884050448 100644 --- a/src/renderer/components/+workloads-cronjobs/index.ts +++ b/src/renderer/components/+workloads-cronjobs/index.ts @@ -1,2 +1,2 @@ -export * from "./cronjobs" -export * from "./cronjob-details" +export * from "./cronjobs"; +export * from "./cronjob-details"; diff --git a/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx b/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx index c234fc841c..9d678c8adf 100644 --- a/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx +++ b/src/renderer/components/+workloads-daemonsets/daemonset-details.tsx @@ -43,12 +43,12 @@ export class DaemonSetDetails extends React.Component { render() { const { object: daemonSet } = this.props; if (!daemonSet) return null; - const { spec } = daemonSet + const { spec } = daemonSet; const selectors = daemonSet.getSelectors(); - const images = daemonSet.getImages() - const nodeSelector = daemonSet.getNodeSelectors() - const childPods = daemonSetStore.getChildPods(daemonSet) - const metrics = daemonSetStore.metrics + const images = daemonSet.getImages(); + const nodeSelector = daemonSet.getNodeSelectors(); + const childPods = daemonSetStore.getChildPods(daemonSet); + const metrics = daemonSetStore.metrics; return ( {podsStore.isLoaded && ( @@ -92,7 +92,7 @@ export class DaemonSetDetails extends React.Component {
(pageId?: string, params?: P) { const { navigate } = await import("../renderer/navigation"); diff --git a/src/extensions/registries/__tests__/page-registry.test.ts b/src/extensions/registries/__tests__/page-registry.test.ts index 47a5f82d9d..29e60dccc0 100644 --- a/src/extensions/registries/__tests__/page-registry.test.ts +++ b/src/extensions/registries/__tests__/page-registry.test.ts @@ -1,8 +1,8 @@ -import { getExtensionPageUrl, globalPageRegistry, PageRegistration } from "../page-registry" -import { LensExtension } from "../../lens-extension" +import { getExtensionPageUrl, globalPageRegistry, PageRegistration } from "../page-registry"; +import { LensExtension } from "../../lens-extension"; import React from "react"; -let ext: LensExtension = null +let ext: LensExtension = null; describe("getPageUrl", () => { beforeEach(async () => { @@ -14,25 +14,25 @@ describe("getPageUrl", () => { manifestPath: "/this/is/fake/package.json", isBundled: false, isEnabled: true - }) - }) + }); + }); it("returns a page url for extension", () => { - expect(getExtensionPageUrl({ extensionId: ext.name })).toBe("/extension/foo-bar") - }) + expect(getExtensionPageUrl({ extensionId: ext.name })).toBe("/extension/foo-bar"); + }); it("allows to pass base url as parameter", () => { - expect(getExtensionPageUrl({ extensionId: ext.name, pageId: "/test" })).toBe("/extension/foo-bar/test") - }) + expect(getExtensionPageUrl({ extensionId: ext.name, pageId: "/test" })).toBe("/extension/foo-bar/test"); + }); it("removes @", () => { - expect(getExtensionPageUrl({ extensionId: "@foo/bar" })).toBe("/extension/foo-bar") - }) + expect(getExtensionPageUrl({ extensionId: "@foo/bar" })).toBe("/extension/foo-bar"); + }); it("adds / prefix", () => { - expect(getExtensionPageUrl({ extensionId: ext.name, pageId: "test" })).toBe("/extension/foo-bar/test") - }) -}) + expect(getExtensionPageUrl({ extensionId: ext.name, pageId: "test" })).toBe("/extension/foo-bar/test"); + }); +}); describe("globalPageRegistry", () => { beforeEach(async () => { @@ -44,7 +44,7 @@ describe("globalPageRegistry", () => { manifestPath: "/this/is/fake/package.json", isBundled: false, isEnabled: true - }) + }); globalPageRegistry.add([ { id: "test-page", @@ -63,12 +63,12 @@ describe("globalPageRegistry", () => { Page: () => React.createElement('Default') } }, - ], ext) - }) + ], ext); + }); describe("getByPageMenuTarget", () => { it("matching to first registered page without id", () => { - const page = globalPageRegistry.getByPageMenuTarget({ extensionId: ext.name }) + const page = globalPageRegistry.getByPageMenuTarget({ extensionId: ext.name }); expect(page.id).toEqual(undefined); expect(page.extensionId).toEqual(ext.name); expect(page.routePath).toEqual(getExtensionPageUrl({ extensionId: ext.name })); @@ -78,16 +78,16 @@ describe("globalPageRegistry", () => { const page = globalPageRegistry.getByPageMenuTarget({ pageId: "test-page", extensionId: ext.name - }) - expect(page.id).toEqual("test-page") - }) + }); + expect(page.id).toEqual("test-page"); + }); it("returns null if target not found", () => { const page = globalPageRegistry.getByPageMenuTarget({ pageId: "wrong-page", extensionId: ext.name - }) - expect(page).toBeNull() - }) - }) -}) + }); + expect(page).toBeNull(); + }); + }); +}); diff --git a/src/extensions/registries/app-preference-registry.ts b/src/extensions/registries/app-preference-registry.ts index 6c54911f82..338f93b5bc 100644 --- a/src/extensions/registries/app-preference-registry.ts +++ b/src/extensions/registries/app-preference-registry.ts @@ -1,4 +1,4 @@ -import type React from "react" +import type React from "react"; import { BaseRegistry } from "./base-registry"; export interface AppPreferenceComponents { @@ -14,4 +14,4 @@ export interface AppPreferenceRegistration { export class AppPreferenceRegistry extends BaseRegistry { } -export const appPreferenceRegistry = new AppPreferenceRegistry() +export const appPreferenceRegistry = new AppPreferenceRegistry(); diff --git a/src/extensions/registries/base-registry.ts b/src/extensions/registries/base-registry.ts index e82c9d11bf..73dbd373f0 100644 --- a/src/extensions/registries/base-registry.ts +++ b/src/extensions/registries/base-registry.ts @@ -12,7 +12,7 @@ export class BaseRegistry { add(items: T | T[], ext?: LensExtension): () => void; // allow method overloading with required "ext" @action add(items: T | T[]) { - const normalizedItems = (Array.isArray(items) ? items : [items]) + const normalizedItems = (Array.isArray(items) ? items : [items]); this.items.push(...normalizedItems); return () => this.remove(...normalizedItems); } @@ -21,6 +21,6 @@ export class BaseRegistry { remove(...items: T[]) { items.forEach(item => { this.items.remove(item); // works because of {deep: false}; - }) + }); } } diff --git a/src/extensions/registries/cluster-feature-registry.ts b/src/extensions/registries/cluster-feature-registry.ts index 0e3363d0f0..5017ad27a6 100644 --- a/src/extensions/registries/cluster-feature-registry.ts +++ b/src/extensions/registries/cluster-feature-registry.ts @@ -1,4 +1,4 @@ -import type React from "react" +import type React from "react"; import { BaseRegistry } from "./base-registry"; import { ClusterFeature } from "../cluster-feature"; @@ -15,4 +15,4 @@ export interface ClusterFeatureRegistration { export class ClusterFeatureRegistry extends BaseRegistry { } -export const clusterFeatureRegistry = new ClusterFeatureRegistry() +export const clusterFeatureRegistry = new ClusterFeatureRegistry(); diff --git a/src/extensions/registries/index.ts b/src/extensions/registries/index.ts index cdcfb7124b..8e343742ec 100644 --- a/src/extensions/registries/index.ts +++ b/src/extensions/registries/index.ts @@ -1,11 +1,11 @@ // All registries managed by extensions api -export * from "./page-registry" -export * from "./page-menu-registry" -export * from "./menu-registry" -export * from "./app-preference-registry" -export * from "./status-bar-registry" +export * from "./page-registry"; +export * from "./page-menu-registry"; +export * from "./menu-registry"; +export * from "./app-preference-registry"; +export * from "./status-bar-registry"; export * from "./kube-object-detail-registry"; export * from "./kube-object-menu-registry"; -export * from "./cluster-feature-registry" -export * from "./kube-object-status-registry" +export * from "./cluster-feature-registry"; +export * from "./kube-object-status-registry"; diff --git a/src/extensions/registries/kube-object-detail-registry.ts b/src/extensions/registries/kube-object-detail-registry.ts index 32fea66b81..2638e82ade 100644 --- a/src/extensions/registries/kube-object-detail-registry.ts +++ b/src/extensions/registries/kube-object-detail-registry.ts @@ -1,4 +1,4 @@ -import React from "react" +import React from "react"; import { BaseRegistry } from "./base-registry"; export interface KubeObjectDetailComponents { @@ -15,15 +15,15 @@ export interface KubeObjectDetailRegistration { export class KubeObjectDetailRegistry extends BaseRegistry { getItemsForKind(kind: string, apiVersion: string) { const items = this.getItems().filter((item) => { - return item.kind === kind && item.apiVersions.includes(apiVersion) + return item.kind === kind && item.apiVersions.includes(apiVersion); }).map((item) => { if (item.priority === null) { - item.priority = 50 + item.priority = 50; } - return item - }) - return items.sort((a, b) => b.priority - a.priority) + return item; + }); + return items.sort((a, b) => b.priority - a.priority); } } -export const kubeObjectDetailRegistry = new KubeObjectDetailRegistry() +export const kubeObjectDetailRegistry = new KubeObjectDetailRegistry(); diff --git a/src/extensions/registries/kube-object-menu-registry.ts b/src/extensions/registries/kube-object-menu-registry.ts index 8f527d6a3d..25901f66ad 100644 --- a/src/extensions/registries/kube-object-menu-registry.ts +++ b/src/extensions/registries/kube-object-menu-registry.ts @@ -1,4 +1,4 @@ -import React from "react" +import React from "react"; import { BaseRegistry } from "./base-registry"; export interface KubeObjectMenuComponents { @@ -14,9 +14,9 @@ export interface KubeObjectMenuRegistration { export class KubeObjectMenuRegistry extends BaseRegistry { getItemsForKind(kind: string, apiVersion: string) { return this.getItems().filter((item) => { - return item.kind === kind && item.apiVersions.includes(apiVersion) - }) + return item.kind === kind && item.apiVersions.includes(apiVersion); + }); } } -export const kubeObjectMenuRegistry = new KubeObjectMenuRegistry() +export const kubeObjectMenuRegistry = new KubeObjectMenuRegistry(); diff --git a/src/extensions/registries/kube-object-status-registry.ts b/src/extensions/registries/kube-object-status-registry.ts index 74fd8145d2..5f7aab8d5d 100644 --- a/src/extensions/registries/kube-object-status-registry.ts +++ b/src/extensions/registries/kube-object-status-registry.ts @@ -10,8 +10,8 @@ export interface KubeObjectStatusRegistration { export class KubeObjectStatusRegistry extends BaseRegistry { getItemsForKind(kind: string, apiVersion: string) { return this.getItems().filter((item) => { - return item.kind === kind && item.apiVersions.includes(apiVersion) - }) + return item.kind === kind && item.apiVersions.includes(apiVersion); + }); } } diff --git a/src/extensions/registries/page-menu-registry.ts b/src/extensions/registries/page-menu-registry.ts index ebaaa42dbb..15f11139e6 100644 --- a/src/extensions/registries/page-menu-registry.ts +++ b/src/extensions/registries/page-menu-registry.ts @@ -29,8 +29,8 @@ export class PageMenuRegistry extends BaseRegistry({ extensionId, pageId = "", params }: PageMenuTarget): string { @@ -68,13 +68,13 @@ export class PageRegistry extends BaseRegistry ...page, extensionId: ext.name, routePath: getExtensionPageUrl({ extensionId: ext.name, pageId: page.id ?? page.routePath }), - })) + })); } catch (err) { logger.error(`[EXTENSION]: page-registration failed`, { items, extension: ext, error: String(err), - }) + }); } return super.add(registeredPages); } diff --git a/src/extensions/renderer-api/components.ts b/src/extensions/renderer-api/components.ts index c051ce13e3..242799c749 100644 --- a/src/extensions/renderer-api/components.ts +++ b/src/extensions/renderer-api/components.ts @@ -1,36 +1,36 @@ // Common UI components // layouts -export * from "../../renderer/components/layout/page-layout" -export * from "../../renderer/components/layout/wizard-layout" -export * from "../../renderer/components/layout/tab-layout" +export * from "../../renderer/components/layout/page-layout"; +export * from "../../renderer/components/layout/wizard-layout"; +export * from "../../renderer/components/layout/tab-layout"; // form-controls -export * from "../../renderer/components/button" -export * from "../../renderer/components/checkbox" -export * from "../../renderer/components/radio" -export * from "../../renderer/components/select" -export * from "../../renderer/components/slider" -export * from "../../renderer/components/input/input" +export * from "../../renderer/components/button"; +export * from "../../renderer/components/checkbox"; +export * from "../../renderer/components/radio"; +export * from "../../renderer/components/select"; +export * from "../../renderer/components/slider"; +export * from "../../renderer/components/input/input"; // other components -export * from "../../renderer/components/icon" -export * from "../../renderer/components/tooltip" -export * from "../../renderer/components/tabs" -export * from "../../renderer/components/table" -export * from "../../renderer/components/badge" -export * from "../../renderer/components/drawer" -export * from "../../renderer/components/dialog" +export * from "../../renderer/components/icon"; +export * from "../../renderer/components/tooltip"; +export * from "../../renderer/components/tabs"; +export * from "../../renderer/components/table"; +export * from "../../renderer/components/badge"; +export * from "../../renderer/components/drawer"; +export * from "../../renderer/components/dialog"; export * from "../../renderer/components/confirm-dialog"; -export * from "../../renderer/components/line-progress" -export * from "../../renderer/components/menu" -export * from "../../renderer/components/notifications" -export * from "../../renderer/components/spinner" -export * from "../../renderer/components/stepper" +export * from "../../renderer/components/line-progress"; +export * from "../../renderer/components/menu"; +export * from "../../renderer/components/notifications"; +export * from "../../renderer/components/spinner"; +export * from "../../renderer/components/stepper"; // kube helpers -export * from "../../renderer/components/kube-object" -export * from "../../renderer/components/+events/kube-event-details" +export * from "../../renderer/components/kube-object"; +export * from "../../renderer/components/+events/kube-event-details"; // specific exports export * from "../../renderer/components/status-brick"; diff --git a/src/extensions/renderer-api/index.ts b/src/extensions/renderer-api/index.ts index 009f49c366..c8e14c0951 100644 --- a/src/extensions/renderer-api/index.ts +++ b/src/extensions/renderer-api/index.ts @@ -1,14 +1,14 @@ // Lens-extensions apis, required in renderer process runtime // APIs -import * as Component from "./components" -import * as K8sApi from "./k8s-api" -import * as Navigation from "./navigation" -import * as Theme from "./theming" +import * as Component from "./components"; +import * as K8sApi from "./k8s-api"; +import * as Navigation from "./navigation"; +import * as Theme from "./theming"; export { Component, K8sApi, Navigation, Theme, -} +}; diff --git a/src/extensions/renderer-api/k8s-api.ts b/src/extensions/renderer-api/k8s-api.ts index 2a26b49cdd..fe04550fb7 100644 --- a/src/extensions/renderer-api/k8s-api.ts +++ b/src/extensions/renderer-api/k8s-api.ts @@ -1,6 +1,6 @@ -export { isAllowedResource } from "../../common/rbac" +export { isAllowedResource } from "../../common/rbac"; export { apiManager } from "../../renderer/api/api-manager"; -export { KubeObjectStore } from "../../renderer/kube-object.store" +export { KubeObjectStore } from "../../renderer/kube-object.store"; export { KubeApi, forCluster, IKubeApiCluster } from "../../renderer/api/kube-api"; export { KubeObject } from "../../renderer/api/kube-object"; export { Pod, podsApi, PodsApi, IPodContainer, IPodContainerStatus } from "../../renderer/api/endpoints"; @@ -31,33 +31,33 @@ export { RoleBinding, roleBindingApi } from "../../renderer/api/endpoints"; export { ClusterRole, clusterRoleApi } from "../../renderer/api/endpoints"; export { ClusterRoleBinding, clusterRoleBindingApi } from "../../renderer/api/endpoints"; export { CustomResourceDefinition, crdApi } from "../../renderer/api/endpoints"; -export { KubeObjectStatus, KubeObjectStatusLevel } from "./kube-object-status" +export { KubeObjectStatus, KubeObjectStatusLevel } from "./kube-object-status"; // stores -export type { EventStore } from "../../renderer/components/+events/event.store" -export type { PodsStore } from "../../renderer/components/+workloads-pods/pods.store" -export type { NodesStore } from "../../renderer/components/+nodes/nodes.store" -export type { DeploymentStore } from "../../renderer/components/+workloads-deployments/deployments.store" -export type { DaemonSetStore } from "../../renderer/components/+workloads-daemonsets/daemonsets.store" -export type { StatefulSetStore } from "../../renderer/components/+workloads-statefulsets/statefulset.store" -export type { JobStore } from "../../renderer/components/+workloads-jobs/job.store" -export type { CronJobStore } from "../../renderer/components/+workloads-cronjobs/cronjob.store" -export type { ConfigMapsStore } from "../../renderer/components/+config-maps/config-maps.store" -export type { SecretsStore } from "../../renderer/components/+config-secrets/secrets.store" -export type { ReplicaSetStore } from "../../renderer/components/+workloads-replicasets/replicasets.store" -export type { ResourceQuotasStore } from "../../renderer/components/+config-resource-quotas/resource-quotas.store" -export type { HPAStore } from "../../renderer/components/+config-autoscalers/hpa.store" -export type { PodDisruptionBudgetsStore } from "../../renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store" -export type { ServiceStore } from "../../renderer/components/+network-services/services.store" -export type { EndpointStore } from "../../renderer/components/+network-endpoints/endpoints.store" -export type { IngressStore } from "../../renderer/components/+network-ingresses/ingress.store" -export type { NetworkPolicyStore } from "../../renderer/components/+network-policies/network-policy.store" -export type { PersistentVolumesStore } from "../../renderer/components/+storage-volumes/volumes.store" -export type { VolumeClaimStore } from "../../renderer/components/+storage-volume-claims/volume-claim.store" -export type { StorageClassStore } from "../../renderer/components/+storage-classes/storage-class.store" -export type { NamespaceStore } from "../../renderer/components/+namespaces/namespace.store" -export type { ServiceAccountsStore } from "../../renderer/components/+user-management-service-accounts/service-accounts.store" -export type { RolesStore } from "../../renderer/components/+user-management-roles/roles.store" -export type { RoleBindingsStore } from "../../renderer/components/+user-management-roles-bindings/role-bindings.store" -export type { CRDStore } from "../../renderer/components/+custom-resources/crd.store" -export type { CRDResourceStore } from "../../renderer/components/+custom-resources/crd-resource.store" +export type { EventStore } from "../../renderer/components/+events/event.store"; +export type { PodsStore } from "../../renderer/components/+workloads-pods/pods.store"; +export type { NodesStore } from "../../renderer/components/+nodes/nodes.store"; +export type { DeploymentStore } from "../../renderer/components/+workloads-deployments/deployments.store"; +export type { DaemonSetStore } from "../../renderer/components/+workloads-daemonsets/daemonsets.store"; +export type { StatefulSetStore } from "../../renderer/components/+workloads-statefulsets/statefulset.store"; +export type { JobStore } from "../../renderer/components/+workloads-jobs/job.store"; +export type { CronJobStore } from "../../renderer/components/+workloads-cronjobs/cronjob.store"; +export type { ConfigMapsStore } from "../../renderer/components/+config-maps/config-maps.store"; +export type { SecretsStore } from "../../renderer/components/+config-secrets/secrets.store"; +export type { ReplicaSetStore } from "../../renderer/components/+workloads-replicasets/replicasets.store"; +export type { ResourceQuotasStore } from "../../renderer/components/+config-resource-quotas/resource-quotas.store"; +export type { HPAStore } from "../../renderer/components/+config-autoscalers/hpa.store"; +export type { PodDisruptionBudgetsStore } from "../../renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store"; +export type { ServiceStore } from "../../renderer/components/+network-services/services.store"; +export type { EndpointStore } from "../../renderer/components/+network-endpoints/endpoints.store"; +export type { IngressStore } from "../../renderer/components/+network-ingresses/ingress.store"; +export type { NetworkPolicyStore } from "../../renderer/components/+network-policies/network-policy.store"; +export type { PersistentVolumesStore } from "../../renderer/components/+storage-volumes/volumes.store"; +export type { VolumeClaimStore } from "../../renderer/components/+storage-volume-claims/volume-claim.store"; +export type { StorageClassStore } from "../../renderer/components/+storage-classes/storage-class.store"; +export type { NamespaceStore } from "../../renderer/components/+namespaces/namespace.store"; +export type { ServiceAccountsStore } from "../../renderer/components/+user-management-service-accounts/service-accounts.store"; +export type { RolesStore } from "../../renderer/components/+user-management-roles/roles.store"; +export type { RoleBindingsStore } from "../../renderer/components/+user-management-roles-bindings/role-bindings.store"; +export type { CRDStore } from "../../renderer/components/+custom-resources/crd.store"; +export type { CRDResourceStore } from "../../renderer/components/+custom-resources/crd-resource.store"; diff --git a/src/extensions/renderer-api/kube-object-status.ts b/src/extensions/renderer-api/kube-object-status.ts index 22994ee85d..f609d736fe 100644 --- a/src/extensions/renderer-api/kube-object-status.ts +++ b/src/extensions/renderer-api/kube-object-status.ts @@ -2,7 +2,7 @@ export type KubeObjectStatus = { level: KubeObjectStatusLevel; text: string; timestamp?: string; -} +}; export enum KubeObjectStatusLevel { INFO = 1, diff --git a/src/extensions/renderer-api/navigation.ts b/src/extensions/renderer-api/navigation.ts index f923f6e152..a1191a4b30 100644 --- a/src/extensions/renderer-api/navigation.ts +++ b/src/extensions/renderer-api/navigation.ts @@ -1,3 +1,3 @@ export { navigate } from "../../renderer/navigation"; -export { hideDetails, showDetails, getDetailsUrl } from "../../renderer/navigation" +export { hideDetails, showDetails, getDetailsUrl } from "../../renderer/navigation"; export { IURLParams } from "../../common/utils/buildUrl"; diff --git a/src/jest.setup.ts b/src/jest.setup.ts index 08727bc910..7b4732930e 100644 --- a/src/jest.setup.ts +++ b/src/jest.setup.ts @@ -1,4 +1,4 @@ -import fetchMock from "jest-fetch-mock" +import fetchMock from "jest-fetch-mock"; // rewire global.fetch to call 'fetchMock' fetchMock.enableMocks(); diff --git a/src/main/__test__/cluster.test.ts b/src/main/__test__/cluster.test.ts index 1fb92ed4bc..95177408af 100644 --- a/src/main/__test__/cluster.test.ts +++ b/src/main/__test__/cluster.test.ts @@ -21,35 +21,35 @@ jest.mock("winston", () => ({ Console: jest.fn(), File: jest.fn(), } -})) +})); -jest.mock("../../common/ipc") -jest.mock("../context-handler") -jest.mock("request") -jest.mock("request-promise-native") +jest.mock("../../common/ipc"); +jest.mock("../context-handler"); +jest.mock("request"); +jest.mock("request-promise-native"); import { Console } from "console"; import mockFs from "mock-fs"; import { workspaceStore } from "../../common/workspace-store"; -import { Cluster } from "../cluster" +import { Cluster } from "../cluster"; import { ContextHandler } from "../context-handler"; import { getFreePort } from "../port"; import { V1ResourceAttributes } from "@kubernetes/client-node"; import { apiResources } from "../../common/rbac"; -import request from "request-promise-native" +import request from "request-promise-native"; import { Kubectl } from "../kubectl"; -const mockedRequest = request as jest.MockedFunction +const mockedRequest = request as jest.MockedFunction; -console = new Console(process.stdout, process.stderr) // fix mockFS +console = new Console(process.stdout, process.stderr); // fix mockFS describe("create clusters", () => { beforeEach(() => { - jest.clearAllMocks() - }) + jest.clearAllMocks(); + }); - let c: Cluster + let c: Cluster; beforeEach(() => { const mockOpts = { @@ -74,68 +74,68 @@ describe("create clusters", () => { kind: "Config", preferences: {}, }) - } - mockFs(mockOpts) - jest.spyOn(Kubectl.prototype, "ensureKubectl").mockReturnValue(Promise.resolve(true)) + }; + mockFs(mockOpts); + jest.spyOn(Kubectl.prototype, "ensureKubectl").mockReturnValue(Promise.resolve(true)); c = new Cluster({ id: "foo", contextName: "minikube", kubeConfigPath: "minikube-config.yml", workspace: workspaceStore.currentWorkspaceId - }) - }) + }); + }); afterEach(() => { - mockFs.restore() - }) + mockFs.restore(); + }); it("should be able to create a cluster from a cluster model and apiURL should be decoded", () => { - expect(c.apiUrl).toBe("https://192.168.64.3:8443") - }) + expect(c.apiUrl).toBe("https://192.168.64.3:8443"); + }); it("reconnect should not throw if contextHandler is missing", () => { - expect(() => c.reconnect()).not.toThrowError() - }) + expect(() => c.reconnect()).not.toThrowError(); + }); it("disconnect should not throw if contextHandler is missing", () => { - expect(() => c.disconnect()).not.toThrowError() - }) + expect(() => c.disconnect()).not.toThrowError(); + }); it("init should not throw if everything is in order", async () => { - await c.init(await getFreePort()) + await c.init(await getFreePort()); expect(logger.info).toBeCalledWith(expect.stringContaining("init success"), { id: "foo", apiUrl: "https://192.168.64.3:8443", context: "minikube", - }) - }) + }); + }); it("activating cluster should try to connect to cluster and do a refresh", async () => { - const port = await getFreePort() + const port = await getFreePort(); jest.spyOn(ContextHandler.prototype, "ensureServer"); - const mockListNSs = jest.fn() + const mockListNSs = jest.fn(); const mockKC = { makeApiClient() { return { listNamespace: mockListNSs, - } + }; } - } - jest.spyOn(Cluster.prototype, "isClusterAdmin").mockReturnValue(Promise.resolve(true)) + }; + jest.spyOn(Cluster.prototype, "isClusterAdmin").mockReturnValue(Promise.resolve(true)); jest.spyOn(Cluster.prototype, "canI") .mockImplementationOnce((attr: V1ResourceAttributes): Promise => { - expect(attr.namespace).toBe("default") - expect(attr.resource).toBe("pods") - expect(attr.verb).toBe("list") - return Promise.resolve(true) + expect(attr.namespace).toBe("default"); + expect(attr.resource).toBe("pods"); + expect(attr.verb).toBe("list"); + return Promise.resolve(true); }) .mockImplementation((attr: V1ResourceAttributes): Promise => { - expect(attr.namespace).toBe("default") - expect(attr.verb).toBe("list") - return Promise.resolve(true) - }) - jest.spyOn(Cluster.prototype, "getProxyKubeconfig").mockReturnValue(mockKC as any) + expect(attr.namespace).toBe("default"); + expect(attr.verb).toBe("list"); + return Promise.resolve(true); + }); + jest.spyOn(Cluster.prototype, "getProxyKubeconfig").mockReturnValue(mockKC as any); mockListNSs.mockImplementationOnce(() => ({ body: { items: [{ @@ -144,36 +144,36 @@ describe("create clusters", () => { } }] } - })) + })); mockedRequest.mockImplementationOnce(((uri: any, _options: any) => { - expect(uri).toBe(`http://localhost:${port}/api-kube/version`) - return Promise.resolve({ gitVersion: "1.2.3" }) - }) as any) + expect(uri).toBe(`http://localhost:${port}/api-kube/version`); + return Promise.resolve({ gitVersion: "1.2.3" }); + }) as any); const c = new class extends Cluster { // only way to mock protected methods, without these we leak promises protected bindEvents() { - return + return; } protected async ensureKubectl() { - return Promise.resolve(true) + return Promise.resolve(true); } }({ id: "foo", contextName: "minikube", kubeConfigPath: "minikube-config.yml", workspace: workspaceStore.currentWorkspaceId - }) - await c.init(port) - await c.activate() + }); + await c.init(port); + await c.activate(); - expect(ContextHandler.prototype.ensureServer).toBeCalled() - expect(mockedRequest).toBeCalled() - expect(c.accessible).toBe(true) - expect(c.allowedNamespaces.length).toBe(1) - expect(c.allowedResources.length).toBe(apiResources.length) - c.disconnect() - jest.resetAllMocks() - }) -}) + expect(ContextHandler.prototype.ensureServer).toBeCalled(); + expect(mockedRequest).toBeCalled(); + expect(c.accessible).toBe(true); + expect(c.allowedNamespaces.length).toBe(1); + expect(c.allowedResources.length).toBe(apiResources.length); + c.disconnect(); + jest.resetAllMocks(); + }); +}); diff --git a/src/main/__test__/kube-auth-proxy.test.ts b/src/main/__test__/kube-auth-proxy.test.ts index 8ef1f058e7..dbb3e308e3 100644 --- a/src/main/__test__/kube-auth-proxy.test.ts +++ b/src/main/__test__/kube-auth-proxy.test.ts @@ -21,109 +21,109 @@ jest.mock("winston", () => ({ Console: jest.fn(), File: jest.fn(), } -})) +})); -jest.mock("../../common/ipc") -jest.mock("child_process") -jest.mock("tcp-port-used") +jest.mock("../../common/ipc"); +jest.mock("child_process"); +jest.mock("tcp-port-used"); -import { Cluster } from "../cluster" -import { KubeAuthProxy } from "../kube-auth-proxy" -import { getFreePort } from "../port" -import { broadcastMessage } from "../../common/ipc" -import { ChildProcess, spawn, SpawnOptions } from "child_process" -import { bundledKubectlPath, Kubectl } from "../kubectl" +import { Cluster } from "../cluster"; +import { KubeAuthProxy } from "../kube-auth-proxy"; +import { getFreePort } from "../port"; +import { broadcastMessage } from "../../common/ipc"; +import { ChildProcess, spawn, SpawnOptions } from "child_process"; +import { bundledKubectlPath, Kubectl } from "../kubectl"; import { mock, MockProxy } from 'jest-mock-extended'; import { waitUntilUsed } from 'tcp-port-used'; -import { Readable } from "stream" +import { Readable } from "stream"; -const mockBroadcastIpc = broadcastMessage as jest.MockedFunction -const mockSpawn = spawn as jest.MockedFunction -const mockWaitUntilUsed = waitUntilUsed as jest.MockedFunction +const mockBroadcastIpc = broadcastMessage as jest.MockedFunction; +const mockSpawn = spawn as jest.MockedFunction; +const mockWaitUntilUsed = waitUntilUsed as jest.MockedFunction; describe("kube auth proxy tests", () => { beforeEach(() => { - jest.clearAllMocks() - }) + jest.clearAllMocks(); + }); it("calling exit multiple times shouldn't throw", async () => { - const port = await getFreePort() - const kap = new KubeAuthProxy(new Cluster({ id: "foobar", kubeConfigPath: "fake-path.yml" }), port, {}) - kap.exit() - kap.exit() - kap.exit() - }) + const port = await getFreePort(); + const kap = new KubeAuthProxy(new Cluster({ id: "foobar", kubeConfigPath: "fake-path.yml" }), port, {}); + kap.exit(); + kap.exit(); + kap.exit(); + }); describe("spawn tests", () => { - let port: number - let mockedCP: MockProxy - let listeners: Record void> - let proxy: KubeAuthProxy + let port: number; + let mockedCP: MockProxy; + let listeners: Record void>; + let proxy: KubeAuthProxy; beforeEach(async () => { - port = await getFreePort() - mockedCP = mock() - listeners = {} + port = await getFreePort(); + mockedCP = mock(); + listeners = {}; - jest.spyOn(Kubectl.prototype, "checkBinary").mockReturnValueOnce(Promise.resolve(true)) - jest.spyOn(Kubectl.prototype, "ensureKubectl").mockReturnValueOnce(Promise.resolve(false)) + jest.spyOn(Kubectl.prototype, "checkBinary").mockReturnValueOnce(Promise.resolve(true)); + jest.spyOn(Kubectl.prototype, "ensureKubectl").mockReturnValueOnce(Promise.resolve(false)); mockedCP.on.mockImplementation((event: string, listener: (message: any, sendHandle: any) => void): ChildProcess => { - listeners[event] = listener - return mockedCP - }) - mockedCP.stderr = mock() + listeners[event] = listener; + return mockedCP; + }); + mockedCP.stderr = mock(); mockedCP.stderr.on.mockImplementation((event: string, listener: (message: any, sendHandle: any) => void): Readable => { - listeners[`stderr/${event}`] = listener - return mockedCP.stderr - }) - mockedCP.stdout = mock() + listeners[`stderr/${event}`] = listener; + return mockedCP.stderr; + }); + mockedCP.stdout = mock(); mockedCP.stdout.on.mockImplementation((event: string, listener: (message: any, sendHandle: any) => void): Readable => { - listeners[`stdout/${event}`] = listener - return mockedCP.stdout - }) + listeners[`stdout/${event}`] = listener; + return mockedCP.stdout; + }); mockSpawn.mockImplementationOnce((command: string, args: readonly string[], options: SpawnOptions): ChildProcess => { - expect(command).toBe(bundledKubectlPath()) - return mockedCP - }) - mockWaitUntilUsed.mockReturnValueOnce(Promise.resolve()) - const cluster = new Cluster({ id: "foobar", kubeConfigPath: "fake-path.yml" }) - jest.spyOn(cluster, "apiUrl", "get").mockReturnValue("https://fake.k8s.internal") - proxy = new KubeAuthProxy(cluster, port, {}) - }) + expect(command).toBe(bundledKubectlPath()); + return mockedCP; + }); + mockWaitUntilUsed.mockReturnValueOnce(Promise.resolve()); + const cluster = new Cluster({ id: "foobar", kubeConfigPath: "fake-path.yml" }); + jest.spyOn(cluster, "apiUrl", "get").mockReturnValue("https://fake.k8s.internal"); + proxy = new KubeAuthProxy(cluster, port, {}); + }); it("should call spawn and broadcast errors", async () => { - await proxy.run() - listeners["error"]({ message: "foobarbat" }) + await proxy.run(); + listeners["error"]({ message: "foobarbat" }); - expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "foobarbat", error: true }) - }) + expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "foobarbat", error: true }); + }); it("should call spawn and broadcast exit", async () => { - await proxy.run() - listeners["exit"](0) + await proxy.run(); + listeners["exit"](0); - expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "proxy exited with code: 0", error: false }) - }) + expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "proxy exited with code: 0", error: false }); + }); it("should call spawn and broadcast errors from stderr", async () => { - await proxy.run() - listeners["stderr/data"]("an error") + await proxy.run(); + listeners["stderr/data"]("an error"); - expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "an error", error: true }) - }) + expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "an error", error: true }); + }); it("should call spawn and broadcast stdout serving info", async () => { - await proxy.run() - listeners["stdout/data"]("Starting to serve on") + await proxy.run(); + listeners["stdout/data"]("Starting to serve on"); - expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "Authentication proxy started\n" }) - }) + expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "Authentication proxy started\n" }); + }); it("should call spawn and broadcast stdout other info", async () => { - await proxy.run() - listeners["stdout/data"]("some info") + await proxy.run(); + listeners["stdout/data"]("some info"); - expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "some info" }) - }) - }) -}) + expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "some info" }); + }); + }); +}); diff --git a/src/main/__test__/kubeconfig-manager.test.ts b/src/main/__test__/kubeconfig-manager.test.ts index a0a4060111..152a13055d 100644 --- a/src/main/__test__/kubeconfig-manager.test.ts +++ b/src/main/__test__/kubeconfig-manager.test.ts @@ -21,24 +21,24 @@ jest.mock("winston", () => ({ Console: jest.fn(), File: jest.fn(), } -})) +})); -import { KubeconfigManager } from "../kubeconfig-manager" -import mockFs from "mock-fs" +import { KubeconfigManager } from "../kubeconfig-manager"; +import mockFs from "mock-fs"; import { Cluster } from "../cluster"; import { workspaceStore } from "../../common/workspace-store"; import { ContextHandler } from "../context-handler"; import { getFreePort } from "../port"; -import fse from "fs-extra" +import fse from "fs-extra"; import { loadYaml } from "@kubernetes/client-node"; import { Console } from "console"; -console = new Console(process.stdout, process.stderr) // fix mockFS +console = new Console(process.stdout, process.stderr); // fix mockFS describe("kubeconfig manager tests", () => { beforeEach(() => { - jest.clearAllMocks() - }) + jest.clearAllMocks(); + }); beforeEach(() => { const mockOpts = { @@ -63,13 +63,13 @@ describe("kubeconfig manager tests", () => { kind: "Config", preferences: {}, }) - } - mockFs(mockOpts) - }) + }; + mockFs(mockOpts); + }); afterEach(() => { - mockFs.restore() - }) + mockFs.restore(); + }); it("should create 'temp' kube config with proxy", async () => { const cluster = new Cluster({ @@ -77,19 +77,19 @@ describe("kubeconfig manager tests", () => { contextName: "minikube", kubeConfigPath: "minikube-config.yml", workspace: workspaceStore.currentWorkspaceId - }) - const contextHandler = new ContextHandler(cluster) - const port = await getFreePort() - const kubeConfManager = await KubeconfigManager.create(cluster, contextHandler, port) + }); + const contextHandler = new ContextHandler(cluster); + const port = await getFreePort(); + const kubeConfManager = await KubeconfigManager.create(cluster, contextHandler, port); - expect(logger.error).not.toBeCalled() - expect(kubeConfManager.getPath()).toBe("tmp/kubeconfig-foo") - const file = await fse.readFile(kubeConfManager.getPath()) - const yml = loadYaml(file.toString()) - expect(yml["current-context"]).toBe("minikube") - expect(yml["clusters"][0]["cluster"]["server"]).toBe(`http://127.0.0.1:${port}/foo`) - expect(yml["users"][0]["name"]).toBe("proxy") - }) + expect(logger.error).not.toBeCalled(); + expect(kubeConfManager.getPath()).toBe("tmp/kubeconfig-foo"); + const file = await fse.readFile(kubeConfManager.getPath()); + const yml = loadYaml(file.toString()); + expect(yml["current-context"]).toBe("minikube"); + expect(yml["clusters"][0]["cluster"]["server"]).toBe(`http://127.0.0.1:${port}/foo`); + expect(yml["users"][0]["name"]).toBe("proxy"); + }); it("should remove 'temp' kube config on unlink and remove reference from inside class", async () => { const cluster = new Cluster({ @@ -97,16 +97,16 @@ describe("kubeconfig manager tests", () => { contextName: "minikube", kubeConfigPath: "minikube-config.yml", workspace: workspaceStore.currentWorkspaceId - }) - const contextHandler = new ContextHandler(cluster) - const port = await getFreePort() - const kubeConfManager = await KubeconfigManager.create(cluster, contextHandler, port) + }); + const contextHandler = new ContextHandler(cluster); + const port = await getFreePort(); + const kubeConfManager = await KubeconfigManager.create(cluster, contextHandler, port); - const configPath = kubeConfManager.getPath() - expect(await fse.pathExists(configPath)).toBe(true) - await kubeConfManager.unlink() - expect(await fse.pathExists(configPath)).toBe(false) - await kubeConfManager.unlink() // doesn't throw - expect(kubeConfManager.getPath()).toBeUndefined() - }) -}) + const configPath = kubeConfManager.getPath(); + expect(await fse.pathExists(configPath)).toBe(true); + await kubeConfManager.unlink(); + expect(await fse.pathExists(configPath)).toBe(false); + await kubeConfManager.unlink(); // doesn't throw + expect(kubeConfManager.getPath()).toBeUndefined(); + }); +}); diff --git a/src/main/app-updater.ts b/src/main/app-updater.ts index 3613c3ef18..c7b6659149 100644 --- a/src/main/app-updater.ts +++ b/src/main/app-updater.ts @@ -1,19 +1,19 @@ -import { autoUpdater } from "electron-updater" -import logger from "./logger" +import { autoUpdater } from "electron-updater"; +import logger from "./logger"; export class AppUpdater { - static readonly defaultUpdateIntervalMs = 1000 * 60 * 60 * 24 // once a day + static readonly defaultUpdateIntervalMs = 1000 * 60 * 60 * 24; // once a day static checkForUpdates() { - return autoUpdater.checkForUpdatesAndNotify() + return autoUpdater.checkForUpdatesAndNotify(); } constructor(protected updateInterval = AppUpdater.defaultUpdateIntervalMs) { - autoUpdater.logger = logger + autoUpdater.logger = logger; } public start() { - setInterval(AppUpdater.checkForUpdates, this.updateInterval) + setInterval(AppUpdater.checkForUpdates, this.updateInterval); return AppUpdater.checkForUpdates(); } } diff --git a/src/main/cluster-detectors/base-cluster-detector.ts b/src/main/cluster-detectors/base-cluster-detector.ts index 8663313005..f73cc2ac81 100644 --- a/src/main/cluster-detectors/base-cluster-detector.ts +++ b/src/main/cluster-detectors/base-cluster-detector.ts @@ -1,21 +1,21 @@ -import request, { RequestPromiseOptions } from "request-promise-native" +import request, { RequestPromiseOptions } from "request-promise-native"; import { Cluster } from "../cluster"; export type ClusterDetectionResult = { value: string | number | boolean accuracy: number -} +}; export class BaseClusterDetector { - cluster: Cluster - key: string + cluster: Cluster; + key: string; constructor(cluster: Cluster) { - this.cluster = cluster + this.cluster = cluster; } detect(): Promise { - return null + return null; } protected async k8sRequest(path: string, options: RequestPromiseOptions = {}): Promise { @@ -28,6 +28,6 @@ export class BaseClusterDetector { Host: `${this.cluster.id}.${new URL(this.cluster.kubeProxyUrl).host}`, // required in ClusterManager.getClusterForRequest() ...(options.headers || {}), }, - }) + }); } } \ No newline at end of file diff --git a/src/main/cluster-detectors/cluster-id-detector.ts b/src/main/cluster-detectors/cluster-id-detector.ts index 558e52d43c..8419ae9db4 100644 --- a/src/main/cluster-detectors/cluster-id-detector.ts +++ b/src/main/cluster-detectors/cluster-id-detector.ts @@ -1,23 +1,23 @@ import { BaseClusterDetector } from "./base-cluster-detector"; -import { createHash } from "crypto" +import { createHash } from "crypto"; import { ClusterMetadataKey } from "../cluster"; export class ClusterIdDetector extends BaseClusterDetector { - key = ClusterMetadataKey.CLUSTER_ID + key = ClusterMetadataKey.CLUSTER_ID; public async detect() { - let id: string + let id: string; try { - id = await this.getDefaultNamespaceId() + id = await this.getDefaultNamespaceId(); } catch(_) { - id = this.cluster.apiUrl + id = this.cluster.apiUrl; } - const value = createHash("sha256").update(id).digest("hex") - return { value: value, accuracy: 100 } + const value = createHash("sha256").update(id).digest("hex"); + return { value: value, accuracy: 100 }; } protected async getDefaultNamespaceId() { - const response = await this.k8sRequest("/api/v1/namespaces/default") - return response.metadata.uid + const response = await this.k8sRequest("/api/v1/namespaces/default"); + return response.metadata.uid; } } \ No newline at end of file diff --git a/src/main/cluster-detectors/detector-registry.ts b/src/main/cluster-detectors/detector-registry.ts index 577fdf2d85..d4abe01304 100644 --- a/src/main/cluster-detectors/detector-registry.ts +++ b/src/main/cluster-detectors/detector-registry.ts @@ -12,34 +12,34 @@ export class DetectorRegistry { registry = observable.array([], { deep: false }); add(detectorClass: typeof BaseClusterDetector) { - this.registry.push(detectorClass) + this.registry.push(detectorClass); } async detectForCluster(cluster: Cluster): Promise { - const results: {[key: string]: ClusterDetectionResult } = {} + const results: {[key: string]: ClusterDetectionResult } = {}; for (const detectorClass of this.registry) { - const detector = new detectorClass(cluster) + const detector = new detectorClass(cluster); try { - const data = await detector.detect() + const data = await detector.detect(); if (!data) continue; - const existingValue = results[detector.key] + const existingValue = results[detector.key]; if (existingValue && existingValue.accuracy > data.accuracy) continue; // previous value exists and is more accurate - results[detector.key] = data + results[detector.key] = data; } catch (e) { // detector raised error, do nothing } } - const metadata: ClusterMetadata = {} + const metadata: ClusterMetadata = {}; for (const [key, result] of Object.entries(results)) { - metadata[key] = result.value + metadata[key] = result.value; } - return metadata + return metadata; } } -export const detectorRegistry = new DetectorRegistry() -detectorRegistry.add(ClusterIdDetector) -detectorRegistry.add(LastSeenDetector) -detectorRegistry.add(VersionDetector) -detectorRegistry.add(DistributionDetector) -detectorRegistry.add(NodesCountDetector) \ No newline at end of file +export const detectorRegistry = new DetectorRegistry(); +detectorRegistry.add(ClusterIdDetector); +detectorRegistry.add(LastSeenDetector); +detectorRegistry.add(VersionDetector); +detectorRegistry.add(DistributionDetector); +detectorRegistry.add(NodesCountDetector); \ No newline at end of file diff --git a/src/main/cluster-detectors/distribution-detector.ts b/src/main/cluster-detectors/distribution-detector.ts index b5895f8a71..181425cb26 100644 --- a/src/main/cluster-detectors/distribution-detector.ts +++ b/src/main/cluster-detectors/distribution-detector.ts @@ -2,79 +2,79 @@ import { BaseClusterDetector } from "./base-cluster-detector"; import { ClusterMetadataKey } from "../cluster"; export class DistributionDetector extends BaseClusterDetector { - key = ClusterMetadataKey.DISTRIBUTION - version: string + key = ClusterMetadataKey.DISTRIBUTION; + version: string; public async detect() { - this.version = await this.getKubernetesVersion() + this.version = await this.getKubernetesVersion(); if (await this.isRancher()) { - return { value: "rancher", accuracy: 80} + return { value: "rancher", accuracy: 80}; } if (this.isGKE()) { - return { value: "gke", accuracy: 80} + return { value: "gke", accuracy: 80}; } if (this.isEKS()) { - return { value: "eks", accuracy: 80} + return { value: "eks", accuracy: 80}; } if (this.isIKS()) { - return { value: "iks", accuracy: 80} + return { value: "iks", accuracy: 80}; } if (this.isAKS()) { - return { value: "aks", accuracy: 80} + return { value: "aks", accuracy: 80}; } if (this.isDigitalOcean()) { - return { value: "digitalocean", accuracy: 90} + return { value: "digitalocean", accuracy: 90}; } if (this.isMinikube()) { - return { value: "minikube", accuracy: 80} + return { value: "minikube", accuracy: 80}; } if (this.isCustom()) { - return { value: "custom", accuracy: 10} + return { value: "custom", accuracy: 10}; } - return { value: "unknown", accuracy: 10} + return { value: "unknown", accuracy: 10}; } public async getKubernetesVersion() { - if (this.cluster.version) return this.cluster.version + if (this.cluster.version) return this.cluster.version; - const response = await this.k8sRequest("/version") - return response.gitVersion + const response = await this.k8sRequest("/version"); + return response.gitVersion; } protected isGKE() { - return this.version.includes("gke") + return this.version.includes("gke"); } protected isEKS() { - return this.version.includes("eks") + return this.version.includes("eks"); } protected isIKS() { - return this.version.includes("IKS") + return this.version.includes("IKS"); } protected isAKS() { - return this.cluster.apiUrl.endsWith("azmk8s.io") + return this.cluster.apiUrl.endsWith("azmk8s.io"); } protected isDigitalOcean() { - return this.cluster.apiUrl.endsWith("k8s.ondigitalocean.com") + return this.cluster.apiUrl.endsWith("k8s.ondigitalocean.com"); } protected isMinikube() { - return this.cluster.contextName.startsWith("minikube") + return this.cluster.contextName.startsWith("minikube"); } protected isCustom() { - return this.version.includes("+") + return this.version.includes("+"); } protected async isRancher() { try { - const response = await this.k8sRequest("") - return response.data.find((api: any) => api?.apiVersion?.group === "meta.cattle.io") !== undefined + const response = await this.k8sRequest(""); + return response.data.find((api: any) => api?.apiVersion?.group === "meta.cattle.io") !== undefined; } catch (e) { - return false + return false; } } } \ No newline at end of file diff --git a/src/main/cluster-detectors/last-seen-detector.ts b/src/main/cluster-detectors/last-seen-detector.ts index 0c231116fe..d56483625a 100644 --- a/src/main/cluster-detectors/last-seen-detector.ts +++ b/src/main/cluster-detectors/last-seen-detector.ts @@ -2,12 +2,12 @@ import { BaseClusterDetector } from "./base-cluster-detector"; import { ClusterMetadataKey } from "../cluster"; export class LastSeenDetector extends BaseClusterDetector { - key = ClusterMetadataKey.LAST_SEEN + key = ClusterMetadataKey.LAST_SEEN; public async detect() { if (!this.cluster.accessible) return null; - await this.k8sRequest("/version") - return { value: new Date().toJSON(), accuracy: 100 } + await this.k8sRequest("/version"); + return { value: new Date().toJSON(), accuracy: 100 }; } } \ No newline at end of file diff --git a/src/main/cluster-detectors/nodes-count-detector.ts b/src/main/cluster-detectors/nodes-count-detector.ts index 858ff43d9f..ba5fc93583 100644 --- a/src/main/cluster-detectors/nodes-count-detector.ts +++ b/src/main/cluster-detectors/nodes-count-detector.ts @@ -2,16 +2,16 @@ import { BaseClusterDetector } from "./base-cluster-detector"; import { ClusterMetadataKey } from "../cluster"; export class NodesCountDetector extends BaseClusterDetector { - key = ClusterMetadataKey.NODES_COUNT + key = ClusterMetadataKey.NODES_COUNT; public async detect() { if (!this.cluster.accessible) return null; - const nodeCount = await this.getNodeCount() - return { value: nodeCount, accuracy: 100} + const nodeCount = await this.getNodeCount(); + return { value: nodeCount, accuracy: 100}; } protected async getNodeCount(): Promise { - const response = await this.k8sRequest("/api/v1/nodes") - return response.items.length + const response = await this.k8sRequest("/api/v1/nodes"); + return response.items.length; } } \ No newline at end of file diff --git a/src/main/cluster-detectors/version-detector.ts b/src/main/cluster-detectors/version-detector.ts index 4092b40b42..e59e6291b9 100644 --- a/src/main/cluster-detectors/version-detector.ts +++ b/src/main/cluster-detectors/version-detector.ts @@ -2,16 +2,16 @@ import { BaseClusterDetector } from "./base-cluster-detector"; import { ClusterMetadataKey } from "../cluster"; export class VersionDetector extends BaseClusterDetector { - key = ClusterMetadataKey.VERSION - value: string + key = ClusterMetadataKey.VERSION; + value: string; public async detect() { - const version = await this.getKubernetesVersion() - return { value: version, accuracy: 100} + const version = await this.getKubernetesVersion(); + return { value: version, accuracy: 100}; } public async getKubernetesVersion() { - const response = await this.k8sRequest("/version") - return response.gitVersion + const response = await this.k8sRequest("/version"); + return response.gitVersion; } } \ No newline at end of file diff --git a/src/main/cluster-manager.ts b/src/main/cluster-manager.ts index 1a479e724e..9b2e88ef89 100644 --- a/src/main/cluster-manager.ts +++ b/src/main/cluster-manager.ts @@ -1,16 +1,16 @@ import "../common/cluster-ipc"; -import type http from "http" -import { ipcMain } from "electron" +import type http from "http"; +import { ipcMain } from "electron"; import { autorun } from "mobx"; -import { clusterStore, getClusterIdFromHost } from "../common/cluster-store" -import { Cluster } from "./cluster" +import { clusterStore, getClusterIdFromHost } from "../common/cluster-store"; +import { Cluster } from "./cluster"; import logger from "./logger"; import { apiKubePrefix } from "../common/vars"; import { Singleton } from "../common/utils"; export class ClusterManager extends Singleton { constructor(public readonly port: number) { - super() + super(); // auto-init clusters autorun(() => { clusterStore.enabledClustersList.forEach(cluster => { @@ -34,52 +34,52 @@ export class ClusterManager extends Singleton { delay: 250 }); - ipcMain.on("network:offline", () => { this.onNetworkOffline() }) - ipcMain.on("network:online", () => { this.onNetworkOnline() }) + ipcMain.on("network:offline", () => { this.onNetworkOffline(); }); + ipcMain.on("network:online", () => { this.onNetworkOnline(); }); } protected onNetworkOffline() { - logger.info("[CLUSTER-MANAGER]: network is offline") + logger.info("[CLUSTER-MANAGER]: network is offline"); clusterStore.enabledClustersList.forEach((cluster) => { if (!cluster.disconnected) { - cluster.online = false - cluster.accessible = false - cluster.refreshConnectionStatus().catch((e) => e) + cluster.online = false; + cluster.accessible = false; + cluster.refreshConnectionStatus().catch((e) => e); } - }) + }); } protected onNetworkOnline() { - logger.info("[CLUSTER-MANAGER]: network is online") + logger.info("[CLUSTER-MANAGER]: network is online"); clusterStore.enabledClustersList.forEach((cluster) => { if (!cluster.disconnected) { - cluster.refreshConnectionStatus().catch((e) => e) + cluster.refreshConnectionStatus().catch((e) => e); } - }) + }); } stop() { clusterStore.clusters.forEach((cluster: Cluster) => { cluster.disconnect(); - }) + }); } getClusterForRequest(req: http.IncomingMessage): Cluster { - let cluster: Cluster = null + let cluster: Cluster = null; // lens-server is connecting to 127.0.0.1:/ if (req.headers.host.startsWith("127.0.0.1")) { - const clusterId = req.url.split("/")[1] - cluster = clusterStore.getById(clusterId) + const clusterId = req.url.split("/")[1]; + cluster = clusterStore.getById(clusterId); if (cluster) { // we need to swap path prefix so that request is proxied to kube api - req.url = req.url.replace(`/${clusterId}`, apiKubePrefix) + req.url = req.url.replace(`/${clusterId}`, apiKubePrefix); } } else if (req.headers["x-cluster-id"]) { - cluster = clusterStore.getById(req.headers["x-cluster-id"].toString()) + cluster = clusterStore.getById(req.headers["x-cluster-id"].toString()); } else { const clusterId = getClusterIdFromHost(req.headers.host); - cluster = clusterStore.getById(clusterId) + cluster = clusterStore.getById(clusterId); } return cluster; diff --git a/src/main/cluster.ts b/src/main/cluster.ts index a2b71a865b..e2831e8c3f 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -1,18 +1,18 @@ -import { ipcMain } from "electron" -import type { ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences } from "../common/cluster-store" +import { ipcMain } from "electron"; +import type { ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences } from "../common/cluster-store"; import type { IMetricsReqParams } from "../renderer/api/endpoints/metrics.api"; import type { WorkspaceId } from "../common/workspace-store"; import { action, computed, observable, reaction, toJS, when } from "mobx"; import { apiKubePrefix } from "../common/vars"; import { broadcastMessage } from "../common/ipc"; -import { ContextHandler } from "./context-handler" -import { AuthorizationV1Api, CoreV1Api, KubeConfig, V1ResourceAttributes } from "@kubernetes/client-node" +import { ContextHandler } from "./context-handler"; +import { AuthorizationV1Api, CoreV1Api, KubeConfig, V1ResourceAttributes } from "@kubernetes/client-node"; import { Kubectl } from "./kubectl"; -import { KubeconfigManager } from "./kubeconfig-manager" -import { getNodeWarningConditions, loadConfig, podHasIssues } from "../common/kube-helpers" -import request, { RequestPromiseOptions } from "request-promise-native" +import { KubeconfigManager } from "./kubeconfig-manager"; +import { getNodeWarningConditions, loadConfig, podHasIssues } from "../common/kube-helpers"; +import request, { RequestPromiseOptions } from "request-promise-native"; import { apiResources } from "../common/rbac"; -import logger from "./logger" +import logger from "./logger"; import { VersionDetector } from "./cluster-detectors/version-detector"; import { detectorRegistry } from "./cluster-detectors/detector-registry"; @@ -32,7 +32,7 @@ export enum ClusterMetadataKey { export type ClusterRefreshOptions = { refreshMetadata?: boolean -} +}; export interface ClusterState { initialized: boolean; @@ -50,7 +50,7 @@ export interface ClusterState { export class Cluster implements ClusterModel, ClusterState { public id: ClusterId; - public kubeCtl: Kubectl + public kubeCtl: Kubectl; public contextHandler: ContextHandler; public ownerRef: string; protected kubeconfigManager: KubeconfigManager; @@ -86,23 +86,23 @@ export class Cluster implements ClusterModel, ClusterState { } @computed get name() { - return this.preferences.clusterName || this.contextName + return this.preferences.clusterName || this.contextName; } get version(): string { - return String(this.metadata?.version) || "" + return String(this.metadata?.version) || ""; } constructor(model: ClusterModel) { this.updateModel(model); - const kubeconfig = this.getKubeconfig() + const kubeconfig = this.getKubeconfig(); if (kubeconfig.getContextObject(this.contextName)) { - this.apiUrl = kubeconfig.getCluster(kubeconfig.getContextObject(this.contextName).cluster).server + this.apiUrl = kubeconfig.getCluster(kubeconfig.getContextObject(this.contextName).cluster).server; } } get isManaged(): boolean { - return !!this.ownerRef + return !!this.ownerRef; } @action @@ -131,16 +131,16 @@ export class Cluster implements ClusterModel, ClusterState { } protected bindEvents() { - logger.info(`[CLUSTER]: bind events`, this.getMeta()) - const refreshTimer = setInterval(() => !this.disconnected && this.refresh(), 30000) // every 30s - const refreshMetadataTimer = setInterval(() => !this.disconnected && this.refreshMetadata(), 900000) // every 15 minutes + logger.info(`[CLUSTER]: bind events`, this.getMeta()); + const refreshTimer = setInterval(() => !this.disconnected && this.refresh(), 30000); // every 30s + const refreshMetadataTimer = setInterval(() => !this.disconnected && this.refreshMetadata(), 900000); // every 15 minutes if (ipcMain) { this.eventDisposers.push( reaction(() => this.getState(), () => this.pushState()), () => { - clearInterval(refreshTimer) - clearInterval(refreshMetadataTimer) + clearInterval(refreshTimer); + clearInterval(refreshMetadataTimer); }, ); } @@ -165,20 +165,20 @@ export class Cluster implements ClusterModel, ClusterState { if (this.disconnected || !this.accessible) { await this.reconnect(); } - await this.refreshConnectionStatus() + await this.refreshConnectionStatus(); if (this.accessible) { - await this.refreshAllowedResources() - this.isAdmin = await this.isClusterAdmin() - this.ready = true - this.ensureKubectl() + await this.refreshAllowedResources(); + this.isAdmin = await this.isClusterAdmin(); + this.ready = true; + this.ensureKubectl(); } - this.activated = true + this.activated = true; return this.pushState(); } protected async ensureKubectl() { - this.kubeCtl = new Kubectl(this.version) - return this.kubeCtl.ensureKubectl() // download kubectl in background, so it's not blocking dashboard + this.kubeCtl = new Kubectl(this.version); + return this.kubeCtl.ensureKubectl(); // download kubectl in background, so it's not blocking dashboard } @action @@ -214,9 +214,9 @@ export class Cluster implements ClusterModel, ClusterState { this.refreshAllowedResources(), ]); if (opts.refreshMetadata) { - this.refreshMetadata() + this.refreshMetadata(); } - this.ready = true + this.ready = true; } this.pushState(); } @@ -224,9 +224,9 @@ export class Cluster implements ClusterModel, ClusterState { @action async refreshMetadata() { logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta()); - const metadata = await detectorRegistry.detectForCluster(this) - const existingMetadata = this.metadata - this.metadata = Object.assign(existingMetadata, metadata) + const metadata = await detectorRegistry.detectForCluster(this); + const existingMetadata = this.metadata; + this.metadata = Object.assign(existingMetadata, metadata); } @action @@ -256,16 +256,16 @@ export class Cluster implements ClusterModel, ClusterState { } getProxyKubeconfigPath(): string { - return this.kubeconfigManager.getPath() + return this.kubeconfigManager.getPath(); } protected async k8sRequest(path: string, options: RequestPromiseOptions = {}): Promise { - options.headers ??= {} - options.json ??= true - options.timeout ??= 30000 - options.headers.Host = `${this.id}.${new URL(this.kubeProxyUrl).host}` // required in ClusterManager.getClusterForRequest() + options.headers ??= {}; + options.json ??= true; + options.timeout ??= 30000; + options.headers.Host = `${this.id}.${new URL(this.kubeProxyUrl).host}`; // required in ClusterManager.getClusterForRequest() - return request(this.kubeProxyUrl + path, options) + return request(this.kubeProxyUrl + path, options); } getMetrics(prometheusPath: string, queryParams: IMetricsReqParams & { query: string }) { @@ -276,17 +276,17 @@ export class Cluster implements ClusterModel, ClusterState { resolveWithFullResponse: false, json: true, qs: queryParams, - }) + }); } protected async getConnectionStatus(): Promise { try { - const versionDetector = new VersionDetector(this) - const versionData = await versionDetector.detect() - this.metadata.version = versionData.value + const versionDetector = new VersionDetector(this); + const versionData = await versionDetector.detect(); + this.metadata.version = versionData.value; return ClusterStatus.AccessGranted; } catch (error) { - logger.error(`Failed to connect cluster "${this.contextName}": ${error}`) + logger.error(`Failed to connect cluster "${this.contextName}": ${error}`); if (error.statusCode) { if (error.statusCode >= 400 && error.statusCode < 500) { this.failureReason = "Invalid credentials"; @@ -310,17 +310,17 @@ export class Cluster implements ClusterModel, ClusterState { } async canI(resourceAttributes: V1ResourceAttributes): Promise { - const authApi = this.getProxyKubeconfig().makeApiClient(AuthorizationV1Api) + const authApi = this.getProxyKubeconfig().makeApiClient(AuthorizationV1Api); try { const accessReview = await authApi.createSelfSubjectAccessReview({ apiVersion: "authorization.k8s.io/v1", kind: "SelfSubjectAccessReview", spec: { resourceAttributes } - }) - return accessReview.body.status.allowed + }); + return accessReview.body.status.allowed; } catch (error) { - logger.error(`failed to request selfSubjectAccessReview: ${error}`) - return false + logger.error(`failed to request selfSubjectAccessReview: ${error}`); + return false; } } @@ -329,7 +329,7 @@ export class Cluster implements ClusterModel, ClusterState { namespace: "kube-system", resource: "*", verb: "create", - }) + }); } protected async getEventCount(): Promise { @@ -345,7 +345,7 @@ export class Cluster implements ClusterModel, ClusterState { if (w.involvedObject.kind === 'Pod') { try { const { body: pod } = await client.readNamespacedPod(w.involvedObject.name, w.involvedObject.namespace); - logger.debug(`checking pod ${w.involvedObject.namespace}/${w.involvedObject.name}`) + logger.debug(`checking pod ${w.involvedObject.namespace}/${w.involvedObject.name}`); if (podHasIssues(pod)) { uniqEventSources.add(w.involvedObject.uid); } @@ -361,7 +361,7 @@ export class Cluster implements ClusterModel, ClusterState { .reduce((sum, conditions) => sum + conditions.length, 0); return uniqEventSources.size + nodeNotificationCount; } catch (error) { - logger.error("Failed to fetch event count: " + JSON.stringify(error)) + logger.error("Failed to fetch event count: " + JSON.stringify(error)); return 0; } } @@ -379,7 +379,7 @@ export class Cluster implements ClusterModel, ClusterState { }; return toJS(model, { recurseEverything: true - }) + }); } // serializable cluster-state used for sync btw main <-> renderer @@ -399,17 +399,17 @@ export class Cluster implements ClusterModel, ClusterState { }; return toJS(state, { recurseEverything: true - }) + }); } @action setState(state: ClusterState) { - Object.assign(this, state) + Object.assign(this, state); } pushState(state = this.getState()) { logger.silly(`[CLUSTER]: push-state`, state); - broadcastMessage("cluster:state", this.id, state) + broadcastMessage("cluster:state", this.id, state); } // get cluster system meta, e.g. use in "logger" @@ -422,30 +422,30 @@ export class Cluster implements ClusterModel, ClusterState { online: this.online, accessible: this.accessible, disconnected: this.disconnected, - } + }; } protected async getAllowedNamespaces() { if (this.accessibleNamespaces.length) { - return this.accessibleNamespaces + return this.accessibleNamespaces; } - const api = this.getProxyKubeconfig().makeApiClient(CoreV1Api) + const api = this.getProxyKubeconfig().makeApiClient(CoreV1Api); try { - const namespaceList = await api.listNamespace() + const namespaceList = await api.listNamespace(); const nsAccessStatuses = await Promise.all( namespaceList.body.items.map(ns => this.canI({ namespace: ns.metadata.name, resource: "pods", verb: "list", })) - ) + ); return namespaceList.body.items .filter((ns, i) => nsAccessStatuses[i]) - .map(ns => ns.metadata.name) + .map(ns => ns.metadata.name); } catch (error) { - const ctx = this.getProxyKubeconfig().getContextObject(this.contextName) - if (ctx.namespace) return [ctx.namespace] + const ctx = this.getProxyKubeconfig().getContextObject(this.contextName); + if (ctx.namespace) return [ctx.namespace]; return []; } } @@ -462,12 +462,12 @@ export class Cluster implements ClusterModel, ClusterState { verb: "list", namespace: this.allowedNamespaces[0] })) - ) + ); return apiResources .filter((resource, i) => resourceAccessStatuses[i]) - .map(apiResource => apiResource.resource) + .map(apiResource => apiResource.resource); } catch (error) { - return [] + return []; } } } diff --git a/src/main/context-handler.ts b/src/main/context-handler.ts index a3cf6185dd..10f84ced6d 100644 --- a/src/main/context-handler.ts +++ b/src/main/context-handler.ts @@ -1,21 +1,21 @@ -import type { PrometheusProvider, PrometheusService } from "./prometheus/provider-registry" +import type { PrometheusProvider, PrometheusService } from "./prometheus/provider-registry"; import type { ClusterPreferences } from "../common/cluster-store"; -import type { Cluster } from "./cluster" -import type httpProxy from "http-proxy" +import type { Cluster } from "./cluster"; +import type httpProxy from "http-proxy"; import url, { UrlWithStringQuery } from "url"; -import { CoreV1Api } from "@kubernetes/client-node" -import { prometheusProviders } from "../common/prometheus-providers" -import logger from "./logger" -import { getFreePort } from "./port" -import { KubeAuthProxy } from "./kube-auth-proxy" +import { CoreV1Api } from "@kubernetes/client-node"; +import { prometheusProviders } from "../common/prometheus-providers"; +import logger from "./logger"; +import { getFreePort } from "./port"; +import { KubeAuthProxy } from "./kube-auth-proxy"; export class ContextHandler { public proxyPort: number; public clusterUrl: UrlWithStringQuery; - protected kubeAuthProxy: KubeAuthProxy - protected apiTarget: httpProxy.ServerOptions - protected prometheusProvider: string - protected prometheusPath: string + protected kubeAuthProxy: KubeAuthProxy; + protected apiTarget: httpProxy.ServerOptions; + protected prometheusProvider: string; + protected prometheusPath: string; constructor(protected cluster: Cluster) { this.clusterUrl = url.parse(cluster.apiUrl); @@ -26,64 +26,64 @@ export class ContextHandler { this.prometheusProvider = preferences.prometheusProvider?.type; this.prometheusPath = null; if (preferences.prometheus) { - const { namespace, service, port } = preferences.prometheus - this.prometheusPath = `${namespace}/services/${service}:${port}` + const { namespace, service, port } = preferences.prometheus; + this.prometheusPath = `${namespace}/services/${service}:${port}`; } } protected async resolvePrometheusPath(): Promise { - const { service, namespace, port } = await this.getPrometheusService() - return `${namespace}/services/${service}:${port}` + const { service, namespace, port } = await this.getPrometheusService(); + return `${namespace}/services/${service}:${port}`; } async getPrometheusProvider() { if (!this.prometheusProvider) { - const service = await this.getPrometheusService() - logger.info(`using ${service.id} as prometheus provider`) - this.prometheusProvider = service.id + const service = await this.getPrometheusService(); + logger.info(`using ${service.id} as prometheus provider`); + this.prometheusProvider = service.id; } - return prometheusProviders.find(p => p.id === this.prometheusProvider) + return prometheusProviders.find(p => p.id === this.prometheusProvider); } async getPrometheusService(): Promise { const providers = this.prometheusProvider ? prometheusProviders.filter(provider => provider.id == this.prometheusProvider) : prometheusProviders; const prometheusPromises: Promise[] = providers.map(async (provider: PrometheusProvider): Promise => { - const apiClient = this.cluster.getProxyKubeconfig().makeApiClient(CoreV1Api) - return await provider.getPrometheusService(apiClient) - }) - const resolvedPrometheusServices = await Promise.all(prometheusPromises) + const apiClient = this.cluster.getProxyKubeconfig().makeApiClient(CoreV1Api); + return await provider.getPrometheusService(apiClient); + }); + const resolvedPrometheusServices = await Promise.all(prometheusPromises); const service = resolvedPrometheusServices.filter(n => n)[0]; return service || { id: "lens", namespace: "lens-metrics", service: "prometheus", port: 80 - } + }; } async getPrometheusPath(): Promise { if (!this.prometheusPath) { - this.prometheusPath = await this.resolvePrometheusPath() + this.prometheusPath = await this.resolvePrometheusPath(); } return this.prometheusPath; } async resolveAuthProxyUrl() { const proxyPort = await this.ensurePort(); - const path = this.clusterUrl.path !== "/" ? this.clusterUrl.path : "" + const path = this.clusterUrl.path !== "/" ? this.clusterUrl.path : ""; return `http://127.0.0.1:${proxyPort}${path}`; } async getApiTarget(isWatchRequest = false): Promise { if (this.apiTarget && !isWatchRequest) { - return this.apiTarget + return this.apiTarget; } - const timeout = isWatchRequest ? 4 * 60 * 60 * 1000 : 30000 // 4 hours for watch request, 30 seconds for the rest - const apiTarget = await this.newApiTarget(timeout) + const timeout = isWatchRequest ? 4 * 60 * 60 * 1000 : 30000; // 4 hours for watch request, 30 seconds for the rest + const apiTarget = await this.newApiTarget(timeout); if (!isWatchRequest) { - this.apiTarget = apiTarget + this.apiTarget = apiTarget; } - return apiTarget + return apiTarget; } protected async newApiTarget(timeout: number): Promise { @@ -95,36 +95,36 @@ export class ContextHandler { headers: { "Host": this.clusterUrl.hostname, }, - } + }; } async ensurePort(): Promise { if (!this.proxyPort) { this.proxyPort = await getFreePort(); } - return this.proxyPort + return this.proxyPort; } async ensureServer() { if (!this.kubeAuthProxy) { await this.ensurePort(); - const proxyEnv = Object.assign({}, process.env) + const proxyEnv = Object.assign({}, process.env); if (this.cluster.preferences.httpsProxy) { - proxyEnv.HTTPS_PROXY = this.cluster.preferences.httpsProxy + proxyEnv.HTTPS_PROXY = this.cluster.preferences.httpsProxy; } - this.kubeAuthProxy = new KubeAuthProxy(this.cluster, this.proxyPort, proxyEnv) - await this.kubeAuthProxy.run() + this.kubeAuthProxy = new KubeAuthProxy(this.cluster, this.proxyPort, proxyEnv); + await this.kubeAuthProxy.run(); } } stopServer() { if (this.kubeAuthProxy) { - this.kubeAuthProxy.exit() - this.kubeAuthProxy = null + this.kubeAuthProxy.exit(); + this.kubeAuthProxy = null; } } get proxyLastError(): string { - return this.kubeAuthProxy?.lastError || "" + return this.kubeAuthProxy?.lastError || ""; } } diff --git a/src/main/exit-app.ts b/src/main/exit-app.ts index bf73e022f3..b58a6e4dfc 100644 --- a/src/main/exit-app.ts +++ b/src/main/exit-app.ts @@ -6,13 +6,13 @@ import logger from "./logger"; export function exitApp() { - const windowManager = WindowManager.getInstance() - const clusterManager = ClusterManager.getInstance() - appEventBus.emit({ name: "service", action: "close" }) + const windowManager = WindowManager.getInstance(); + const clusterManager = ClusterManager.getInstance(); + appEventBus.emit({ name: "service", action: "close" }); windowManager.hide(); clusterManager.stop(); logger.info('SERVICE:QUIT'); setTimeout(() => { - app.exit() - }, 1000) + app.exit(); + }, 1000); } \ No newline at end of file diff --git a/src/main/helm/helm-chart-manager.ts b/src/main/helm/helm-chart-manager.ts index e42f7a1aaf..42c1a30ed2 100644 --- a/src/main/helm/helm-chart-manager.ts +++ b/src/main/helm/helm-chart-manager.ts @@ -1,74 +1,74 @@ import fs from "fs"; import * as yaml from "js-yaml"; -import { HelmRepo, HelmRepoManager } from "./helm-repo-manager" +import { HelmRepo, HelmRepoManager } from "./helm-repo-manager"; import logger from "../logger"; -import { promiseExec } from "../promise-exec" -import { helmCli } from "./helm-cli" +import { promiseExec } from "../promise-exec"; +import { helmCli } from "./helm-cli"; type CachedYaml = { entries: any; // todo: types -} +}; export class HelmChartManager { - protected cache: any = {} - protected repo: HelmRepo + protected cache: any = {}; + protected repo: HelmRepo; constructor(repo: HelmRepo){ - this.cache = HelmRepoManager.cache - this.repo = repo + this.cache = HelmRepoManager.cache; + this.repo = repo; } public async chart(name: string) { - const charts = await this.charts() - return charts[name] + const charts = await this.charts(); + return charts[name]; } public async charts(): Promise { try { - const cachedYaml = await this.cachedYaml() - return cachedYaml["entries"] + const cachedYaml = await this.cachedYaml(); + return cachedYaml["entries"]; } catch(error) { - logger.error(error) - return [] + logger.error(error); + return []; } } public async getReadme(name: string, version = "") { - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); if(version && version != "") { - const { stdout, stderr} = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr)}) - return stdout + const { stdout, stderr} = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr);}); + return stdout; } else { - const { stdout, stderr} = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr)}) - return stdout + const { stdout, stderr} = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr);}); + return stdout; } } public async getValues(name: string, version = "") { - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); if(version && version != "") { - const { stdout, stderr} = await promiseExec(`"${helm}" show values ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr)}) + const { stdout, stderr} = await promiseExec(`"${helm}" show values ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr);}); - return stdout + return stdout; } else { - const { stdout, stderr} = await promiseExec(`"${helm}" show values ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr)}) + const { stdout, stderr} = await promiseExec(`"${helm}" show values ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr);}); - return stdout + return stdout; } } protected async cachedYaml(): Promise { if (!(this.repo.name in this.cache)) { - const cacheFile = await fs.promises.readFile(this.repo.cacheFilePath, 'utf-8') - const data = yaml.safeLoad(cacheFile) + const cacheFile = await fs.promises.readFile(this.repo.cacheFilePath, 'utf-8'); + const data = yaml.safeLoad(cacheFile); for(const key in data["entries"]) { data["entries"][key].forEach((version: any) => { - version['repo'] = this.repo.name - version['created'] = Date.parse(version.created).toString() - }) + version['repo'] = this.repo.name; + version['created'] = Date.parse(version.created).toString(); + }); } - this.cache[this.repo.name] = Buffer.from(JSON.stringify(data)) + this.cache[this.repo.name] = Buffer.from(JSON.stringify(data)); } - return JSON.parse(this.cache[this.repo.name].toString()) + return JSON.parse(this.cache[this.repo.name].toString()); } } diff --git a/src/main/helm/helm-cli.ts b/src/main/helm/helm-cli.ts index 1484ceacf1..34a3becc33 100644 --- a/src/main/helm/helm-cli.ts +++ b/src/main/helm/helm-cli.ts @@ -1,6 +1,6 @@ -import packageInfo from "../../../package.json" -import path from "path" -import { LensBinary, LensBinaryOpts } from "../lens-binary" +import packageInfo from "../../../package.json"; +import path from "path"; +import { LensBinary, LensBinaryOpts } from "../lens-binary"; import { isProduction } from "../../common/vars"; export class HelmCli extends LensBinary { @@ -11,24 +11,24 @@ export class HelmCli extends LensBinary { baseDir: baseDir, originalBinaryName: "helm", newBinaryName: "helm3" - } - super(opts) + }; + super(opts); } protected getTarName(): string | null { - return `${this.binaryName}-v${this.binaryVersion}-${this.platformName}-${this.arch}.tar.gz` + return `${this.binaryName}-v${this.binaryVersion}-${this.platformName}-${this.arch}.tar.gz`; } protected getUrl() { - return `https://get.helm.sh/helm-v${this.binaryVersion}-${this.platformName}-${this.arch}.tar.gz` + return `https://get.helm.sh/helm-v${this.binaryVersion}-${this.platformName}-${this.arch}.tar.gz`; } protected getBinaryPath() { - return path.join(this.dirname, this.binaryName) + return path.join(this.dirname, this.binaryName); } protected getOriginalBinaryPath() { - return path.join(this.dirname, this.platformName + "-" + this.arch, this.originalBinaryName) + return path.join(this.dirname, this.platformName + "-" + this.arch, this.originalBinaryName); } } diff --git a/src/main/helm/helm-release-manager.ts b/src/main/helm/helm-release-manager.ts index 80be023227..3a8b4707ba 100644 --- a/src/main/helm/helm-release-manager.ts +++ b/src/main/helm/helm-release-manager.ts @@ -1,7 +1,7 @@ import * as tempy from "tempy"; import fs from "fs"; import * as yaml from "js-yaml"; -import { promiseExec} from "../promise-exec" +import { promiseExec} from "../promise-exec"; import { helmCli } from "./helm-cli"; import { Cluster } from "../cluster"; import { toCamelCase } from "../../common/utils/camelCase"; @@ -9,103 +9,103 @@ import { toCamelCase } from "../../common/utils/camelCase"; export class HelmReleaseManager { public async listReleases(pathToKubeconfig: string, namespace?: string) { - const helm = await helmCli.binaryPath() - const namespaceFlag = namespace ? `-n ${namespace}` : "--all-namespaces" - const { stdout } = await promiseExec(`"${helm}" ls --output json ${namespaceFlag} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)}) + const helm = await helmCli.binaryPath(); + const namespaceFlag = namespace ? `-n ${namespace}` : "--all-namespaces"; + const { stdout } = await promiseExec(`"${helm}" ls --output json ${namespaceFlag} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); - const output = JSON.parse(stdout) + const output = JSON.parse(stdout); if (output.length == 0) { - return output + return output; } output.forEach((release: any, index: number) => { - output[index] = toCamelCase(release) + output[index] = toCamelCase(release); }); - return output + return output; } public async installChart(chart: string, values: any, name: string, namespace: string, version: string, pathToKubeconfig: string){ - const helm = await helmCli.binaryPath() - const fileName = tempy.file({name: "values.yaml"}) - await fs.promises.writeFile(fileName, yaml.safeDump(values)) + const helm = await helmCli.binaryPath(); + const fileName = tempy.file({name: "values.yaml"}); + await fs.promises.writeFile(fileName, yaml.safeDump(values)); try { - let generateName = "" + let generateName = ""; if (!name) { - generateName = "--generate-name" - name = "" + generateName = "--generate-name"; + name = ""; } - const { stdout, stderr } = await promiseExec(`"${helm}" install ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${pathToKubeconfig} ${generateName}`).catch((error) => { throw(error.stderr)}) - const releaseName = stdout.split("\n")[0].split(' ')[1].trim() + const { stdout, stderr } = await promiseExec(`"${helm}" install ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${pathToKubeconfig} ${generateName}`).catch((error) => { throw(error.stderr);}); + const releaseName = stdout.split("\n")[0].split(' ')[1].trim(); return { log: stdout, release: { name: releaseName, namespace: namespace } - } + }; } finally { - await fs.promises.unlink(fileName) + await fs.promises.unlink(fileName); } } public async upgradeRelease(name: string, chart: string, values: any, namespace: string, version: string, cluster: Cluster){ - const helm = await helmCli.binaryPath() - const fileName = tempy.file({name: "values.yaml"}) - await fs.promises.writeFile(fileName, yaml.safeDump(values)) + const helm = await helmCli.binaryPath(); + const fileName = tempy.file({name: "values.yaml"}); + await fs.promises.writeFile(fileName, yaml.safeDump(values)); try { - const { stdout, stderr } = await promiseExec(`"${helm}" upgrade ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr)}) + const { stdout, stderr } = await promiseExec(`"${helm}" upgrade ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr);}); return { log: stdout, release: this.getRelease(name, namespace, cluster) - } + }; } finally { - await fs.promises.unlink(fileName) + await fs.promises.unlink(fileName); } } public async getRelease(name: string, namespace: string, cluster: Cluster) { - const helm = await helmCli.binaryPath() - const {stdout, stderr} = await promiseExec(`"${helm}" status ${name} --output json --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr)}) - const release = JSON.parse(stdout) - release.resources = await this.getResources(name, namespace, cluster) - return release + const helm = await helmCli.binaryPath(); + const {stdout, stderr} = await promiseExec(`"${helm}" status ${name} --output json --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr);}); + const release = JSON.parse(stdout); + release.resources = await this.getResources(name, namespace, cluster); + return release; } public async deleteRelease(name: string, namespace: string, pathToKubeconfig: string) { - const helm = await helmCli.binaryPath() - const { stdout, stderr } = await promiseExec(`"${helm}" delete ${name} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)}) + const helm = await helmCli.binaryPath(); + const { stdout, stderr } = await promiseExec(`"${helm}" delete ${name} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); - return stdout + return stdout; } public async getValues(name: string, namespace: string, pathToKubeconfig: string) { - const helm = await helmCli.binaryPath() - const { stdout, stderr } = await promiseExec(`"${helm}" get values ${name} --all --output yaml --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)}) - return stdout + const helm = await helmCli.binaryPath(); + const { stdout, stderr } = await promiseExec(`"${helm}" get values ${name} --all --output yaml --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); + return stdout; } public async getHistory(name: string, namespace: string, pathToKubeconfig: string) { - const helm = await helmCli.binaryPath() - const {stdout, stderr} = await promiseExec(`"${helm}" history ${name} --output json --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)}) - return JSON.parse(stdout) + const helm = await helmCli.binaryPath(); + const {stdout, stderr} = await promiseExec(`"${helm}" history ${name} --output json --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); + return JSON.parse(stdout); } public async rollback(name: string, namespace: string, revision: number, pathToKubeconfig: string) { - const helm = await helmCli.binaryPath() - const {stdout, stderr} = await promiseExec(`"${helm}" rollback ${name} ${revision} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)}) - return stdout + const helm = await helmCli.binaryPath(); + const {stdout, stderr} = await promiseExec(`"${helm}" rollback ${name} ${revision} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); + return stdout; } protected async getResources(name: string, namespace: string, cluster: Cluster) { - const helm = await helmCli.binaryPath() - const kubectl = await cluster.kubeCtl.getPath() - const pathToKubeconfig = cluster.getProxyKubeconfigPath() + const helm = await helmCli.binaryPath(); + const kubectl = await cluster.kubeCtl.getPath(); + const pathToKubeconfig = cluster.getProxyKubeconfigPath(); const { stdout } = await promiseExec(`"${helm}" get manifest ${name} --namespace ${namespace} --kubeconfig ${pathToKubeconfig} | "${kubectl}" get -n ${namespace} --kubeconfig ${pathToKubeconfig} -f - -o=json`).catch((error) => { - return { stdout: JSON.stringify({items: []})} - }) - return stdout + return { stdout: JSON.stringify({items: []})}; + }); + return stdout; } } -export const releaseManager = new HelmReleaseManager() +export const releaseManager = new HelmReleaseManager(); diff --git a/src/main/helm/helm-repo-manager.ts b/src/main/helm/helm-repo-manager.ts index c2af9ea7ba..dff372a301 100644 --- a/src/main/helm/helm-repo-manager.ts +++ b/src/main/helm/helm-repo-manager.ts @@ -10,7 +10,7 @@ import logger from "../logger"; export type HelmEnv = Record & { HELM_REPOSITORY_CACHE?: string; HELM_REPOSITORY_CONFIG?: string; -} +}; export interface HelmRepoConfig { repositories: HelmRepo[] @@ -29,11 +29,11 @@ export interface HelmRepo { } export class HelmRepoManager extends Singleton { - static cache = {} // todo: remove implicit updates in helm-chart-manager.ts + static cache = {}; // todo: remove implicit updates in helm-chart-manager.ts protected repos: HelmRepo[]; - protected helmEnv: HelmEnv - protected initialized: boolean + protected helmEnv: HelmEnv; + protected initialized: boolean; async loadAvailableRepos(): Promise { const res = await customRequestPromise({ @@ -46,34 +46,34 @@ export class HelmRepoManager extends Singleton { } async init() { - helmCli.setLogger(logger) + helmCli.setLogger(logger); await helmCli.ensureBinary(); if (!this.initialized) { - this.helmEnv = await this.parseHelmEnv() - await this.update() - this.initialized = true + this.helmEnv = await this.parseHelmEnv(); + await this.update(); + this.initialized = true; } } protected async parseHelmEnv() { - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); const { stdout } = await promiseExec(`"${helm}" env`).catch((error) => { - throw(error.stderr) - }) - const lines = stdout.split(/\r?\n/) // split by new line feed - const env: HelmEnv = {} + throw(error.stderr); + }); + const lines = stdout.split(/\r?\n/); // split by new line feed + const env: HelmEnv = {}; lines.forEach((line: string) => { - const [key, value] = line.split("=") + const [key, value] = line.split("="); if (key && value) { - env[key] = value.replace(/"/g, "") // strip quotas + env[key] = value.replace(/"/g, ""); // strip quotas } - }) - return env + }); + return env; } public async repositories(): Promise { if (!this.initialized) { - await this.init() + await this.init(); } try { const repoConfigFile = this.helmEnv.HELM_REPOSITORY_CONFIG; @@ -91,41 +91,41 @@ export class HelmRepoManager extends Singleton { cacheFilePath: `${this.helmEnv.HELM_REPOSITORY_CACHE}/${repo.name}-index.yaml` })); } catch (error) { - logger.error(`[HELM]: repositories listing error "${error}"`) - return [] + logger.error(`[HELM]: repositories listing error "${error}"`); + return []; } } public async repository(name: string) { - const repositories = await this.repositories() + const repositories = await this.repositories(); return repositories.find(repo => repo.name == name); } public async update() { - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); const { stdout } = await promiseExec(`"${helm}" repo update`).catch((error) => { - return { stdout: error.stdout } - }) - return stdout + return { stdout: error.stdout }; + }); + return stdout; } public async addRepo({ name, url }: HelmRepo) { logger.info(`[HELM]: adding repo "${name}" from ${url}`); - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); const { stdout } = await promiseExec(`"${helm}" repo add ${name} ${url}`).catch((error) => { - throw(error.stderr) - }) - return stdout + throw(error.stderr); + }); + return stdout; } public async removeRepo({ name, url }: HelmRepo): Promise { logger.info(`[HELM]: removing repo "${name}" from ${url}`); - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); const { stdout, stderr } = await promiseExec(`"${helm}" repo remove ${name}`).catch((error) => { - throw(error.stderr) - }) - return stdout + throw(error.stderr); + }); + return stdout; } } -export const repoManager = HelmRepoManager.getInstance() +export const repoManager = HelmRepoManager.getInstance(); diff --git a/src/main/helm/helm-service.ts b/src/main/helm/helm-service.ts index 664a30358c..88ca4dda3e 100644 --- a/src/main/helm/helm-service.ts +++ b/src/main/helm/helm-service.ts @@ -6,93 +6,93 @@ import { releaseManager } from "./helm-release-manager"; class HelmService { public async installChart(cluster: Cluster, data: { chart: string; values: {}; name: string; namespace: string; version: string }) { - return await releaseManager.installChart(data.chart, data.values, data.name, data.namespace, data.version, cluster.getProxyKubeconfigPath()) + return await releaseManager.installChart(data.chart, data.values, data.name, data.namespace, data.version, cluster.getProxyKubeconfigPath()); } public async listCharts() { - const charts: any = {} - await repoManager.init() - const repositories = await repoManager.repositories() + const charts: any = {}; + await repoManager.init(); + const repositories = await repoManager.repositories(); for (const repo of repositories) { - charts[repo.name] = {} - const manager = new HelmChartManager(repo) - let entries = await manager.charts() - entries = this.excludeDeprecated(entries) + charts[repo.name] = {}; + const manager = new HelmChartManager(repo); + let entries = await manager.charts(); + entries = this.excludeDeprecated(entries); for (const key in entries) { - entries[key] = entries[key][0] + entries[key] = entries[key][0]; } - charts[repo.name] = entries + charts[repo.name] = entries; } - return charts + return charts; } public async getChart(repoName: string, chartName: string, version = "") { const result = { readme: "", versions: {} - } - const repo = await repoManager.repository(repoName) - const chartManager = new HelmChartManager(repo) - const chart = await chartManager.chart(chartName) - result.readme = await chartManager.getReadme(chartName, version) - result.versions = chart - return result + }; + const repo = await repoManager.repository(repoName); + const chartManager = new HelmChartManager(repo); + const chart = await chartManager.chart(chartName); + result.readme = await chartManager.getReadme(chartName, version); + result.versions = chart; + return result; } public async getChartValues(repoName: string, chartName: string, version = "") { - const repo = await repoManager.repository(repoName) - const chartManager = new HelmChartManager(repo) - return chartManager.getValues(chartName, version) + const repo = await repoManager.repository(repoName); + const chartManager = new HelmChartManager(repo); + return chartManager.getValues(chartName, version); } public async listReleases(cluster: Cluster, namespace: string = null) { - await repoManager.init() - return await releaseManager.listReleases(cluster.getProxyKubeconfigPath(), namespace) + await repoManager.init(); + return await releaseManager.listReleases(cluster.getProxyKubeconfigPath(), namespace); } public async getRelease(cluster: Cluster, releaseName: string, namespace: string) { - logger.debug("Fetch release") - return await releaseManager.getRelease(releaseName, namespace, cluster) + logger.debug("Fetch release"); + return await releaseManager.getRelease(releaseName, namespace, cluster); } public async getReleaseValues(cluster: Cluster, releaseName: string, namespace: string) { - logger.debug("Fetch release values") - return await releaseManager.getValues(releaseName, namespace, cluster.getProxyKubeconfigPath()) + logger.debug("Fetch release values"); + return await releaseManager.getValues(releaseName, namespace, cluster.getProxyKubeconfigPath()); } public async getReleaseHistory(cluster: Cluster, releaseName: string, namespace: string) { - logger.debug("Fetch release history") - return await releaseManager.getHistory(releaseName, namespace, cluster.getProxyKubeconfigPath()) + logger.debug("Fetch release history"); + return await releaseManager.getHistory(releaseName, namespace, cluster.getProxyKubeconfigPath()); } public async deleteRelease(cluster: Cluster, releaseName: string, namespace: string) { - logger.debug("Delete release") - return await releaseManager.deleteRelease(releaseName, namespace, cluster.getProxyKubeconfigPath()) + logger.debug("Delete release"); + return await releaseManager.deleteRelease(releaseName, namespace, cluster.getProxyKubeconfigPath()); } public async updateRelease(cluster: Cluster, releaseName: string, namespace: string, data: { chart: string; values: {}; version: string }) { - logger.debug("Upgrade release") - return await releaseManager.upgradeRelease(releaseName, data.chart, data.values, namespace, data.version, cluster) + logger.debug("Upgrade release"); + return await releaseManager.upgradeRelease(releaseName, data.chart, data.values, namespace, data.version, cluster); } public async rollback(cluster: Cluster, releaseName: string, namespace: string, revision: number) { - logger.debug("Rollback release") - const output = await releaseManager.rollback(releaseName, namespace, revision, cluster.getProxyKubeconfigPath()) - return { message: output } + logger.debug("Rollback release"); + const output = await releaseManager.rollback(releaseName, namespace, revision, cluster.getProxyKubeconfigPath()); + return { message: output }; } protected excludeDeprecated(entries: any) { for (const key in entries) { entries[key] = entries[key].filter((entry: any) => { if (Array.isArray(entry)) { - return entry[0]['deprecated'] != true + return entry[0]['deprecated'] != true; } - return entry["deprecated"] != true - }) + return entry["deprecated"] != true; + }); } - return entries + return entries; } } -export const helmService = new HelmService() +export const helmService = new HelmService(); diff --git a/src/main/index.ts b/src/main/index.ts index e360c2fe85..2087432d7b 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,25 +1,25 @@ // Main process -import "../common/system-ca" -import "../common/prometheus-providers" -import * as Mobx from "mobx" +import "../common/system-ca"; +import "../common/prometheus-providers"; +import * as Mobx from "mobx"; import * as LensExtensions from "../extensions/core-api"; -import { app, dialog } from "electron" +import { app, dialog } from "electron"; import { appName } from "../common/vars"; -import path from "path" -import { LensProxy } from "./lens-proxy" +import path from "path"; +import { LensProxy } from "./lens-proxy"; import { WindowManager } from "./window-manager"; import { ClusterManager } from "./cluster-manager"; -import { AppUpdater } from "./app-updater" -import { shellSync } from "./shell-sync" -import { getFreePort } from "./port" -import { mangleProxyEnv } from "./proxy-env" +import { AppUpdater } from "./app-updater"; +import { shellSync } from "./shell-sync"; +import { getFreePort } from "./port"; +import { mangleProxyEnv } from "./proxy-env"; import { registerFileProtocol } from "../common/register-protocol"; -import logger from "./logger" -import { clusterStore } from "../common/cluster-store" +import logger from "./logger"; +import { clusterStore } from "../common/cluster-store"; import { userStore } from "../common/user-store"; import { workspaceStore } from "../common/workspace-store"; -import { appEventBus } from "../common/event-bus" +import { appEventBus } from "../common/event-bus"; import { extensionLoader } from "../extensions/extension-loader"; import { extensionManager } from "../extensions/extension-manager"; import { extensionsStore } from "../extensions/extensions-store"; @@ -35,16 +35,16 @@ if (!process.env.CICD) { app.setPath("userData", workingDir); } -mangleProxyEnv() +mangleProxyEnv(); if (app.commandLine.getSwitchValue("proxy-server") !== "") { - process.env.HTTPS_PROXY = app.commandLine.getSwitchValue("proxy-server") + process.env.HTTPS_PROXY = app.commandLine.getSwitchValue("proxy-server"); } app.on("ready", async () => { - logger.info(`🚀 Starting Lens from "${workingDir}"`) + logger.info(`🚀 Starting Lens from "${workingDir}"`); await shellSync(); - const updater = new AppUpdater() + const updater = new AppUpdater(); updater.start(); registerFileProtocol("static", __static); @@ -59,10 +59,10 @@ app.on("ready", async () => { // find free port try { - proxyPort = await getFreePort() + proxyPort = await getFreePort(); } catch (error) { - logger.error(error) - dialog.showErrorBox("Lens Error", "Could not find a free port for the cluster proxy") + logger.error(error); + dialog.showErrorBox("Lens Error", "Could not find a free port for the cluster proxy"); app.exit(); } @@ -73,22 +73,22 @@ app.on("ready", async () => { try { proxyServer = LensProxy.create(proxyPort, clusterManager); } catch (error) { - logger.error(`Could not start proxy (127.0.0:${proxyPort}): ${error.message}`) - dialog.showErrorBox("Lens Error", `Could not start proxy (127.0.0:${proxyPort}): ${error.message || "unknown error"}`) + logger.error(`Could not start proxy (127.0.0:${proxyPort}): ${error.message}`); + dialog.showErrorBox("Lens Error", `Could not start proxy (127.0.0:${proxyPort}): ${error.message || "unknown error"}`); app.exit(); } - extensionLoader.init() + extensionLoader.init(); windowManager = WindowManager.getInstance(proxyPort); extensionLoader.initExtensions(await extensionManager.load()); // call after windowManager to see splash earlier setTimeout(() => { - appEventBus.emit({ name: "service", action: "start" }) - }, 1000) + appEventBus.emit({ name: "service", action: "start" }); + }, 1000); }); app.on("activate", (event, hasVisibleWindows) => { - logger.info('APP:ACTIVATE', { hasVisibleWindows }) + logger.info('APP:ACTIVATE', { hasVisibleWindows }); if (!hasVisibleWindows) { windowManager.initMainWindow(); } @@ -97,11 +97,11 @@ app.on("activate", (event, hasVisibleWindows) => { // Quit app on Cmd+Q (MacOS) app.on("will-quit", (event) => { logger.info('APP:QUIT'); - appEventBus.emit({name: "app", action: "close"}) + appEventBus.emit({name: "app", action: "close"}); event.preventDefault(); // prevent app's default shutdown (e.g. required for telemetry, etc.) clusterManager?.stop(); // close cluster connections return; // skip exit to make tray work, to quit go to app's global menu or tray's menu -}) +}); // Extensions-api runtime exports export const LensExtensionsApi = { @@ -111,4 +111,4 @@ export const LensExtensionsApi = { export { Mobx, LensExtensionsApi as LensExtensions, -} +}; diff --git a/src/main/kube-auth-proxy.ts b/src/main/kube-auth-proxy.ts index 5377ecb829..3ad76e52b0 100644 --- a/src/main/kube-auth-proxy.ts +++ b/src/main/kube-auth-proxy.ts @@ -1,10 +1,10 @@ -import { ChildProcess, spawn } from "child_process" +import { ChildProcess, spawn } from "child_process"; import { waitUntilUsed } from "tcp-port-used"; import { broadcastMessage } from "../common/ipc"; -import type { Cluster } from "./cluster" -import { Kubectl } from "./kubectl" -import logger from "./logger" -import * as url from "url" +import type { Cluster } from "./cluster"; +import { Kubectl } from "./kubectl"; +import logger from "./logger"; +import * as url from "url"; export interface KubeAuthProxyLog { data: string; @@ -12,19 +12,19 @@ export interface KubeAuthProxyLog { } export class KubeAuthProxy { - public lastError: string + public lastError: string; - protected cluster: Cluster - protected env: NodeJS.ProcessEnv = null - protected proxyProcess: ChildProcess - protected port: number - protected kubectl: Kubectl + protected cluster: Cluster; + protected env: NodeJS.ProcessEnv = null; + protected proxyProcess: ChildProcess; + protected port: number; + protected kubectl: Kubectl; constructor(cluster: Cluster, port: number, env: NodeJS.ProcessEnv) { - this.env = env - this.port = port - this.cluster = cluster - this.kubectl = Kubectl.bundled() + this.env = env; + this.port = port; + this.cluster = cluster; + this.kubectl = Kubectl.bundled(); } get acceptHosts() { @@ -36,7 +36,7 @@ export class KubeAuthProxy { return; } - const proxyBin = await this.kubectl.getPath() + const proxyBin = await this.kubectl.getPath(); const args = [ "proxy", "-p", `${this.port}`, @@ -44,63 +44,63 @@ export class KubeAuthProxy { "--context", `${this.cluster.contextName}`, "--accept-hosts", this.acceptHosts, "--reject-paths", "^[^/]" - ] + ]; if (process.env.DEBUG_PROXY === "true") { - args.push("-v", "9") + args.push("-v", "9"); } - logger.debug(`spawning kubectl proxy with args: ${args}`) - this.proxyProcess = spawn(proxyBin, args, { env: this.env, }) + logger.debug(`spawning kubectl proxy with args: ${args}`); + this.proxyProcess = spawn(proxyBin, args, { env: this.env, }); this.proxyProcess.on("error", (error) => { - this.sendIpcLogMessage({ data: error.message, error: true }) - this.exit() - }) + this.sendIpcLogMessage({ data: error.message, error: true }); + this.exit(); + }); this.proxyProcess.on("exit", (code) => { - this.sendIpcLogMessage({ data: `proxy exited with code: ${code}`, error: code > 0 }) + this.sendIpcLogMessage({ data: `proxy exited with code: ${code}`, error: code > 0 }); this.exit(); - }) + }); this.proxyProcess.stdout.on('data', (data) => { - let logItem = data.toString() + let logItem = data.toString(); if (logItem.startsWith("Starting to serve on")) { - logItem = "Authentication proxy started\n" + logItem = "Authentication proxy started\n"; } - this.sendIpcLogMessage({ data: logItem }) - }) + this.sendIpcLogMessage({ data: logItem }); + }); this.proxyProcess.stderr.on('data', (data) => { - this.lastError = this.parseError(data.toString()) - this.sendIpcLogMessage({ data: data.toString(), error: true }) - }) + this.lastError = this.parseError(data.toString()); + this.sendIpcLogMessage({ data: data.toString(), error: true }); + }); - return waitUntilUsed(this.port, 500, 10000) + return waitUntilUsed(this.port, 500, 10000); } protected parseError(data: string) { - const error = data.split("http: proxy error:").slice(1).join("").trim() - let errorMsg = error - const jsonError = error.split("Response: ")[1] + const error = data.split("http: proxy error:").slice(1).join("").trim(); + let errorMsg = error; + const jsonError = error.split("Response: ")[1]; if (jsonError) { try { - const parsedError = JSON.parse(jsonError) - errorMsg = parsedError.error_description || parsedError.error || jsonError + const parsedError = JSON.parse(jsonError); + errorMsg = parsedError.error_description || parsedError.error || jsonError; } catch (_) { - errorMsg = jsonError.trim() + errorMsg = jsonError.trim(); } } - return errorMsg + return errorMsg; } protected async sendIpcLogMessage(res: KubeAuthProxyLog) { - const channel = `kube-auth:${this.cluster.id}` + const channel = `kube-auth:${this.cluster.id}`; logger.info(`[KUBE-AUTH]: out-channel "${channel}"`, { ...res, meta: this.cluster.getMeta() }); - broadcastMessage(channel, res) + broadcastMessage(channel, res); } public exit() { if (!this.proxyProcess) return; - logger.debug("[KUBE-AUTH]: stopping local proxy", this.cluster.getMeta()) - this.proxyProcess.kill() + logger.debug("[KUBE-AUTH]: stopping local proxy", this.cluster.getMeta()); + this.proxyProcess.kill(); this.proxyProcess.removeAllListeners(); this.proxyProcess.stderr.removeAllListeners(); this.proxyProcess.stdout.removeAllListeners(); diff --git a/src/main/kubeconfig-manager.ts b/src/main/kubeconfig-manager.ts index fc84d00ddb..a8b3ae3fce 100644 --- a/src/main/kubeconfig-manager.ts +++ b/src/main/kubeconfig-manager.ts @@ -1,22 +1,22 @@ import type { KubeConfig } from "@kubernetes/client-node"; -import type { Cluster } from "./cluster" +import type { Cluster } from "./cluster"; import type { ContextHandler } from "./context-handler"; -import { app } from "electron" -import path from "path" -import fs from "fs-extra" -import { dumpConfigYaml, loadConfig } from "../common/kube-helpers" -import logger from "./logger" +import { app } from "electron"; +import path from "path"; +import fs from "fs-extra"; +import { dumpConfigYaml, loadConfig } from "../common/kube-helpers"; +import logger from "./logger"; export class KubeconfigManager { - protected configDir = app.getPath("temp") + protected configDir = app.getPath("temp"); protected tempFile: string; private constructor(protected cluster: Cluster, protected contextHandler: ContextHandler, protected port: number) { } static async create(cluster: Cluster, contextHandler: ContextHandler, port: number) { - const kcm = new KubeconfigManager(cluster, contextHandler, port) - await kcm.init() - return kcm + const kcm = new KubeconfigManager(cluster, contextHandler, port); + await kcm.init(); + return kcm; } protected async init() { @@ -24,7 +24,7 @@ export class KubeconfigManager { await this.contextHandler.ensurePort(); await this.createProxyKubeconfig(); } catch (err) { - logger.error(`Failed to created temp config for auth-proxy`, { err }) + logger.error(`Failed to created temp config for auth-proxy`, { err }); } } @@ -33,7 +33,7 @@ export class KubeconfigManager { } protected resolveProxyUrl() { - return `http://127.0.0.1:${this.port}/${this.cluster.id}` + return `http://127.0.0.1:${this.port}/${this.cluster.id}`; } /** @@ -78,11 +78,11 @@ export class KubeconfigManager { async unlink() { if (!this.tempFile) { - return + return; } - logger.info('Deleting temporary kubeconfig: ' + this.tempFile) - await fs.unlink(this.tempFile) - this.tempFile = undefined + logger.info('Deleting temporary kubeconfig: ' + this.tempFile); + await fs.unlink(this.tempFile); + this.tempFile = undefined; } } diff --git a/src/main/kubectl.ts b/src/main/kubectl.ts index 6b2f51476d..5d3f12746e 100644 --- a/src/main/kubectl.ts +++ b/src/main/kubectl.ts @@ -1,17 +1,17 @@ -import { app, remote } from "electron" -import path from "path" -import fs from "fs" -import { promiseExec } from "./promise-exec" -import logger from "./logger" -import { ensureDir, pathExists } from "fs-extra" -import * as lockFile from "proper-lockfile" -import { helmCli } from "./helm/helm-cli" -import { userStore } from "../common/user-store" +import { app, remote } from "electron"; +import path from "path"; +import fs from "fs"; +import { promiseExec } from "./promise-exec"; +import logger from "./logger"; +import { ensureDir, pathExists } from "fs-extra"; +import * as lockFile from "proper-lockfile"; +import { helmCli } from "./helm/helm-cli"; +import { userStore } from "../common/user-store"; import { customRequest } from "../common/request"; -import { getBundledKubectlVersion } from "../common/utils/app-version" +import { getBundledKubectlVersion } from "../common/utils/app-version"; import { isDevelopment, isWindows, isTestEnv } from "../common/vars"; -const bundledVersion = getBundledKubectlVersion() +const bundledVersion = getBundledKubectlVersion(); const kubectlMap: Map = new Map([ ["1.7", "1.8.15"], ["1.8", "1.9.10"], @@ -26,314 +26,314 @@ const kubectlMap: Map = new Map([ ["1.17", bundledVersion], ["1.18", "1.18.8"], ["1.19", "1.19.0"] -]) +]); const packageMirrors: Map = new Map([ ["default", "https://storage.googleapis.com/kubernetes-release/release"], ["china", "https://mirror.azure.cn/kubernetes/kubectl"] -]) +]); -let bundledPath: string -const initScriptVersionString = "# lens-initscript v3\n" +let bundledPath: string; +const initScriptVersionString = "# lens-initscript v3\n"; export function bundledKubectlPath(): string { - if (bundledPath) { return bundledPath } + if (bundledPath) { return bundledPath; } if (isDevelopment || isTestEnv) { - const platformName = isWindows ? "windows" : process.platform - bundledPath = path.join(process.cwd(), "binaries", "client", platformName, process.arch, "kubectl") + const platformName = isWindows ? "windows" : process.platform; + bundledPath = path.join(process.cwd(), "binaries", "client", platformName, process.arch, "kubectl"); } else { - bundledPath = path.join(process.resourcesPath, process.arch, "kubectl") + bundledPath = path.join(process.resourcesPath, process.arch, "kubectl"); } if (isWindows) { - bundledPath = `${bundledPath}.exe` + bundledPath = `${bundledPath}.exe`; } - return bundledPath + return bundledPath; } export class Kubectl { - public kubectlVersion: string - protected directory: string - protected url: string - protected path: string - protected dirname: string + public kubectlVersion: string; + protected directory: string; + protected url: string; + protected path: string; + protected dirname: string; static get kubectlDir() { - return path.join((app || remote.app).getPath("userData"), "binaries", "kubectl") + return path.join((app || remote.app).getPath("userData"), "binaries", "kubectl"); } - public static readonly bundledKubectlVersion: string = bundledVersion - public static invalidBundle = false + public static readonly bundledKubectlVersion: string = bundledVersion; + public static invalidBundle = false; private static bundledInstance: Kubectl; // Returns the single bundled Kubectl instance public static bundled() { - if (!Kubectl.bundledInstance) Kubectl.bundledInstance = new Kubectl(Kubectl.bundledKubectlVersion) - return Kubectl.bundledInstance + if (!Kubectl.bundledInstance) Kubectl.bundledInstance = new Kubectl(Kubectl.bundledKubectlVersion); + return Kubectl.bundledInstance; } constructor(clusterVersion: string) { - const versionParts = /^v?(\d+\.\d+)(.*)/.exec(clusterVersion) - const minorVersion = versionParts[1] + const versionParts = /^v?(\d+\.\d+)(.*)/.exec(clusterVersion); + const minorVersion = versionParts[1]; /* minorVersion is the first two digits of kube server version if the version map includes that, use that version, if not, fallback to the exact x.y.z of kube version */ if (kubectlMap.has(minorVersion)) { - this.kubectlVersion = kubectlMap.get(minorVersion) - logger.debug("Set kubectl version " + this.kubectlVersion + " for cluster version " + clusterVersion + " using version map") + this.kubectlVersion = kubectlMap.get(minorVersion); + logger.debug("Set kubectl version " + this.kubectlVersion + " for cluster version " + clusterVersion + " using version map"); } else { - this.kubectlVersion = versionParts[1] + versionParts[2] - logger.debug("Set kubectl version " + this.kubectlVersion + " for cluster version " + clusterVersion + " using fallback") + this.kubectlVersion = versionParts[1] + versionParts[2]; + logger.debug("Set kubectl version " + this.kubectlVersion + " for cluster version " + clusterVersion + " using fallback"); } - let arch = null + let arch = null; if (process.arch == "x64") { - arch = "amd64" + arch = "amd64"; } else if (process.arch == "x86" || process.arch == "ia32") { - arch = "386" + arch = "386"; } else { - arch = process.arch + arch = process.arch; } - const platformName = isWindows ? "windows" : process.platform - const binaryName = isWindows ? "kubectl.exe" : "kubectl" + const platformName = isWindows ? "windows" : process.platform; + const binaryName = isWindows ? "kubectl.exe" : "kubectl"; - this.url = `${this.getDownloadMirror()}/v${this.kubectlVersion}/bin/${platformName}/${arch}/${binaryName}` + this.url = `${this.getDownloadMirror()}/v${this.kubectlVersion}/bin/${platformName}/${arch}/${binaryName}`; - this.dirname = path.normalize(path.join(this.getDownloadDir(), this.kubectlVersion)) - this.path = path.join(this.dirname, binaryName) + this.dirname = path.normalize(path.join(this.getDownloadDir(), this.kubectlVersion)); + this.path = path.join(this.dirname, binaryName); } public getBundledPath() { - return bundledKubectlPath() + return bundledKubectlPath(); } public getPathFromPreferences() { - return userStore.preferences?.kubectlBinariesPath || this.getBundledPath() + return userStore.preferences?.kubectlBinariesPath || this.getBundledPath(); } protected getDownloadDir() { if (userStore.preferences?.downloadBinariesPath) { - return path.join(userStore.preferences.downloadBinariesPath, "kubectl") + return path.join(userStore.preferences.downloadBinariesPath, "kubectl"); } - return Kubectl.kubectlDir + return Kubectl.kubectlDir; } public async getPath(bundled = false): Promise { if (userStore.preferences?.downloadKubectlBinaries === false) { - return this.getPathFromPreferences() + return this.getPathFromPreferences(); } // return binary name if bundled path is not functional if (!await this.checkBinary(this.getBundledPath(), false)) { - Kubectl.invalidBundle = true - return path.basename(this.getBundledPath()) + Kubectl.invalidBundle = true; + return path.basename(this.getBundledPath()); } try { if (!await this.ensureKubectl()) { - logger.error("Failed to ensure kubectl, fallback to the bundled version") - return this.getBundledPath() + logger.error("Failed to ensure kubectl, fallback to the bundled version"); + return this.getBundledPath(); } - return this.path + return this.path; } catch (err) { - logger.error("Failed to ensure kubectl, fallback to the bundled version") - logger.error(err) - return this.getBundledPath() + logger.error("Failed to ensure kubectl, fallback to the bundled version"); + logger.error(err); + return this.getBundledPath(); } } public async binDir() { try { - await this.ensureKubectl() - await this.writeInitScripts() - return this.dirname + await this.ensureKubectl(); + await this.writeInitScripts(); + return this.dirname; } catch (err) { - logger.error(err) - return "" + logger.error(err); + return ""; } } public async checkBinary(path: string, checkVersion = true) { - const exists = await pathExists(path) + const exists = await pathExists(path); if (exists) { try { - const { stdout } = await promiseExec(`"${path}" version --client=true -o json`) - const output = JSON.parse(stdout) + const { stdout } = await promiseExec(`"${path}" version --client=true -o json`); + const output = JSON.parse(stdout); if (!checkVersion) { - return true + return true; } - let version: string = output.clientVersion.gitVersion + let version: string = output.clientVersion.gitVersion; if (version[0] === 'v') { - version = version.slice(1) + version = version.slice(1); } if (version === this.kubectlVersion) { - logger.debug(`Local kubectl is version ${this.kubectlVersion}`) - return true + logger.debug(`Local kubectl is version ${this.kubectlVersion}`); + return true; } - logger.error(`Local kubectl is version ${version}, expected ${this.kubectlVersion}, unlinking`) + logger.error(`Local kubectl is version ${version}, expected ${this.kubectlVersion}, unlinking`); } catch (err) { - logger.error(`Local kubectl failed to run properly (${err.message}), unlinking`) + logger.error(`Local kubectl failed to run properly (${err.message}), unlinking`); } - await fs.promises.unlink(this.path) + await fs.promises.unlink(this.path); } - return false + return false; } protected async checkBundled(): Promise { if (this.kubectlVersion === Kubectl.bundledKubectlVersion) { try { - const exist = await pathExists(this.path) + const exist = await pathExists(this.path); if (!exist) { - await fs.promises.copyFile(this.getBundledPath(), this.path) - await fs.promises.chmod(this.path, 0o755) + await fs.promises.copyFile(this.getBundledPath(), this.path); + await fs.promises.chmod(this.path, 0o755); } - return true + return true; } catch (err) { - logger.error("Could not copy the bundled kubectl to app-data: " + err) - return false + logger.error("Could not copy the bundled kubectl to app-data: " + err); + return false; } } else { - return false + return false; } } public async ensureKubectl(): Promise { if (userStore.preferences?.downloadKubectlBinaries === false) { - return true + return true; } if (Kubectl.invalidBundle) { - logger.error(`Detected invalid bundle binary, returning ...`) - return false + logger.error(`Detected invalid bundle binary, returning ...`); + return false; } - await ensureDir(this.dirname, 0o755) + await ensureDir(this.dirname, 0o755); return lockFile.lock(this.dirname).then(async (release) => { - logger.debug(`Acquired a lock for ${this.kubectlVersion}`) - const bundled = await this.checkBundled() - let isValid = await this.checkBinary(this.path, !bundled) + logger.debug(`Acquired a lock for ${this.kubectlVersion}`); + const bundled = await this.checkBundled(); + let isValid = await this.checkBinary(this.path, !bundled); if (!isValid && !bundled) { await this.downloadKubectl().catch((error) => { - logger.error(error) - logger.debug(`Releasing lock for ${this.kubectlVersion}`) - release() - return false + logger.error(error); + logger.debug(`Releasing lock for ${this.kubectlVersion}`); + release(); + return false; }); - isValid = !await this.checkBinary(this.path, false) + isValid = !await this.checkBinary(this.path, false); } if (!isValid) { - logger.debug(`Releasing lock for ${this.kubectlVersion}`) - release() - return false + logger.debug(`Releasing lock for ${this.kubectlVersion}`); + release(); + return false; } - logger.debug(`Releasing lock for ${this.kubectlVersion}`) - release() - return true + logger.debug(`Releasing lock for ${this.kubectlVersion}`); + release(); + return true; }).catch((e) => { - logger.error(`Failed to get a lock for ${this.kubectlVersion}`) - logger.error(e) - return false - }) + logger.error(`Failed to get a lock for ${this.kubectlVersion}`); + logger.error(e); + return false; + }); } public async downloadKubectl() { - await ensureDir(path.dirname(this.path), 0o755) + await ensureDir(path.dirname(this.path), 0o755); - logger.info(`Downloading kubectl ${this.kubectlVersion} from ${this.url} to ${this.path}`) + logger.info(`Downloading kubectl ${this.kubectlVersion} from ${this.url} to ${this.path}`); return new Promise((resolve, reject) => { const stream = customRequest({ url: this.url, gzip: true, }); - const file = fs.createWriteStream(this.path) + const file = fs.createWriteStream(this.path); stream.on("complete", () => { - logger.debug("kubectl binary download finished") - file.end() - }) + logger.debug("kubectl binary download finished"); + file.end(); + }); stream.on("error", (error) => { - logger.error(error) + logger.error(error); fs.unlink(this.path, () => { // do nothing - }) - reject(error) - }) + }); + reject(error); + }); file.on("close", () => { - logger.debug("kubectl binary download closed") + logger.debug("kubectl binary download closed"); fs.chmod(this.path, 0o755, (err) => { if (err) reject(err); - }) - resolve() - }) - stream.pipe(file) - }) + }); + resolve(); + }); + stream.pipe(file); + }); } protected async writeInitScripts() { - const kubectlPath = userStore.preferences?.downloadKubectlBinaries ? this.dirname : path.dirname(this.getPathFromPreferences()) - const helmPath = helmCli.getBinaryDir() + const kubectlPath = userStore.preferences?.downloadKubectlBinaries ? this.dirname : path.dirname(this.getPathFromPreferences()); + const helmPath = helmCli.getBinaryDir(); const fsPromises = fs.promises; - const bashScriptPath = path.join(this.dirname, '.bash_set_path') + const bashScriptPath = path.join(this.dirname, '.bash_set_path'); - let bashScript = "" + initScriptVersionString - bashScript += "tempkubeconfig=\"$KUBECONFIG\"\n" - bashScript += "test -f \"/etc/profile\" && . \"/etc/profile\"\n" - bashScript += "if test -f \"$HOME/.bash_profile\"; then\n" - bashScript += " . \"$HOME/.bash_profile\"\n" - bashScript += "elif test -f \"$HOME/.bash_login\"; then\n" - bashScript += " . \"$HOME/.bash_login\"\n" - bashScript += "elif test -f \"$HOME/.profile\"; then\n" - bashScript += " . \"$HOME/.profile\"\n" - bashScript += "fi\n" - bashScript += `export PATH="${helmPath}:${kubectlPath}:$PATH"\n` - bashScript += "export KUBECONFIG=\"$tempkubeconfig\"\n" + let bashScript = "" + initScriptVersionString; + bashScript += "tempkubeconfig=\"$KUBECONFIG\"\n"; + bashScript += "test -f \"/etc/profile\" && . \"/etc/profile\"\n"; + bashScript += "if test -f \"$HOME/.bash_profile\"; then\n"; + bashScript += " . \"$HOME/.bash_profile\"\n"; + bashScript += "elif test -f \"$HOME/.bash_login\"; then\n"; + bashScript += " . \"$HOME/.bash_login\"\n"; + bashScript += "elif test -f \"$HOME/.profile\"; then\n"; + bashScript += " . \"$HOME/.profile\"\n"; + bashScript += "fi\n"; + bashScript += `export PATH="${helmPath}:${kubectlPath}:$PATH"\n`; + bashScript += "export KUBECONFIG=\"$tempkubeconfig\"\n"; - bashScript += "NO_PROXY=\",${NO_PROXY:-localhost},\"\n" - bashScript += "NO_PROXY=\"${NO_PROXY//,localhost,/,}\"\n" - bashScript += "NO_PROXY=\"${NO_PROXY//,127.0.0.1,/,}\"\n" - bashScript += "NO_PROXY=\"localhost,127.0.0.1${NO_PROXY%,}\"\n" - bashScript += "export NO_PROXY\n" - bashScript += "unset tempkubeconfig\n" - await fsPromises.writeFile(bashScriptPath, bashScript.toString(), { mode: 0o644 }) + bashScript += "NO_PROXY=\",${NO_PROXY:-localhost},\"\n"; + bashScript += "NO_PROXY=\"${NO_PROXY//,localhost,/,}\"\n"; + bashScript += "NO_PROXY=\"${NO_PROXY//,127.0.0.1,/,}\"\n"; + bashScript += "NO_PROXY=\"localhost,127.0.0.1${NO_PROXY%,}\"\n"; + bashScript += "export NO_PROXY\n"; + bashScript += "unset tempkubeconfig\n"; + await fsPromises.writeFile(bashScriptPath, bashScript.toString(), { mode: 0o644 }); - const zshScriptPath = path.join(this.dirname, '.zlogin') + const zshScriptPath = path.join(this.dirname, '.zlogin'); - let zshScript = "" + initScriptVersionString + let zshScript = "" + initScriptVersionString; - zshScript += "tempkubeconfig=\"$KUBECONFIG\"\n" + zshScript += "tempkubeconfig=\"$KUBECONFIG\"\n"; // restore previous ZDOTDIR - zshScript += "export ZDOTDIR=\"$OLD_ZDOTDIR\"\n" + zshScript += "export ZDOTDIR=\"$OLD_ZDOTDIR\"\n"; // source all the files - zshScript += "test -f \"$OLD_ZDOTDIR/.zshenv\" && . \"$OLD_ZDOTDIR/.zshenv\"\n" - zshScript += "test -f \"$OLD_ZDOTDIR/.zprofile\" && . \"$OLD_ZDOTDIR/.zprofile\"\n" - zshScript += "test -f \"$OLD_ZDOTDIR/.zlogin\" && . \"$OLD_ZDOTDIR/.zlogin\"\n" - zshScript += "test -f \"$OLD_ZDOTDIR/.zshrc\" && . \"$OLD_ZDOTDIR/.zshrc\"\n" + zshScript += "test -f \"$OLD_ZDOTDIR/.zshenv\" && . \"$OLD_ZDOTDIR/.zshenv\"\n"; + zshScript += "test -f \"$OLD_ZDOTDIR/.zprofile\" && . \"$OLD_ZDOTDIR/.zprofile\"\n"; + zshScript += "test -f \"$OLD_ZDOTDIR/.zlogin\" && . \"$OLD_ZDOTDIR/.zlogin\"\n"; + zshScript += "test -f \"$OLD_ZDOTDIR/.zshrc\" && . \"$OLD_ZDOTDIR/.zshrc\"\n"; // voodoo to replace any previous occurrences of kubectl path in the PATH - zshScript += `kubectlpath=\"${kubectlPath}"\n` - zshScript += `helmpath=\"${helmPath}"\n` - zshScript += "p=\":$kubectlpath:\"\n" - zshScript += "d=\":$PATH:\"\n" - zshScript += "d=${d//$p/:}\n" - zshScript += "d=${d/#:/}\n" - zshScript += "export PATH=\"$helmpath:$kubectlpath:${d/%:/}\"\n" - zshScript += "export KUBECONFIG=\"$tempkubeconfig\"\n" - zshScript += "NO_PROXY=\",${NO_PROXY:-localhost},\"\n" - zshScript += "NO_PROXY=\"${NO_PROXY//,localhost,/,}\"\n" - zshScript += "NO_PROXY=\"${NO_PROXY//,127.0.0.1,/,}\"\n" - zshScript += "NO_PROXY=\"localhost,127.0.0.1${NO_PROXY%,}\"\n" - zshScript += "export NO_PROXY\n" - zshScript += "unset tempkubeconfig\n" - zshScript += "unset OLD_ZDOTDIR\n" - await fsPromises.writeFile(zshScriptPath, zshScript.toString(), { mode: 0o644 }) + zshScript += `kubectlpath=\"${kubectlPath}"\n`; + zshScript += `helmpath=\"${helmPath}"\n`; + zshScript += "p=\":$kubectlpath:\"\n"; + zshScript += "d=\":$PATH:\"\n"; + zshScript += "d=${d//$p/:}\n"; + zshScript += "d=${d/#:/}\n"; + zshScript += "export PATH=\"$helmpath:$kubectlpath:${d/%:/}\"\n"; + zshScript += "export KUBECONFIG=\"$tempkubeconfig\"\n"; + zshScript += "NO_PROXY=\",${NO_PROXY:-localhost},\"\n"; + zshScript += "NO_PROXY=\"${NO_PROXY//,localhost,/,}\"\n"; + zshScript += "NO_PROXY=\"${NO_PROXY//,127.0.0.1,/,}\"\n"; + zshScript += "NO_PROXY=\"localhost,127.0.0.1${NO_PROXY%,}\"\n"; + zshScript += "export NO_PROXY\n"; + zshScript += "unset tempkubeconfig\n"; + zshScript += "unset OLD_ZDOTDIR\n"; + await fsPromises.writeFile(zshScriptPath, zshScript.toString(), { mode: 0o644 }); } protected getDownloadMirror() { - const mirror = packageMirrors.get(userStore.preferences?.downloadMirror) + const mirror = packageMirrors.get(userStore.preferences?.downloadMirror); if (mirror) { - return mirror + return mirror; } - return packageMirrors.get("default") // MacOS packages are only available from default + return packageMirrors.get("default"); // MacOS packages are only available from default } } diff --git a/src/main/kubectl_spec.ts b/src/main/kubectl_spec.ts index ade999c082..9d5a5d1e1d 100644 --- a/src/main/kubectl_spec.ts +++ b/src/main/kubectl_spec.ts @@ -1,5 +1,5 @@ -import packageInfo from "../../package.json" -import path from "path" +import packageInfo from "../../package.json"; +import path from "path"; import { Kubectl } from "../../src/main/kubectl"; import { isWindows } from "../common/vars"; @@ -7,39 +7,39 @@ jest.mock("../common/user-store"); describe("kubectlVersion", () => { it("returns bundled version if exactly same version used", async () => { - const kubectl = new Kubectl(Kubectl.bundled().kubectlVersion) - expect(kubectl.kubectlVersion).toBe(Kubectl.bundled().kubectlVersion) - }) + const kubectl = new Kubectl(Kubectl.bundled().kubectlVersion); + expect(kubectl.kubectlVersion).toBe(Kubectl.bundled().kubectlVersion); + }); it("returns bundled version if same major.minor version is used", async () => { const { bundledKubectlVersion } = packageInfo.config; const kubectl = new Kubectl(bundledKubectlVersion); - expect(kubectl.kubectlVersion).toBe(Kubectl.bundled().kubectlVersion) - }) -}) + expect(kubectl.kubectlVersion).toBe(Kubectl.bundled().kubectlVersion); + }); +}); describe("getPath()", () => { it("returns path to downloaded kubectl binary", async () => { const { bundledKubectlVersion } = packageInfo.config; const kubectl = new Kubectl(bundledKubectlVersion); - const kubectlPath = await kubectl.getPath() - let binaryName = "kubectl" + const kubectlPath = await kubectl.getPath(); + let binaryName = "kubectl"; if (isWindows) { - binaryName += ".exe" + binaryName += ".exe"; } - const expectedPath = path.join(Kubectl.kubectlDir, Kubectl.bundledKubectlVersion, binaryName) - expect(kubectlPath).toBe(expectedPath) - }) + const expectedPath = path.join(Kubectl.kubectlDir, Kubectl.bundledKubectlVersion, binaryName); + expect(kubectlPath).toBe(expectedPath); + }); it("returns plain binary name if bundled kubectl is non-functional", async () => { const { bundledKubectlVersion } = packageInfo.config; const kubectl = new Kubectl(bundledKubectlVersion); - jest.spyOn(kubectl, "getBundledPath").mockReturnValue("/invalid/path/kubectl") - const kubectlPath = await kubectl.getPath() - let binaryName = "kubectl" + jest.spyOn(kubectl, "getBundledPath").mockReturnValue("/invalid/path/kubectl"); + const kubectlPath = await kubectl.getPath(); + let binaryName = "kubectl"; if (isWindows) { - binaryName += ".exe" + binaryName += ".exe"; } - expect(kubectlPath).toBe(binaryName) - }) -}) + expect(kubectlPath).toBe(binaryName); + }); +}); diff --git a/src/main/lens-api.ts b/src/main/lens-api.ts index a0a7361a68..fafeffce91 100644 --- a/src/main/lens-api.ts +++ b/src/main/lens-api.ts @@ -2,16 +2,16 @@ import http from "http"; export abstract class LensApi { protected respondJson(res: http.ServerResponse, content: {}, status = 200) { - this.respond(res, JSON.stringify(content), "application/json", status) + this.respond(res, JSON.stringify(content), "application/json", status); } protected respondText(res: http.ServerResponse, content: string, status = 200) { - this.respond(res, content, "text/plain", status) + this.respond(res, content, "text/plain", status); } protected respond(res: http.ServerResponse, content: string, contentType: string, status = 200) { - res.setHeader("Content-Type", contentType) - res.statusCode = status - res.end(content) + res.setHeader("Content-Type", contentType); + res.statusCode = status; + res.end(content); } } diff --git a/src/main/lens-binary.ts b/src/main/lens-binary.ts index dd6f2aa058..fc6b59ee74 100644 --- a/src/main/lens-binary.ts +++ b/src/main/lens-binary.ts @@ -1,10 +1,10 @@ -import path from "path" -import fs from "fs" -import request from "request" -import { ensureDir, pathExists } from "fs-extra" -import * as tar from "tar" +import path from "path"; +import fs from "fs"; +import request from "request"; +import { ensureDir, pathExists } from "fs-extra"; +import * as tar from "tar"; import { isWindows } from "../common/vars"; -import winston from "winston" +import winston from "winston"; export type LensBinaryOpts = { version: string; @@ -12,177 +12,177 @@ export type LensBinaryOpts = { originalBinaryName: string; newBinaryName?: string; requestOpts?: request.Options; -} +}; export class LensBinary { - public binaryVersion: string - protected directory: string - protected url: string + public binaryVersion: string; + protected directory: string; + protected url: string; protected path: string; protected tarPath: string; - protected dirname: string - protected binaryName: string - protected platformName: string - protected arch: string - protected originalBinaryName: string - protected requestOpts: request.Options - protected logger: Console | winston.Logger + protected dirname: string; + protected binaryName: string; + protected platformName: string; + protected arch: string; + protected originalBinaryName: string; + protected requestOpts: request.Options; + protected logger: Console | winston.Logger; constructor(opts: LensBinaryOpts) { - const baseDir = opts.baseDir - this.originalBinaryName = opts.originalBinaryName - this.binaryName = opts.newBinaryName || opts.originalBinaryName - this.binaryVersion = opts.version - this.requestOpts = opts.requestOpts - this.logger = console - let arch = null + const baseDir = opts.baseDir; + this.originalBinaryName = opts.originalBinaryName; + this.binaryName = opts.newBinaryName || opts.originalBinaryName; + this.binaryVersion = opts.version; + this.requestOpts = opts.requestOpts; + this.logger = console; + let arch = null; if (process.arch == "x64") { - arch = "amd64" + arch = "amd64"; } else if (process.arch == "x86" || process.arch == "ia32") { - arch = "386" + arch = "386"; } else { - arch = process.arch + arch = process.arch; } - this.arch = arch - this.platformName = isWindows ? "windows" : process.platform - this.dirname = path.normalize(path.join(baseDir, this.binaryName)) + this.arch = arch; + this.platformName = isWindows ? "windows" : process.platform; + this.dirname = path.normalize(path.join(baseDir, this.binaryName)); if (isWindows) { - this.binaryName = this.binaryName + ".exe" - this.originalBinaryName = this.originalBinaryName + ".exe" + this.binaryName = this.binaryName + ".exe"; + this.originalBinaryName = this.originalBinaryName + ".exe"; } - const tarName = this.getTarName() + const tarName = this.getTarName(); if (tarName) { - this.tarPath = path.join(this.dirname, tarName) + this.tarPath = path.join(this.dirname, tarName); } } public setLogger(logger: Console | winston.Logger) { - this.logger = logger + this.logger = logger; } protected binaryDir() { - throw new Error("binaryDir not implemented") + throw new Error("binaryDir not implemented"); } public async binaryPath() { - await this.ensureBinary() - return this.getBinaryPath() + await this.ensureBinary(); + return this.getBinaryPath(); } protected getTarName(): string | null { - return null + return null; } protected getUrl() { - return "" + return ""; } protected getBinaryPath() { - return "" + return ""; } protected getOriginalBinaryPath() { - return "" + return ""; } public getBinaryDir() { - return path.dirname(this.getBinaryPath()) + return path.dirname(this.getBinaryPath()); } public async binDir() { try { - await this.ensureBinary() - return this.dirname + await this.ensureBinary(); + return this.dirname; } catch (err) { - this.logger.error(err) - return "" + this.logger.error(err); + return ""; } } protected async checkBinary() { - const exists = await pathExists(this.getBinaryPath()) - return exists + const exists = await pathExists(this.getBinaryPath()); + return exists; } public async ensureBinary() { - const isValid = await this.checkBinary() + const isValid = await this.checkBinary(); if (!isValid) { await this.downloadBinary().catch((error) => { - this.logger.error(error) + this.logger.error(error); }); - if (this.tarPath) await this.untarBinary() - if (this.originalBinaryName != this.binaryName) await this.renameBinary() - this.logger.info(`${this.originalBinaryName} has been downloaded to ${this.getBinaryPath()}`) + if (this.tarPath) await this.untarBinary(); + if (this.originalBinaryName != this.binaryName) await this.renameBinary(); + this.logger.info(`${this.originalBinaryName} has been downloaded to ${this.getBinaryPath()}`); } } protected async untarBinary() { return new Promise((resolve, reject) => { - this.logger.debug(`Extracting ${this.originalBinaryName} binary`) + this.logger.debug(`Extracting ${this.originalBinaryName} binary`); tar.x({ file: this.tarPath, cwd: this.dirname }).then((_ => { - resolve() - })) - }) + resolve(); + })); + }); } protected async renameBinary() { return new Promise((resolve, reject) => { - this.logger.debug(`Renaming ${this.originalBinaryName} binary to ${this.binaryName}`) + this.logger.debug(`Renaming ${this.originalBinaryName} binary to ${this.binaryName}`); fs.rename(this.getOriginalBinaryPath(), this.getBinaryPath(), (err) => { if (err) { - reject(err) + reject(err); } else { - resolve() + resolve(); } - }) - }) + }); + }); } protected async downloadBinary() { - const binaryPath = this.tarPath || this.getBinaryPath() - await ensureDir(this.getBinaryDir(), 0o755) + const binaryPath = this.tarPath || this.getBinaryPath(); + await ensureDir(this.getBinaryDir(), 0o755); - const file = fs.createWriteStream(binaryPath) - const url = this.getUrl() + const file = fs.createWriteStream(binaryPath); + const url = this.getUrl(); - this.logger.info(`Downloading ${this.originalBinaryName} ${this.binaryVersion} from ${url} to ${binaryPath}`) + this.logger.info(`Downloading ${this.originalBinaryName} ${this.binaryVersion} from ${url} to ${binaryPath}`); const requestOpts: request.UriOptions & request.CoreOptions = { uri: url, gzip: true, ...this.requestOpts - } + }; - const stream = request(requestOpts) + const stream = request(requestOpts); stream.on("complete", () => { - this.logger.info(`Download of ${this.originalBinaryName} finished`) - file.end() - }) + this.logger.info(`Download of ${this.originalBinaryName} finished`); + file.end(); + }); stream.on("error", (error) => { - this.logger.error(error) + this.logger.error(error); fs.unlink(binaryPath, () => { // do nothing - }) - throw(error) - }) + }); + throw(error); + }); return new Promise((resolve, reject) => { file.on("close", () => { - this.logger.debug(`${this.originalBinaryName} binary download closed`) + this.logger.debug(`${this.originalBinaryName} binary download closed`); if (!this.tarPath) fs.chmod(binaryPath, 0o755, (err) => { if (err) reject(err); - }) - resolve() - }) - stream.pipe(file) - }) + }); + resolve(); + }); + stream.pipe(file); + }); } } diff --git a/src/main/lens-proxy.ts b/src/main/lens-proxy.ts index 7f0b14721d..03b1b15d29 100644 --- a/src/main/lens-proxy.ts +++ b/src/main/lens-proxy.ts @@ -3,27 +3,27 @@ import http from "http"; import spdy from "spdy"; import httpProxy from "http-proxy"; import url from "url"; -import * as WebSocket from "ws" -import { apiPrefix, apiKubePrefix } from "../common/vars" +import * as WebSocket from "ws"; +import { apiPrefix, apiKubePrefix } from "../common/vars"; import { openShell } from "./node-shell-session"; -import { Router } from "./router" -import { ClusterManager } from "./cluster-manager" +import { Router } from "./router"; +import { ClusterManager } from "./cluster-manager"; import { ContextHandler } from "./context-handler"; -import logger from "./logger" +import logger from "./logger"; export class LensProxy { - protected origin: string - protected proxyServer: http.Server - protected router: Router - protected closed = false - protected retryCounters = new Map() + protected origin: string; + protected proxyServer: http.Server; + protected router: Router; + protected closed = false; + protected retryCounters = new Map(); static create(port: number, clusterManager: ClusterManager) { return new LensProxy(port, clusterManager).listen(); } private constructor(protected port: number, protected clusterManager: ClusterManager) { - this.origin = `http://localhost:${port}` + this.origin = `http://localhost:${port}`; this.router = new Router(); } @@ -35,8 +35,8 @@ export class LensProxy { close() { logger.info("Closing proxy server"); - this.proxyServer.close() - this.closed = true + this.proxyServer.close(); + this.closed = true; } protected buildCustomProxy(): http.Server { @@ -47,66 +47,66 @@ export class LensProxy { protocols: ["http/1.1", "spdy/3.1"] } }, (req: http.IncomingMessage, res: http.ServerResponse) => { - this.handleRequest(proxy, req, res) - }) + this.handleRequest(proxy, req, res); + }); spdyProxy.on("upgrade", (req: http.IncomingMessage, socket: net.Socket, head: Buffer) => { if (req.url.startsWith(`${apiPrefix}?`)) { - this.handleWsUpgrade(req, socket, head) + this.handleWsUpgrade(req, socket, head); } else { - this.handleProxyUpgrade(proxy, req, socket, head) + this.handleProxyUpgrade(proxy, req, socket, head); } - }) + }); spdyProxy.on("error", (err) => { - logger.error("proxy error", err) - }) - return spdyProxy + logger.error("proxy error", err); + }); + return spdyProxy; } protected async handleProxyUpgrade(proxy: httpProxy, req: http.IncomingMessage, socket: net.Socket, head: Buffer) { - const cluster = this.clusterManager.getClusterForRequest(req) + const cluster = this.clusterManager.getClusterForRequest(req); if (cluster) { - const proxyUrl = await cluster.contextHandler.resolveAuthProxyUrl() + req.url.replace(apiKubePrefix, "") - const apiUrl = url.parse(cluster.apiUrl) - const pUrl = url.parse(proxyUrl) - const connectOpts = { port: parseInt(pUrl.port), host: pUrl.hostname } - const proxySocket = new net.Socket() + const proxyUrl = await cluster.contextHandler.resolveAuthProxyUrl() + req.url.replace(apiKubePrefix, ""); + const apiUrl = url.parse(cluster.apiUrl); + const pUrl = url.parse(proxyUrl); + const connectOpts = { port: parseInt(pUrl.port), host: pUrl.hostname }; + const proxySocket = new net.Socket(); proxySocket.connect(connectOpts, () => { - proxySocket.write(`${req.method} ${pUrl.path} HTTP/1.1\r\n`) - proxySocket.write(`Host: ${apiUrl.host}\r\n`) + proxySocket.write(`${req.method} ${pUrl.path} HTTP/1.1\r\n`); + proxySocket.write(`Host: ${apiUrl.host}\r\n`); for (let i = 0; i < req.rawHeaders.length; i += 2) { - const key = req.rawHeaders[i] + const key = req.rawHeaders[i]; if (key !== "Host" && key !== "Authorization") { - proxySocket.write(`${req.rawHeaders[i]}: ${req.rawHeaders[i+1]}\r\n`) + proxySocket.write(`${req.rawHeaders[i]}: ${req.rawHeaders[i+1]}\r\n`); } } - proxySocket.write("\r\n") - proxySocket.write(head) - }) + proxySocket.write("\r\n"); + proxySocket.write(head); + }); - proxySocket.setKeepAlive(true) - socket.setKeepAlive(true) - proxySocket.setTimeout(0) - socket.setTimeout(0) + proxySocket.setKeepAlive(true); + socket.setKeepAlive(true); + proxySocket.setTimeout(0); + socket.setTimeout(0); proxySocket.on('data', function (chunk) { - socket.write(chunk) - }) + socket.write(chunk); + }); proxySocket.on('end', function () { - socket.end() - }) + socket.end(); + }); proxySocket.on('error', function (err) { socket.write("HTTP/" + req.httpVersion + " 500 Connection error\r\n\r\n"); - socket.end() - }) + socket.end(); + }); socket.on('data', function (chunk) { - proxySocket.write(chunk) - }) + proxySocket.write(chunk); + }); socket.on('end', function () { - proxySocket.end() - }) + proxySocket.end(); + }); socket.on('error', function () { - proxySocket.end() - }) + proxySocket.end(); + }); } } @@ -120,29 +120,29 @@ export class LensProxy { logger.debug("Failed proxy to target: " + JSON.stringify(target, null, 2)); if (req.method === "GET" && (!res.statusCode || res.statusCode >= 500)) { const reqId = this.getRequestId(req); - const retryCount = this.retryCounters.get(reqId) || 0 - const timeoutMs = retryCount * 250 + const retryCount = this.retryCounters.get(reqId) || 0; + const timeoutMs = retryCount * 250; if (retryCount < 20) { - logger.debug(`Retrying proxy request to url: ${reqId}`) + logger.debug(`Retrying proxy request to url: ${reqId}`); setTimeout(() => { - this.retryCounters.set(reqId, retryCount + 1) - this.handleRequest(proxy, req, res) - }, timeoutMs) + this.retryCounters.set(reqId, retryCount + 1); + this.handleRequest(proxy, req, res); + }, timeoutMs); } } } try { - res.writeHead(500).end("Oops, something went wrong.") + res.writeHead(500).end("Oops, something went wrong."); } catch (e) { - logger.error(`[LENS-PROXY]: Failed to write headers: `, e) + logger.error(`[LENS-PROXY]: Failed to write headers: `, e); } - }) + }); return proxy; } protected createWsListener(): WebSocket.Server { - const ws = new WebSocket.Server({ noServer: true }) + const ws = new WebSocket.Server({ noServer: true }); return ws.on("connection", ((socket: WebSocket, req: http.IncomingMessage) => { const cluster = this.clusterManager.getClusterForRequest(req); const nodeParam = url.parse(req.url, true).query["node"]?.toString(); @@ -152,10 +152,10 @@ export class LensProxy { protected async getProxyTarget(req: http.IncomingMessage, contextHandler: ContextHandler): Promise { if (req.url.startsWith(apiKubePrefix)) { - delete req.headers.authorization - req.url = req.url.replace(apiKubePrefix, "") - const isWatchRequest = req.url.includes("watch=") - return await contextHandler.getApiTarget(isWatchRequest) + delete req.headers.authorization; + req.url = req.url.replace(apiKubePrefix, ""); + const isWatchRequest = req.url.includes("watch="); + return await contextHandler.getApiTarget(isWatchRequest); } } @@ -164,9 +164,9 @@ export class LensProxy { } protected async handleRequest(proxy: httpProxy, req: http.IncomingMessage, res: http.ServerResponse) { - const cluster = this.clusterManager.getClusterForRequest(req) + const cluster = this.clusterManager.getClusterForRequest(req); if (cluster) { - const proxyTarget = await this.getProxyTarget(req, cluster.contextHandler) + const proxyTarget = await this.getProxyTarget(req, cluster.contextHandler); if (proxyTarget) { // allow to fetch apis in "clusterId.localhost:port" from "localhost:port" res.setHeader("Access-Control-Allow-Origin", this.origin); diff --git a/src/main/logger.ts b/src/main/logger.ts index f4e2707c27..81d61e8002 100644 --- a/src/main/logger.ts +++ b/src/main/logger.ts @@ -1,13 +1,13 @@ import { app, remote } from "electron"; -import winston from "winston" +import winston from "winston"; import { isDebugging } from "../common/vars"; -const logLevel = process.env.LOG_LEVEL ? process.env.LOG_LEVEL : isDebugging ? "debug" : "info" +const logLevel = process.env.LOG_LEVEL ? process.env.LOG_LEVEL : isDebugging ? "debug" : "info"; const consoleOptions: winston.transports.ConsoleTransportOptions = { handleExceptions: false, level: logLevel, -} +}; const fileOptions: winston.transports.FileTransportOptions = { handleExceptions: false, @@ -17,7 +17,7 @@ const fileOptions: winston.transports.FileTransportOptions = { maxsize: 16 * 1024, maxFiles: 16, tailable: true, -} +}; const logger = winston.createLogger({ format: winston.format.combine( @@ -30,4 +30,4 @@ const logger = winston.createLogger({ ], }); -export default logger +export default logger; diff --git a/src/main/menu.ts b/src/main/menu.ts index 14525581b8..99a0d0bb55 100644 --- a/src/main/menu.ts +++ b/src/main/menu.ts @@ -1,4 +1,4 @@ -import { app, BrowserWindow, dialog, ipcMain, IpcMainEvent, Menu, MenuItem, MenuItemConstructorOptions, webContents, shell } from "electron" +import { app, BrowserWindow, dialog, ipcMain, IpcMainEvent, Menu, MenuItem, MenuItemConstructorOptions, webContents, shell } from "electron"; import { autorun } from "mobx"; import { WindowManager } from "./window-manager"; import { appName, isMac, isWindows, isTestEnv } from "../common/vars"; @@ -11,7 +11,7 @@ import { menuRegistry } from "../extensions/registries/menu-registry"; import logger from "./logger"; import { exitApp } from "./exit-app"; -export type MenuTopId = "mac" | "file" | "edit" | "view" | "help" +export type MenuTopId = "mac" | "file" | "edit" | "view" | "help"; export function initMenu(windowManager: WindowManager) { return autorun(() => buildMenu(windowManager), { @@ -25,14 +25,14 @@ export function showAbout(browserWindow: BrowserWindow) { `Electron: ${process.versions.electron}`, `Chrome: ${process.versions.chrome}`, `Copyright 2020 Mirantis, Inc.`, - ] + ]; dialog.showMessageBoxSync(browserWindow, { title: `${isWindows ? " ".repeat(2) : ""}${appName}`, type: "info", buttons: ["Close"], message: `Lens`, detail: appInfo.join("\r\n") - }) + }); } export function buildMenu(windowManager: WindowManager) { @@ -44,7 +44,7 @@ export function buildMenu(windowManager: WindowManager) { function activeClusterOnly(menuItems: MenuItemConstructorOptions[]) { if (!windowManager.activeClusterId) { menuItems.forEach(item => { - item.enabled = false + item.enabled = false; }); } return menuItems; @@ -61,7 +61,7 @@ export function buildMenu(windowManager: WindowManager) { { label: "About Lens", click(menuItem: MenuItem, browserWindow: BrowserWindow) { - showAbout(browserWindow) + showAbout(browserWindow); } }, { type: 'separator' }, @@ -69,14 +69,14 @@ export function buildMenu(windowManager: WindowManager) { label: 'Preferences', accelerator: 'CmdOrCtrl+,', click() { - navigate(preferencesURL()) + navigate(preferencesURL()); } }, { label: 'Extensions', accelerator: 'CmdOrCtrl+Shift+E', click() { - navigate(extensionsURL()) + navigate(extensionsURL()); } }, { type: 'separator' }, @@ -90,7 +90,7 @@ export function buildMenu(windowManager: WindowManager) { label: 'Quit', accelerator: 'Cmd+Q', click() { - exitApp() + exitApp(); } } ] @@ -103,7 +103,7 @@ export function buildMenu(windowManager: WindowManager) { label: 'Add Cluster', accelerator: 'CmdOrCtrl+Shift+A', click() { - navigate(addClusterURL()) + navigate(addClusterURL()); } }, ...activeClusterOnly([ @@ -115,7 +115,7 @@ export function buildMenu(windowManager: WindowManager) { params: { clusterId: windowManager.activeClusterId } - })) + })); } } ]), @@ -125,14 +125,14 @@ export function buildMenu(windowManager: WindowManager) { label: 'Preferences', accelerator: 'Ctrl+,', click() { - navigate(preferencesURL()) + navigate(preferencesURL()); } }, { label: 'Extensions', accelerator: 'Ctrl+Shift+E', click() { - navigate(extensionsURL()) + navigate(extensionsURL()); } } ]), @@ -147,7 +147,7 @@ export function buildMenu(windowManager: WindowManager) { label: 'Exit', accelerator: 'Alt+F4', click() { - exitApp() + exitApp(); } } ]) @@ -183,7 +183,7 @@ export function buildMenu(windowManager: WindowManager) { label: 'Forward', accelerator: 'CmdOrCtrl+]', click() { - webContents.getFocusedWebContents()?.goForward() + webContents.getFocusedWebContents()?.goForward(); } }, { @@ -209,7 +209,7 @@ export function buildMenu(windowManager: WindowManager) { { label: "What's new?", click() { - navigate(whatsNewURL()) + navigate(whatsNewURL()); }, }, { @@ -222,7 +222,7 @@ export function buildMenu(windowManager: WindowManager) { { label: "About Lens", click(menuItem: MenuItem, browserWindow: BrowserWindow) { - showAbout(browserWindow) + showAbout(browserWindow); } } ]) @@ -236,7 +236,7 @@ export function buildMenu(windowManager: WindowManager) { edit: editMenu, view: viewMenu, help: helpMenu, - } + }; // Modify menu from extensions-api menuRegistry.getItems().forEach(({ parentId, ...menuItem }) => { @@ -244,12 +244,12 @@ export function buildMenu(windowManager: WindowManager) { const topMenu = appMenu[parentId as MenuTopId].submenu as MenuItemConstructorOptions[]; topMenu.push(menuItem); } catch (err) { - logger.error(`[MENU]: can't register menu item, parentId=${parentId}`, { menuItem }) + logger.error(`[MENU]: can't register menu item, parentId=${parentId}`, { menuItem }); } - }) + }); if (!isMac) { - delete appMenu.mac + delete appMenu.mac; } const menu = Menu.buildFromTemplate(Object.values(appMenu)); @@ -259,9 +259,9 @@ export function buildMenu(windowManager: WindowManager) { // this is a workaround for the test environment (spectron) not being able to directly access // the application menus (https://github.com/electron-userland/spectron/issues/21) ipcMain.on('test-menu-item-click', (event: IpcMainEvent, ...names: string[]) => { - let menu: Menu = Menu.getApplicationMenu() + let menu: Menu = Menu.getApplicationMenu(); const parentLabels: string[] = []; - let menuItem: MenuItem + let menuItem: MenuItem; for (const name of names) { parentLabels.push(name); @@ -272,7 +272,7 @@ export function buildMenu(windowManager: WindowManager) { menu = menuItem.submenu; } - const menuPath: string = parentLabels.join(" -> ") + const menuPath: string = parentLabels.join(" -> "); if (!menuItem) { logger.info(`[MENU:test-menu-item-click] Cannot find menu item ${menuPath}`); return; diff --git a/src/main/node-shell-session.ts b/src/main/node-shell-session.ts index 9e97398327..3d48afebc5 100644 --- a/src/main/node-shell-session.ts +++ b/src/main/node-shell-session.ts @@ -1,36 +1,36 @@ -import * as WebSocket from "ws" -import * as pty from "node-pty" +import * as WebSocket from "ws"; +import * as pty from "node-pty"; import { ShellSession } from "./shell-session"; -import { v4 as uuid } from "uuid" -import * as k8s from "@kubernetes/client-node" -import { KubeConfig } from "@kubernetes/client-node" -import { Cluster } from "./cluster" +import { v4 as uuid } from "uuid"; +import * as k8s from "@kubernetes/client-node"; +import { KubeConfig } from "@kubernetes/client-node"; +import { Cluster } from "./cluster"; import logger from "./logger"; -import { appEventBus } from "../common/event-bus" +import { appEventBus } from "../common/event-bus"; export class NodeShellSession extends ShellSession { protected nodeName: string; - protected podId: string - protected kc: KubeConfig + protected podId: string; + protected kc: KubeConfig; constructor(socket: WebSocket, cluster: Cluster, nodeName: string) { - super(socket, cluster) - this.nodeName = nodeName - this.podId = `node-shell-${uuid()}` - this.kc = cluster.getProxyKubeconfig() + super(socket, cluster); + this.nodeName = nodeName; + this.podId = `node-shell-${uuid()}`; + this.kc = cluster.getProxyKubeconfig(); } public async open() { - const shell = await this.kubectl.getPath() - let args = [] + const shell = await this.kubectl.getPath(); + let args = []; if (this.createNodeShellPod(this.podId, this.nodeName)) { await this.waitForRunningPod(this.podId).catch((error) => { - this.exit(1001) - }) + this.exit(1001); + }); } - args = ["exec", "-i", "-t", "-n", "kube-system", this.podId, "--", "sh", "-c", "((clear && bash) || (clear && ash) || (clear && sh))"] + args = ["exec", "-i", "-t", "-n", "kube-system", this.podId, "--", "sh", "-c", "((clear && bash) || (clear && ash) || (clear && sh))"]; - const shellEnv = await this.getCachedShellEnv() + const shellEnv = await this.getCachedShellEnv(); this.shellProcess = pty.spawn(shell, args, { cols: 80, cwd: this.cwd() || shellEnv["HOME"], @@ -39,19 +39,19 @@ export class NodeShellSession extends ShellSession { rows: 30, }); this.running = true; - this.pipeStdout() - this.pipeStdin() - this.closeWebsocketOnProcessExit() - this.exitProcessOnWebsocketClose() + this.pipeStdout(); + this.pipeStdin(); + this.closeWebsocketOnProcessExit(); + this.exitProcessOnWebsocketClose(); - appEventBus.emit({name: "node-shell", action: "open"}) + appEventBus.emit({name: "node-shell", action: "open"}); } protected exit(code = 1000) { if (this.podId) { - this.deleteNodeShellPod() + this.deleteNodeShellPod(); } - super.exit(code) + super.exit(code); } protected async createNodeShellPod(podId: string, nodeName: string) { @@ -86,19 +86,19 @@ export class NodeShellSession extends ShellSession { } } as k8s.V1Pod; await k8sApi.createNamespacedPod("kube-system", pod).catch((error) => { - logger.error(error) - return false - }) - return true + logger.error(error); + return false; + }); + return true; } protected getKubeConfig() { if (this.kc) { - return this.kc + return this.kc; } this.kc = new k8s.KubeConfig(); - this.kc.loadFromFile(this.kubeconfigPath) - return this.kc + this.kc.loadFromFile(this.kubeconfigPath); + return this.kc; } protected waitForRunningPod(podId: string) { @@ -110,36 +110,36 @@ export class NodeShellSession extends ShellSession { // callback is called for each received object. (_type, obj) => { if (obj.metadata.name == podId && obj.status.phase === "Running") { - resolve(true) + resolve(true); } }, // done callback is called if the watch terminates normally (err) => { - logger.error(err) - reject(false) + logger.error(err); + reject(false); } ); setTimeout(() => { req.abort(); reject(false); }, 120 * 1000); - }) + }); } protected deleteNodeShellPod() { const kc = this.getKubeConfig(); const k8sApi = kc.makeApiClient(k8s.CoreV1Api); - k8sApi.deleteNamespacedPod(this.podId, "kube-system") + k8sApi.deleteNamespacedPod(this.podId, "kube-system"); } } export async function openShell(socket: WebSocket, cluster: Cluster, nodeName?: string): Promise { let shell: ShellSession; if (nodeName) { - shell = new NodeShellSession(socket, cluster, nodeName) + shell = new NodeShellSession(socket, cluster, nodeName); } else { shell = new ShellSession(socket, cluster); } - shell.open() + shell.open(); return shell; } diff --git a/src/main/port.ts b/src/main/port.ts index b253d3590a..6ba8f71695 100644 --- a/src/main/port.ts +++ b/src/main/port.ts @@ -1,15 +1,15 @@ -import net, { AddressInfo } from "net" -import logger from "./logger" +import net, { AddressInfo } from "net"; +import logger from "./logger"; // todo: check https://github.com/http-party/node-portfinder ? export async function getFreePort(): Promise { logger.debug("Lookup new free port.."); return new Promise((resolve, reject) => { - const server = net.createServer() - server.unref() + const server = net.createServer(); + server.unref(); server.on("listening", () => { - const port = (server.address() as AddressInfo).port + const port = (server.address() as AddressInfo).port; server.close(() => resolve(port)); logger.debug(`New port found: ${port}`); }); @@ -17,6 +17,6 @@ export async function getFreePort(): Promise { logger.error(`Can't resolve new port: "${error}"`); reject(error); }); - server.listen({ host: "127.0.0.1", port: 0 }) - }) + server.listen({ host: "127.0.0.1", port: 0 }); + }); } diff --git a/src/main/port_spec.ts b/src/main/port_spec.ts index c9be25e514..bf01eb5dde 100644 --- a/src/main/port_spec.ts +++ b/src/main/port_spec.ts @@ -1,5 +1,5 @@ -import { EventEmitter } from 'events' -import { getFreePort } from "./port" +import { EventEmitter } from 'events'; +import { getFreePort } from "./port"; let newPort = 0; @@ -8,24 +8,24 @@ jest.mock("net", () => { createServer() { return new class MockServer extends EventEmitter { listen = jest.fn(() => { - this.emit('listening') - return this - }) + this.emit('listening'); + return this; + }); address = () => { - newPort = Math.round(Math.random() * 10000) + newPort = Math.round(Math.random() * 10000); return { port: newPort - } - } - unref = jest.fn() - close = jest.fn(cb => cb()) - } + }; + }; + unref = jest.fn(); + close = jest.fn(cb => cb()); + }; }, - } + }; }); describe("getFreePort", () => { it("finds the next free port", async () => { return expect(getFreePort()).resolves.toEqual(newPort); - }) -}) + }); +}); diff --git a/src/main/prometheus/helm.ts b/src/main/prometheus/helm.ts index f1462931df..56d739c630 100644 --- a/src/main/prometheus/helm.ts +++ b/src/main/prometheus/helm.ts @@ -1,29 +1,29 @@ -import { PrometheusLens } from "./lens" -import { CoreV1Api } from "@kubernetes/client-node" +import { PrometheusLens } from "./lens"; +import { CoreV1Api } from "@kubernetes/client-node"; import { PrometheusService } from "./provider-registry"; -import logger from "../logger" +import logger from "../logger"; export class PrometheusHelm extends PrometheusLens { - id = "helm" - name = "Helm" - rateAccuracy = "5m" + id = "helm"; + name = "Helm"; + rateAccuracy = "5m"; public async getPrometheusService(client: CoreV1Api): Promise { - const labelSelector = "app=prometheus,component=server,heritage=Helm" + const labelSelector = "app=prometheus,component=server,heritage=Helm"; try { - const serviceList = await client.listServiceForAllNamespaces(false, "", null, labelSelector) - const service = serviceList.body.items[0] - if (!service) return + const serviceList = await client.listServiceForAllNamespaces(false, "", null, labelSelector); + const service = serviceList.body.items[0]; + if (!service) return; return { id: this.id, namespace: service.metadata.namespace, service: service.metadata.name, port: service.spec.ports[0].port - } + }; } catch(error) { - logger.warn(`PrometheusHelm: failed to list services: ${error.toString()}`) - return + logger.warn(`PrometheusHelm: failed to list services: ${error.toString()}`); + return; } } } diff --git a/src/main/prometheus/lens.ts b/src/main/prometheus/lens.ts index 4db70bf45d..76a459212d 100644 --- a/src/main/prometheus/lens.ts +++ b/src/main/prometheus/lens.ts @@ -1,24 +1,24 @@ import { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry"; import { CoreV1Api } from "@kubernetes/client-node"; -import logger from "../logger" +import logger from "../logger"; export class PrometheusLens implements PrometheusProvider { - id = "lens" - name = "Lens" - rateAccuracy = "1m" + id = "lens"; + name = "Lens"; + rateAccuracy = "1m"; public async getPrometheusService(client: CoreV1Api): Promise { try { - const resp = await client.readNamespacedService("prometheus", "lens-metrics") - const service = resp.body + const resp = await client.readNamespacedService("prometheus", "lens-metrics"); + const service = resp.body; return { id: this.id, namespace: service.metadata.namespace, service: service.metadata.name, port: service.spec.ports[0].port - } + }; } catch(error) { - logger.warn(`PrometheusLens: failed to list services: ${error.response.body.message}`) + logger.warn(`PrometheusLens: failed to list services: ${error.response.body.message}`); } } @@ -42,7 +42,7 @@ export class PrometheusLens implements PrometheusProvider { podCapacity: `sum(kube_node_status_capacity{node=~"${opts.nodes}", resource="pods"}) by (component)`, fsSize: `sum(node_filesystem_size_bytes{kubernetes_node=~"${opts.nodes}", mountpoint="/"}) by (kubernetes_node)`, fsUsage: `sum(node_filesystem_size_bytes{kubernetes_node=~"${opts.nodes}", mountpoint="/"} - node_filesystem_avail_bytes{kubernetes_node=~"${opts.nodes}", mountpoint="/"}) by (kubernetes_node)` - } + }; case 'nodes': return { memoryUsage: `sum (node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) by (kubernetes_node)`, @@ -51,7 +51,7 @@ export class PrometheusLens implements PrometheusProvider { cpuCapacity: `sum(kube_node_status_allocatable{resource="cpu"}) by (node)`, fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"}) by (kubernetes_node)`, fsUsage: `sum(node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) by (kubernetes_node)` - } + }; case 'pods': return { cpuUsage: `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, @@ -63,21 +63,21 @@ export class PrometheusLens implements PrometheusProvider { fsUsage: `sum(container_fs_usage_bytes{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}) by (${opts.selector})`, networkReceive: `sum(rate(container_network_receive_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, networkTransmit: `sum(rate(container_network_transmit_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})` - } + }; case 'pvc': return { diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`, diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)` - } + }; case 'ingress': const bytesSent = (ingress: string, statuses: string) => - `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)` + `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`; return { bytesSentSuccess: bytesSent(opts.igress, "^2\\\\d*"), bytesSentFailure: bytesSent(opts.ingres, "^5\\\\d*"), requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`, responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)` - } + }; } } } diff --git a/src/main/prometheus/operator.ts b/src/main/prometheus/operator.ts index 3d335ff554..8e27a4a6f3 100644 --- a/src/main/prometheus/operator.ts +++ b/src/main/prometheus/operator.ts @@ -3,30 +3,30 @@ import { CoreV1Api, V1Service } from "@kubernetes/client-node"; import logger from "../logger"; export class PrometheusOperator implements PrometheusProvider { - rateAccuracy = "1m" - id = "operator" - name = "Prometheus Operator" + rateAccuracy = "1m"; + id = "operator"; + name = "Prometheus Operator"; public async getPrometheusService(client: CoreV1Api): Promise { try { - let service: V1Service + let service: V1Service; for (const labelSelector of ["operated-prometheus=true", "self-monitor=true"]) { if (!service) { - const serviceList = await client.listServiceForAllNamespaces(null, null, null, labelSelector) - service = serviceList.body.items[0] + const serviceList = await client.listServiceForAllNamespaces(null, null, null, labelSelector); + service = serviceList.body.items[0]; } } - if (!service) return + if (!service) return; return { id: this.id, namespace: service.metadata.namespace, service: service.metadata.name, port: service.spec.ports[0].port - } + }; } catch(error) { - logger.warn(`PrometheusOperator: failed to list services: ${error.toString()}`) - return + logger.warn(`PrometheusOperator: failed to list services: ${error.toString()}`); + return; } } @@ -50,7 +50,7 @@ export class PrometheusOperator implements PrometheusProvider { podCapacity: `sum(kube_node_status_capacity{node=~"${opts.nodes}", resource="pods"})`, fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"})`, fsUsage: `sum(node_filesystem_size_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"} - node_filesystem_avail_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"})` - } + }; case 'nodes': return { memoryUsage: `sum((node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) * on (pod,namespace) group_left(node) kube_pod_info) by (node)`, @@ -59,7 +59,7 @@ export class PrometheusOperator implements PrometheusProvider { cpuCapacity: `sum(kube_node_status_allocatable{resource="cpu"}) by (node)`, fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info) by (node)`, fsUsage: `sum((node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) * on (pod,namespace) group_left(node) kube_pod_info) by (node)` - } + }; case 'pods': return { cpuUsage: `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",image!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, @@ -71,12 +71,12 @@ export class PrometheusOperator implements PrometheusProvider { fsUsage: `sum(container_fs_usage_bytes{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}) by (${opts.selector})`, networkReceive: `sum(rate(container_network_receive_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, networkTransmit: `sum(rate(container_network_transmit_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})` - } + }; case 'pvc': return { diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`, diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)` - } + }; case 'ingress': const bytesSent = (ingress: string, statuses: string) => `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`; @@ -85,7 +85,7 @@ export class PrometheusOperator implements PrometheusProvider { bytesSentFailure: bytesSent(opts.ingres, "^5\\\\d*"), requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`, responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)` - } + }; } } } diff --git a/src/main/prometheus/provider-registry.ts b/src/main/prometheus/provider-registry.ts index 0a4eb22e95..641b1b8cf2 100644 --- a/src/main/prometheus/provider-registry.ts +++ b/src/main/prometheus/provider-registry.ts @@ -1,4 +1,4 @@ -import { CoreV1Api } from "@kubernetes/client-node" +import { CoreV1Api } from "@kubernetes/client-node"; export type PrometheusClusterQuery = { memoryUsage: string; @@ -11,7 +11,7 @@ export type PrometheusClusterQuery = { cpuCapacity: string; podUsage: string; podCapacity: string; -} +}; export type PrometheusNodeQuery = { memoryUsage: string; @@ -20,7 +20,7 @@ export type PrometheusNodeQuery = { cpuCapacity: string; fsSize: string; fsUsage: string; -} +}; export type PrometheusPodQuery = { memoryUsage: string; @@ -32,32 +32,32 @@ export type PrometheusPodQuery = { fsUsage: string; networkReceive: string; networkTransmit: string; -} +}; export type PrometheusPvcQuery = { diskUsage: string; diskCapacity: string; -} +}; export type PrometheusIngressQuery = { bytesSentSuccess: string; bytesSentFailure: string; requestDurationSeconds: string; responseDurationSeconds: string; -} +}; export type PrometheusQueryOpts = { [key: string]: string | any; }; -export type PrometheusQuery = PrometheusNodeQuery | PrometheusClusterQuery | PrometheusPodQuery | PrometheusPvcQuery | PrometheusIngressQuery +export type PrometheusQuery = PrometheusNodeQuery | PrometheusClusterQuery | PrometheusPodQuery | PrometheusPvcQuery | PrometheusIngressQuery; export type PrometheusService = { id: string; namespace: string; service: string; port: number; -} +}; export interface PrometheusProvider { id: string; @@ -68,23 +68,23 @@ export interface PrometheusProvider { export type PrometheusProviderList = { [key: string]: PrometheusProvider; -} +}; export class PrometheusProviderRegistry { - private static prometheusProviders: PrometheusProviderList = {} + private static prometheusProviders: PrometheusProviderList = {}; static getProvider(type: string): PrometheusProvider { if (!this.prometheusProviders[type]) { throw "Unknown Prometheus provider"; } - return this.prometheusProviders[type] + return this.prometheusProviders[type]; } static registerProvider(key: string, provider: PrometheusProvider) { - this.prometheusProviders[key] = provider + this.prometheusProviders[key] = provider; } static getProviders(): PrometheusProvider[] { - return Object.values(this.prometheusProviders) + return Object.values(this.prometheusProviders); } } diff --git a/src/main/prometheus/stacklight.ts b/src/main/prometheus/stacklight.ts index 4cb946c81d..35394336d3 100644 --- a/src/main/prometheus/stacklight.ts +++ b/src/main/prometheus/stacklight.ts @@ -1,24 +1,24 @@ import { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry"; import { CoreV1Api } from "@kubernetes/client-node"; -import logger from "../logger" +import logger from "../logger"; export class PrometheusStacklight implements PrometheusProvider { - id = "stacklight" - name = "Stacklight" - rateAccuracy = "1m" + id = "stacklight"; + name = "Stacklight"; + rateAccuracy = "1m"; public async getPrometheusService(client: CoreV1Api): Promise { try { - const resp = await client.readNamespacedService("prometheus-server", "stacklight") - const service = resp.body + const resp = await client.readNamespacedService("prometheus-server", "stacklight"); + const service = resp.body; return { id: this.id, namespace: service.metadata.namespace, service: service.metadata.name, port: service.spec.ports[0].port - } + }; } catch(error) { - logger.warn(`PrometheusLens: failed to list services: ${error.response.body.message}`) + logger.warn(`PrometheusLens: failed to list services: ${error.response.body.message}`); } } @@ -42,7 +42,7 @@ export class PrometheusStacklight implements PrometheusProvider { podCapacity: `sum(kube_node_status_capacity{node=~"${opts.nodes}", resource="pods"}) by (component)`, fsSize: `sum(node_filesystem_size_bytes{node=~"${opts.nodes}", mountpoint="/"}) by (node)`, fsUsage: `sum(node_filesystem_size_bytes{node=~"${opts.nodes}", mountpoint="/"} - node_filesystem_avail_bytes{node=~"${opts.nodes}", mountpoint="/"}) by (node)` - } + }; case 'nodes': return { memoryUsage: `sum (node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) by (node)`, @@ -51,7 +51,7 @@ export class PrometheusStacklight implements PrometheusProvider { cpuCapacity: `sum(kube_node_status_allocatable{resource="cpu"}) by (node)`, fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"}) by (node)`, fsUsage: `sum(node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) by (node)` - } + }; case 'pods': return { cpuUsage: `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, @@ -63,21 +63,21 @@ export class PrometheusStacklight implements PrometheusProvider { fsUsage: `sum(container_fs_usage_bytes{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}) by (${opts.selector})`, networkReceive: `sum(rate(container_network_receive_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, networkTransmit: `sum(rate(container_network_transmit_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})` - } + }; case 'pvc': return { diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`, diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)` - } + }; case 'ingress': const bytesSent = (ingress: string, statuses: string) => - `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)` + `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`; return { bytesSentSuccess: bytesSent(opts.igress, "^2\\\\d*"), bytesSentFailure: bytesSent(opts.ingres, "^5\\\\d*"), requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`, responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)` - } + }; } } } diff --git a/src/main/promise-exec.ts b/src/main/promise-exec.ts index b3bc303165..426bca4c23 100644 --- a/src/main/promise-exec.ts +++ b/src/main/promise-exec.ts @@ -1,4 +1,4 @@ -import * as util from "util" +import * as util from "util"; import { exec } from "child_process"; -export const promiseExec = util.promisify(exec) +export const promiseExec = util.promisify(exec); diff --git a/src/main/proxy-env.ts b/src/main/proxy-env.ts index 04c62ef534..51c8286a7f 100644 --- a/src/main/proxy-env.ts +++ b/src/main/proxy-env.ts @@ -1,18 +1,18 @@ -import { app } from "electron" +import { app } from "electron"; -const switchValue = app.commandLine.getSwitchValue("proxy-server") +const switchValue = app.commandLine.getSwitchValue("proxy-server"); export function mangleProxyEnv() { - let httpsProxy = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || "" + let httpsProxy = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || ""; - delete process.env.HTTPS_PROXY - delete process.env.HTTP_PROXY + delete process.env.HTTPS_PROXY; + delete process.env.HTTP_PROXY; if (switchValue !== "") { - httpsProxy = switchValue + httpsProxy = switchValue; } if (httpsProxy !== "") { - process.env.APP_HTTPS_PROXY = httpsProxy + process.env.APP_HTTPS_PROXY = httpsProxy; } } diff --git a/src/main/resource-applier.ts b/src/main/resource-applier.ts index 41441a3f90..0f4647a60f 100644 --- a/src/main/resource-applier.ts +++ b/src/main/resource-applier.ts @@ -1,12 +1,12 @@ import type { Cluster } from "./cluster"; -import { KubernetesObject } from "@kubernetes/client-node" +import { KubernetesObject } from "@kubernetes/client-node"; import { exec } from "child_process"; import fs from "fs"; import * as yaml from "js-yaml"; import path from "path"; import * as tempy from "tempy"; -import logger from "./logger" -import { appEventBus } from "../common/event-bus" +import logger from "./logger"; +import { appEventBus } from "../common/event-bus"; import { cloneJsonObject } from "../common/utils"; export class ResourceApplier { @@ -15,58 +15,58 @@ export class ResourceApplier { async apply(resource: KubernetesObject | any): Promise { resource = this.sanitizeObject(resource); - appEventBus.emit({name: "resource", action: "apply"}) + appEventBus.emit({name: "resource", action: "apply"}); return await this.kubectlApply(yaml.safeDump(resource)); } protected async kubectlApply(content: string): Promise { const { kubeCtl } = this.cluster; - const kubectlPath = await kubeCtl.getPath() + const kubectlPath = await kubeCtl.getPath(); return new Promise((resolve, reject) => { - const fileName = tempy.file({ name: "resource.yaml" }) - fs.writeFileSync(fileName, content) - const cmd = `"${kubectlPath}" apply --kubeconfig "${this.cluster.getProxyKubeconfigPath()}" -o json -f "${fileName}"` + const fileName = tempy.file({ name: "resource.yaml" }); + fs.writeFileSync(fileName, content); + const cmd = `"${kubectlPath}" apply --kubeconfig "${this.cluster.getProxyKubeconfigPath()}" -o json -f "${fileName}"`; logger.debug("shooting manifests with: " + cmd); - const execEnv: NodeJS.ProcessEnv = Object.assign({}, process.env) - const httpsProxy = this.cluster.preferences?.httpsProxy + const execEnv: NodeJS.ProcessEnv = Object.assign({}, process.env); + const httpsProxy = this.cluster.preferences?.httpsProxy; if (httpsProxy) { - execEnv["HTTPS_PROXY"] = httpsProxy + execEnv["HTTPS_PROXY"] = httpsProxy; } exec(cmd, { env: execEnv }, (error, stdout, stderr) => { if (stderr != "") { - fs.unlinkSync(fileName) - reject(stderr) - return + fs.unlinkSync(fileName); + reject(stderr); + return; } - fs.unlinkSync(fileName) - resolve(JSON.parse(stdout)) - }) - }) + fs.unlinkSync(fileName); + resolve(JSON.parse(stdout)); + }); + }); } public async kubectlApplyAll(resources: string[]): Promise { const { kubeCtl } = this.cluster; - const kubectlPath = await kubeCtl.getPath() + const kubectlPath = await kubeCtl.getPath(); return new Promise((resolve, reject) => { - const tmpDir = tempy.directory() + const tmpDir = tempy.directory(); // Dump each resource into tmpDir resources.forEach((resource, index) => { fs.writeFileSync(path.join(tmpDir, `${index}.yaml`), resource); - }) - const cmd = `"${kubectlPath}" apply --kubeconfig "${this.cluster.getProxyKubeconfigPath()}" -o json -f "${tmpDir}"` + }); + const cmd = `"${kubectlPath}" apply --kubeconfig "${this.cluster.getProxyKubeconfigPath()}" -o json -f "${tmpDir}"`; console.log("shooting manifests with:", cmd); exec(cmd, (error, stdout, stderr) => { if (error) { reject("Error applying manifests:" + error); } if (stderr != "") { - reject(stderr) - return + reject(stderr); + return; } - resolve(stdout) - }) - }) + resolve(stdout); + }); + }); } protected sanitizeObject(resource: KubernetesObject | any) { diff --git a/src/main/router.ts b/src/main/router.ts index 230c93f09e..ed072836b9 100644 --- a/src/main/router.ts +++ b/src/main/router.ts @@ -1,12 +1,12 @@ -import Call from "@hapi/call" -import Subtext from "@hapi/subtext" -import http from "http" -import path from "path" -import { readFile } from "fs-extra" -import { Cluster } from "./cluster" +import Call from "@hapi/call"; +import Subtext from "@hapi/subtext"; +import http from "http"; +import path from "path"; +import { readFile } from "fs-extra"; +import { Cluster } from "./cluster"; import { apiPrefix, appName, publicPath, isDevelopment, webpackDevServerPort } from "../common/vars"; import { helmRoute, kubeconfigRoute, metricsRoute, portForwardRoute, resourceApplierRoute, watchRoute } from "./routes"; -import logger from "./logger" +import logger from "./logger"; export interface RouterRequestOpts { req: http.IncomingMessage; @@ -43,25 +43,25 @@ export class Router { public constructor() { this.router = new Call.Router(); - this.addRoutes() + this.addRoutes(); } public async route(cluster: Cluster, req: http.IncomingMessage, res: http.ServerResponse): Promise { const url = new URL(req.url, "http://localhost"); - const path = url.pathname - const method = req.method.toLowerCase() + const path = url.pathname; + const method = req.method.toLowerCase(); const matchingRoute = this.router.route(method, path); const routeFound = !matchingRoute.isBoom; if (routeFound) { const request = await this.getRequest({ req, res, cluster, url, params: matchingRoute.params }); - await matchingRoute.route(request) - return true + await matchingRoute.route(request); + return true; } return false; } protected async getRequest(opts: RouterRequestOpts): Promise { - const { req, res, url, cluster, params } = opts + const { req, res, url, cluster, params } = opts; const { payload } = await Subtext.parse(req, null, { parse: true, output: "data", @@ -76,7 +76,7 @@ export class Router { query: url.searchParams, payload: payload, params: params - } + }; } protected getMimeType(filename: string) { @@ -92,7 +92,7 @@ export class Router { woff2: "font/woff2", ttf: "font/ttf" }; - return mimeTypes[path.extname(filename).slice(1)] || "text/plain" + return mimeTypes[path.extname(filename).slice(1)] || "text/plain"; } async handleStaticFile(filePath: string, res: http.ServerResponse, req: http.IncomingMessage, retryCount = 0) { @@ -114,10 +114,10 @@ export class Router { res.end(); } catch (err) { if (retryCount > 5) { - logger.error("handleStaticFile:", err.toString()) - res.statusCode = 404 - res.end() - return + logger.error("handleStaticFile:", err.toString()); + res.statusCode = 404; + res.end(); + return; } this.handleStaticFile(`${publicPath}/${appName}.html`, res, req, Math.max(retryCount, 0) + 1); } @@ -131,32 +131,32 @@ export class Router { this.handleStaticFile(params.path, response, req); }); - this.router.add({ method: "get", path: `${apiPrefix}/kubeconfig/service-account/{namespace}/{account}` }, kubeconfigRoute.routeServiceAccountRoute.bind(kubeconfigRoute)) + this.router.add({ method: "get", path: `${apiPrefix}/kubeconfig/service-account/{namespace}/{account}` }, kubeconfigRoute.routeServiceAccountRoute.bind(kubeconfigRoute)); // Watch API - this.router.add({ method: "get", path: `${apiPrefix}/watch` }, watchRoute.routeWatch.bind(watchRoute)) + this.router.add({ method: "get", path: `${apiPrefix}/watch` }, watchRoute.routeWatch.bind(watchRoute)); // Metrics API - this.router.add({ method: "post", path: `${apiPrefix}/metrics` }, metricsRoute.routeMetrics.bind(metricsRoute)) + this.router.add({ method: "post", path: `${apiPrefix}/metrics` }, metricsRoute.routeMetrics.bind(metricsRoute)); // Port-forward API - this.router.add({ method: "post", path: `${apiPrefix}/pods/{namespace}/{resourceType}/{resourceName}/port-forward/{port}` }, portForwardRoute.routePortForward.bind(portForwardRoute)) + this.router.add({ method: "post", path: `${apiPrefix}/pods/{namespace}/{resourceType}/{resourceName}/port-forward/{port}` }, portForwardRoute.routePortForward.bind(portForwardRoute)); // Helm API - this.router.add({ method: "get", path: `${apiPrefix}/v2/charts` }, helmRoute.listCharts.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}` }, helmRoute.getChart.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}/values` }, helmRoute.getChartValues.bind(helmRoute)) + this.router.add({ method: "get", path: `${apiPrefix}/v2/charts` }, helmRoute.listCharts.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}` }, helmRoute.getChart.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}/values` }, helmRoute.getChartValues.bind(helmRoute)); - this.router.add({ method: "post", path: `${apiPrefix}/v2/releases` }, helmRoute.installChart.bind(helmRoute)) - this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.updateRelease.bind(helmRoute)) - this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}/rollback` }, helmRoute.rollbackRelease.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace?}` }, helmRoute.listReleases.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.getRelease.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/values` }, helmRoute.getReleaseValues.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/history` }, helmRoute.getReleaseHistory.bind(helmRoute)) - this.router.add({ method: "delete", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.deleteRelease.bind(helmRoute)) + this.router.add({ method: "post", path: `${apiPrefix}/v2/releases` }, helmRoute.installChart.bind(helmRoute)); + this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.updateRelease.bind(helmRoute)); + this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}/rollback` }, helmRoute.rollbackRelease.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace?}` }, helmRoute.listReleases.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.getRelease.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/values` }, helmRoute.getReleaseValues.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/history` }, helmRoute.getReleaseHistory.bind(helmRoute)); + this.router.add({ method: "delete", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.deleteRelease.bind(helmRoute)); // Resource Applier API - this.router.add({ method: "post", path: `${apiPrefix}/stack` }, resourceApplierRoute.applyResource.bind(resourceApplierRoute)) + this.router.add({ method: "post", path: `${apiPrefix}/stack` }, resourceApplierRoute.applyResource.bind(resourceApplierRoute)); } } diff --git a/src/main/routes/helm-route.ts b/src/main/routes/helm-route.ts index 0ffd7252d5..853f8ddded 100644 --- a/src/main/routes/helm-route.ts +++ b/src/main/routes/helm-route.ts @@ -1,114 +1,114 @@ -import { LensApiRequest } from "../router" -import { helmService } from "../helm/helm-service" -import { LensApi } from "../lens-api" -import logger from "../logger" +import { LensApiRequest } from "../router"; +import { helmService } from "../helm/helm-service"; +import { LensApi } from "../lens-api"; +import logger from "../logger"; class HelmApiRoute extends LensApi { public async listCharts(request: LensApiRequest) { - const { response } = request - const charts = await helmService.listCharts() - this.respondJson(response, charts) + const { response } = request; + const charts = await helmService.listCharts(); + this.respondJson(response, charts); } public async getChart(request: LensApiRequest) { - const { params, query, response } = request - const chart = await helmService.getChart(params.repo, params.chart, query.get("version")) - this.respondJson(response, chart) + const { params, query, response } = request; + const chart = await helmService.getChart(params.repo, params.chart, query.get("version")); + this.respondJson(response, chart); } public async getChartValues(request: LensApiRequest) { - const { params, query, response } = request - const values = await helmService.getChartValues(params.repo, params.chart, query.get("version")) - this.respondJson(response, values) + const { params, query, response } = request; + const values = await helmService.getChartValues(params.repo, params.chart, query.get("version")); + this.respondJson(response, values); } public async installChart(request: LensApiRequest) { - const { payload, cluster, response } = request + const { payload, cluster, response } = request; try { - const result = await helmService.installChart(cluster, payload) - this.respondJson(response, result, 201) + const result = await helmService.installChart(cluster, payload); + this.respondJson(response, result, 201); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } public async updateRelease(request: LensApiRequest) { - const { cluster, params, payload, response } = request + const { cluster, params, payload, response } = request; try { - const result = await helmService.updateRelease(cluster, params.release, params.namespace, payload ) - this.respondJson(response, result) + const result = await helmService.updateRelease(cluster, params.release, params.namespace, payload ); + this.respondJson(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } public async rollbackRelease(request: LensApiRequest) { - const { cluster, params, payload, response } = request + const { cluster, params, payload, response } = request; try { - const result = await helmService.rollback(cluster, params.release, params.namespace, payload.revision) - this.respondJson(response, result) + const result = await helmService.rollback(cluster, params.release, params.namespace, payload.revision); + this.respondJson(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error) + logger.debug(error); + this.respondText(response, error); } } public async listReleases(request: LensApiRequest) { - const { cluster, params, response } = request + const { cluster, params, response } = request; try { - const result = await helmService.listReleases(cluster, params.namespace) - this.respondJson(response, result) + const result = await helmService.listReleases(cluster, params.namespace); + this.respondJson(response, result); } catch(error) { - logger.debug(error) - this.respondText(response, error) + logger.debug(error); + this.respondText(response, error); } } public async getRelease(request: LensApiRequest) { - const { cluster, params, response } = request + const { cluster, params, response } = request; try { - const result = await helmService.getRelease(cluster, params.release, params.namespace) - this.respondJson(response, result) + const result = await helmService.getRelease(cluster, params.release, params.namespace); + this.respondJson(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } public async getReleaseValues(request: LensApiRequest) { - const { cluster, params, response } = request + const { cluster, params, response } = request; try { - const result = await helmService.getReleaseValues(cluster, params.release, params.namespace) - this.respondText(response, result) + const result = await helmService.getReleaseValues(cluster, params.release, params.namespace); + this.respondText(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } public async getReleaseHistory(request: LensApiRequest) { - const { cluster, params, response } = request + const { cluster, params, response } = request; try { - const result = await helmService.getReleaseHistory(cluster, params.release, params.namespace) - this.respondJson(response, result) + const result = await helmService.getReleaseHistory(cluster, params.release, params.namespace); + this.respondJson(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } public async deleteRelease(request: LensApiRequest) { - const { cluster, params, response } = request + const { cluster, params, response } = request; try { - const result = await helmService.deleteRelease(cluster, params.release, params.namespace) - this.respondJson(response, result) + const result = await helmService.deleteRelease(cluster, params.release, params.namespace); + this.respondJson(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } } -export const helmRoute = new HelmApiRoute() +export const helmRoute = new HelmApiRoute(); diff --git a/src/main/routes/index.ts b/src/main/routes/index.ts index 60a0423de4..5bc5b3f3dd 100644 --- a/src/main/routes/index.ts +++ b/src/main/routes/index.ts @@ -1,6 +1,6 @@ -export * from "./kubeconfig-route" -export * from "./metrics-route" -export * from "./port-forward-route" -export * from "./watch-route" -export * from "./helm-route" -export * from "./resource-applier-route" +export * from "./kubeconfig-route"; +export * from "./metrics-route"; +export * from "./port-forward-route"; +export * from "./watch-route"; +export * from "./helm-route"; +export * from "./resource-applier-route"; diff --git a/src/main/routes/kubeconfig-route.ts b/src/main/routes/kubeconfig-route.ts index 09f1f061cf..1c04b9525d 100644 --- a/src/main/routes/kubeconfig-route.ts +++ b/src/main/routes/kubeconfig-route.ts @@ -1,10 +1,10 @@ -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { Cluster } from "../cluster" -import { CoreV1Api, V1Secret } from "@kubernetes/client-node" +import { LensApiRequest } from "../router"; +import { LensApi } from "../lens-api"; +import { Cluster } from "../cluster"; +import { CoreV1Api, V1Secret } from "@kubernetes/client-node"; function generateKubeConfig(username: string, secret: V1Secret, cluster: Cluster) { - const tokenData = Buffer.from(secret.data["token"], "base64") + const tokenData = Buffer.from(secret.data["token"], "base64"); return { 'apiVersion': 'v1', 'kind': 'Config', @@ -36,23 +36,23 @@ function generateKubeConfig(username: string, secret: V1Secret, cluster: Cluster } ], 'current-context': cluster.contextName - } + }; } class KubeconfigRoute extends LensApi { public async routeServiceAccountRoute(request: LensApiRequest) { - const { params, response, cluster} = request + const { params, response, cluster} = request; const client = cluster.getProxyKubeconfig().makeApiClient(CoreV1Api); - const secretList = await client.listNamespacedSecret(params.namespace) + const secretList = await client.listNamespacedSecret(params.namespace); const secret = secretList.body.items.find(secret => { const { annotations } = secret.metadata; return annotations && annotations["kubernetes.io/service-account.name"] == params.account; }); const data = generateKubeConfig(params.account, secret, cluster); - this.respondJson(response, data) + this.respondJson(response, data); } } -export const kubeconfigRoute = new KubeconfigRoute() +export const kubeconfigRoute = new KubeconfigRoute(); diff --git a/src/main/routes/metrics-route.ts b/src/main/routes/metrics-route.ts index dc77f7fb9f..254abe188f 100644 --- a/src/main/routes/metrics-route.ts +++ b/src/main/routes/metrics-route.ts @@ -1,32 +1,32 @@ -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { Cluster } from "../cluster" -import _ from "lodash" +import { LensApiRequest } from "../router"; +import { LensApi } from "../lens-api"; +import { Cluster } from "../cluster"; +import _ from "lodash"; export type IMetricsQuery = string | string[] | { [metricName: string]: string; -} +}; // This is used for backoff retry tracking. -const MAX_ATTEMPTS = 5 -const ATTEMPTS = [...(_.fill(Array(MAX_ATTEMPTS - 1), false)), true] +const MAX_ATTEMPTS = 5; +const ATTEMPTS = [...(_.fill(Array(MAX_ATTEMPTS - 1), false)), true]; // prometheus metrics loader async function loadMetrics(promQueries: string[], cluster: Cluster, prometheusPath: string, queryParams: Record): Promise { - const queries = promQueries.map(p => p.trim()) - const loaders = new Map>() + const queries = promQueries.map(p => p.trim()); + const loaders = new Map>(); async function loadMetric(query: string): Promise { async function loadMetricHelper(): Promise { for (const [attempt, lastAttempt] of ATTEMPTS.entries()) { // retry try { - return await cluster.getMetrics(prometheusPath, { query, ...queryParams }) + return await cluster.getMetrics(prometheusPath, { query, ...queryParams }); } catch (error) { if (lastAttempt || error?.statusCode === 404) { return { status: error.toString(), data: { result: [] }, - } + }; } await new Promise(resolve => setTimeout(resolve, (attempt + 1) * 1000)); // add delay before repeating request @@ -34,41 +34,41 @@ async function loadMetrics(promQueries: string[], cluster: Cluster, prometheusPa } } - return loaders.get(query) ?? loaders.set(query, loadMetricHelper()).get(query) + return loaders.get(query) ?? loaders.set(query, loadMetricHelper()).get(query); } - return Promise.all(queries.map(loadMetric)) + return Promise.all(queries.map(loadMetric)); } class MetricsRoute extends LensApi { async routeMetrics({ response, cluster, payload, query }: LensApiRequest) { - const queryParams: IMetricsQuery = Object.fromEntries(query.entries()) + const queryParams: IMetricsQuery = Object.fromEntries(query.entries()); try { const [prometheusPath, prometheusProvider] = await Promise.all([ cluster.contextHandler.getPrometheusPath(), cluster.contextHandler.getPrometheusProvider() - ]) + ]); // return data in same structure as query if (typeof payload === "string") { - const [data] = await loadMetrics([payload], cluster, prometheusPath, queryParams) - this.respondJson(response, data) + const [data] = await loadMetrics([payload], cluster, prometheusPath, queryParams); + this.respondJson(response, data); } else if (Array.isArray(payload)) { - const data = await loadMetrics(payload, cluster, prometheusPath, queryParams) - this.respondJson(response, data) + const data = await loadMetrics(payload, cluster, prometheusPath, queryParams); + this.respondJson(response, data); } else { const queries = Object.entries(payload).map(([queryName, queryOpts]) => ( (prometheusProvider.getQueries(queryOpts) as Record)[queryName] - )) - const result = await loadMetrics(queries, cluster, prometheusPath, queryParams) - const data = Object.fromEntries(Object.keys(payload).map((metricName, i) => [metricName, result[i]])) - this.respondJson(response, data) + )); + const result = await loadMetrics(queries, cluster, prometheusPath, queryParams); + const data = Object.fromEntries(Object.keys(payload).map((metricName, i) => [metricName, result[i]])); + this.respondJson(response, data); } } catch { - this.respondJson(response, {}) + this.respondJson(response, {}); } } } -export const metricsRoute = new MetricsRoute() +export const metricsRoute = new MetricsRoute(); diff --git a/src/main/routes/port-forward-route.ts b/src/main/routes/port-forward-route.ts index 7ed79aa936..55402ff72f 100644 --- a/src/main/routes/port-forward-route.ts +++ b/src/main/routes/port-forward-route.ts @@ -1,14 +1,14 @@ -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { spawn, ChildProcessWithoutNullStreams } from "child_process" -import { Kubectl } from "../kubectl" -import { getFreePort } from "../port" -import { shell } from "electron" -import * as tcpPortUsed from "tcp-port-used" -import logger from "../logger" +import { LensApiRequest } from "../router"; +import { LensApi } from "../lens-api"; +import { spawn, ChildProcessWithoutNullStreams } from "child_process"; +import { Kubectl } from "../kubectl"; +import { getFreePort } from "../port"; +import { shell } from "electron"; +import * as tcpPortUsed from "tcp-port-used"; +import logger from "../logger"; class PortForward { - public static portForwards: PortForward[] = [] + public static portForwards: PortForward[] = []; static getPortforward(forward: {clusterId: string; kind: string; name: string; namespace: string; port: string}) { return PortForward.portForwards.find((pf) => { @@ -18,70 +18,70 @@ class PortForward { pf.name == forward.name && pf.namespace == forward.namespace && pf.port == forward.port - ) - }) + ); + }); } - public clusterId: string - public process: ChildProcessWithoutNullStreams - public kubeConfig: string - public kind: string - public namespace: string - public name: string - public port: string - public localPort: number + public clusterId: string; + public process: ChildProcessWithoutNullStreams; + public kubeConfig: string; + public kind: string; + public namespace: string; + public name: string; + public port: string; + public localPort: number; constructor(obj: any) { - Object.assign(this, obj) + Object.assign(this, obj); } public async start() { - this.localPort = await getFreePort() - const kubectlBin = await Kubectl.bundled().getPath() + this.localPort = await getFreePort(); + const kubectlBin = await Kubectl.bundled().getPath(); const args = [ "--kubeconfig", this.kubeConfig, "port-forward", "-n", this.namespace, `${this.kind}/${this.name}`, `${this.localPort}:${this.port}` - ] + ]; this.process = spawn(kubectlBin, args, { env: process.env - }) - PortForward.portForwards.push(this) + }); + PortForward.portForwards.push(this); this.process.on("exit", () => { - const index = PortForward.portForwards.indexOf(this) + const index = PortForward.portForwards.indexOf(this); if (index > -1) { - PortForward.portForwards.splice(index, 1) + PortForward.portForwards.splice(index, 1); } - }) + }); try { - await tcpPortUsed.waitUntilUsed(this.localPort, 500, 15000) - return true + await tcpPortUsed.waitUntilUsed(this.localPort, 500, 15000); + return true; } catch (error) { - this.process.kill() - return false + this.process.kill(); + return false; } } public open() { - shell.openExternal(`http://localhost:${this.localPort}`) + shell.openExternal(`http://localhost:${this.localPort}`); } } class PortForwardRoute extends LensApi { public async routePortForward(request: LensApiRequest) { - const { params, response, cluster} = request - const { namespace, port, resourceType, resourceName } = params + const { params, response, cluster} = request; + const { namespace, port, resourceType, resourceName } = params; let portForward = PortForward.getPortforward({ clusterId: cluster.id, kind: resourceType, name: resourceName, namespace: namespace, port: port - }) + }); if (!portForward) { - logger.info(`Creating a new port-forward ${namespace}/${resourceType}/${resourceName}:${port}`) + logger.info(`Creating a new port-forward ${namespace}/${resourceType}/${resourceName}:${port}`); portForward = new PortForward({ clusterId: cluster.id, kind: resourceType, @@ -89,20 +89,20 @@ class PortForwardRoute extends LensApi { name: resourceName, port: port, kubeConfig: cluster.getProxyKubeconfigPath() - }) - const started = await portForward.start() + }); + const started = await portForward.start(); if (!started) { this.respondJson(response, { message: "Failed to open port-forward" - }, 400) - return + }, 400); + return; } } - portForward.open() + portForward.open(); - this.respondJson(response, {}) + this.respondJson(response, {}); } } -export const portForwardRoute = new PortForwardRoute() +export const portForwardRoute = new PortForwardRoute(); diff --git a/src/main/routes/resource-applier-route.ts b/src/main/routes/resource-applier-route.ts index 56125af8f3..8bbfec0d9c 100644 --- a/src/main/routes/resource-applier-route.ts +++ b/src/main/routes/resource-applier-route.ts @@ -1,17 +1,17 @@ -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { ResourceApplier } from "../resource-applier" +import { LensApiRequest } from "../router"; +import { LensApi } from "../lens-api"; +import { ResourceApplier } from "../resource-applier"; class ResourceApplierApiRoute extends LensApi { public async applyResource(request: LensApiRequest) { - const { response, cluster, payload } = request + const { response, cluster, payload } = request; try { const resource = await new ResourceApplier(cluster).apply(payload); - this.respondJson(response, [resource], 200) + this.respondJson(response, [resource], 200); } catch (error) { - this.respondText(response, error, 422) + this.respondText(response, error, 422); } } } -export const resourceApplierRoute = new ResourceApplierApiRoute() +export const resourceApplierRoute = new ResourceApplierApiRoute(); diff --git a/src/main/routes/watch-route.ts b/src/main/routes/watch-route.ts index d88276eaac..dd42460a9d 100644 --- a/src/main/routes/watch-route.ts +++ b/src/main/routes/watch-route.ts @@ -1,53 +1,53 @@ -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { Watch, KubeConfig } from "@kubernetes/client-node" -import { ServerResponse } from "http" -import { Request } from "request" -import logger from "../logger" +import { LensApiRequest } from "../router"; +import { LensApi } from "../lens-api"; +import { Watch, KubeConfig } from "@kubernetes/client-node"; +import { ServerResponse } from "http"; +import { Request } from "request"; +import logger from "../logger"; class ApiWatcher { - private apiUrl: string - private response: ServerResponse - private watchRequest: Request - private watch: Watch - private processor: NodeJS.Timeout - private eventBuffer: any[] = [] + private apiUrl: string; + private response: ServerResponse; + private watchRequest: Request; + private watch: Watch; + private processor: NodeJS.Timeout; + private eventBuffer: any[] = []; constructor(apiUrl: string, kubeConfig: KubeConfig, response: ServerResponse) { - this.apiUrl = apiUrl - this.watch = new Watch(kubeConfig) - this.response = response + this.apiUrl = apiUrl; + this.watch = new Watch(kubeConfig); + this.response = response; } public async start() { if (this.processor) { - clearInterval(this.processor) + clearInterval(this.processor); } this.processor = setInterval(() => { - const events = this.eventBuffer.splice(0) - events.map(event => this.sendEvent(event)) - this.response.flushHeaders() - }, 50) - this.watchRequest = await this.watch.watch(this.apiUrl, {}, this.watchHandler.bind(this), this.doneHandler.bind(this)) + const events = this.eventBuffer.splice(0); + events.map(event => this.sendEvent(event)); + this.response.flushHeaders(); + }, 50); + this.watchRequest = await this.watch.watch(this.apiUrl, {}, this.watchHandler.bind(this), this.doneHandler.bind(this)); } public stop() { - if (!this.watchRequest) { return } + if (!this.watchRequest) { return; } if (this.processor) { - clearInterval(this.processor) + clearInterval(this.processor); } - logger.debug("Stopping watcher for api: " + this.apiUrl) + logger.debug("Stopping watcher for api: " + this.apiUrl); try { - this.watchRequest.abort() + this.watchRequest.abort(); this.sendEvent({ type: "STREAM_END", url: this.apiUrl, status: 410, - }) - logger.debug("watch aborted") + }); + logger.debug("watch aborted"); } catch (error) { - logger.error("Watch abort errored:" + error) + logger.error("Watch abort errored:" + error); } } @@ -55,12 +55,12 @@ class ApiWatcher { this.eventBuffer.push({ type: phase, object: obj - }) + }); } private doneHandler(error: Error) { - if (error) logger.warn("watch ended: " + error.toString()) - this.watchRequest.abort() + if (error) logger.warn("watch ended: " + error.toString()); + this.watchRequest.abort(); } private sendEvent(evt: any) { @@ -72,40 +72,40 @@ class ApiWatcher { class WatchRoute extends LensApi { public async routeWatch(request: LensApiRequest) { - const { params, response, cluster} = request - const apis: string[] = request.query.getAll("api") - const watchers: ApiWatcher[] = [] + const { params, response, cluster} = request; + const apis: string[] = request.query.getAll("api"); + const watchers: ApiWatcher[] = []; if (!apis.length) { this.respondJson(response, { message: "Empty request. Query params 'api' are not provided.", example: "?api=/api/v1/pods&api=/api/v1/nodes", - }, 400) - return + }, 400); + return; } - response.setHeader("Content-Type", "text/event-stream") - response.setHeader("Cache-Control", "no-cache") - response.setHeader("Connection", "keep-alive") - logger.debug("watch using kubeconfig:" + JSON.stringify(cluster.getProxyKubeconfig(), null, 2)) + response.setHeader("Content-Type", "text/event-stream"); + response.setHeader("Cache-Control", "no-cache"); + response.setHeader("Connection", "keep-alive"); + logger.debug("watch using kubeconfig:" + JSON.stringify(cluster.getProxyKubeconfig(), null, 2)); apis.forEach(apiUrl => { - const watcher = new ApiWatcher(apiUrl, cluster.getProxyKubeconfig(), response) - watcher.start() - watchers.push(watcher) - }) + const watcher = new ApiWatcher(apiUrl, cluster.getProxyKubeconfig(), response); + watcher.start(); + watchers.push(watcher); + }); request.raw.req.on("close", () => { - logger.debug("Watch request closed") - watchers.map(watcher => watcher.stop()) - }) + logger.debug("Watch request closed"); + watchers.map(watcher => watcher.stop()); + }); request.raw.req.on("end", () => { - logger.debug("Watch request ended") - watchers.map(watcher => watcher.stop()) - }) + logger.debug("Watch request ended"); + watchers.map(watcher => watcher.stop()); + }); } } -export const watchRoute = new WatchRoute() +export const watchRoute = new WatchRoute(); diff --git a/src/main/shell-session.ts b/src/main/shell-session.ts index 6ea9e4eede..42e0039047 100644 --- a/src/main/shell-session.ts +++ b/src/main/shell-session.ts @@ -1,23 +1,23 @@ -import * as pty from "node-pty" -import * as WebSocket from "ws" +import * as pty from "node-pty"; +import * as WebSocket from "ws"; import { EventEmitter } from "events"; -import path from "path" -import shellEnv from "shell-env" -import { app } from "electron" -import { Kubectl } from "./kubectl" -import { Cluster } from "./cluster" +import path from "path"; +import shellEnv from "shell-env"; +import { app } from "electron"; +import { Kubectl } from "./kubectl"; +import { Cluster } from "./cluster"; import { ClusterPreferences } from "../common/cluster-store"; -import { helmCli } from "./helm/helm-cli" +import { helmCli } from "./helm/helm-cli"; import { isWindows } from "../common/vars"; -import { appEventBus } from "../common/event-bus" +import { appEventBus } from "../common/event-bus"; import { userStore } from "../common/user-store"; export class ShellSession extends EventEmitter { - static shellEnvs: Map = new Map() + static shellEnvs: Map = new Map(); - protected websocket: WebSocket - protected shellProcess: pty.IPty - protected kubeconfigPath: string + protected websocket: WebSocket; + protected shellProcess: pty.IPty; + protected kubeconfigPath: string; protected nodeShellPod: string; protected kubectl: Kubectl; protected kubectlBinDir: string; @@ -28,22 +28,22 @@ export class ShellSession extends EventEmitter { protected clusterId: string; constructor(socket: WebSocket, cluster: Cluster) { - super() - this.websocket = socket - this.kubeconfigPath = cluster.getProxyKubeconfigPath() - this.kubectl = new Kubectl(cluster.version) - this.preferences = cluster.preferences || {} - this.clusterId = cluster.id + super(); + this.websocket = socket; + this.kubeconfigPath = cluster.getProxyKubeconfigPath(); + this.kubectl = new Kubectl(cluster.version); + this.preferences = cluster.preferences || {}; + this.clusterId = cluster.id; } public async open() { - this.kubectlBinDir = await this.kubectl.binDir() - const pathFromPreferences = userStore.preferences.kubectlBinariesPath || this.kubectl.getBundledPath() - this.kubectlPathDir = userStore.preferences.downloadKubectlBinaries ? this.kubectlBinDir : path.dirname(pathFromPreferences) - this.helmBinDir = helmCli.getBinaryDir() - const env = await this.getCachedShellEnv() - const shell = env.PTYSHELL - const args = await this.getShellArgs(shell) + this.kubectlBinDir = await this.kubectl.binDir(); + const pathFromPreferences = userStore.preferences.kubectlBinariesPath || this.kubectl.getBundledPath(); + this.kubectlPathDir = userStore.preferences.downloadKubectlBinaries ? this.kubectlBinDir : path.dirname(pathFromPreferences); + this.helmBinDir = helmCli.getBinaryDir(); + const env = await this.getCachedShellEnv(); + const shell = env.PTYSHELL; + const args = await this.getShellArgs(shell); this.shellProcess = pty.spawn(shell, args, { cols: 80, cwd: this.cwd() || env.HOME, @@ -53,138 +53,138 @@ export class ShellSession extends EventEmitter { }); this.running = true; - this.pipeStdout() - this.pipeStdin() - this.closeWebsocketOnProcessExit() - this.exitProcessOnWebsocketClose() + this.pipeStdout(); + this.pipeStdin(); + this.closeWebsocketOnProcessExit(); + this.exitProcessOnWebsocketClose(); - appEventBus.emit({name: "shell", action: "open"}) + appEventBus.emit({name: "shell", action: "open"}); } protected cwd(): string { if(!this.preferences || !this.preferences.terminalCWD || this.preferences.terminalCWD === "") { - return null + return null; } - return this.preferences.terminalCWD + return this.preferences.terminalCWD; } protected async getShellArgs(shell: string): Promise> { switch(path.basename(shell)) { case "powershell.exe": - return ["-NoExit", "-command", `& {Set-Location $Env:USERPROFILE; $Env:PATH="${this.helmBinDir};${this.kubectlPathDir};$Env:PATH"}`] + return ["-NoExit", "-command", `& {Set-Location $Env:USERPROFILE; $Env:PATH="${this.helmBinDir};${this.kubectlPathDir};$Env:PATH"}`]; case "bash": - return ["--init-file", path.join(this.kubectlBinDir, '.bash_set_path')] + return ["--init-file", path.join(this.kubectlBinDir, '.bash_set_path')]; case "fish": - return ["--login", "--init-command", `export PATH="${this.helmBinDir}:${this.kubectlPathDir}:$PATH"; export KUBECONFIG="${this.kubeconfigPath}"`] + return ["--login", "--init-command", `export PATH="${this.helmBinDir}:${this.kubectlPathDir}:$PATH"; export KUBECONFIG="${this.kubeconfigPath}"`]; case "zsh": - return ["--login"] + return ["--login"]; default: - return [] + return []; } } protected async getCachedShellEnv() { - let env = ShellSession.shellEnvs.get(this.clusterId) + let env = ShellSession.shellEnvs.get(this.clusterId); if (!env) { - env = await this.getShellEnv() - ShellSession.shellEnvs.set(this.clusterId, env) + env = await this.getShellEnv(); + ShellSession.shellEnvs.set(this.clusterId, env); } else { // refresh env in the background this.getShellEnv().then((shellEnv: any) => { - ShellSession.shellEnvs.set(this.clusterId, shellEnv) - }) + ShellSession.shellEnvs.set(this.clusterId, shellEnv); + }); } - return env + return env; } protected async getShellEnv() { - const env = JSON.parse(JSON.stringify(await shellEnv())) - const pathStr = [this.kubectlBinDir, this.helmBinDir, process.env.PATH].join(path.delimiter) + const env = JSON.parse(JSON.stringify(await shellEnv())); + const pathStr = [this.kubectlBinDir, this.helmBinDir, process.env.PATH].join(path.delimiter); if(isWindows) { - env["SystemRoot"] = process.env.SystemRoot - env["PTYSHELL"] = "powershell.exe" - env["PATH"] = pathStr + env["SystemRoot"] = process.env.SystemRoot; + env["PTYSHELL"] = "powershell.exe"; + env["PATH"] = pathStr; } else if(typeof(process.env.SHELL) != "undefined") { - env["PTYSHELL"] = process.env.SHELL - env["PATH"] = pathStr + env["PTYSHELL"] = process.env.SHELL; + env["PATH"] = pathStr; } else { - env["PTYSHELL"] = "" // blank runs the system default shell + env["PTYSHELL"] = ""; // blank runs the system default shell } if(path.basename(env["PTYSHELL"]) === "zsh") { - env["OLD_ZDOTDIR"] = env.ZDOTDIR || env.HOME - env["ZDOTDIR"] = this.kubectlBinDir + env["OLD_ZDOTDIR"] = env.ZDOTDIR || env.HOME; + env["ZDOTDIR"] = this.kubectlBinDir; } - env["PTYPID"] = process.pid.toString() - env["KUBECONFIG"] = this.kubeconfigPath - env["TERM_PROGRAM"] = app.getName() - env["TERM_PROGRAM_VERSION"] = app.getVersion() + env["PTYPID"] = process.pid.toString(); + env["KUBECONFIG"] = this.kubeconfigPath; + env["TERM_PROGRAM"] = app.getName(); + env["TERM_PROGRAM_VERSION"] = app.getVersion(); if (this.preferences.httpsProxy) { - env["HTTPS_PROXY"] = this.preferences.httpsProxy + env["HTTPS_PROXY"] = this.preferences.httpsProxy; } - const no_proxy = ["localhost", "127.0.0.1", env["NO_PROXY"]] - env["NO_PROXY"] = no_proxy.filter(address => !!address).join() + const no_proxy = ["localhost", "127.0.0.1", env["NO_PROXY"]]; + env["NO_PROXY"] = no_proxy.filter(address => !!address).join(); if (env.DEBUG) { // do not pass debug option to bash - delete env["DEBUG"] + delete env["DEBUG"]; } - return(env) + return(env); } protected pipeStdout() { // send shell output to websocket this.shellProcess.onData(((data: string) => { - this.sendResponse(data) + this.sendResponse(data); })); } protected pipeStdin() { // write websocket messages to shellProcess this.websocket.on("message", (data: string) => { - if (!this.running) { return } + if (!this.running) { return; } - const message = Buffer.from(data.slice(1, data.length), "base64").toString() + const message = Buffer.from(data.slice(1, data.length), "base64").toString(); switch (data[0]) { case "0": - this.shellProcess.write(message) + this.shellProcess.write(message); break; case "4": - const resizeMsgObj = JSON.parse(message) - this.shellProcess.resize(resizeMsgObj["Width"], resizeMsgObj["Height"]) + const resizeMsgObj = JSON.parse(message); + this.shellProcess.resize(resizeMsgObj["Width"], resizeMsgObj["Height"]); break; case "9": - this.emit('newToken', message) + this.emit('newToken', message); break; } - }) + }); } protected exit(code = 1000) { - if (this.websocket.readyState == this.websocket.OPEN) this.websocket.close(code) - this.emit('exit') + if (this.websocket.readyState == this.websocket.OPEN) this.websocket.close(code); + this.emit('exit'); } protected closeWebsocketOnProcessExit() { this.shellProcess.onExit(({ exitCode }) => { - this.running = false - let timeout = 0 + this.running = false; + let timeout = 0; if (exitCode > 0) { - this.sendResponse("Terminal will auto-close in 15 seconds ...") - timeout = 15*1000 + this.sendResponse("Terminal will auto-close in 15 seconds ..."); + timeout = 15*1000; } setTimeout(() => { - this.exit() - }, timeout) + this.exit(); + }, timeout); }); } protected exitProcessOnWebsocketClose() { this.websocket.on("close", () => { - this.killShellProcess() - }) + this.killShellProcess(); + }); } protected killShellProcess(){ @@ -192,17 +192,17 @@ export class ShellSession extends EventEmitter { // On Windows we need to kill the shell process by pid, since Lens won't respond after a while if using `this.shellProcess.kill()` if (isWindows) { try { - process.kill(this.shellProcess.pid) + process.kill(this.shellProcess.pid); } catch(e) { - return + return; } } else { - this.shellProcess.kill() + this.shellProcess.kill(); } } } protected sendResponse(msg: string) { - this.websocket.send("1" + Buffer.from(msg).toString("base64")) + this.websocket.send("1" + Buffer.from(msg).toString("base64")); } } diff --git a/src/main/shell-sync.ts b/src/main/shell-sync.ts index 373d0a36ba..46d5788c12 100644 --- a/src/main/shell-sync.ts +++ b/src/main/shell-sync.ts @@ -1,4 +1,4 @@ -import shellEnv from "shell-env" +import shellEnv from "shell-env"; import os from "os"; import { app } from "electron"; import logger from "./logger"; @@ -19,7 +19,7 @@ export async function shellSync() { try { envVars = await shellEnv(shell); } catch (error) { - logger.error(`shellEnv: ${error}`) + logger.error(`shellEnv: ${error}`); } const env: Env = JSON.parse(JSON.stringify(envVars)); @@ -27,12 +27,12 @@ export async function shellSync() { // the LANG env var expects an underscore instead of electron's dash env.LANG = `${app.getLocale().replace('-', '_')}.UTF-8`; } else if (!env.LANG.endsWith(".UTF-8")) { - env.LANG += ".UTF-8" + env.LANG += ".UTF-8"; } // Overwrite PATH on darwin if (process.env.NODE_ENV === "production" && process.platform === "darwin") { - process.env["PATH"] = env.PATH + process.env["PATH"] = env.PATH; } // The spread operator allows joining of objects. The precedence is last to first. diff --git a/src/main/tray.ts b/src/main/tray.ts index 268e006089..f84ea21896 100644 --- a/src/main/tray.ts +++ b/src/main/tray.ts @@ -1,6 +1,6 @@ -import path from "path" -import packageInfo from "../../package.json" -import { dialog, Menu, NativeImage, nativeTheme, Tray } from "electron" +import path from "path"; +import packageInfo from "../../package.json"; +import { dialog, Menu, NativeImage, nativeTheme, Tray } from "electron"; import { autorun } from "mobx"; import { showAbout } from "./menu"; import { AppUpdater } from "./app-updater"; @@ -24,7 +24,7 @@ export function getTrayIcon(isDark = nativeTheme.shouldUseDarkColors): string { __static, isDevelopment ? "../build/tray" : "icons", // copied within electron-builder extras `tray_icon${isDark ? "_dark" : ""}.png` - ) + ); } export function initTray(windowManager: WindowManager) { @@ -35,18 +35,18 @@ export function initTray(windowManager: WindowManager) { } catch (err) { logger.error(`[TRAY]: building failed: ${err}`); } - }) + }); return () => { dispose(); tray?.destroy(); tray = null; - } + }; } export function buildTray(icon: string | NativeImage, menu: Menu) { if (!tray) { - tray = new Tray(icon) - tray.setToolTip(packageInfo.description) + tray = new Tray(icon); + tray.setToolTip(packageInfo.description); tray.setIgnoreDoubleClickEvents(true); } @@ -70,7 +70,7 @@ export function createTrayMenu(windowManager: WindowManager): Menu { { label: "Open Lens", async click() { - await windowManager.ensureMainWindow() + await windowManager.ensureMainWindow(); }, }, { @@ -98,9 +98,9 @@ export function createTrayMenu(windowManager: WindowManager): Menu { clusterStore.setActive(clusterId); windowManager.navigate(clusterViewURL({ params: { clusterId } })); } - } + }; }) - } + }; }), }, { @@ -112,7 +112,7 @@ export function createTrayMenu(windowManager: WindowManager): Menu { dialog.showMessageBoxSync(browserWindow, { message: "No updates available", type: "info", - }) + }); } }, }, @@ -120,7 +120,7 @@ export function createTrayMenu(windowManager: WindowManager): Menu { { label: 'Quit App', click() { - exitApp() + exitApp(); } } ]); diff --git a/src/main/window-manager.ts b/src/main/window-manager.ts index 019ed270eb..00fbdd4243 100644 --- a/src/main/window-manager.ts +++ b/src/main/window-manager.ts @@ -1,9 +1,9 @@ import type { ClusterId } from "../common/cluster-store"; import { observable } from "mobx"; -import { app, BrowserWindow, dialog, shell, webContents } from "electron" -import windowStateKeeper from "electron-window-state" -import { appEventBus } from "../common/event-bus" -import { subscribeToBroadcast } from "../common/ipc" +import { app, BrowserWindow, dialog, shell, webContents } from "electron"; +import windowStateKeeper from "electron-window-state"; +import { appEventBus } from "../common/event-bus"; +import { subscribeToBroadcast } from "../common/ipc"; import { initMenu } from "./menu"; import { initTray } from "./tray"; import { Singleton } from "../common/utils"; @@ -26,7 +26,7 @@ export class WindowManager extends Singleton { } get mainUrl() { - return `http://localhost:${this.proxyPort}` + return `http://localhost:${this.proxyPort}`; } async initMainWindow(showSplash = true) { @@ -63,14 +63,14 @@ export class WindowManager extends Singleton { shell.openExternal(url); }); this.mainWindow.webContents.on("dom-ready", () => { - appEventBus.emit({name: "app", action: "dom-ready"}) - }) + appEventBus.emit({name: "app", action: "dom-ready"}); + }); this.mainWindow.on("focus", () => { - appEventBus.emit({name: "app", action: "focus"}) - }) + appEventBus.emit({name: "app", action: "focus"}); + }); this.mainWindow.on("blur", () => { - appEventBus.emit({name: "app", action: "blur"}) - }) + appEventBus.emit({name: "app", action: "blur"}); + }); // clean up this.mainWindow.on("closed", () => { @@ -78,16 +78,16 @@ export class WindowManager extends Singleton { this.mainWindow = null; this.splashWindow = null; app.dock?.hide(); // hide icon in dock (mac-os) - }) + }); } try { if (showSplash) await this.showSplash(); await this.mainWindow.loadURL(this.mainUrl); this.mainWindow.show(); this.splashWindow?.close(); - appEventBus.emit({ name: "app", action: "start" }) + appEventBus.emit({ name: "app", action: "start" }); } catch (err) { - dialog.showErrorBox("ERROR!", err.toString()) + dialog.showErrorBox("ERROR!", err.toString()); } } @@ -103,7 +103,7 @@ export class WindowManager extends Singleton { // track visible cluster from ui subscribeToBroadcast("cluster-view:current-id", (event, clusterId: ClusterId) => { this.activeClusterId = clusterId; - }) + }); } async ensureMainWindow(): Promise { @@ -126,11 +126,11 @@ export class WindowManager extends Singleton { channel: "renderer:navigate", frameId: frameId, data: [url], - }) + }); } reload() { - const frameId = clusterFrameMap.get(this.activeClusterId) + const frameId = clusterFrameMap.get(this.activeClusterId); if (frameId) { this.sendToView({ channel: "renderer:reload", frameId }); } else { @@ -169,7 +169,7 @@ export class WindowManager extends Singleton { this.splashWindow = null; Object.entries(this.disposers).forEach(([name, dispose]) => { dispose(); - delete this.disposers[name] + delete this.disposers[name]; }); } } diff --git a/src/migrations/cluster-store/2.0.0-beta.2.ts b/src/migrations/cluster-store/2.0.0-beta.2.ts index 8a01af5407..245e9c019c 100644 --- a/src/migrations/cluster-store/2.0.0-beta.2.ts +++ b/src/migrations/cluster-store/2.0.0-beta.2.ts @@ -13,4 +13,4 @@ export default migration({ store.set(contextName, { kubeConfig: value[1] }); } } -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/src/migrations/cluster-store/2.4.1.ts b/src/migrations/cluster-store/2.4.1.ts index 5789f6cc36..f9de1ed6d8 100644 --- a/src/migrations/cluster-store/2.4.1.ts +++ b/src/migrations/cluster-store/2.4.1.ts @@ -11,4 +11,4 @@ export default migration({ store.set(contextName, { kubeConfig: cluster.kubeConfig, icon: cluster.icon || null, preferences: cluster.preferences || {} }); } } -}) +}); diff --git a/src/migrations/cluster-store/2.6.0-beta.2.ts b/src/migrations/cluster-store/2.6.0-beta.2.ts index 0e13afe7a9..3114202ed1 100644 --- a/src/migrations/cluster-store/2.6.0-beta.2.ts +++ b/src/migrations/cluster-store/2.6.0-beta.2.ts @@ -6,7 +6,7 @@ export default migration({ run(store, log) { for (const value of store) { const clusterKey = value[0]; - if (clusterKey === "__internal__") continue + if (clusterKey === "__internal__") continue; const cluster = value[1]; if (!cluster.preferences) cluster.preferences = {}; if (cluster.icon) { @@ -16,4 +16,4 @@ export default migration({ store.set(clusterKey, { contextName: clusterKey, kubeConfig: value[1].kubeConfig, preferences: value[1].preferences }); } } -}) +}); diff --git a/src/migrations/cluster-store/2.6.0-beta.3.ts b/src/migrations/cluster-store/2.6.0-beta.3.ts index 11f1a3bce9..7f17440e60 100644 --- a/src/migrations/cluster-store/2.6.0-beta.3.ts +++ b/src/migrations/cluster-store/2.6.0-beta.3.ts @@ -1,38 +1,38 @@ import { migration } from "../migration-wrapper"; -import yaml from "js-yaml" +import yaml from "js-yaml"; export default migration({ version: "2.6.0-beta.3", run(store, log) { for (const value of store) { const clusterKey = value[0]; - if (clusterKey === "__internal__") continue + if (clusterKey === "__internal__") continue; const cluster = value[1]; - if (!cluster.kubeConfig) continue - const kubeConfig = yaml.safeLoad(cluster.kubeConfig) - if (!kubeConfig.hasOwnProperty('users')) continue - const userObj = kubeConfig.users[0] + if (!cluster.kubeConfig) continue; + const kubeConfig = yaml.safeLoad(cluster.kubeConfig); + if (!kubeConfig.hasOwnProperty('users')) continue; + const userObj = kubeConfig.users[0]; if (userObj) { - const user = userObj.user + const user = userObj.user; if (user["auth-provider"] && user["auth-provider"].config) { - const authConfig = user["auth-provider"].config + const authConfig = user["auth-provider"].config; if (authConfig["access-token"]) { - authConfig["access-token"] = `${authConfig["access-token"]}` + authConfig["access-token"] = `${authConfig["access-token"]}`; } if (authConfig.expiry) { - authConfig.expiry = `${authConfig.expiry}` + authConfig.expiry = `${authConfig.expiry}`; } - log(authConfig) - user["auth-provider"].config = authConfig + log(authConfig); + user["auth-provider"].config = authConfig; kubeConfig.users = [{ name: userObj.name, user: user - }] - cluster.kubeConfig = yaml.safeDump(kubeConfig) - store.set(clusterKey, cluster) + }]; + cluster.kubeConfig = yaml.safeDump(kubeConfig); + store.set(clusterKey, cluster); } } } } -}) +}); diff --git a/src/migrations/cluster-store/2.7.0-beta.0.ts b/src/migrations/cluster-store/2.7.0-beta.0.ts index 3e0ae9337f..f1af3de3c9 100644 --- a/src/migrations/cluster-store/2.7.0-beta.0.ts +++ b/src/migrations/cluster-store/2.7.0-beta.0.ts @@ -6,10 +6,10 @@ export default migration({ run(store, log) { for (const value of store) { const clusterKey = value[0]; - if (clusterKey === "__internal__") continue + if (clusterKey === "__internal__") continue; const cluster = value[1]; - cluster.workspace = "default" - store.set(clusterKey, cluster) + cluster.workspace = "default"; + store.set(clusterKey, cluster); } } -}) +}); diff --git a/src/migrations/cluster-store/2.7.0-beta.1.ts b/src/migrations/cluster-store/2.7.0-beta.1.ts index de9e4506d1..52e60ba527 100644 --- a/src/migrations/cluster-store/2.7.0-beta.1.ts +++ b/src/migrations/cluster-store/2.7.0-beta.1.ts @@ -1,25 +1,25 @@ // Add id for clusters and store them to array import { migration } from "../migration-wrapper"; -import { v4 as uuid } from "uuid" +import { v4 as uuid } from "uuid"; export default migration({ version: "2.7.0-beta.1", run(store, log) { - const clusters: any[] = [] + const clusters: any[] = []; for (const value of store) { const clusterKey = value[0]; - if (clusterKey === "__internal__") continue - if (clusterKey === "clusters") continue + if (clusterKey === "__internal__") continue; + if (clusterKey === "clusters") continue; const cluster = value[1]; - cluster.id = uuid() + cluster.id = uuid(); if (!cluster.preferences.clusterName) { - cluster.preferences.clusterName = clusterKey + cluster.preferences.clusterName = clusterKey; } - clusters.push(cluster) - store.delete(clusterKey) + clusters.push(cluster); + store.delete(clusterKey); } if (clusters.length > 0) { - store.set("clusters", clusters) + store.set("clusters", clusters); } } -}) +}); diff --git a/src/migrations/cluster-store/3.6.0-beta.1.ts b/src/migrations/cluster-store/3.6.0-beta.1.ts index 412c77ab96..c7e5889cd9 100644 --- a/src/migrations/cluster-store/3.6.0-beta.1.ts +++ b/src/migrations/cluster-store/3.6.0-beta.1.ts @@ -1,24 +1,24 @@ // Move embedded kubeconfig into separate file and add reference to it to cluster settings // convert file path cluster icons to their base64 encoded versions -import path from "path" -import { app, remote } from "electron" +import path from "path"; +import { app, remote } from "electron"; import { migration } from "../migration-wrapper"; -import fse from "fs-extra" +import fse from "fs-extra"; import { ClusterModel, ClusterStore } from "../../common/cluster-store"; import { loadConfig } from "../../common/kube-helpers"; export default migration({ version: "3.6.0-beta.1", run(store, printLog) { - const userDataPath = (app || remote.app).getPath("userData") + const userDataPath = (app || remote.app).getPath("userData"); const kubeConfigBase = ClusterStore.getCustomKubeConfigPath(""); const storedClusters: ClusterModel[] = store.get("clusters") || []; if (!storedClusters.length) return; fse.ensureDirSync(kubeConfigBase); - printLog("Number of clusters to migrate: ", storedClusters.length) + printLog("Number of clusters to migrate: ", storedClusters.length); const migratedClusters = storedClusters .map(cluster => { /** @@ -31,7 +31,7 @@ export default migration({ delete cluster.kubeConfig; } catch (error) { - printLog(`Failed to migrate Kubeconfig for cluster "${cluster.id}", removing cluster...`, error) + printLog(`Failed to migrate Kubeconfig for cluster "${cluster.id}", removing cluster...`, error); return undefined; } @@ -40,8 +40,8 @@ export default migration({ */ try { if (cluster.preferences?.icon) { - printLog(`migrating ${cluster.preferences.icon} for ${cluster.preferences.clusterName}`) - const iconPath = cluster.preferences.icon.replace("store://", "") + printLog(`migrating ${cluster.preferences.icon} for ${cluster.preferences.clusterName}`); + const iconPath = cluster.preferences.icon.replace("store://", ""); const fileData = fse.readFileSync(path.join(userDataPath, iconPath)); cluster.preferences.icon = `data:;base64,${fileData.toString('base64')}`; @@ -49,7 +49,7 @@ export default migration({ delete cluster.preferences?.icon; } } catch (error) { - printLog(`Failed to migrate cluster icon for cluster "${cluster.id}"`, error) + printLog(`Failed to migrate cluster icon for cluster "${cluster.id}"`, error); delete cluster.preferences.icon; } @@ -59,7 +59,7 @@ export default migration({ // "overwrite" the cluster configs if (migratedClusters.length > 0) { - store.set("clusters", migratedClusters) + store.set("clusters", migratedClusters); } } -}) +}); diff --git a/src/migrations/cluster-store/index.ts b/src/migrations/cluster-store/index.ts index f35e8f6c9c..c546fdaeda 100644 --- a/src/migrations/cluster-store/index.ts +++ b/src/migrations/cluster-store/index.ts @@ -1,13 +1,13 @@ // Cluster store migrations -import version200Beta2 from "./2.0.0-beta.2" -import version241 from "./2.4.1" -import version260Beta2 from "./2.6.0-beta.2" -import version260Beta3 from "./2.6.0-beta.3" -import version270Beta0 from "./2.7.0-beta.0" -import version270Beta1 from "./2.7.0-beta.1" -import version360Beta1 from "./3.6.0-beta.1" -import snap from "./snap" +import version200Beta2 from "./2.0.0-beta.2"; +import version241 from "./2.4.1"; +import version260Beta2 from "./2.6.0-beta.2"; +import version260Beta3 from "./2.6.0-beta.3"; +import version270Beta0 from "./2.7.0-beta.0"; +import version270Beta1 from "./2.7.0-beta.1"; +import version360Beta1 from "./3.6.0-beta.1"; +import snap from "./snap"; export default { ...version200Beta2, @@ -18,4 +18,4 @@ export default { ...version270Beta1, ...version360Beta1, ...snap -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/migrations/cluster-store/snap.ts b/src/migrations/cluster-store/snap.ts index a377ba4268..1136607cd7 100644 --- a/src/migrations/cluster-store/snap.ts +++ b/src/migrations/cluster-store/snap.ts @@ -3,31 +3,31 @@ import { migration } from "../migration-wrapper"; import { ClusterModel, ClusterStore } from "../../common/cluster-store"; import { getAppVersion } from "../../common/utils/app-version"; -import fs from "fs" +import fs from "fs"; export default migration({ version: getAppVersion(), // Run always after upgrade run(store, printLog) { if (!process.env["SNAP"]) return; - printLog("Migrating embedded kubeconfig paths") + printLog("Migrating embedded kubeconfig paths"); const storedClusters: ClusterModel[] = store.get("clusters") || []; if (!storedClusters.length) return; - printLog("Number of clusters to migrate: ", storedClusters.length) + printLog("Number of clusters to migrate: ", storedClusters.length); const migratedClusters = storedClusters .map(cluster => { /** * replace snap version with 'current' in kubeconfig path */ if (!fs.existsSync(cluster.kubeConfigPath)) { - const kubeconfigPath = cluster.kubeConfigPath.replace(/\/snap\/kontena-lens\/[0-9]*\//, "/snap/kontena-lens/current/") - cluster.kubeConfigPath = kubeconfigPath + const kubeconfigPath = cluster.kubeConfigPath.replace(/\/snap\/kontena-lens\/[0-9]*\//, "/snap/kontena-lens/current/"); + cluster.kubeConfigPath = kubeconfigPath; } return cluster; - }) + }); - store.set("clusters", migratedClusters) + store.set("clusters", migratedClusters); } -}) +}); diff --git a/src/migrations/user-store/2.1.0-beta.4.ts b/src/migrations/user-store/2.1.0-beta.4.ts index 24c4cde5e3..e8f6500b05 100644 --- a/src/migrations/user-store/2.1.0-beta.4.ts +++ b/src/migrations/user-store/2.1.0-beta.4.ts @@ -6,4 +6,4 @@ export default migration({ run(store) { store.set("lastSeenAppVersion", "0.0.0"); } -}) +}); diff --git a/src/migrations/user-store/index.ts b/src/migrations/user-store/index.ts index 895bc5ee18..e1e7b8ffc9 100644 --- a/src/migrations/user-store/index.ts +++ b/src/migrations/user-store/index.ts @@ -1,7 +1,7 @@ // User store migrations -import version210Beta4 from "./2.1.0-beta.4" +import version210Beta4 from "./2.1.0-beta.4"; export default { ...version210Beta4, -} +}; diff --git a/src/renderer/api/api-manager.ts b/src/renderer/api/api-manager.ts index a0d90f4a13..98dbe206c7 100644 --- a/src/renderer/api/api-manager.ts +++ b/src/renderer/api/api-manager.ts @@ -24,7 +24,7 @@ export class ApiManager { } protected resolveApi(api: string | KubeApi): KubeApi { - if (typeof api === "string") return this.getApi(api) + if (typeof api === "string") return this.getApi(api); return api; } @@ -41,7 +41,7 @@ export class ApiManager { registerStore(store: KubeObjectStore, apis: KubeApi[] = [store.api]) { apis.forEach(api => { this.stores.set(api, store); - }) + }); } getStore(api: string | KubeApi): KubeObjectStore { diff --git a/src/renderer/api/endpoints/cluster-role-binding.api.ts b/src/renderer/api/endpoints/cluster-role-binding.api.ts index 35e4ded7e7..d566717bff 100644 --- a/src/renderer/api/endpoints/cluster-role-binding.api.ts +++ b/src/renderer/api/endpoints/cluster-role-binding.api.ts @@ -2,9 +2,9 @@ import { RoleBinding } from "./role-binding.api"; import { KubeApi } from "../kube-api"; export class ClusterRoleBinding extends RoleBinding { - static kind = "ClusterRoleBinding" - static namespaced = false - static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings" + static kind = "ClusterRoleBinding"; + static namespaced = false; + static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings"; } export const clusterRoleBindingApi = new KubeApi({ diff --git a/src/renderer/api/endpoints/cluster-role.api.ts b/src/renderer/api/endpoints/cluster-role.api.ts index 8a99f7ad27..9e3c90ca2e 100644 --- a/src/renderer/api/endpoints/cluster-role.api.ts +++ b/src/renderer/api/endpoints/cluster-role.api.ts @@ -4,9 +4,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class ClusterRole extends Role { - static kind = "ClusterRole" - static namespaced = false - static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterroles" + static kind = "ClusterRole"; + static namespaced = false; + static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterroles"; } export const clusterRoleApi = new KubeApi({ diff --git a/src/renderer/api/endpoints/cluster.api.ts b/src/renderer/api/endpoints/cluster.api.ts index 4386f28184..43783e1c00 100644 --- a/src/renderer/api/endpoints/cluster.api.ts +++ b/src/renderer/api/endpoints/cluster.api.ts @@ -3,12 +3,12 @@ import { KubeObject } from "../kube-object"; import { KubeApi } from "../kube-api"; export class ClusterApi extends KubeApi { - static kind = "Cluster" - static namespaced = true + static kind = "Cluster"; + static namespaced = true; async getMetrics(nodeNames: string[], params?: IMetricsReqParams): Promise { const nodes = nodeNames.join("|"); - const opts = { category: "cluster", nodes: nodes } + const opts = { category: "cluster", nodes: nodes }; return metricsApi.getMetrics({ memoryUsage: opts, @@ -52,7 +52,7 @@ export interface IClusterMetrics { export class Cluster extends KubeObject { static kind = "Cluster"; - static apiBase = "/apis/cluster.k8s.io/v1alpha1/clusters" + static apiBase = "/apis/cluster.k8s.io/v1alpha1/clusters"; spec: { clusterNetwork?: { @@ -69,7 +69,7 @@ export class Cluster extends KubeObject { profile: string; }; }; - } + }; status?: { apiEndpoints: { host: string; @@ -84,7 +84,7 @@ export class Cluster extends KubeObject { }; errorMessage?: string; errorReason?: string; - } + }; getStatus() { if (this.metadata.deletionTimestamp) return ClusterStatus.REMOVING; diff --git a/src/renderer/api/endpoints/component-status.api.ts b/src/renderer/api/endpoints/component-status.api.ts index 7f7e04fe2a..fec4dda1da 100644 --- a/src/renderer/api/endpoints/component-status.api.ts +++ b/src/renderer/api/endpoints/component-status.api.ts @@ -8,11 +8,11 @@ export interface IComponentStatusCondition { } export class ComponentStatus extends KubeObject { - static kind = "ComponentStatus" - static namespaced = false - static apiBase = "/api/v1/componentstatuses" + static kind = "ComponentStatus"; + static namespaced = false; + static apiBase = "/api/v1/componentstatuses"; - conditions: IComponentStatusCondition[] + conditions: IComponentStatusCondition[]; getTruthyConditions() { return this.conditions.filter(c => c.status === "True"); diff --git a/src/renderer/api/endpoints/configmap.api.ts b/src/renderer/api/endpoints/configmap.api.ts index 59f3e3b090..042fb59d86 100644 --- a/src/renderer/api/endpoints/configmap.api.ts +++ b/src/renderer/api/endpoints/configmap.api.ts @@ -7,7 +7,7 @@ import { KubeApi } from "../kube-api"; export class ConfigMap extends KubeObject { static kind = "ConfigMap"; static namespaced = true; - static apiBase = "/api/v1/configmaps" + static apiBase = "/api/v1/configmaps"; constructor(data: KubeJsonApiData) { super(data); @@ -16,7 +16,7 @@ export class ConfigMap extends KubeObject { data: { [param: string]: string; - } + }; getKeys(): string[] { return Object.keys(this.data); diff --git a/src/renderer/api/endpoints/crd.api.ts b/src/renderer/api/endpoints/crd.api.ts index 1916d71f1b..02690a2afd 100644 --- a/src/renderer/api/endpoints/crd.api.ts +++ b/src/renderer/api/endpoints/crd.api.ts @@ -7,20 +7,20 @@ type AdditionalPrinterColumnsCommon = { type: "integer" | "number" | "string" | "boolean" | "date"; priority: number; description: string; -} +}; export type AdditionalPrinterColumnsV1 = AdditionalPrinterColumnsCommon & { jsonPath: string; -} +}; type AdditionalPrinterColumnsV1Beta = AdditionalPrinterColumnsCommon & { JSONPath: string; -} +}; export class CustomResourceDefinition extends KubeObject { static kind = "CustomResourceDefinition"; static namespaced = false; - static apiBase = "/apis/apiextensions.k8s.io/v1/customresourcedefinitions" + static apiBase = "/apis/apiextensions.k8s.io/v1/customresourcedefinitions"; spec: { group: string; @@ -45,7 +45,7 @@ export class CustomResourceDefinition extends KubeObject { webhook?: any; }; additionalPrinterColumns?: AdditionalPrinterColumnsV1Beta[]; // removed in v1 - } + }; status: { conditions: { lastTransitionTime: string; @@ -62,7 +62,7 @@ export class CustomResourceDefinition extends KubeObject { listKind: string; }; storedVersions: string[]; - } + }; getResourceUrl() { return crdResourcesURL({ @@ -70,25 +70,25 @@ export class CustomResourceDefinition extends KubeObject { group: this.getGroup(), name: this.getPluralName(), } - }) + }); } getResourceApiBase() { const { group } = this.spec; - return `/apis/${group}/${this.getVersion()}/${this.getPluralName()}` + return `/apis/${group}/${this.getVersion()}/${this.getPluralName()}`; } getPluralName() { - return this.getNames().plural + return this.getNames().plural; } getResourceKind() { - return this.spec.names.kind + return this.spec.names.kind; } getResourceTitle() { const name = this.getPluralName(); - return name[0].toUpperCase() + name.substr(1) + return name[0].toUpperCase() + name.substr(1); } getGroup() { @@ -141,7 +141,7 @@ export class CustomResourceDefinition extends KubeObject { ...condition, isReady: status === "True", tooltip: `${message || reason} (${lastTransitionTime})` - } + }; }); } } diff --git a/src/renderer/api/endpoints/cron-job.api.ts b/src/renderer/api/endpoints/cron-job.api.ts index b385647bb9..2cca8bfb3d 100644 --- a/src/renderer/api/endpoints/cron-job.api.ts +++ b/src/renderer/api/endpoints/cron-job.api.ts @@ -7,12 +7,12 @@ import { KubeApi } from "../kube-api"; @autobind() export class CronJob extends KubeObject { - static kind = "CronJob" - static namespaced = true - static apiBase = "/apis/batch/v1beta1/cronjobs" + static kind = "CronJob"; + static namespaced = true; + static apiBase = "/apis/batch/v1beta1/cronjobs"; - kind: string - apiVersion: string + kind: string; + apiVersion: string; metadata: { name: string; namespace: string; @@ -26,7 +26,7 @@ export class CronJob extends KubeObject { annotations: { [key: string]: string; }; - } + }; spec: { schedule: string; concurrencyPolicy: string; @@ -59,23 +59,23 @@ export class CronJob extends KubeObject { }; successfulJobsHistoryLimit: number; failedJobsHistoryLimit: number; - } + }; status: { lastScheduleTime?: string; - } + }; getSuspendFlag() { - return this.spec.suspend.toString() + return this.spec.suspend.toString(); } getLastScheduleTime() { - if (!this.status.lastScheduleTime) return "-" - const diff = moment().diff(this.status.lastScheduleTime) - return formatDuration(diff, true) + if (!this.status.lastScheduleTime) return "-"; + const diff = moment().diff(this.status.lastScheduleTime); + return formatDuration(diff, true); } getSchedule() { - return this.spec.schedule + return this.spec.schedule; } isNeverRun() { diff --git a/src/renderer/api/endpoints/daemon-set.api.ts b/src/renderer/api/endpoints/daemon-set.api.ts index d947293c1c..63fc6363e4 100644 --- a/src/renderer/api/endpoints/daemon-set.api.ts +++ b/src/renderer/api/endpoints/daemon-set.api.ts @@ -6,9 +6,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class DaemonSet extends WorkloadKubeObject { - static kind = "DaemonSet" - static namespaced = true - static apiBase = "/apis/apps/v1/daemonsets" + static kind = "DaemonSet"; + static namespaced = true; + static apiBase = "/apis/apps/v1/daemonsets"; spec: { selector: { @@ -51,7 +51,7 @@ export class DaemonSet extends WorkloadKubeObject { }; }; revisionHistoryLimit: number; - } + }; status: { currentNumberScheduled: number; numberMisscheduled: number; @@ -61,12 +61,12 @@ export class DaemonSet extends WorkloadKubeObject { updatedNumberScheduled: number; numberAvailable: number; numberUnavailable: number; - } + }; getImages() { - const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []) - const initContainers: IPodContainer[] = get(this, "spec.template.spec.initContainers", []) - return [...containers, ...initContainers].map(container => container.image) + const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []); + const initContainers: IPodContainer[] = get(this, "spec.template.spec.initContainers", []); + return [...containers, ...initContainers].map(container => container.image); } } diff --git a/src/renderer/api/endpoints/deployment.api.ts b/src/renderer/api/endpoints/deployment.api.ts index b21495ecc1..28ed71f86a 100644 --- a/src/renderer/api/endpoints/deployment.api.ts +++ b/src/renderer/api/endpoints/deployment.api.ts @@ -6,13 +6,13 @@ import { KubeApi } from "../kube-api"; export class DeploymentApi extends KubeApi { protected getScaleApiUrl(params: { namespace: string; name: string }) { - return this.getUrl(params) + "/scale" + return this.getUrl(params) + "/scale"; } getReplicas(params: { namespace: string; name: string }): Promise { return this.request .get(this.getScaleApiUrl(params)) - .then(({ status }: any) => status?.replicas) + .then(({ status }: any) => status?.replicas); } scale(params: { namespace: string; name: string }, replicas: number) { @@ -23,7 +23,7 @@ export class DeploymentApi extends KubeApi { replicas: replicas } } - }) + }); } restart(params: { namespace: string; name: string }) { @@ -42,15 +42,15 @@ export class DeploymentApi extends KubeApi { headers: { 'content-type': 'application/strategic-merge-patch+json' } - }) + }); } } @autobind() export class Deployment extends WorkloadKubeObject { - static kind = "Deployment" - static namespaced = true - static apiBase = "/apis/apps/v1/deployments" + static kind = "Deployment"; + static namespaced = true; + static apiBase = "/apis/apps/v1/deployments"; spec: { replicas: number; @@ -151,7 +151,7 @@ export class Deployment extends WorkloadKubeObject { maxSurge: number; }; }; - } + }; status: { observedGeneration: number; replicas: number; @@ -167,19 +167,19 @@ export class Deployment extends WorkloadKubeObject { reason: string; message: string; }[]; - } + }; getConditions(activeOnly = false) { - const { conditions } = this.status - if (!conditions) return [] + const { conditions } = this.status; + if (!conditions) return []; if (activeOnly) { - return conditions.filter(c => c.status === "True") + return conditions.filter(c => c.status === "True"); } - return conditions + return conditions; } getConditionsText(activeOnly = true) { - return this.getConditions(activeOnly).map(({ type }) => type).join(" ") + return this.getConditions(activeOnly).map(({ type }) => type).join(" "); } getReplicas() { diff --git a/src/renderer/api/endpoints/endpoint.api.ts b/src/renderer/api/endpoints/endpoint.api.ts index 4f4afc9b17..121836a637 100644 --- a/src/renderer/api/endpoints/endpoint.api.ts +++ b/src/renderer/api/endpoints/endpoint.api.ts @@ -42,22 +42,22 @@ export class EndpointAddress implements IEndpointAddress { }; constructor(data: IEndpointAddress) { - Object.assign(this, data) + Object.assign(this, data); } getId() { - return this.ip + return this.ip; } getName() { - return this.hostname + return this.hostname; } getTargetRef(): ITargetRef { if (this.targetRef) { - return Object.assign(this.targetRef, {apiVersion: "v1"}) + return Object.assign(this.targetRef, {apiVersion: "v1"}); } else { - return null + return null; } } } @@ -68,7 +68,7 @@ export class EndpointSubset implements IEndpointSubset { ports: IEndpointPort[]; constructor(data: IEndpointSubset) { - Object.assign(this, data) + Object.assign(this, data); } getAddresses(): EndpointAddress[] { @@ -83,26 +83,26 @@ export class EndpointSubset implements IEndpointSubset { toString(): string { if(!this.addresses) { - return "" + return ""; } return this.addresses.map(address => { if (!this.ports) { - return address.ip + return address.ip; } return this.ports.map(port => { - return `${address.ip}:${port.port}` - }).join(", ") - }).join(", ") + return `${address.ip}:${port.port}`; + }).join(", "); + }).join(", "); } } @autobind() export class Endpoint extends KubeObject { - static kind = "Endpoints" - static namespaced = true - static apiBase = "/api/v1/endpoints" + static kind = "Endpoints"; + static namespaced = true; + static apiBase = "/api/v1/endpoints"; - subsets: IEndpointSubset[] + subsets: IEndpointSubset[]; getEndpointSubsets(): EndpointSubset[] { const subsets = this.subsets || []; @@ -111,9 +111,9 @@ export class Endpoint extends KubeObject { toString(): string { if(this.subsets) { - return this.getEndpointSubsets().map(es => es.toString()).join(", ") + return this.getEndpointSubsets().map(es => es.toString()).join(", "); } else { - return "" + return ""; } } diff --git a/src/renderer/api/endpoints/events.api.ts b/src/renderer/api/endpoints/events.api.ts index 0608a3d44b..51dbf3c3b5 100644 --- a/src/renderer/api/endpoints/events.api.ts +++ b/src/renderer/api/endpoints/events.api.ts @@ -6,9 +6,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class KubeEvent extends KubeObject { - static kind = "Event" - static namespaced = true - static apiBase = "/api/v1/events" + static kind = "Event"; + static namespaced = true; + static apiBase = "/api/v1/events"; involvedObject: { kind: string; @@ -18,41 +18,41 @@ export class KubeEvent extends KubeObject { apiVersion: string; resourceVersion: string; fieldPath: string; - } - reason: string - message: string + }; + reason: string; + message: string; source: { component: string; host: string; - } - firstTimestamp: string - lastTimestamp: string - count: number - type: string - eventTime: null - reportingComponent: string - reportingInstance: string + }; + firstTimestamp: string; + lastTimestamp: string; + count: number; + type: string; + eventTime: null; + reportingComponent: string; + reportingInstance: string; isWarning() { return this.type === "Warning"; } getSource() { - const { component, host } = this.source - return `${component} ${host || ""}` + const { component, host } = this.source; + return `${component} ${host || ""}`; } getFirstSeenTime() { - const diff = moment().diff(this.firstTimestamp) - return formatDuration(diff, true) + const diff = moment().diff(this.firstTimestamp); + return formatDuration(diff, true); } getLastSeenTime() { - const diff = moment().diff(this.lastTimestamp) - return formatDuration(diff, true) + const diff = moment().diff(this.lastTimestamp); + return formatDuration(diff, true); } } export const eventApi = new KubeApi({ objectConstructor: KubeEvent, -}) +}); diff --git a/src/renderer/api/endpoints/helm-charts.api.ts b/src/renderer/api/endpoints/helm-charts.api.ts index 8943cd49df..e6328f136b 100644 --- a/src/renderer/api/endpoints/helm-charts.api.ts +++ b/src/renderer/api/endpoints/helm-charts.api.ts @@ -41,7 +41,7 @@ export const helmChartsApi = { return { readme, versions, - } + }; }); }, @@ -61,27 +61,27 @@ export class HelmChart { return new HelmChart(data); } - apiVersion: string - name: string - version: string - repo: string - kubeVersion?: string - created: string - description?: string - digest: string - keywords?: string[] - home?: string - sources?: string[] + apiVersion: string; + name: string; + version: string; + repo: string; + kubeVersion?: string; + created: string; + description?: string; + digest: string; + keywords?: string[]; + home?: string; + sources?: string[]; maintainers?: { name: string; email: string; url: string; - }[] - engine?: string - icon?: string - appVersion?: string - deprecated?: boolean - tillerVersion?: string + }[]; + engine?: string; + icon?: string; + appVersion?: string; + deprecated?: boolean; + tillerVersion?: string; getId() { return this.digest; diff --git a/src/renderer/api/endpoints/helm-releases.api.ts b/src/renderer/api/endpoints/helm-releases.api.ts index 9051936ac8..0ddbf1c734 100644 --- a/src/renderer/api/endpoints/helm-releases.api.ts +++ b/src/renderer/api/endpoints/helm-releases.api.ts @@ -82,7 +82,7 @@ export const helmReleasesApi = { return { ...details, resources - } + }; }); }, @@ -135,13 +135,13 @@ export class HelmRelease implements ItemObject { return new HelmRelease(data); } - appVersion: string - name: string - namespace: string - chart: string - status: string - updated: string - revision: string + appVersion: string; + name: string; + namespace: string; + chart: string; + status: string; + updated: string; + revision: string; getId() { return this.namespace + this.name; @@ -156,12 +156,12 @@ export class HelmRelease implements ItemObject { } getChart(withVersion = false) { - let chart = this.chart + let chart = this.chart; if(!withVersion && this.getVersion() != "" ) { - const search = new RegExp(`-${this.getVersion()}`) + const search = new RegExp(`-${this.getVersion()}`); chart = chart.replace(search, ""); } - return chart + return chart; } getRevision() { @@ -173,12 +173,12 @@ export class HelmRelease implements ItemObject { } getVersion() { - const versions = this.chart.match(/(v?\d+)[^-].*$/) + const versions = this.chart.match(/(v?\d+)[^-].*$/); if (versions) { - return versions[0] + return versions[0]; } else { - return "" + return ""; } } diff --git a/src/renderer/api/endpoints/hpa.api.ts b/src/renderer/api/endpoints/hpa.api.ts index f55f6d327f..79e6cada0f 100644 --- a/src/renderer/api/endpoints/hpa.api.ts +++ b/src/renderer/api/endpoints/hpa.api.ts @@ -20,7 +20,7 @@ export type IHpaMetricData = T & { currentAverageValue?: string; targetAverageUtilization?: number; targetAverageValue?: string; -} +}; export interface IHpaMetric { [kind: string]: IHpaMetricData; @@ -41,7 +41,7 @@ export interface IHpaMetric { export class HorizontalPodAutoscaler extends KubeObject { static kind = "HorizontalPodAutoscaler"; static namespaced = true; - static apiBase = "/apis/autoscaling/v2beta1/horizontalpodautoscalers" + static apiBase = "/apis/autoscaling/v2beta1/horizontalpodautoscalers"; spec: { scaleTargetRef: { @@ -52,7 +52,7 @@ export class HorizontalPodAutoscaler extends KubeObject { minReplicas: number; maxReplicas: number; metrics: IHpaMetric[]; - } + }; status: { currentReplicas: number; desiredReplicas: number; @@ -64,7 +64,7 @@ export class HorizontalPodAutoscaler extends KubeObject { status: string; type: string; }[]; - } + }; getMaxPods() { return this.spec.maxReplicas || 0; @@ -86,7 +86,7 @@ export class HorizontalPodAutoscaler extends KubeObject { ...condition, isReady: status === "True", tooltip: `${message || reason} (${lastTransitionTime})` - } + }; }); } @@ -102,7 +102,7 @@ export class HorizontalPodAutoscaler extends KubeObject { const { type, resource, pods, object, external } = metric; switch (type) { case HpaMetricType.Resource: - return resource.name + return resource.name; case HpaMetricType.Pods: return pods.metricName; case HpaMetricType.Object: @@ -128,7 +128,7 @@ export class HorizontalPodAutoscaler extends KubeObject { } if (target) { targetValue = target.targetAverageUtilization || target.targetAverageValue || target.targetValue; - if (target.targetAverageUtilization) targetValue += "%" + if (target.targetAverageUtilization) targetValue += "%"; } return `${currentValue} / ${targetValue}`; } diff --git a/src/renderer/api/endpoints/index.ts b/src/renderer/api/endpoints/index.ts index 337d193043..f1202b9122 100644 --- a/src/renderer/api/endpoints/index.ts +++ b/src/renderer/api/endpoints/index.ts @@ -1,35 +1,35 @@ // Kubernetes apis // Docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/ -export * from "./cluster.api" -export * from "./cluster-role.api" -export * from "./cluster-role-binding.api" -export * from "./configmap.api" -export * from "./crd.api" -export * from "./cron-job.api" -export * from "./daemon-set.api" -export * from "./deployment.api" -export * from "./endpoint.api" -export * from "./events.api" -export * from "./hpa.api" -export * from "./ingress.api" -export * from "./job.api" -export * from "./namespaces.api" -export * from "./network-policy.api" -export * from "./nodes.api" -export * from "./persistent-volume.api" -export * from "./persistent-volume-claims.api" -export * from "./pods.api" -export * from "./poddisruptionbudget.api" -export * from "./pod-metrics.api" -export * from "./podsecuritypolicy.api" -export * from "./replica-set.api" -export * from "./resource-quota.api" -export * from "./role.api" -export * from "./role-binding.api" -export * from "./secret.api" -export * from "./selfsubjectrulesreviews.api" -export * from "./service.api" -export * from "./service-accounts.api" -export * from "./stateful-set.api" -export * from "./storage-class.api" +export * from "./cluster.api"; +export * from "./cluster-role.api"; +export * from "./cluster-role-binding.api"; +export * from "./configmap.api"; +export * from "./crd.api"; +export * from "./cron-job.api"; +export * from "./daemon-set.api"; +export * from "./deployment.api"; +export * from "./endpoint.api"; +export * from "./events.api"; +export * from "./hpa.api"; +export * from "./ingress.api"; +export * from "./job.api"; +export * from "./namespaces.api"; +export * from "./network-policy.api"; +export * from "./nodes.api"; +export * from "./persistent-volume.api"; +export * from "./persistent-volume-claims.api"; +export * from "./pods.api"; +export * from "./poddisruptionbudget.api"; +export * from "./pod-metrics.api"; +export * from "./podsecuritypolicy.api"; +export * from "./replica-set.api"; +export * from "./resource-quota.api"; +export * from "./role.api"; +export * from "./role-binding.api"; +export * from "./secret.api"; +export * from "./selfsubjectrulesreviews.api"; +export * from "./service.api"; +export * from "./service-accounts.api"; +export * from "./stateful-set.api"; +export * from "./storage-class.api"; diff --git a/src/renderer/api/endpoints/ingress.api.ts b/src/renderer/api/endpoints/ingress.api.ts index 1f3e1659f0..0594e3446e 100644 --- a/src/renderer/api/endpoints/ingress.api.ts +++ b/src/renderer/api/endpoints/ingress.api.ts @@ -5,7 +5,7 @@ import { KubeApi } from "../kube-api"; export class IngressApi extends KubeApi { getMetrics(ingress: string, namespace: string): Promise { - const opts = { category: "ingress", ingress } + const opts = { category: "ingress", ingress }; return metricsApi.getMetrics({ bytesSentSuccess: opts, bytesSentFailure: opts, @@ -31,9 +31,9 @@ export interface ILoadBalancerIngress { } @autobind() export class Ingress extends KubeObject { - static kind = "Ingress" - static namespaced = true - static apiBase = "/apis/extensions/v1beta1/ingresses" + static kind = "Ingress"; + static namespaced = true; + static apiBase = "/apis/extensions/v1beta1/ingresses"; spec: { tls: { @@ -55,59 +55,59 @@ export class Ingress extends KubeObject { serviceName: string; servicePort: number; }; - } + }; status: { loadBalancer: { ingress: ILoadBalancerIngress[]; }; - } + }; getRoutes() { - const { spec: { tls, rules } } = this - if (!rules) return [] + const { spec: { tls, rules } } = this; + if (!rules) return []; - let protocol = "http" - const routes: string[] = [] + let protocol = "http"; + const routes: string[] = []; if (tls && tls.length > 0) { - protocol += "s" + protocol += "s"; } rules.map(rule => { - const host = rule.host ? rule.host : "*" + const host = rule.host ? rule.host : "*"; if (rule.http && rule.http.paths) { rule.http.paths.forEach(path => { - routes.push(protocol + "://" + host + (path.path || "/") + " ⇢ " + path.backend.serviceName + ":" + path.backend.servicePort) - }) + routes.push(protocol + "://" + host + (path.path || "/") + " ⇢ " + path.backend.serviceName + ":" + path.backend.servicePort); + }); } - }) + }); return routes; } getHosts() { - const { spec: { rules } } = this - if (!rules) return [] - return rules.filter(rule => rule.host).map(rule => rule.host) + const { spec: { rules } } = this; + if (!rules) return []; + return rules.filter(rule => rule.host).map(rule => rule.host); } getPorts() { - const ports: number[] = [] - const { spec: { tls, rules, backend } } = this - const httpPort = 80 - const tlsPort = 443 + const ports: number[] = []; + const { spec: { tls, rules, backend } } = this; + const httpPort = 80; + const tlsPort = 443; if (rules && rules.length > 0) { if (rules.some(rule => rule.hasOwnProperty("http"))) { - ports.push(httpPort) + ports.push(httpPort); } } else { if (backend && backend.servicePort) { - ports.push(backend.servicePort) + ports.push(backend.servicePort); } } if (tls && tls.length > 0) { - ports.push(tlsPort) + ports.push(tlsPort); } - return ports.join(", ") + return ports.join(", "); } getLoadBalancers() { @@ -115,7 +115,7 @@ export class Ingress extends KubeObject { return (loadBalancer.ingress ?? []).map(address => ( address.hostname || address.ip - )) + )); } } diff --git a/src/renderer/api/endpoints/job.api.ts b/src/renderer/api/endpoints/job.api.ts index 59e9e9ba8f..1dc78fdc94 100644 --- a/src/renderer/api/endpoints/job.api.ts +++ b/src/renderer/api/endpoints/job.api.ts @@ -7,9 +7,9 @@ import { JsonApiParams } from "../json-api"; @autobind() export class Job extends WorkloadKubeObject { - static kind = "Job" - static namespaced = true - static apiBase = "/apis/batch/v1/jobs" + static kind = "Job"; + static namespaced = true; + static apiBase = "/apis/batch/v1/jobs"; spec: { parallelism?: number; @@ -56,7 +56,7 @@ export class Job extends WorkloadKubeObject { serviceAccountName?: string; serviceAccount?: string; schedulerName?: string; - } + }; status: { conditions: { type: string; @@ -68,7 +68,7 @@ export class Job extends WorkloadKubeObject { startTime: string; completionTime: string; succeeded: number; - } + }; getDesiredCompletions() { return this.spec.completions || 0; @@ -91,15 +91,15 @@ export class Job extends WorkloadKubeObject { } getImages() { - const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []) - return [...containers].map(container => container.image) + const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []); + return [...containers].map(container => container.image); } delete() { const params: JsonApiParams = { query: { propagationPolicy: "Background" } - } - return super.delete(params) + }; + return super.delete(params); } } diff --git a/src/renderer/api/endpoints/metrics.api.ts b/src/renderer/api/endpoints/metrics.api.ts index 81d2f1d500..7f30487d44 100644 --- a/src/renderer/api/endpoints/metrics.api.ts +++ b/src/renderer/api/endpoints/metrics.api.ts @@ -66,7 +66,7 @@ export function normalizeMetrics(metrics: IMetrics, frames = 60): IMetrics { } as IMetricsResult], }, status: "", - } + }; } const { result } = metrics.data; @@ -78,7 +78,7 @@ export function normalizeMetrics(metrics: IMetrics, frames = 60): IMetrics { if (!res.values || !res.values.length) return; while (res.values.length < frames) { const timestamp = moment.unix(res.values[0][0]).subtract(1, "minute").unix(); - res.values.unshift([timestamp, "0"]) + res.values.unshift([timestamp, "0"]); } }); } @@ -103,7 +103,7 @@ export function getItemMetrics(metrics: { [key: string]: IMetrics }, itemName: s const itemMetrics = { ...metrics }; for (const metric in metrics) { if (!metrics[metric]?.data?.result) { - continue + continue; } const results = metrics[metric].data.result; const result = results.find(res => Object.values(res.metric)[0] == itemName); diff --git a/src/renderer/api/endpoints/namespaces.api.ts b/src/renderer/api/endpoints/namespaces.api.ts index c615789cd9..430565bf57 100644 --- a/src/renderer/api/endpoints/namespaces.api.ts +++ b/src/renderer/api/endpoints/namespaces.api.ts @@ -15,7 +15,7 @@ export class Namespace extends KubeObject { status?: { phase: string; - } + }; getStatus() { return this.status ? this.status.phase : "-"; diff --git a/src/renderer/api/endpoints/network-policy.api.ts b/src/renderer/api/endpoints/network-policy.api.ts index bfae6cbcdc..4ecd333854 100644 --- a/src/renderer/api/endpoints/network-policy.api.ts +++ b/src/renderer/api/endpoints/network-policy.api.ts @@ -37,9 +37,9 @@ export interface IPolicyEgress { @autobind() export class NetworkPolicy extends KubeObject { - static kind = "NetworkPolicy" - static namespaced = true - static apiBase = "/apis/networking.k8s.io/v1/networkpolicies" + static kind = "NetworkPolicy"; + static namespaced = true; + static apiBase = "/apis/networking.k8s.io/v1/networkpolicies"; spec: { podSelector: { @@ -51,13 +51,13 @@ export class NetworkPolicy extends KubeObject { policyTypes: string[]; ingress: IPolicyIngress[]; egress: IPolicyEgress[]; - } + }; getMatchLabels(): string[] { if (!this.spec.podSelector || !this.spec.podSelector.matchLabels) return []; return Object .entries(this.spec.podSelector.matchLabels) - .map(data => data.join(":")) + .map(data => data.join(":")); } getTypes(): string[] { diff --git a/src/renderer/api/endpoints/nodes.api.ts b/src/renderer/api/endpoints/nodes.api.ts index f8031a9824..c85cd8f9b0 100644 --- a/src/renderer/api/endpoints/nodes.api.ts +++ b/src/renderer/api/endpoints/nodes.api.ts @@ -5,7 +5,7 @@ import { KubeApi } from "../kube-api"; export class NodesApi extends KubeApi { getMetrics(): Promise { - const opts = { category: "nodes"} + const opts = { category: "nodes"}; return metricsApi.getMetrics({ memoryUsage: opts, @@ -30,9 +30,9 @@ export interface INodeMetrics { @autobind() export class Node extends KubeObject { - static kind = "Node" - static namespaced = false - static apiBase = "/api/v1/nodes" + static kind = "Node"; + static namespaced = false; + static apiBase = "/api/v1/nodes"; spec: { podCIDR: string; @@ -43,7 +43,7 @@ export class Node extends KubeObject { effect: string; }[]; unschedulable?: boolean; - } + }; status: { capacity: { cpu: string; @@ -83,15 +83,15 @@ export class Node extends KubeObject { names: string[]; sizeBytes: number; }[]; - } + }; getNodeConditionText() { - const { conditions } = this.status - if (!conditions) return "" + const { conditions } = this.status; + if (!conditions) return ""; return conditions.reduce((types, current) => { - if (current.status !== "True") return "" - return types += ` ${current.type}` - }, "") + if (current.status !== "True") return ""; + return types += ` ${current.type}`; + }, ""); } getTaints() { @@ -101,23 +101,23 @@ export class Node extends KubeObject { getRoleLabels() { const roleLabels = Object.keys(this.metadata.labels).filter(key => key.includes("node-role.kubernetes.io") - ).map(key => key.match(/([^/]+$)/)[0]) // all after last slash + ).map(key => key.match(/([^/]+$)/)[0]); // all after last slash if (this.metadata.labels["kubernetes.io/role"] != undefined) { - roleLabels.push(this.metadata.labels["kubernetes.io/role"]) + roleLabels.push(this.metadata.labels["kubernetes.io/role"]); } - return roleLabels.join(", ") + return roleLabels.join(", "); } getCpuCapacity() { - if (!this.status.capacity || !this.status.capacity.cpu) return 0 - return cpuUnitsToNumber(this.status.capacity.cpu) + if (!this.status.capacity || !this.status.capacity.cpu) return 0; + return cpuUnitsToNumber(this.status.capacity.cpu); } getMemoryCapacity() { - if (!this.status.capacity || !this.status.capacity.memory) return 0 - return unitsToBytes(this.status.capacity.memory) + if (!this.status.capacity || !this.status.capacity.memory) return 0; + return unitsToBytes(this.status.capacity.memory); } getConditions() { @@ -144,16 +144,16 @@ export class Node extends KubeObject { } getOperatingSystem(): string { - const label = this.getLabels().find(label => label.startsWith("kubernetes.io/os=")) + const label = this.getLabels().find(label => label.startsWith("kubernetes.io/os=")); if (label) { - return label.split("=", 2)[1] + return label.split("=", 2)[1]; } - return "linux" + return "linux"; } isUnschedulable() { - return this.spec.unschedulable + return this.spec.unschedulable; } } diff --git a/src/renderer/api/endpoints/persistent-volume-claims.api.ts b/src/renderer/api/endpoints/persistent-volume-claims.api.ts index 4e719c529b..9aa73bb0bc 100644 --- a/src/renderer/api/endpoints/persistent-volume-claims.api.ts +++ b/src/renderer/api/endpoints/persistent-volume-claims.api.ts @@ -23,9 +23,9 @@ export interface IPvcMetrics { @autobind() export class PersistentVolumeClaim extends KubeObject { - static kind = "PersistentVolumeClaim" - static namespaced = true - static apiBase = "/api/v1/persistentvolumeclaims" + static kind = "PersistentVolumeClaim"; + static namespaced = true; + static apiBase = "/api/v1/persistentvolumeclaims"; spec: { accessModes: string[]; @@ -45,19 +45,19 @@ export class PersistentVolumeClaim extends KubeObject { storage: string; // 8Gi }; }; - } + }; status: { phase: string; // Pending - } + }; getPods(allPods: Pod[]): Pod[] { - const pods = allPods.filter(pod => pod.getNs() === this.getNs()) + const pods = allPods.filter(pod => pod.getNs() === this.getNs()); return pods.filter(pod => { return pod.getVolumes().filter(volume => volume.persistentVolumeClaim && volume.persistentVolumeClaim.claimName === this.getName() - ).length > 0 - }) + ).length > 0; + }); } getStorage(): string { @@ -78,7 +78,7 @@ export class PersistentVolumeClaim extends KubeObject { getStatus(): string { if (this.status) return this.status.phase; - return "-" + return "-"; } } diff --git a/src/renderer/api/endpoints/persistent-volume.api.ts b/src/renderer/api/endpoints/persistent-volume.api.ts index 8ab2efbf89..5e31eeb028 100644 --- a/src/renderer/api/endpoints/persistent-volume.api.ts +++ b/src/renderer/api/endpoints/persistent-volume.api.ts @@ -5,9 +5,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class PersistentVolume extends KubeObject { - static kind = "PersistentVolume" - static namespaced = false - static apiBase = "/api/v1/persistentvolumes" + static kind = "PersistentVolume"; + static namespaced = false; + static apiBase = "/api/v1/persistentvolumes"; spec: { capacity: { @@ -38,17 +38,17 @@ export class PersistentVolume extends KubeObject { path: string; server: string; }; - } + }; status: { phase: string; reason?: string; - } + }; getCapacity(inBytes = false) { const capacity = this.spec.capacity; if (capacity) { - if (inBytes) return unitsToBytes(capacity.storage) + if (inBytes) return unitsToBytes(capacity.storage); return capacity.storage; } return 0; diff --git a/src/renderer/api/endpoints/pod-metrics.api.ts b/src/renderer/api/endpoints/pod-metrics.api.ts index 7e01a1a990..acf6e7b20f 100644 --- a/src/renderer/api/endpoints/pod-metrics.api.ts +++ b/src/renderer/api/endpoints/pod-metrics.api.ts @@ -2,19 +2,19 @@ import { KubeObject } from "../kube-object"; import { KubeApi } from "../kube-api"; export class PodMetrics extends KubeObject { - static kind = "Pod" - static namespaced = true - static apiBase = "/apis/metrics.k8s.io/v1beta1/pods" + static kind = "Pod"; + static namespaced = true; + static apiBase = "/apis/metrics.k8s.io/v1beta1/pods"; - timestamp: string - window: string + timestamp: string; + window: string; containers: { name: string; usage: { cpu: string; memory: string; }; - }[] + }[]; } export const podMetricsApi = new KubeApi({ diff --git a/src/renderer/api/endpoints/poddisruptionbudget.api.ts b/src/renderer/api/endpoints/poddisruptionbudget.api.ts index ea7e0575ff..b76260ae6f 100644 --- a/src/renderer/api/endpoints/poddisruptionbudget.api.ts +++ b/src/renderer/api/endpoints/poddisruptionbudget.api.ts @@ -12,13 +12,13 @@ export class PodDisruptionBudget extends KubeObject { minAvailable: string; maxUnavailable: string; selector: { matchLabels: { [app: string]: string } }; - } + }; status: { currentHealthy: number desiredHealthy: number disruptionsAllowed: number expectedPods: number - } + }; getSelectors() { const selector = this.spec.selector; diff --git a/src/renderer/api/endpoints/pods.api.ts b/src/renderer/api/endpoints/pods.api.ts index 92b7059272..a5c833b5fa 100644 --- a/src/renderer/api/endpoints/pods.api.ts +++ b/src/renderer/api/endpoints/pods.api.ts @@ -11,7 +11,7 @@ export class PodsApi extends KubeApi { getMetrics(pods: Pod[], namespace: string, selector = "pod, namespace"): Promise { const podSelector = pods.map(pod => pod.getName()).join("|"); - const opts = { category: "pods", pods: podSelector, namespace, selector } + const opts = { category: "pods", pods: podSelector, namespace, selector }; return metricsApi.getMetrics({ cpuUsage: opts, @@ -171,9 +171,9 @@ export interface IPodContainerStatus { @autobind() export class Pod extends WorkloadKubeObject { - static kind = "Pod" - static namespaced = true - static apiBase = "/api/v1/pods" + static kind = "Pod"; + static namespaced = true; + static apiBase = "/api/v1/pods"; spec: { volumes?: { @@ -215,7 +215,7 @@ export class Pod extends WorkloadKubeObject { tolerationSeconds: number; }[]; affinity: IAffinity; - } + }; status: { phase: string; conditions: { @@ -231,7 +231,7 @@ export class Pod extends WorkloadKubeObject { containerStatuses?: IPodContainerStatus[]; qosClass: string; reason?: string; - } + }; getInitContainers() { return this.spec.initContainers || []; @@ -246,11 +246,11 @@ export class Pod extends WorkloadKubeObject { } getRunningContainers() { - const statuses = this.getContainerStatuses() + const statuses = this.getContainerStatuses(); return this.getAllContainers().filter(container => { - return statuses.find(status => status.name === container.name && !!status.state["running"]) + return statuses.find(status => status.name === container.name && !!status.state["running"]); } - ) + ); } getContainerStatuses(includeInitContainers = true) { @@ -323,7 +323,7 @@ export class Pod extends WorkloadKubeObject { const { reason } = state.terminated; message = reason ? reason : "Terminated"; } - }) + }); } if (message) return message; return this.getStatusPhase(); @@ -348,32 +348,32 @@ export class Pod extends WorkloadKubeObject { } getNodeSelectors(): string[] { - const { nodeSelector } = this.spec - if (!nodeSelector) return [] - return Object.entries(nodeSelector).map(values => values.join(": ")) + const { nodeSelector } = this.spec; + if (!nodeSelector) return []; + return Object.entries(nodeSelector).map(values => values.join(": ")); } getTolerations() { - return this.spec.tolerations || [] + return this.spec.tolerations || []; } getAffinity(): IAffinity { - return this.spec.affinity + return this.spec.affinity; } hasIssues() { const notReady = !!this.getConditions().find(condition => { - return condition.type == "Ready" && condition.status !== "True" + return condition.type == "Ready" && condition.status !== "True"; }); const crashLoop = !!this.getContainerStatuses().find(condition => { - const waiting = condition.state.waiting - return (waiting && waiting.reason == "CrashLoopBackOff") - }) + const waiting = condition.state.waiting; + return (waiting && waiting.reason == "CrashLoopBackOff"); + }); return ( notReady || crashLoop || this.getStatusPhase() !== "Running" - ) + ); } getLivenessProbe(container: IPodContainer) { @@ -418,14 +418,14 @@ export class Pod extends WorkloadKubeObject { } getNodeName() { - return this.spec?.nodeName + return this.spec?.nodeName; } getSelectedNodeOs() { - if (!this.spec.nodeSelector) return - if (!this.spec.nodeSelector["kubernetes.io/os"] && !this.spec.nodeSelector["beta.kubernetes.io/os"]) return + if (!this.spec.nodeSelector) return; + if (!this.spec.nodeSelector["kubernetes.io/os"] && !this.spec.nodeSelector["beta.kubernetes.io/os"]) return; - return this.spec.nodeSelector["kubernetes.io/os"] || this.spec.nodeSelector["beta.kubernetes.io/os"] + return this.spec.nodeSelector["kubernetes.io/os"] || this.spec.nodeSelector["beta.kubernetes.io/os"]; } } diff --git a/src/renderer/api/endpoints/podsecuritypolicy.api.ts b/src/renderer/api/endpoints/podsecuritypolicy.api.ts index aa705c8748..c7981f65be 100644 --- a/src/renderer/api/endpoints/podsecuritypolicy.api.ts +++ b/src/renderer/api/endpoints/podsecuritypolicy.api.ts @@ -4,9 +4,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class PodSecurityPolicy extends KubeObject { - static kind = "PodSecurityPolicy" - static namespaced = false - static apiBase = "/apis/policy/v1beta1/podsecuritypolicies" + static kind = "PodSecurityPolicy"; + static namespaced = false; + static apiBase = "/apis/policy/v1beta1/podsecuritypolicies"; spec: { allowPrivilegeEscalation?: boolean; @@ -66,7 +66,7 @@ export class PodSecurityPolicy extends KubeObject { ranges: { max: number; min: number }[]; }; volumes?: string[]; - } + }; isPrivileged() { return !!this.spec.privileged; diff --git a/src/renderer/api/endpoints/replica-set.api.ts b/src/renderer/api/endpoints/replica-set.api.ts index dd06299644..d1081811e9 100644 --- a/src/renderer/api/endpoints/replica-set.api.ts +++ b/src/renderer/api/endpoints/replica-set.api.ts @@ -6,9 +6,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class ReplicaSet extends WorkloadKubeObject { - static kind = "ReplicaSet" - static namespaced = true - static apiBase = "/apis/apps/v1/replicasets" + static kind = "ReplicaSet"; + static namespaced = true; + static apiBase = "/apis/apps/v1/replicasets"; spec: { replicas?: number; @@ -37,18 +37,18 @@ export class ReplicaSet extends WorkloadKubeObject { terminationGracePeriodSeconds?: number; dnsPolicy?: string; schedulerName?: string; - } + }; status: { replicas: number; fullyLabeledReplicas: number; readyReplicas: number; availableReplicas: number; observedGeneration: number; - } + }; getImages() { - const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []) - return [...containers].map(container => container.image) + const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []); + return [...containers].map(container => container.image); } } diff --git a/src/renderer/api/endpoints/resource-applier.api.ts b/src/renderer/api/endpoints/resource-applier.api.ts index 088c7ed8f2..a2843a6262 100644 --- a/src/renderer/api/endpoints/resource-applier.api.ts +++ b/src/renderer/api/endpoints/resource-applier.api.ts @@ -1,4 +1,4 @@ -import jsYaml from "js-yaml" +import jsYaml from "js-yaml"; import { KubeObject } from "../kube-object"; import { KubeJsonApiData } from "../kube-json-api"; import { apiBase } from "../index"; @@ -21,7 +21,7 @@ export const resourceApplierApi = { if (api) { return new api.objectConstructor(obj); } else { - return new KubeObject(obj) + return new KubeObject(obj); } }); return items.length === 1 ? items[0] : items; diff --git a/src/renderer/api/endpoints/resource-quota.api.ts b/src/renderer/api/endpoints/resource-quota.api.ts index ce73d24595..a19e4025c5 100644 --- a/src/renderer/api/endpoints/resource-quota.api.ts +++ b/src/renderer/api/endpoints/resource-quota.api.ts @@ -31,13 +31,13 @@ export interface IResourceQuotaValues { } export class ResourceQuota extends KubeObject { - static kind = "ResourceQuota" - static namespaced = true - static apiBase = "/api/v1/resourcequotas" + static kind = "ResourceQuota"; + static namespaced = true; + static apiBase = "/api/v1/resourcequotas"; constructor(data: KubeJsonApiData) { super(data); - this.spec = this.spec || {} as any + this.spec = this.spec || {} as any; } spec: { @@ -49,12 +49,12 @@ export class ResourceQuota extends KubeObject { values: string[]; }[]; }; - } + }; status: { hard: IResourceQuotaValues; used: IResourceQuotaValues; - } + }; getScopeSelector() { const { matchExpressions = [] } = this.spec.scopeSelector || {}; diff --git a/src/renderer/api/endpoints/role-binding.api.ts b/src/renderer/api/endpoints/role-binding.api.ts index 455e2c6e4d..866656ee56 100644 --- a/src/renderer/api/endpoints/role-binding.api.ts +++ b/src/renderer/api/endpoints/role-binding.api.ts @@ -11,23 +11,23 @@ export interface IRoleBindingSubject { @autobind() export class RoleBinding extends KubeObject { - static kind = "RoleBinding" - static namespaced = true - static apiBase = "/apis/rbac.authorization.k8s.io/v1/rolebindings" + static kind = "RoleBinding"; + static namespaced = true; + static apiBase = "/apis/rbac.authorization.k8s.io/v1/rolebindings"; - subjects?: IRoleBindingSubject[] + subjects?: IRoleBindingSubject[]; roleRef: { kind: string; name: string; apiGroup?: string; - } + }; getSubjects() { return this.subjects || []; } getSubjectNames(): string { - return this.getSubjects().map(subject => subject.name).join(", ") + return this.getSubjects().map(subject => subject.name).join(", "); } } diff --git a/src/renderer/api/endpoints/role.api.ts b/src/renderer/api/endpoints/role.api.ts index 400761cfbe..c89834ed05 100644 --- a/src/renderer/api/endpoints/role.api.ts +++ b/src/renderer/api/endpoints/role.api.ts @@ -2,16 +2,16 @@ import { KubeObject } from "../kube-object"; import { KubeApi } from "../kube-api"; export class Role extends KubeObject { - static kind = "Role" - static namespaced = true - static apiBase = "/apis/rbac.authorization.k8s.io/v1/roles" + static kind = "Role"; + static namespaced = true; + static apiBase = "/apis/rbac.authorization.k8s.io/v1/roles"; rules: { verbs: string[]; apiGroups: string[]; resources: string[]; resourceNames?: string[]; - }[] + }[]; getRules() { return this.rules || []; diff --git a/src/renderer/api/endpoints/secret.api.ts b/src/renderer/api/endpoints/secret.api.ts index f2166abbe1..16262570df 100644 --- a/src/renderer/api/endpoints/secret.api.ts +++ b/src/renderer/api/endpoints/secret.api.ts @@ -21,15 +21,15 @@ export interface ISecretRef { @autobind() export class Secret extends KubeObject { - static kind = "Secret" - static namespaced = true - static apiBase = "/api/v1/secrets" + static kind = "Secret"; + static namespaced = true; + static apiBase = "/api/v1/secrets"; type: SecretType; data: { [prop: string]: string; token?: string; - } + }; constructor(data: KubeJsonApiData) { super(data); diff --git a/src/renderer/api/endpoints/selfsubjectrulesreviews.api.ts b/src/renderer/api/endpoints/selfsubjectrulesreviews.api.ts index 1beece3fc3..149a94e678 100644 --- a/src/renderer/api/endpoints/selfsubjectrulesreviews.api.ts +++ b/src/renderer/api/endpoints/selfsubjectrulesreviews.api.ts @@ -21,20 +21,20 @@ export interface ISelfSubjectReviewRule { } export class SelfSubjectRulesReview extends KubeObject { - static kind = "SelfSubjectRulesReview" - static namespaced = false - static apiBase = "/apis/authorization.k8s.io/v1/selfsubjectrulesreviews" + static kind = "SelfSubjectRulesReview"; + static namespaced = false; + static apiBase = "/apis/authorization.k8s.io/v1/selfsubjectrulesreviews"; spec: { // todo: add more types from api docs namespace?: string; - } + }; status: { resourceRules: ISelfSubjectReviewRule[]; nonResourceRules: ISelfSubjectReviewRule[]; incomplete: boolean; - } + }; getResourceRules() { const rules = this.status && this.status.resourceRules || []; @@ -58,7 +58,7 @@ export class SelfSubjectRulesReview extends KubeObject { const separator = apiGroup == "" ? "" : "."; return resource + separator + apiGroup; }) - } + }; } } diff --git a/src/renderer/api/endpoints/service-accounts.api.ts b/src/renderer/api/endpoints/service-accounts.api.ts index 4f3ae47014..9f449cdec4 100644 --- a/src/renderer/api/endpoints/service-accounts.api.ts +++ b/src/renderer/api/endpoints/service-accounts.api.ts @@ -6,14 +6,14 @@ import { KubeApi } from "../kube-api"; export class ServiceAccount extends KubeObject { static kind = "ServiceAccount"; static namespaced = true; - static apiBase = "/api/v1/serviceaccounts" + static apiBase = "/api/v1/serviceaccounts"; secrets?: { name: string; - }[] + }[]; imagePullSecrets?: { name: string; - }[] + }[]; getSecrets() { return this.secrets || []; diff --git a/src/renderer/api/endpoints/service.api.ts b/src/renderer/api/endpoints/service.api.ts index 49ac733220..5524e85263 100644 --- a/src/renderer/api/endpoints/service.api.ts +++ b/src/renderer/api/endpoints/service.api.ts @@ -17,7 +17,7 @@ export class ServicePort implements IServicePort { nodePort?: number; constructor(data: IServicePort) { - Object.assign(this, data) + Object.assign(this, data); } toString() { @@ -31,9 +31,9 @@ export class ServicePort implements IServicePort { @autobind() export class Service extends KubeObject { - static kind = "Service" - static namespaced = true - static apiBase = "/api/v1/services" + static kind = "Service"; + static namespaced = true; + static apiBase = "/api/v1/services"; spec: { type: string; @@ -44,7 +44,7 @@ export class Service extends KubeObject { selector: { [key: string]: string }; ports: ServicePort[]; externalIPs?: string[]; // https://kubernetes.io/docs/concepts/services-networking/service/#external-ips - } + }; status: { loadBalancer?: { @@ -53,7 +53,7 @@ export class Service extends KubeObject { hostname?: string; }[]; }; - } + }; getClusterIp() { return this.spec.clusterIP; @@ -62,7 +62,7 @@ export class Service extends KubeObject { getExternalIps() { const lb = this.getLoadBalancer(); if (lb && lb.ingress) { - return lb.ingress.map(val => val.ip || val.hostname) + return lb.ingress.map(val => val.ip || val.hostname); } return this.spec.externalIPs || []; } diff --git a/src/renderer/api/endpoints/stateful-set.api.ts b/src/renderer/api/endpoints/stateful-set.api.ts index c507e7df59..6a6f8c151d 100644 --- a/src/renderer/api/endpoints/stateful-set.api.ts +++ b/src/renderer/api/endpoints/stateful-set.api.ts @@ -6,9 +6,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class StatefulSet extends WorkloadKubeObject { - static kind = "StatefulSet" - static namespaced = true - static apiBase = "/apis/apps/v1/statefulsets" + static kind = "StatefulSet"; + static namespaced = true; + static apiBase = "/apis/apps/v1/statefulsets"; spec: { serviceName: string; @@ -62,7 +62,7 @@ export class StatefulSet extends WorkloadKubeObject { }; }; }[]; - } + }; status: { observedGeneration: number; replicas: number; @@ -70,11 +70,11 @@ export class StatefulSet extends WorkloadKubeObject { currentRevision: string; updateRevision: string; collisionCount: number; - } + }; getImages() { - const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []) - return [...containers].map(container => container.image) + const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []); + return [...containers].map(container => container.image); } } diff --git a/src/renderer/api/endpoints/storage-class.api.ts b/src/renderer/api/endpoints/storage-class.api.ts index cf05e13eaf..adb2059e4a 100644 --- a/src/renderer/api/endpoints/storage-class.api.ts +++ b/src/renderer/api/endpoints/storage-class.api.ts @@ -4,9 +4,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class StorageClass extends KubeObject { - static kind = "StorageClass" - static namespaced = false - static apiBase = "/apis/storage.k8s.io/v1/storageclasses" + static kind = "StorageClass"; + static namespaced = false; + static apiBase = "/apis/storage.k8s.io/v1/storageclasses"; provisioner: string; // e.g. "storage.k8s.io/v1" mountOptions?: string[]; @@ -14,22 +14,22 @@ export class StorageClass extends KubeObject { reclaimPolicy: string; parameters: { [param: string]: string; // every provisioner has own set of these parameters - } + }; isDefault() { const annotations = this.metadata.annotations || {}; return ( annotations["storageclass.kubernetes.io/is-default-class"] === "true" || annotations["storageclass.beta.kubernetes.io/is-default-class"] === "true" - ) + ); } getVolumeBindingMode() { - return this.volumeBindingMode || "-" + return this.volumeBindingMode || "-"; } getReclaimPolicy() { - return this.reclaimPolicy || "-" + return this.reclaimPolicy || "-"; } } diff --git a/src/renderer/api/json-api.ts b/src/renderer/api/json-api.ts index e42996c041..cc239a804e 100644 --- a/src/renderer/api/json-api.ts +++ b/src/renderer/api/json-api.ts @@ -110,23 +110,23 @@ export class JsonApi { } else { const error = new JsonApiErrorParsed(data, this.parseError(data, res)); this.onError.emit(error, res); - this.writeLog({ ...log, error }) + this.writeLog({ ...log, error }); throw error; } - }) + }); } protected parseError(error: JsonApiError | string, res: Response): string[] { if (typeof error === "string") { - return [error] + return [error]; } else if (Array.isArray(error.errors)) { - return error.errors.map(error => error.title) + return error.errors.map(error => error.title); } else if (error.message) { - return [error.message] + return [error.message]; } - return [res.statusText || "Error!"] + return [res.statusText || "Error!"]; } protected writeLog(log: JsonApiLog) { diff --git a/src/renderer/api/kube-api-parse.ts b/src/renderer/api/kube-api-parse.ts index c4c93562cf..0995fac24f 100644 --- a/src/renderer/api/kube-api-parse.ts +++ b/src/renderer/api/kube-api-parse.ts @@ -51,7 +51,7 @@ export function parseKubeApi(path: string): IKubeApiParsed { } else { switch (left.length) { case 4: - [apiGroup, apiVersion, resource, name] = left + [apiGroup, apiVersion, resource, name] = left; break; case 2: resource = left.pop(); @@ -79,11 +79,11 @@ export function parseKubeApi(path: string): IKubeApiParsed { */ if (left[0].includes('.') || left[1].match(/^v[0-9]/)) { [apiGroup, apiVersion] = left; - resource = left.slice(2).join("/") + resource = left.slice(2).join("/"); } else { apiGroup = ""; apiVersion = left[0]; - [resource, name] = left.slice(1) + [resource, name] = left.slice(1); } break; } @@ -93,7 +93,7 @@ export function parseKubeApi(path: string): IKubeApiParsed { const apiBase = [apiPrefix, apiGroup, apiVersion, resource].filter(v => v).join("/"); if (!apiBase) { - throw new Error(`invalid apiPath: ${path}`) + throw new Error(`invalid apiPath: ${path}`); } return { @@ -108,11 +108,11 @@ export function createKubeApiURL(ref: IKubeApiLinkRef): string { const { apiPrefix = "/apis", resource, apiVersion, name } = ref; let { namespace } = ref; if (namespace) { - namespace = `namespaces/${namespace}` + namespace = `namespaces/${namespace}`; } return [apiPrefix, apiVersion, namespace, resource, name] .filter(v => v) - .join("/") + .join("/"); } export function lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): string { @@ -124,9 +124,9 @@ export function lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): st if (!kind) return ""; // search in registered apis by 'kind' & 'apiVersion' - const api = apiManager.getApi(api => api.kind === kind && api.apiVersionWithGroup == apiVersion) + const api = apiManager.getApi(api => api.kind === kind && api.apiVersionWithGroup == apiVersion); if (api) { - return api.getUrl({ namespace, name }) + return api.getUrl({ namespace, name }); } // lookup api by generated resource link @@ -142,10 +142,10 @@ export function lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): st // resolve by kind only (hpa's might use refs to older versions of resources for example) const apiByKind = apiManager.getApi(api => api.kind === kind); if (apiByKind) { - return apiByKind.getUrl({ name, namespace }) + return apiByKind.getUrl({ name, namespace }); } // otherwise generate link with default prefix // resource still might exists in k8s, but api is not registered in the app - return createKubeApiURL({ apiVersion, name, namespace, resource }) + return createKubeApiURL({ apiVersion, name, namespace, resource }); } diff --git a/src/renderer/api/kube-api.ts b/src/renderer/api/kube-api.ts index c3c9698cfa..d4840d3620 100644 --- a/src/renderer/api/kube-api.ts +++ b/src/renderer/api/kube-api.ts @@ -1,6 +1,6 @@ // Base class for building all kubernetes apis -import merge from "lodash/merge" +import merge from "lodash/merge"; import { stringify } from "querystring"; import { IKubeObjectConstructor, KubeObject } from "./kube-object"; import { KubeJsonApi, KubeJsonApiData, KubeJsonApiDataList } from "./kube-json-api"; @@ -51,7 +51,7 @@ export function forCluster(cluster: IKubeApiCluster, kubeC return new KubeApi({ objectConstructor: kubeClass, request: request - }) + }); } export class KubeApi { @@ -62,14 +62,14 @@ export class KubeApi { return () => disposers.forEach(unwatch => unwatch()); } - readonly kind: string - readonly apiBase: string - readonly apiPrefix: string - readonly apiGroup: string - readonly apiVersion: string + readonly kind: string; + readonly apiBase: string; + readonly apiPrefix: string; + readonly apiGroup: string; + readonly apiVersion: string; readonly apiVersionPreferred?: string; - readonly apiResource: string - readonly isNamespaced: boolean + readonly apiResource: string; + readonly isNamespaced: boolean; public objectConstructor: IKubeObjectConstructor; protected request: KubeJsonApi; @@ -83,7 +83,7 @@ export class KubeApi { isNamespaced = options.objectConstructor?.namespaced } = options || {}; if (!options.apiBase) { - options.apiBase = objectConstructor.apiBase + options.apiBase = objectConstructor.apiBase; } const { apiBase, apiPrefix, apiGroup, apiVersion, apiVersionWithGroup, resource } = KubeApi.parseApi(options.apiBase); @@ -105,7 +105,7 @@ export class KubeApi { get apiVersionWithGroup() { return [this.apiGroup, this.apiVersionPreferred ?? this.apiVersion] .filter(Boolean) - .join("/") + .join("/"); } protected async checkPreferredVersion() { @@ -116,7 +116,7 @@ export class KubeApi { }); if (this.apiVersionPreferred) { - Object.defineProperty(this, "apiBase", { value: this.getUrl() }) + Object.defineProperty(this, "apiBase", { value: this.getUrl() }); apiManager.registerApi(this.apiBase, this); } } @@ -147,10 +147,10 @@ export class KubeApi { protected normalizeQuery(query: Partial = {}) { if (query.labelSelector) { - query.labelSelector = [query.labelSelector].flat().join(",") + query.labelSelector = [query.labelSelector].flat().join(","); } if (query.fieldSelector) { - query.fieldSelector = [query.fieldSelector].flat().join(",") + query.fieldSelector = [query.fieldSelector].flat().join(","); } return query; } @@ -170,7 +170,7 @@ export class KubeApi { kind: this.kind, apiVersion: apiVersion, ...item, - })) + })); } // custom apis might return array for list response, e.g. users, groups, etc. @@ -218,13 +218,13 @@ export class KubeApi { const apiUrl = this.getUrl({ namespace, name }); return this.request .put(apiUrl, { data }) - .then(this.parseResponse) + .then(this.parseResponse); } async delete({ name = "", namespace = "default" }) { await this.checkPreferredVersion(); const apiUrl = this.getUrl({ namespace, name }); - return this.request.del(apiUrl) + return this.request.del(apiUrl); } getWatchUrl(namespace = "", query: IKubeApiQueryParams = {}) { @@ -232,7 +232,7 @@ export class KubeApi { watch: 1, resourceVersion: this.getResourceVersion(namespace), ...query, - }) + }); } watch(): () => void { @@ -240,4 +240,4 @@ export class KubeApi { } } -export * from "./kube-api-parse" +export * from "./kube-api-parse"; diff --git a/src/renderer/api/kube-object-detail-registry.ts b/src/renderer/api/kube-object-detail-registry.ts index f844da9ef3..5246254532 100644 --- a/src/renderer/api/kube-object-detail-registry.ts +++ b/src/renderer/api/kube-object-detail-registry.ts @@ -1 +1 @@ -export { kubeObjectDetailRegistry } from "../../extensions/registries/kube-object-detail-registry" +export { kubeObjectDetailRegistry } from "../../extensions/registries/kube-object-detail-registry"; diff --git a/src/renderer/api/kube-object.ts b/src/renderer/api/kube-object.ts index 664f9a5c22..8d0e6123f3 100644 --- a/src/renderer/api/kube-object.ts +++ b/src/renderer/api/kube-object.ts @@ -65,20 +65,20 @@ export class KubeObject implements ItemObject { static stringifyLabels(labels: { [name: string]: string }): string[] { if (!labels) return []; - return Object.entries(labels).map(([name, value]) => `${name}=${value}`) + return Object.entries(labels).map(([name, value]) => `${name}=${value}`); } constructor(data: KubeJsonApiData) { Object.assign(this, data); } - apiVersion: string - kind: string + apiVersion: string; + kind: string; metadata: IKubeObjectMetadata; status?: any; // todo: type-safety support get selfLink() { - return this.metadata.selfLink + return this.metadata.selfLink; } getId() { @@ -131,18 +131,18 @@ export class KubeObject implements ItemObject { return refs.map(ownerRef => ({ ...ownerRef, namespace: this.getNs(), - })) + })); } getSearchFields() { - const { getName, getId, getNs, getAnnotations, getLabels } = this + const { getName, getId, getNs, getAnnotations, getLabels } = this; return [ getName(), getNs(), getId(), ...getLabels(), ...getAnnotations(true), - ] + ]; } toPlainObject(): object { diff --git a/src/renderer/api/kube-watch-api.ts b/src/renderer/api/kube-watch-api.ts index 56c3fc1c86..8ce44fb77c 100644 --- a/src/renderer/api/kube-watch-api.ts +++ b/src/renderer/api/kube-watch-api.ts @@ -1,7 +1,7 @@ // Kubernetes watch-api consumer import { computed, observable, reaction } from "mobx"; -import { stringify } from "querystring" +import { stringify } from "querystring"; import { autobind, EventEmitter } from "../utils"; import { KubeJsonApiData } from "./kube-json-api"; import type { KubeObjectStore } from "../kube-object.store"; @@ -61,13 +61,13 @@ export class KubeWatchApi { } protected getQuery(): Partial { - const { isAdmin, allowedNamespaces } = getHostedCluster() + const { isAdmin, allowedNamespaces } = getHostedCluster(); return { api: this.activeApis.map(api => { if (isAdmin) return api.getWatchUrl(); - return allowedNamespaces.map(namespace => api.getWatchUrl(namespace)) + return allowedNamespaces.map(namespace => api.getWatchUrl(namespace)); }).flat() - } + }; } // todo: maybe switch to websocket to avoid often reconnects @@ -119,11 +119,11 @@ export class KubeWatchApi { await api.refreshResourceVersion({ namespace }); this.reconnect(); } catch (error) { - console.error("failed to refresh resource version", error) + console.error("failed to refresh resource version", error); if (this.subscribers.size > 0) { setTimeout(() => { - this.onRouteEvent(event) - }, 1000) + this.onRouteEvent(event); + }, 1000); } } } diff --git a/src/renderer/api/terminal-api.ts b/src/renderer/api/terminal-api.ts index 0e8bba2df6..4f66544f86 100644 --- a/src/renderer/api/terminal-api.ts +++ b/src/renderer/api/terminal-api.ts @@ -1,7 +1,7 @@ import { stringify } from "querystring"; import { autobind, base64, EventEmitter } from "../utils"; import { WebSocketApi } from "./websocket-api"; -import isEqual from "lodash/isEqual" +import isEqual from "lodash/isEqual"; import { isDevelopment } from "../../common/vars"; export enum TerminalChannels { @@ -28,7 +28,7 @@ export type TerminalApiQuery = Record & { id: string; node?: string; type?: string | "node"; -} +}; export class TerminalApi extends WebSocketApi { protected size: { Width: number; Height: number }; @@ -51,7 +51,7 @@ export class TerminalApi extends WebSocketApi { const wss = `ws${protocol === "https:" ? "s" : ""}://`; const query: TerminalApiQuery = { id }; if (port) { - port = `:${port}` + port = `:${port}`; } if (node) { query.node = node; diff --git a/src/renderer/api/websocket-api.ts b/src/renderer/api/websocket-api.ts index cb94881035..934d6cded6 100644 --- a/src/renderer/api/websocket-api.ts +++ b/src/renderer/api/websocket-api.ts @@ -146,7 +146,7 @@ export class WebSocketApi { } protected _onError(evt: Event) { - this.writeLog('%cERROR', 'color:red;font-weight:bold;', evt) + this.writeLog('%cERROR', 'color:red;font-weight:bold;', evt); } protected _onClose(evt: CloseEvent) { diff --git a/src/renderer/api/workload-kube-object.ts b/src/renderer/api/workload-kube-object.ts index c18b8df6c4..51c0461f15 100644 --- a/src/renderer/api/workload-kube-object.ts +++ b/src/renderer/api/workload-kube-object.ts @@ -65,16 +65,16 @@ export class WorkloadKubeObject extends KubeObject { } getTolerations(): IToleration[] { - return get(this, "spec.template.spec.tolerations", []) + return get(this, "spec.template.spec.tolerations", []); } getAffinity(): IAffinity { - return get(this, "spec.template.spec.affinity") + return get(this, "spec.template.spec.affinity"); } getAffinityNumber() { - const affinity = this.getAffinity() - if (!affinity) return 0 - return Object.keys(affinity).length + const affinity = this.getAffinity(); + if (!affinity) return 0; + return Object.keys(affinity).length; } } \ No newline at end of file diff --git a/src/renderer/bootstrap.tsx b/src/renderer/bootstrap.tsx index cfadb5c379..7aa78f1682 100644 --- a/src/renderer/bootstrap.tsx +++ b/src/renderer/bootstrap.tsx @@ -1,9 +1,9 @@ -import "./components/app.scss" +import "./components/app.scss"; import React from "react"; -import * as Mobx from "mobx" -import * as MobxReact from "mobx-react" -import * as LensExtensions from "../extensions/extension-api" +import * as Mobx from "mobx"; +import * as MobxReact from "mobx-react"; +import * as LensExtensions from "../extensions/extension-api"; import { App } from "./components/app"; import { LensApp } from "./lens-app"; import { render, unmountComponentAtNode } from "react-dom"; @@ -18,20 +18,20 @@ import { extensionLoader } from "../extensions/extension-loader"; type AppComponent = React.ComponentType & { init?(): Promise; -} +}; export { React, Mobx, MobxReact, LensExtensions -} +}; export async function bootstrap(App: AppComponent) { - const rootElem = document.getElementById("app") + const rootElem = document.getElementById("app"); rootElem.classList.toggle("is-mac", isMac); - extensionLoader.init() + extensionLoader.init(); // preload common stores await Promise.all([ @@ -53,13 +53,13 @@ export async function bootstrap(App: AppComponent) { } window.addEventListener("message", (ev: MessageEvent) => { if (ev.data === "teardown") { - userStore.unregisterIpcListener() - workspaceStore.unregisterIpcListener() - clusterStore.unregisterIpcListener() - unmountComponentAtNode(rootElem) - window.location.href = "about:blank" + userStore.unregisterIpcListener(); + workspaceStore.unregisterIpcListener(); + clusterStore.unregisterIpcListener(); + unmountComponentAtNode(rootElem); + window.location.href = "about:blank"; } - }) + }); render(<> {isMac && } diff --git a/src/renderer/components/+404/index.ts b/src/renderer/components/+404/index.ts index 7314f53562..67433b02c3 100644 --- a/src/renderer/components/+404/index.ts +++ b/src/renderer/components/+404/index.ts @@ -1 +1 @@ -export * from "./not-found" +export * from "./not-found"; diff --git a/src/renderer/components/+add-cluster/add-cluster.route.ts b/src/renderer/components/+add-cluster/add-cluster.route.ts index ba3ffcd104..3f1e36be9e 100644 --- a/src/renderer/components/+add-cluster/add-cluster.route.ts +++ b/src/renderer/components/+add-cluster/add-cluster.route.ts @@ -3,6 +3,6 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const addClusterRoute: RouteProps = { path: "/add-cluster" -} +}; -export const addClusterURL = buildURL(addClusterRoute.path) +export const addClusterURL = buildURL(addClusterRoute.path); diff --git a/src/renderer/components/+add-cluster/add-cluster.tsx b/src/renderer/components/+add-cluster/add-cluster.tsx index 8acd3a51ea..abb28d090e 100644 --- a/src/renderer/components/+add-cluster/add-cluster.tsx +++ b/src/renderer/components/+add-cluster/add-cluster.tsx @@ -1,4 +1,4 @@ -import "./add-cluster.scss" +import "./add-cluster.scss"; import os from "os"; import React, { Fragment } from "react"; import { observer } from "mobx-react"; @@ -16,7 +16,7 @@ import { WizardLayout } from "../layout/wizard-layout"; import { kubeConfigDefaultPath, loadConfig, splitConfig, validateConfig, validateKubeConfig } from "../../../common/kube-helpers"; import { ClusterModel, ClusterStore, clusterStore } from "../../../common/cluster-store"; import { workspaceStore } from "../../../common/workspace-store"; -import { v4 as uuid } from "uuid" +import { v4 as uuid } from "uuid"; import { navigate } from "../../navigation"; import { userStore } from "../../../common/user-store"; import { clusterViewURL } from "../cluster-manager/cluster-view.route"; @@ -39,10 +39,10 @@ export class AddCluster extends React.Component { @observable selectedContexts = observable.array(); @observable sourceTab = KubeConfigSourceTab.FILE; @observable kubeConfigPath = ""; - @observable customConfig = "" - @observable proxyServer = "" - @observable isWaiting = false - @observable showSettings = false + @observable customConfig = ""; + @observable proxyServer = ""; + @observable isWaiting = false; + @observable showSettings = false; @observable dropAreaActive = false; componentDidMount() { @@ -84,7 +84,7 @@ export class AddCluster extends React.Component { break; case KubeConfigSourceTab.TEXT: try { - this.error = "" + this.error = ""; const contexts = this.getContexts(loadConfig(this.customConfig || "{}")); this.kubeContexts.replace(contexts); } catch (err) { @@ -94,7 +94,7 @@ export class AddCluster extends React.Component { } if (this.kubeContexts.size === 1) { - this.selectedContexts.push(this.kubeContexts.keys().next().value) + this.selectedContexts.push(this.kubeContexts.keys().next().value); } } @@ -102,8 +102,8 @@ export class AddCluster extends React.Component { const contexts = new Map(); splitConfig(config).forEach(config => { contexts.set(config.currentContext, config); - }) - return contexts + }); + return contexts; } selectKubeConfigDialog = async () => { @@ -117,18 +117,18 @@ export class AddCluster extends React.Component { if (!canceled && filePaths.length) { this.setKubeConfig(filePaths[0]); } - } + }; @action addClusters = () => { let newClusters: ClusterModel[] = []; try { if (!this.selectedContexts.length) { - this.error = Please select at least one cluster context + this.error = Please select at least one cluster context; return; } - this.error = "" - this.isWaiting = true + this.error = ""; + this.isWaiting = true; newClusters = this.selectedContexts.filter(context => { try { @@ -136,7 +136,7 @@ export class AddCluster extends React.Component { validateKubeConfig(kubeConfig); return true; } catch (err) { - this.error = String(err.message) + this.error = String(err.message); if (err instanceof ExecValidationNotFoundError ) { Notifications.error(Error while adding cluster(s): {this.error}); return false; @@ -159,8 +159,8 @@ export class AddCluster extends React.Component { clusterName: kubeConfig.currentContext, httpsProxy: this.proxyServer || undefined, }, - } - }) + }; + }); runInAction(() => { clusterStore.addClusters(...newClusters); @@ -175,7 +175,7 @@ export class AddCluster extends React.Component { ); } } - }) + }); this.refreshContexts(); } catch (err) { this.error = String(err); @@ -183,7 +183,7 @@ export class AddCluster extends React.Component { } finally { this.isWaiting = false; } - } + }; renderInfo() { return ( @@ -218,7 +218,7 @@ export class AddCluster extends React.Component { Lens app might not have all login shell env variables set automatically. - ) + ); } renderKubeConfigSource() { @@ -281,7 +281,7 @@ export class AddCluster extends React.Component { > )} > - ) + ); } renderContextSelector() { @@ -302,7 +302,7 @@ export class AddCluster extends React.Component { noOptionsMessage={() => _i18n._(t`No contexts available or they have been added already`)} onChange={({ value: ctx }: SelectOption) => { if (this.selectedContexts.includes(ctx)) { - this.selectedContexts.remove(ctx) + this.selectedContexts.remove(ctx); } else { this.selectedContexts.push(ctx); } @@ -315,7 +315,7 @@ export class AddCluster extends React.Component { )} > - ) + ); } onKubeConfigInputBlur = (evt: React.FocusEvent) => { @@ -328,13 +328,13 @@ export class AddCluster extends React.Component { this.setKubeConfig(userStore.kubeConfigPath); // revert to previous valid path } } - } + }; onKubeConfigTabChange = (tabId: KubeConfigSourceTab) => { this.sourceTab = tabId; this.error = ""; this.refreshContexts(); - } + }; protected formatContextLabel = ({ value: context }: SelectOption) => { const isNew = userStore.newContexts.has(context); @@ -345,11 +345,11 @@ export class AddCluster extends React.Component { {isNew && } {isSelected && } - ) + ); }; render() { - const addDisabled = this.selectedContexts.length === 0 + const addDisabled = this.selectedContexts.length === 0; return ( this.dropAreaActive = false, onDragOver: event => { event.preventDefault(); // enable onDrop()-callback - event.dataTransfer.dropEffect = "move" + event.dataTransfer.dropEffect = "move"; }, onDrop: event => { this.sourceTab = KubeConfigSourceTab.FILE; - this.dropAreaActive = false - this.setKubeConfig(event.dataTransfer.files[0].path) + this.dropAreaActive = false; + this.setKubeConfig(event.dataTransfer.files[0].path); } }} > @@ -407,6 +407,6 @@ export class AddCluster extends React.Component { /> - ) + ); } } diff --git a/src/renderer/components/+add-cluster/index.ts b/src/renderer/components/+add-cluster/index.ts index 42ab8bf944..1ddb3d069d 100644 --- a/src/renderer/components/+add-cluster/index.ts +++ b/src/renderer/components/+add-cluster/index.ts @@ -1,2 +1,2 @@ -export * from "./add-cluster" -export * from "./add-cluster.route" +export * from "./add-cluster"; +export * from "./add-cluster.route"; diff --git a/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx b/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx index a5531affa3..a446c4dd52 100644 --- a/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx +++ b/src/renderer/components/+apps-helm-charts/helm-chart-details.tsx @@ -35,16 +35,16 @@ export class HelmChartDetails extends Component { } chartUpdater = autorun(() => { - this.selectedChart = null - const { chart: { name, repo, version } } = this.props + this.selectedChart = null; + const { chart: { name, repo, version } } = this.props; helmChartsApi.get(repo, name, version).then(result => { - this.readme = result.readme - this.chartVersions = result.versions - this.selectedChart = result.versions[0] + this.readme = result.readme; + this.chartVersions = result.versions; + this.selectedChart = result.versions[0]; }, error => { this.error = error; - }) + }); }); @autobind() @@ -55,7 +55,7 @@ export class HelmChartDetails extends Component { try { this.chartPromise?.cancel(); const { chart: { name, repo } } = this.props; - const { readme } = await (this.chartPromise = helmChartsApi.get(repo, name, version)) + const { readme } = await (this.chartPromise = helmChartsApi.get(repo, name, version)); this.readme = readme; } catch (error) { this.error = error; @@ -65,7 +65,7 @@ export class HelmChartDetails extends Component { @autobind() install() { createInstallChartTab(this.selectedChart); - this.props.hideDetails() + this.props.hideDetails(); } renderIntroduction() { @@ -112,14 +112,14 @@ export class HelmChartDetails extends Component { renderReadme() { if (this.readme === null) { - return + return ; } return ( - ) + ); } renderContent() { @@ -132,7 +132,7 @@ export class HelmChartDetails extends Component { {this.error} - ) + ); } return ( diff --git a/src/renderer/components/+apps-helm-charts/helm-chart.store.ts b/src/renderer/components/+apps-helm-charts/helm-chart.store.ts index 1d231c08dd..65e73b556f 100644 --- a/src/renderer/components/+apps-helm-charts/helm-chart.store.ts +++ b/src/renderer/components/+apps-helm-charts/helm-chart.store.ts @@ -1,9 +1,9 @@ -import semver from "semver" +import semver from "semver"; import { observable } from "mobx"; import { autobind } from "../../utils"; import { HelmChart, helmChartsApi } from "../../api/endpoints/helm-charts.api"; import { ItemStore } from "../../item.store"; -import flatten from "lodash/flatten" +import flatten from "lodash/flatten"; export interface IChartVersion { repo: string; @@ -24,7 +24,7 @@ export class HelmChartStore extends ItemStore { protected sortVersions = (versions: IChartVersion[]) => { return versions.sort((first, second) => { - return semver.compare(second.version, first.version) + return semver.compare(second.version, first.version); }); }; @@ -38,8 +38,8 @@ export class HelmChartStore extends ItemStore { return versions.map(chart => ({ repo: repo, version: chart.getVersion() - })) - }) + })); + }); }; if (!this.isLoaded) { await this.loadAll(); diff --git a/src/renderer/components/+apps-helm-charts/helm-charts.route.ts b/src/renderer/components/+apps-helm-charts/helm-charts.route.ts index 047ff656b6..abd0677de8 100644 --- a/src/renderer/components/+apps-helm-charts/helm-charts.route.ts +++ b/src/renderer/components/+apps-helm-charts/helm-charts.route.ts @@ -4,11 +4,11 @@ import { appsRoute } from "../+apps/apps.route"; export const helmChartsRoute: RouteProps = { path: appsRoute.path + "/charts/:repo?/:chartName?" -} +}; export interface IHelmChartsRouteParams { chartName?: string; repo?: string; } -export const helmChartsURL = buildURL(helmChartsRoute.path) \ No newline at end of file +export const helmChartsURL = buildURL(helmChartsRoute.path); \ No newline at end of file diff --git a/src/renderer/components/+apps-helm-charts/helm-charts.tsx b/src/renderer/components/+apps-helm-charts/helm-charts.tsx index 473d78194e..c8b5312800 100644 --- a/src/renderer/components/+apps-helm-charts/helm-charts.tsx +++ b/src/renderer/components/+apps-helm-charts/helm-charts.tsx @@ -28,13 +28,13 @@ export class HelmCharts extends Component { } get selectedChart() { - const { match: { params: { chartName, repo } } } = this.props + const { match: { params: { chartName, repo } } } = this.props; return helmChartStore.getByName(chartName, repo); } showDetails = (chart: HelmChart) => { if (!chart) { - navigation.merge(helmChartsURL()) + navigation.merge(helmChartsURL()); } else { navigation.merge(helmChartsURL({ @@ -42,13 +42,13 @@ export class HelmCharts extends Component { chartName: chart.getName(), repo: chart.getRepository(), } - })) + })); } - } + }; hideDetails = () => { this.showDetails(null); - } + }; render() { return ( diff --git a/src/renderer/components/+apps-releases/release-details.tsx b/src/renderer/components/+apps-releases/release-details.tsx index cb7c7b8069..a27db5dc83 100644 --- a/src/renderer/components/+apps-releases/release-details.tsx +++ b/src/renderer/components/+apps-releases/release-details.tsx @@ -77,7 +77,7 @@ export class ReleaseDetails extends Component { updateValues = async () => { const { release } = this.props; const name = release.getName(); - const namespace = release.getNs() + const namespace = release.getNs(); const data = { chart: release.getChart(), repo: await release.getRepo(), @@ -94,13 +94,13 @@ export class ReleaseDetails extends Component { Notifications.error(err); } this.saving = false; - } + }; upgradeVersion = () => { const { release, hideDetails } = this.props; createUpgradeChartTab(release); hideDetails(); - } + }; renderValues() { const { values, saving } = this; @@ -121,7 +121,7 @@ export class ReleaseDetails extends Component { /> - ) + ); } renderNotes() { @@ -222,13 +222,13 @@ export class ReleaseDetails extends Component { {this.renderResources()} - ) + ); } render() { - const { release, hideDetails } = this.props - const title = release ? Release: {release.getName()} : "" - const toolbar = + const { release, hideDetails } = this.props; + const title = release ? Release: {release.getName()} : ""; + const toolbar = ; return ( { > {this.renderContent()} - ) + ); } } diff --git a/src/renderer/components/+apps-releases/release-menu.tsx b/src/renderer/components/+apps-releases/release-menu.tsx index 0bdb94edd2..aae3f34b79 100644 --- a/src/renderer/components/+apps-releases/release-menu.tsx +++ b/src/renderer/components/+apps-releases/release-menu.tsx @@ -46,7 +46,7 @@ export class HelmReleaseMenu extends React.Component { )} > - ) + ); } render() { diff --git a/src/renderer/components/+apps-releases/release-rollback-dialog.tsx b/src/renderer/components/+apps-releases/release-rollback-dialog.tsx index 259394c2e1..f1c1841775 100644 --- a/src/renderer/components/+apps-releases/release-rollback-dialog.tsx +++ b/src/renderer/components/+apps-releases/release-rollback-dialog.tsx @@ -10,7 +10,7 @@ import { HelmRelease, helmReleasesApi, IReleaseRevision } from "../../api/endpoi import { releaseStore } from "./release.store"; import { Select, SelectOption } from "../select"; import { Notifications } from "../notifications"; -import orderBy from "lodash/orderBy" +import orderBy from "lodash/orderBy"; interface Props extends DialogProps { } @@ -46,7 +46,7 @@ export class ReleaseRollbackDialog extends React.Component { this.revisions.replace(releases); this.revision = this.revisions[0]; this.isLoading = false; - } + }; rollback = async () => { const revisionNumber = this.revision.revision; @@ -60,12 +60,12 @@ export class ReleaseRollbackDialog extends React.Component { close = () => { ReleaseRollbackDialog.close(); - } + }; renderContent() { const { revision, revisions } = this; if (!revision) { - return No revisions to rollback. + return No revisions to rollback.; } return ( @@ -78,13 +78,13 @@ export class ReleaseRollbackDialog extends React.Component { onChange={({ value }: SelectOption) => this.revision = value} /> - ) + ); } render() { const { ...dialogProps } = this.props; const releaseName = this.release ? this.release.getName() : ""; - const header = Rollback {releaseName} + const header = Rollback {releaseName}; return ( { - ) + ); } } diff --git a/src/renderer/components/+apps-releases/release.route.ts b/src/renderer/components/+apps-releases/release.route.ts index f874fefe67..a992383657 100644 --- a/src/renderer/components/+apps-releases/release.route.ts +++ b/src/renderer/components/+apps-releases/release.route.ts @@ -4,7 +4,7 @@ import { appsRoute } from "../+apps/apps.route"; export const releaseRoute: RouteProps = { path: appsRoute.path + "/releases/:namespace?/:name?" -} +}; export interface IReleaseRouteParams { name?: string; diff --git a/src/renderer/components/+apps-releases/release.store.ts b/src/renderer/components/+apps-releases/release.store.ts index 5120a63053..7fb438fd84 100644 --- a/src/renderer/components/+apps-releases/release.store.ts +++ b/src/renderer/components/+apps-releases/release.store.ts @@ -33,7 +33,7 @@ export class ReleaseStore extends ItemStore { this.loadAll(); } this.releaseSecrets = [...secrets]; - }) + }); } unwatch() { @@ -48,7 +48,7 @@ export class ReleaseStore extends ItemStore { const labels = { owner: "helm", name: release.getName() - } + }; return secretsStore.getByLabel(labels) .filter(secret => secret.getNs() == release.getNs())[0]; } @@ -58,7 +58,7 @@ export class ReleaseStore extends ItemStore { this.isLoading = true; let items; try { - const { isAdmin, allowedNamespaces } = getHostedCluster() + const { isAdmin, allowedNamespaces } = getHostedCluster(); items = await this.loadItems(!isAdmin ? allowedNamespaces : null); } finally { if (items) { diff --git a/src/renderer/components/+apps-releases/releases.tsx b/src/renderer/components/+apps-releases/releases.tsx index 234a812543..29dd11deb8 100644 --- a/src/renderer/components/+apps-releases/releases.tsx +++ b/src/renderer/components/+apps-releases/releases.tsx @@ -48,7 +48,7 @@ export class HelmReleases extends Component { showDetails = (item: HelmRelease) => { if (!item) { - navigation.merge(releaseURL()) + navigation.merge(releaseURL()); } else { navigation.merge(releaseURL({ @@ -56,13 +56,13 @@ export class HelmReleases extends Component { name: item.getName(), namespace: item.getNs() } - })) + })); } - } + }; hideDetails = () => { this.showDetails(null); - } + }; renderRemoveDialogMessage(selectedItems: HelmRelease[]) { const releaseNames = selectedItems.map(item => item.getName()).join(", "); @@ -73,7 +73,7 @@ export class HelmReleases extends Component { Note: StatefulSet Volumes won't be deleted automatically
): string { @@ -68,13 +68,13 @@ export class PageRegistry extends BaseRegistry ...page, extensionId: ext.name, routePath: getExtensionPageUrl({ extensionId: ext.name, pageId: page.id ?? page.routePath }), - })) + })); } catch (err) { logger.error(`[EXTENSION]: page-registration failed`, { items, extension: ext, error: String(err), - }) + }); } return super.add(registeredPages); } diff --git a/src/extensions/renderer-api/components.ts b/src/extensions/renderer-api/components.ts index c051ce13e3..242799c749 100644 --- a/src/extensions/renderer-api/components.ts +++ b/src/extensions/renderer-api/components.ts @@ -1,36 +1,36 @@ // Common UI components // layouts -export * from "../../renderer/components/layout/page-layout" -export * from "../../renderer/components/layout/wizard-layout" -export * from "../../renderer/components/layout/tab-layout" +export * from "../../renderer/components/layout/page-layout"; +export * from "../../renderer/components/layout/wizard-layout"; +export * from "../../renderer/components/layout/tab-layout"; // form-controls -export * from "../../renderer/components/button" -export * from "../../renderer/components/checkbox" -export * from "../../renderer/components/radio" -export * from "../../renderer/components/select" -export * from "../../renderer/components/slider" -export * from "../../renderer/components/input/input" +export * from "../../renderer/components/button"; +export * from "../../renderer/components/checkbox"; +export * from "../../renderer/components/radio"; +export * from "../../renderer/components/select"; +export * from "../../renderer/components/slider"; +export * from "../../renderer/components/input/input"; // other components -export * from "../../renderer/components/icon" -export * from "../../renderer/components/tooltip" -export * from "../../renderer/components/tabs" -export * from "../../renderer/components/table" -export * from "../../renderer/components/badge" -export * from "../../renderer/components/drawer" -export * from "../../renderer/components/dialog" +export * from "../../renderer/components/icon"; +export * from "../../renderer/components/tooltip"; +export * from "../../renderer/components/tabs"; +export * from "../../renderer/components/table"; +export * from "../../renderer/components/badge"; +export * from "../../renderer/components/drawer"; +export * from "../../renderer/components/dialog"; export * from "../../renderer/components/confirm-dialog"; -export * from "../../renderer/components/line-progress" -export * from "../../renderer/components/menu" -export * from "../../renderer/components/notifications" -export * from "../../renderer/components/spinner" -export * from "../../renderer/components/stepper" +export * from "../../renderer/components/line-progress"; +export * from "../../renderer/components/menu"; +export * from "../../renderer/components/notifications"; +export * from "../../renderer/components/spinner"; +export * from "../../renderer/components/stepper"; // kube helpers -export * from "../../renderer/components/kube-object" -export * from "../../renderer/components/+events/kube-event-details" +export * from "../../renderer/components/kube-object"; +export * from "../../renderer/components/+events/kube-event-details"; // specific exports export * from "../../renderer/components/status-brick"; diff --git a/src/extensions/renderer-api/index.ts b/src/extensions/renderer-api/index.ts index 009f49c366..c8e14c0951 100644 --- a/src/extensions/renderer-api/index.ts +++ b/src/extensions/renderer-api/index.ts @@ -1,14 +1,14 @@ // Lens-extensions apis, required in renderer process runtime // APIs -import * as Component from "./components" -import * as K8sApi from "./k8s-api" -import * as Navigation from "./navigation" -import * as Theme from "./theming" +import * as Component from "./components"; +import * as K8sApi from "./k8s-api"; +import * as Navigation from "./navigation"; +import * as Theme from "./theming"; export { Component, K8sApi, Navigation, Theme, -} +}; diff --git a/src/extensions/renderer-api/k8s-api.ts b/src/extensions/renderer-api/k8s-api.ts index 2a26b49cdd..fe04550fb7 100644 --- a/src/extensions/renderer-api/k8s-api.ts +++ b/src/extensions/renderer-api/k8s-api.ts @@ -1,6 +1,6 @@ -export { isAllowedResource } from "../../common/rbac" +export { isAllowedResource } from "../../common/rbac"; export { apiManager } from "../../renderer/api/api-manager"; -export { KubeObjectStore } from "../../renderer/kube-object.store" +export { KubeObjectStore } from "../../renderer/kube-object.store"; export { KubeApi, forCluster, IKubeApiCluster } from "../../renderer/api/kube-api"; export { KubeObject } from "../../renderer/api/kube-object"; export { Pod, podsApi, PodsApi, IPodContainer, IPodContainerStatus } from "../../renderer/api/endpoints"; @@ -31,33 +31,33 @@ export { RoleBinding, roleBindingApi } from "../../renderer/api/endpoints"; export { ClusterRole, clusterRoleApi } from "../../renderer/api/endpoints"; export { ClusterRoleBinding, clusterRoleBindingApi } from "../../renderer/api/endpoints"; export { CustomResourceDefinition, crdApi } from "../../renderer/api/endpoints"; -export { KubeObjectStatus, KubeObjectStatusLevel } from "./kube-object-status" +export { KubeObjectStatus, KubeObjectStatusLevel } from "./kube-object-status"; // stores -export type { EventStore } from "../../renderer/components/+events/event.store" -export type { PodsStore } from "../../renderer/components/+workloads-pods/pods.store" -export type { NodesStore } from "../../renderer/components/+nodes/nodes.store" -export type { DeploymentStore } from "../../renderer/components/+workloads-deployments/deployments.store" -export type { DaemonSetStore } from "../../renderer/components/+workloads-daemonsets/daemonsets.store" -export type { StatefulSetStore } from "../../renderer/components/+workloads-statefulsets/statefulset.store" -export type { JobStore } from "../../renderer/components/+workloads-jobs/job.store" -export type { CronJobStore } from "../../renderer/components/+workloads-cronjobs/cronjob.store" -export type { ConfigMapsStore } from "../../renderer/components/+config-maps/config-maps.store" -export type { SecretsStore } from "../../renderer/components/+config-secrets/secrets.store" -export type { ReplicaSetStore } from "../../renderer/components/+workloads-replicasets/replicasets.store" -export type { ResourceQuotasStore } from "../../renderer/components/+config-resource-quotas/resource-quotas.store" -export type { HPAStore } from "../../renderer/components/+config-autoscalers/hpa.store" -export type { PodDisruptionBudgetsStore } from "../../renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store" -export type { ServiceStore } from "../../renderer/components/+network-services/services.store" -export type { EndpointStore } from "../../renderer/components/+network-endpoints/endpoints.store" -export type { IngressStore } from "../../renderer/components/+network-ingresses/ingress.store" -export type { NetworkPolicyStore } from "../../renderer/components/+network-policies/network-policy.store" -export type { PersistentVolumesStore } from "../../renderer/components/+storage-volumes/volumes.store" -export type { VolumeClaimStore } from "../../renderer/components/+storage-volume-claims/volume-claim.store" -export type { StorageClassStore } from "../../renderer/components/+storage-classes/storage-class.store" -export type { NamespaceStore } from "../../renderer/components/+namespaces/namespace.store" -export type { ServiceAccountsStore } from "../../renderer/components/+user-management-service-accounts/service-accounts.store" -export type { RolesStore } from "../../renderer/components/+user-management-roles/roles.store" -export type { RoleBindingsStore } from "../../renderer/components/+user-management-roles-bindings/role-bindings.store" -export type { CRDStore } from "../../renderer/components/+custom-resources/crd.store" -export type { CRDResourceStore } from "../../renderer/components/+custom-resources/crd-resource.store" +export type { EventStore } from "../../renderer/components/+events/event.store"; +export type { PodsStore } from "../../renderer/components/+workloads-pods/pods.store"; +export type { NodesStore } from "../../renderer/components/+nodes/nodes.store"; +export type { DeploymentStore } from "../../renderer/components/+workloads-deployments/deployments.store"; +export type { DaemonSetStore } from "../../renderer/components/+workloads-daemonsets/daemonsets.store"; +export type { StatefulSetStore } from "../../renderer/components/+workloads-statefulsets/statefulset.store"; +export type { JobStore } from "../../renderer/components/+workloads-jobs/job.store"; +export type { CronJobStore } from "../../renderer/components/+workloads-cronjobs/cronjob.store"; +export type { ConfigMapsStore } from "../../renderer/components/+config-maps/config-maps.store"; +export type { SecretsStore } from "../../renderer/components/+config-secrets/secrets.store"; +export type { ReplicaSetStore } from "../../renderer/components/+workloads-replicasets/replicasets.store"; +export type { ResourceQuotasStore } from "../../renderer/components/+config-resource-quotas/resource-quotas.store"; +export type { HPAStore } from "../../renderer/components/+config-autoscalers/hpa.store"; +export type { PodDisruptionBudgetsStore } from "../../renderer/components/+config-pod-disruption-budgets/pod-disruption-budgets.store"; +export type { ServiceStore } from "../../renderer/components/+network-services/services.store"; +export type { EndpointStore } from "../../renderer/components/+network-endpoints/endpoints.store"; +export type { IngressStore } from "../../renderer/components/+network-ingresses/ingress.store"; +export type { NetworkPolicyStore } from "../../renderer/components/+network-policies/network-policy.store"; +export type { PersistentVolumesStore } from "../../renderer/components/+storage-volumes/volumes.store"; +export type { VolumeClaimStore } from "../../renderer/components/+storage-volume-claims/volume-claim.store"; +export type { StorageClassStore } from "../../renderer/components/+storage-classes/storage-class.store"; +export type { NamespaceStore } from "../../renderer/components/+namespaces/namespace.store"; +export type { ServiceAccountsStore } from "../../renderer/components/+user-management-service-accounts/service-accounts.store"; +export type { RolesStore } from "../../renderer/components/+user-management-roles/roles.store"; +export type { RoleBindingsStore } from "../../renderer/components/+user-management-roles-bindings/role-bindings.store"; +export type { CRDStore } from "../../renderer/components/+custom-resources/crd.store"; +export type { CRDResourceStore } from "../../renderer/components/+custom-resources/crd-resource.store"; diff --git a/src/extensions/renderer-api/kube-object-status.ts b/src/extensions/renderer-api/kube-object-status.ts index 22994ee85d..f609d736fe 100644 --- a/src/extensions/renderer-api/kube-object-status.ts +++ b/src/extensions/renderer-api/kube-object-status.ts @@ -2,7 +2,7 @@ export type KubeObjectStatus = { level: KubeObjectStatusLevel; text: string; timestamp?: string; -} +}; export enum KubeObjectStatusLevel { INFO = 1, diff --git a/src/extensions/renderer-api/navigation.ts b/src/extensions/renderer-api/navigation.ts index f923f6e152..a1191a4b30 100644 --- a/src/extensions/renderer-api/navigation.ts +++ b/src/extensions/renderer-api/navigation.ts @@ -1,3 +1,3 @@ export { navigate } from "../../renderer/navigation"; -export { hideDetails, showDetails, getDetailsUrl } from "../../renderer/navigation" +export { hideDetails, showDetails, getDetailsUrl } from "../../renderer/navigation"; export { IURLParams } from "../../common/utils/buildUrl"; diff --git a/src/jest.setup.ts b/src/jest.setup.ts index 08727bc910..7b4732930e 100644 --- a/src/jest.setup.ts +++ b/src/jest.setup.ts @@ -1,4 +1,4 @@ -import fetchMock from "jest-fetch-mock" +import fetchMock from "jest-fetch-mock"; // rewire global.fetch to call 'fetchMock' fetchMock.enableMocks(); diff --git a/src/main/__test__/cluster.test.ts b/src/main/__test__/cluster.test.ts index 1fb92ed4bc..95177408af 100644 --- a/src/main/__test__/cluster.test.ts +++ b/src/main/__test__/cluster.test.ts @@ -21,35 +21,35 @@ jest.mock("winston", () => ({ Console: jest.fn(), File: jest.fn(), } -})) +})); -jest.mock("../../common/ipc") -jest.mock("../context-handler") -jest.mock("request") -jest.mock("request-promise-native") +jest.mock("../../common/ipc"); +jest.mock("../context-handler"); +jest.mock("request"); +jest.mock("request-promise-native"); import { Console } from "console"; import mockFs from "mock-fs"; import { workspaceStore } from "../../common/workspace-store"; -import { Cluster } from "../cluster" +import { Cluster } from "../cluster"; import { ContextHandler } from "../context-handler"; import { getFreePort } from "../port"; import { V1ResourceAttributes } from "@kubernetes/client-node"; import { apiResources } from "../../common/rbac"; -import request from "request-promise-native" +import request from "request-promise-native"; import { Kubectl } from "../kubectl"; -const mockedRequest = request as jest.MockedFunction +const mockedRequest = request as jest.MockedFunction; -console = new Console(process.stdout, process.stderr) // fix mockFS +console = new Console(process.stdout, process.stderr); // fix mockFS describe("create clusters", () => { beforeEach(() => { - jest.clearAllMocks() - }) + jest.clearAllMocks(); + }); - let c: Cluster + let c: Cluster; beforeEach(() => { const mockOpts = { @@ -74,68 +74,68 @@ describe("create clusters", () => { kind: "Config", preferences: {}, }) - } - mockFs(mockOpts) - jest.spyOn(Kubectl.prototype, "ensureKubectl").mockReturnValue(Promise.resolve(true)) + }; + mockFs(mockOpts); + jest.spyOn(Kubectl.prototype, "ensureKubectl").mockReturnValue(Promise.resolve(true)); c = new Cluster({ id: "foo", contextName: "minikube", kubeConfigPath: "minikube-config.yml", workspace: workspaceStore.currentWorkspaceId - }) - }) + }); + }); afterEach(() => { - mockFs.restore() - }) + mockFs.restore(); + }); it("should be able to create a cluster from a cluster model and apiURL should be decoded", () => { - expect(c.apiUrl).toBe("https://192.168.64.3:8443") - }) + expect(c.apiUrl).toBe("https://192.168.64.3:8443"); + }); it("reconnect should not throw if contextHandler is missing", () => { - expect(() => c.reconnect()).not.toThrowError() - }) + expect(() => c.reconnect()).not.toThrowError(); + }); it("disconnect should not throw if contextHandler is missing", () => { - expect(() => c.disconnect()).not.toThrowError() - }) + expect(() => c.disconnect()).not.toThrowError(); + }); it("init should not throw if everything is in order", async () => { - await c.init(await getFreePort()) + await c.init(await getFreePort()); expect(logger.info).toBeCalledWith(expect.stringContaining("init success"), { id: "foo", apiUrl: "https://192.168.64.3:8443", context: "minikube", - }) - }) + }); + }); it("activating cluster should try to connect to cluster and do a refresh", async () => { - const port = await getFreePort() + const port = await getFreePort(); jest.spyOn(ContextHandler.prototype, "ensureServer"); - const mockListNSs = jest.fn() + const mockListNSs = jest.fn(); const mockKC = { makeApiClient() { return { listNamespace: mockListNSs, - } + }; } - } - jest.spyOn(Cluster.prototype, "isClusterAdmin").mockReturnValue(Promise.resolve(true)) + }; + jest.spyOn(Cluster.prototype, "isClusterAdmin").mockReturnValue(Promise.resolve(true)); jest.spyOn(Cluster.prototype, "canI") .mockImplementationOnce((attr: V1ResourceAttributes): Promise => { - expect(attr.namespace).toBe("default") - expect(attr.resource).toBe("pods") - expect(attr.verb).toBe("list") - return Promise.resolve(true) + expect(attr.namespace).toBe("default"); + expect(attr.resource).toBe("pods"); + expect(attr.verb).toBe("list"); + return Promise.resolve(true); }) .mockImplementation((attr: V1ResourceAttributes): Promise => { - expect(attr.namespace).toBe("default") - expect(attr.verb).toBe("list") - return Promise.resolve(true) - }) - jest.spyOn(Cluster.prototype, "getProxyKubeconfig").mockReturnValue(mockKC as any) + expect(attr.namespace).toBe("default"); + expect(attr.verb).toBe("list"); + return Promise.resolve(true); + }); + jest.spyOn(Cluster.prototype, "getProxyKubeconfig").mockReturnValue(mockKC as any); mockListNSs.mockImplementationOnce(() => ({ body: { items: [{ @@ -144,36 +144,36 @@ describe("create clusters", () => { } }] } - })) + })); mockedRequest.mockImplementationOnce(((uri: any, _options: any) => { - expect(uri).toBe(`http://localhost:${port}/api-kube/version`) - return Promise.resolve({ gitVersion: "1.2.3" }) - }) as any) + expect(uri).toBe(`http://localhost:${port}/api-kube/version`); + return Promise.resolve({ gitVersion: "1.2.3" }); + }) as any); const c = new class extends Cluster { // only way to mock protected methods, without these we leak promises protected bindEvents() { - return + return; } protected async ensureKubectl() { - return Promise.resolve(true) + return Promise.resolve(true); } }({ id: "foo", contextName: "minikube", kubeConfigPath: "minikube-config.yml", workspace: workspaceStore.currentWorkspaceId - }) - await c.init(port) - await c.activate() + }); + await c.init(port); + await c.activate(); - expect(ContextHandler.prototype.ensureServer).toBeCalled() - expect(mockedRequest).toBeCalled() - expect(c.accessible).toBe(true) - expect(c.allowedNamespaces.length).toBe(1) - expect(c.allowedResources.length).toBe(apiResources.length) - c.disconnect() - jest.resetAllMocks() - }) -}) + expect(ContextHandler.prototype.ensureServer).toBeCalled(); + expect(mockedRequest).toBeCalled(); + expect(c.accessible).toBe(true); + expect(c.allowedNamespaces.length).toBe(1); + expect(c.allowedResources.length).toBe(apiResources.length); + c.disconnect(); + jest.resetAllMocks(); + }); +}); diff --git a/src/main/__test__/kube-auth-proxy.test.ts b/src/main/__test__/kube-auth-proxy.test.ts index 8ef1f058e7..dbb3e308e3 100644 --- a/src/main/__test__/kube-auth-proxy.test.ts +++ b/src/main/__test__/kube-auth-proxy.test.ts @@ -21,109 +21,109 @@ jest.mock("winston", () => ({ Console: jest.fn(), File: jest.fn(), } -})) +})); -jest.mock("../../common/ipc") -jest.mock("child_process") -jest.mock("tcp-port-used") +jest.mock("../../common/ipc"); +jest.mock("child_process"); +jest.mock("tcp-port-used"); -import { Cluster } from "../cluster" -import { KubeAuthProxy } from "../kube-auth-proxy" -import { getFreePort } from "../port" -import { broadcastMessage } from "../../common/ipc" -import { ChildProcess, spawn, SpawnOptions } from "child_process" -import { bundledKubectlPath, Kubectl } from "../kubectl" +import { Cluster } from "../cluster"; +import { KubeAuthProxy } from "../kube-auth-proxy"; +import { getFreePort } from "../port"; +import { broadcastMessage } from "../../common/ipc"; +import { ChildProcess, spawn, SpawnOptions } from "child_process"; +import { bundledKubectlPath, Kubectl } from "../kubectl"; import { mock, MockProxy } from 'jest-mock-extended'; import { waitUntilUsed } from 'tcp-port-used'; -import { Readable } from "stream" +import { Readable } from "stream"; -const mockBroadcastIpc = broadcastMessage as jest.MockedFunction -const mockSpawn = spawn as jest.MockedFunction -const mockWaitUntilUsed = waitUntilUsed as jest.MockedFunction +const mockBroadcastIpc = broadcastMessage as jest.MockedFunction; +const mockSpawn = spawn as jest.MockedFunction; +const mockWaitUntilUsed = waitUntilUsed as jest.MockedFunction; describe("kube auth proxy tests", () => { beforeEach(() => { - jest.clearAllMocks() - }) + jest.clearAllMocks(); + }); it("calling exit multiple times shouldn't throw", async () => { - const port = await getFreePort() - const kap = new KubeAuthProxy(new Cluster({ id: "foobar", kubeConfigPath: "fake-path.yml" }), port, {}) - kap.exit() - kap.exit() - kap.exit() - }) + const port = await getFreePort(); + const kap = new KubeAuthProxy(new Cluster({ id: "foobar", kubeConfigPath: "fake-path.yml" }), port, {}); + kap.exit(); + kap.exit(); + kap.exit(); + }); describe("spawn tests", () => { - let port: number - let mockedCP: MockProxy - let listeners: Record void> - let proxy: KubeAuthProxy + let port: number; + let mockedCP: MockProxy; + let listeners: Record void>; + let proxy: KubeAuthProxy; beforeEach(async () => { - port = await getFreePort() - mockedCP = mock() - listeners = {} + port = await getFreePort(); + mockedCP = mock(); + listeners = {}; - jest.spyOn(Kubectl.prototype, "checkBinary").mockReturnValueOnce(Promise.resolve(true)) - jest.spyOn(Kubectl.prototype, "ensureKubectl").mockReturnValueOnce(Promise.resolve(false)) + jest.spyOn(Kubectl.prototype, "checkBinary").mockReturnValueOnce(Promise.resolve(true)); + jest.spyOn(Kubectl.prototype, "ensureKubectl").mockReturnValueOnce(Promise.resolve(false)); mockedCP.on.mockImplementation((event: string, listener: (message: any, sendHandle: any) => void): ChildProcess => { - listeners[event] = listener - return mockedCP - }) - mockedCP.stderr = mock() + listeners[event] = listener; + return mockedCP; + }); + mockedCP.stderr = mock(); mockedCP.stderr.on.mockImplementation((event: string, listener: (message: any, sendHandle: any) => void): Readable => { - listeners[`stderr/${event}`] = listener - return mockedCP.stderr - }) - mockedCP.stdout = mock() + listeners[`stderr/${event}`] = listener; + return mockedCP.stderr; + }); + mockedCP.stdout = mock(); mockedCP.stdout.on.mockImplementation((event: string, listener: (message: any, sendHandle: any) => void): Readable => { - listeners[`stdout/${event}`] = listener - return mockedCP.stdout - }) + listeners[`stdout/${event}`] = listener; + return mockedCP.stdout; + }); mockSpawn.mockImplementationOnce((command: string, args: readonly string[], options: SpawnOptions): ChildProcess => { - expect(command).toBe(bundledKubectlPath()) - return mockedCP - }) - mockWaitUntilUsed.mockReturnValueOnce(Promise.resolve()) - const cluster = new Cluster({ id: "foobar", kubeConfigPath: "fake-path.yml" }) - jest.spyOn(cluster, "apiUrl", "get").mockReturnValue("https://fake.k8s.internal") - proxy = new KubeAuthProxy(cluster, port, {}) - }) + expect(command).toBe(bundledKubectlPath()); + return mockedCP; + }); + mockWaitUntilUsed.mockReturnValueOnce(Promise.resolve()); + const cluster = new Cluster({ id: "foobar", kubeConfigPath: "fake-path.yml" }); + jest.spyOn(cluster, "apiUrl", "get").mockReturnValue("https://fake.k8s.internal"); + proxy = new KubeAuthProxy(cluster, port, {}); + }); it("should call spawn and broadcast errors", async () => { - await proxy.run() - listeners["error"]({ message: "foobarbat" }) + await proxy.run(); + listeners["error"]({ message: "foobarbat" }); - expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "foobarbat", error: true }) - }) + expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "foobarbat", error: true }); + }); it("should call spawn and broadcast exit", async () => { - await proxy.run() - listeners["exit"](0) + await proxy.run(); + listeners["exit"](0); - expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "proxy exited with code: 0", error: false }) - }) + expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "proxy exited with code: 0", error: false }); + }); it("should call spawn and broadcast errors from stderr", async () => { - await proxy.run() - listeners["stderr/data"]("an error") + await proxy.run(); + listeners["stderr/data"]("an error"); - expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "an error", error: true }) - }) + expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "an error", error: true }); + }); it("should call spawn and broadcast stdout serving info", async () => { - await proxy.run() - listeners["stdout/data"]("Starting to serve on") + await proxy.run(); + listeners["stdout/data"]("Starting to serve on"); - expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "Authentication proxy started\n" }) - }) + expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "Authentication proxy started\n" }); + }); it("should call spawn and broadcast stdout other info", async () => { - await proxy.run() - listeners["stdout/data"]("some info") + await proxy.run(); + listeners["stdout/data"]("some info"); - expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "some info" }) - }) - }) -}) + expect(mockBroadcastIpc).toBeCalledWith("kube-auth:foobar", { data: "some info" }); + }); + }); +}); diff --git a/src/main/__test__/kubeconfig-manager.test.ts b/src/main/__test__/kubeconfig-manager.test.ts index a0a4060111..152a13055d 100644 --- a/src/main/__test__/kubeconfig-manager.test.ts +++ b/src/main/__test__/kubeconfig-manager.test.ts @@ -21,24 +21,24 @@ jest.mock("winston", () => ({ Console: jest.fn(), File: jest.fn(), } -})) +})); -import { KubeconfigManager } from "../kubeconfig-manager" -import mockFs from "mock-fs" +import { KubeconfigManager } from "../kubeconfig-manager"; +import mockFs from "mock-fs"; import { Cluster } from "../cluster"; import { workspaceStore } from "../../common/workspace-store"; import { ContextHandler } from "../context-handler"; import { getFreePort } from "../port"; -import fse from "fs-extra" +import fse from "fs-extra"; import { loadYaml } from "@kubernetes/client-node"; import { Console } from "console"; -console = new Console(process.stdout, process.stderr) // fix mockFS +console = new Console(process.stdout, process.stderr); // fix mockFS describe("kubeconfig manager tests", () => { beforeEach(() => { - jest.clearAllMocks() - }) + jest.clearAllMocks(); + }); beforeEach(() => { const mockOpts = { @@ -63,13 +63,13 @@ describe("kubeconfig manager tests", () => { kind: "Config", preferences: {}, }) - } - mockFs(mockOpts) - }) + }; + mockFs(mockOpts); + }); afterEach(() => { - mockFs.restore() - }) + mockFs.restore(); + }); it("should create 'temp' kube config with proxy", async () => { const cluster = new Cluster({ @@ -77,19 +77,19 @@ describe("kubeconfig manager tests", () => { contextName: "minikube", kubeConfigPath: "minikube-config.yml", workspace: workspaceStore.currentWorkspaceId - }) - const contextHandler = new ContextHandler(cluster) - const port = await getFreePort() - const kubeConfManager = await KubeconfigManager.create(cluster, contextHandler, port) + }); + const contextHandler = new ContextHandler(cluster); + const port = await getFreePort(); + const kubeConfManager = await KubeconfigManager.create(cluster, contextHandler, port); - expect(logger.error).not.toBeCalled() - expect(kubeConfManager.getPath()).toBe("tmp/kubeconfig-foo") - const file = await fse.readFile(kubeConfManager.getPath()) - const yml = loadYaml(file.toString()) - expect(yml["current-context"]).toBe("minikube") - expect(yml["clusters"][0]["cluster"]["server"]).toBe(`http://127.0.0.1:${port}/foo`) - expect(yml["users"][0]["name"]).toBe("proxy") - }) + expect(logger.error).not.toBeCalled(); + expect(kubeConfManager.getPath()).toBe("tmp/kubeconfig-foo"); + const file = await fse.readFile(kubeConfManager.getPath()); + const yml = loadYaml(file.toString()); + expect(yml["current-context"]).toBe("minikube"); + expect(yml["clusters"][0]["cluster"]["server"]).toBe(`http://127.0.0.1:${port}/foo`); + expect(yml["users"][0]["name"]).toBe("proxy"); + }); it("should remove 'temp' kube config on unlink and remove reference from inside class", async () => { const cluster = new Cluster({ @@ -97,16 +97,16 @@ describe("kubeconfig manager tests", () => { contextName: "minikube", kubeConfigPath: "minikube-config.yml", workspace: workspaceStore.currentWorkspaceId - }) - const contextHandler = new ContextHandler(cluster) - const port = await getFreePort() - const kubeConfManager = await KubeconfigManager.create(cluster, contextHandler, port) + }); + const contextHandler = new ContextHandler(cluster); + const port = await getFreePort(); + const kubeConfManager = await KubeconfigManager.create(cluster, contextHandler, port); - const configPath = kubeConfManager.getPath() - expect(await fse.pathExists(configPath)).toBe(true) - await kubeConfManager.unlink() - expect(await fse.pathExists(configPath)).toBe(false) - await kubeConfManager.unlink() // doesn't throw - expect(kubeConfManager.getPath()).toBeUndefined() - }) -}) + const configPath = kubeConfManager.getPath(); + expect(await fse.pathExists(configPath)).toBe(true); + await kubeConfManager.unlink(); + expect(await fse.pathExists(configPath)).toBe(false); + await kubeConfManager.unlink(); // doesn't throw + expect(kubeConfManager.getPath()).toBeUndefined(); + }); +}); diff --git a/src/main/app-updater.ts b/src/main/app-updater.ts index 3613c3ef18..c7b6659149 100644 --- a/src/main/app-updater.ts +++ b/src/main/app-updater.ts @@ -1,19 +1,19 @@ -import { autoUpdater } from "electron-updater" -import logger from "./logger" +import { autoUpdater } from "electron-updater"; +import logger from "./logger"; export class AppUpdater { - static readonly defaultUpdateIntervalMs = 1000 * 60 * 60 * 24 // once a day + static readonly defaultUpdateIntervalMs = 1000 * 60 * 60 * 24; // once a day static checkForUpdates() { - return autoUpdater.checkForUpdatesAndNotify() + return autoUpdater.checkForUpdatesAndNotify(); } constructor(protected updateInterval = AppUpdater.defaultUpdateIntervalMs) { - autoUpdater.logger = logger + autoUpdater.logger = logger; } public start() { - setInterval(AppUpdater.checkForUpdates, this.updateInterval) + setInterval(AppUpdater.checkForUpdates, this.updateInterval); return AppUpdater.checkForUpdates(); } } diff --git a/src/main/cluster-detectors/base-cluster-detector.ts b/src/main/cluster-detectors/base-cluster-detector.ts index 8663313005..f73cc2ac81 100644 --- a/src/main/cluster-detectors/base-cluster-detector.ts +++ b/src/main/cluster-detectors/base-cluster-detector.ts @@ -1,21 +1,21 @@ -import request, { RequestPromiseOptions } from "request-promise-native" +import request, { RequestPromiseOptions } from "request-promise-native"; import { Cluster } from "../cluster"; export type ClusterDetectionResult = { value: string | number | boolean accuracy: number -} +}; export class BaseClusterDetector { - cluster: Cluster - key: string + cluster: Cluster; + key: string; constructor(cluster: Cluster) { - this.cluster = cluster + this.cluster = cluster; } detect(): Promise { - return null + return null; } protected async k8sRequest(path: string, options: RequestPromiseOptions = {}): Promise { @@ -28,6 +28,6 @@ export class BaseClusterDetector { Host: `${this.cluster.id}.${new URL(this.cluster.kubeProxyUrl).host}`, // required in ClusterManager.getClusterForRequest() ...(options.headers || {}), }, - }) + }); } } \ No newline at end of file diff --git a/src/main/cluster-detectors/cluster-id-detector.ts b/src/main/cluster-detectors/cluster-id-detector.ts index 558e52d43c..8419ae9db4 100644 --- a/src/main/cluster-detectors/cluster-id-detector.ts +++ b/src/main/cluster-detectors/cluster-id-detector.ts @@ -1,23 +1,23 @@ import { BaseClusterDetector } from "./base-cluster-detector"; -import { createHash } from "crypto" +import { createHash } from "crypto"; import { ClusterMetadataKey } from "../cluster"; export class ClusterIdDetector extends BaseClusterDetector { - key = ClusterMetadataKey.CLUSTER_ID + key = ClusterMetadataKey.CLUSTER_ID; public async detect() { - let id: string + let id: string; try { - id = await this.getDefaultNamespaceId() + id = await this.getDefaultNamespaceId(); } catch(_) { - id = this.cluster.apiUrl + id = this.cluster.apiUrl; } - const value = createHash("sha256").update(id).digest("hex") - return { value: value, accuracy: 100 } + const value = createHash("sha256").update(id).digest("hex"); + return { value: value, accuracy: 100 }; } protected async getDefaultNamespaceId() { - const response = await this.k8sRequest("/api/v1/namespaces/default") - return response.metadata.uid + const response = await this.k8sRequest("/api/v1/namespaces/default"); + return response.metadata.uid; } } \ No newline at end of file diff --git a/src/main/cluster-detectors/detector-registry.ts b/src/main/cluster-detectors/detector-registry.ts index 577fdf2d85..d4abe01304 100644 --- a/src/main/cluster-detectors/detector-registry.ts +++ b/src/main/cluster-detectors/detector-registry.ts @@ -12,34 +12,34 @@ export class DetectorRegistry { registry = observable.array([], { deep: false }); add(detectorClass: typeof BaseClusterDetector) { - this.registry.push(detectorClass) + this.registry.push(detectorClass); } async detectForCluster(cluster: Cluster): Promise { - const results: {[key: string]: ClusterDetectionResult } = {} + const results: {[key: string]: ClusterDetectionResult } = {}; for (const detectorClass of this.registry) { - const detector = new detectorClass(cluster) + const detector = new detectorClass(cluster); try { - const data = await detector.detect() + const data = await detector.detect(); if (!data) continue; - const existingValue = results[detector.key] + const existingValue = results[detector.key]; if (existingValue && existingValue.accuracy > data.accuracy) continue; // previous value exists and is more accurate - results[detector.key] = data + results[detector.key] = data; } catch (e) { // detector raised error, do nothing } } - const metadata: ClusterMetadata = {} + const metadata: ClusterMetadata = {}; for (const [key, result] of Object.entries(results)) { - metadata[key] = result.value + metadata[key] = result.value; } - return metadata + return metadata; } } -export const detectorRegistry = new DetectorRegistry() -detectorRegistry.add(ClusterIdDetector) -detectorRegistry.add(LastSeenDetector) -detectorRegistry.add(VersionDetector) -detectorRegistry.add(DistributionDetector) -detectorRegistry.add(NodesCountDetector) \ No newline at end of file +export const detectorRegistry = new DetectorRegistry(); +detectorRegistry.add(ClusterIdDetector); +detectorRegistry.add(LastSeenDetector); +detectorRegistry.add(VersionDetector); +detectorRegistry.add(DistributionDetector); +detectorRegistry.add(NodesCountDetector); \ No newline at end of file diff --git a/src/main/cluster-detectors/distribution-detector.ts b/src/main/cluster-detectors/distribution-detector.ts index b5895f8a71..181425cb26 100644 --- a/src/main/cluster-detectors/distribution-detector.ts +++ b/src/main/cluster-detectors/distribution-detector.ts @@ -2,79 +2,79 @@ import { BaseClusterDetector } from "./base-cluster-detector"; import { ClusterMetadataKey } from "../cluster"; export class DistributionDetector extends BaseClusterDetector { - key = ClusterMetadataKey.DISTRIBUTION - version: string + key = ClusterMetadataKey.DISTRIBUTION; + version: string; public async detect() { - this.version = await this.getKubernetesVersion() + this.version = await this.getKubernetesVersion(); if (await this.isRancher()) { - return { value: "rancher", accuracy: 80} + return { value: "rancher", accuracy: 80}; } if (this.isGKE()) { - return { value: "gke", accuracy: 80} + return { value: "gke", accuracy: 80}; } if (this.isEKS()) { - return { value: "eks", accuracy: 80} + return { value: "eks", accuracy: 80}; } if (this.isIKS()) { - return { value: "iks", accuracy: 80} + return { value: "iks", accuracy: 80}; } if (this.isAKS()) { - return { value: "aks", accuracy: 80} + return { value: "aks", accuracy: 80}; } if (this.isDigitalOcean()) { - return { value: "digitalocean", accuracy: 90} + return { value: "digitalocean", accuracy: 90}; } if (this.isMinikube()) { - return { value: "minikube", accuracy: 80} + return { value: "minikube", accuracy: 80}; } if (this.isCustom()) { - return { value: "custom", accuracy: 10} + return { value: "custom", accuracy: 10}; } - return { value: "unknown", accuracy: 10} + return { value: "unknown", accuracy: 10}; } public async getKubernetesVersion() { - if (this.cluster.version) return this.cluster.version + if (this.cluster.version) return this.cluster.version; - const response = await this.k8sRequest("/version") - return response.gitVersion + const response = await this.k8sRequest("/version"); + return response.gitVersion; } protected isGKE() { - return this.version.includes("gke") + return this.version.includes("gke"); } protected isEKS() { - return this.version.includes("eks") + return this.version.includes("eks"); } protected isIKS() { - return this.version.includes("IKS") + return this.version.includes("IKS"); } protected isAKS() { - return this.cluster.apiUrl.endsWith("azmk8s.io") + return this.cluster.apiUrl.endsWith("azmk8s.io"); } protected isDigitalOcean() { - return this.cluster.apiUrl.endsWith("k8s.ondigitalocean.com") + return this.cluster.apiUrl.endsWith("k8s.ondigitalocean.com"); } protected isMinikube() { - return this.cluster.contextName.startsWith("minikube") + return this.cluster.contextName.startsWith("minikube"); } protected isCustom() { - return this.version.includes("+") + return this.version.includes("+"); } protected async isRancher() { try { - const response = await this.k8sRequest("") - return response.data.find((api: any) => api?.apiVersion?.group === "meta.cattle.io") !== undefined + const response = await this.k8sRequest(""); + return response.data.find((api: any) => api?.apiVersion?.group === "meta.cattle.io") !== undefined; } catch (e) { - return false + return false; } } } \ No newline at end of file diff --git a/src/main/cluster-detectors/last-seen-detector.ts b/src/main/cluster-detectors/last-seen-detector.ts index 0c231116fe..d56483625a 100644 --- a/src/main/cluster-detectors/last-seen-detector.ts +++ b/src/main/cluster-detectors/last-seen-detector.ts @@ -2,12 +2,12 @@ import { BaseClusterDetector } from "./base-cluster-detector"; import { ClusterMetadataKey } from "../cluster"; export class LastSeenDetector extends BaseClusterDetector { - key = ClusterMetadataKey.LAST_SEEN + key = ClusterMetadataKey.LAST_SEEN; public async detect() { if (!this.cluster.accessible) return null; - await this.k8sRequest("/version") - return { value: new Date().toJSON(), accuracy: 100 } + await this.k8sRequest("/version"); + return { value: new Date().toJSON(), accuracy: 100 }; } } \ No newline at end of file diff --git a/src/main/cluster-detectors/nodes-count-detector.ts b/src/main/cluster-detectors/nodes-count-detector.ts index 858ff43d9f..ba5fc93583 100644 --- a/src/main/cluster-detectors/nodes-count-detector.ts +++ b/src/main/cluster-detectors/nodes-count-detector.ts @@ -2,16 +2,16 @@ import { BaseClusterDetector } from "./base-cluster-detector"; import { ClusterMetadataKey } from "../cluster"; export class NodesCountDetector extends BaseClusterDetector { - key = ClusterMetadataKey.NODES_COUNT + key = ClusterMetadataKey.NODES_COUNT; public async detect() { if (!this.cluster.accessible) return null; - const nodeCount = await this.getNodeCount() - return { value: nodeCount, accuracy: 100} + const nodeCount = await this.getNodeCount(); + return { value: nodeCount, accuracy: 100}; } protected async getNodeCount(): Promise { - const response = await this.k8sRequest("/api/v1/nodes") - return response.items.length + const response = await this.k8sRequest("/api/v1/nodes"); + return response.items.length; } } \ No newline at end of file diff --git a/src/main/cluster-detectors/version-detector.ts b/src/main/cluster-detectors/version-detector.ts index 4092b40b42..e59e6291b9 100644 --- a/src/main/cluster-detectors/version-detector.ts +++ b/src/main/cluster-detectors/version-detector.ts @@ -2,16 +2,16 @@ import { BaseClusterDetector } from "./base-cluster-detector"; import { ClusterMetadataKey } from "../cluster"; export class VersionDetector extends BaseClusterDetector { - key = ClusterMetadataKey.VERSION - value: string + key = ClusterMetadataKey.VERSION; + value: string; public async detect() { - const version = await this.getKubernetesVersion() - return { value: version, accuracy: 100} + const version = await this.getKubernetesVersion(); + return { value: version, accuracy: 100}; } public async getKubernetesVersion() { - const response = await this.k8sRequest("/version") - return response.gitVersion + const response = await this.k8sRequest("/version"); + return response.gitVersion; } } \ No newline at end of file diff --git a/src/main/cluster-manager.ts b/src/main/cluster-manager.ts index 1a479e724e..9b2e88ef89 100644 --- a/src/main/cluster-manager.ts +++ b/src/main/cluster-manager.ts @@ -1,16 +1,16 @@ import "../common/cluster-ipc"; -import type http from "http" -import { ipcMain } from "electron" +import type http from "http"; +import { ipcMain } from "electron"; import { autorun } from "mobx"; -import { clusterStore, getClusterIdFromHost } from "../common/cluster-store" -import { Cluster } from "./cluster" +import { clusterStore, getClusterIdFromHost } from "../common/cluster-store"; +import { Cluster } from "./cluster"; import logger from "./logger"; import { apiKubePrefix } from "../common/vars"; import { Singleton } from "../common/utils"; export class ClusterManager extends Singleton { constructor(public readonly port: number) { - super() + super(); // auto-init clusters autorun(() => { clusterStore.enabledClustersList.forEach(cluster => { @@ -34,52 +34,52 @@ export class ClusterManager extends Singleton { delay: 250 }); - ipcMain.on("network:offline", () => { this.onNetworkOffline() }) - ipcMain.on("network:online", () => { this.onNetworkOnline() }) + ipcMain.on("network:offline", () => { this.onNetworkOffline(); }); + ipcMain.on("network:online", () => { this.onNetworkOnline(); }); } protected onNetworkOffline() { - logger.info("[CLUSTER-MANAGER]: network is offline") + logger.info("[CLUSTER-MANAGER]: network is offline"); clusterStore.enabledClustersList.forEach((cluster) => { if (!cluster.disconnected) { - cluster.online = false - cluster.accessible = false - cluster.refreshConnectionStatus().catch((e) => e) + cluster.online = false; + cluster.accessible = false; + cluster.refreshConnectionStatus().catch((e) => e); } - }) + }); } protected onNetworkOnline() { - logger.info("[CLUSTER-MANAGER]: network is online") + logger.info("[CLUSTER-MANAGER]: network is online"); clusterStore.enabledClustersList.forEach((cluster) => { if (!cluster.disconnected) { - cluster.refreshConnectionStatus().catch((e) => e) + cluster.refreshConnectionStatus().catch((e) => e); } - }) + }); } stop() { clusterStore.clusters.forEach((cluster: Cluster) => { cluster.disconnect(); - }) + }); } getClusterForRequest(req: http.IncomingMessage): Cluster { - let cluster: Cluster = null + let cluster: Cluster = null; // lens-server is connecting to 127.0.0.1:/ if (req.headers.host.startsWith("127.0.0.1")) { - const clusterId = req.url.split("/")[1] - cluster = clusterStore.getById(clusterId) + const clusterId = req.url.split("/")[1]; + cluster = clusterStore.getById(clusterId); if (cluster) { // we need to swap path prefix so that request is proxied to kube api - req.url = req.url.replace(`/${clusterId}`, apiKubePrefix) + req.url = req.url.replace(`/${clusterId}`, apiKubePrefix); } } else if (req.headers["x-cluster-id"]) { - cluster = clusterStore.getById(req.headers["x-cluster-id"].toString()) + cluster = clusterStore.getById(req.headers["x-cluster-id"].toString()); } else { const clusterId = getClusterIdFromHost(req.headers.host); - cluster = clusterStore.getById(clusterId) + cluster = clusterStore.getById(clusterId); } return cluster; diff --git a/src/main/cluster.ts b/src/main/cluster.ts index a2b71a865b..e2831e8c3f 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -1,18 +1,18 @@ -import { ipcMain } from "electron" -import type { ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences } from "../common/cluster-store" +import { ipcMain } from "electron"; +import type { ClusterId, ClusterMetadata, ClusterModel, ClusterPreferences } from "../common/cluster-store"; import type { IMetricsReqParams } from "../renderer/api/endpoints/metrics.api"; import type { WorkspaceId } from "../common/workspace-store"; import { action, computed, observable, reaction, toJS, when } from "mobx"; import { apiKubePrefix } from "../common/vars"; import { broadcastMessage } from "../common/ipc"; -import { ContextHandler } from "./context-handler" -import { AuthorizationV1Api, CoreV1Api, KubeConfig, V1ResourceAttributes } from "@kubernetes/client-node" +import { ContextHandler } from "./context-handler"; +import { AuthorizationV1Api, CoreV1Api, KubeConfig, V1ResourceAttributes } from "@kubernetes/client-node"; import { Kubectl } from "./kubectl"; -import { KubeconfigManager } from "./kubeconfig-manager" -import { getNodeWarningConditions, loadConfig, podHasIssues } from "../common/kube-helpers" -import request, { RequestPromiseOptions } from "request-promise-native" +import { KubeconfigManager } from "./kubeconfig-manager"; +import { getNodeWarningConditions, loadConfig, podHasIssues } from "../common/kube-helpers"; +import request, { RequestPromiseOptions } from "request-promise-native"; import { apiResources } from "../common/rbac"; -import logger from "./logger" +import logger from "./logger"; import { VersionDetector } from "./cluster-detectors/version-detector"; import { detectorRegistry } from "./cluster-detectors/detector-registry"; @@ -32,7 +32,7 @@ export enum ClusterMetadataKey { export type ClusterRefreshOptions = { refreshMetadata?: boolean -} +}; export interface ClusterState { initialized: boolean; @@ -50,7 +50,7 @@ export interface ClusterState { export class Cluster implements ClusterModel, ClusterState { public id: ClusterId; - public kubeCtl: Kubectl + public kubeCtl: Kubectl; public contextHandler: ContextHandler; public ownerRef: string; protected kubeconfigManager: KubeconfigManager; @@ -86,23 +86,23 @@ export class Cluster implements ClusterModel, ClusterState { } @computed get name() { - return this.preferences.clusterName || this.contextName + return this.preferences.clusterName || this.contextName; } get version(): string { - return String(this.metadata?.version) || "" + return String(this.metadata?.version) || ""; } constructor(model: ClusterModel) { this.updateModel(model); - const kubeconfig = this.getKubeconfig() + const kubeconfig = this.getKubeconfig(); if (kubeconfig.getContextObject(this.contextName)) { - this.apiUrl = kubeconfig.getCluster(kubeconfig.getContextObject(this.contextName).cluster).server + this.apiUrl = kubeconfig.getCluster(kubeconfig.getContextObject(this.contextName).cluster).server; } } get isManaged(): boolean { - return !!this.ownerRef + return !!this.ownerRef; } @action @@ -131,16 +131,16 @@ export class Cluster implements ClusterModel, ClusterState { } protected bindEvents() { - logger.info(`[CLUSTER]: bind events`, this.getMeta()) - const refreshTimer = setInterval(() => !this.disconnected && this.refresh(), 30000) // every 30s - const refreshMetadataTimer = setInterval(() => !this.disconnected && this.refreshMetadata(), 900000) // every 15 minutes + logger.info(`[CLUSTER]: bind events`, this.getMeta()); + const refreshTimer = setInterval(() => !this.disconnected && this.refresh(), 30000); // every 30s + const refreshMetadataTimer = setInterval(() => !this.disconnected && this.refreshMetadata(), 900000); // every 15 minutes if (ipcMain) { this.eventDisposers.push( reaction(() => this.getState(), () => this.pushState()), () => { - clearInterval(refreshTimer) - clearInterval(refreshMetadataTimer) + clearInterval(refreshTimer); + clearInterval(refreshMetadataTimer); }, ); } @@ -165,20 +165,20 @@ export class Cluster implements ClusterModel, ClusterState { if (this.disconnected || !this.accessible) { await this.reconnect(); } - await this.refreshConnectionStatus() + await this.refreshConnectionStatus(); if (this.accessible) { - await this.refreshAllowedResources() - this.isAdmin = await this.isClusterAdmin() - this.ready = true - this.ensureKubectl() + await this.refreshAllowedResources(); + this.isAdmin = await this.isClusterAdmin(); + this.ready = true; + this.ensureKubectl(); } - this.activated = true + this.activated = true; return this.pushState(); } protected async ensureKubectl() { - this.kubeCtl = new Kubectl(this.version) - return this.kubeCtl.ensureKubectl() // download kubectl in background, so it's not blocking dashboard + this.kubeCtl = new Kubectl(this.version); + return this.kubeCtl.ensureKubectl(); // download kubectl in background, so it's not blocking dashboard } @action @@ -214,9 +214,9 @@ export class Cluster implements ClusterModel, ClusterState { this.refreshAllowedResources(), ]); if (opts.refreshMetadata) { - this.refreshMetadata() + this.refreshMetadata(); } - this.ready = true + this.ready = true; } this.pushState(); } @@ -224,9 +224,9 @@ export class Cluster implements ClusterModel, ClusterState { @action async refreshMetadata() { logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta()); - const metadata = await detectorRegistry.detectForCluster(this) - const existingMetadata = this.metadata - this.metadata = Object.assign(existingMetadata, metadata) + const metadata = await detectorRegistry.detectForCluster(this); + const existingMetadata = this.metadata; + this.metadata = Object.assign(existingMetadata, metadata); } @action @@ -256,16 +256,16 @@ export class Cluster implements ClusterModel, ClusterState { } getProxyKubeconfigPath(): string { - return this.kubeconfigManager.getPath() + return this.kubeconfigManager.getPath(); } protected async k8sRequest(path: string, options: RequestPromiseOptions = {}): Promise { - options.headers ??= {} - options.json ??= true - options.timeout ??= 30000 - options.headers.Host = `${this.id}.${new URL(this.kubeProxyUrl).host}` // required in ClusterManager.getClusterForRequest() + options.headers ??= {}; + options.json ??= true; + options.timeout ??= 30000; + options.headers.Host = `${this.id}.${new URL(this.kubeProxyUrl).host}`; // required in ClusterManager.getClusterForRequest() - return request(this.kubeProxyUrl + path, options) + return request(this.kubeProxyUrl + path, options); } getMetrics(prometheusPath: string, queryParams: IMetricsReqParams & { query: string }) { @@ -276,17 +276,17 @@ export class Cluster implements ClusterModel, ClusterState { resolveWithFullResponse: false, json: true, qs: queryParams, - }) + }); } protected async getConnectionStatus(): Promise { try { - const versionDetector = new VersionDetector(this) - const versionData = await versionDetector.detect() - this.metadata.version = versionData.value + const versionDetector = new VersionDetector(this); + const versionData = await versionDetector.detect(); + this.metadata.version = versionData.value; return ClusterStatus.AccessGranted; } catch (error) { - logger.error(`Failed to connect cluster "${this.contextName}": ${error}`) + logger.error(`Failed to connect cluster "${this.contextName}": ${error}`); if (error.statusCode) { if (error.statusCode >= 400 && error.statusCode < 500) { this.failureReason = "Invalid credentials"; @@ -310,17 +310,17 @@ export class Cluster implements ClusterModel, ClusterState { } async canI(resourceAttributes: V1ResourceAttributes): Promise { - const authApi = this.getProxyKubeconfig().makeApiClient(AuthorizationV1Api) + const authApi = this.getProxyKubeconfig().makeApiClient(AuthorizationV1Api); try { const accessReview = await authApi.createSelfSubjectAccessReview({ apiVersion: "authorization.k8s.io/v1", kind: "SelfSubjectAccessReview", spec: { resourceAttributes } - }) - return accessReview.body.status.allowed + }); + return accessReview.body.status.allowed; } catch (error) { - logger.error(`failed to request selfSubjectAccessReview: ${error}`) - return false + logger.error(`failed to request selfSubjectAccessReview: ${error}`); + return false; } } @@ -329,7 +329,7 @@ export class Cluster implements ClusterModel, ClusterState { namespace: "kube-system", resource: "*", verb: "create", - }) + }); } protected async getEventCount(): Promise { @@ -345,7 +345,7 @@ export class Cluster implements ClusterModel, ClusterState { if (w.involvedObject.kind === 'Pod') { try { const { body: pod } = await client.readNamespacedPod(w.involvedObject.name, w.involvedObject.namespace); - logger.debug(`checking pod ${w.involvedObject.namespace}/${w.involvedObject.name}`) + logger.debug(`checking pod ${w.involvedObject.namespace}/${w.involvedObject.name}`); if (podHasIssues(pod)) { uniqEventSources.add(w.involvedObject.uid); } @@ -361,7 +361,7 @@ export class Cluster implements ClusterModel, ClusterState { .reduce((sum, conditions) => sum + conditions.length, 0); return uniqEventSources.size + nodeNotificationCount; } catch (error) { - logger.error("Failed to fetch event count: " + JSON.stringify(error)) + logger.error("Failed to fetch event count: " + JSON.stringify(error)); return 0; } } @@ -379,7 +379,7 @@ export class Cluster implements ClusterModel, ClusterState { }; return toJS(model, { recurseEverything: true - }) + }); } // serializable cluster-state used for sync btw main <-> renderer @@ -399,17 +399,17 @@ export class Cluster implements ClusterModel, ClusterState { }; return toJS(state, { recurseEverything: true - }) + }); } @action setState(state: ClusterState) { - Object.assign(this, state) + Object.assign(this, state); } pushState(state = this.getState()) { logger.silly(`[CLUSTER]: push-state`, state); - broadcastMessage("cluster:state", this.id, state) + broadcastMessage("cluster:state", this.id, state); } // get cluster system meta, e.g. use in "logger" @@ -422,30 +422,30 @@ export class Cluster implements ClusterModel, ClusterState { online: this.online, accessible: this.accessible, disconnected: this.disconnected, - } + }; } protected async getAllowedNamespaces() { if (this.accessibleNamespaces.length) { - return this.accessibleNamespaces + return this.accessibleNamespaces; } - const api = this.getProxyKubeconfig().makeApiClient(CoreV1Api) + const api = this.getProxyKubeconfig().makeApiClient(CoreV1Api); try { - const namespaceList = await api.listNamespace() + const namespaceList = await api.listNamespace(); const nsAccessStatuses = await Promise.all( namespaceList.body.items.map(ns => this.canI({ namespace: ns.metadata.name, resource: "pods", verb: "list", })) - ) + ); return namespaceList.body.items .filter((ns, i) => nsAccessStatuses[i]) - .map(ns => ns.metadata.name) + .map(ns => ns.metadata.name); } catch (error) { - const ctx = this.getProxyKubeconfig().getContextObject(this.contextName) - if (ctx.namespace) return [ctx.namespace] + const ctx = this.getProxyKubeconfig().getContextObject(this.contextName); + if (ctx.namespace) return [ctx.namespace]; return []; } } @@ -462,12 +462,12 @@ export class Cluster implements ClusterModel, ClusterState { verb: "list", namespace: this.allowedNamespaces[0] })) - ) + ); return apiResources .filter((resource, i) => resourceAccessStatuses[i]) - .map(apiResource => apiResource.resource) + .map(apiResource => apiResource.resource); } catch (error) { - return [] + return []; } } } diff --git a/src/main/context-handler.ts b/src/main/context-handler.ts index a3cf6185dd..10f84ced6d 100644 --- a/src/main/context-handler.ts +++ b/src/main/context-handler.ts @@ -1,21 +1,21 @@ -import type { PrometheusProvider, PrometheusService } from "./prometheus/provider-registry" +import type { PrometheusProvider, PrometheusService } from "./prometheus/provider-registry"; import type { ClusterPreferences } from "../common/cluster-store"; -import type { Cluster } from "./cluster" -import type httpProxy from "http-proxy" +import type { Cluster } from "./cluster"; +import type httpProxy from "http-proxy"; import url, { UrlWithStringQuery } from "url"; -import { CoreV1Api } from "@kubernetes/client-node" -import { prometheusProviders } from "../common/prometheus-providers" -import logger from "./logger" -import { getFreePort } from "./port" -import { KubeAuthProxy } from "./kube-auth-proxy" +import { CoreV1Api } from "@kubernetes/client-node"; +import { prometheusProviders } from "../common/prometheus-providers"; +import logger from "./logger"; +import { getFreePort } from "./port"; +import { KubeAuthProxy } from "./kube-auth-proxy"; export class ContextHandler { public proxyPort: number; public clusterUrl: UrlWithStringQuery; - protected kubeAuthProxy: KubeAuthProxy - protected apiTarget: httpProxy.ServerOptions - protected prometheusProvider: string - protected prometheusPath: string + protected kubeAuthProxy: KubeAuthProxy; + protected apiTarget: httpProxy.ServerOptions; + protected prometheusProvider: string; + protected prometheusPath: string; constructor(protected cluster: Cluster) { this.clusterUrl = url.parse(cluster.apiUrl); @@ -26,64 +26,64 @@ export class ContextHandler { this.prometheusProvider = preferences.prometheusProvider?.type; this.prometheusPath = null; if (preferences.prometheus) { - const { namespace, service, port } = preferences.prometheus - this.prometheusPath = `${namespace}/services/${service}:${port}` + const { namespace, service, port } = preferences.prometheus; + this.prometheusPath = `${namespace}/services/${service}:${port}`; } } protected async resolvePrometheusPath(): Promise { - const { service, namespace, port } = await this.getPrometheusService() - return `${namespace}/services/${service}:${port}` + const { service, namespace, port } = await this.getPrometheusService(); + return `${namespace}/services/${service}:${port}`; } async getPrometheusProvider() { if (!this.prometheusProvider) { - const service = await this.getPrometheusService() - logger.info(`using ${service.id} as prometheus provider`) - this.prometheusProvider = service.id + const service = await this.getPrometheusService(); + logger.info(`using ${service.id} as prometheus provider`); + this.prometheusProvider = service.id; } - return prometheusProviders.find(p => p.id === this.prometheusProvider) + return prometheusProviders.find(p => p.id === this.prometheusProvider); } async getPrometheusService(): Promise { const providers = this.prometheusProvider ? prometheusProviders.filter(provider => provider.id == this.prometheusProvider) : prometheusProviders; const prometheusPromises: Promise[] = providers.map(async (provider: PrometheusProvider): Promise => { - const apiClient = this.cluster.getProxyKubeconfig().makeApiClient(CoreV1Api) - return await provider.getPrometheusService(apiClient) - }) - const resolvedPrometheusServices = await Promise.all(prometheusPromises) + const apiClient = this.cluster.getProxyKubeconfig().makeApiClient(CoreV1Api); + return await provider.getPrometheusService(apiClient); + }); + const resolvedPrometheusServices = await Promise.all(prometheusPromises); const service = resolvedPrometheusServices.filter(n => n)[0]; return service || { id: "lens", namespace: "lens-metrics", service: "prometheus", port: 80 - } + }; } async getPrometheusPath(): Promise { if (!this.prometheusPath) { - this.prometheusPath = await this.resolvePrometheusPath() + this.prometheusPath = await this.resolvePrometheusPath(); } return this.prometheusPath; } async resolveAuthProxyUrl() { const proxyPort = await this.ensurePort(); - const path = this.clusterUrl.path !== "/" ? this.clusterUrl.path : "" + const path = this.clusterUrl.path !== "/" ? this.clusterUrl.path : ""; return `http://127.0.0.1:${proxyPort}${path}`; } async getApiTarget(isWatchRequest = false): Promise { if (this.apiTarget && !isWatchRequest) { - return this.apiTarget + return this.apiTarget; } - const timeout = isWatchRequest ? 4 * 60 * 60 * 1000 : 30000 // 4 hours for watch request, 30 seconds for the rest - const apiTarget = await this.newApiTarget(timeout) + const timeout = isWatchRequest ? 4 * 60 * 60 * 1000 : 30000; // 4 hours for watch request, 30 seconds for the rest + const apiTarget = await this.newApiTarget(timeout); if (!isWatchRequest) { - this.apiTarget = apiTarget + this.apiTarget = apiTarget; } - return apiTarget + return apiTarget; } protected async newApiTarget(timeout: number): Promise { @@ -95,36 +95,36 @@ export class ContextHandler { headers: { "Host": this.clusterUrl.hostname, }, - } + }; } async ensurePort(): Promise { if (!this.proxyPort) { this.proxyPort = await getFreePort(); } - return this.proxyPort + return this.proxyPort; } async ensureServer() { if (!this.kubeAuthProxy) { await this.ensurePort(); - const proxyEnv = Object.assign({}, process.env) + const proxyEnv = Object.assign({}, process.env); if (this.cluster.preferences.httpsProxy) { - proxyEnv.HTTPS_PROXY = this.cluster.preferences.httpsProxy + proxyEnv.HTTPS_PROXY = this.cluster.preferences.httpsProxy; } - this.kubeAuthProxy = new KubeAuthProxy(this.cluster, this.proxyPort, proxyEnv) - await this.kubeAuthProxy.run() + this.kubeAuthProxy = new KubeAuthProxy(this.cluster, this.proxyPort, proxyEnv); + await this.kubeAuthProxy.run(); } } stopServer() { if (this.kubeAuthProxy) { - this.kubeAuthProxy.exit() - this.kubeAuthProxy = null + this.kubeAuthProxy.exit(); + this.kubeAuthProxy = null; } } get proxyLastError(): string { - return this.kubeAuthProxy?.lastError || "" + return this.kubeAuthProxy?.lastError || ""; } } diff --git a/src/main/exit-app.ts b/src/main/exit-app.ts index bf73e022f3..b58a6e4dfc 100644 --- a/src/main/exit-app.ts +++ b/src/main/exit-app.ts @@ -6,13 +6,13 @@ import logger from "./logger"; export function exitApp() { - const windowManager = WindowManager.getInstance() - const clusterManager = ClusterManager.getInstance() - appEventBus.emit({ name: "service", action: "close" }) + const windowManager = WindowManager.getInstance(); + const clusterManager = ClusterManager.getInstance(); + appEventBus.emit({ name: "service", action: "close" }); windowManager.hide(); clusterManager.stop(); logger.info('SERVICE:QUIT'); setTimeout(() => { - app.exit() - }, 1000) + app.exit(); + }, 1000); } \ No newline at end of file diff --git a/src/main/helm/helm-chart-manager.ts b/src/main/helm/helm-chart-manager.ts index e42f7a1aaf..42c1a30ed2 100644 --- a/src/main/helm/helm-chart-manager.ts +++ b/src/main/helm/helm-chart-manager.ts @@ -1,74 +1,74 @@ import fs from "fs"; import * as yaml from "js-yaml"; -import { HelmRepo, HelmRepoManager } from "./helm-repo-manager" +import { HelmRepo, HelmRepoManager } from "./helm-repo-manager"; import logger from "../logger"; -import { promiseExec } from "../promise-exec" -import { helmCli } from "./helm-cli" +import { promiseExec } from "../promise-exec"; +import { helmCli } from "./helm-cli"; type CachedYaml = { entries: any; // todo: types -} +}; export class HelmChartManager { - protected cache: any = {} - protected repo: HelmRepo + protected cache: any = {}; + protected repo: HelmRepo; constructor(repo: HelmRepo){ - this.cache = HelmRepoManager.cache - this.repo = repo + this.cache = HelmRepoManager.cache; + this.repo = repo; } public async chart(name: string) { - const charts = await this.charts() - return charts[name] + const charts = await this.charts(); + return charts[name]; } public async charts(): Promise { try { - const cachedYaml = await this.cachedYaml() - return cachedYaml["entries"] + const cachedYaml = await this.cachedYaml(); + return cachedYaml["entries"]; } catch(error) { - logger.error(error) - return [] + logger.error(error); + return []; } } public async getReadme(name: string, version = "") { - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); if(version && version != "") { - const { stdout, stderr} = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr)}) - return stdout + const { stdout, stderr} = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr);}); + return stdout; } else { - const { stdout, stderr} = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr)}) - return stdout + const { stdout, stderr} = await promiseExec(`"${helm}" show readme ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr);}); + return stdout; } } public async getValues(name: string, version = "") { - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); if(version && version != "") { - const { stdout, stderr} = await promiseExec(`"${helm}" show values ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr)}) + const { stdout, stderr} = await promiseExec(`"${helm}" show values ${this.repo.name}/${name} --version ${version}`).catch((error) => { throw(error.stderr);}); - return stdout + return stdout; } else { - const { stdout, stderr} = await promiseExec(`"${helm}" show values ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr)}) + const { stdout, stderr} = await promiseExec(`"${helm}" show values ${this.repo.name}/${name}`).catch((error) => { throw(error.stderr);}); - return stdout + return stdout; } } protected async cachedYaml(): Promise { if (!(this.repo.name in this.cache)) { - const cacheFile = await fs.promises.readFile(this.repo.cacheFilePath, 'utf-8') - const data = yaml.safeLoad(cacheFile) + const cacheFile = await fs.promises.readFile(this.repo.cacheFilePath, 'utf-8'); + const data = yaml.safeLoad(cacheFile); for(const key in data["entries"]) { data["entries"][key].forEach((version: any) => { - version['repo'] = this.repo.name - version['created'] = Date.parse(version.created).toString() - }) + version['repo'] = this.repo.name; + version['created'] = Date.parse(version.created).toString(); + }); } - this.cache[this.repo.name] = Buffer.from(JSON.stringify(data)) + this.cache[this.repo.name] = Buffer.from(JSON.stringify(data)); } - return JSON.parse(this.cache[this.repo.name].toString()) + return JSON.parse(this.cache[this.repo.name].toString()); } } diff --git a/src/main/helm/helm-cli.ts b/src/main/helm/helm-cli.ts index 1484ceacf1..34a3becc33 100644 --- a/src/main/helm/helm-cli.ts +++ b/src/main/helm/helm-cli.ts @@ -1,6 +1,6 @@ -import packageInfo from "../../../package.json" -import path from "path" -import { LensBinary, LensBinaryOpts } from "../lens-binary" +import packageInfo from "../../../package.json"; +import path from "path"; +import { LensBinary, LensBinaryOpts } from "../lens-binary"; import { isProduction } from "../../common/vars"; export class HelmCli extends LensBinary { @@ -11,24 +11,24 @@ export class HelmCli extends LensBinary { baseDir: baseDir, originalBinaryName: "helm", newBinaryName: "helm3" - } - super(opts) + }; + super(opts); } protected getTarName(): string | null { - return `${this.binaryName}-v${this.binaryVersion}-${this.platformName}-${this.arch}.tar.gz` + return `${this.binaryName}-v${this.binaryVersion}-${this.platformName}-${this.arch}.tar.gz`; } protected getUrl() { - return `https://get.helm.sh/helm-v${this.binaryVersion}-${this.platformName}-${this.arch}.tar.gz` + return `https://get.helm.sh/helm-v${this.binaryVersion}-${this.platformName}-${this.arch}.tar.gz`; } protected getBinaryPath() { - return path.join(this.dirname, this.binaryName) + return path.join(this.dirname, this.binaryName); } protected getOriginalBinaryPath() { - return path.join(this.dirname, this.platformName + "-" + this.arch, this.originalBinaryName) + return path.join(this.dirname, this.platformName + "-" + this.arch, this.originalBinaryName); } } diff --git a/src/main/helm/helm-release-manager.ts b/src/main/helm/helm-release-manager.ts index 80be023227..3a8b4707ba 100644 --- a/src/main/helm/helm-release-manager.ts +++ b/src/main/helm/helm-release-manager.ts @@ -1,7 +1,7 @@ import * as tempy from "tempy"; import fs from "fs"; import * as yaml from "js-yaml"; -import { promiseExec} from "../promise-exec" +import { promiseExec} from "../promise-exec"; import { helmCli } from "./helm-cli"; import { Cluster } from "../cluster"; import { toCamelCase } from "../../common/utils/camelCase"; @@ -9,103 +9,103 @@ import { toCamelCase } from "../../common/utils/camelCase"; export class HelmReleaseManager { public async listReleases(pathToKubeconfig: string, namespace?: string) { - const helm = await helmCli.binaryPath() - const namespaceFlag = namespace ? `-n ${namespace}` : "--all-namespaces" - const { stdout } = await promiseExec(`"${helm}" ls --output json ${namespaceFlag} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)}) + const helm = await helmCli.binaryPath(); + const namespaceFlag = namespace ? `-n ${namespace}` : "--all-namespaces"; + const { stdout } = await promiseExec(`"${helm}" ls --output json ${namespaceFlag} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); - const output = JSON.parse(stdout) + const output = JSON.parse(stdout); if (output.length == 0) { - return output + return output; } output.forEach((release: any, index: number) => { - output[index] = toCamelCase(release) + output[index] = toCamelCase(release); }); - return output + return output; } public async installChart(chart: string, values: any, name: string, namespace: string, version: string, pathToKubeconfig: string){ - const helm = await helmCli.binaryPath() - const fileName = tempy.file({name: "values.yaml"}) - await fs.promises.writeFile(fileName, yaml.safeDump(values)) + const helm = await helmCli.binaryPath(); + const fileName = tempy.file({name: "values.yaml"}); + await fs.promises.writeFile(fileName, yaml.safeDump(values)); try { - let generateName = "" + let generateName = ""; if (!name) { - generateName = "--generate-name" - name = "" + generateName = "--generate-name"; + name = ""; } - const { stdout, stderr } = await promiseExec(`"${helm}" install ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${pathToKubeconfig} ${generateName}`).catch((error) => { throw(error.stderr)}) - const releaseName = stdout.split("\n")[0].split(' ')[1].trim() + const { stdout, stderr } = await promiseExec(`"${helm}" install ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${pathToKubeconfig} ${generateName}`).catch((error) => { throw(error.stderr);}); + const releaseName = stdout.split("\n")[0].split(' ')[1].trim(); return { log: stdout, release: { name: releaseName, namespace: namespace } - } + }; } finally { - await fs.promises.unlink(fileName) + await fs.promises.unlink(fileName); } } public async upgradeRelease(name: string, chart: string, values: any, namespace: string, version: string, cluster: Cluster){ - const helm = await helmCli.binaryPath() - const fileName = tempy.file({name: "values.yaml"}) - await fs.promises.writeFile(fileName, yaml.safeDump(values)) + const helm = await helmCli.binaryPath(); + const fileName = tempy.file({name: "values.yaml"}); + await fs.promises.writeFile(fileName, yaml.safeDump(values)); try { - const { stdout, stderr } = await promiseExec(`"${helm}" upgrade ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr)}) + const { stdout, stderr } = await promiseExec(`"${helm}" upgrade ${name} ${chart} --version ${version} -f ${fileName} --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr);}); return { log: stdout, release: this.getRelease(name, namespace, cluster) - } + }; } finally { - await fs.promises.unlink(fileName) + await fs.promises.unlink(fileName); } } public async getRelease(name: string, namespace: string, cluster: Cluster) { - const helm = await helmCli.binaryPath() - const {stdout, stderr} = await promiseExec(`"${helm}" status ${name} --output json --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr)}) - const release = JSON.parse(stdout) - release.resources = await this.getResources(name, namespace, cluster) - return release + const helm = await helmCli.binaryPath(); + const {stdout, stderr} = await promiseExec(`"${helm}" status ${name} --output json --namespace ${namespace} --kubeconfig ${cluster.getProxyKubeconfigPath()}`).catch((error) => { throw(error.stderr);}); + const release = JSON.parse(stdout); + release.resources = await this.getResources(name, namespace, cluster); + return release; } public async deleteRelease(name: string, namespace: string, pathToKubeconfig: string) { - const helm = await helmCli.binaryPath() - const { stdout, stderr } = await promiseExec(`"${helm}" delete ${name} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)}) + const helm = await helmCli.binaryPath(); + const { stdout, stderr } = await promiseExec(`"${helm}" delete ${name} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); - return stdout + return stdout; } public async getValues(name: string, namespace: string, pathToKubeconfig: string) { - const helm = await helmCli.binaryPath() - const { stdout, stderr } = await promiseExec(`"${helm}" get values ${name} --all --output yaml --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)}) - return stdout + const helm = await helmCli.binaryPath(); + const { stdout, stderr } = await promiseExec(`"${helm}" get values ${name} --all --output yaml --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); + return stdout; } public async getHistory(name: string, namespace: string, pathToKubeconfig: string) { - const helm = await helmCli.binaryPath() - const {stdout, stderr} = await promiseExec(`"${helm}" history ${name} --output json --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)}) - return JSON.parse(stdout) + const helm = await helmCli.binaryPath(); + const {stdout, stderr} = await promiseExec(`"${helm}" history ${name} --output json --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); + return JSON.parse(stdout); } public async rollback(name: string, namespace: string, revision: number, pathToKubeconfig: string) { - const helm = await helmCli.binaryPath() - const {stdout, stderr} = await promiseExec(`"${helm}" rollback ${name} ${revision} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr)}) - return stdout + const helm = await helmCli.binaryPath(); + const {stdout, stderr} = await promiseExec(`"${helm}" rollback ${name} ${revision} --namespace ${namespace} --kubeconfig ${pathToKubeconfig}`).catch((error) => { throw(error.stderr);}); + return stdout; } protected async getResources(name: string, namespace: string, cluster: Cluster) { - const helm = await helmCli.binaryPath() - const kubectl = await cluster.kubeCtl.getPath() - const pathToKubeconfig = cluster.getProxyKubeconfigPath() + const helm = await helmCli.binaryPath(); + const kubectl = await cluster.kubeCtl.getPath(); + const pathToKubeconfig = cluster.getProxyKubeconfigPath(); const { stdout } = await promiseExec(`"${helm}" get manifest ${name} --namespace ${namespace} --kubeconfig ${pathToKubeconfig} | "${kubectl}" get -n ${namespace} --kubeconfig ${pathToKubeconfig} -f - -o=json`).catch((error) => { - return { stdout: JSON.stringify({items: []})} - }) - return stdout + return { stdout: JSON.stringify({items: []})}; + }); + return stdout; } } -export const releaseManager = new HelmReleaseManager() +export const releaseManager = new HelmReleaseManager(); diff --git a/src/main/helm/helm-repo-manager.ts b/src/main/helm/helm-repo-manager.ts index c2af9ea7ba..dff372a301 100644 --- a/src/main/helm/helm-repo-manager.ts +++ b/src/main/helm/helm-repo-manager.ts @@ -10,7 +10,7 @@ import logger from "../logger"; export type HelmEnv = Record & { HELM_REPOSITORY_CACHE?: string; HELM_REPOSITORY_CONFIG?: string; -} +}; export interface HelmRepoConfig { repositories: HelmRepo[] @@ -29,11 +29,11 @@ export interface HelmRepo { } export class HelmRepoManager extends Singleton { - static cache = {} // todo: remove implicit updates in helm-chart-manager.ts + static cache = {}; // todo: remove implicit updates in helm-chart-manager.ts protected repos: HelmRepo[]; - protected helmEnv: HelmEnv - protected initialized: boolean + protected helmEnv: HelmEnv; + protected initialized: boolean; async loadAvailableRepos(): Promise { const res = await customRequestPromise({ @@ -46,34 +46,34 @@ export class HelmRepoManager extends Singleton { } async init() { - helmCli.setLogger(logger) + helmCli.setLogger(logger); await helmCli.ensureBinary(); if (!this.initialized) { - this.helmEnv = await this.parseHelmEnv() - await this.update() - this.initialized = true + this.helmEnv = await this.parseHelmEnv(); + await this.update(); + this.initialized = true; } } protected async parseHelmEnv() { - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); const { stdout } = await promiseExec(`"${helm}" env`).catch((error) => { - throw(error.stderr) - }) - const lines = stdout.split(/\r?\n/) // split by new line feed - const env: HelmEnv = {} + throw(error.stderr); + }); + const lines = stdout.split(/\r?\n/); // split by new line feed + const env: HelmEnv = {}; lines.forEach((line: string) => { - const [key, value] = line.split("=") + const [key, value] = line.split("="); if (key && value) { - env[key] = value.replace(/"/g, "") // strip quotas + env[key] = value.replace(/"/g, ""); // strip quotas } - }) - return env + }); + return env; } public async repositories(): Promise { if (!this.initialized) { - await this.init() + await this.init(); } try { const repoConfigFile = this.helmEnv.HELM_REPOSITORY_CONFIG; @@ -91,41 +91,41 @@ export class HelmRepoManager extends Singleton { cacheFilePath: `${this.helmEnv.HELM_REPOSITORY_CACHE}/${repo.name}-index.yaml` })); } catch (error) { - logger.error(`[HELM]: repositories listing error "${error}"`) - return [] + logger.error(`[HELM]: repositories listing error "${error}"`); + return []; } } public async repository(name: string) { - const repositories = await this.repositories() + const repositories = await this.repositories(); return repositories.find(repo => repo.name == name); } public async update() { - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); const { stdout } = await promiseExec(`"${helm}" repo update`).catch((error) => { - return { stdout: error.stdout } - }) - return stdout + return { stdout: error.stdout }; + }); + return stdout; } public async addRepo({ name, url }: HelmRepo) { logger.info(`[HELM]: adding repo "${name}" from ${url}`); - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); const { stdout } = await promiseExec(`"${helm}" repo add ${name} ${url}`).catch((error) => { - throw(error.stderr) - }) - return stdout + throw(error.stderr); + }); + return stdout; } public async removeRepo({ name, url }: HelmRepo): Promise { logger.info(`[HELM]: removing repo "${name}" from ${url}`); - const helm = await helmCli.binaryPath() + const helm = await helmCli.binaryPath(); const { stdout, stderr } = await promiseExec(`"${helm}" repo remove ${name}`).catch((error) => { - throw(error.stderr) - }) - return stdout + throw(error.stderr); + }); + return stdout; } } -export const repoManager = HelmRepoManager.getInstance() +export const repoManager = HelmRepoManager.getInstance(); diff --git a/src/main/helm/helm-service.ts b/src/main/helm/helm-service.ts index 664a30358c..88ca4dda3e 100644 --- a/src/main/helm/helm-service.ts +++ b/src/main/helm/helm-service.ts @@ -6,93 +6,93 @@ import { releaseManager } from "./helm-release-manager"; class HelmService { public async installChart(cluster: Cluster, data: { chart: string; values: {}; name: string; namespace: string; version: string }) { - return await releaseManager.installChart(data.chart, data.values, data.name, data.namespace, data.version, cluster.getProxyKubeconfigPath()) + return await releaseManager.installChart(data.chart, data.values, data.name, data.namespace, data.version, cluster.getProxyKubeconfigPath()); } public async listCharts() { - const charts: any = {} - await repoManager.init() - const repositories = await repoManager.repositories() + const charts: any = {}; + await repoManager.init(); + const repositories = await repoManager.repositories(); for (const repo of repositories) { - charts[repo.name] = {} - const manager = new HelmChartManager(repo) - let entries = await manager.charts() - entries = this.excludeDeprecated(entries) + charts[repo.name] = {}; + const manager = new HelmChartManager(repo); + let entries = await manager.charts(); + entries = this.excludeDeprecated(entries); for (const key in entries) { - entries[key] = entries[key][0] + entries[key] = entries[key][0]; } - charts[repo.name] = entries + charts[repo.name] = entries; } - return charts + return charts; } public async getChart(repoName: string, chartName: string, version = "") { const result = { readme: "", versions: {} - } - const repo = await repoManager.repository(repoName) - const chartManager = new HelmChartManager(repo) - const chart = await chartManager.chart(chartName) - result.readme = await chartManager.getReadme(chartName, version) - result.versions = chart - return result + }; + const repo = await repoManager.repository(repoName); + const chartManager = new HelmChartManager(repo); + const chart = await chartManager.chart(chartName); + result.readme = await chartManager.getReadme(chartName, version); + result.versions = chart; + return result; } public async getChartValues(repoName: string, chartName: string, version = "") { - const repo = await repoManager.repository(repoName) - const chartManager = new HelmChartManager(repo) - return chartManager.getValues(chartName, version) + const repo = await repoManager.repository(repoName); + const chartManager = new HelmChartManager(repo); + return chartManager.getValues(chartName, version); } public async listReleases(cluster: Cluster, namespace: string = null) { - await repoManager.init() - return await releaseManager.listReleases(cluster.getProxyKubeconfigPath(), namespace) + await repoManager.init(); + return await releaseManager.listReleases(cluster.getProxyKubeconfigPath(), namespace); } public async getRelease(cluster: Cluster, releaseName: string, namespace: string) { - logger.debug("Fetch release") - return await releaseManager.getRelease(releaseName, namespace, cluster) + logger.debug("Fetch release"); + return await releaseManager.getRelease(releaseName, namespace, cluster); } public async getReleaseValues(cluster: Cluster, releaseName: string, namespace: string) { - logger.debug("Fetch release values") - return await releaseManager.getValues(releaseName, namespace, cluster.getProxyKubeconfigPath()) + logger.debug("Fetch release values"); + return await releaseManager.getValues(releaseName, namespace, cluster.getProxyKubeconfigPath()); } public async getReleaseHistory(cluster: Cluster, releaseName: string, namespace: string) { - logger.debug("Fetch release history") - return await releaseManager.getHistory(releaseName, namespace, cluster.getProxyKubeconfigPath()) + logger.debug("Fetch release history"); + return await releaseManager.getHistory(releaseName, namespace, cluster.getProxyKubeconfigPath()); } public async deleteRelease(cluster: Cluster, releaseName: string, namespace: string) { - logger.debug("Delete release") - return await releaseManager.deleteRelease(releaseName, namespace, cluster.getProxyKubeconfigPath()) + logger.debug("Delete release"); + return await releaseManager.deleteRelease(releaseName, namespace, cluster.getProxyKubeconfigPath()); } public async updateRelease(cluster: Cluster, releaseName: string, namespace: string, data: { chart: string; values: {}; version: string }) { - logger.debug("Upgrade release") - return await releaseManager.upgradeRelease(releaseName, data.chart, data.values, namespace, data.version, cluster) + logger.debug("Upgrade release"); + return await releaseManager.upgradeRelease(releaseName, data.chart, data.values, namespace, data.version, cluster); } public async rollback(cluster: Cluster, releaseName: string, namespace: string, revision: number) { - logger.debug("Rollback release") - const output = await releaseManager.rollback(releaseName, namespace, revision, cluster.getProxyKubeconfigPath()) - return { message: output } + logger.debug("Rollback release"); + const output = await releaseManager.rollback(releaseName, namespace, revision, cluster.getProxyKubeconfigPath()); + return { message: output }; } protected excludeDeprecated(entries: any) { for (const key in entries) { entries[key] = entries[key].filter((entry: any) => { if (Array.isArray(entry)) { - return entry[0]['deprecated'] != true + return entry[0]['deprecated'] != true; } - return entry["deprecated"] != true - }) + return entry["deprecated"] != true; + }); } - return entries + return entries; } } -export const helmService = new HelmService() +export const helmService = new HelmService(); diff --git a/src/main/index.ts b/src/main/index.ts index e360c2fe85..2087432d7b 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,25 +1,25 @@ // Main process -import "../common/system-ca" -import "../common/prometheus-providers" -import * as Mobx from "mobx" +import "../common/system-ca"; +import "../common/prometheus-providers"; +import * as Mobx from "mobx"; import * as LensExtensions from "../extensions/core-api"; -import { app, dialog } from "electron" +import { app, dialog } from "electron"; import { appName } from "../common/vars"; -import path from "path" -import { LensProxy } from "./lens-proxy" +import path from "path"; +import { LensProxy } from "./lens-proxy"; import { WindowManager } from "./window-manager"; import { ClusterManager } from "./cluster-manager"; -import { AppUpdater } from "./app-updater" -import { shellSync } from "./shell-sync" -import { getFreePort } from "./port" -import { mangleProxyEnv } from "./proxy-env" +import { AppUpdater } from "./app-updater"; +import { shellSync } from "./shell-sync"; +import { getFreePort } from "./port"; +import { mangleProxyEnv } from "./proxy-env"; import { registerFileProtocol } from "../common/register-protocol"; -import logger from "./logger" -import { clusterStore } from "../common/cluster-store" +import logger from "./logger"; +import { clusterStore } from "../common/cluster-store"; import { userStore } from "../common/user-store"; import { workspaceStore } from "../common/workspace-store"; -import { appEventBus } from "../common/event-bus" +import { appEventBus } from "../common/event-bus"; import { extensionLoader } from "../extensions/extension-loader"; import { extensionManager } from "../extensions/extension-manager"; import { extensionsStore } from "../extensions/extensions-store"; @@ -35,16 +35,16 @@ if (!process.env.CICD) { app.setPath("userData", workingDir); } -mangleProxyEnv() +mangleProxyEnv(); if (app.commandLine.getSwitchValue("proxy-server") !== "") { - process.env.HTTPS_PROXY = app.commandLine.getSwitchValue("proxy-server") + process.env.HTTPS_PROXY = app.commandLine.getSwitchValue("proxy-server"); } app.on("ready", async () => { - logger.info(`🚀 Starting Lens from "${workingDir}"`) + logger.info(`🚀 Starting Lens from "${workingDir}"`); await shellSync(); - const updater = new AppUpdater() + const updater = new AppUpdater(); updater.start(); registerFileProtocol("static", __static); @@ -59,10 +59,10 @@ app.on("ready", async () => { // find free port try { - proxyPort = await getFreePort() + proxyPort = await getFreePort(); } catch (error) { - logger.error(error) - dialog.showErrorBox("Lens Error", "Could not find a free port for the cluster proxy") + logger.error(error); + dialog.showErrorBox("Lens Error", "Could not find a free port for the cluster proxy"); app.exit(); } @@ -73,22 +73,22 @@ app.on("ready", async () => { try { proxyServer = LensProxy.create(proxyPort, clusterManager); } catch (error) { - logger.error(`Could not start proxy (127.0.0:${proxyPort}): ${error.message}`) - dialog.showErrorBox("Lens Error", `Could not start proxy (127.0.0:${proxyPort}): ${error.message || "unknown error"}`) + logger.error(`Could not start proxy (127.0.0:${proxyPort}): ${error.message}`); + dialog.showErrorBox("Lens Error", `Could not start proxy (127.0.0:${proxyPort}): ${error.message || "unknown error"}`); app.exit(); } - extensionLoader.init() + extensionLoader.init(); windowManager = WindowManager.getInstance(proxyPort); extensionLoader.initExtensions(await extensionManager.load()); // call after windowManager to see splash earlier setTimeout(() => { - appEventBus.emit({ name: "service", action: "start" }) - }, 1000) + appEventBus.emit({ name: "service", action: "start" }); + }, 1000); }); app.on("activate", (event, hasVisibleWindows) => { - logger.info('APP:ACTIVATE', { hasVisibleWindows }) + logger.info('APP:ACTIVATE', { hasVisibleWindows }); if (!hasVisibleWindows) { windowManager.initMainWindow(); } @@ -97,11 +97,11 @@ app.on("activate", (event, hasVisibleWindows) => { // Quit app on Cmd+Q (MacOS) app.on("will-quit", (event) => { logger.info('APP:QUIT'); - appEventBus.emit({name: "app", action: "close"}) + appEventBus.emit({name: "app", action: "close"}); event.preventDefault(); // prevent app's default shutdown (e.g. required for telemetry, etc.) clusterManager?.stop(); // close cluster connections return; // skip exit to make tray work, to quit go to app's global menu or tray's menu -}) +}); // Extensions-api runtime exports export const LensExtensionsApi = { @@ -111,4 +111,4 @@ export const LensExtensionsApi = { export { Mobx, LensExtensionsApi as LensExtensions, -} +}; diff --git a/src/main/kube-auth-proxy.ts b/src/main/kube-auth-proxy.ts index 5377ecb829..3ad76e52b0 100644 --- a/src/main/kube-auth-proxy.ts +++ b/src/main/kube-auth-proxy.ts @@ -1,10 +1,10 @@ -import { ChildProcess, spawn } from "child_process" +import { ChildProcess, spawn } from "child_process"; import { waitUntilUsed } from "tcp-port-used"; import { broadcastMessage } from "../common/ipc"; -import type { Cluster } from "./cluster" -import { Kubectl } from "./kubectl" -import logger from "./logger" -import * as url from "url" +import type { Cluster } from "./cluster"; +import { Kubectl } from "./kubectl"; +import logger from "./logger"; +import * as url from "url"; export interface KubeAuthProxyLog { data: string; @@ -12,19 +12,19 @@ export interface KubeAuthProxyLog { } export class KubeAuthProxy { - public lastError: string + public lastError: string; - protected cluster: Cluster - protected env: NodeJS.ProcessEnv = null - protected proxyProcess: ChildProcess - protected port: number - protected kubectl: Kubectl + protected cluster: Cluster; + protected env: NodeJS.ProcessEnv = null; + protected proxyProcess: ChildProcess; + protected port: number; + protected kubectl: Kubectl; constructor(cluster: Cluster, port: number, env: NodeJS.ProcessEnv) { - this.env = env - this.port = port - this.cluster = cluster - this.kubectl = Kubectl.bundled() + this.env = env; + this.port = port; + this.cluster = cluster; + this.kubectl = Kubectl.bundled(); } get acceptHosts() { @@ -36,7 +36,7 @@ export class KubeAuthProxy { return; } - const proxyBin = await this.kubectl.getPath() + const proxyBin = await this.kubectl.getPath(); const args = [ "proxy", "-p", `${this.port}`, @@ -44,63 +44,63 @@ export class KubeAuthProxy { "--context", `${this.cluster.contextName}`, "--accept-hosts", this.acceptHosts, "--reject-paths", "^[^/]" - ] + ]; if (process.env.DEBUG_PROXY === "true") { - args.push("-v", "9") + args.push("-v", "9"); } - logger.debug(`spawning kubectl proxy with args: ${args}`) - this.proxyProcess = spawn(proxyBin, args, { env: this.env, }) + logger.debug(`spawning kubectl proxy with args: ${args}`); + this.proxyProcess = spawn(proxyBin, args, { env: this.env, }); this.proxyProcess.on("error", (error) => { - this.sendIpcLogMessage({ data: error.message, error: true }) - this.exit() - }) + this.sendIpcLogMessage({ data: error.message, error: true }); + this.exit(); + }); this.proxyProcess.on("exit", (code) => { - this.sendIpcLogMessage({ data: `proxy exited with code: ${code}`, error: code > 0 }) + this.sendIpcLogMessage({ data: `proxy exited with code: ${code}`, error: code > 0 }); this.exit(); - }) + }); this.proxyProcess.stdout.on('data', (data) => { - let logItem = data.toString() + let logItem = data.toString(); if (logItem.startsWith("Starting to serve on")) { - logItem = "Authentication proxy started\n" + logItem = "Authentication proxy started\n"; } - this.sendIpcLogMessage({ data: logItem }) - }) + this.sendIpcLogMessage({ data: logItem }); + }); this.proxyProcess.stderr.on('data', (data) => { - this.lastError = this.parseError(data.toString()) - this.sendIpcLogMessage({ data: data.toString(), error: true }) - }) + this.lastError = this.parseError(data.toString()); + this.sendIpcLogMessage({ data: data.toString(), error: true }); + }); - return waitUntilUsed(this.port, 500, 10000) + return waitUntilUsed(this.port, 500, 10000); } protected parseError(data: string) { - const error = data.split("http: proxy error:").slice(1).join("").trim() - let errorMsg = error - const jsonError = error.split("Response: ")[1] + const error = data.split("http: proxy error:").slice(1).join("").trim(); + let errorMsg = error; + const jsonError = error.split("Response: ")[1]; if (jsonError) { try { - const parsedError = JSON.parse(jsonError) - errorMsg = parsedError.error_description || parsedError.error || jsonError + const parsedError = JSON.parse(jsonError); + errorMsg = parsedError.error_description || parsedError.error || jsonError; } catch (_) { - errorMsg = jsonError.trim() + errorMsg = jsonError.trim(); } } - return errorMsg + return errorMsg; } protected async sendIpcLogMessage(res: KubeAuthProxyLog) { - const channel = `kube-auth:${this.cluster.id}` + const channel = `kube-auth:${this.cluster.id}`; logger.info(`[KUBE-AUTH]: out-channel "${channel}"`, { ...res, meta: this.cluster.getMeta() }); - broadcastMessage(channel, res) + broadcastMessage(channel, res); } public exit() { if (!this.proxyProcess) return; - logger.debug("[KUBE-AUTH]: stopping local proxy", this.cluster.getMeta()) - this.proxyProcess.kill() + logger.debug("[KUBE-AUTH]: stopping local proxy", this.cluster.getMeta()); + this.proxyProcess.kill(); this.proxyProcess.removeAllListeners(); this.proxyProcess.stderr.removeAllListeners(); this.proxyProcess.stdout.removeAllListeners(); diff --git a/src/main/kubeconfig-manager.ts b/src/main/kubeconfig-manager.ts index fc84d00ddb..a8b3ae3fce 100644 --- a/src/main/kubeconfig-manager.ts +++ b/src/main/kubeconfig-manager.ts @@ -1,22 +1,22 @@ import type { KubeConfig } from "@kubernetes/client-node"; -import type { Cluster } from "./cluster" +import type { Cluster } from "./cluster"; import type { ContextHandler } from "./context-handler"; -import { app } from "electron" -import path from "path" -import fs from "fs-extra" -import { dumpConfigYaml, loadConfig } from "../common/kube-helpers" -import logger from "./logger" +import { app } from "electron"; +import path from "path"; +import fs from "fs-extra"; +import { dumpConfigYaml, loadConfig } from "../common/kube-helpers"; +import logger from "./logger"; export class KubeconfigManager { - protected configDir = app.getPath("temp") + protected configDir = app.getPath("temp"); protected tempFile: string; private constructor(protected cluster: Cluster, protected contextHandler: ContextHandler, protected port: number) { } static async create(cluster: Cluster, contextHandler: ContextHandler, port: number) { - const kcm = new KubeconfigManager(cluster, contextHandler, port) - await kcm.init() - return kcm + const kcm = new KubeconfigManager(cluster, contextHandler, port); + await kcm.init(); + return kcm; } protected async init() { @@ -24,7 +24,7 @@ export class KubeconfigManager { await this.contextHandler.ensurePort(); await this.createProxyKubeconfig(); } catch (err) { - logger.error(`Failed to created temp config for auth-proxy`, { err }) + logger.error(`Failed to created temp config for auth-proxy`, { err }); } } @@ -33,7 +33,7 @@ export class KubeconfigManager { } protected resolveProxyUrl() { - return `http://127.0.0.1:${this.port}/${this.cluster.id}` + return `http://127.0.0.1:${this.port}/${this.cluster.id}`; } /** @@ -78,11 +78,11 @@ export class KubeconfigManager { async unlink() { if (!this.tempFile) { - return + return; } - logger.info('Deleting temporary kubeconfig: ' + this.tempFile) - await fs.unlink(this.tempFile) - this.tempFile = undefined + logger.info('Deleting temporary kubeconfig: ' + this.tempFile); + await fs.unlink(this.tempFile); + this.tempFile = undefined; } } diff --git a/src/main/kubectl.ts b/src/main/kubectl.ts index 6b2f51476d..5d3f12746e 100644 --- a/src/main/kubectl.ts +++ b/src/main/kubectl.ts @@ -1,17 +1,17 @@ -import { app, remote } from "electron" -import path from "path" -import fs from "fs" -import { promiseExec } from "./promise-exec" -import logger from "./logger" -import { ensureDir, pathExists } from "fs-extra" -import * as lockFile from "proper-lockfile" -import { helmCli } from "./helm/helm-cli" -import { userStore } from "../common/user-store" +import { app, remote } from "electron"; +import path from "path"; +import fs from "fs"; +import { promiseExec } from "./promise-exec"; +import logger from "./logger"; +import { ensureDir, pathExists } from "fs-extra"; +import * as lockFile from "proper-lockfile"; +import { helmCli } from "./helm/helm-cli"; +import { userStore } from "../common/user-store"; import { customRequest } from "../common/request"; -import { getBundledKubectlVersion } from "../common/utils/app-version" +import { getBundledKubectlVersion } from "../common/utils/app-version"; import { isDevelopment, isWindows, isTestEnv } from "../common/vars"; -const bundledVersion = getBundledKubectlVersion() +const bundledVersion = getBundledKubectlVersion(); const kubectlMap: Map = new Map([ ["1.7", "1.8.15"], ["1.8", "1.9.10"], @@ -26,314 +26,314 @@ const kubectlMap: Map = new Map([ ["1.17", bundledVersion], ["1.18", "1.18.8"], ["1.19", "1.19.0"] -]) +]); const packageMirrors: Map = new Map([ ["default", "https://storage.googleapis.com/kubernetes-release/release"], ["china", "https://mirror.azure.cn/kubernetes/kubectl"] -]) +]); -let bundledPath: string -const initScriptVersionString = "# lens-initscript v3\n" +let bundledPath: string; +const initScriptVersionString = "# lens-initscript v3\n"; export function bundledKubectlPath(): string { - if (bundledPath) { return bundledPath } + if (bundledPath) { return bundledPath; } if (isDevelopment || isTestEnv) { - const platformName = isWindows ? "windows" : process.platform - bundledPath = path.join(process.cwd(), "binaries", "client", platformName, process.arch, "kubectl") + const platformName = isWindows ? "windows" : process.platform; + bundledPath = path.join(process.cwd(), "binaries", "client", platformName, process.arch, "kubectl"); } else { - bundledPath = path.join(process.resourcesPath, process.arch, "kubectl") + bundledPath = path.join(process.resourcesPath, process.arch, "kubectl"); } if (isWindows) { - bundledPath = `${bundledPath}.exe` + bundledPath = `${bundledPath}.exe`; } - return bundledPath + return bundledPath; } export class Kubectl { - public kubectlVersion: string - protected directory: string - protected url: string - protected path: string - protected dirname: string + public kubectlVersion: string; + protected directory: string; + protected url: string; + protected path: string; + protected dirname: string; static get kubectlDir() { - return path.join((app || remote.app).getPath("userData"), "binaries", "kubectl") + return path.join((app || remote.app).getPath("userData"), "binaries", "kubectl"); } - public static readonly bundledKubectlVersion: string = bundledVersion - public static invalidBundle = false + public static readonly bundledKubectlVersion: string = bundledVersion; + public static invalidBundle = false; private static bundledInstance: Kubectl; // Returns the single bundled Kubectl instance public static bundled() { - if (!Kubectl.bundledInstance) Kubectl.bundledInstance = new Kubectl(Kubectl.bundledKubectlVersion) - return Kubectl.bundledInstance + if (!Kubectl.bundledInstance) Kubectl.bundledInstance = new Kubectl(Kubectl.bundledKubectlVersion); + return Kubectl.bundledInstance; } constructor(clusterVersion: string) { - const versionParts = /^v?(\d+\.\d+)(.*)/.exec(clusterVersion) - const minorVersion = versionParts[1] + const versionParts = /^v?(\d+\.\d+)(.*)/.exec(clusterVersion); + const minorVersion = versionParts[1]; /* minorVersion is the first two digits of kube server version if the version map includes that, use that version, if not, fallback to the exact x.y.z of kube version */ if (kubectlMap.has(minorVersion)) { - this.kubectlVersion = kubectlMap.get(minorVersion) - logger.debug("Set kubectl version " + this.kubectlVersion + " for cluster version " + clusterVersion + " using version map") + this.kubectlVersion = kubectlMap.get(minorVersion); + logger.debug("Set kubectl version " + this.kubectlVersion + " for cluster version " + clusterVersion + " using version map"); } else { - this.kubectlVersion = versionParts[1] + versionParts[2] - logger.debug("Set kubectl version " + this.kubectlVersion + " for cluster version " + clusterVersion + " using fallback") + this.kubectlVersion = versionParts[1] + versionParts[2]; + logger.debug("Set kubectl version " + this.kubectlVersion + " for cluster version " + clusterVersion + " using fallback"); } - let arch = null + let arch = null; if (process.arch == "x64") { - arch = "amd64" + arch = "amd64"; } else if (process.arch == "x86" || process.arch == "ia32") { - arch = "386" + arch = "386"; } else { - arch = process.arch + arch = process.arch; } - const platformName = isWindows ? "windows" : process.platform - const binaryName = isWindows ? "kubectl.exe" : "kubectl" + const platformName = isWindows ? "windows" : process.platform; + const binaryName = isWindows ? "kubectl.exe" : "kubectl"; - this.url = `${this.getDownloadMirror()}/v${this.kubectlVersion}/bin/${platformName}/${arch}/${binaryName}` + this.url = `${this.getDownloadMirror()}/v${this.kubectlVersion}/bin/${platformName}/${arch}/${binaryName}`; - this.dirname = path.normalize(path.join(this.getDownloadDir(), this.kubectlVersion)) - this.path = path.join(this.dirname, binaryName) + this.dirname = path.normalize(path.join(this.getDownloadDir(), this.kubectlVersion)); + this.path = path.join(this.dirname, binaryName); } public getBundledPath() { - return bundledKubectlPath() + return bundledKubectlPath(); } public getPathFromPreferences() { - return userStore.preferences?.kubectlBinariesPath || this.getBundledPath() + return userStore.preferences?.kubectlBinariesPath || this.getBundledPath(); } protected getDownloadDir() { if (userStore.preferences?.downloadBinariesPath) { - return path.join(userStore.preferences.downloadBinariesPath, "kubectl") + return path.join(userStore.preferences.downloadBinariesPath, "kubectl"); } - return Kubectl.kubectlDir + return Kubectl.kubectlDir; } public async getPath(bundled = false): Promise { if (userStore.preferences?.downloadKubectlBinaries === false) { - return this.getPathFromPreferences() + return this.getPathFromPreferences(); } // return binary name if bundled path is not functional if (!await this.checkBinary(this.getBundledPath(), false)) { - Kubectl.invalidBundle = true - return path.basename(this.getBundledPath()) + Kubectl.invalidBundle = true; + return path.basename(this.getBundledPath()); } try { if (!await this.ensureKubectl()) { - logger.error("Failed to ensure kubectl, fallback to the bundled version") - return this.getBundledPath() + logger.error("Failed to ensure kubectl, fallback to the bundled version"); + return this.getBundledPath(); } - return this.path + return this.path; } catch (err) { - logger.error("Failed to ensure kubectl, fallback to the bundled version") - logger.error(err) - return this.getBundledPath() + logger.error("Failed to ensure kubectl, fallback to the bundled version"); + logger.error(err); + return this.getBundledPath(); } } public async binDir() { try { - await this.ensureKubectl() - await this.writeInitScripts() - return this.dirname + await this.ensureKubectl(); + await this.writeInitScripts(); + return this.dirname; } catch (err) { - logger.error(err) - return "" + logger.error(err); + return ""; } } public async checkBinary(path: string, checkVersion = true) { - const exists = await pathExists(path) + const exists = await pathExists(path); if (exists) { try { - const { stdout } = await promiseExec(`"${path}" version --client=true -o json`) - const output = JSON.parse(stdout) + const { stdout } = await promiseExec(`"${path}" version --client=true -o json`); + const output = JSON.parse(stdout); if (!checkVersion) { - return true + return true; } - let version: string = output.clientVersion.gitVersion + let version: string = output.clientVersion.gitVersion; if (version[0] === 'v') { - version = version.slice(1) + version = version.slice(1); } if (version === this.kubectlVersion) { - logger.debug(`Local kubectl is version ${this.kubectlVersion}`) - return true + logger.debug(`Local kubectl is version ${this.kubectlVersion}`); + return true; } - logger.error(`Local kubectl is version ${version}, expected ${this.kubectlVersion}, unlinking`) + logger.error(`Local kubectl is version ${version}, expected ${this.kubectlVersion}, unlinking`); } catch (err) { - logger.error(`Local kubectl failed to run properly (${err.message}), unlinking`) + logger.error(`Local kubectl failed to run properly (${err.message}), unlinking`); } - await fs.promises.unlink(this.path) + await fs.promises.unlink(this.path); } - return false + return false; } protected async checkBundled(): Promise { if (this.kubectlVersion === Kubectl.bundledKubectlVersion) { try { - const exist = await pathExists(this.path) + const exist = await pathExists(this.path); if (!exist) { - await fs.promises.copyFile(this.getBundledPath(), this.path) - await fs.promises.chmod(this.path, 0o755) + await fs.promises.copyFile(this.getBundledPath(), this.path); + await fs.promises.chmod(this.path, 0o755); } - return true + return true; } catch (err) { - logger.error("Could not copy the bundled kubectl to app-data: " + err) - return false + logger.error("Could not copy the bundled kubectl to app-data: " + err); + return false; } } else { - return false + return false; } } public async ensureKubectl(): Promise { if (userStore.preferences?.downloadKubectlBinaries === false) { - return true + return true; } if (Kubectl.invalidBundle) { - logger.error(`Detected invalid bundle binary, returning ...`) - return false + logger.error(`Detected invalid bundle binary, returning ...`); + return false; } - await ensureDir(this.dirname, 0o755) + await ensureDir(this.dirname, 0o755); return lockFile.lock(this.dirname).then(async (release) => { - logger.debug(`Acquired a lock for ${this.kubectlVersion}`) - const bundled = await this.checkBundled() - let isValid = await this.checkBinary(this.path, !bundled) + logger.debug(`Acquired a lock for ${this.kubectlVersion}`); + const bundled = await this.checkBundled(); + let isValid = await this.checkBinary(this.path, !bundled); if (!isValid && !bundled) { await this.downloadKubectl().catch((error) => { - logger.error(error) - logger.debug(`Releasing lock for ${this.kubectlVersion}`) - release() - return false + logger.error(error); + logger.debug(`Releasing lock for ${this.kubectlVersion}`); + release(); + return false; }); - isValid = !await this.checkBinary(this.path, false) + isValid = !await this.checkBinary(this.path, false); } if (!isValid) { - logger.debug(`Releasing lock for ${this.kubectlVersion}`) - release() - return false + logger.debug(`Releasing lock for ${this.kubectlVersion}`); + release(); + return false; } - logger.debug(`Releasing lock for ${this.kubectlVersion}`) - release() - return true + logger.debug(`Releasing lock for ${this.kubectlVersion}`); + release(); + return true; }).catch((e) => { - logger.error(`Failed to get a lock for ${this.kubectlVersion}`) - logger.error(e) - return false - }) + logger.error(`Failed to get a lock for ${this.kubectlVersion}`); + logger.error(e); + return false; + }); } public async downloadKubectl() { - await ensureDir(path.dirname(this.path), 0o755) + await ensureDir(path.dirname(this.path), 0o755); - logger.info(`Downloading kubectl ${this.kubectlVersion} from ${this.url} to ${this.path}`) + logger.info(`Downloading kubectl ${this.kubectlVersion} from ${this.url} to ${this.path}`); return new Promise((resolve, reject) => { const stream = customRequest({ url: this.url, gzip: true, }); - const file = fs.createWriteStream(this.path) + const file = fs.createWriteStream(this.path); stream.on("complete", () => { - logger.debug("kubectl binary download finished") - file.end() - }) + logger.debug("kubectl binary download finished"); + file.end(); + }); stream.on("error", (error) => { - logger.error(error) + logger.error(error); fs.unlink(this.path, () => { // do nothing - }) - reject(error) - }) + }); + reject(error); + }); file.on("close", () => { - logger.debug("kubectl binary download closed") + logger.debug("kubectl binary download closed"); fs.chmod(this.path, 0o755, (err) => { if (err) reject(err); - }) - resolve() - }) - stream.pipe(file) - }) + }); + resolve(); + }); + stream.pipe(file); + }); } protected async writeInitScripts() { - const kubectlPath = userStore.preferences?.downloadKubectlBinaries ? this.dirname : path.dirname(this.getPathFromPreferences()) - const helmPath = helmCli.getBinaryDir() + const kubectlPath = userStore.preferences?.downloadKubectlBinaries ? this.dirname : path.dirname(this.getPathFromPreferences()); + const helmPath = helmCli.getBinaryDir(); const fsPromises = fs.promises; - const bashScriptPath = path.join(this.dirname, '.bash_set_path') + const bashScriptPath = path.join(this.dirname, '.bash_set_path'); - let bashScript = "" + initScriptVersionString - bashScript += "tempkubeconfig=\"$KUBECONFIG\"\n" - bashScript += "test -f \"/etc/profile\" && . \"/etc/profile\"\n" - bashScript += "if test -f \"$HOME/.bash_profile\"; then\n" - bashScript += " . \"$HOME/.bash_profile\"\n" - bashScript += "elif test -f \"$HOME/.bash_login\"; then\n" - bashScript += " . \"$HOME/.bash_login\"\n" - bashScript += "elif test -f \"$HOME/.profile\"; then\n" - bashScript += " . \"$HOME/.profile\"\n" - bashScript += "fi\n" - bashScript += `export PATH="${helmPath}:${kubectlPath}:$PATH"\n` - bashScript += "export KUBECONFIG=\"$tempkubeconfig\"\n" + let bashScript = "" + initScriptVersionString; + bashScript += "tempkubeconfig=\"$KUBECONFIG\"\n"; + bashScript += "test -f \"/etc/profile\" && . \"/etc/profile\"\n"; + bashScript += "if test -f \"$HOME/.bash_profile\"; then\n"; + bashScript += " . \"$HOME/.bash_profile\"\n"; + bashScript += "elif test -f \"$HOME/.bash_login\"; then\n"; + bashScript += " . \"$HOME/.bash_login\"\n"; + bashScript += "elif test -f \"$HOME/.profile\"; then\n"; + bashScript += " . \"$HOME/.profile\"\n"; + bashScript += "fi\n"; + bashScript += `export PATH="${helmPath}:${kubectlPath}:$PATH"\n`; + bashScript += "export KUBECONFIG=\"$tempkubeconfig\"\n"; - bashScript += "NO_PROXY=\",${NO_PROXY:-localhost},\"\n" - bashScript += "NO_PROXY=\"${NO_PROXY//,localhost,/,}\"\n" - bashScript += "NO_PROXY=\"${NO_PROXY//,127.0.0.1,/,}\"\n" - bashScript += "NO_PROXY=\"localhost,127.0.0.1${NO_PROXY%,}\"\n" - bashScript += "export NO_PROXY\n" - bashScript += "unset tempkubeconfig\n" - await fsPromises.writeFile(bashScriptPath, bashScript.toString(), { mode: 0o644 }) + bashScript += "NO_PROXY=\",${NO_PROXY:-localhost},\"\n"; + bashScript += "NO_PROXY=\"${NO_PROXY//,localhost,/,}\"\n"; + bashScript += "NO_PROXY=\"${NO_PROXY//,127.0.0.1,/,}\"\n"; + bashScript += "NO_PROXY=\"localhost,127.0.0.1${NO_PROXY%,}\"\n"; + bashScript += "export NO_PROXY\n"; + bashScript += "unset tempkubeconfig\n"; + await fsPromises.writeFile(bashScriptPath, bashScript.toString(), { mode: 0o644 }); - const zshScriptPath = path.join(this.dirname, '.zlogin') + const zshScriptPath = path.join(this.dirname, '.zlogin'); - let zshScript = "" + initScriptVersionString + let zshScript = "" + initScriptVersionString; - zshScript += "tempkubeconfig=\"$KUBECONFIG\"\n" + zshScript += "tempkubeconfig=\"$KUBECONFIG\"\n"; // restore previous ZDOTDIR - zshScript += "export ZDOTDIR=\"$OLD_ZDOTDIR\"\n" + zshScript += "export ZDOTDIR=\"$OLD_ZDOTDIR\"\n"; // source all the files - zshScript += "test -f \"$OLD_ZDOTDIR/.zshenv\" && . \"$OLD_ZDOTDIR/.zshenv\"\n" - zshScript += "test -f \"$OLD_ZDOTDIR/.zprofile\" && . \"$OLD_ZDOTDIR/.zprofile\"\n" - zshScript += "test -f \"$OLD_ZDOTDIR/.zlogin\" && . \"$OLD_ZDOTDIR/.zlogin\"\n" - zshScript += "test -f \"$OLD_ZDOTDIR/.zshrc\" && . \"$OLD_ZDOTDIR/.zshrc\"\n" + zshScript += "test -f \"$OLD_ZDOTDIR/.zshenv\" && . \"$OLD_ZDOTDIR/.zshenv\"\n"; + zshScript += "test -f \"$OLD_ZDOTDIR/.zprofile\" && . \"$OLD_ZDOTDIR/.zprofile\"\n"; + zshScript += "test -f \"$OLD_ZDOTDIR/.zlogin\" && . \"$OLD_ZDOTDIR/.zlogin\"\n"; + zshScript += "test -f \"$OLD_ZDOTDIR/.zshrc\" && . \"$OLD_ZDOTDIR/.zshrc\"\n"; // voodoo to replace any previous occurrences of kubectl path in the PATH - zshScript += `kubectlpath=\"${kubectlPath}"\n` - zshScript += `helmpath=\"${helmPath}"\n` - zshScript += "p=\":$kubectlpath:\"\n" - zshScript += "d=\":$PATH:\"\n" - zshScript += "d=${d//$p/:}\n" - zshScript += "d=${d/#:/}\n" - zshScript += "export PATH=\"$helmpath:$kubectlpath:${d/%:/}\"\n" - zshScript += "export KUBECONFIG=\"$tempkubeconfig\"\n" - zshScript += "NO_PROXY=\",${NO_PROXY:-localhost},\"\n" - zshScript += "NO_PROXY=\"${NO_PROXY//,localhost,/,}\"\n" - zshScript += "NO_PROXY=\"${NO_PROXY//,127.0.0.1,/,}\"\n" - zshScript += "NO_PROXY=\"localhost,127.0.0.1${NO_PROXY%,}\"\n" - zshScript += "export NO_PROXY\n" - zshScript += "unset tempkubeconfig\n" - zshScript += "unset OLD_ZDOTDIR\n" - await fsPromises.writeFile(zshScriptPath, zshScript.toString(), { mode: 0o644 }) + zshScript += `kubectlpath=\"${kubectlPath}"\n`; + zshScript += `helmpath=\"${helmPath}"\n`; + zshScript += "p=\":$kubectlpath:\"\n"; + zshScript += "d=\":$PATH:\"\n"; + zshScript += "d=${d//$p/:}\n"; + zshScript += "d=${d/#:/}\n"; + zshScript += "export PATH=\"$helmpath:$kubectlpath:${d/%:/}\"\n"; + zshScript += "export KUBECONFIG=\"$tempkubeconfig\"\n"; + zshScript += "NO_PROXY=\",${NO_PROXY:-localhost},\"\n"; + zshScript += "NO_PROXY=\"${NO_PROXY//,localhost,/,}\"\n"; + zshScript += "NO_PROXY=\"${NO_PROXY//,127.0.0.1,/,}\"\n"; + zshScript += "NO_PROXY=\"localhost,127.0.0.1${NO_PROXY%,}\"\n"; + zshScript += "export NO_PROXY\n"; + zshScript += "unset tempkubeconfig\n"; + zshScript += "unset OLD_ZDOTDIR\n"; + await fsPromises.writeFile(zshScriptPath, zshScript.toString(), { mode: 0o644 }); } protected getDownloadMirror() { - const mirror = packageMirrors.get(userStore.preferences?.downloadMirror) + const mirror = packageMirrors.get(userStore.preferences?.downloadMirror); if (mirror) { - return mirror + return mirror; } - return packageMirrors.get("default") // MacOS packages are only available from default + return packageMirrors.get("default"); // MacOS packages are only available from default } } diff --git a/src/main/kubectl_spec.ts b/src/main/kubectl_spec.ts index ade999c082..9d5a5d1e1d 100644 --- a/src/main/kubectl_spec.ts +++ b/src/main/kubectl_spec.ts @@ -1,5 +1,5 @@ -import packageInfo from "../../package.json" -import path from "path" +import packageInfo from "../../package.json"; +import path from "path"; import { Kubectl } from "../../src/main/kubectl"; import { isWindows } from "../common/vars"; @@ -7,39 +7,39 @@ jest.mock("../common/user-store"); describe("kubectlVersion", () => { it("returns bundled version if exactly same version used", async () => { - const kubectl = new Kubectl(Kubectl.bundled().kubectlVersion) - expect(kubectl.kubectlVersion).toBe(Kubectl.bundled().kubectlVersion) - }) + const kubectl = new Kubectl(Kubectl.bundled().kubectlVersion); + expect(kubectl.kubectlVersion).toBe(Kubectl.bundled().kubectlVersion); + }); it("returns bundled version if same major.minor version is used", async () => { const { bundledKubectlVersion } = packageInfo.config; const kubectl = new Kubectl(bundledKubectlVersion); - expect(kubectl.kubectlVersion).toBe(Kubectl.bundled().kubectlVersion) - }) -}) + expect(kubectl.kubectlVersion).toBe(Kubectl.bundled().kubectlVersion); + }); +}); describe("getPath()", () => { it("returns path to downloaded kubectl binary", async () => { const { bundledKubectlVersion } = packageInfo.config; const kubectl = new Kubectl(bundledKubectlVersion); - const kubectlPath = await kubectl.getPath() - let binaryName = "kubectl" + const kubectlPath = await kubectl.getPath(); + let binaryName = "kubectl"; if (isWindows) { - binaryName += ".exe" + binaryName += ".exe"; } - const expectedPath = path.join(Kubectl.kubectlDir, Kubectl.bundledKubectlVersion, binaryName) - expect(kubectlPath).toBe(expectedPath) - }) + const expectedPath = path.join(Kubectl.kubectlDir, Kubectl.bundledKubectlVersion, binaryName); + expect(kubectlPath).toBe(expectedPath); + }); it("returns plain binary name if bundled kubectl is non-functional", async () => { const { bundledKubectlVersion } = packageInfo.config; const kubectl = new Kubectl(bundledKubectlVersion); - jest.spyOn(kubectl, "getBundledPath").mockReturnValue("/invalid/path/kubectl") - const kubectlPath = await kubectl.getPath() - let binaryName = "kubectl" + jest.spyOn(kubectl, "getBundledPath").mockReturnValue("/invalid/path/kubectl"); + const kubectlPath = await kubectl.getPath(); + let binaryName = "kubectl"; if (isWindows) { - binaryName += ".exe" + binaryName += ".exe"; } - expect(kubectlPath).toBe(binaryName) - }) -}) + expect(kubectlPath).toBe(binaryName); + }); +}); diff --git a/src/main/lens-api.ts b/src/main/lens-api.ts index a0a7361a68..fafeffce91 100644 --- a/src/main/lens-api.ts +++ b/src/main/lens-api.ts @@ -2,16 +2,16 @@ import http from "http"; export abstract class LensApi { protected respondJson(res: http.ServerResponse, content: {}, status = 200) { - this.respond(res, JSON.stringify(content), "application/json", status) + this.respond(res, JSON.stringify(content), "application/json", status); } protected respondText(res: http.ServerResponse, content: string, status = 200) { - this.respond(res, content, "text/plain", status) + this.respond(res, content, "text/plain", status); } protected respond(res: http.ServerResponse, content: string, contentType: string, status = 200) { - res.setHeader("Content-Type", contentType) - res.statusCode = status - res.end(content) + res.setHeader("Content-Type", contentType); + res.statusCode = status; + res.end(content); } } diff --git a/src/main/lens-binary.ts b/src/main/lens-binary.ts index dd6f2aa058..fc6b59ee74 100644 --- a/src/main/lens-binary.ts +++ b/src/main/lens-binary.ts @@ -1,10 +1,10 @@ -import path from "path" -import fs from "fs" -import request from "request" -import { ensureDir, pathExists } from "fs-extra" -import * as tar from "tar" +import path from "path"; +import fs from "fs"; +import request from "request"; +import { ensureDir, pathExists } from "fs-extra"; +import * as tar from "tar"; import { isWindows } from "../common/vars"; -import winston from "winston" +import winston from "winston"; export type LensBinaryOpts = { version: string; @@ -12,177 +12,177 @@ export type LensBinaryOpts = { originalBinaryName: string; newBinaryName?: string; requestOpts?: request.Options; -} +}; export class LensBinary { - public binaryVersion: string - protected directory: string - protected url: string + public binaryVersion: string; + protected directory: string; + protected url: string; protected path: string; protected tarPath: string; - protected dirname: string - protected binaryName: string - protected platformName: string - protected arch: string - protected originalBinaryName: string - protected requestOpts: request.Options - protected logger: Console | winston.Logger + protected dirname: string; + protected binaryName: string; + protected platformName: string; + protected arch: string; + protected originalBinaryName: string; + protected requestOpts: request.Options; + protected logger: Console | winston.Logger; constructor(opts: LensBinaryOpts) { - const baseDir = opts.baseDir - this.originalBinaryName = opts.originalBinaryName - this.binaryName = opts.newBinaryName || opts.originalBinaryName - this.binaryVersion = opts.version - this.requestOpts = opts.requestOpts - this.logger = console - let arch = null + const baseDir = opts.baseDir; + this.originalBinaryName = opts.originalBinaryName; + this.binaryName = opts.newBinaryName || opts.originalBinaryName; + this.binaryVersion = opts.version; + this.requestOpts = opts.requestOpts; + this.logger = console; + let arch = null; if (process.arch == "x64") { - arch = "amd64" + arch = "amd64"; } else if (process.arch == "x86" || process.arch == "ia32") { - arch = "386" + arch = "386"; } else { - arch = process.arch + arch = process.arch; } - this.arch = arch - this.platformName = isWindows ? "windows" : process.platform - this.dirname = path.normalize(path.join(baseDir, this.binaryName)) + this.arch = arch; + this.platformName = isWindows ? "windows" : process.platform; + this.dirname = path.normalize(path.join(baseDir, this.binaryName)); if (isWindows) { - this.binaryName = this.binaryName + ".exe" - this.originalBinaryName = this.originalBinaryName + ".exe" + this.binaryName = this.binaryName + ".exe"; + this.originalBinaryName = this.originalBinaryName + ".exe"; } - const tarName = this.getTarName() + const tarName = this.getTarName(); if (tarName) { - this.tarPath = path.join(this.dirname, tarName) + this.tarPath = path.join(this.dirname, tarName); } } public setLogger(logger: Console | winston.Logger) { - this.logger = logger + this.logger = logger; } protected binaryDir() { - throw new Error("binaryDir not implemented") + throw new Error("binaryDir not implemented"); } public async binaryPath() { - await this.ensureBinary() - return this.getBinaryPath() + await this.ensureBinary(); + return this.getBinaryPath(); } protected getTarName(): string | null { - return null + return null; } protected getUrl() { - return "" + return ""; } protected getBinaryPath() { - return "" + return ""; } protected getOriginalBinaryPath() { - return "" + return ""; } public getBinaryDir() { - return path.dirname(this.getBinaryPath()) + return path.dirname(this.getBinaryPath()); } public async binDir() { try { - await this.ensureBinary() - return this.dirname + await this.ensureBinary(); + return this.dirname; } catch (err) { - this.logger.error(err) - return "" + this.logger.error(err); + return ""; } } protected async checkBinary() { - const exists = await pathExists(this.getBinaryPath()) - return exists + const exists = await pathExists(this.getBinaryPath()); + return exists; } public async ensureBinary() { - const isValid = await this.checkBinary() + const isValid = await this.checkBinary(); if (!isValid) { await this.downloadBinary().catch((error) => { - this.logger.error(error) + this.logger.error(error); }); - if (this.tarPath) await this.untarBinary() - if (this.originalBinaryName != this.binaryName) await this.renameBinary() - this.logger.info(`${this.originalBinaryName} has been downloaded to ${this.getBinaryPath()}`) + if (this.tarPath) await this.untarBinary(); + if (this.originalBinaryName != this.binaryName) await this.renameBinary(); + this.logger.info(`${this.originalBinaryName} has been downloaded to ${this.getBinaryPath()}`); } } protected async untarBinary() { return new Promise((resolve, reject) => { - this.logger.debug(`Extracting ${this.originalBinaryName} binary`) + this.logger.debug(`Extracting ${this.originalBinaryName} binary`); tar.x({ file: this.tarPath, cwd: this.dirname }).then((_ => { - resolve() - })) - }) + resolve(); + })); + }); } protected async renameBinary() { return new Promise((resolve, reject) => { - this.logger.debug(`Renaming ${this.originalBinaryName} binary to ${this.binaryName}`) + this.logger.debug(`Renaming ${this.originalBinaryName} binary to ${this.binaryName}`); fs.rename(this.getOriginalBinaryPath(), this.getBinaryPath(), (err) => { if (err) { - reject(err) + reject(err); } else { - resolve() + resolve(); } - }) - }) + }); + }); } protected async downloadBinary() { - const binaryPath = this.tarPath || this.getBinaryPath() - await ensureDir(this.getBinaryDir(), 0o755) + const binaryPath = this.tarPath || this.getBinaryPath(); + await ensureDir(this.getBinaryDir(), 0o755); - const file = fs.createWriteStream(binaryPath) - const url = this.getUrl() + const file = fs.createWriteStream(binaryPath); + const url = this.getUrl(); - this.logger.info(`Downloading ${this.originalBinaryName} ${this.binaryVersion} from ${url} to ${binaryPath}`) + this.logger.info(`Downloading ${this.originalBinaryName} ${this.binaryVersion} from ${url} to ${binaryPath}`); const requestOpts: request.UriOptions & request.CoreOptions = { uri: url, gzip: true, ...this.requestOpts - } + }; - const stream = request(requestOpts) + const stream = request(requestOpts); stream.on("complete", () => { - this.logger.info(`Download of ${this.originalBinaryName} finished`) - file.end() - }) + this.logger.info(`Download of ${this.originalBinaryName} finished`); + file.end(); + }); stream.on("error", (error) => { - this.logger.error(error) + this.logger.error(error); fs.unlink(binaryPath, () => { // do nothing - }) - throw(error) - }) + }); + throw(error); + }); return new Promise((resolve, reject) => { file.on("close", () => { - this.logger.debug(`${this.originalBinaryName} binary download closed`) + this.logger.debug(`${this.originalBinaryName} binary download closed`); if (!this.tarPath) fs.chmod(binaryPath, 0o755, (err) => { if (err) reject(err); - }) - resolve() - }) - stream.pipe(file) - }) + }); + resolve(); + }); + stream.pipe(file); + }); } } diff --git a/src/main/lens-proxy.ts b/src/main/lens-proxy.ts index 7f0b14721d..03b1b15d29 100644 --- a/src/main/lens-proxy.ts +++ b/src/main/lens-proxy.ts @@ -3,27 +3,27 @@ import http from "http"; import spdy from "spdy"; import httpProxy from "http-proxy"; import url from "url"; -import * as WebSocket from "ws" -import { apiPrefix, apiKubePrefix } from "../common/vars" +import * as WebSocket from "ws"; +import { apiPrefix, apiKubePrefix } from "../common/vars"; import { openShell } from "./node-shell-session"; -import { Router } from "./router" -import { ClusterManager } from "./cluster-manager" +import { Router } from "./router"; +import { ClusterManager } from "./cluster-manager"; import { ContextHandler } from "./context-handler"; -import logger from "./logger" +import logger from "./logger"; export class LensProxy { - protected origin: string - protected proxyServer: http.Server - protected router: Router - protected closed = false - protected retryCounters = new Map() + protected origin: string; + protected proxyServer: http.Server; + protected router: Router; + protected closed = false; + protected retryCounters = new Map(); static create(port: number, clusterManager: ClusterManager) { return new LensProxy(port, clusterManager).listen(); } private constructor(protected port: number, protected clusterManager: ClusterManager) { - this.origin = `http://localhost:${port}` + this.origin = `http://localhost:${port}`; this.router = new Router(); } @@ -35,8 +35,8 @@ export class LensProxy { close() { logger.info("Closing proxy server"); - this.proxyServer.close() - this.closed = true + this.proxyServer.close(); + this.closed = true; } protected buildCustomProxy(): http.Server { @@ -47,66 +47,66 @@ export class LensProxy { protocols: ["http/1.1", "spdy/3.1"] } }, (req: http.IncomingMessage, res: http.ServerResponse) => { - this.handleRequest(proxy, req, res) - }) + this.handleRequest(proxy, req, res); + }); spdyProxy.on("upgrade", (req: http.IncomingMessage, socket: net.Socket, head: Buffer) => { if (req.url.startsWith(`${apiPrefix}?`)) { - this.handleWsUpgrade(req, socket, head) + this.handleWsUpgrade(req, socket, head); } else { - this.handleProxyUpgrade(proxy, req, socket, head) + this.handleProxyUpgrade(proxy, req, socket, head); } - }) + }); spdyProxy.on("error", (err) => { - logger.error("proxy error", err) - }) - return spdyProxy + logger.error("proxy error", err); + }); + return spdyProxy; } protected async handleProxyUpgrade(proxy: httpProxy, req: http.IncomingMessage, socket: net.Socket, head: Buffer) { - const cluster = this.clusterManager.getClusterForRequest(req) + const cluster = this.clusterManager.getClusterForRequest(req); if (cluster) { - const proxyUrl = await cluster.contextHandler.resolveAuthProxyUrl() + req.url.replace(apiKubePrefix, "") - const apiUrl = url.parse(cluster.apiUrl) - const pUrl = url.parse(proxyUrl) - const connectOpts = { port: parseInt(pUrl.port), host: pUrl.hostname } - const proxySocket = new net.Socket() + const proxyUrl = await cluster.contextHandler.resolveAuthProxyUrl() + req.url.replace(apiKubePrefix, ""); + const apiUrl = url.parse(cluster.apiUrl); + const pUrl = url.parse(proxyUrl); + const connectOpts = { port: parseInt(pUrl.port), host: pUrl.hostname }; + const proxySocket = new net.Socket(); proxySocket.connect(connectOpts, () => { - proxySocket.write(`${req.method} ${pUrl.path} HTTP/1.1\r\n`) - proxySocket.write(`Host: ${apiUrl.host}\r\n`) + proxySocket.write(`${req.method} ${pUrl.path} HTTP/1.1\r\n`); + proxySocket.write(`Host: ${apiUrl.host}\r\n`); for (let i = 0; i < req.rawHeaders.length; i += 2) { - const key = req.rawHeaders[i] + const key = req.rawHeaders[i]; if (key !== "Host" && key !== "Authorization") { - proxySocket.write(`${req.rawHeaders[i]}: ${req.rawHeaders[i+1]}\r\n`) + proxySocket.write(`${req.rawHeaders[i]}: ${req.rawHeaders[i+1]}\r\n`); } } - proxySocket.write("\r\n") - proxySocket.write(head) - }) + proxySocket.write("\r\n"); + proxySocket.write(head); + }); - proxySocket.setKeepAlive(true) - socket.setKeepAlive(true) - proxySocket.setTimeout(0) - socket.setTimeout(0) + proxySocket.setKeepAlive(true); + socket.setKeepAlive(true); + proxySocket.setTimeout(0); + socket.setTimeout(0); proxySocket.on('data', function (chunk) { - socket.write(chunk) - }) + socket.write(chunk); + }); proxySocket.on('end', function () { - socket.end() - }) + socket.end(); + }); proxySocket.on('error', function (err) { socket.write("HTTP/" + req.httpVersion + " 500 Connection error\r\n\r\n"); - socket.end() - }) + socket.end(); + }); socket.on('data', function (chunk) { - proxySocket.write(chunk) - }) + proxySocket.write(chunk); + }); socket.on('end', function () { - proxySocket.end() - }) + proxySocket.end(); + }); socket.on('error', function () { - proxySocket.end() - }) + proxySocket.end(); + }); } } @@ -120,29 +120,29 @@ export class LensProxy { logger.debug("Failed proxy to target: " + JSON.stringify(target, null, 2)); if (req.method === "GET" && (!res.statusCode || res.statusCode >= 500)) { const reqId = this.getRequestId(req); - const retryCount = this.retryCounters.get(reqId) || 0 - const timeoutMs = retryCount * 250 + const retryCount = this.retryCounters.get(reqId) || 0; + const timeoutMs = retryCount * 250; if (retryCount < 20) { - logger.debug(`Retrying proxy request to url: ${reqId}`) + logger.debug(`Retrying proxy request to url: ${reqId}`); setTimeout(() => { - this.retryCounters.set(reqId, retryCount + 1) - this.handleRequest(proxy, req, res) - }, timeoutMs) + this.retryCounters.set(reqId, retryCount + 1); + this.handleRequest(proxy, req, res); + }, timeoutMs); } } } try { - res.writeHead(500).end("Oops, something went wrong.") + res.writeHead(500).end("Oops, something went wrong."); } catch (e) { - logger.error(`[LENS-PROXY]: Failed to write headers: `, e) + logger.error(`[LENS-PROXY]: Failed to write headers: `, e); } - }) + }); return proxy; } protected createWsListener(): WebSocket.Server { - const ws = new WebSocket.Server({ noServer: true }) + const ws = new WebSocket.Server({ noServer: true }); return ws.on("connection", ((socket: WebSocket, req: http.IncomingMessage) => { const cluster = this.clusterManager.getClusterForRequest(req); const nodeParam = url.parse(req.url, true).query["node"]?.toString(); @@ -152,10 +152,10 @@ export class LensProxy { protected async getProxyTarget(req: http.IncomingMessage, contextHandler: ContextHandler): Promise { if (req.url.startsWith(apiKubePrefix)) { - delete req.headers.authorization - req.url = req.url.replace(apiKubePrefix, "") - const isWatchRequest = req.url.includes("watch=") - return await contextHandler.getApiTarget(isWatchRequest) + delete req.headers.authorization; + req.url = req.url.replace(apiKubePrefix, ""); + const isWatchRequest = req.url.includes("watch="); + return await contextHandler.getApiTarget(isWatchRequest); } } @@ -164,9 +164,9 @@ export class LensProxy { } protected async handleRequest(proxy: httpProxy, req: http.IncomingMessage, res: http.ServerResponse) { - const cluster = this.clusterManager.getClusterForRequest(req) + const cluster = this.clusterManager.getClusterForRequest(req); if (cluster) { - const proxyTarget = await this.getProxyTarget(req, cluster.contextHandler) + const proxyTarget = await this.getProxyTarget(req, cluster.contextHandler); if (proxyTarget) { // allow to fetch apis in "clusterId.localhost:port" from "localhost:port" res.setHeader("Access-Control-Allow-Origin", this.origin); diff --git a/src/main/logger.ts b/src/main/logger.ts index f4e2707c27..81d61e8002 100644 --- a/src/main/logger.ts +++ b/src/main/logger.ts @@ -1,13 +1,13 @@ import { app, remote } from "electron"; -import winston from "winston" +import winston from "winston"; import { isDebugging } from "../common/vars"; -const logLevel = process.env.LOG_LEVEL ? process.env.LOG_LEVEL : isDebugging ? "debug" : "info" +const logLevel = process.env.LOG_LEVEL ? process.env.LOG_LEVEL : isDebugging ? "debug" : "info"; const consoleOptions: winston.transports.ConsoleTransportOptions = { handleExceptions: false, level: logLevel, -} +}; const fileOptions: winston.transports.FileTransportOptions = { handleExceptions: false, @@ -17,7 +17,7 @@ const fileOptions: winston.transports.FileTransportOptions = { maxsize: 16 * 1024, maxFiles: 16, tailable: true, -} +}; const logger = winston.createLogger({ format: winston.format.combine( @@ -30,4 +30,4 @@ const logger = winston.createLogger({ ], }); -export default logger +export default logger; diff --git a/src/main/menu.ts b/src/main/menu.ts index 14525581b8..99a0d0bb55 100644 --- a/src/main/menu.ts +++ b/src/main/menu.ts @@ -1,4 +1,4 @@ -import { app, BrowserWindow, dialog, ipcMain, IpcMainEvent, Menu, MenuItem, MenuItemConstructorOptions, webContents, shell } from "electron" +import { app, BrowserWindow, dialog, ipcMain, IpcMainEvent, Menu, MenuItem, MenuItemConstructorOptions, webContents, shell } from "electron"; import { autorun } from "mobx"; import { WindowManager } from "./window-manager"; import { appName, isMac, isWindows, isTestEnv } from "../common/vars"; @@ -11,7 +11,7 @@ import { menuRegistry } from "../extensions/registries/menu-registry"; import logger from "./logger"; import { exitApp } from "./exit-app"; -export type MenuTopId = "mac" | "file" | "edit" | "view" | "help" +export type MenuTopId = "mac" | "file" | "edit" | "view" | "help"; export function initMenu(windowManager: WindowManager) { return autorun(() => buildMenu(windowManager), { @@ -25,14 +25,14 @@ export function showAbout(browserWindow: BrowserWindow) { `Electron: ${process.versions.electron}`, `Chrome: ${process.versions.chrome}`, `Copyright 2020 Mirantis, Inc.`, - ] + ]; dialog.showMessageBoxSync(browserWindow, { title: `${isWindows ? " ".repeat(2) : ""}${appName}`, type: "info", buttons: ["Close"], message: `Lens`, detail: appInfo.join("\r\n") - }) + }); } export function buildMenu(windowManager: WindowManager) { @@ -44,7 +44,7 @@ export function buildMenu(windowManager: WindowManager) { function activeClusterOnly(menuItems: MenuItemConstructorOptions[]) { if (!windowManager.activeClusterId) { menuItems.forEach(item => { - item.enabled = false + item.enabled = false; }); } return menuItems; @@ -61,7 +61,7 @@ export function buildMenu(windowManager: WindowManager) { { label: "About Lens", click(menuItem: MenuItem, browserWindow: BrowserWindow) { - showAbout(browserWindow) + showAbout(browserWindow); } }, { type: 'separator' }, @@ -69,14 +69,14 @@ export function buildMenu(windowManager: WindowManager) { label: 'Preferences', accelerator: 'CmdOrCtrl+,', click() { - navigate(preferencesURL()) + navigate(preferencesURL()); } }, { label: 'Extensions', accelerator: 'CmdOrCtrl+Shift+E', click() { - navigate(extensionsURL()) + navigate(extensionsURL()); } }, { type: 'separator' }, @@ -90,7 +90,7 @@ export function buildMenu(windowManager: WindowManager) { label: 'Quit', accelerator: 'Cmd+Q', click() { - exitApp() + exitApp(); } } ] @@ -103,7 +103,7 @@ export function buildMenu(windowManager: WindowManager) { label: 'Add Cluster', accelerator: 'CmdOrCtrl+Shift+A', click() { - navigate(addClusterURL()) + navigate(addClusterURL()); } }, ...activeClusterOnly([ @@ -115,7 +115,7 @@ export function buildMenu(windowManager: WindowManager) { params: { clusterId: windowManager.activeClusterId } - })) + })); } } ]), @@ -125,14 +125,14 @@ export function buildMenu(windowManager: WindowManager) { label: 'Preferences', accelerator: 'Ctrl+,', click() { - navigate(preferencesURL()) + navigate(preferencesURL()); } }, { label: 'Extensions', accelerator: 'Ctrl+Shift+E', click() { - navigate(extensionsURL()) + navigate(extensionsURL()); } } ]), @@ -147,7 +147,7 @@ export function buildMenu(windowManager: WindowManager) { label: 'Exit', accelerator: 'Alt+F4', click() { - exitApp() + exitApp(); } } ]) @@ -183,7 +183,7 @@ export function buildMenu(windowManager: WindowManager) { label: 'Forward', accelerator: 'CmdOrCtrl+]', click() { - webContents.getFocusedWebContents()?.goForward() + webContents.getFocusedWebContents()?.goForward(); } }, { @@ -209,7 +209,7 @@ export function buildMenu(windowManager: WindowManager) { { label: "What's new?", click() { - navigate(whatsNewURL()) + navigate(whatsNewURL()); }, }, { @@ -222,7 +222,7 @@ export function buildMenu(windowManager: WindowManager) { { label: "About Lens", click(menuItem: MenuItem, browserWindow: BrowserWindow) { - showAbout(browserWindow) + showAbout(browserWindow); } } ]) @@ -236,7 +236,7 @@ export function buildMenu(windowManager: WindowManager) { edit: editMenu, view: viewMenu, help: helpMenu, - } + }; // Modify menu from extensions-api menuRegistry.getItems().forEach(({ parentId, ...menuItem }) => { @@ -244,12 +244,12 @@ export function buildMenu(windowManager: WindowManager) { const topMenu = appMenu[parentId as MenuTopId].submenu as MenuItemConstructorOptions[]; topMenu.push(menuItem); } catch (err) { - logger.error(`[MENU]: can't register menu item, parentId=${parentId}`, { menuItem }) + logger.error(`[MENU]: can't register menu item, parentId=${parentId}`, { menuItem }); } - }) + }); if (!isMac) { - delete appMenu.mac + delete appMenu.mac; } const menu = Menu.buildFromTemplate(Object.values(appMenu)); @@ -259,9 +259,9 @@ export function buildMenu(windowManager: WindowManager) { // this is a workaround for the test environment (spectron) not being able to directly access // the application menus (https://github.com/electron-userland/spectron/issues/21) ipcMain.on('test-menu-item-click', (event: IpcMainEvent, ...names: string[]) => { - let menu: Menu = Menu.getApplicationMenu() + let menu: Menu = Menu.getApplicationMenu(); const parentLabels: string[] = []; - let menuItem: MenuItem + let menuItem: MenuItem; for (const name of names) { parentLabels.push(name); @@ -272,7 +272,7 @@ export function buildMenu(windowManager: WindowManager) { menu = menuItem.submenu; } - const menuPath: string = parentLabels.join(" -> ") + const menuPath: string = parentLabels.join(" -> "); if (!menuItem) { logger.info(`[MENU:test-menu-item-click] Cannot find menu item ${menuPath}`); return; diff --git a/src/main/node-shell-session.ts b/src/main/node-shell-session.ts index 9e97398327..3d48afebc5 100644 --- a/src/main/node-shell-session.ts +++ b/src/main/node-shell-session.ts @@ -1,36 +1,36 @@ -import * as WebSocket from "ws" -import * as pty from "node-pty" +import * as WebSocket from "ws"; +import * as pty from "node-pty"; import { ShellSession } from "./shell-session"; -import { v4 as uuid } from "uuid" -import * as k8s from "@kubernetes/client-node" -import { KubeConfig } from "@kubernetes/client-node" -import { Cluster } from "./cluster" +import { v4 as uuid } from "uuid"; +import * as k8s from "@kubernetes/client-node"; +import { KubeConfig } from "@kubernetes/client-node"; +import { Cluster } from "./cluster"; import logger from "./logger"; -import { appEventBus } from "../common/event-bus" +import { appEventBus } from "../common/event-bus"; export class NodeShellSession extends ShellSession { protected nodeName: string; - protected podId: string - protected kc: KubeConfig + protected podId: string; + protected kc: KubeConfig; constructor(socket: WebSocket, cluster: Cluster, nodeName: string) { - super(socket, cluster) - this.nodeName = nodeName - this.podId = `node-shell-${uuid()}` - this.kc = cluster.getProxyKubeconfig() + super(socket, cluster); + this.nodeName = nodeName; + this.podId = `node-shell-${uuid()}`; + this.kc = cluster.getProxyKubeconfig(); } public async open() { - const shell = await this.kubectl.getPath() - let args = [] + const shell = await this.kubectl.getPath(); + let args = []; if (this.createNodeShellPod(this.podId, this.nodeName)) { await this.waitForRunningPod(this.podId).catch((error) => { - this.exit(1001) - }) + this.exit(1001); + }); } - args = ["exec", "-i", "-t", "-n", "kube-system", this.podId, "--", "sh", "-c", "((clear && bash) || (clear && ash) || (clear && sh))"] + args = ["exec", "-i", "-t", "-n", "kube-system", this.podId, "--", "sh", "-c", "((clear && bash) || (clear && ash) || (clear && sh))"]; - const shellEnv = await this.getCachedShellEnv() + const shellEnv = await this.getCachedShellEnv(); this.shellProcess = pty.spawn(shell, args, { cols: 80, cwd: this.cwd() || shellEnv["HOME"], @@ -39,19 +39,19 @@ export class NodeShellSession extends ShellSession { rows: 30, }); this.running = true; - this.pipeStdout() - this.pipeStdin() - this.closeWebsocketOnProcessExit() - this.exitProcessOnWebsocketClose() + this.pipeStdout(); + this.pipeStdin(); + this.closeWebsocketOnProcessExit(); + this.exitProcessOnWebsocketClose(); - appEventBus.emit({name: "node-shell", action: "open"}) + appEventBus.emit({name: "node-shell", action: "open"}); } protected exit(code = 1000) { if (this.podId) { - this.deleteNodeShellPod() + this.deleteNodeShellPod(); } - super.exit(code) + super.exit(code); } protected async createNodeShellPod(podId: string, nodeName: string) { @@ -86,19 +86,19 @@ export class NodeShellSession extends ShellSession { } } as k8s.V1Pod; await k8sApi.createNamespacedPod("kube-system", pod).catch((error) => { - logger.error(error) - return false - }) - return true + logger.error(error); + return false; + }); + return true; } protected getKubeConfig() { if (this.kc) { - return this.kc + return this.kc; } this.kc = new k8s.KubeConfig(); - this.kc.loadFromFile(this.kubeconfigPath) - return this.kc + this.kc.loadFromFile(this.kubeconfigPath); + return this.kc; } protected waitForRunningPod(podId: string) { @@ -110,36 +110,36 @@ export class NodeShellSession extends ShellSession { // callback is called for each received object. (_type, obj) => { if (obj.metadata.name == podId && obj.status.phase === "Running") { - resolve(true) + resolve(true); } }, // done callback is called if the watch terminates normally (err) => { - logger.error(err) - reject(false) + logger.error(err); + reject(false); } ); setTimeout(() => { req.abort(); reject(false); }, 120 * 1000); - }) + }); } protected deleteNodeShellPod() { const kc = this.getKubeConfig(); const k8sApi = kc.makeApiClient(k8s.CoreV1Api); - k8sApi.deleteNamespacedPod(this.podId, "kube-system") + k8sApi.deleteNamespacedPod(this.podId, "kube-system"); } } export async function openShell(socket: WebSocket, cluster: Cluster, nodeName?: string): Promise { let shell: ShellSession; if (nodeName) { - shell = new NodeShellSession(socket, cluster, nodeName) + shell = new NodeShellSession(socket, cluster, nodeName); } else { shell = new ShellSession(socket, cluster); } - shell.open() + shell.open(); return shell; } diff --git a/src/main/port.ts b/src/main/port.ts index b253d3590a..6ba8f71695 100644 --- a/src/main/port.ts +++ b/src/main/port.ts @@ -1,15 +1,15 @@ -import net, { AddressInfo } from "net" -import logger from "./logger" +import net, { AddressInfo } from "net"; +import logger from "./logger"; // todo: check https://github.com/http-party/node-portfinder ? export async function getFreePort(): Promise { logger.debug("Lookup new free port.."); return new Promise((resolve, reject) => { - const server = net.createServer() - server.unref() + const server = net.createServer(); + server.unref(); server.on("listening", () => { - const port = (server.address() as AddressInfo).port + const port = (server.address() as AddressInfo).port; server.close(() => resolve(port)); logger.debug(`New port found: ${port}`); }); @@ -17,6 +17,6 @@ export async function getFreePort(): Promise { logger.error(`Can't resolve new port: "${error}"`); reject(error); }); - server.listen({ host: "127.0.0.1", port: 0 }) - }) + server.listen({ host: "127.0.0.1", port: 0 }); + }); } diff --git a/src/main/port_spec.ts b/src/main/port_spec.ts index c9be25e514..bf01eb5dde 100644 --- a/src/main/port_spec.ts +++ b/src/main/port_spec.ts @@ -1,5 +1,5 @@ -import { EventEmitter } from 'events' -import { getFreePort } from "./port" +import { EventEmitter } from 'events'; +import { getFreePort } from "./port"; let newPort = 0; @@ -8,24 +8,24 @@ jest.mock("net", () => { createServer() { return new class MockServer extends EventEmitter { listen = jest.fn(() => { - this.emit('listening') - return this - }) + this.emit('listening'); + return this; + }); address = () => { - newPort = Math.round(Math.random() * 10000) + newPort = Math.round(Math.random() * 10000); return { port: newPort - } - } - unref = jest.fn() - close = jest.fn(cb => cb()) - } + }; + }; + unref = jest.fn(); + close = jest.fn(cb => cb()); + }; }, - } + }; }); describe("getFreePort", () => { it("finds the next free port", async () => { return expect(getFreePort()).resolves.toEqual(newPort); - }) -}) + }); +}); diff --git a/src/main/prometheus/helm.ts b/src/main/prometheus/helm.ts index f1462931df..56d739c630 100644 --- a/src/main/prometheus/helm.ts +++ b/src/main/prometheus/helm.ts @@ -1,29 +1,29 @@ -import { PrometheusLens } from "./lens" -import { CoreV1Api } from "@kubernetes/client-node" +import { PrometheusLens } from "./lens"; +import { CoreV1Api } from "@kubernetes/client-node"; import { PrometheusService } from "./provider-registry"; -import logger from "../logger" +import logger from "../logger"; export class PrometheusHelm extends PrometheusLens { - id = "helm" - name = "Helm" - rateAccuracy = "5m" + id = "helm"; + name = "Helm"; + rateAccuracy = "5m"; public async getPrometheusService(client: CoreV1Api): Promise { - const labelSelector = "app=prometheus,component=server,heritage=Helm" + const labelSelector = "app=prometheus,component=server,heritage=Helm"; try { - const serviceList = await client.listServiceForAllNamespaces(false, "", null, labelSelector) - const service = serviceList.body.items[0] - if (!service) return + const serviceList = await client.listServiceForAllNamespaces(false, "", null, labelSelector); + const service = serviceList.body.items[0]; + if (!service) return; return { id: this.id, namespace: service.metadata.namespace, service: service.metadata.name, port: service.spec.ports[0].port - } + }; } catch(error) { - logger.warn(`PrometheusHelm: failed to list services: ${error.toString()}`) - return + logger.warn(`PrometheusHelm: failed to list services: ${error.toString()}`); + return; } } } diff --git a/src/main/prometheus/lens.ts b/src/main/prometheus/lens.ts index 4db70bf45d..76a459212d 100644 --- a/src/main/prometheus/lens.ts +++ b/src/main/prometheus/lens.ts @@ -1,24 +1,24 @@ import { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry"; import { CoreV1Api } from "@kubernetes/client-node"; -import logger from "../logger" +import logger from "../logger"; export class PrometheusLens implements PrometheusProvider { - id = "lens" - name = "Lens" - rateAccuracy = "1m" + id = "lens"; + name = "Lens"; + rateAccuracy = "1m"; public async getPrometheusService(client: CoreV1Api): Promise { try { - const resp = await client.readNamespacedService("prometheus", "lens-metrics") - const service = resp.body + const resp = await client.readNamespacedService("prometheus", "lens-metrics"); + const service = resp.body; return { id: this.id, namespace: service.metadata.namespace, service: service.metadata.name, port: service.spec.ports[0].port - } + }; } catch(error) { - logger.warn(`PrometheusLens: failed to list services: ${error.response.body.message}`) + logger.warn(`PrometheusLens: failed to list services: ${error.response.body.message}`); } } @@ -42,7 +42,7 @@ export class PrometheusLens implements PrometheusProvider { podCapacity: `sum(kube_node_status_capacity{node=~"${opts.nodes}", resource="pods"}) by (component)`, fsSize: `sum(node_filesystem_size_bytes{kubernetes_node=~"${opts.nodes}", mountpoint="/"}) by (kubernetes_node)`, fsUsage: `sum(node_filesystem_size_bytes{kubernetes_node=~"${opts.nodes}", mountpoint="/"} - node_filesystem_avail_bytes{kubernetes_node=~"${opts.nodes}", mountpoint="/"}) by (kubernetes_node)` - } + }; case 'nodes': return { memoryUsage: `sum (node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) by (kubernetes_node)`, @@ -51,7 +51,7 @@ export class PrometheusLens implements PrometheusProvider { cpuCapacity: `sum(kube_node_status_allocatable{resource="cpu"}) by (node)`, fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"}) by (kubernetes_node)`, fsUsage: `sum(node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) by (kubernetes_node)` - } + }; case 'pods': return { cpuUsage: `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, @@ -63,21 +63,21 @@ export class PrometheusLens implements PrometheusProvider { fsUsage: `sum(container_fs_usage_bytes{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}) by (${opts.selector})`, networkReceive: `sum(rate(container_network_receive_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, networkTransmit: `sum(rate(container_network_transmit_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})` - } + }; case 'pvc': return { diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`, diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)` - } + }; case 'ingress': const bytesSent = (ingress: string, statuses: string) => - `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)` + `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`; return { bytesSentSuccess: bytesSent(opts.igress, "^2\\\\d*"), bytesSentFailure: bytesSent(opts.ingres, "^5\\\\d*"), requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`, responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)` - } + }; } } } diff --git a/src/main/prometheus/operator.ts b/src/main/prometheus/operator.ts index 3d335ff554..8e27a4a6f3 100644 --- a/src/main/prometheus/operator.ts +++ b/src/main/prometheus/operator.ts @@ -3,30 +3,30 @@ import { CoreV1Api, V1Service } from "@kubernetes/client-node"; import logger from "../logger"; export class PrometheusOperator implements PrometheusProvider { - rateAccuracy = "1m" - id = "operator" - name = "Prometheus Operator" + rateAccuracy = "1m"; + id = "operator"; + name = "Prometheus Operator"; public async getPrometheusService(client: CoreV1Api): Promise { try { - let service: V1Service + let service: V1Service; for (const labelSelector of ["operated-prometheus=true", "self-monitor=true"]) { if (!service) { - const serviceList = await client.listServiceForAllNamespaces(null, null, null, labelSelector) - service = serviceList.body.items[0] + const serviceList = await client.listServiceForAllNamespaces(null, null, null, labelSelector); + service = serviceList.body.items[0]; } } - if (!service) return + if (!service) return; return { id: this.id, namespace: service.metadata.namespace, service: service.metadata.name, port: service.spec.ports[0].port - } + }; } catch(error) { - logger.warn(`PrometheusOperator: failed to list services: ${error.toString()}`) - return + logger.warn(`PrometheusOperator: failed to list services: ${error.toString()}`); + return; } } @@ -50,7 +50,7 @@ export class PrometheusOperator implements PrometheusProvider { podCapacity: `sum(kube_node_status_capacity{node=~"${opts.nodes}", resource="pods"})`, fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"})`, fsUsage: `sum(node_filesystem_size_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"} - node_filesystem_avail_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info{node=~"${opts.nodes}"})` - } + }; case 'nodes': return { memoryUsage: `sum((node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) * on (pod,namespace) group_left(node) kube_pod_info) by (node)`, @@ -59,7 +59,7 @@ export class PrometheusOperator implements PrometheusProvider { cpuCapacity: `sum(kube_node_status_allocatable{resource="cpu"}) by (node)`, fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"} * on (pod,namespace) group_left(node) kube_pod_info) by (node)`, fsUsage: `sum((node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) * on (pod,namespace) group_left(node) kube_pod_info) by (node)` - } + }; case 'pods': return { cpuUsage: `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",image!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, @@ -71,12 +71,12 @@ export class PrometheusOperator implements PrometheusProvider { fsUsage: `sum(container_fs_usage_bytes{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}) by (${opts.selector})`, networkReceive: `sum(rate(container_network_receive_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, networkTransmit: `sum(rate(container_network_transmit_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})` - } + }; case 'pvc': return { diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`, diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)` - } + }; case 'ingress': const bytesSent = (ingress: string, statuses: string) => `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`; @@ -85,7 +85,7 @@ export class PrometheusOperator implements PrometheusProvider { bytesSentFailure: bytesSent(opts.ingres, "^5\\\\d*"), requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`, responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)` - } + }; } } } diff --git a/src/main/prometheus/provider-registry.ts b/src/main/prometheus/provider-registry.ts index 0a4eb22e95..641b1b8cf2 100644 --- a/src/main/prometheus/provider-registry.ts +++ b/src/main/prometheus/provider-registry.ts @@ -1,4 +1,4 @@ -import { CoreV1Api } from "@kubernetes/client-node" +import { CoreV1Api } from "@kubernetes/client-node"; export type PrometheusClusterQuery = { memoryUsage: string; @@ -11,7 +11,7 @@ export type PrometheusClusterQuery = { cpuCapacity: string; podUsage: string; podCapacity: string; -} +}; export type PrometheusNodeQuery = { memoryUsage: string; @@ -20,7 +20,7 @@ export type PrometheusNodeQuery = { cpuCapacity: string; fsSize: string; fsUsage: string; -} +}; export type PrometheusPodQuery = { memoryUsage: string; @@ -32,32 +32,32 @@ export type PrometheusPodQuery = { fsUsage: string; networkReceive: string; networkTransmit: string; -} +}; export type PrometheusPvcQuery = { diskUsage: string; diskCapacity: string; -} +}; export type PrometheusIngressQuery = { bytesSentSuccess: string; bytesSentFailure: string; requestDurationSeconds: string; responseDurationSeconds: string; -} +}; export type PrometheusQueryOpts = { [key: string]: string | any; }; -export type PrometheusQuery = PrometheusNodeQuery | PrometheusClusterQuery | PrometheusPodQuery | PrometheusPvcQuery | PrometheusIngressQuery +export type PrometheusQuery = PrometheusNodeQuery | PrometheusClusterQuery | PrometheusPodQuery | PrometheusPvcQuery | PrometheusIngressQuery; export type PrometheusService = { id: string; namespace: string; service: string; port: number; -} +}; export interface PrometheusProvider { id: string; @@ -68,23 +68,23 @@ export interface PrometheusProvider { export type PrometheusProviderList = { [key: string]: PrometheusProvider; -} +}; export class PrometheusProviderRegistry { - private static prometheusProviders: PrometheusProviderList = {} + private static prometheusProviders: PrometheusProviderList = {}; static getProvider(type: string): PrometheusProvider { if (!this.prometheusProviders[type]) { throw "Unknown Prometheus provider"; } - return this.prometheusProviders[type] + return this.prometheusProviders[type]; } static registerProvider(key: string, provider: PrometheusProvider) { - this.prometheusProviders[key] = provider + this.prometheusProviders[key] = provider; } static getProviders(): PrometheusProvider[] { - return Object.values(this.prometheusProviders) + return Object.values(this.prometheusProviders); } } diff --git a/src/main/prometheus/stacklight.ts b/src/main/prometheus/stacklight.ts index 4cb946c81d..35394336d3 100644 --- a/src/main/prometheus/stacklight.ts +++ b/src/main/prometheus/stacklight.ts @@ -1,24 +1,24 @@ import { PrometheusProvider, PrometheusQueryOpts, PrometheusQuery, PrometheusService } from "./provider-registry"; import { CoreV1Api } from "@kubernetes/client-node"; -import logger from "../logger" +import logger from "../logger"; export class PrometheusStacklight implements PrometheusProvider { - id = "stacklight" - name = "Stacklight" - rateAccuracy = "1m" + id = "stacklight"; + name = "Stacklight"; + rateAccuracy = "1m"; public async getPrometheusService(client: CoreV1Api): Promise { try { - const resp = await client.readNamespacedService("prometheus-server", "stacklight") - const service = resp.body + const resp = await client.readNamespacedService("prometheus-server", "stacklight"); + const service = resp.body; return { id: this.id, namespace: service.metadata.namespace, service: service.metadata.name, port: service.spec.ports[0].port - } + }; } catch(error) { - logger.warn(`PrometheusLens: failed to list services: ${error.response.body.message}`) + logger.warn(`PrometheusLens: failed to list services: ${error.response.body.message}`); } } @@ -42,7 +42,7 @@ export class PrometheusStacklight implements PrometheusProvider { podCapacity: `sum(kube_node_status_capacity{node=~"${opts.nodes}", resource="pods"}) by (component)`, fsSize: `sum(node_filesystem_size_bytes{node=~"${opts.nodes}", mountpoint="/"}) by (node)`, fsUsage: `sum(node_filesystem_size_bytes{node=~"${opts.nodes}", mountpoint="/"} - node_filesystem_avail_bytes{node=~"${opts.nodes}", mountpoint="/"}) by (node)` - } + }; case 'nodes': return { memoryUsage: `sum (node_memory_MemTotal_bytes - (node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes)) by (node)`, @@ -51,7 +51,7 @@ export class PrometheusStacklight implements PrometheusProvider { cpuCapacity: `sum(kube_node_status_allocatable{resource="cpu"}) by (node)`, fsSize: `sum(node_filesystem_size_bytes{mountpoint="/"}) by (node)`, fsUsage: `sum(node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) by (node)` - } + }; case 'pods': return { cpuUsage: `sum(rate(container_cpu_usage_seconds_total{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, @@ -63,21 +63,21 @@ export class PrometheusStacklight implements PrometheusProvider { fsUsage: `sum(container_fs_usage_bytes{container!="POD",container!="",pod=~"${opts.pods}",namespace="${opts.namespace}"}) by (${opts.selector})`, networkReceive: `sum(rate(container_network_receive_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})`, networkTransmit: `sum(rate(container_network_transmit_bytes_total{pod=~"${opts.pods}",namespace="${opts.namespace}"}[${this.rateAccuracy}])) by (${opts.selector})` - } + }; case 'pvc': return { diskUsage: `sum(kubelet_volume_stats_used_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)`, diskCapacity: `sum(kubelet_volume_stats_capacity_bytes{persistentvolumeclaim="${opts.pvc}"}) by (persistentvolumeclaim, namespace)` - } + }; case 'ingress': const bytesSent = (ingress: string, statuses: string) => - `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)` + `sum(rate(nginx_ingress_controller_bytes_sent_sum{ingress="${ingress}", status=~"${statuses}"}[${this.rateAccuracy}])) by (ingress)`; return { bytesSentSuccess: bytesSent(opts.igress, "^2\\\\d*"), bytesSentFailure: bytesSent(opts.ingres, "^5\\\\d*"), requestDurationSeconds: `sum(rate(nginx_ingress_controller_request_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)`, responseDurationSeconds: `sum(rate(nginx_ingress_controller_response_duration_seconds_sum{ingress="${opts.ingress}"}[${this.rateAccuracy}])) by (ingress)` - } + }; } } } diff --git a/src/main/promise-exec.ts b/src/main/promise-exec.ts index b3bc303165..426bca4c23 100644 --- a/src/main/promise-exec.ts +++ b/src/main/promise-exec.ts @@ -1,4 +1,4 @@ -import * as util from "util" +import * as util from "util"; import { exec } from "child_process"; -export const promiseExec = util.promisify(exec) +export const promiseExec = util.promisify(exec); diff --git a/src/main/proxy-env.ts b/src/main/proxy-env.ts index 04c62ef534..51c8286a7f 100644 --- a/src/main/proxy-env.ts +++ b/src/main/proxy-env.ts @@ -1,18 +1,18 @@ -import { app } from "electron" +import { app } from "electron"; -const switchValue = app.commandLine.getSwitchValue("proxy-server") +const switchValue = app.commandLine.getSwitchValue("proxy-server"); export function mangleProxyEnv() { - let httpsProxy = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || "" + let httpsProxy = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || ""; - delete process.env.HTTPS_PROXY - delete process.env.HTTP_PROXY + delete process.env.HTTPS_PROXY; + delete process.env.HTTP_PROXY; if (switchValue !== "") { - httpsProxy = switchValue + httpsProxy = switchValue; } if (httpsProxy !== "") { - process.env.APP_HTTPS_PROXY = httpsProxy + process.env.APP_HTTPS_PROXY = httpsProxy; } } diff --git a/src/main/resource-applier.ts b/src/main/resource-applier.ts index 41441a3f90..0f4647a60f 100644 --- a/src/main/resource-applier.ts +++ b/src/main/resource-applier.ts @@ -1,12 +1,12 @@ import type { Cluster } from "./cluster"; -import { KubernetesObject } from "@kubernetes/client-node" +import { KubernetesObject } from "@kubernetes/client-node"; import { exec } from "child_process"; import fs from "fs"; import * as yaml from "js-yaml"; import path from "path"; import * as tempy from "tempy"; -import logger from "./logger" -import { appEventBus } from "../common/event-bus" +import logger from "./logger"; +import { appEventBus } from "../common/event-bus"; import { cloneJsonObject } from "../common/utils"; export class ResourceApplier { @@ -15,58 +15,58 @@ export class ResourceApplier { async apply(resource: KubernetesObject | any): Promise { resource = this.sanitizeObject(resource); - appEventBus.emit({name: "resource", action: "apply"}) + appEventBus.emit({name: "resource", action: "apply"}); return await this.kubectlApply(yaml.safeDump(resource)); } protected async kubectlApply(content: string): Promise { const { kubeCtl } = this.cluster; - const kubectlPath = await kubeCtl.getPath() + const kubectlPath = await kubeCtl.getPath(); return new Promise((resolve, reject) => { - const fileName = tempy.file({ name: "resource.yaml" }) - fs.writeFileSync(fileName, content) - const cmd = `"${kubectlPath}" apply --kubeconfig "${this.cluster.getProxyKubeconfigPath()}" -o json -f "${fileName}"` + const fileName = tempy.file({ name: "resource.yaml" }); + fs.writeFileSync(fileName, content); + const cmd = `"${kubectlPath}" apply --kubeconfig "${this.cluster.getProxyKubeconfigPath()}" -o json -f "${fileName}"`; logger.debug("shooting manifests with: " + cmd); - const execEnv: NodeJS.ProcessEnv = Object.assign({}, process.env) - const httpsProxy = this.cluster.preferences?.httpsProxy + const execEnv: NodeJS.ProcessEnv = Object.assign({}, process.env); + const httpsProxy = this.cluster.preferences?.httpsProxy; if (httpsProxy) { - execEnv["HTTPS_PROXY"] = httpsProxy + execEnv["HTTPS_PROXY"] = httpsProxy; } exec(cmd, { env: execEnv }, (error, stdout, stderr) => { if (stderr != "") { - fs.unlinkSync(fileName) - reject(stderr) - return + fs.unlinkSync(fileName); + reject(stderr); + return; } - fs.unlinkSync(fileName) - resolve(JSON.parse(stdout)) - }) - }) + fs.unlinkSync(fileName); + resolve(JSON.parse(stdout)); + }); + }); } public async kubectlApplyAll(resources: string[]): Promise { const { kubeCtl } = this.cluster; - const kubectlPath = await kubeCtl.getPath() + const kubectlPath = await kubeCtl.getPath(); return new Promise((resolve, reject) => { - const tmpDir = tempy.directory() + const tmpDir = tempy.directory(); // Dump each resource into tmpDir resources.forEach((resource, index) => { fs.writeFileSync(path.join(tmpDir, `${index}.yaml`), resource); - }) - const cmd = `"${kubectlPath}" apply --kubeconfig "${this.cluster.getProxyKubeconfigPath()}" -o json -f "${tmpDir}"` + }); + const cmd = `"${kubectlPath}" apply --kubeconfig "${this.cluster.getProxyKubeconfigPath()}" -o json -f "${tmpDir}"`; console.log("shooting manifests with:", cmd); exec(cmd, (error, stdout, stderr) => { if (error) { reject("Error applying manifests:" + error); } if (stderr != "") { - reject(stderr) - return + reject(stderr); + return; } - resolve(stdout) - }) - }) + resolve(stdout); + }); + }); } protected sanitizeObject(resource: KubernetesObject | any) { diff --git a/src/main/router.ts b/src/main/router.ts index 230c93f09e..ed072836b9 100644 --- a/src/main/router.ts +++ b/src/main/router.ts @@ -1,12 +1,12 @@ -import Call from "@hapi/call" -import Subtext from "@hapi/subtext" -import http from "http" -import path from "path" -import { readFile } from "fs-extra" -import { Cluster } from "./cluster" +import Call from "@hapi/call"; +import Subtext from "@hapi/subtext"; +import http from "http"; +import path from "path"; +import { readFile } from "fs-extra"; +import { Cluster } from "./cluster"; import { apiPrefix, appName, publicPath, isDevelopment, webpackDevServerPort } from "../common/vars"; import { helmRoute, kubeconfigRoute, metricsRoute, portForwardRoute, resourceApplierRoute, watchRoute } from "./routes"; -import logger from "./logger" +import logger from "./logger"; export interface RouterRequestOpts { req: http.IncomingMessage; @@ -43,25 +43,25 @@ export class Router { public constructor() { this.router = new Call.Router(); - this.addRoutes() + this.addRoutes(); } public async route(cluster: Cluster, req: http.IncomingMessage, res: http.ServerResponse): Promise { const url = new URL(req.url, "http://localhost"); - const path = url.pathname - const method = req.method.toLowerCase() + const path = url.pathname; + const method = req.method.toLowerCase(); const matchingRoute = this.router.route(method, path); const routeFound = !matchingRoute.isBoom; if (routeFound) { const request = await this.getRequest({ req, res, cluster, url, params: matchingRoute.params }); - await matchingRoute.route(request) - return true + await matchingRoute.route(request); + return true; } return false; } protected async getRequest(opts: RouterRequestOpts): Promise { - const { req, res, url, cluster, params } = opts + const { req, res, url, cluster, params } = opts; const { payload } = await Subtext.parse(req, null, { parse: true, output: "data", @@ -76,7 +76,7 @@ export class Router { query: url.searchParams, payload: payload, params: params - } + }; } protected getMimeType(filename: string) { @@ -92,7 +92,7 @@ export class Router { woff2: "font/woff2", ttf: "font/ttf" }; - return mimeTypes[path.extname(filename).slice(1)] || "text/plain" + return mimeTypes[path.extname(filename).slice(1)] || "text/plain"; } async handleStaticFile(filePath: string, res: http.ServerResponse, req: http.IncomingMessage, retryCount = 0) { @@ -114,10 +114,10 @@ export class Router { res.end(); } catch (err) { if (retryCount > 5) { - logger.error("handleStaticFile:", err.toString()) - res.statusCode = 404 - res.end() - return + logger.error("handleStaticFile:", err.toString()); + res.statusCode = 404; + res.end(); + return; } this.handleStaticFile(`${publicPath}/${appName}.html`, res, req, Math.max(retryCount, 0) + 1); } @@ -131,32 +131,32 @@ export class Router { this.handleStaticFile(params.path, response, req); }); - this.router.add({ method: "get", path: `${apiPrefix}/kubeconfig/service-account/{namespace}/{account}` }, kubeconfigRoute.routeServiceAccountRoute.bind(kubeconfigRoute)) + this.router.add({ method: "get", path: `${apiPrefix}/kubeconfig/service-account/{namespace}/{account}` }, kubeconfigRoute.routeServiceAccountRoute.bind(kubeconfigRoute)); // Watch API - this.router.add({ method: "get", path: `${apiPrefix}/watch` }, watchRoute.routeWatch.bind(watchRoute)) + this.router.add({ method: "get", path: `${apiPrefix}/watch` }, watchRoute.routeWatch.bind(watchRoute)); // Metrics API - this.router.add({ method: "post", path: `${apiPrefix}/metrics` }, metricsRoute.routeMetrics.bind(metricsRoute)) + this.router.add({ method: "post", path: `${apiPrefix}/metrics` }, metricsRoute.routeMetrics.bind(metricsRoute)); // Port-forward API - this.router.add({ method: "post", path: `${apiPrefix}/pods/{namespace}/{resourceType}/{resourceName}/port-forward/{port}` }, portForwardRoute.routePortForward.bind(portForwardRoute)) + this.router.add({ method: "post", path: `${apiPrefix}/pods/{namespace}/{resourceType}/{resourceName}/port-forward/{port}` }, portForwardRoute.routePortForward.bind(portForwardRoute)); // Helm API - this.router.add({ method: "get", path: `${apiPrefix}/v2/charts` }, helmRoute.listCharts.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}` }, helmRoute.getChart.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}/values` }, helmRoute.getChartValues.bind(helmRoute)) + this.router.add({ method: "get", path: `${apiPrefix}/v2/charts` }, helmRoute.listCharts.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}` }, helmRoute.getChart.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/charts/{repo}/{chart}/values` }, helmRoute.getChartValues.bind(helmRoute)); - this.router.add({ method: "post", path: `${apiPrefix}/v2/releases` }, helmRoute.installChart.bind(helmRoute)) - this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.updateRelease.bind(helmRoute)) - this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}/rollback` }, helmRoute.rollbackRelease.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace?}` }, helmRoute.listReleases.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.getRelease.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/values` }, helmRoute.getReleaseValues.bind(helmRoute)) - this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/history` }, helmRoute.getReleaseHistory.bind(helmRoute)) - this.router.add({ method: "delete", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.deleteRelease.bind(helmRoute)) + this.router.add({ method: "post", path: `${apiPrefix}/v2/releases` }, helmRoute.installChart.bind(helmRoute)); + this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.updateRelease.bind(helmRoute)); + this.router.add({ method: `put`, path: `${apiPrefix}/v2/releases/{namespace}/{release}/rollback` }, helmRoute.rollbackRelease.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace?}` }, helmRoute.listReleases.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.getRelease.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/values` }, helmRoute.getReleaseValues.bind(helmRoute)); + this.router.add({ method: "get", path: `${apiPrefix}/v2/releases/{namespace}/{release}/history` }, helmRoute.getReleaseHistory.bind(helmRoute)); + this.router.add({ method: "delete", path: `${apiPrefix}/v2/releases/{namespace}/{release}` }, helmRoute.deleteRelease.bind(helmRoute)); // Resource Applier API - this.router.add({ method: "post", path: `${apiPrefix}/stack` }, resourceApplierRoute.applyResource.bind(resourceApplierRoute)) + this.router.add({ method: "post", path: `${apiPrefix}/stack` }, resourceApplierRoute.applyResource.bind(resourceApplierRoute)); } } diff --git a/src/main/routes/helm-route.ts b/src/main/routes/helm-route.ts index 0ffd7252d5..853f8ddded 100644 --- a/src/main/routes/helm-route.ts +++ b/src/main/routes/helm-route.ts @@ -1,114 +1,114 @@ -import { LensApiRequest } from "../router" -import { helmService } from "../helm/helm-service" -import { LensApi } from "../lens-api" -import logger from "../logger" +import { LensApiRequest } from "../router"; +import { helmService } from "../helm/helm-service"; +import { LensApi } from "../lens-api"; +import logger from "../logger"; class HelmApiRoute extends LensApi { public async listCharts(request: LensApiRequest) { - const { response } = request - const charts = await helmService.listCharts() - this.respondJson(response, charts) + const { response } = request; + const charts = await helmService.listCharts(); + this.respondJson(response, charts); } public async getChart(request: LensApiRequest) { - const { params, query, response } = request - const chart = await helmService.getChart(params.repo, params.chart, query.get("version")) - this.respondJson(response, chart) + const { params, query, response } = request; + const chart = await helmService.getChart(params.repo, params.chart, query.get("version")); + this.respondJson(response, chart); } public async getChartValues(request: LensApiRequest) { - const { params, query, response } = request - const values = await helmService.getChartValues(params.repo, params.chart, query.get("version")) - this.respondJson(response, values) + const { params, query, response } = request; + const values = await helmService.getChartValues(params.repo, params.chart, query.get("version")); + this.respondJson(response, values); } public async installChart(request: LensApiRequest) { - const { payload, cluster, response } = request + const { payload, cluster, response } = request; try { - const result = await helmService.installChart(cluster, payload) - this.respondJson(response, result, 201) + const result = await helmService.installChart(cluster, payload); + this.respondJson(response, result, 201); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } public async updateRelease(request: LensApiRequest) { - const { cluster, params, payload, response } = request + const { cluster, params, payload, response } = request; try { - const result = await helmService.updateRelease(cluster, params.release, params.namespace, payload ) - this.respondJson(response, result) + const result = await helmService.updateRelease(cluster, params.release, params.namespace, payload ); + this.respondJson(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } public async rollbackRelease(request: LensApiRequest) { - const { cluster, params, payload, response } = request + const { cluster, params, payload, response } = request; try { - const result = await helmService.rollback(cluster, params.release, params.namespace, payload.revision) - this.respondJson(response, result) + const result = await helmService.rollback(cluster, params.release, params.namespace, payload.revision); + this.respondJson(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error) + logger.debug(error); + this.respondText(response, error); } } public async listReleases(request: LensApiRequest) { - const { cluster, params, response } = request + const { cluster, params, response } = request; try { - const result = await helmService.listReleases(cluster, params.namespace) - this.respondJson(response, result) + const result = await helmService.listReleases(cluster, params.namespace); + this.respondJson(response, result); } catch(error) { - logger.debug(error) - this.respondText(response, error) + logger.debug(error); + this.respondText(response, error); } } public async getRelease(request: LensApiRequest) { - const { cluster, params, response } = request + const { cluster, params, response } = request; try { - const result = await helmService.getRelease(cluster, params.release, params.namespace) - this.respondJson(response, result) + const result = await helmService.getRelease(cluster, params.release, params.namespace); + this.respondJson(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } public async getReleaseValues(request: LensApiRequest) { - const { cluster, params, response } = request + const { cluster, params, response } = request; try { - const result = await helmService.getReleaseValues(cluster, params.release, params.namespace) - this.respondText(response, result) + const result = await helmService.getReleaseValues(cluster, params.release, params.namespace); + this.respondText(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } public async getReleaseHistory(request: LensApiRequest) { - const { cluster, params, response } = request + const { cluster, params, response } = request; try { - const result = await helmService.getReleaseHistory(cluster, params.release, params.namespace) - this.respondJson(response, result) + const result = await helmService.getReleaseHistory(cluster, params.release, params.namespace); + this.respondJson(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } public async deleteRelease(request: LensApiRequest) { - const { cluster, params, response } = request + const { cluster, params, response } = request; try { - const result = await helmService.deleteRelease(cluster, params.release, params.namespace) - this.respondJson(response, result) + const result = await helmService.deleteRelease(cluster, params.release, params.namespace); + this.respondJson(response, result); } catch (error) { - logger.debug(error) - this.respondText(response, error, 422) + logger.debug(error); + this.respondText(response, error, 422); } } } -export const helmRoute = new HelmApiRoute() +export const helmRoute = new HelmApiRoute(); diff --git a/src/main/routes/index.ts b/src/main/routes/index.ts index 60a0423de4..5bc5b3f3dd 100644 --- a/src/main/routes/index.ts +++ b/src/main/routes/index.ts @@ -1,6 +1,6 @@ -export * from "./kubeconfig-route" -export * from "./metrics-route" -export * from "./port-forward-route" -export * from "./watch-route" -export * from "./helm-route" -export * from "./resource-applier-route" +export * from "./kubeconfig-route"; +export * from "./metrics-route"; +export * from "./port-forward-route"; +export * from "./watch-route"; +export * from "./helm-route"; +export * from "./resource-applier-route"; diff --git a/src/main/routes/kubeconfig-route.ts b/src/main/routes/kubeconfig-route.ts index 09f1f061cf..1c04b9525d 100644 --- a/src/main/routes/kubeconfig-route.ts +++ b/src/main/routes/kubeconfig-route.ts @@ -1,10 +1,10 @@ -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { Cluster } from "../cluster" -import { CoreV1Api, V1Secret } from "@kubernetes/client-node" +import { LensApiRequest } from "../router"; +import { LensApi } from "../lens-api"; +import { Cluster } from "../cluster"; +import { CoreV1Api, V1Secret } from "@kubernetes/client-node"; function generateKubeConfig(username: string, secret: V1Secret, cluster: Cluster) { - const tokenData = Buffer.from(secret.data["token"], "base64") + const tokenData = Buffer.from(secret.data["token"], "base64"); return { 'apiVersion': 'v1', 'kind': 'Config', @@ -36,23 +36,23 @@ function generateKubeConfig(username: string, secret: V1Secret, cluster: Cluster } ], 'current-context': cluster.contextName - } + }; } class KubeconfigRoute extends LensApi { public async routeServiceAccountRoute(request: LensApiRequest) { - const { params, response, cluster} = request + const { params, response, cluster} = request; const client = cluster.getProxyKubeconfig().makeApiClient(CoreV1Api); - const secretList = await client.listNamespacedSecret(params.namespace) + const secretList = await client.listNamespacedSecret(params.namespace); const secret = secretList.body.items.find(secret => { const { annotations } = secret.metadata; return annotations && annotations["kubernetes.io/service-account.name"] == params.account; }); const data = generateKubeConfig(params.account, secret, cluster); - this.respondJson(response, data) + this.respondJson(response, data); } } -export const kubeconfigRoute = new KubeconfigRoute() +export const kubeconfigRoute = new KubeconfigRoute(); diff --git a/src/main/routes/metrics-route.ts b/src/main/routes/metrics-route.ts index dc77f7fb9f..254abe188f 100644 --- a/src/main/routes/metrics-route.ts +++ b/src/main/routes/metrics-route.ts @@ -1,32 +1,32 @@ -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { Cluster } from "../cluster" -import _ from "lodash" +import { LensApiRequest } from "../router"; +import { LensApi } from "../lens-api"; +import { Cluster } from "../cluster"; +import _ from "lodash"; export type IMetricsQuery = string | string[] | { [metricName: string]: string; -} +}; // This is used for backoff retry tracking. -const MAX_ATTEMPTS = 5 -const ATTEMPTS = [...(_.fill(Array(MAX_ATTEMPTS - 1), false)), true] +const MAX_ATTEMPTS = 5; +const ATTEMPTS = [...(_.fill(Array(MAX_ATTEMPTS - 1), false)), true]; // prometheus metrics loader async function loadMetrics(promQueries: string[], cluster: Cluster, prometheusPath: string, queryParams: Record): Promise { - const queries = promQueries.map(p => p.trim()) - const loaders = new Map>() + const queries = promQueries.map(p => p.trim()); + const loaders = new Map>(); async function loadMetric(query: string): Promise { async function loadMetricHelper(): Promise { for (const [attempt, lastAttempt] of ATTEMPTS.entries()) { // retry try { - return await cluster.getMetrics(prometheusPath, { query, ...queryParams }) + return await cluster.getMetrics(prometheusPath, { query, ...queryParams }); } catch (error) { if (lastAttempt || error?.statusCode === 404) { return { status: error.toString(), data: { result: [] }, - } + }; } await new Promise(resolve => setTimeout(resolve, (attempt + 1) * 1000)); // add delay before repeating request @@ -34,41 +34,41 @@ async function loadMetrics(promQueries: string[], cluster: Cluster, prometheusPa } } - return loaders.get(query) ?? loaders.set(query, loadMetricHelper()).get(query) + return loaders.get(query) ?? loaders.set(query, loadMetricHelper()).get(query); } - return Promise.all(queries.map(loadMetric)) + return Promise.all(queries.map(loadMetric)); } class MetricsRoute extends LensApi { async routeMetrics({ response, cluster, payload, query }: LensApiRequest) { - const queryParams: IMetricsQuery = Object.fromEntries(query.entries()) + const queryParams: IMetricsQuery = Object.fromEntries(query.entries()); try { const [prometheusPath, prometheusProvider] = await Promise.all([ cluster.contextHandler.getPrometheusPath(), cluster.contextHandler.getPrometheusProvider() - ]) + ]); // return data in same structure as query if (typeof payload === "string") { - const [data] = await loadMetrics([payload], cluster, prometheusPath, queryParams) - this.respondJson(response, data) + const [data] = await loadMetrics([payload], cluster, prometheusPath, queryParams); + this.respondJson(response, data); } else if (Array.isArray(payload)) { - const data = await loadMetrics(payload, cluster, prometheusPath, queryParams) - this.respondJson(response, data) + const data = await loadMetrics(payload, cluster, prometheusPath, queryParams); + this.respondJson(response, data); } else { const queries = Object.entries(payload).map(([queryName, queryOpts]) => ( (prometheusProvider.getQueries(queryOpts) as Record)[queryName] - )) - const result = await loadMetrics(queries, cluster, prometheusPath, queryParams) - const data = Object.fromEntries(Object.keys(payload).map((metricName, i) => [metricName, result[i]])) - this.respondJson(response, data) + )); + const result = await loadMetrics(queries, cluster, prometheusPath, queryParams); + const data = Object.fromEntries(Object.keys(payload).map((metricName, i) => [metricName, result[i]])); + this.respondJson(response, data); } } catch { - this.respondJson(response, {}) + this.respondJson(response, {}); } } } -export const metricsRoute = new MetricsRoute() +export const metricsRoute = new MetricsRoute(); diff --git a/src/main/routes/port-forward-route.ts b/src/main/routes/port-forward-route.ts index 7ed79aa936..55402ff72f 100644 --- a/src/main/routes/port-forward-route.ts +++ b/src/main/routes/port-forward-route.ts @@ -1,14 +1,14 @@ -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { spawn, ChildProcessWithoutNullStreams } from "child_process" -import { Kubectl } from "../kubectl" -import { getFreePort } from "../port" -import { shell } from "electron" -import * as tcpPortUsed from "tcp-port-used" -import logger from "../logger" +import { LensApiRequest } from "../router"; +import { LensApi } from "../lens-api"; +import { spawn, ChildProcessWithoutNullStreams } from "child_process"; +import { Kubectl } from "../kubectl"; +import { getFreePort } from "../port"; +import { shell } from "electron"; +import * as tcpPortUsed from "tcp-port-used"; +import logger from "../logger"; class PortForward { - public static portForwards: PortForward[] = [] + public static portForwards: PortForward[] = []; static getPortforward(forward: {clusterId: string; kind: string; name: string; namespace: string; port: string}) { return PortForward.portForwards.find((pf) => { @@ -18,70 +18,70 @@ class PortForward { pf.name == forward.name && pf.namespace == forward.namespace && pf.port == forward.port - ) - }) + ); + }); } - public clusterId: string - public process: ChildProcessWithoutNullStreams - public kubeConfig: string - public kind: string - public namespace: string - public name: string - public port: string - public localPort: number + public clusterId: string; + public process: ChildProcessWithoutNullStreams; + public kubeConfig: string; + public kind: string; + public namespace: string; + public name: string; + public port: string; + public localPort: number; constructor(obj: any) { - Object.assign(this, obj) + Object.assign(this, obj); } public async start() { - this.localPort = await getFreePort() - const kubectlBin = await Kubectl.bundled().getPath() + this.localPort = await getFreePort(); + const kubectlBin = await Kubectl.bundled().getPath(); const args = [ "--kubeconfig", this.kubeConfig, "port-forward", "-n", this.namespace, `${this.kind}/${this.name}`, `${this.localPort}:${this.port}` - ] + ]; this.process = spawn(kubectlBin, args, { env: process.env - }) - PortForward.portForwards.push(this) + }); + PortForward.portForwards.push(this); this.process.on("exit", () => { - const index = PortForward.portForwards.indexOf(this) + const index = PortForward.portForwards.indexOf(this); if (index > -1) { - PortForward.portForwards.splice(index, 1) + PortForward.portForwards.splice(index, 1); } - }) + }); try { - await tcpPortUsed.waitUntilUsed(this.localPort, 500, 15000) - return true + await tcpPortUsed.waitUntilUsed(this.localPort, 500, 15000); + return true; } catch (error) { - this.process.kill() - return false + this.process.kill(); + return false; } } public open() { - shell.openExternal(`http://localhost:${this.localPort}`) + shell.openExternal(`http://localhost:${this.localPort}`); } } class PortForwardRoute extends LensApi { public async routePortForward(request: LensApiRequest) { - const { params, response, cluster} = request - const { namespace, port, resourceType, resourceName } = params + const { params, response, cluster} = request; + const { namespace, port, resourceType, resourceName } = params; let portForward = PortForward.getPortforward({ clusterId: cluster.id, kind: resourceType, name: resourceName, namespace: namespace, port: port - }) + }); if (!portForward) { - logger.info(`Creating a new port-forward ${namespace}/${resourceType}/${resourceName}:${port}`) + logger.info(`Creating a new port-forward ${namespace}/${resourceType}/${resourceName}:${port}`); portForward = new PortForward({ clusterId: cluster.id, kind: resourceType, @@ -89,20 +89,20 @@ class PortForwardRoute extends LensApi { name: resourceName, port: port, kubeConfig: cluster.getProxyKubeconfigPath() - }) - const started = await portForward.start() + }); + const started = await portForward.start(); if (!started) { this.respondJson(response, { message: "Failed to open port-forward" - }, 400) - return + }, 400); + return; } } - portForward.open() + portForward.open(); - this.respondJson(response, {}) + this.respondJson(response, {}); } } -export const portForwardRoute = new PortForwardRoute() +export const portForwardRoute = new PortForwardRoute(); diff --git a/src/main/routes/resource-applier-route.ts b/src/main/routes/resource-applier-route.ts index 56125af8f3..8bbfec0d9c 100644 --- a/src/main/routes/resource-applier-route.ts +++ b/src/main/routes/resource-applier-route.ts @@ -1,17 +1,17 @@ -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { ResourceApplier } from "../resource-applier" +import { LensApiRequest } from "../router"; +import { LensApi } from "../lens-api"; +import { ResourceApplier } from "../resource-applier"; class ResourceApplierApiRoute extends LensApi { public async applyResource(request: LensApiRequest) { - const { response, cluster, payload } = request + const { response, cluster, payload } = request; try { const resource = await new ResourceApplier(cluster).apply(payload); - this.respondJson(response, [resource], 200) + this.respondJson(response, [resource], 200); } catch (error) { - this.respondText(response, error, 422) + this.respondText(response, error, 422); } } } -export const resourceApplierRoute = new ResourceApplierApiRoute() +export const resourceApplierRoute = new ResourceApplierApiRoute(); diff --git a/src/main/routes/watch-route.ts b/src/main/routes/watch-route.ts index d88276eaac..dd42460a9d 100644 --- a/src/main/routes/watch-route.ts +++ b/src/main/routes/watch-route.ts @@ -1,53 +1,53 @@ -import { LensApiRequest } from "../router" -import { LensApi } from "../lens-api" -import { Watch, KubeConfig } from "@kubernetes/client-node" -import { ServerResponse } from "http" -import { Request } from "request" -import logger from "../logger" +import { LensApiRequest } from "../router"; +import { LensApi } from "../lens-api"; +import { Watch, KubeConfig } from "@kubernetes/client-node"; +import { ServerResponse } from "http"; +import { Request } from "request"; +import logger from "../logger"; class ApiWatcher { - private apiUrl: string - private response: ServerResponse - private watchRequest: Request - private watch: Watch - private processor: NodeJS.Timeout - private eventBuffer: any[] = [] + private apiUrl: string; + private response: ServerResponse; + private watchRequest: Request; + private watch: Watch; + private processor: NodeJS.Timeout; + private eventBuffer: any[] = []; constructor(apiUrl: string, kubeConfig: KubeConfig, response: ServerResponse) { - this.apiUrl = apiUrl - this.watch = new Watch(kubeConfig) - this.response = response + this.apiUrl = apiUrl; + this.watch = new Watch(kubeConfig); + this.response = response; } public async start() { if (this.processor) { - clearInterval(this.processor) + clearInterval(this.processor); } this.processor = setInterval(() => { - const events = this.eventBuffer.splice(0) - events.map(event => this.sendEvent(event)) - this.response.flushHeaders() - }, 50) - this.watchRequest = await this.watch.watch(this.apiUrl, {}, this.watchHandler.bind(this), this.doneHandler.bind(this)) + const events = this.eventBuffer.splice(0); + events.map(event => this.sendEvent(event)); + this.response.flushHeaders(); + }, 50); + this.watchRequest = await this.watch.watch(this.apiUrl, {}, this.watchHandler.bind(this), this.doneHandler.bind(this)); } public stop() { - if (!this.watchRequest) { return } + if (!this.watchRequest) { return; } if (this.processor) { - clearInterval(this.processor) + clearInterval(this.processor); } - logger.debug("Stopping watcher for api: " + this.apiUrl) + logger.debug("Stopping watcher for api: " + this.apiUrl); try { - this.watchRequest.abort() + this.watchRequest.abort(); this.sendEvent({ type: "STREAM_END", url: this.apiUrl, status: 410, - }) - logger.debug("watch aborted") + }); + logger.debug("watch aborted"); } catch (error) { - logger.error("Watch abort errored:" + error) + logger.error("Watch abort errored:" + error); } } @@ -55,12 +55,12 @@ class ApiWatcher { this.eventBuffer.push({ type: phase, object: obj - }) + }); } private doneHandler(error: Error) { - if (error) logger.warn("watch ended: " + error.toString()) - this.watchRequest.abort() + if (error) logger.warn("watch ended: " + error.toString()); + this.watchRequest.abort(); } private sendEvent(evt: any) { @@ -72,40 +72,40 @@ class ApiWatcher { class WatchRoute extends LensApi { public async routeWatch(request: LensApiRequest) { - const { params, response, cluster} = request - const apis: string[] = request.query.getAll("api") - const watchers: ApiWatcher[] = [] + const { params, response, cluster} = request; + const apis: string[] = request.query.getAll("api"); + const watchers: ApiWatcher[] = []; if (!apis.length) { this.respondJson(response, { message: "Empty request. Query params 'api' are not provided.", example: "?api=/api/v1/pods&api=/api/v1/nodes", - }, 400) - return + }, 400); + return; } - response.setHeader("Content-Type", "text/event-stream") - response.setHeader("Cache-Control", "no-cache") - response.setHeader("Connection", "keep-alive") - logger.debug("watch using kubeconfig:" + JSON.stringify(cluster.getProxyKubeconfig(), null, 2)) + response.setHeader("Content-Type", "text/event-stream"); + response.setHeader("Cache-Control", "no-cache"); + response.setHeader("Connection", "keep-alive"); + logger.debug("watch using kubeconfig:" + JSON.stringify(cluster.getProxyKubeconfig(), null, 2)); apis.forEach(apiUrl => { - const watcher = new ApiWatcher(apiUrl, cluster.getProxyKubeconfig(), response) - watcher.start() - watchers.push(watcher) - }) + const watcher = new ApiWatcher(apiUrl, cluster.getProxyKubeconfig(), response); + watcher.start(); + watchers.push(watcher); + }); request.raw.req.on("close", () => { - logger.debug("Watch request closed") - watchers.map(watcher => watcher.stop()) - }) + logger.debug("Watch request closed"); + watchers.map(watcher => watcher.stop()); + }); request.raw.req.on("end", () => { - logger.debug("Watch request ended") - watchers.map(watcher => watcher.stop()) - }) + logger.debug("Watch request ended"); + watchers.map(watcher => watcher.stop()); + }); } } -export const watchRoute = new WatchRoute() +export const watchRoute = new WatchRoute(); diff --git a/src/main/shell-session.ts b/src/main/shell-session.ts index 6ea9e4eede..42e0039047 100644 --- a/src/main/shell-session.ts +++ b/src/main/shell-session.ts @@ -1,23 +1,23 @@ -import * as pty from "node-pty" -import * as WebSocket from "ws" +import * as pty from "node-pty"; +import * as WebSocket from "ws"; import { EventEmitter } from "events"; -import path from "path" -import shellEnv from "shell-env" -import { app } from "electron" -import { Kubectl } from "./kubectl" -import { Cluster } from "./cluster" +import path from "path"; +import shellEnv from "shell-env"; +import { app } from "electron"; +import { Kubectl } from "./kubectl"; +import { Cluster } from "./cluster"; import { ClusterPreferences } from "../common/cluster-store"; -import { helmCli } from "./helm/helm-cli" +import { helmCli } from "./helm/helm-cli"; import { isWindows } from "../common/vars"; -import { appEventBus } from "../common/event-bus" +import { appEventBus } from "../common/event-bus"; import { userStore } from "../common/user-store"; export class ShellSession extends EventEmitter { - static shellEnvs: Map = new Map() + static shellEnvs: Map = new Map(); - protected websocket: WebSocket - protected shellProcess: pty.IPty - protected kubeconfigPath: string + protected websocket: WebSocket; + protected shellProcess: pty.IPty; + protected kubeconfigPath: string; protected nodeShellPod: string; protected kubectl: Kubectl; protected kubectlBinDir: string; @@ -28,22 +28,22 @@ export class ShellSession extends EventEmitter { protected clusterId: string; constructor(socket: WebSocket, cluster: Cluster) { - super() - this.websocket = socket - this.kubeconfigPath = cluster.getProxyKubeconfigPath() - this.kubectl = new Kubectl(cluster.version) - this.preferences = cluster.preferences || {} - this.clusterId = cluster.id + super(); + this.websocket = socket; + this.kubeconfigPath = cluster.getProxyKubeconfigPath(); + this.kubectl = new Kubectl(cluster.version); + this.preferences = cluster.preferences || {}; + this.clusterId = cluster.id; } public async open() { - this.kubectlBinDir = await this.kubectl.binDir() - const pathFromPreferences = userStore.preferences.kubectlBinariesPath || this.kubectl.getBundledPath() - this.kubectlPathDir = userStore.preferences.downloadKubectlBinaries ? this.kubectlBinDir : path.dirname(pathFromPreferences) - this.helmBinDir = helmCli.getBinaryDir() - const env = await this.getCachedShellEnv() - const shell = env.PTYSHELL - const args = await this.getShellArgs(shell) + this.kubectlBinDir = await this.kubectl.binDir(); + const pathFromPreferences = userStore.preferences.kubectlBinariesPath || this.kubectl.getBundledPath(); + this.kubectlPathDir = userStore.preferences.downloadKubectlBinaries ? this.kubectlBinDir : path.dirname(pathFromPreferences); + this.helmBinDir = helmCli.getBinaryDir(); + const env = await this.getCachedShellEnv(); + const shell = env.PTYSHELL; + const args = await this.getShellArgs(shell); this.shellProcess = pty.spawn(shell, args, { cols: 80, cwd: this.cwd() || env.HOME, @@ -53,138 +53,138 @@ export class ShellSession extends EventEmitter { }); this.running = true; - this.pipeStdout() - this.pipeStdin() - this.closeWebsocketOnProcessExit() - this.exitProcessOnWebsocketClose() + this.pipeStdout(); + this.pipeStdin(); + this.closeWebsocketOnProcessExit(); + this.exitProcessOnWebsocketClose(); - appEventBus.emit({name: "shell", action: "open"}) + appEventBus.emit({name: "shell", action: "open"}); } protected cwd(): string { if(!this.preferences || !this.preferences.terminalCWD || this.preferences.terminalCWD === "") { - return null + return null; } - return this.preferences.terminalCWD + return this.preferences.terminalCWD; } protected async getShellArgs(shell: string): Promise> { switch(path.basename(shell)) { case "powershell.exe": - return ["-NoExit", "-command", `& {Set-Location $Env:USERPROFILE; $Env:PATH="${this.helmBinDir};${this.kubectlPathDir};$Env:PATH"}`] + return ["-NoExit", "-command", `& {Set-Location $Env:USERPROFILE; $Env:PATH="${this.helmBinDir};${this.kubectlPathDir};$Env:PATH"}`]; case "bash": - return ["--init-file", path.join(this.kubectlBinDir, '.bash_set_path')] + return ["--init-file", path.join(this.kubectlBinDir, '.bash_set_path')]; case "fish": - return ["--login", "--init-command", `export PATH="${this.helmBinDir}:${this.kubectlPathDir}:$PATH"; export KUBECONFIG="${this.kubeconfigPath}"`] + return ["--login", "--init-command", `export PATH="${this.helmBinDir}:${this.kubectlPathDir}:$PATH"; export KUBECONFIG="${this.kubeconfigPath}"`]; case "zsh": - return ["--login"] + return ["--login"]; default: - return [] + return []; } } protected async getCachedShellEnv() { - let env = ShellSession.shellEnvs.get(this.clusterId) + let env = ShellSession.shellEnvs.get(this.clusterId); if (!env) { - env = await this.getShellEnv() - ShellSession.shellEnvs.set(this.clusterId, env) + env = await this.getShellEnv(); + ShellSession.shellEnvs.set(this.clusterId, env); } else { // refresh env in the background this.getShellEnv().then((shellEnv: any) => { - ShellSession.shellEnvs.set(this.clusterId, shellEnv) - }) + ShellSession.shellEnvs.set(this.clusterId, shellEnv); + }); } - return env + return env; } protected async getShellEnv() { - const env = JSON.parse(JSON.stringify(await shellEnv())) - const pathStr = [this.kubectlBinDir, this.helmBinDir, process.env.PATH].join(path.delimiter) + const env = JSON.parse(JSON.stringify(await shellEnv())); + const pathStr = [this.kubectlBinDir, this.helmBinDir, process.env.PATH].join(path.delimiter); if(isWindows) { - env["SystemRoot"] = process.env.SystemRoot - env["PTYSHELL"] = "powershell.exe" - env["PATH"] = pathStr + env["SystemRoot"] = process.env.SystemRoot; + env["PTYSHELL"] = "powershell.exe"; + env["PATH"] = pathStr; } else if(typeof(process.env.SHELL) != "undefined") { - env["PTYSHELL"] = process.env.SHELL - env["PATH"] = pathStr + env["PTYSHELL"] = process.env.SHELL; + env["PATH"] = pathStr; } else { - env["PTYSHELL"] = "" // blank runs the system default shell + env["PTYSHELL"] = ""; // blank runs the system default shell } if(path.basename(env["PTYSHELL"]) === "zsh") { - env["OLD_ZDOTDIR"] = env.ZDOTDIR || env.HOME - env["ZDOTDIR"] = this.kubectlBinDir + env["OLD_ZDOTDIR"] = env.ZDOTDIR || env.HOME; + env["ZDOTDIR"] = this.kubectlBinDir; } - env["PTYPID"] = process.pid.toString() - env["KUBECONFIG"] = this.kubeconfigPath - env["TERM_PROGRAM"] = app.getName() - env["TERM_PROGRAM_VERSION"] = app.getVersion() + env["PTYPID"] = process.pid.toString(); + env["KUBECONFIG"] = this.kubeconfigPath; + env["TERM_PROGRAM"] = app.getName(); + env["TERM_PROGRAM_VERSION"] = app.getVersion(); if (this.preferences.httpsProxy) { - env["HTTPS_PROXY"] = this.preferences.httpsProxy + env["HTTPS_PROXY"] = this.preferences.httpsProxy; } - const no_proxy = ["localhost", "127.0.0.1", env["NO_PROXY"]] - env["NO_PROXY"] = no_proxy.filter(address => !!address).join() + const no_proxy = ["localhost", "127.0.0.1", env["NO_PROXY"]]; + env["NO_PROXY"] = no_proxy.filter(address => !!address).join(); if (env.DEBUG) { // do not pass debug option to bash - delete env["DEBUG"] + delete env["DEBUG"]; } - return(env) + return(env); } protected pipeStdout() { // send shell output to websocket this.shellProcess.onData(((data: string) => { - this.sendResponse(data) + this.sendResponse(data); })); } protected pipeStdin() { // write websocket messages to shellProcess this.websocket.on("message", (data: string) => { - if (!this.running) { return } + if (!this.running) { return; } - const message = Buffer.from(data.slice(1, data.length), "base64").toString() + const message = Buffer.from(data.slice(1, data.length), "base64").toString(); switch (data[0]) { case "0": - this.shellProcess.write(message) + this.shellProcess.write(message); break; case "4": - const resizeMsgObj = JSON.parse(message) - this.shellProcess.resize(resizeMsgObj["Width"], resizeMsgObj["Height"]) + const resizeMsgObj = JSON.parse(message); + this.shellProcess.resize(resizeMsgObj["Width"], resizeMsgObj["Height"]); break; case "9": - this.emit('newToken', message) + this.emit('newToken', message); break; } - }) + }); } protected exit(code = 1000) { - if (this.websocket.readyState == this.websocket.OPEN) this.websocket.close(code) - this.emit('exit') + if (this.websocket.readyState == this.websocket.OPEN) this.websocket.close(code); + this.emit('exit'); } protected closeWebsocketOnProcessExit() { this.shellProcess.onExit(({ exitCode }) => { - this.running = false - let timeout = 0 + this.running = false; + let timeout = 0; if (exitCode > 0) { - this.sendResponse("Terminal will auto-close in 15 seconds ...") - timeout = 15*1000 + this.sendResponse("Terminal will auto-close in 15 seconds ..."); + timeout = 15*1000; } setTimeout(() => { - this.exit() - }, timeout) + this.exit(); + }, timeout); }); } protected exitProcessOnWebsocketClose() { this.websocket.on("close", () => { - this.killShellProcess() - }) + this.killShellProcess(); + }); } protected killShellProcess(){ @@ -192,17 +192,17 @@ export class ShellSession extends EventEmitter { // On Windows we need to kill the shell process by pid, since Lens won't respond after a while if using `this.shellProcess.kill()` if (isWindows) { try { - process.kill(this.shellProcess.pid) + process.kill(this.shellProcess.pid); } catch(e) { - return + return; } } else { - this.shellProcess.kill() + this.shellProcess.kill(); } } } protected sendResponse(msg: string) { - this.websocket.send("1" + Buffer.from(msg).toString("base64")) + this.websocket.send("1" + Buffer.from(msg).toString("base64")); } } diff --git a/src/main/shell-sync.ts b/src/main/shell-sync.ts index 373d0a36ba..46d5788c12 100644 --- a/src/main/shell-sync.ts +++ b/src/main/shell-sync.ts @@ -1,4 +1,4 @@ -import shellEnv from "shell-env" +import shellEnv from "shell-env"; import os from "os"; import { app } from "electron"; import logger from "./logger"; @@ -19,7 +19,7 @@ export async function shellSync() { try { envVars = await shellEnv(shell); } catch (error) { - logger.error(`shellEnv: ${error}`) + logger.error(`shellEnv: ${error}`); } const env: Env = JSON.parse(JSON.stringify(envVars)); @@ -27,12 +27,12 @@ export async function shellSync() { // the LANG env var expects an underscore instead of electron's dash env.LANG = `${app.getLocale().replace('-', '_')}.UTF-8`; } else if (!env.LANG.endsWith(".UTF-8")) { - env.LANG += ".UTF-8" + env.LANG += ".UTF-8"; } // Overwrite PATH on darwin if (process.env.NODE_ENV === "production" && process.platform === "darwin") { - process.env["PATH"] = env.PATH + process.env["PATH"] = env.PATH; } // The spread operator allows joining of objects. The precedence is last to first. diff --git a/src/main/tray.ts b/src/main/tray.ts index 268e006089..f84ea21896 100644 --- a/src/main/tray.ts +++ b/src/main/tray.ts @@ -1,6 +1,6 @@ -import path from "path" -import packageInfo from "../../package.json" -import { dialog, Menu, NativeImage, nativeTheme, Tray } from "electron" +import path from "path"; +import packageInfo from "../../package.json"; +import { dialog, Menu, NativeImage, nativeTheme, Tray } from "electron"; import { autorun } from "mobx"; import { showAbout } from "./menu"; import { AppUpdater } from "./app-updater"; @@ -24,7 +24,7 @@ export function getTrayIcon(isDark = nativeTheme.shouldUseDarkColors): string { __static, isDevelopment ? "../build/tray" : "icons", // copied within electron-builder extras `tray_icon${isDark ? "_dark" : ""}.png` - ) + ); } export function initTray(windowManager: WindowManager) { @@ -35,18 +35,18 @@ export function initTray(windowManager: WindowManager) { } catch (err) { logger.error(`[TRAY]: building failed: ${err}`); } - }) + }); return () => { dispose(); tray?.destroy(); tray = null; - } + }; } export function buildTray(icon: string | NativeImage, menu: Menu) { if (!tray) { - tray = new Tray(icon) - tray.setToolTip(packageInfo.description) + tray = new Tray(icon); + tray.setToolTip(packageInfo.description); tray.setIgnoreDoubleClickEvents(true); } @@ -70,7 +70,7 @@ export function createTrayMenu(windowManager: WindowManager): Menu { { label: "Open Lens", async click() { - await windowManager.ensureMainWindow() + await windowManager.ensureMainWindow(); }, }, { @@ -98,9 +98,9 @@ export function createTrayMenu(windowManager: WindowManager): Menu { clusterStore.setActive(clusterId); windowManager.navigate(clusterViewURL({ params: { clusterId } })); } - } + }; }) - } + }; }), }, { @@ -112,7 +112,7 @@ export function createTrayMenu(windowManager: WindowManager): Menu { dialog.showMessageBoxSync(browserWindow, { message: "No updates available", type: "info", - }) + }); } }, }, @@ -120,7 +120,7 @@ export function createTrayMenu(windowManager: WindowManager): Menu { { label: 'Quit App', click() { - exitApp() + exitApp(); } } ]); diff --git a/src/main/window-manager.ts b/src/main/window-manager.ts index 019ed270eb..00fbdd4243 100644 --- a/src/main/window-manager.ts +++ b/src/main/window-manager.ts @@ -1,9 +1,9 @@ import type { ClusterId } from "../common/cluster-store"; import { observable } from "mobx"; -import { app, BrowserWindow, dialog, shell, webContents } from "electron" -import windowStateKeeper from "electron-window-state" -import { appEventBus } from "../common/event-bus" -import { subscribeToBroadcast } from "../common/ipc" +import { app, BrowserWindow, dialog, shell, webContents } from "electron"; +import windowStateKeeper from "electron-window-state"; +import { appEventBus } from "../common/event-bus"; +import { subscribeToBroadcast } from "../common/ipc"; import { initMenu } from "./menu"; import { initTray } from "./tray"; import { Singleton } from "../common/utils"; @@ -26,7 +26,7 @@ export class WindowManager extends Singleton { } get mainUrl() { - return `http://localhost:${this.proxyPort}` + return `http://localhost:${this.proxyPort}`; } async initMainWindow(showSplash = true) { @@ -63,14 +63,14 @@ export class WindowManager extends Singleton { shell.openExternal(url); }); this.mainWindow.webContents.on("dom-ready", () => { - appEventBus.emit({name: "app", action: "dom-ready"}) - }) + appEventBus.emit({name: "app", action: "dom-ready"}); + }); this.mainWindow.on("focus", () => { - appEventBus.emit({name: "app", action: "focus"}) - }) + appEventBus.emit({name: "app", action: "focus"}); + }); this.mainWindow.on("blur", () => { - appEventBus.emit({name: "app", action: "blur"}) - }) + appEventBus.emit({name: "app", action: "blur"}); + }); // clean up this.mainWindow.on("closed", () => { @@ -78,16 +78,16 @@ export class WindowManager extends Singleton { this.mainWindow = null; this.splashWindow = null; app.dock?.hide(); // hide icon in dock (mac-os) - }) + }); } try { if (showSplash) await this.showSplash(); await this.mainWindow.loadURL(this.mainUrl); this.mainWindow.show(); this.splashWindow?.close(); - appEventBus.emit({ name: "app", action: "start" }) + appEventBus.emit({ name: "app", action: "start" }); } catch (err) { - dialog.showErrorBox("ERROR!", err.toString()) + dialog.showErrorBox("ERROR!", err.toString()); } } @@ -103,7 +103,7 @@ export class WindowManager extends Singleton { // track visible cluster from ui subscribeToBroadcast("cluster-view:current-id", (event, clusterId: ClusterId) => { this.activeClusterId = clusterId; - }) + }); } async ensureMainWindow(): Promise { @@ -126,11 +126,11 @@ export class WindowManager extends Singleton { channel: "renderer:navigate", frameId: frameId, data: [url], - }) + }); } reload() { - const frameId = clusterFrameMap.get(this.activeClusterId) + const frameId = clusterFrameMap.get(this.activeClusterId); if (frameId) { this.sendToView({ channel: "renderer:reload", frameId }); } else { @@ -169,7 +169,7 @@ export class WindowManager extends Singleton { this.splashWindow = null; Object.entries(this.disposers).forEach(([name, dispose]) => { dispose(); - delete this.disposers[name] + delete this.disposers[name]; }); } } diff --git a/src/migrations/cluster-store/2.0.0-beta.2.ts b/src/migrations/cluster-store/2.0.0-beta.2.ts index 8a01af5407..245e9c019c 100644 --- a/src/migrations/cluster-store/2.0.0-beta.2.ts +++ b/src/migrations/cluster-store/2.0.0-beta.2.ts @@ -13,4 +13,4 @@ export default migration({ store.set(contextName, { kubeConfig: value[1] }); } } -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/src/migrations/cluster-store/2.4.1.ts b/src/migrations/cluster-store/2.4.1.ts index 5789f6cc36..f9de1ed6d8 100644 --- a/src/migrations/cluster-store/2.4.1.ts +++ b/src/migrations/cluster-store/2.4.1.ts @@ -11,4 +11,4 @@ export default migration({ store.set(contextName, { kubeConfig: cluster.kubeConfig, icon: cluster.icon || null, preferences: cluster.preferences || {} }); } } -}) +}); diff --git a/src/migrations/cluster-store/2.6.0-beta.2.ts b/src/migrations/cluster-store/2.6.0-beta.2.ts index 0e13afe7a9..3114202ed1 100644 --- a/src/migrations/cluster-store/2.6.0-beta.2.ts +++ b/src/migrations/cluster-store/2.6.0-beta.2.ts @@ -6,7 +6,7 @@ export default migration({ run(store, log) { for (const value of store) { const clusterKey = value[0]; - if (clusterKey === "__internal__") continue + if (clusterKey === "__internal__") continue; const cluster = value[1]; if (!cluster.preferences) cluster.preferences = {}; if (cluster.icon) { @@ -16,4 +16,4 @@ export default migration({ store.set(clusterKey, { contextName: clusterKey, kubeConfig: value[1].kubeConfig, preferences: value[1].preferences }); } } -}) +}); diff --git a/src/migrations/cluster-store/2.6.0-beta.3.ts b/src/migrations/cluster-store/2.6.0-beta.3.ts index 11f1a3bce9..7f17440e60 100644 --- a/src/migrations/cluster-store/2.6.0-beta.3.ts +++ b/src/migrations/cluster-store/2.6.0-beta.3.ts @@ -1,38 +1,38 @@ import { migration } from "../migration-wrapper"; -import yaml from "js-yaml" +import yaml from "js-yaml"; export default migration({ version: "2.6.0-beta.3", run(store, log) { for (const value of store) { const clusterKey = value[0]; - if (clusterKey === "__internal__") continue + if (clusterKey === "__internal__") continue; const cluster = value[1]; - if (!cluster.kubeConfig) continue - const kubeConfig = yaml.safeLoad(cluster.kubeConfig) - if (!kubeConfig.hasOwnProperty('users')) continue - const userObj = kubeConfig.users[0] + if (!cluster.kubeConfig) continue; + const kubeConfig = yaml.safeLoad(cluster.kubeConfig); + if (!kubeConfig.hasOwnProperty('users')) continue; + const userObj = kubeConfig.users[0]; if (userObj) { - const user = userObj.user + const user = userObj.user; if (user["auth-provider"] && user["auth-provider"].config) { - const authConfig = user["auth-provider"].config + const authConfig = user["auth-provider"].config; if (authConfig["access-token"]) { - authConfig["access-token"] = `${authConfig["access-token"]}` + authConfig["access-token"] = `${authConfig["access-token"]}`; } if (authConfig.expiry) { - authConfig.expiry = `${authConfig.expiry}` + authConfig.expiry = `${authConfig.expiry}`; } - log(authConfig) - user["auth-provider"].config = authConfig + log(authConfig); + user["auth-provider"].config = authConfig; kubeConfig.users = [{ name: userObj.name, user: user - }] - cluster.kubeConfig = yaml.safeDump(kubeConfig) - store.set(clusterKey, cluster) + }]; + cluster.kubeConfig = yaml.safeDump(kubeConfig); + store.set(clusterKey, cluster); } } } } -}) +}); diff --git a/src/migrations/cluster-store/2.7.0-beta.0.ts b/src/migrations/cluster-store/2.7.0-beta.0.ts index 3e0ae9337f..f1af3de3c9 100644 --- a/src/migrations/cluster-store/2.7.0-beta.0.ts +++ b/src/migrations/cluster-store/2.7.0-beta.0.ts @@ -6,10 +6,10 @@ export default migration({ run(store, log) { for (const value of store) { const clusterKey = value[0]; - if (clusterKey === "__internal__") continue + if (clusterKey === "__internal__") continue; const cluster = value[1]; - cluster.workspace = "default" - store.set(clusterKey, cluster) + cluster.workspace = "default"; + store.set(clusterKey, cluster); } } -}) +}); diff --git a/src/migrations/cluster-store/2.7.0-beta.1.ts b/src/migrations/cluster-store/2.7.0-beta.1.ts index de9e4506d1..52e60ba527 100644 --- a/src/migrations/cluster-store/2.7.0-beta.1.ts +++ b/src/migrations/cluster-store/2.7.0-beta.1.ts @@ -1,25 +1,25 @@ // Add id for clusters and store them to array import { migration } from "../migration-wrapper"; -import { v4 as uuid } from "uuid" +import { v4 as uuid } from "uuid"; export default migration({ version: "2.7.0-beta.1", run(store, log) { - const clusters: any[] = [] + const clusters: any[] = []; for (const value of store) { const clusterKey = value[0]; - if (clusterKey === "__internal__") continue - if (clusterKey === "clusters") continue + if (clusterKey === "__internal__") continue; + if (clusterKey === "clusters") continue; const cluster = value[1]; - cluster.id = uuid() + cluster.id = uuid(); if (!cluster.preferences.clusterName) { - cluster.preferences.clusterName = clusterKey + cluster.preferences.clusterName = clusterKey; } - clusters.push(cluster) - store.delete(clusterKey) + clusters.push(cluster); + store.delete(clusterKey); } if (clusters.length > 0) { - store.set("clusters", clusters) + store.set("clusters", clusters); } } -}) +}); diff --git a/src/migrations/cluster-store/3.6.0-beta.1.ts b/src/migrations/cluster-store/3.6.0-beta.1.ts index 412c77ab96..c7e5889cd9 100644 --- a/src/migrations/cluster-store/3.6.0-beta.1.ts +++ b/src/migrations/cluster-store/3.6.0-beta.1.ts @@ -1,24 +1,24 @@ // Move embedded kubeconfig into separate file and add reference to it to cluster settings // convert file path cluster icons to their base64 encoded versions -import path from "path" -import { app, remote } from "electron" +import path from "path"; +import { app, remote } from "electron"; import { migration } from "../migration-wrapper"; -import fse from "fs-extra" +import fse from "fs-extra"; import { ClusterModel, ClusterStore } from "../../common/cluster-store"; import { loadConfig } from "../../common/kube-helpers"; export default migration({ version: "3.6.0-beta.1", run(store, printLog) { - const userDataPath = (app || remote.app).getPath("userData") + const userDataPath = (app || remote.app).getPath("userData"); const kubeConfigBase = ClusterStore.getCustomKubeConfigPath(""); const storedClusters: ClusterModel[] = store.get("clusters") || []; if (!storedClusters.length) return; fse.ensureDirSync(kubeConfigBase); - printLog("Number of clusters to migrate: ", storedClusters.length) + printLog("Number of clusters to migrate: ", storedClusters.length); const migratedClusters = storedClusters .map(cluster => { /** @@ -31,7 +31,7 @@ export default migration({ delete cluster.kubeConfig; } catch (error) { - printLog(`Failed to migrate Kubeconfig for cluster "${cluster.id}", removing cluster...`, error) + printLog(`Failed to migrate Kubeconfig for cluster "${cluster.id}", removing cluster...`, error); return undefined; } @@ -40,8 +40,8 @@ export default migration({ */ try { if (cluster.preferences?.icon) { - printLog(`migrating ${cluster.preferences.icon} for ${cluster.preferences.clusterName}`) - const iconPath = cluster.preferences.icon.replace("store://", "") + printLog(`migrating ${cluster.preferences.icon} for ${cluster.preferences.clusterName}`); + const iconPath = cluster.preferences.icon.replace("store://", ""); const fileData = fse.readFileSync(path.join(userDataPath, iconPath)); cluster.preferences.icon = `data:;base64,${fileData.toString('base64')}`; @@ -49,7 +49,7 @@ export default migration({ delete cluster.preferences?.icon; } } catch (error) { - printLog(`Failed to migrate cluster icon for cluster "${cluster.id}"`, error) + printLog(`Failed to migrate cluster icon for cluster "${cluster.id}"`, error); delete cluster.preferences.icon; } @@ -59,7 +59,7 @@ export default migration({ // "overwrite" the cluster configs if (migratedClusters.length > 0) { - store.set("clusters", migratedClusters) + store.set("clusters", migratedClusters); } } -}) +}); diff --git a/src/migrations/cluster-store/index.ts b/src/migrations/cluster-store/index.ts index f35e8f6c9c..c546fdaeda 100644 --- a/src/migrations/cluster-store/index.ts +++ b/src/migrations/cluster-store/index.ts @@ -1,13 +1,13 @@ // Cluster store migrations -import version200Beta2 from "./2.0.0-beta.2" -import version241 from "./2.4.1" -import version260Beta2 from "./2.6.0-beta.2" -import version260Beta3 from "./2.6.0-beta.3" -import version270Beta0 from "./2.7.0-beta.0" -import version270Beta1 from "./2.7.0-beta.1" -import version360Beta1 from "./3.6.0-beta.1" -import snap from "./snap" +import version200Beta2 from "./2.0.0-beta.2"; +import version241 from "./2.4.1"; +import version260Beta2 from "./2.6.0-beta.2"; +import version260Beta3 from "./2.6.0-beta.3"; +import version270Beta0 from "./2.7.0-beta.0"; +import version270Beta1 from "./2.7.0-beta.1"; +import version360Beta1 from "./3.6.0-beta.1"; +import snap from "./snap"; export default { ...version200Beta2, @@ -18,4 +18,4 @@ export default { ...version270Beta1, ...version360Beta1, ...snap -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/migrations/cluster-store/snap.ts b/src/migrations/cluster-store/snap.ts index a377ba4268..1136607cd7 100644 --- a/src/migrations/cluster-store/snap.ts +++ b/src/migrations/cluster-store/snap.ts @@ -3,31 +3,31 @@ import { migration } from "../migration-wrapper"; import { ClusterModel, ClusterStore } from "../../common/cluster-store"; import { getAppVersion } from "../../common/utils/app-version"; -import fs from "fs" +import fs from "fs"; export default migration({ version: getAppVersion(), // Run always after upgrade run(store, printLog) { if (!process.env["SNAP"]) return; - printLog("Migrating embedded kubeconfig paths") + printLog("Migrating embedded kubeconfig paths"); const storedClusters: ClusterModel[] = store.get("clusters") || []; if (!storedClusters.length) return; - printLog("Number of clusters to migrate: ", storedClusters.length) + printLog("Number of clusters to migrate: ", storedClusters.length); const migratedClusters = storedClusters .map(cluster => { /** * replace snap version with 'current' in kubeconfig path */ if (!fs.existsSync(cluster.kubeConfigPath)) { - const kubeconfigPath = cluster.kubeConfigPath.replace(/\/snap\/kontena-lens\/[0-9]*\//, "/snap/kontena-lens/current/") - cluster.kubeConfigPath = kubeconfigPath + const kubeconfigPath = cluster.kubeConfigPath.replace(/\/snap\/kontena-lens\/[0-9]*\//, "/snap/kontena-lens/current/"); + cluster.kubeConfigPath = kubeconfigPath; } return cluster; - }) + }); - store.set("clusters", migratedClusters) + store.set("clusters", migratedClusters); } -}) +}); diff --git a/src/migrations/user-store/2.1.0-beta.4.ts b/src/migrations/user-store/2.1.0-beta.4.ts index 24c4cde5e3..e8f6500b05 100644 --- a/src/migrations/user-store/2.1.0-beta.4.ts +++ b/src/migrations/user-store/2.1.0-beta.4.ts @@ -6,4 +6,4 @@ export default migration({ run(store) { store.set("lastSeenAppVersion", "0.0.0"); } -}) +}); diff --git a/src/migrations/user-store/index.ts b/src/migrations/user-store/index.ts index 895bc5ee18..e1e7b8ffc9 100644 --- a/src/migrations/user-store/index.ts +++ b/src/migrations/user-store/index.ts @@ -1,7 +1,7 @@ // User store migrations -import version210Beta4 from "./2.1.0-beta.4" +import version210Beta4 from "./2.1.0-beta.4"; export default { ...version210Beta4, -} +}; diff --git a/src/renderer/api/api-manager.ts b/src/renderer/api/api-manager.ts index a0d90f4a13..98dbe206c7 100644 --- a/src/renderer/api/api-manager.ts +++ b/src/renderer/api/api-manager.ts @@ -24,7 +24,7 @@ export class ApiManager { } protected resolveApi(api: string | KubeApi): KubeApi { - if (typeof api === "string") return this.getApi(api) + if (typeof api === "string") return this.getApi(api); return api; } @@ -41,7 +41,7 @@ export class ApiManager { registerStore(store: KubeObjectStore, apis: KubeApi[] = [store.api]) { apis.forEach(api => { this.stores.set(api, store); - }) + }); } getStore(api: string | KubeApi): KubeObjectStore { diff --git a/src/renderer/api/endpoints/cluster-role-binding.api.ts b/src/renderer/api/endpoints/cluster-role-binding.api.ts index 35e4ded7e7..d566717bff 100644 --- a/src/renderer/api/endpoints/cluster-role-binding.api.ts +++ b/src/renderer/api/endpoints/cluster-role-binding.api.ts @@ -2,9 +2,9 @@ import { RoleBinding } from "./role-binding.api"; import { KubeApi } from "../kube-api"; export class ClusterRoleBinding extends RoleBinding { - static kind = "ClusterRoleBinding" - static namespaced = false - static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings" + static kind = "ClusterRoleBinding"; + static namespaced = false; + static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings"; } export const clusterRoleBindingApi = new KubeApi({ diff --git a/src/renderer/api/endpoints/cluster-role.api.ts b/src/renderer/api/endpoints/cluster-role.api.ts index 8a99f7ad27..9e3c90ca2e 100644 --- a/src/renderer/api/endpoints/cluster-role.api.ts +++ b/src/renderer/api/endpoints/cluster-role.api.ts @@ -4,9 +4,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class ClusterRole extends Role { - static kind = "ClusterRole" - static namespaced = false - static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterroles" + static kind = "ClusterRole"; + static namespaced = false; + static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterroles"; } export const clusterRoleApi = new KubeApi({ diff --git a/src/renderer/api/endpoints/cluster.api.ts b/src/renderer/api/endpoints/cluster.api.ts index 4386f28184..43783e1c00 100644 --- a/src/renderer/api/endpoints/cluster.api.ts +++ b/src/renderer/api/endpoints/cluster.api.ts @@ -3,12 +3,12 @@ import { KubeObject } from "../kube-object"; import { KubeApi } from "../kube-api"; export class ClusterApi extends KubeApi { - static kind = "Cluster" - static namespaced = true + static kind = "Cluster"; + static namespaced = true; async getMetrics(nodeNames: string[], params?: IMetricsReqParams): Promise { const nodes = nodeNames.join("|"); - const opts = { category: "cluster", nodes: nodes } + const opts = { category: "cluster", nodes: nodes }; return metricsApi.getMetrics({ memoryUsage: opts, @@ -52,7 +52,7 @@ export interface IClusterMetrics { export class Cluster extends KubeObject { static kind = "Cluster"; - static apiBase = "/apis/cluster.k8s.io/v1alpha1/clusters" + static apiBase = "/apis/cluster.k8s.io/v1alpha1/clusters"; spec: { clusterNetwork?: { @@ -69,7 +69,7 @@ export class Cluster extends KubeObject { profile: string; }; }; - } + }; status?: { apiEndpoints: { host: string; @@ -84,7 +84,7 @@ export class Cluster extends KubeObject { }; errorMessage?: string; errorReason?: string; - } + }; getStatus() { if (this.metadata.deletionTimestamp) return ClusterStatus.REMOVING; diff --git a/src/renderer/api/endpoints/component-status.api.ts b/src/renderer/api/endpoints/component-status.api.ts index 7f7e04fe2a..fec4dda1da 100644 --- a/src/renderer/api/endpoints/component-status.api.ts +++ b/src/renderer/api/endpoints/component-status.api.ts @@ -8,11 +8,11 @@ export interface IComponentStatusCondition { } export class ComponentStatus extends KubeObject { - static kind = "ComponentStatus" - static namespaced = false - static apiBase = "/api/v1/componentstatuses" + static kind = "ComponentStatus"; + static namespaced = false; + static apiBase = "/api/v1/componentstatuses"; - conditions: IComponentStatusCondition[] + conditions: IComponentStatusCondition[]; getTruthyConditions() { return this.conditions.filter(c => c.status === "True"); diff --git a/src/renderer/api/endpoints/configmap.api.ts b/src/renderer/api/endpoints/configmap.api.ts index 59f3e3b090..042fb59d86 100644 --- a/src/renderer/api/endpoints/configmap.api.ts +++ b/src/renderer/api/endpoints/configmap.api.ts @@ -7,7 +7,7 @@ import { KubeApi } from "../kube-api"; export class ConfigMap extends KubeObject { static kind = "ConfigMap"; static namespaced = true; - static apiBase = "/api/v1/configmaps" + static apiBase = "/api/v1/configmaps"; constructor(data: KubeJsonApiData) { super(data); @@ -16,7 +16,7 @@ export class ConfigMap extends KubeObject { data: { [param: string]: string; - } + }; getKeys(): string[] { return Object.keys(this.data); diff --git a/src/renderer/api/endpoints/crd.api.ts b/src/renderer/api/endpoints/crd.api.ts index 1916d71f1b..02690a2afd 100644 --- a/src/renderer/api/endpoints/crd.api.ts +++ b/src/renderer/api/endpoints/crd.api.ts @@ -7,20 +7,20 @@ type AdditionalPrinterColumnsCommon = { type: "integer" | "number" | "string" | "boolean" | "date"; priority: number; description: string; -} +}; export type AdditionalPrinterColumnsV1 = AdditionalPrinterColumnsCommon & { jsonPath: string; -} +}; type AdditionalPrinterColumnsV1Beta = AdditionalPrinterColumnsCommon & { JSONPath: string; -} +}; export class CustomResourceDefinition extends KubeObject { static kind = "CustomResourceDefinition"; static namespaced = false; - static apiBase = "/apis/apiextensions.k8s.io/v1/customresourcedefinitions" + static apiBase = "/apis/apiextensions.k8s.io/v1/customresourcedefinitions"; spec: { group: string; @@ -45,7 +45,7 @@ export class CustomResourceDefinition extends KubeObject { webhook?: any; }; additionalPrinterColumns?: AdditionalPrinterColumnsV1Beta[]; // removed in v1 - } + }; status: { conditions: { lastTransitionTime: string; @@ -62,7 +62,7 @@ export class CustomResourceDefinition extends KubeObject { listKind: string; }; storedVersions: string[]; - } + }; getResourceUrl() { return crdResourcesURL({ @@ -70,25 +70,25 @@ export class CustomResourceDefinition extends KubeObject { group: this.getGroup(), name: this.getPluralName(), } - }) + }); } getResourceApiBase() { const { group } = this.spec; - return `/apis/${group}/${this.getVersion()}/${this.getPluralName()}` + return `/apis/${group}/${this.getVersion()}/${this.getPluralName()}`; } getPluralName() { - return this.getNames().plural + return this.getNames().plural; } getResourceKind() { - return this.spec.names.kind + return this.spec.names.kind; } getResourceTitle() { const name = this.getPluralName(); - return name[0].toUpperCase() + name.substr(1) + return name[0].toUpperCase() + name.substr(1); } getGroup() { @@ -141,7 +141,7 @@ export class CustomResourceDefinition extends KubeObject { ...condition, isReady: status === "True", tooltip: `${message || reason} (${lastTransitionTime})` - } + }; }); } } diff --git a/src/renderer/api/endpoints/cron-job.api.ts b/src/renderer/api/endpoints/cron-job.api.ts index b385647bb9..2cca8bfb3d 100644 --- a/src/renderer/api/endpoints/cron-job.api.ts +++ b/src/renderer/api/endpoints/cron-job.api.ts @@ -7,12 +7,12 @@ import { KubeApi } from "../kube-api"; @autobind() export class CronJob extends KubeObject { - static kind = "CronJob" - static namespaced = true - static apiBase = "/apis/batch/v1beta1/cronjobs" + static kind = "CronJob"; + static namespaced = true; + static apiBase = "/apis/batch/v1beta1/cronjobs"; - kind: string - apiVersion: string + kind: string; + apiVersion: string; metadata: { name: string; namespace: string; @@ -26,7 +26,7 @@ export class CronJob extends KubeObject { annotations: { [key: string]: string; }; - } + }; spec: { schedule: string; concurrencyPolicy: string; @@ -59,23 +59,23 @@ export class CronJob extends KubeObject { }; successfulJobsHistoryLimit: number; failedJobsHistoryLimit: number; - } + }; status: { lastScheduleTime?: string; - } + }; getSuspendFlag() { - return this.spec.suspend.toString() + return this.spec.suspend.toString(); } getLastScheduleTime() { - if (!this.status.lastScheduleTime) return "-" - const diff = moment().diff(this.status.lastScheduleTime) - return formatDuration(diff, true) + if (!this.status.lastScheduleTime) return "-"; + const diff = moment().diff(this.status.lastScheduleTime); + return formatDuration(diff, true); } getSchedule() { - return this.spec.schedule + return this.spec.schedule; } isNeverRun() { diff --git a/src/renderer/api/endpoints/daemon-set.api.ts b/src/renderer/api/endpoints/daemon-set.api.ts index d947293c1c..63fc6363e4 100644 --- a/src/renderer/api/endpoints/daemon-set.api.ts +++ b/src/renderer/api/endpoints/daemon-set.api.ts @@ -6,9 +6,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class DaemonSet extends WorkloadKubeObject { - static kind = "DaemonSet" - static namespaced = true - static apiBase = "/apis/apps/v1/daemonsets" + static kind = "DaemonSet"; + static namespaced = true; + static apiBase = "/apis/apps/v1/daemonsets"; spec: { selector: { @@ -51,7 +51,7 @@ export class DaemonSet extends WorkloadKubeObject { }; }; revisionHistoryLimit: number; - } + }; status: { currentNumberScheduled: number; numberMisscheduled: number; @@ -61,12 +61,12 @@ export class DaemonSet extends WorkloadKubeObject { updatedNumberScheduled: number; numberAvailable: number; numberUnavailable: number; - } + }; getImages() { - const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []) - const initContainers: IPodContainer[] = get(this, "spec.template.spec.initContainers", []) - return [...containers, ...initContainers].map(container => container.image) + const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []); + const initContainers: IPodContainer[] = get(this, "spec.template.spec.initContainers", []); + return [...containers, ...initContainers].map(container => container.image); } } diff --git a/src/renderer/api/endpoints/deployment.api.ts b/src/renderer/api/endpoints/deployment.api.ts index b21495ecc1..28ed71f86a 100644 --- a/src/renderer/api/endpoints/deployment.api.ts +++ b/src/renderer/api/endpoints/deployment.api.ts @@ -6,13 +6,13 @@ import { KubeApi } from "../kube-api"; export class DeploymentApi extends KubeApi { protected getScaleApiUrl(params: { namespace: string; name: string }) { - return this.getUrl(params) + "/scale" + return this.getUrl(params) + "/scale"; } getReplicas(params: { namespace: string; name: string }): Promise { return this.request .get(this.getScaleApiUrl(params)) - .then(({ status }: any) => status?.replicas) + .then(({ status }: any) => status?.replicas); } scale(params: { namespace: string; name: string }, replicas: number) { @@ -23,7 +23,7 @@ export class DeploymentApi extends KubeApi { replicas: replicas } } - }) + }); } restart(params: { namespace: string; name: string }) { @@ -42,15 +42,15 @@ export class DeploymentApi extends KubeApi { headers: { 'content-type': 'application/strategic-merge-patch+json' } - }) + }); } } @autobind() export class Deployment extends WorkloadKubeObject { - static kind = "Deployment" - static namespaced = true - static apiBase = "/apis/apps/v1/deployments" + static kind = "Deployment"; + static namespaced = true; + static apiBase = "/apis/apps/v1/deployments"; spec: { replicas: number; @@ -151,7 +151,7 @@ export class Deployment extends WorkloadKubeObject { maxSurge: number; }; }; - } + }; status: { observedGeneration: number; replicas: number; @@ -167,19 +167,19 @@ export class Deployment extends WorkloadKubeObject { reason: string; message: string; }[]; - } + }; getConditions(activeOnly = false) { - const { conditions } = this.status - if (!conditions) return [] + const { conditions } = this.status; + if (!conditions) return []; if (activeOnly) { - return conditions.filter(c => c.status === "True") + return conditions.filter(c => c.status === "True"); } - return conditions + return conditions; } getConditionsText(activeOnly = true) { - return this.getConditions(activeOnly).map(({ type }) => type).join(" ") + return this.getConditions(activeOnly).map(({ type }) => type).join(" "); } getReplicas() { diff --git a/src/renderer/api/endpoints/endpoint.api.ts b/src/renderer/api/endpoints/endpoint.api.ts index 4f4afc9b17..121836a637 100644 --- a/src/renderer/api/endpoints/endpoint.api.ts +++ b/src/renderer/api/endpoints/endpoint.api.ts @@ -42,22 +42,22 @@ export class EndpointAddress implements IEndpointAddress { }; constructor(data: IEndpointAddress) { - Object.assign(this, data) + Object.assign(this, data); } getId() { - return this.ip + return this.ip; } getName() { - return this.hostname + return this.hostname; } getTargetRef(): ITargetRef { if (this.targetRef) { - return Object.assign(this.targetRef, {apiVersion: "v1"}) + return Object.assign(this.targetRef, {apiVersion: "v1"}); } else { - return null + return null; } } } @@ -68,7 +68,7 @@ export class EndpointSubset implements IEndpointSubset { ports: IEndpointPort[]; constructor(data: IEndpointSubset) { - Object.assign(this, data) + Object.assign(this, data); } getAddresses(): EndpointAddress[] { @@ -83,26 +83,26 @@ export class EndpointSubset implements IEndpointSubset { toString(): string { if(!this.addresses) { - return "" + return ""; } return this.addresses.map(address => { if (!this.ports) { - return address.ip + return address.ip; } return this.ports.map(port => { - return `${address.ip}:${port.port}` - }).join(", ") - }).join(", ") + return `${address.ip}:${port.port}`; + }).join(", "); + }).join(", "); } } @autobind() export class Endpoint extends KubeObject { - static kind = "Endpoints" - static namespaced = true - static apiBase = "/api/v1/endpoints" + static kind = "Endpoints"; + static namespaced = true; + static apiBase = "/api/v1/endpoints"; - subsets: IEndpointSubset[] + subsets: IEndpointSubset[]; getEndpointSubsets(): EndpointSubset[] { const subsets = this.subsets || []; @@ -111,9 +111,9 @@ export class Endpoint extends KubeObject { toString(): string { if(this.subsets) { - return this.getEndpointSubsets().map(es => es.toString()).join(", ") + return this.getEndpointSubsets().map(es => es.toString()).join(", "); } else { - return "" + return ""; } } diff --git a/src/renderer/api/endpoints/events.api.ts b/src/renderer/api/endpoints/events.api.ts index 0608a3d44b..51dbf3c3b5 100644 --- a/src/renderer/api/endpoints/events.api.ts +++ b/src/renderer/api/endpoints/events.api.ts @@ -6,9 +6,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class KubeEvent extends KubeObject { - static kind = "Event" - static namespaced = true - static apiBase = "/api/v1/events" + static kind = "Event"; + static namespaced = true; + static apiBase = "/api/v1/events"; involvedObject: { kind: string; @@ -18,41 +18,41 @@ export class KubeEvent extends KubeObject { apiVersion: string; resourceVersion: string; fieldPath: string; - } - reason: string - message: string + }; + reason: string; + message: string; source: { component: string; host: string; - } - firstTimestamp: string - lastTimestamp: string - count: number - type: string - eventTime: null - reportingComponent: string - reportingInstance: string + }; + firstTimestamp: string; + lastTimestamp: string; + count: number; + type: string; + eventTime: null; + reportingComponent: string; + reportingInstance: string; isWarning() { return this.type === "Warning"; } getSource() { - const { component, host } = this.source - return `${component} ${host || ""}` + const { component, host } = this.source; + return `${component} ${host || ""}`; } getFirstSeenTime() { - const diff = moment().diff(this.firstTimestamp) - return formatDuration(diff, true) + const diff = moment().diff(this.firstTimestamp); + return formatDuration(diff, true); } getLastSeenTime() { - const diff = moment().diff(this.lastTimestamp) - return formatDuration(diff, true) + const diff = moment().diff(this.lastTimestamp); + return formatDuration(diff, true); } } export const eventApi = new KubeApi({ objectConstructor: KubeEvent, -}) +}); diff --git a/src/renderer/api/endpoints/helm-charts.api.ts b/src/renderer/api/endpoints/helm-charts.api.ts index 8943cd49df..e6328f136b 100644 --- a/src/renderer/api/endpoints/helm-charts.api.ts +++ b/src/renderer/api/endpoints/helm-charts.api.ts @@ -41,7 +41,7 @@ export const helmChartsApi = { return { readme, versions, - } + }; }); }, @@ -61,27 +61,27 @@ export class HelmChart { return new HelmChart(data); } - apiVersion: string - name: string - version: string - repo: string - kubeVersion?: string - created: string - description?: string - digest: string - keywords?: string[] - home?: string - sources?: string[] + apiVersion: string; + name: string; + version: string; + repo: string; + kubeVersion?: string; + created: string; + description?: string; + digest: string; + keywords?: string[]; + home?: string; + sources?: string[]; maintainers?: { name: string; email: string; url: string; - }[] - engine?: string - icon?: string - appVersion?: string - deprecated?: boolean - tillerVersion?: string + }[]; + engine?: string; + icon?: string; + appVersion?: string; + deprecated?: boolean; + tillerVersion?: string; getId() { return this.digest; diff --git a/src/renderer/api/endpoints/helm-releases.api.ts b/src/renderer/api/endpoints/helm-releases.api.ts index 9051936ac8..0ddbf1c734 100644 --- a/src/renderer/api/endpoints/helm-releases.api.ts +++ b/src/renderer/api/endpoints/helm-releases.api.ts @@ -82,7 +82,7 @@ export const helmReleasesApi = { return { ...details, resources - } + }; }); }, @@ -135,13 +135,13 @@ export class HelmRelease implements ItemObject { return new HelmRelease(data); } - appVersion: string - name: string - namespace: string - chart: string - status: string - updated: string - revision: string + appVersion: string; + name: string; + namespace: string; + chart: string; + status: string; + updated: string; + revision: string; getId() { return this.namespace + this.name; @@ -156,12 +156,12 @@ export class HelmRelease implements ItemObject { } getChart(withVersion = false) { - let chart = this.chart + let chart = this.chart; if(!withVersion && this.getVersion() != "" ) { - const search = new RegExp(`-${this.getVersion()}`) + const search = new RegExp(`-${this.getVersion()}`); chart = chart.replace(search, ""); } - return chart + return chart; } getRevision() { @@ -173,12 +173,12 @@ export class HelmRelease implements ItemObject { } getVersion() { - const versions = this.chart.match(/(v?\d+)[^-].*$/) + const versions = this.chart.match(/(v?\d+)[^-].*$/); if (versions) { - return versions[0] + return versions[0]; } else { - return "" + return ""; } } diff --git a/src/renderer/api/endpoints/hpa.api.ts b/src/renderer/api/endpoints/hpa.api.ts index f55f6d327f..79e6cada0f 100644 --- a/src/renderer/api/endpoints/hpa.api.ts +++ b/src/renderer/api/endpoints/hpa.api.ts @@ -20,7 +20,7 @@ export type IHpaMetricData = T & { currentAverageValue?: string; targetAverageUtilization?: number; targetAverageValue?: string; -} +}; export interface IHpaMetric { [kind: string]: IHpaMetricData; @@ -41,7 +41,7 @@ export interface IHpaMetric { export class HorizontalPodAutoscaler extends KubeObject { static kind = "HorizontalPodAutoscaler"; static namespaced = true; - static apiBase = "/apis/autoscaling/v2beta1/horizontalpodautoscalers" + static apiBase = "/apis/autoscaling/v2beta1/horizontalpodautoscalers"; spec: { scaleTargetRef: { @@ -52,7 +52,7 @@ export class HorizontalPodAutoscaler extends KubeObject { minReplicas: number; maxReplicas: number; metrics: IHpaMetric[]; - } + }; status: { currentReplicas: number; desiredReplicas: number; @@ -64,7 +64,7 @@ export class HorizontalPodAutoscaler extends KubeObject { status: string; type: string; }[]; - } + }; getMaxPods() { return this.spec.maxReplicas || 0; @@ -86,7 +86,7 @@ export class HorizontalPodAutoscaler extends KubeObject { ...condition, isReady: status === "True", tooltip: `${message || reason} (${lastTransitionTime})` - } + }; }); } @@ -102,7 +102,7 @@ export class HorizontalPodAutoscaler extends KubeObject { const { type, resource, pods, object, external } = metric; switch (type) { case HpaMetricType.Resource: - return resource.name + return resource.name; case HpaMetricType.Pods: return pods.metricName; case HpaMetricType.Object: @@ -128,7 +128,7 @@ export class HorizontalPodAutoscaler extends KubeObject { } if (target) { targetValue = target.targetAverageUtilization || target.targetAverageValue || target.targetValue; - if (target.targetAverageUtilization) targetValue += "%" + if (target.targetAverageUtilization) targetValue += "%"; } return `${currentValue} / ${targetValue}`; } diff --git a/src/renderer/api/endpoints/index.ts b/src/renderer/api/endpoints/index.ts index 337d193043..f1202b9122 100644 --- a/src/renderer/api/endpoints/index.ts +++ b/src/renderer/api/endpoints/index.ts @@ -1,35 +1,35 @@ // Kubernetes apis // Docs: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/ -export * from "./cluster.api" -export * from "./cluster-role.api" -export * from "./cluster-role-binding.api" -export * from "./configmap.api" -export * from "./crd.api" -export * from "./cron-job.api" -export * from "./daemon-set.api" -export * from "./deployment.api" -export * from "./endpoint.api" -export * from "./events.api" -export * from "./hpa.api" -export * from "./ingress.api" -export * from "./job.api" -export * from "./namespaces.api" -export * from "./network-policy.api" -export * from "./nodes.api" -export * from "./persistent-volume.api" -export * from "./persistent-volume-claims.api" -export * from "./pods.api" -export * from "./poddisruptionbudget.api" -export * from "./pod-metrics.api" -export * from "./podsecuritypolicy.api" -export * from "./replica-set.api" -export * from "./resource-quota.api" -export * from "./role.api" -export * from "./role-binding.api" -export * from "./secret.api" -export * from "./selfsubjectrulesreviews.api" -export * from "./service.api" -export * from "./service-accounts.api" -export * from "./stateful-set.api" -export * from "./storage-class.api" +export * from "./cluster.api"; +export * from "./cluster-role.api"; +export * from "./cluster-role-binding.api"; +export * from "./configmap.api"; +export * from "./crd.api"; +export * from "./cron-job.api"; +export * from "./daemon-set.api"; +export * from "./deployment.api"; +export * from "./endpoint.api"; +export * from "./events.api"; +export * from "./hpa.api"; +export * from "./ingress.api"; +export * from "./job.api"; +export * from "./namespaces.api"; +export * from "./network-policy.api"; +export * from "./nodes.api"; +export * from "./persistent-volume.api"; +export * from "./persistent-volume-claims.api"; +export * from "./pods.api"; +export * from "./poddisruptionbudget.api"; +export * from "./pod-metrics.api"; +export * from "./podsecuritypolicy.api"; +export * from "./replica-set.api"; +export * from "./resource-quota.api"; +export * from "./role.api"; +export * from "./role-binding.api"; +export * from "./secret.api"; +export * from "./selfsubjectrulesreviews.api"; +export * from "./service.api"; +export * from "./service-accounts.api"; +export * from "./stateful-set.api"; +export * from "./storage-class.api"; diff --git a/src/renderer/api/endpoints/ingress.api.ts b/src/renderer/api/endpoints/ingress.api.ts index 1f3e1659f0..0594e3446e 100644 --- a/src/renderer/api/endpoints/ingress.api.ts +++ b/src/renderer/api/endpoints/ingress.api.ts @@ -5,7 +5,7 @@ import { KubeApi } from "../kube-api"; export class IngressApi extends KubeApi { getMetrics(ingress: string, namespace: string): Promise { - const opts = { category: "ingress", ingress } + const opts = { category: "ingress", ingress }; return metricsApi.getMetrics({ bytesSentSuccess: opts, bytesSentFailure: opts, @@ -31,9 +31,9 @@ export interface ILoadBalancerIngress { } @autobind() export class Ingress extends KubeObject { - static kind = "Ingress" - static namespaced = true - static apiBase = "/apis/extensions/v1beta1/ingresses" + static kind = "Ingress"; + static namespaced = true; + static apiBase = "/apis/extensions/v1beta1/ingresses"; spec: { tls: { @@ -55,59 +55,59 @@ export class Ingress extends KubeObject { serviceName: string; servicePort: number; }; - } + }; status: { loadBalancer: { ingress: ILoadBalancerIngress[]; }; - } + }; getRoutes() { - const { spec: { tls, rules } } = this - if (!rules) return [] + const { spec: { tls, rules } } = this; + if (!rules) return []; - let protocol = "http" - const routes: string[] = [] + let protocol = "http"; + const routes: string[] = []; if (tls && tls.length > 0) { - protocol += "s" + protocol += "s"; } rules.map(rule => { - const host = rule.host ? rule.host : "*" + const host = rule.host ? rule.host : "*"; if (rule.http && rule.http.paths) { rule.http.paths.forEach(path => { - routes.push(protocol + "://" + host + (path.path || "/") + " ⇢ " + path.backend.serviceName + ":" + path.backend.servicePort) - }) + routes.push(protocol + "://" + host + (path.path || "/") + " ⇢ " + path.backend.serviceName + ":" + path.backend.servicePort); + }); } - }) + }); return routes; } getHosts() { - const { spec: { rules } } = this - if (!rules) return [] - return rules.filter(rule => rule.host).map(rule => rule.host) + const { spec: { rules } } = this; + if (!rules) return []; + return rules.filter(rule => rule.host).map(rule => rule.host); } getPorts() { - const ports: number[] = [] - const { spec: { tls, rules, backend } } = this - const httpPort = 80 - const tlsPort = 443 + const ports: number[] = []; + const { spec: { tls, rules, backend } } = this; + const httpPort = 80; + const tlsPort = 443; if (rules && rules.length > 0) { if (rules.some(rule => rule.hasOwnProperty("http"))) { - ports.push(httpPort) + ports.push(httpPort); } } else { if (backend && backend.servicePort) { - ports.push(backend.servicePort) + ports.push(backend.servicePort); } } if (tls && tls.length > 0) { - ports.push(tlsPort) + ports.push(tlsPort); } - return ports.join(", ") + return ports.join(", "); } getLoadBalancers() { @@ -115,7 +115,7 @@ export class Ingress extends KubeObject { return (loadBalancer.ingress ?? []).map(address => ( address.hostname || address.ip - )) + )); } } diff --git a/src/renderer/api/endpoints/job.api.ts b/src/renderer/api/endpoints/job.api.ts index 59e9e9ba8f..1dc78fdc94 100644 --- a/src/renderer/api/endpoints/job.api.ts +++ b/src/renderer/api/endpoints/job.api.ts @@ -7,9 +7,9 @@ import { JsonApiParams } from "../json-api"; @autobind() export class Job extends WorkloadKubeObject { - static kind = "Job" - static namespaced = true - static apiBase = "/apis/batch/v1/jobs" + static kind = "Job"; + static namespaced = true; + static apiBase = "/apis/batch/v1/jobs"; spec: { parallelism?: number; @@ -56,7 +56,7 @@ export class Job extends WorkloadKubeObject { serviceAccountName?: string; serviceAccount?: string; schedulerName?: string; - } + }; status: { conditions: { type: string; @@ -68,7 +68,7 @@ export class Job extends WorkloadKubeObject { startTime: string; completionTime: string; succeeded: number; - } + }; getDesiredCompletions() { return this.spec.completions || 0; @@ -91,15 +91,15 @@ export class Job extends WorkloadKubeObject { } getImages() { - const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []) - return [...containers].map(container => container.image) + const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []); + return [...containers].map(container => container.image); } delete() { const params: JsonApiParams = { query: { propagationPolicy: "Background" } - } - return super.delete(params) + }; + return super.delete(params); } } diff --git a/src/renderer/api/endpoints/metrics.api.ts b/src/renderer/api/endpoints/metrics.api.ts index 81d2f1d500..7f30487d44 100644 --- a/src/renderer/api/endpoints/metrics.api.ts +++ b/src/renderer/api/endpoints/metrics.api.ts @@ -66,7 +66,7 @@ export function normalizeMetrics(metrics: IMetrics, frames = 60): IMetrics { } as IMetricsResult], }, status: "", - } + }; } const { result } = metrics.data; @@ -78,7 +78,7 @@ export function normalizeMetrics(metrics: IMetrics, frames = 60): IMetrics { if (!res.values || !res.values.length) return; while (res.values.length < frames) { const timestamp = moment.unix(res.values[0][0]).subtract(1, "minute").unix(); - res.values.unshift([timestamp, "0"]) + res.values.unshift([timestamp, "0"]); } }); } @@ -103,7 +103,7 @@ export function getItemMetrics(metrics: { [key: string]: IMetrics }, itemName: s const itemMetrics = { ...metrics }; for (const metric in metrics) { if (!metrics[metric]?.data?.result) { - continue + continue; } const results = metrics[metric].data.result; const result = results.find(res => Object.values(res.metric)[0] == itemName); diff --git a/src/renderer/api/endpoints/namespaces.api.ts b/src/renderer/api/endpoints/namespaces.api.ts index c615789cd9..430565bf57 100644 --- a/src/renderer/api/endpoints/namespaces.api.ts +++ b/src/renderer/api/endpoints/namespaces.api.ts @@ -15,7 +15,7 @@ export class Namespace extends KubeObject { status?: { phase: string; - } + }; getStatus() { return this.status ? this.status.phase : "-"; diff --git a/src/renderer/api/endpoints/network-policy.api.ts b/src/renderer/api/endpoints/network-policy.api.ts index bfae6cbcdc..4ecd333854 100644 --- a/src/renderer/api/endpoints/network-policy.api.ts +++ b/src/renderer/api/endpoints/network-policy.api.ts @@ -37,9 +37,9 @@ export interface IPolicyEgress { @autobind() export class NetworkPolicy extends KubeObject { - static kind = "NetworkPolicy" - static namespaced = true - static apiBase = "/apis/networking.k8s.io/v1/networkpolicies" + static kind = "NetworkPolicy"; + static namespaced = true; + static apiBase = "/apis/networking.k8s.io/v1/networkpolicies"; spec: { podSelector: { @@ -51,13 +51,13 @@ export class NetworkPolicy extends KubeObject { policyTypes: string[]; ingress: IPolicyIngress[]; egress: IPolicyEgress[]; - } + }; getMatchLabels(): string[] { if (!this.spec.podSelector || !this.spec.podSelector.matchLabels) return []; return Object .entries(this.spec.podSelector.matchLabels) - .map(data => data.join(":")) + .map(data => data.join(":")); } getTypes(): string[] { diff --git a/src/renderer/api/endpoints/nodes.api.ts b/src/renderer/api/endpoints/nodes.api.ts index f8031a9824..c85cd8f9b0 100644 --- a/src/renderer/api/endpoints/nodes.api.ts +++ b/src/renderer/api/endpoints/nodes.api.ts @@ -5,7 +5,7 @@ import { KubeApi } from "../kube-api"; export class NodesApi extends KubeApi { getMetrics(): Promise { - const opts = { category: "nodes"} + const opts = { category: "nodes"}; return metricsApi.getMetrics({ memoryUsage: opts, @@ -30,9 +30,9 @@ export interface INodeMetrics { @autobind() export class Node extends KubeObject { - static kind = "Node" - static namespaced = false - static apiBase = "/api/v1/nodes" + static kind = "Node"; + static namespaced = false; + static apiBase = "/api/v1/nodes"; spec: { podCIDR: string; @@ -43,7 +43,7 @@ export class Node extends KubeObject { effect: string; }[]; unschedulable?: boolean; - } + }; status: { capacity: { cpu: string; @@ -83,15 +83,15 @@ export class Node extends KubeObject { names: string[]; sizeBytes: number; }[]; - } + }; getNodeConditionText() { - const { conditions } = this.status - if (!conditions) return "" + const { conditions } = this.status; + if (!conditions) return ""; return conditions.reduce((types, current) => { - if (current.status !== "True") return "" - return types += ` ${current.type}` - }, "") + if (current.status !== "True") return ""; + return types += ` ${current.type}`; + }, ""); } getTaints() { @@ -101,23 +101,23 @@ export class Node extends KubeObject { getRoleLabels() { const roleLabels = Object.keys(this.metadata.labels).filter(key => key.includes("node-role.kubernetes.io") - ).map(key => key.match(/([^/]+$)/)[0]) // all after last slash + ).map(key => key.match(/([^/]+$)/)[0]); // all after last slash if (this.metadata.labels["kubernetes.io/role"] != undefined) { - roleLabels.push(this.metadata.labels["kubernetes.io/role"]) + roleLabels.push(this.metadata.labels["kubernetes.io/role"]); } - return roleLabels.join(", ") + return roleLabels.join(", "); } getCpuCapacity() { - if (!this.status.capacity || !this.status.capacity.cpu) return 0 - return cpuUnitsToNumber(this.status.capacity.cpu) + if (!this.status.capacity || !this.status.capacity.cpu) return 0; + return cpuUnitsToNumber(this.status.capacity.cpu); } getMemoryCapacity() { - if (!this.status.capacity || !this.status.capacity.memory) return 0 - return unitsToBytes(this.status.capacity.memory) + if (!this.status.capacity || !this.status.capacity.memory) return 0; + return unitsToBytes(this.status.capacity.memory); } getConditions() { @@ -144,16 +144,16 @@ export class Node extends KubeObject { } getOperatingSystem(): string { - const label = this.getLabels().find(label => label.startsWith("kubernetes.io/os=")) + const label = this.getLabels().find(label => label.startsWith("kubernetes.io/os=")); if (label) { - return label.split("=", 2)[1] + return label.split("=", 2)[1]; } - return "linux" + return "linux"; } isUnschedulable() { - return this.spec.unschedulable + return this.spec.unschedulable; } } diff --git a/src/renderer/api/endpoints/persistent-volume-claims.api.ts b/src/renderer/api/endpoints/persistent-volume-claims.api.ts index 4e719c529b..9aa73bb0bc 100644 --- a/src/renderer/api/endpoints/persistent-volume-claims.api.ts +++ b/src/renderer/api/endpoints/persistent-volume-claims.api.ts @@ -23,9 +23,9 @@ export interface IPvcMetrics { @autobind() export class PersistentVolumeClaim extends KubeObject { - static kind = "PersistentVolumeClaim" - static namespaced = true - static apiBase = "/api/v1/persistentvolumeclaims" + static kind = "PersistentVolumeClaim"; + static namespaced = true; + static apiBase = "/api/v1/persistentvolumeclaims"; spec: { accessModes: string[]; @@ -45,19 +45,19 @@ export class PersistentVolumeClaim extends KubeObject { storage: string; // 8Gi }; }; - } + }; status: { phase: string; // Pending - } + }; getPods(allPods: Pod[]): Pod[] { - const pods = allPods.filter(pod => pod.getNs() === this.getNs()) + const pods = allPods.filter(pod => pod.getNs() === this.getNs()); return pods.filter(pod => { return pod.getVolumes().filter(volume => volume.persistentVolumeClaim && volume.persistentVolumeClaim.claimName === this.getName() - ).length > 0 - }) + ).length > 0; + }); } getStorage(): string { @@ -78,7 +78,7 @@ export class PersistentVolumeClaim extends KubeObject { getStatus(): string { if (this.status) return this.status.phase; - return "-" + return "-"; } } diff --git a/src/renderer/api/endpoints/persistent-volume.api.ts b/src/renderer/api/endpoints/persistent-volume.api.ts index 8ab2efbf89..5e31eeb028 100644 --- a/src/renderer/api/endpoints/persistent-volume.api.ts +++ b/src/renderer/api/endpoints/persistent-volume.api.ts @@ -5,9 +5,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class PersistentVolume extends KubeObject { - static kind = "PersistentVolume" - static namespaced = false - static apiBase = "/api/v1/persistentvolumes" + static kind = "PersistentVolume"; + static namespaced = false; + static apiBase = "/api/v1/persistentvolumes"; spec: { capacity: { @@ -38,17 +38,17 @@ export class PersistentVolume extends KubeObject { path: string; server: string; }; - } + }; status: { phase: string; reason?: string; - } + }; getCapacity(inBytes = false) { const capacity = this.spec.capacity; if (capacity) { - if (inBytes) return unitsToBytes(capacity.storage) + if (inBytes) return unitsToBytes(capacity.storage); return capacity.storage; } return 0; diff --git a/src/renderer/api/endpoints/pod-metrics.api.ts b/src/renderer/api/endpoints/pod-metrics.api.ts index 7e01a1a990..acf6e7b20f 100644 --- a/src/renderer/api/endpoints/pod-metrics.api.ts +++ b/src/renderer/api/endpoints/pod-metrics.api.ts @@ -2,19 +2,19 @@ import { KubeObject } from "../kube-object"; import { KubeApi } from "../kube-api"; export class PodMetrics extends KubeObject { - static kind = "Pod" - static namespaced = true - static apiBase = "/apis/metrics.k8s.io/v1beta1/pods" + static kind = "Pod"; + static namespaced = true; + static apiBase = "/apis/metrics.k8s.io/v1beta1/pods"; - timestamp: string - window: string + timestamp: string; + window: string; containers: { name: string; usage: { cpu: string; memory: string; }; - }[] + }[]; } export const podMetricsApi = new KubeApi({ diff --git a/src/renderer/api/endpoints/poddisruptionbudget.api.ts b/src/renderer/api/endpoints/poddisruptionbudget.api.ts index ea7e0575ff..b76260ae6f 100644 --- a/src/renderer/api/endpoints/poddisruptionbudget.api.ts +++ b/src/renderer/api/endpoints/poddisruptionbudget.api.ts @@ -12,13 +12,13 @@ export class PodDisruptionBudget extends KubeObject { minAvailable: string; maxUnavailable: string; selector: { matchLabels: { [app: string]: string } }; - } + }; status: { currentHealthy: number desiredHealthy: number disruptionsAllowed: number expectedPods: number - } + }; getSelectors() { const selector = this.spec.selector; diff --git a/src/renderer/api/endpoints/pods.api.ts b/src/renderer/api/endpoints/pods.api.ts index 92b7059272..a5c833b5fa 100644 --- a/src/renderer/api/endpoints/pods.api.ts +++ b/src/renderer/api/endpoints/pods.api.ts @@ -11,7 +11,7 @@ export class PodsApi extends KubeApi { getMetrics(pods: Pod[], namespace: string, selector = "pod, namespace"): Promise { const podSelector = pods.map(pod => pod.getName()).join("|"); - const opts = { category: "pods", pods: podSelector, namespace, selector } + const opts = { category: "pods", pods: podSelector, namespace, selector }; return metricsApi.getMetrics({ cpuUsage: opts, @@ -171,9 +171,9 @@ export interface IPodContainerStatus { @autobind() export class Pod extends WorkloadKubeObject { - static kind = "Pod" - static namespaced = true - static apiBase = "/api/v1/pods" + static kind = "Pod"; + static namespaced = true; + static apiBase = "/api/v1/pods"; spec: { volumes?: { @@ -215,7 +215,7 @@ export class Pod extends WorkloadKubeObject { tolerationSeconds: number; }[]; affinity: IAffinity; - } + }; status: { phase: string; conditions: { @@ -231,7 +231,7 @@ export class Pod extends WorkloadKubeObject { containerStatuses?: IPodContainerStatus[]; qosClass: string; reason?: string; - } + }; getInitContainers() { return this.spec.initContainers || []; @@ -246,11 +246,11 @@ export class Pod extends WorkloadKubeObject { } getRunningContainers() { - const statuses = this.getContainerStatuses() + const statuses = this.getContainerStatuses(); return this.getAllContainers().filter(container => { - return statuses.find(status => status.name === container.name && !!status.state["running"]) + return statuses.find(status => status.name === container.name && !!status.state["running"]); } - ) + ); } getContainerStatuses(includeInitContainers = true) { @@ -323,7 +323,7 @@ export class Pod extends WorkloadKubeObject { const { reason } = state.terminated; message = reason ? reason : "Terminated"; } - }) + }); } if (message) return message; return this.getStatusPhase(); @@ -348,32 +348,32 @@ export class Pod extends WorkloadKubeObject { } getNodeSelectors(): string[] { - const { nodeSelector } = this.spec - if (!nodeSelector) return [] - return Object.entries(nodeSelector).map(values => values.join(": ")) + const { nodeSelector } = this.spec; + if (!nodeSelector) return []; + return Object.entries(nodeSelector).map(values => values.join(": ")); } getTolerations() { - return this.spec.tolerations || [] + return this.spec.tolerations || []; } getAffinity(): IAffinity { - return this.spec.affinity + return this.spec.affinity; } hasIssues() { const notReady = !!this.getConditions().find(condition => { - return condition.type == "Ready" && condition.status !== "True" + return condition.type == "Ready" && condition.status !== "True"; }); const crashLoop = !!this.getContainerStatuses().find(condition => { - const waiting = condition.state.waiting - return (waiting && waiting.reason == "CrashLoopBackOff") - }) + const waiting = condition.state.waiting; + return (waiting && waiting.reason == "CrashLoopBackOff"); + }); return ( notReady || crashLoop || this.getStatusPhase() !== "Running" - ) + ); } getLivenessProbe(container: IPodContainer) { @@ -418,14 +418,14 @@ export class Pod extends WorkloadKubeObject { } getNodeName() { - return this.spec?.nodeName + return this.spec?.nodeName; } getSelectedNodeOs() { - if (!this.spec.nodeSelector) return - if (!this.spec.nodeSelector["kubernetes.io/os"] && !this.spec.nodeSelector["beta.kubernetes.io/os"]) return + if (!this.spec.nodeSelector) return; + if (!this.spec.nodeSelector["kubernetes.io/os"] && !this.spec.nodeSelector["beta.kubernetes.io/os"]) return; - return this.spec.nodeSelector["kubernetes.io/os"] || this.spec.nodeSelector["beta.kubernetes.io/os"] + return this.spec.nodeSelector["kubernetes.io/os"] || this.spec.nodeSelector["beta.kubernetes.io/os"]; } } diff --git a/src/renderer/api/endpoints/podsecuritypolicy.api.ts b/src/renderer/api/endpoints/podsecuritypolicy.api.ts index aa705c8748..c7981f65be 100644 --- a/src/renderer/api/endpoints/podsecuritypolicy.api.ts +++ b/src/renderer/api/endpoints/podsecuritypolicy.api.ts @@ -4,9 +4,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class PodSecurityPolicy extends KubeObject { - static kind = "PodSecurityPolicy" - static namespaced = false - static apiBase = "/apis/policy/v1beta1/podsecuritypolicies" + static kind = "PodSecurityPolicy"; + static namespaced = false; + static apiBase = "/apis/policy/v1beta1/podsecuritypolicies"; spec: { allowPrivilegeEscalation?: boolean; @@ -66,7 +66,7 @@ export class PodSecurityPolicy extends KubeObject { ranges: { max: number; min: number }[]; }; volumes?: string[]; - } + }; isPrivileged() { return !!this.spec.privileged; diff --git a/src/renderer/api/endpoints/replica-set.api.ts b/src/renderer/api/endpoints/replica-set.api.ts index dd06299644..d1081811e9 100644 --- a/src/renderer/api/endpoints/replica-set.api.ts +++ b/src/renderer/api/endpoints/replica-set.api.ts @@ -6,9 +6,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class ReplicaSet extends WorkloadKubeObject { - static kind = "ReplicaSet" - static namespaced = true - static apiBase = "/apis/apps/v1/replicasets" + static kind = "ReplicaSet"; + static namespaced = true; + static apiBase = "/apis/apps/v1/replicasets"; spec: { replicas?: number; @@ -37,18 +37,18 @@ export class ReplicaSet extends WorkloadKubeObject { terminationGracePeriodSeconds?: number; dnsPolicy?: string; schedulerName?: string; - } + }; status: { replicas: number; fullyLabeledReplicas: number; readyReplicas: number; availableReplicas: number; observedGeneration: number; - } + }; getImages() { - const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []) - return [...containers].map(container => container.image) + const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []); + return [...containers].map(container => container.image); } } diff --git a/src/renderer/api/endpoints/resource-applier.api.ts b/src/renderer/api/endpoints/resource-applier.api.ts index 088c7ed8f2..a2843a6262 100644 --- a/src/renderer/api/endpoints/resource-applier.api.ts +++ b/src/renderer/api/endpoints/resource-applier.api.ts @@ -1,4 +1,4 @@ -import jsYaml from "js-yaml" +import jsYaml from "js-yaml"; import { KubeObject } from "../kube-object"; import { KubeJsonApiData } from "../kube-json-api"; import { apiBase } from "../index"; @@ -21,7 +21,7 @@ export const resourceApplierApi = { if (api) { return new api.objectConstructor(obj); } else { - return new KubeObject(obj) + return new KubeObject(obj); } }); return items.length === 1 ? items[0] : items; diff --git a/src/renderer/api/endpoints/resource-quota.api.ts b/src/renderer/api/endpoints/resource-quota.api.ts index ce73d24595..a19e4025c5 100644 --- a/src/renderer/api/endpoints/resource-quota.api.ts +++ b/src/renderer/api/endpoints/resource-quota.api.ts @@ -31,13 +31,13 @@ export interface IResourceQuotaValues { } export class ResourceQuota extends KubeObject { - static kind = "ResourceQuota" - static namespaced = true - static apiBase = "/api/v1/resourcequotas" + static kind = "ResourceQuota"; + static namespaced = true; + static apiBase = "/api/v1/resourcequotas"; constructor(data: KubeJsonApiData) { super(data); - this.spec = this.spec || {} as any + this.spec = this.spec || {} as any; } spec: { @@ -49,12 +49,12 @@ export class ResourceQuota extends KubeObject { values: string[]; }[]; }; - } + }; status: { hard: IResourceQuotaValues; used: IResourceQuotaValues; - } + }; getScopeSelector() { const { matchExpressions = [] } = this.spec.scopeSelector || {}; diff --git a/src/renderer/api/endpoints/role-binding.api.ts b/src/renderer/api/endpoints/role-binding.api.ts index 455e2c6e4d..866656ee56 100644 --- a/src/renderer/api/endpoints/role-binding.api.ts +++ b/src/renderer/api/endpoints/role-binding.api.ts @@ -11,23 +11,23 @@ export interface IRoleBindingSubject { @autobind() export class RoleBinding extends KubeObject { - static kind = "RoleBinding" - static namespaced = true - static apiBase = "/apis/rbac.authorization.k8s.io/v1/rolebindings" + static kind = "RoleBinding"; + static namespaced = true; + static apiBase = "/apis/rbac.authorization.k8s.io/v1/rolebindings"; - subjects?: IRoleBindingSubject[] + subjects?: IRoleBindingSubject[]; roleRef: { kind: string; name: string; apiGroup?: string; - } + }; getSubjects() { return this.subjects || []; } getSubjectNames(): string { - return this.getSubjects().map(subject => subject.name).join(", ") + return this.getSubjects().map(subject => subject.name).join(", "); } } diff --git a/src/renderer/api/endpoints/role.api.ts b/src/renderer/api/endpoints/role.api.ts index 400761cfbe..c89834ed05 100644 --- a/src/renderer/api/endpoints/role.api.ts +++ b/src/renderer/api/endpoints/role.api.ts @@ -2,16 +2,16 @@ import { KubeObject } from "../kube-object"; import { KubeApi } from "../kube-api"; export class Role extends KubeObject { - static kind = "Role" - static namespaced = true - static apiBase = "/apis/rbac.authorization.k8s.io/v1/roles" + static kind = "Role"; + static namespaced = true; + static apiBase = "/apis/rbac.authorization.k8s.io/v1/roles"; rules: { verbs: string[]; apiGroups: string[]; resources: string[]; resourceNames?: string[]; - }[] + }[]; getRules() { return this.rules || []; diff --git a/src/renderer/api/endpoints/secret.api.ts b/src/renderer/api/endpoints/secret.api.ts index f2166abbe1..16262570df 100644 --- a/src/renderer/api/endpoints/secret.api.ts +++ b/src/renderer/api/endpoints/secret.api.ts @@ -21,15 +21,15 @@ export interface ISecretRef { @autobind() export class Secret extends KubeObject { - static kind = "Secret" - static namespaced = true - static apiBase = "/api/v1/secrets" + static kind = "Secret"; + static namespaced = true; + static apiBase = "/api/v1/secrets"; type: SecretType; data: { [prop: string]: string; token?: string; - } + }; constructor(data: KubeJsonApiData) { super(data); diff --git a/src/renderer/api/endpoints/selfsubjectrulesreviews.api.ts b/src/renderer/api/endpoints/selfsubjectrulesreviews.api.ts index 1beece3fc3..149a94e678 100644 --- a/src/renderer/api/endpoints/selfsubjectrulesreviews.api.ts +++ b/src/renderer/api/endpoints/selfsubjectrulesreviews.api.ts @@ -21,20 +21,20 @@ export interface ISelfSubjectReviewRule { } export class SelfSubjectRulesReview extends KubeObject { - static kind = "SelfSubjectRulesReview" - static namespaced = false - static apiBase = "/apis/authorization.k8s.io/v1/selfsubjectrulesreviews" + static kind = "SelfSubjectRulesReview"; + static namespaced = false; + static apiBase = "/apis/authorization.k8s.io/v1/selfsubjectrulesreviews"; spec: { // todo: add more types from api docs namespace?: string; - } + }; status: { resourceRules: ISelfSubjectReviewRule[]; nonResourceRules: ISelfSubjectReviewRule[]; incomplete: boolean; - } + }; getResourceRules() { const rules = this.status && this.status.resourceRules || []; @@ -58,7 +58,7 @@ export class SelfSubjectRulesReview extends KubeObject { const separator = apiGroup == "" ? "" : "."; return resource + separator + apiGroup; }) - } + }; } } diff --git a/src/renderer/api/endpoints/service-accounts.api.ts b/src/renderer/api/endpoints/service-accounts.api.ts index 4f3ae47014..9f449cdec4 100644 --- a/src/renderer/api/endpoints/service-accounts.api.ts +++ b/src/renderer/api/endpoints/service-accounts.api.ts @@ -6,14 +6,14 @@ import { KubeApi } from "../kube-api"; export class ServiceAccount extends KubeObject { static kind = "ServiceAccount"; static namespaced = true; - static apiBase = "/api/v1/serviceaccounts" + static apiBase = "/api/v1/serviceaccounts"; secrets?: { name: string; - }[] + }[]; imagePullSecrets?: { name: string; - }[] + }[]; getSecrets() { return this.secrets || []; diff --git a/src/renderer/api/endpoints/service.api.ts b/src/renderer/api/endpoints/service.api.ts index 49ac733220..5524e85263 100644 --- a/src/renderer/api/endpoints/service.api.ts +++ b/src/renderer/api/endpoints/service.api.ts @@ -17,7 +17,7 @@ export class ServicePort implements IServicePort { nodePort?: number; constructor(data: IServicePort) { - Object.assign(this, data) + Object.assign(this, data); } toString() { @@ -31,9 +31,9 @@ export class ServicePort implements IServicePort { @autobind() export class Service extends KubeObject { - static kind = "Service" - static namespaced = true - static apiBase = "/api/v1/services" + static kind = "Service"; + static namespaced = true; + static apiBase = "/api/v1/services"; spec: { type: string; @@ -44,7 +44,7 @@ export class Service extends KubeObject { selector: { [key: string]: string }; ports: ServicePort[]; externalIPs?: string[]; // https://kubernetes.io/docs/concepts/services-networking/service/#external-ips - } + }; status: { loadBalancer?: { @@ -53,7 +53,7 @@ export class Service extends KubeObject { hostname?: string; }[]; }; - } + }; getClusterIp() { return this.spec.clusterIP; @@ -62,7 +62,7 @@ export class Service extends KubeObject { getExternalIps() { const lb = this.getLoadBalancer(); if (lb && lb.ingress) { - return lb.ingress.map(val => val.ip || val.hostname) + return lb.ingress.map(val => val.ip || val.hostname); } return this.spec.externalIPs || []; } diff --git a/src/renderer/api/endpoints/stateful-set.api.ts b/src/renderer/api/endpoints/stateful-set.api.ts index c507e7df59..6a6f8c151d 100644 --- a/src/renderer/api/endpoints/stateful-set.api.ts +++ b/src/renderer/api/endpoints/stateful-set.api.ts @@ -6,9 +6,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class StatefulSet extends WorkloadKubeObject { - static kind = "StatefulSet" - static namespaced = true - static apiBase = "/apis/apps/v1/statefulsets" + static kind = "StatefulSet"; + static namespaced = true; + static apiBase = "/apis/apps/v1/statefulsets"; spec: { serviceName: string; @@ -62,7 +62,7 @@ export class StatefulSet extends WorkloadKubeObject { }; }; }[]; - } + }; status: { observedGeneration: number; replicas: number; @@ -70,11 +70,11 @@ export class StatefulSet extends WorkloadKubeObject { currentRevision: string; updateRevision: string; collisionCount: number; - } + }; getImages() { - const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []) - return [...containers].map(container => container.image) + const containers: IPodContainer[] = get(this, "spec.template.spec.containers", []); + return [...containers].map(container => container.image); } } diff --git a/src/renderer/api/endpoints/storage-class.api.ts b/src/renderer/api/endpoints/storage-class.api.ts index cf05e13eaf..adb2059e4a 100644 --- a/src/renderer/api/endpoints/storage-class.api.ts +++ b/src/renderer/api/endpoints/storage-class.api.ts @@ -4,9 +4,9 @@ import { KubeApi } from "../kube-api"; @autobind() export class StorageClass extends KubeObject { - static kind = "StorageClass" - static namespaced = false - static apiBase = "/apis/storage.k8s.io/v1/storageclasses" + static kind = "StorageClass"; + static namespaced = false; + static apiBase = "/apis/storage.k8s.io/v1/storageclasses"; provisioner: string; // e.g. "storage.k8s.io/v1" mountOptions?: string[]; @@ -14,22 +14,22 @@ export class StorageClass extends KubeObject { reclaimPolicy: string; parameters: { [param: string]: string; // every provisioner has own set of these parameters - } + }; isDefault() { const annotations = this.metadata.annotations || {}; return ( annotations["storageclass.kubernetes.io/is-default-class"] === "true" || annotations["storageclass.beta.kubernetes.io/is-default-class"] === "true" - ) + ); } getVolumeBindingMode() { - return this.volumeBindingMode || "-" + return this.volumeBindingMode || "-"; } getReclaimPolicy() { - return this.reclaimPolicy || "-" + return this.reclaimPolicy || "-"; } } diff --git a/src/renderer/api/json-api.ts b/src/renderer/api/json-api.ts index e42996c041..cc239a804e 100644 --- a/src/renderer/api/json-api.ts +++ b/src/renderer/api/json-api.ts @@ -110,23 +110,23 @@ export class JsonApi { } else { const error = new JsonApiErrorParsed(data, this.parseError(data, res)); this.onError.emit(error, res); - this.writeLog({ ...log, error }) + this.writeLog({ ...log, error }); throw error; } - }) + }); } protected parseError(error: JsonApiError | string, res: Response): string[] { if (typeof error === "string") { - return [error] + return [error]; } else if (Array.isArray(error.errors)) { - return error.errors.map(error => error.title) + return error.errors.map(error => error.title); } else if (error.message) { - return [error.message] + return [error.message]; } - return [res.statusText || "Error!"] + return [res.statusText || "Error!"]; } protected writeLog(log: JsonApiLog) { diff --git a/src/renderer/api/kube-api-parse.ts b/src/renderer/api/kube-api-parse.ts index c4c93562cf..0995fac24f 100644 --- a/src/renderer/api/kube-api-parse.ts +++ b/src/renderer/api/kube-api-parse.ts @@ -51,7 +51,7 @@ export function parseKubeApi(path: string): IKubeApiParsed { } else { switch (left.length) { case 4: - [apiGroup, apiVersion, resource, name] = left + [apiGroup, apiVersion, resource, name] = left; break; case 2: resource = left.pop(); @@ -79,11 +79,11 @@ export function parseKubeApi(path: string): IKubeApiParsed { */ if (left[0].includes('.') || left[1].match(/^v[0-9]/)) { [apiGroup, apiVersion] = left; - resource = left.slice(2).join("/") + resource = left.slice(2).join("/"); } else { apiGroup = ""; apiVersion = left[0]; - [resource, name] = left.slice(1) + [resource, name] = left.slice(1); } break; } @@ -93,7 +93,7 @@ export function parseKubeApi(path: string): IKubeApiParsed { const apiBase = [apiPrefix, apiGroup, apiVersion, resource].filter(v => v).join("/"); if (!apiBase) { - throw new Error(`invalid apiPath: ${path}`) + throw new Error(`invalid apiPath: ${path}`); } return { @@ -108,11 +108,11 @@ export function createKubeApiURL(ref: IKubeApiLinkRef): string { const { apiPrefix = "/apis", resource, apiVersion, name } = ref; let { namespace } = ref; if (namespace) { - namespace = `namespaces/${namespace}` + namespace = `namespaces/${namespace}`; } return [apiPrefix, apiVersion, namespace, resource, name] .filter(v => v) - .join("/") + .join("/"); } export function lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): string { @@ -124,9 +124,9 @@ export function lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): st if (!kind) return ""; // search in registered apis by 'kind' & 'apiVersion' - const api = apiManager.getApi(api => api.kind === kind && api.apiVersionWithGroup == apiVersion) + const api = apiManager.getApi(api => api.kind === kind && api.apiVersionWithGroup == apiVersion); if (api) { - return api.getUrl({ namespace, name }) + return api.getUrl({ namespace, name }); } // lookup api by generated resource link @@ -142,10 +142,10 @@ export function lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): st // resolve by kind only (hpa's might use refs to older versions of resources for example) const apiByKind = apiManager.getApi(api => api.kind === kind); if (apiByKind) { - return apiByKind.getUrl({ name, namespace }) + return apiByKind.getUrl({ name, namespace }); } // otherwise generate link with default prefix // resource still might exists in k8s, but api is not registered in the app - return createKubeApiURL({ apiVersion, name, namespace, resource }) + return createKubeApiURL({ apiVersion, name, namespace, resource }); } diff --git a/src/renderer/api/kube-api.ts b/src/renderer/api/kube-api.ts index c3c9698cfa..d4840d3620 100644 --- a/src/renderer/api/kube-api.ts +++ b/src/renderer/api/kube-api.ts @@ -1,6 +1,6 @@ // Base class for building all kubernetes apis -import merge from "lodash/merge" +import merge from "lodash/merge"; import { stringify } from "querystring"; import { IKubeObjectConstructor, KubeObject } from "./kube-object"; import { KubeJsonApi, KubeJsonApiData, KubeJsonApiDataList } from "./kube-json-api"; @@ -51,7 +51,7 @@ export function forCluster(cluster: IKubeApiCluster, kubeC return new KubeApi({ objectConstructor: kubeClass, request: request - }) + }); } export class KubeApi { @@ -62,14 +62,14 @@ export class KubeApi { return () => disposers.forEach(unwatch => unwatch()); } - readonly kind: string - readonly apiBase: string - readonly apiPrefix: string - readonly apiGroup: string - readonly apiVersion: string + readonly kind: string; + readonly apiBase: string; + readonly apiPrefix: string; + readonly apiGroup: string; + readonly apiVersion: string; readonly apiVersionPreferred?: string; - readonly apiResource: string - readonly isNamespaced: boolean + readonly apiResource: string; + readonly isNamespaced: boolean; public objectConstructor: IKubeObjectConstructor; protected request: KubeJsonApi; @@ -83,7 +83,7 @@ export class KubeApi { isNamespaced = options.objectConstructor?.namespaced } = options || {}; if (!options.apiBase) { - options.apiBase = objectConstructor.apiBase + options.apiBase = objectConstructor.apiBase; } const { apiBase, apiPrefix, apiGroup, apiVersion, apiVersionWithGroup, resource } = KubeApi.parseApi(options.apiBase); @@ -105,7 +105,7 @@ export class KubeApi { get apiVersionWithGroup() { return [this.apiGroup, this.apiVersionPreferred ?? this.apiVersion] .filter(Boolean) - .join("/") + .join("/"); } protected async checkPreferredVersion() { @@ -116,7 +116,7 @@ export class KubeApi { }); if (this.apiVersionPreferred) { - Object.defineProperty(this, "apiBase", { value: this.getUrl() }) + Object.defineProperty(this, "apiBase", { value: this.getUrl() }); apiManager.registerApi(this.apiBase, this); } } @@ -147,10 +147,10 @@ export class KubeApi { protected normalizeQuery(query: Partial = {}) { if (query.labelSelector) { - query.labelSelector = [query.labelSelector].flat().join(",") + query.labelSelector = [query.labelSelector].flat().join(","); } if (query.fieldSelector) { - query.fieldSelector = [query.fieldSelector].flat().join(",") + query.fieldSelector = [query.fieldSelector].flat().join(","); } return query; } @@ -170,7 +170,7 @@ export class KubeApi { kind: this.kind, apiVersion: apiVersion, ...item, - })) + })); } // custom apis might return array for list response, e.g. users, groups, etc. @@ -218,13 +218,13 @@ export class KubeApi { const apiUrl = this.getUrl({ namespace, name }); return this.request .put(apiUrl, { data }) - .then(this.parseResponse) + .then(this.parseResponse); } async delete({ name = "", namespace = "default" }) { await this.checkPreferredVersion(); const apiUrl = this.getUrl({ namespace, name }); - return this.request.del(apiUrl) + return this.request.del(apiUrl); } getWatchUrl(namespace = "", query: IKubeApiQueryParams = {}) { @@ -232,7 +232,7 @@ export class KubeApi { watch: 1, resourceVersion: this.getResourceVersion(namespace), ...query, - }) + }); } watch(): () => void { @@ -240,4 +240,4 @@ export class KubeApi { } } -export * from "./kube-api-parse" +export * from "./kube-api-parse"; diff --git a/src/renderer/api/kube-object-detail-registry.ts b/src/renderer/api/kube-object-detail-registry.ts index f844da9ef3..5246254532 100644 --- a/src/renderer/api/kube-object-detail-registry.ts +++ b/src/renderer/api/kube-object-detail-registry.ts @@ -1 +1 @@ -export { kubeObjectDetailRegistry } from "../../extensions/registries/kube-object-detail-registry" +export { kubeObjectDetailRegistry } from "../../extensions/registries/kube-object-detail-registry"; diff --git a/src/renderer/api/kube-object.ts b/src/renderer/api/kube-object.ts index 664f9a5c22..8d0e6123f3 100644 --- a/src/renderer/api/kube-object.ts +++ b/src/renderer/api/kube-object.ts @@ -65,20 +65,20 @@ export class KubeObject implements ItemObject { static stringifyLabels(labels: { [name: string]: string }): string[] { if (!labels) return []; - return Object.entries(labels).map(([name, value]) => `${name}=${value}`) + return Object.entries(labels).map(([name, value]) => `${name}=${value}`); } constructor(data: KubeJsonApiData) { Object.assign(this, data); } - apiVersion: string - kind: string + apiVersion: string; + kind: string; metadata: IKubeObjectMetadata; status?: any; // todo: type-safety support get selfLink() { - return this.metadata.selfLink + return this.metadata.selfLink; } getId() { @@ -131,18 +131,18 @@ export class KubeObject implements ItemObject { return refs.map(ownerRef => ({ ...ownerRef, namespace: this.getNs(), - })) + })); } getSearchFields() { - const { getName, getId, getNs, getAnnotations, getLabels } = this + const { getName, getId, getNs, getAnnotations, getLabels } = this; return [ getName(), getNs(), getId(), ...getLabels(), ...getAnnotations(true), - ] + ]; } toPlainObject(): object { diff --git a/src/renderer/api/kube-watch-api.ts b/src/renderer/api/kube-watch-api.ts index 56c3fc1c86..8ce44fb77c 100644 --- a/src/renderer/api/kube-watch-api.ts +++ b/src/renderer/api/kube-watch-api.ts @@ -1,7 +1,7 @@ // Kubernetes watch-api consumer import { computed, observable, reaction } from "mobx"; -import { stringify } from "querystring" +import { stringify } from "querystring"; import { autobind, EventEmitter } from "../utils"; import { KubeJsonApiData } from "./kube-json-api"; import type { KubeObjectStore } from "../kube-object.store"; @@ -61,13 +61,13 @@ export class KubeWatchApi { } protected getQuery(): Partial { - const { isAdmin, allowedNamespaces } = getHostedCluster() + const { isAdmin, allowedNamespaces } = getHostedCluster(); return { api: this.activeApis.map(api => { if (isAdmin) return api.getWatchUrl(); - return allowedNamespaces.map(namespace => api.getWatchUrl(namespace)) + return allowedNamespaces.map(namespace => api.getWatchUrl(namespace)); }).flat() - } + }; } // todo: maybe switch to websocket to avoid often reconnects @@ -119,11 +119,11 @@ export class KubeWatchApi { await api.refreshResourceVersion({ namespace }); this.reconnect(); } catch (error) { - console.error("failed to refresh resource version", error) + console.error("failed to refresh resource version", error); if (this.subscribers.size > 0) { setTimeout(() => { - this.onRouteEvent(event) - }, 1000) + this.onRouteEvent(event); + }, 1000); } } } diff --git a/src/renderer/api/terminal-api.ts b/src/renderer/api/terminal-api.ts index 0e8bba2df6..4f66544f86 100644 --- a/src/renderer/api/terminal-api.ts +++ b/src/renderer/api/terminal-api.ts @@ -1,7 +1,7 @@ import { stringify } from "querystring"; import { autobind, base64, EventEmitter } from "../utils"; import { WebSocketApi } from "./websocket-api"; -import isEqual from "lodash/isEqual" +import isEqual from "lodash/isEqual"; import { isDevelopment } from "../../common/vars"; export enum TerminalChannels { @@ -28,7 +28,7 @@ export type TerminalApiQuery = Record & { id: string; node?: string; type?: string | "node"; -} +}; export class TerminalApi extends WebSocketApi { protected size: { Width: number; Height: number }; @@ -51,7 +51,7 @@ export class TerminalApi extends WebSocketApi { const wss = `ws${protocol === "https:" ? "s" : ""}://`; const query: TerminalApiQuery = { id }; if (port) { - port = `:${port}` + port = `:${port}`; } if (node) { query.node = node; diff --git a/src/renderer/api/websocket-api.ts b/src/renderer/api/websocket-api.ts index cb94881035..934d6cded6 100644 --- a/src/renderer/api/websocket-api.ts +++ b/src/renderer/api/websocket-api.ts @@ -146,7 +146,7 @@ export class WebSocketApi { } protected _onError(evt: Event) { - this.writeLog('%cERROR', 'color:red;font-weight:bold;', evt) + this.writeLog('%cERROR', 'color:red;font-weight:bold;', evt); } protected _onClose(evt: CloseEvent) { diff --git a/src/renderer/api/workload-kube-object.ts b/src/renderer/api/workload-kube-object.ts index c18b8df6c4..51c0461f15 100644 --- a/src/renderer/api/workload-kube-object.ts +++ b/src/renderer/api/workload-kube-object.ts @@ -65,16 +65,16 @@ export class WorkloadKubeObject extends KubeObject { } getTolerations(): IToleration[] { - return get(this, "spec.template.spec.tolerations", []) + return get(this, "spec.template.spec.tolerations", []); } getAffinity(): IAffinity { - return get(this, "spec.template.spec.affinity") + return get(this, "spec.template.spec.affinity"); } getAffinityNumber() { - const affinity = this.getAffinity() - if (!affinity) return 0 - return Object.keys(affinity).length + const affinity = this.getAffinity(); + if (!affinity) return 0; + return Object.keys(affinity).length; } } \ No newline at end of file diff --git a/src/renderer/bootstrap.tsx b/src/renderer/bootstrap.tsx index cfadb5c379..7aa78f1682 100644 --- a/src/renderer/bootstrap.tsx +++ b/src/renderer/bootstrap.tsx @@ -1,9 +1,9 @@ -import "./components/app.scss" +import "./components/app.scss"; import React from "react"; -import * as Mobx from "mobx" -import * as MobxReact from "mobx-react" -import * as LensExtensions from "../extensions/extension-api" +import * as Mobx from "mobx"; +import * as MobxReact from "mobx-react"; +import * as LensExtensions from "../extensions/extension-api"; import { App } from "./components/app"; import { LensApp } from "./lens-app"; import { render, unmountComponentAtNode } from "react-dom"; @@ -18,20 +18,20 @@ import { extensionLoader } from "../extensions/extension-loader"; type AppComponent = React.ComponentType & { init?(): Promise; -} +}; export { React, Mobx, MobxReact, LensExtensions -} +}; export async function bootstrap(App: AppComponent) { - const rootElem = document.getElementById("app") + const rootElem = document.getElementById("app"); rootElem.classList.toggle("is-mac", isMac); - extensionLoader.init() + extensionLoader.init(); // preload common stores await Promise.all([ @@ -53,13 +53,13 @@ export async function bootstrap(App: AppComponent) { } window.addEventListener("message", (ev: MessageEvent) => { if (ev.data === "teardown") { - userStore.unregisterIpcListener() - workspaceStore.unregisterIpcListener() - clusterStore.unregisterIpcListener() - unmountComponentAtNode(rootElem) - window.location.href = "about:blank" + userStore.unregisterIpcListener(); + workspaceStore.unregisterIpcListener(); + clusterStore.unregisterIpcListener(); + unmountComponentAtNode(rootElem); + window.location.href = "about:blank"; } - }) + }); render(<> {isMac && } diff --git a/src/renderer/components/+404/index.ts b/src/renderer/components/+404/index.ts index 7314f53562..67433b02c3 100644 --- a/src/renderer/components/+404/index.ts +++ b/src/renderer/components/+404/index.ts @@ -1 +1 @@ -export * from "./not-found" +export * from "./not-found"; diff --git a/src/renderer/components/+add-cluster/add-cluster.route.ts b/src/renderer/components/+add-cluster/add-cluster.route.ts index ba3ffcd104..3f1e36be9e 100644 --- a/src/renderer/components/+add-cluster/add-cluster.route.ts +++ b/src/renderer/components/+add-cluster/add-cluster.route.ts @@ -3,6 +3,6 @@ import { buildURL } from "../../../common/utils/buildUrl"; export const addClusterRoute: RouteProps = { path: "/add-cluster" -} +}; -export const addClusterURL = buildURL(addClusterRoute.path) +export const addClusterURL = buildURL(addClusterRoute.path); diff --git a/src/renderer/components/+add-cluster/add-cluster.tsx b/src/renderer/components/+add-cluster/add-cluster.tsx index 8acd3a51ea..abb28d090e 100644 --- a/src/renderer/components/+add-cluster/add-cluster.tsx +++ b/src/renderer/components/+add-cluster/add-cluster.tsx @@ -1,4 +1,4 @@ -import "./add-cluster.scss" +import "./add-cluster.scss"; import os from "os"; import React, { Fragment } from "react"; import { observer } from "mobx-react"; @@ -16,7 +16,7 @@ import { WizardLayout } from "../layout/wizard-layout"; import { kubeConfigDefaultPath, loadConfig, splitConfig, validateConfig, validateKubeConfig } from "../../../common/kube-helpers"; import { ClusterModel, ClusterStore, clusterStore } from "../../../common/cluster-store"; import { workspaceStore } from "../../../common/workspace-store"; -import { v4 as uuid } from "uuid" +import { v4 as uuid } from "uuid"; import { navigate } from "../../navigation"; import { userStore } from "../../../common/user-store"; import { clusterViewURL } from "../cluster-manager/cluster-view.route"; @@ -39,10 +39,10 @@ export class AddCluster extends React.Component { @observable selectedContexts = observable.array(); @observable sourceTab = KubeConfigSourceTab.FILE; @observable kubeConfigPath = ""; - @observable customConfig = "" - @observable proxyServer = "" - @observable isWaiting = false - @observable showSettings = false + @observable customConfig = ""; + @observable proxyServer = ""; + @observable isWaiting = false; + @observable showSettings = false; @observable dropAreaActive = false; componentDidMount() { @@ -84,7 +84,7 @@ export class AddCluster extends React.Component { break; case KubeConfigSourceTab.TEXT: try { - this.error = "" + this.error = ""; const contexts = this.getContexts(loadConfig(this.customConfig || "{}")); this.kubeContexts.replace(contexts); } catch (err) { @@ -94,7 +94,7 @@ export class AddCluster extends React.Component { } if (this.kubeContexts.size === 1) { - this.selectedContexts.push(this.kubeContexts.keys().next().value) + this.selectedContexts.push(this.kubeContexts.keys().next().value); } } @@ -102,8 +102,8 @@ export class AddCluster extends React.Component { const contexts = new Map(); splitConfig(config).forEach(config => { contexts.set(config.currentContext, config); - }) - return contexts + }); + return contexts; } selectKubeConfigDialog = async () => { @@ -117,18 +117,18 @@ export class AddCluster extends React.Component { if (!canceled && filePaths.length) { this.setKubeConfig(filePaths[0]); } - } + }; @action addClusters = () => { let newClusters: ClusterModel[] = []; try { if (!this.selectedContexts.length) { - this.error = Please select at least one cluster context + this.error = Please select at least one cluster context; return; } - this.error = "" - this.isWaiting = true + this.error = ""; + this.isWaiting = true; newClusters = this.selectedContexts.filter(context => { try { @@ -136,7 +136,7 @@ export class AddCluster extends React.Component { validateKubeConfig(kubeConfig); return true; } catch (err) { - this.error = String(err.message) + this.error = String(err.message); if (err instanceof ExecValidationNotFoundError ) { Notifications.error(Error while adding cluster(s): {this.error}); return false; @@ -159,8 +159,8 @@ export class AddCluster extends React.Component { clusterName: kubeConfig.currentContext, httpsProxy: this.proxyServer || undefined, }, - } - }) + }; + }); runInAction(() => { clusterStore.addClusters(...newClusters); @@ -175,7 +175,7 @@ export class AddCluster extends React.Component { ); } } - }) + }); this.refreshContexts(); } catch (err) { this.error = String(err); @@ -183,7 +183,7 @@ export class AddCluster extends React.Component { } finally { this.isWaiting = false; } - } + }; renderInfo() { return ( @@ -218,7 +218,7 @@ export class AddCluster extends React.Component { Lens app might not have all login shell env variables set automatically.
{this.error}
No revisions to rollback.
Specified limits are higher than node capacity!
There are no extensions in {extensionsPath}
{extensionsPath}
{backend}
Remove selected bindings for {roleBinding.getName()}?