From 5b98674d808954de1ae31605e2a6038bd04629ab Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 16 Jul 2020 20:19:04 +0300 Subject: [PATCH] add-cluster page -- part 1 Signed-off-by: Roman --- locales/en/messages.po | 32 +++++ locales/fi/messages.po | 32 +++++ locales/ru/messages.po | 32 +++++ src/{main/k8s.ts => common/kube-helpers.ts} | 15 +- src/common/utils/kubeconfig.ts | 15 -- src/main/cluster-manager.ts | 2 +- src/main/cluster.ts | 2 +- src/main/kubeconfig-manager.ts | 2 +- src/migrations/cluster-store/3.6.0-beta.1.ts | 11 +- .../_vue/components/AddClusterPage.vue | 55 +------- .../components/+add-cluster/add-cluster.scss | 25 +++- .../components/+add-cluster/add-cluster.tsx | 131 +++++++++++++++++- .../components/+whats-new/whats-new.scss | 7 - src/renderer/components/app.scss | 17 ++- .../components/dialog/logs-dialog.tsx | 2 +- .../error-boundary/error-boundary.tsx | 2 +- 16 files changed, 286 insertions(+), 96 deletions(-) rename src/{main/k8s.ts => common/kube-helpers.ts} (87%) delete mode 100644 src/common/utils/kubeconfig.ts diff --git a/locales/en/messages.po b/locales/en/messages.po index fd430beb58..e879875424 100644 --- a/locales/en/messages.po +++ b/locales/en/messages.po @@ -41,6 +41,10 @@ msgstr "<0>Your browser does not support all Lens features. Please consider msgid "<0>{0} successfully created" msgstr "<0>{0} successfully created" +#: src/renderer/components/+add-cluster/add-cluster.tsx:52 +msgid "A HTTP proxy server URL (format: http://
:)" +msgstr "A HTTP proxy server URL (format: http://
:)" + #: src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx:80 msgid "API Group" msgstr "API Group" @@ -63,6 +67,10 @@ msgstr "Account Name" msgid "Active" msgstr "Active" +#: src/renderer/components/+add-cluster/add-cluster.tsx:44 +msgid "Add Cluster" +msgstr "Add Cluster" + #: src/renderer/components/+namespaces/namespaces.tsx:43 msgid "Add Namespace" msgstr "Add Namespace" @@ -75,6 +83,10 @@ msgstr "Add RoleBinding" msgid "Add bindings to {name}" msgstr "Add bindings to {name}" +#: src/renderer/components/+add-cluster/add-cluster.tsx:62 +msgid "Add cluster" +msgstr "Add cluster" + #: src/renderer/components/+workspaces/clusters-menu.tsx:58 #~ msgid "Add clusters" #~ msgstr "Add clusters" @@ -613,11 +625,19 @@ msgstr "Current replica scale: {currentReplicas}" msgid "Currently applied filters:" msgstr "Currently applied filters:" +#: src/renderer/components/+add-cluster/add-cluster.tsx:36 +#~ msgid "Custom" +#~ msgstr "Custom" + #: src/renderer/components/+custom-resources/crd-list.tsx:55 #: src/renderer/components/layout/sidebar.tsx:95 msgid "Custom Resources" msgstr "Custom Resources" +#: src/renderer/components/+add-cluster/add-cluster.tsx:36 +msgid "Custom.." +msgstr "Custom.." + #: src/renderer/components/+custom-resources/certmanager.k8s.io/certificate-details.tsx:95 msgid "DNS Provider" msgstr "DNS Provider" @@ -862,6 +882,10 @@ msgstr "Groups" msgid "HPA" msgstr "HPA" +#: src/renderer/components/+add-cluster/add-cluster.tsx:54 +msgid "HTTP Proxy server. Used for communicating with Kubernetes API." +msgstr "HTTP Proxy server. Used for communicating with Kubernetes API." + #: src/renderer/components/dock/install-chart.tsx:113 msgid "Helm Chart Install" msgstr "Helm Chart Install" @@ -1627,6 +1651,10 @@ msgstr "Privileged" msgid "Provisioner" msgstr "Provisioner" +#: src/renderer/components/+add-cluster/add-cluster.tsx:48 +msgid "Proxy settings" +msgstr "Proxy settings" + #: src/renderer/components/+workloads-pods/pods.tsx:79 msgid "QoS" msgstr "QoS" @@ -1987,6 +2015,10 @@ msgstr "Secrets" msgid "Select a quota.." msgstr "Select a quota.." +#: src/renderer/components/+add-cluster/add-cluster.tsx:45 +msgid "Select kubeconfig" +msgstr "Select kubeconfig" + #: src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx:188 msgid "Select role.." msgstr "Select role.." diff --git a/locales/fi/messages.po b/locales/fi/messages.po index 7ecb2b814b..cd0bb6feec 100644 --- a/locales/fi/messages.po +++ b/locales/fi/messages.po @@ -41,6 +41,10 @@ msgstr "" msgid "<0>{0} successfully created" msgstr "" +#: src/renderer/components/+add-cluster/add-cluster.tsx:52 +msgid "A HTTP proxy server URL (format: http://
:)" +msgstr "" + #: src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx:80 msgid "API Group" msgstr "" @@ -63,6 +67,10 @@ msgstr "" msgid "Active" msgstr "" +#: src/renderer/components/+add-cluster/add-cluster.tsx:44 +msgid "Add Cluster" +msgstr "" + #: src/renderer/components/+namespaces/namespaces.tsx:43 msgid "Add Namespace" msgstr "" @@ -75,6 +83,10 @@ msgstr "" msgid "Add bindings to {name}" msgstr "" +#: src/renderer/components/+add-cluster/add-cluster.tsx:62 +msgid "Add cluster" +msgstr "" + #: src/renderer/components/+workspaces/clusters-menu.tsx:58 #~ msgid "Add clusters" #~ msgstr "" @@ -609,11 +621,19 @@ msgstr "" msgid "Currently applied filters:" msgstr "" +#: src/renderer/components/+add-cluster/add-cluster.tsx:36 +#~ msgid "Custom" +#~ msgstr "" + #: src/renderer/components/+custom-resources/crd-list.tsx:55 #: src/renderer/components/layout/sidebar.tsx:95 msgid "Custom Resources" msgstr "" +#: src/renderer/components/+add-cluster/add-cluster.tsx:36 +msgid "Custom.." +msgstr "" + #: src/renderer/components/+custom-resources/certmanager.k8s.io/certificate-details.tsx:95 msgid "DNS Provider" msgstr "" @@ -853,6 +873,10 @@ msgstr "" msgid "HPA" msgstr "" +#: src/renderer/components/+add-cluster/add-cluster.tsx:54 +msgid "HTTP Proxy server. Used for communicating with Kubernetes API." +msgstr "" + #: src/renderer/components/dock/install-chart.tsx:113 msgid "Helm Chart Install" msgstr "" @@ -1610,6 +1634,10 @@ msgstr "" msgid "Provisioner" msgstr "" +#: src/renderer/components/+add-cluster/add-cluster.tsx:48 +msgid "Proxy settings" +msgstr "" + #: src/renderer/components/+workloads-pods/pods.tsx:79 msgid "QoS" msgstr "" @@ -1970,6 +1998,10 @@ msgstr "" msgid "Select a quota.." msgstr "" +#: src/renderer/components/+add-cluster/add-cluster.tsx:45 +msgid "Select kubeconfig" +msgstr "" + #: src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx:188 msgid "Select role.." msgstr "" diff --git a/locales/ru/messages.po b/locales/ru/messages.po index 52bf77e107..1787dbc5c9 100644 --- a/locales/ru/messages.po +++ b/locales/ru/messages.po @@ -42,6 +42,10 @@ msgstr "<0>Ваш браузер не поддерживает все возмо msgid "<0>{0} successfully created" msgstr "" +#: src/renderer/components/+add-cluster/add-cluster.tsx:52 +msgid "A HTTP proxy server URL (format: http://
:)" +msgstr "" + #: src/renderer/components/+user-management-roles-bindings/role-binding-details.tsx:80 msgid "API Group" msgstr "" @@ -64,6 +68,10 @@ msgstr "Название аккаунта" msgid "Active" msgstr "Активный" +#: src/renderer/components/+add-cluster/add-cluster.tsx:44 +msgid "Add Cluster" +msgstr "" + #: src/renderer/components/+namespaces/namespaces.tsx:43 msgid "Add Namespace" msgstr "Добавить Namespace" @@ -76,6 +84,10 @@ msgstr "Добавить привязку ролей" msgid "Add bindings to {name}" msgstr "Добавить привязки к {name}" +#: src/renderer/components/+add-cluster/add-cluster.tsx:62 +msgid "Add cluster" +msgstr "" + #: src/renderer/components/+workspaces/clusters-menu.tsx:58 #~ msgid "Add clusters" #~ msgstr "" @@ -614,11 +626,19 @@ msgstr "Текущий размер реплики: {currentReplicas}" msgid "Currently applied filters:" msgstr "Текущие фильтры:" +#: src/renderer/components/+add-cluster/add-cluster.tsx:36 +#~ msgid "Custom" +#~ msgstr "" + #: src/renderer/components/+custom-resources/crd-list.tsx:55 #: src/renderer/components/layout/sidebar.tsx:95 msgid "Custom Resources" msgstr "" +#: src/renderer/components/+add-cluster/add-cluster.tsx:36 +msgid "Custom.." +msgstr "" + #: src/renderer/components/+custom-resources/certmanager.k8s.io/certificate-details.tsx:95 msgid "DNS Provider" msgstr "DNS провайдер" @@ -863,6 +883,10 @@ msgstr "Группы" msgid "HPA" msgstr "HPA" +#: src/renderer/components/+add-cluster/add-cluster.tsx:54 +msgid "HTTP Proxy server. Used for communicating with Kubernetes API." +msgstr "" + #: src/renderer/components/dock/install-chart.tsx:113 msgid "Helm Chart Install" msgstr "Установка Helm чарта" @@ -1628,6 +1652,10 @@ msgstr "" msgid "Provisioner" msgstr "Комиссия" +#: src/renderer/components/+add-cluster/add-cluster.tsx:48 +msgid "Proxy settings" +msgstr "" + #: src/renderer/components/+workloads-pods/pods.tsx:79 msgid "QoS" msgstr "QoS" @@ -1988,6 +2016,10 @@ msgstr "Secrets" msgid "Select a quota.." msgstr "Выберите квоту..." +#: src/renderer/components/+add-cluster/add-cluster.tsx:45 +msgid "Select kubeconfig" +msgstr "" + #: src/renderer/components/+user-management-roles-bindings/add-role-binding-dialog.tsx:188 msgid "Select role.." msgstr "Выбрать роль.." diff --git a/src/main/k8s.ts b/src/common/kube-helpers.ts similarity index 87% rename from src/main/k8s.ts rename to src/common/kube-helpers.ts index 90c5d78cfa..c276ddcfde 100644 --- a/src/main/k8s.ts +++ b/src/common/kube-helpers.ts @@ -1,8 +1,10 @@ +import { app, remote } from "electron"; import { KubeConfig, V1Node, V1Pod } from "@kubernetes/client-node" +import { ensureDirSync, writeFileSync } from "fs-extra"; import path from "path" import os from "os" import yaml from "js-yaml" -import logger from "./logger"; +import logger from "../main/logger"; function resolveTilde(filePath: string) { if (filePath[0] === "~" && (filePath[1] === "/" || filePath.length === 1)) { @@ -112,6 +114,7 @@ export function dumpConfigYaml(kubeConfig: Partial): string { } logger.debug("Dumping KubeConfig:", config); + // skipInvalid: true makes dump ignore undefined values return yaml.safeDump(config, { skipInvalid: true }); } @@ -136,3 +139,13 @@ export function getNodeWarningConditions(node: V1Node) { c.status.toLowerCase() === "true" && c.type !== "Ready" && c.type !== "HostUpgrades" ) } + +// Write kubeconfigs to "embedded" store, i.e. "/Users/ixrock/Library/Application Support/Lens/kubeconfigs" +export function saveConfigToAppFiles(clusterId: string, kubeConfig: string): string { + const userData = (app || remote.app).getPath("userData"); + const kubeConfigFile = path.join(userData, `kubeconfigs/${clusterId}`) + + ensureDirSync(path.dirname(kubeConfigFile)); + writeFileSync(kubeConfigFile, kubeConfig); + return kubeConfigFile; +} diff --git a/src/common/utils/kubeconfig.ts b/src/common/utils/kubeconfig.ts deleted file mode 100644 index 17bdf3bb90..0000000000 --- a/src/common/utils/kubeconfig.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { app, remote } from "electron" -import { ensureDirSync, writeFileSync } from "fs-extra" -import * as path from "path" - -// Write kubeconfigs to "embedded" store, i.e. "/Users/ixrock/Library/Application Support/Lens/kubeconfigs" -export function writeEmbeddedKubeConfig(clusterId: string, kubeConfig: string): string { - const userData = (app || remote.app).getPath("userData"); - const kubeConfigBase = path.join(userData, "kubeconfigs") - ensureDirSync(kubeConfigBase) - - const kubeConfigFile = path.join(kubeConfigBase, clusterId) - writeFileSync(kubeConfigFile, kubeConfig) - - return kubeConfigFile -} diff --git a/src/main/cluster-manager.ts b/src/main/cluster-manager.ts index 34bf0fe48c..d30b794da4 100644 --- a/src/main/cluster-manager.ts +++ b/src/main/cluster-manager.ts @@ -9,7 +9,7 @@ import { ClusterId, ClusterModel, clusterStore } from "../common/cluster-store" import { handleMessages } from "../common/ipc"; import { ClusterIpcMessage } from "../common/ipc-messages"; import { tracker } from "../common/tracker"; -import { validateConfig } from "./k8s"; +import { validateConfig } from "../common/kube-helpers"; import { Cluster } from "./cluster" import { FeatureInstallRequest } from "./feature"; import logger from "./logger" diff --git a/src/main/cluster.ts b/src/main/cluster.ts index ed2e8d3205..987cb5d50e 100644 --- a/src/main/cluster.ts +++ b/src/main/cluster.ts @@ -8,7 +8,7 @@ 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 "./k8s" +import { getNodeWarningConditions, loadConfig, podHasIssues } from "../common/kube-helpers" import { getFeatures, installFeature, uninstallFeature, upgradeFeature } from "./feature-manager"; import request, { RequestPromiseOptions } from "request-promise-native" import logger from "./logger" diff --git a/src/main/kubeconfig-manager.ts b/src/main/kubeconfig-manager.ts index 9d297ed223..9d3fcd1892 100644 --- a/src/main/kubeconfig-manager.ts +++ b/src/main/kubeconfig-manager.ts @@ -4,7 +4,7 @@ import type { ContextHandler } from "./context-handler"; import { app } from "electron" import path from "path" import fs from "fs-extra" -import { dumpConfigYaml, loadConfig } from "./k8s" +import { dumpConfigYaml, loadConfig } from "../common/kube-helpers" import logger from "./logger" export class KubeconfigManager { 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 bf230d6a0b..adc354d9ef 100644 --- a/src/migrations/cluster-store/3.6.0-beta.1.ts +++ b/src/migrations/cluster-store/3.6.0-beta.1.ts @@ -4,13 +4,12 @@ import path from "path" import { app, remote } from "electron" import { migration } from "../migration-wrapper"; import { ensureDirSync } from "fs-extra" -import { writeEmbeddedKubeConfig } from "../../common/utils/kubeconfig" import { ClusterModel } from "../../common/cluster-store"; -import { loadConfig } from "../../main/k8s"; +import { loadConfig, saveConfigToAppFiles } from "../../common/kube-helpers"; export default migration({ version: "3.6.0-beta.1", - run(store, log: (...args: any[]) => void) { + run(store, printLog) { const migratedClusters: ClusterModel[] = [] const storedClusters: ClusterModel[] = store.get("clusters"); const kubeConfigBase = path.join((app || remote.app).getPath("userData"), "kubeconfigs") @@ -18,16 +17,16 @@ export default migration({ if (!storedClusters) return; ensureDirSync(kubeConfigBase); - log("Number of clusters to migrate: ", storedClusters.length) + printLog("Number of clusters to migrate: ", storedClusters.length) for (const cluster of storedClusters) { try { // take the embedded kubeconfig and dump it into a file - cluster.kubeConfigPath = writeEmbeddedKubeConfig(cluster.id, cluster.kubeConfig) + cluster.kubeConfigPath = saveConfigToAppFiles(cluster.id, cluster.kubeConfig) cluster.contextName = loadConfig(cluster.kubeConfigPath).getCurrentContext(); delete cluster.kubeConfig; migratedClusters.push(cluster) } catch (error) { - log(`Failed to migrate Kubeconfig for cluster "${cluster.id}"`, error) + printLog(`Failed to migrate Kubeconfig for cluster "${cluster.id}"`, error) } } diff --git a/src/renderer/_vue/components/AddClusterPage.vue b/src/renderer/_vue/components/AddClusterPage.vue index 510521b711..25bff611fd 100644 --- a/src/renderer/_vue/components/AddClusterPage.vue +++ b/src/renderer/_vue/components/AddClusterPage.vue @@ -75,46 +75,7 @@ - -

