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

New decc manager

This commit is contained in:
Steve Richards 2020-09-21 17:52:55 +01:00
parent c9e0f573ee
commit 526a38422c
3 changed files with 174 additions and 114 deletions

162
src/main/decc-manager.ts Normal file
View File

@ -0,0 +1,162 @@
import "../common/cluster-ipc";
import type http from "http"
import { autorun } from "mobx";
import { ClusterStore, clusterStore, getClusterIdFromHost } from "../common/cluster-store"
import { Cluster } from "./cluster"
import logger from "./logger";
import { apiKubePrefix } from "../common/vars";
import { workspaceStore, Workspace } from "../common/workspace-store";
import { userStore } from "../common/user-store";
import * as request from "request-promise-native";
import { v4 as uuid } from "uuid";
import {kubeconfig} from '../common/utils/k8sTemplates';
import YAML from 'yaml';
const ignoredDECCNamespaces = [
'kube-system', 'kube-public', 'openstack-provider-system', 'system',
'kaas', 'lcm-system', 'istio-system', 'kube-node-lease', 'stacklight'
];
export class DECCManager {
constructor(protected keycloakServer: http.Server, protected deccURL: string) {
}
// auto-init clusters
// autorun(() => {
// clusterStore.clusters.forEach(cluster => {
// if (!cluster.initialized) {
// logger.info(`[CLUSTER-MANAGER]: init cluster`, cluster.getMeta());
// cluster.init(port);
// }
// });
// });
// // auto-stop removed clusters
// autorun(() => {
// const removedClusters = Array.from(clusterStore.removedClusters.values());
// if (removedClusters.length > 0) {
// const meta = removedClusters.map(cluster => cluster.getMeta());
// logger.info(`[CLUSTER-MANAGER]: removing clusters`, meta);
// removedClusters.forEach(cluster => cluster.disconnect());
// clusterStore.removedClusters.clear();
// }
// }, {
// delay: 250
// });
// }
getNamespacesForUser() {
var namespacesUserCanAccess: Array<Workspace> = workspaceStore.workspacesList;
var parsedToken = userStore.decodeToken (userStore.getTokenDetails().token);
// get all namespaces this id has access to
const namespaces = {
method: 'GET',
url: `http://${this.deccURL}/api/v1/namespaces`,
headers: {
'Authorization': 'Bearer ' + userStore.getTokenDetails().token
},
json: true
};
request(namespaces)
.then(function(response) {
//API call ok....
const deccNamespaces = response["items"];
// logger.info(JSON.stringify(deccNamespaces));
deccNamespaces.forEach(function(namespace) {
if (!ignoredDECCNamespaces.includes(namespace.metadata.name)) {
// console.log("Namespace Name: " + namespace.metadata.name);
let ns = namespace.metadata.name;
//console.log("parsedToken.iam_roles: ", parsedToken.iam_roles);
if (parsedToken.iam_roles.includes(`m:kaas:${ns}@reader`) || parsedToken.iam_roles.includes(`m:kaas:${ns}@writer`)) {
// add namespace to workspaceStore if not present
console.log(`User: ${parsedToken.preferred_username} has access to namespace: ${ns}`);
if (!workspaceStore.getByName(ns)) {
workspaceStore.saveWorkspace({id: uuid(), name: ns, description: `DECC Namespace: ${ns}`});
console.log(`Added new workspace: ${ns}`);
namespacesUserCanAccess.push(ns);
}
};
};
});
return namespacesUserCanAccess;
})
.catch(function (err) {
// API call failed...
console.log(err);
});
}
addClustersToWorkspace() {
var parsedToken = userStore.decodeToken (userStore.getTokenDetails().token);
console.log(`deccURL: ${this.deccURL}`);
workspaceStore.workspacesList.forEach(function(ws) {
console.log(`Adding clusters for ws: ${ws.name}`);
let clusters = {
method: 'GET',
url: `http://a09bfce9ea3074e25b8e5e7b1df576fd-1162277427.eu-west-2.elb.amazonaws.com/apis/cluster.k8s.io/v1alpha1/namespaces/${ws.name}/clusters`,
headers: {
'Authorization': 'Bearer ' + userStore.getTokenDetails().token
},
json: true
};
request(clusters)
.then(function(response) {
//API call ok....
const deccClusters = response["items"];
deccClusters.forEach(function(deccCluster: object) {
// check if cluster is already in the cluster store
let clusterPresent = false;
clusterStore.getByWorkspaceId(ws.id).forEach(wsCluster => {
if (wsCluster.contextName === `${parsedToken.preferred_username}@${deccCluster.metadata.name}`) {
clusterPresent = true;
}
});
if ("status" in deccCluster && !clusterPresent) {
// clusterUCPURL = cluster.status.
let ucpDashboard = `https://${deccCluster.status.providerStatus.ucpDashboard.split(":", 2).reverse()[0].substring(2)}:443`;
console.log (`ucpDashboard: ${ucpDashboard}`);
const jsConfig = kubeconfig({
username: parsedToken.preferred_username,
clusterName: deccCluster.metadata.name,
clientId: deccCluster.status.providerStatus.oidc.clientId,
idpCertificateAuthorityData: deccCluster.status.providerStatus.oidc.certificate,
idpIssuerUrl: deccCluster.status.providerStatus.oidc.issuerUrl,
server: ucpDashboard,
apiCertificate: deccCluster.status.providerStatus.apiServerCertificate,
idToken: userStore.getTokenDetails().token,
refreshToken: userStore.getTokenDetails().refreshToken
});
console.log(`Generated kubeconfig: ${YAML.stringify(jsConfig)}`)
console.log(`Cluster Name: ${deccCluster.metadata.name}, Cluster UCP Dashboard URL: ${deccCluster.status.providerStatus.ucpDashboard}`)
let newCluster = new Cluster({
id: uuid(),
contextName: `${parsedToken.preferred_username}@${deccCluster.metadata.name}`,
preferences: {
clusterName: deccCluster.metadata.name,
httpsProxy: undefined,
},
kubeConfigPath: ClusterStore.embedCustomKubeConfig(deccCluster.metadata.uid, YAML.stringify(jsConfig)),
workspace: ws.name,
});
clusterStore.addCluster(newCluster);
};
});
})
.catch(function (err: string) {
// API call failed...
console.log(err);
});
});
}
}

