1
0
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:
Jussi Nummelin 2020-06-18 12:32:34 +03:00 committed by Jari Kolehmainen
parent 985bb29b96
commit b051623056
12 changed files with 51 additions and 31 deletions

View File

@ -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);

View File

@ -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");

View File

@ -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();

View File

@ -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)

View File

@ -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 {

View File

@ -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"])

View File

@ -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"
}
],

View File

@ -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() {

View File

@ -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]
}

View File

@ -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;

View File

@ -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)
})

View File

@ -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