1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

move kubeconfig route

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
Jari Kolehmainen 2020-03-21 10:32:27 +02:00
parent 9c9196e4de
commit f0716e7a28
7 changed files with 66 additions and 124 deletions

View File

@ -14,6 +14,7 @@ import { UserManagement } from "./+user-management/user-management";
import { ConfirmDialog } from "./confirm-dialog";
import { usersManagementRoute } from "./+user-management/user-management.routes";
import { clusterRoute, clusterURL } from "./+cluster";
import { KubeConfigDialog } from "./kubeconfig-dialog/kubeconfig-dialog";
import { Nodes, nodesRoute } from "./+nodes";
import { Workloads, workloadsRoute, workloadsURL } from "./+workloads";
import { Namespaces, namespacesRoute } from "./+namespaces";
@ -70,6 +71,7 @@ class App extends React.Component {
<KubeObjectDetails/>
<Notifications/>
<ConfirmDialog/>
<KubeConfigDialog/>
<AddRoleBindingDialog/>
<PodLogsDialog/>
<DeploymentScaleDialog/>

View File

@ -1,39 +1,20 @@
// Get cluster info
import config from "../config"
import { kubeRequest } from "./kube-request";
import { IClusterInfo, IClusterConfigMap } from "../common/cluster"
import { IClusterInfo } from "../common/cluster"
export async function getClusterInfo(): Promise<IClusterInfo> {
const [configMap, kubeVersion, pharosVersion] = await Promise.all([
getClusterConfigMap().catch(() => ({} as IClusterConfigMap)),
const [kubeVersion] = await Promise.all([
getKubeVersion().catch(() => null),
getPharosVersion().catch(() => null),
]);
return {
...configMap,
kubeVersion,
pharosVersion,
};
}
export async function getClusterConfigMap() {
const res = await kubeRequest<{ data: IClusterConfigMap }>({
path: `/api/v1/namespaces/${config.LENS_NAMESPACE}/configmaps/config`,
});
return res.data;
}
export async function getKubeVersion() {
const res = await kubeRequest<{ gitVersion: string }>({
path: "/version",
});
return res.gitVersion.slice(1);
}
export async function getPharosVersion() {
const res = await kubeRequest<{ data: { "pharos-version": string } }>({
path: `/api/v1/namespaces/kube-system/configmaps/pharos-config`,
});
return res ? res.data["pharos-version"] : null;
}

View File

@ -8,7 +8,7 @@ import compression from "compression"
import helmet from "helmet"
import morgan from "morgan"
import { logger } from "../server/utils/logger"
import { configRoute, kubeconfigRoute, kubewatchRoute, metricsRoute, readyStateRoute } from "../server/routes";
import { configRoute, kubewatchRoute, metricsRoute, readyStateRoute } from "../server/routes";
import { useRequestHeaderToken } from "../server/middlewares";
const {
@ -25,7 +25,6 @@ app.set('trust proxy', 1); // trust first proxy
localApis.use(
configRoute(),
readyStateRoute(),
kubeconfigRoute(),
kubewatchRoute(),
metricsRoute()
);

View File

@ -1,5 +1,4 @@
export * from "./config-route"
export * from "./kubeconfig-route"
export * from "./kubewatch-route"
export * from "./metrics-route"
export * from "./ready-state-route"

View File

@ -1,100 +0,0 @@
//-- Kubeconfig route
import { Router } from "express";
import { AxiosError } from "axios";
import { userSession } from "../user-session";
import { kubeRequest } from "../api/kube-request";
import { Secret } from "../../client/api/endpoints";
import { base64 } from "../../client/utils/base64";
import { getCertificateAuthorityData } from "../api/get-cert-auth-data";
import { getClusterConfigMap } from "../api/get-cluster-info";
interface IKubeConfigParams {
username: string;
authToken: string;
certificateAuthority: string;
namespace?: string;
}
export function kubeconfigRoute() {
const router = Router();
router.route('/kubeconfig/user')
.get(async (req, res) => {
const { username = "kubernetes" } = userSession.get(req);
const authToken = userSession.getToken(req);
const cert = await getCertificateAuthorityData('base64');
const data = await generateKubeConfig({
username,
authToken: authToken,
certificateAuthority: cert
});
res.json(data);
});
router.route('/kubeconfig/service-account/:namespace/:account')
.get(async (req, res) => {
const { authHeader } = userSession.get(req);
const { namespace, account } = req.params;
try {
const secret = await kubeRequest<{ items: Secret[] }>({
path: `/api/v1/namespaces/${namespace}/secrets`,
authHeader: authHeader,
}).then(secrets => {
return secrets.items.find(secret => {
const { annotations } = secret.metadata;
return annotations && annotations["kubernetes.io/service-account.name"] == account;
});
});
const data = await generateKubeConfig({
username: account,
namespace: namespace,
authToken: base64.decode(secret.data.token),
certificateAuthority: secret.data["ca.crt"],
});
res.json(data);
} catch (err) {
const { response }: AxiosError = err;
res.status(403).json(response ? response.data : err.toString());
}
});
return router;
}
async function generateKubeConfig(params: IKubeConfigParams) {
const { clusterName, clusterUrl } = await getClusterConfigMap();
const { authToken, username, certificateAuthority, namespace = "" } = params;
return {
'apiVersion': 'v1',
'kind': 'Config',
'clusters': [
{
'name': clusterName,
'cluster': {
'server': clusterUrl,
'certificate-authority-data': certificateAuthority
}
}
],
'users': [
{
'name': username,
'user': {
'token': authToken,
}
}
],
'contexts': [
{
'name': clusterName,
'context': {
'user': username,
'cluster': clusterName,
'namespace': namespace,
}
}
],
'current-context': clusterName
}
}

View File

@ -2,6 +2,7 @@ import * as http from "http";
import { Cluster } from "./cluster";
import { helmApi } from "./helm-api"
import { resourceApplierApi } from "./resource-applier-api"
import { kubeconfigRoute } from "./routes/kubeconfig"
// eslint-disable-next-line @typescript-eslint/no-var-requires
const Call = require('@hapi/call');
@ -65,6 +66,8 @@ export class Router {
}
protected addRoutes() {
this.router.add({ method: 'get', path: '/api/kubeconfig/service-account/{namespace}/{account}' }, kubeconfigRoute.routeServiceAccountRoute.bind(kubeconfigRoute))
// Helm API
this.router.add({ method: 'get', path: '/api-helm/v2/charts' }, helmApi.listCharts.bind(helmApi))
this.router.add({ method: 'get', path: '/api-helm/v2/charts/{repo}/{chart}' }, helmApi.getChart.bind(helmApi))

View File

@ -0,0 +1,58 @@
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 = new Buffer(secret.data["token"], "base64")
return {
'apiVersion': 'v1',
'kind': 'Config',
'clusters': [
{
'name': cluster.contextName,
'cluster': {
'server': cluster.contextHandler.kc.getCurrentCluster().server,
'certificate-authority-data': secret.data["ca.crt"]
}
}
],
'users': [
{
'name': username,
'user': {
'token': tokenData.toString("utf8"),
}
}
],
'contexts': [
{
'name': cluster.contextName,
'context': {
'user': username,
'cluster': cluster.contextName,
'namespace': secret.metadata.namespace,
}
}
],
'current-context': cluster.contextName
}
}
class KubeconfigRoute extends LensApi {
public async routeServiceAccountRoute(request: LensApiRequest) {
const { params, response, cluster} = request
const client = cluster.contextHandler.kc.makeApiClient(CoreV1Api);
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)
}
}
export const kubeconfigRoute = new KubeconfigRoute()