View File

@ -25,7 +25,8 @@ import { uniqueId } from "lodash";
import { v4 as uuid } from "uuid";
import { Cluster } from "../main/cluster";
import {kubeconfig} from '../common/utils/k8sTemplates';
import YAML from 'yaml'
import YAML from 'yaml';
import { DECCManager } from "./decc-manager";
const workingDir = path.join(app.getPath("appData"), appName);
app.setName(appName);
@ -36,6 +37,7 @@ if (!process.env.CICD) {
let windowManager: WindowManager;
let clusterManager: ClusterManager;
let proxyServer: LensProxy;
let deccManager: DECCManager;
//let clusterStore: ClusterStore;
mangleProxyEnv()
@ -92,6 +94,7 @@ async function main() {
app.quit();
}
//start renderer with keycloak login page
const keycloakServer = http.createServer(function(req: http.IncomingMessage, res: http.ServerResponse) {
res.writeHead(200, {"Content-Type": "text/html"});
@ -99,6 +102,10 @@ async function main() {
readSream.pipe(res);
}).listen(3000);
// create cluster manager
deccManager = new DECCManager(keycloakServer, 'a09bfce9ea3074e25b8e5e7b1df576fd-1162277427.eu-west-2.elb.amazonaws.com');
// create window manager and open app
windowManager = new WindowManager(proxyPort, 3000);
//windowManager = new WindowManager(3000);
@ -140,118 +147,8 @@ ipcMain.on('keycloak-token', (event, idToken, refreshToken) => {
var parsedToken = userStore.decodeToken (idToken);
var namespacesUserCanAccess: string[] = workspaceStore.workspacesList;
// get all namespaces this id has access to
const namespaces = {
method: 'GET',
url: 'http://a09bfce9ea3074e25b8e5e7b1df576fd-1162277427.eu-west-2.elb.amazonaws.com/api/v1/namespaces',
headers: {
'Authorization': 'Bearer ' + userStore.getTokenDetails().token
},
json: true
};
request(namespaces)
.then(function(response) {
//API call ok....
const deccNamespaces = response["items"];
// logger.info(JSON.stringify(deccNamespaces));
deccNamespaces.forEach(function(namespace) {
if (!ignoredDECCNamespaces.includes(namespace.metadata.name)) {
// console.log("Namespace Name: " + namespace.metadata.name);
let ns = namespace.metadata.name;
//console.log("parsedToken.iam_roles: ", parsedToken.iam_roles);
if (parsedToken.iam_roles.includes(`m:kaas:${ns}@reader`) || parsedToken.iam_roles.includes(`m:kaas:${ns}@writer`)) {
// add namespace to workspaceStore if not present
console.log(`User: ${parsedToken.preferred_username} has access to namespace: ${ns}`);
if (!workspaceStore.getByName(ns)) {
workspaceStore.saveWorkspace({id: uuid(), name: ns, description: `DECC Namespace: ${ns}`});
console.log(`Added new workspace: ${ns}`);
namespacesUserCanAccess.push(ns);
}
};
};
});
})
.catch(function (err) {
// API call failed...
console.log(err);
});
// now lets add the clusters for each namespace
workspaceStore.workspacesList.forEach(function(ws) {
console.log(`Adding clusters for ws: ${ws.name}`);
var clusters = {
method: 'GET',
url: `http://a09bfce9ea3074e25b8e5e7b1df576fd-1162277427.eu-west-2.elb.amazonaws.com/apis/cluster.k8s.io/v1alpha1/namespaces/${ws.name}/clusters`,
headers: {
'Authorization': 'Bearer ' + userStore.getTokenDetails().token
},
json: true
};
request(clusters)
.then(function(response) {
//API call ok....
const deccClusters = response["items"];
deccClusters.forEach(function(deccCluster: object) {
// check if cluster is already in the cluster store
let clusterPresent = false;
clusterStore.getByWorkspaceId(ws.id).forEach(wsCluster => {
if (wsCluster.contextName === `${parsedToken.preferred_username}@${deccCluster.metadata.name}`) {
clusterPresent = true;
}
});
if ("status" in deccCluster && !clusterPresent) {
// clusterUCPURL = cluster.status.
let ucpDashboard = `https://${deccCluster.status.providerStatus.ucpDashboard.split(":", 2).reverse()[0].substring(2)}:443`;
console.log (`ucpDashboard: ${ucpDashboard}`);
const jsConfig = kubeconfig({
username: parsedToken.preferred_username,
clusterName: deccCluster.metadata.name,
clientId: deccCluster.status.providerStatus.oidc.clientId,
idpCertificateAuthorityData: deccCluster.status.providerStatus.oidc.certificate,
idpIssuerUrl: deccCluster.status.providerStatus.oidc.issuerUrl,
server: ucpDashboard,
apiCertificate: deccCluster.status.providerStatus.apiServerCertificate,
idToken: idToken,
refreshToken: refreshToken
});
console.log(`Generated kubeconfig: ${YAML.stringify(jsConfig)}`)
console.log(`Cluster Name: ${deccCluster.metadata.name}, Cluster UCP Dashboard URL: ${deccCluster.status.providerStatus.ucpDashboard}`)
let newCluster = new Cluster({
id: uuid(),
contextName: `${parsedToken.preferred_username}@${deccCluster.metadata.name}`,
preferences: {
// icon: "data:;base64,iVBORw0KGgoAAAANSUhEUgAAA1wAAAKoCAYAAABjkf5",
clusterName: deccCluster.metadata.name,
httpsProxy: undefined,
},
kubeConfigPath: ClusterStore.embedCustomKubeConfig(deccCluster.metadata.uid, YAML.stringify(jsConfig)),
workspace: ws.name,
});
clusterStore.addCluster(newCluster);
};
});
})
.catch(function (err: string) {
// API call failed...
console.log(err);
});
});
//TODO: Use vmURL instead of hardcoded localhost:9080 here
// const winURL = process.env.NODE_ENV === 'development'
// ? `http://localhost:9080?token=${token}`
// : `file://${__dirname}/index.html?token=${token}`
deccManager.getNamespacesForUser();
deccManager.addClustersToWorkspace();
//TODO: refresh token!
windowManager.showMain();

View File

@ -7,7 +7,8 @@ const { ipcRenderer } = require('electron')
var keycloak = new Keycloak({
url: 'https://a69adcd0687194b2b8adebdbe93f2a02-977850409.eu-west-2.elb.amazonaws.com/auth',
realm: 'iam',
clientId: 'kaas'
clientId: 'kaas',
scope: 'offline_access openid',
});
//if param "logout" was passed to this page, logout user!