mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
remove direct kubeconfig usages
Signed-off-by: Jussi Nummelin <jussi.nummelin@gmail.com>
This commit is contained in:
parent
985bb29b96
commit
b051623056
@ -53,7 +53,7 @@ export class MetricsFeature extends Feature {
|
||||
|
||||
async install(cluster: Cluster): Promise<boolean> {
|
||||
// Check if there are storageclasses
|
||||
const storageClient = cluster.contextHandler.kc.makeApiClient(k8s.StorageV1Api)
|
||||
const storageClient = cluster.proxyKubeconfig().makeApiClient(k8s.StorageV1Api)
|
||||
const scs = await storageClient.listStorageClass();
|
||||
scs.body.items.forEach(sc => {
|
||||
if(sc.metadata.annotations &&
|
||||
@ -93,9 +93,9 @@ export class MetricsFeature extends Feature {
|
||||
|
||||
async uninstall(cluster: Cluster): Promise<boolean> {
|
||||
return new Promise<boolean>(async (resolve, reject) => {
|
||||
const rbacClient = cluster.contextHandler.kc.makeApiClient(RbacAuthorizationV1Api)
|
||||
const rbacClient = cluster.proxyKubeconfig().makeApiClient(RbacAuthorizationV1Api)
|
||||
try {
|
||||
await this.deleteNamespace(cluster.contextHandler.kc, "lens-metrics")
|
||||
await this.deleteNamespace(cluster.proxyKubeconfig(), "lens-metrics")
|
||||
await rbacClient.deleteClusterRole("lens-prometheus");
|
||||
await rbacClient.deleteClusterRoleBinding("lens-prometheus");
|
||||
resolve(true);
|
||||
|
||||
@ -37,7 +37,7 @@ export class UserModeFeature extends Feature {
|
||||
|
||||
async uninstall(cluster: Cluster): Promise<boolean> {
|
||||
return new Promise<boolean>(async (resolve, reject) => {
|
||||
const rbacClient = cluster.contextHandler.kc.makeApiClient(RbacAuthorizationV1Api)
|
||||
const rbacClient = cluster.proxyKubeconfig().makeApiClient(RbacAuthorizationV1Api)
|
||||
try {
|
||||
await rbacClient.deleteClusterRole("lens-user");
|
||||
await rbacClient.deleteClusterRoleBinding("lens-user");
|
||||
|
||||
@ -92,13 +92,19 @@ export class Cluster implements ClusterInfo {
|
||||
return this.kubeconfigManager.getPath()
|
||||
}
|
||||
|
||||
public proxyKubeconfig() {
|
||||
const kc = new KubeConfig()
|
||||
kc.loadFromFile(this.kubeconfigManager.getPath())
|
||||
return kc
|
||||
}
|
||||
|
||||
public async init(kc: KubeConfig) {
|
||||
this.apiUrl = kc.getCurrentCluster().server
|
||||
this.contextHandler = new ContextHandler(kc, this)
|
||||
await this.contextHandler.init() // So we get the proxy port reserved
|
||||
this.kubeconfigManager = new KubeconfigManager(this)
|
||||
|
||||
this.url = this.contextHandler.url
|
||||
this.apiUrl = kc.getCurrentCluster().server
|
||||
}
|
||||
|
||||
public stopServer() {
|
||||
@ -131,7 +137,7 @@ export class Cluster implements ClusterInfo {
|
||||
|
||||
if (this.accessible) {
|
||||
this.distribution = this.detectKubernetesDistribution(this.version)
|
||||
this.features = await fm.getFeatures(this.contextHandler)
|
||||
this.features = await fm.getFeatures(this)
|
||||
this.isAdmin = await this.isClusterAdmin()
|
||||
this.nodes = await this.getNodeCount()
|
||||
this.kubeCtl = new Kubectl(this.version)
|
||||
@ -156,7 +162,7 @@ export class Cluster implements ClusterInfo {
|
||||
id: this.id,
|
||||
workspace: this.workspace,
|
||||
url: this.url,
|
||||
contextName: this.contextHandler.kc.currentContext,
|
||||
contextName: this.contextName,
|
||||
apiUrl: this.apiUrl,
|
||||
online: this.online,
|
||||
accessible: this.accessible,
|
||||
@ -216,7 +222,7 @@ export class Cluster implements ClusterInfo {
|
||||
}
|
||||
|
||||
public async canI(resourceAttributes: V1ResourceAttributes): Promise<boolean> {
|
||||
const authApi = this.contextHandler.kc.makeApiClient(AuthorizationV1Api)
|
||||
const authApi = this.proxyKubeconfig().makeApiClient(AuthorizationV1Api)
|
||||
try {
|
||||
const accessReview = await authApi.createSelfSubjectAccessReview({
|
||||
apiVersion: "authorization.k8s.io/v1",
|
||||
@ -278,7 +284,7 @@ export class Cluster implements ClusterInfo {
|
||||
if (!this.isAdmin) {
|
||||
return 0;
|
||||
}
|
||||
const client = this.contextHandler.kc.makeApiClient(CoreV1Api);
|
||||
const client = this.proxyKubeconfig().makeApiClient(CoreV1Api);
|
||||
try {
|
||||
const response = await client.listEventForAllNamespaces(false, null, null, null, 1000);
|
||||
const uniqEventSources = new Set();
|
||||
|
||||
@ -15,7 +15,7 @@ export class ContextHandler {
|
||||
public contextName: string
|
||||
public id: string
|
||||
public url: string
|
||||
public kc: KubeConfig
|
||||
|
||||
public certData: string
|
||||
public authCertData: string
|
||||
public cluster: Cluster
|
||||
@ -37,13 +37,11 @@ export class ContextHandler {
|
||||
|
||||
constructor(kc: KubeConfig, cluster: Cluster) {
|
||||
this.id = cluster.id
|
||||
this.kc = kc
|
||||
this.kc.setCurrentContext(cluster.contextName)
|
||||
|
||||
this.cluster = cluster
|
||||
this.clusterUrl = url.parse(kc.getCurrentCluster().server)
|
||||
this.clusterUrl = url.parse(cluster.apiUrl) //url.parse(kc.getCurrentCluster().server)
|
||||
this.contextName = cluster.contextName;
|
||||
this.defaultNamespace = kc.getContextObject(kc.currentContext).namespace
|
||||
this.defaultNamespace = kc.getContextObject(cluster.contextName).namespace
|
||||
this.url = `http://${this.id}.localhost:${cluster.port}/`
|
||||
this.kubernetesApi = `http://127.0.0.1:${cluster.port}/${this.id}`
|
||||
|
||||
@ -89,7 +87,7 @@ export class ContextHandler {
|
||||
public async getPrometheusService(): Promise<PrometheusService> {
|
||||
const providers = this.prometheusProvider ? prometheusProviders.filter((p, _) => p.id == this.prometheusProvider) : prometheusProviders
|
||||
const prometheusPromises: Promise<PrometheusService>[] = providers.map(async (provider: PrometheusProvider): Promise<PrometheusService> => {
|
||||
const apiClient = this.kc.makeApiClient(CoreV1Api)
|
||||
const apiClient = this.cluster.proxyKubeconfig().makeApiClient(CoreV1Api)
|
||||
return await provider.getPrometheusService(apiClient)
|
||||
})
|
||||
const resolvedPrometheusServices = await Promise.all(prometheusPromises)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ContextHandler } from "./context-handler"
|
||||
import { KubeConfig } from "@kubernetes/client-node"
|
||||
import logger from "./logger";
|
||||
import { Cluster } from "./cluster";
|
||||
import { Feature, FeatureStatusMap } from "./feature"
|
||||
@ -10,17 +10,19 @@ const ALL_FEATURES: any = {
|
||||
'user-mode': new UserModeFeature(null),
|
||||
}
|
||||
|
||||
export async function getFeatures(clusterContext: ContextHandler): Promise<FeatureStatusMap> {
|
||||
export async function getFeatures(cluster: Cluster): Promise<FeatureStatusMap> {
|
||||
return new Promise<FeatureStatusMap>(async (resolve, reject) => {
|
||||
const result: FeatureStatusMap = {};
|
||||
logger.debug(`features for ${clusterContext.contextName}`);
|
||||
logger.debug(`features for ${cluster.contextName}`);
|
||||
for (const key in ALL_FEATURES) {
|
||||
logger.debug(`feature ${key}`);
|
||||
if (ALL_FEATURES.hasOwnProperty(key)) {
|
||||
logger.debug("getting feature status...");
|
||||
const feature = ALL_FEATURES[key] as Feature;
|
||||
|
||||
const status = await feature.featureStatus(clusterContext.kc);
|
||||
const kc = new KubeConfig()
|
||||
kc.loadFromFile(cluster.proxyKubeconfigPath())
|
||||
|
||||
const status = await feature.featureStatus(kc);
|
||||
result[feature.name] = status
|
||||
|
||||
} else {
|
||||
|
||||
@ -35,7 +35,7 @@ export class KubeAuthProxy {
|
||||
"--kubeconfig", this.cluster.kubeConfigPath,
|
||||
"--context", this.cluster.contextName,
|
||||
"--accept-hosts", ".*",
|
||||
"--reject-paths", "^[^/]",
|
||||
"--reject-paths", "^[^/]"
|
||||
]
|
||||
if (process.env.DEBUG_PROXY === "true") {
|
||||
args = args.concat(["-v", "9"])
|
||||
|
||||
@ -27,6 +27,8 @@ export class KubeconfigManager {
|
||||
protected createTemporaryKubeconfig(): string {
|
||||
ensureDir(this.configDir)
|
||||
const path = `${this.configDir}/${randomFileName("kubeconfig")}`
|
||||
const originalKc = new KubeConfig()
|
||||
originalKc.loadFromFile(this.cluster.kubeConfigPath)
|
||||
const kc = {
|
||||
clusters: [
|
||||
{
|
||||
@ -43,7 +45,7 @@ export class KubeconfigManager {
|
||||
{
|
||||
name: this.cluster.contextName,
|
||||
cluster: this.cluster.contextName,
|
||||
namespace: this.cluster.contextHandler.kc.getContextObject(this.cluster.contextName).namespace,
|
||||
namespace: originalKc.getContextObject(this.cluster.contextName).namespace,
|
||||
user: "proxy"
|
||||
}
|
||||
],
|
||||
|
||||
@ -17,7 +17,7 @@ export class NodeShellSession extends ShellSession {
|
||||
super(socket, pathToKubeconfig, cluster)
|
||||
this.nodeName = nodeName
|
||||
this.podId = `node-shell-${uuid()}`
|
||||
this.kc = cluster.contextHandler.kc
|
||||
this.kc = cluster.proxyKubeconfig()
|
||||
}
|
||||
|
||||
public async open() {
|
||||
|
||||
@ -45,7 +45,7 @@ const apiResources = [
|
||||
]
|
||||
|
||||
async function getAllowedNamespaces(cluster: Cluster) {
|
||||
const api = cluster.contextHandler.kc.makeApiClient(CoreV1Api)
|
||||
const api = cluster.proxyKubeconfig().makeApiClient(CoreV1Api)
|
||||
try {
|
||||
const namespaceList = await api.listNamespace()
|
||||
const nsAccessStatuses = await Promise.all(
|
||||
@ -58,9 +58,8 @@ async function getAllowedNamespaces(cluster: Cluster) {
|
||||
return namespaceList.body.items
|
||||
.filter((ns, i) => nsAccessStatuses[i])
|
||||
.map(ns => ns.metadata.name)
|
||||
} catch (error) {
|
||||
const kc = cluster.contextHandler.kc
|
||||
const ctx = kc.getContextObject(kc.currentContext)
|
||||
} catch(error) {
|
||||
const ctx = cluster.proxyKubeconfig().getContextObject(cluster.contextName)
|
||||
if (ctx.namespace) {
|
||||
return [ctx.namespace]
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ function generateKubeConfig(username: string, secret: V1Secret, cluster: Cluster
|
||||
{
|
||||
'name': cluster.contextName,
|
||||
'cluster': {
|
||||
'server': cluster.contextHandler.kc.getCurrentCluster().server,
|
||||
'server': cluster.apiUrl,
|
||||
'certificate-authority-data': secret.data["ca.crt"]
|
||||
}
|
||||
}
|
||||
@ -44,7 +44,7 @@ class KubeconfigRoute extends LensApi {
|
||||
public async routeServiceAccountRoute(request: LensApiRequest) {
|
||||
const { params, response, cluster} = request
|
||||
|
||||
const client = cluster.contextHandler.kc.makeApiClient(CoreV1Api);
|
||||
const client = cluster.proxyKubeconfig().makeApiClient(CoreV1Api);
|
||||
const secretList = await client.listNamespacedSecret(params.namespace)
|
||||
const secret = secretList.body.items.find(secret => {
|
||||
const { annotations } = secret.metadata;
|
||||
|
||||
@ -38,7 +38,17 @@ class ApiWatcher {
|
||||
clearInterval(this.processor)
|
||||
}
|
||||
logger.debug("Stopping watcher for api: " + this.apiUrl)
|
||||
this.watchRequest.abort()
|
||||
try {
|
||||
this.watchRequest.abort()
|
||||
this.sendEvent({
|
||||
type: "STREAM_END",
|
||||
url: this.apiUrl,
|
||||
status: 410,
|
||||
})
|
||||
logger.debug("watch aborted")
|
||||
} catch (error) {
|
||||
logger.error("Watch abort errored:" + error)
|
||||
}
|
||||
}
|
||||
|
||||
private watchHandler(phase: string, obj: any) {
|
||||
@ -49,6 +59,7 @@ class ApiWatcher {
|
||||
}
|
||||
|
||||
private doneHandler(error: Error) {
|
||||
logger.debug("********** watch.doneHandler")
|
||||
if (error) logger.warn("watch ended: " + error.toString())
|
||||
|
||||
this.sendEvent({
|
||||
@ -82,9 +93,10 @@ class WatchRoute extends LensApi {
|
||||
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.proxyKubeconfig(), null, 2))
|
||||
|
||||
apis.forEach(apiUrl => {
|
||||
const watcher = new ApiWatcher(apiUrl, cluster.contextHandler.kc, response)
|
||||
const watcher = new ApiWatcher(apiUrl, cluster.proxyKubeconfig() /*cluster.contextHandler.kc*/, response)
|
||||
watcher.start()
|
||||
watchers.push(watcher)
|
||||
})
|
||||
|
||||
@ -17,6 +17,7 @@ export function migration(store: any) {
|
||||
console.log("num clusters to migrate: ", storedClusters.length)
|
||||
for (const cluster of storedClusters ) {
|
||||
// TODO Should probably guard this, not to make the whole migration fail if one cluster fails!?
|
||||
|
||||
// take the embedded kubeconfig and dump it into a file
|
||||
const kubeConfigFile = writeEmbeddedKubeConfig(cluster.id, cluster.kubeConfig)
|
||||
cluster.kubeConfigPath = kubeConfigFile
|
||||
|
||||
Loading…
Reference in New Issue
Block a user