Clusters associated with Lens

-

- Add clusters by clicking the Add Cluster button. - You'll need to obtain a working kubeconfig for the cluster you want to add. -

-

- Each cluster context is added as a separate item in the left-side cluster menu to allow you to operate easily on multiple clusters and/or contexts. -

-

- For more information on kubeconfig see Kubernetes docs -

-

- NOTE: Any manually added cluster is not merged into your kubeconfig file. -

-

- To see your currently enabled config with kubectl, use kubectl config view --minify --raw command in your terminal. -

-

- When connecting to a cluster, make sure you have a valid and working kubeconfig for the cluster. Following lists known "gotchas" in some authentication types used in kubeconfig with Lens app. -

- -

OIDC (OpenID Connect)

-
-
-

- When connecting Lens to OIDC enabled cluster, there's few things you as a user need to take into account. -

- Dedicated refresh token -

- As Lens app utilized kubeconfig is "disconnected" from your main kubeconfig Lens needs to have it's own refresh token it utilizes. - If you share the refresh token with e.g. kubectl who ever uses the token first will invalidate it for the next user. - One way to achieve this is with kubelogin tool by removing the tokens (both id_token and refresh_token) from the config and issuing kubelogin command. That'll take you through the login process and will result you having "dedicated" refresh token. -

-
-

Exec auth plugins

-

- When using exec auth plugins make sure the paths that are used to call any binaries are full paths as Lens app might not be able to call binaries with relative paths. Make also sure that you pass all needed information either as arguments or env variables in the config, Lens app might not have all login shell env variables set automatically. -

-
+ @@ -123,12 +84,11 @@