mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Migrating Vue components to React and stores refactoring (#585)
Signed-off-by: Roman <ixrock@gmail.com> Co-authored-by: Sebastian Malton <sebastian@malton.name> Co-authored-by: Sebastian Malton <smalton@mirantis.com> Co-authored-by: Lauri Nevala <lauri.nevala@gmail.com> Co-authored-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
297 files changed
+8186
-9103
No files matched your search
@@ -1,109 +0,0 @@
|
||||
import { app } from "electron"
|
||||
import { CoreV1Api } from "@kubernetes/client-node"
|
||||
import { LensApiRequest } from "../router"
|
||||
import { LensApi } from "../lens-api"
|
||||
import { userStore } from "../../common/user-store"
|
||||
import { Cluster } from "../cluster"
|
||||
|
||||
export interface IConfigRoutePayload {
|
||||
kubeVersion?: string;
|
||||
clusterName?: string;
|
||||
lensVersion?: string;
|
||||
lensTheme?: string;
|
||||
username?: string;
|
||||
token?: string;
|
||||
allowedNamespaces?: string[];
|
||||
allowedResources?: string[];
|
||||
isClusterAdmin?: boolean;
|
||||
chartsEnabled: boolean;
|
||||
kubectlAccess?: boolean; // User accessed via kubectl-lens plugin
|
||||
}
|
||||
|
||||
// TODO: auto-populate all resources dynamically
|
||||
const apiResources = [
|
||||
{ resource: "configmaps" },
|
||||
{ resource: "cronjobs", group: "batch" },
|
||||
{ resource: "customresourcedefinitions", group: "apiextensions.k8s.io" },
|
||||
{ resource: "daemonsets", group: "apps" },
|
||||
{ resource: "deployments", group: "apps" },
|
||||
{ resource: "endpoints" },
|
||||
{ resource: "events" },
|
||||
{ resource: "horizontalpodautoscalers" },
|
||||
{ resource: "ingresses", group: "networking.k8s.io" },
|
||||
{ resource: "jobs", group: "batch" },
|
||||
{ resource: "namespaces" },
|
||||
{ resource: "networkpolicies", group: "networking.k8s.io" },
|
||||
{ resource: "nodes" },
|
||||
{ resource: "persistentvolumes" },
|
||||
{ resource: "pods" },
|
||||
{ resource: "podsecuritypolicies" },
|
||||
{ resource: "resourcequotas" },
|
||||
{ resource: "secrets" },
|
||||
{ resource: "services" },
|
||||
{ resource: "statefulsets", group: "apps" },
|
||||
{ resource: "storageclasses", group: "storage.k8s.io" },
|
||||
]
|
||||
|
||||
async function getAllowedNamespaces(cluster: Cluster) {
|
||||
const api = cluster.proxyKubeconfig().makeApiClient(CoreV1Api)
|
||||
try {
|
||||
const namespaceList = await api.listNamespace()
|
||||
const nsAccessStatuses = await Promise.all(
|
||||
namespaceList.body.items.map(ns => cluster.canI({
|
||||
namespace: ns.metadata.name,
|
||||
resource: "pods",
|
||||
verb: "list",
|
||||
}))
|
||||
)
|
||||
return namespaceList.body.items
|
||||
.filter((ns, i) => nsAccessStatuses[i])
|
||||
.map(ns => ns.metadata.name)
|
||||
} catch(error) {
|
||||
const ctx = cluster.proxyKubeconfig().getContextObject(cluster.contextName)
|
||||
if (ctx.namespace) {
|
||||
return [ctx.namespace]
|
||||
}
|
||||
else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function getAllowedResources(cluster: Cluster, namespaces: string[]) {
|
||||
try {
|
||||
const resourceAccessStatuses = await Promise.all(
|
||||
apiResources.map(apiResource => cluster.canI({
|
||||
resource: apiResource.resource,
|
||||
group: apiResource.group,
|
||||
verb: "list",
|
||||
namespace: namespaces[0]
|
||||
}))
|
||||
)
|
||||
return apiResources
|
||||
.filter((resource, i) => resourceAccessStatuses[i]).map(apiResource => apiResource.resource)
|
||||
} catch (error) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
class ConfigRoute extends LensApi {
|
||||
public async routeConfig(request: LensApiRequest) {
|
||||
const { params, response, cluster } = request
|
||||
|
||||
const namespaces = await getAllowedNamespaces(cluster)
|
||||
const data: IConfigRoutePayload = {
|
||||
clusterName: cluster.contextName,
|
||||
lensVersion: app.getVersion(),
|
||||
lensTheme: `kontena-${userStore.getPreferences().colorTheme}`,
|
||||
kubeVersion: cluster.version,
|
||||
chartsEnabled: true,
|
||||
isClusterAdmin: cluster.isAdmin,
|
||||
allowedResources: await getAllowedResources(cluster, namespaces),
|
||||
allowedNamespaces: namespaces
|
||||
};
|
||||
|
||||
this.respondJson(response, data)
|
||||
}
|
||||
}
|
||||
|
||||
export const configRoute = new ConfigRoute()
|
||||
@@ -0,0 +1,114 @@
|
||||
import { LensApiRequest } from "../router"
|
||||
import { helmService } from "../helm/helm-service"
|
||||
import { LensApi } from "../lens-api"
|
||||
import logger from "../logger"
|
||||
|
||||
class HelmApiRoute extends LensApi {
|
||||
public async listCharts(request: LensApiRequest) {
|
||||
const { response } = request
|
||||
const charts = await helmService.listCharts()
|
||||
this.respondJson(response, charts)
|
||||
}
|
||||
|
||||
public async getChart(request: LensApiRequest) {
|
||||
const { params, query, response } = request
|
||||
const chart = await helmService.getChart(params.repo, params.chart, query.get("version"))
|
||||
this.respondJson(response, chart)
|
||||
}
|
||||
|
||||
public async getChartValues(request: LensApiRequest) {
|
||||
const { params, query, response } = request
|
||||
const values = await helmService.getChartValues(params.repo, params.chart, query.get("version"))
|
||||
this.respondJson(response, values)
|
||||
}
|
||||
|
||||
public async installChart(request: LensApiRequest) {
|
||||
const { payload, cluster, response } = request
|
||||
try {
|
||||
const result = await helmService.installChart(cluster, payload)
|
||||
this.respondJson(response, result, 201)
|
||||
} catch (error) {
|
||||
logger.debug(error)
|
||||
this.respondText(response, error, 422)
|
||||
}
|
||||
}
|
||||
|
||||
public async updateRelease(request: LensApiRequest) {
|
||||
const { cluster, params, payload, response } = request
|
||||
try {
|
||||
const result = await helmService.updateRelease(cluster, params.release, params.namespace, payload )
|
||||
this.respondJson(response, result)
|
||||
} catch (error) {
|
||||
logger.debug(error)
|
||||
this.respondText(response, error, 422)
|
||||
}
|
||||
}
|
||||
|
||||
public async rollbackRelease(request: LensApiRequest) {
|
||||
const { cluster, params, payload, response } = request
|
||||
try {
|
||||
const result = await helmService.rollback(cluster, params.release, params.namespace, payload.revision)
|
||||
this.respondJson(response, result)
|
||||
} catch (error) {
|
||||
logger.debug(error)
|
||||
this.respondText(response, error)
|
||||
}
|
||||
}
|
||||
|
||||
public async listReleases(request: LensApiRequest) {
|
||||
const { cluster, params, response } = request
|
||||
try {
|
||||
const result = await helmService.listReleases(cluster, params.namespace)
|
||||
this.respondJson(response, result)
|
||||
} catch(error) {
|
||||
logger.debug(error)
|
||||
this.respondText(response, error)
|
||||
}
|
||||
}
|
||||
|
||||
public async getRelease(request: LensApiRequest) {
|
||||
const { cluster, params, response } = request
|
||||
try {
|
||||
const result = await helmService.getRelease(cluster, params.release, params.namespace)
|
||||
this.respondJson(response, result)
|
||||
} catch (error) {
|
||||
logger.debug(error)
|
||||
this.respondText(response, error, 422)
|
||||
}
|
||||
}
|
||||
|
||||
public async getReleaseValues(request: LensApiRequest) {
|
||||
const { cluster, params, response } = request
|
||||
try {
|
||||
const result = await helmService.getReleaseValues(cluster, params.release, params.namespace)
|
||||
this.respondText(response, result)
|
||||
} catch (error) {
|
||||
logger.debug(error)
|
||||
this.respondText(response, error, 422)
|
||||
}
|
||||
}
|
||||
|
||||
public async getReleaseHistory(request: LensApiRequest) {
|
||||
const { cluster, params, response } = request
|
||||
try {
|
||||
const result = await helmService.getReleaseHistory(cluster, params.release, params.namespace)
|
||||
this.respondJson(response, result)
|
||||
} catch (error) {
|
||||
logger.debug(error)
|
||||
this.respondText(response, error, 422)
|
||||
}
|
||||
}
|
||||
|
||||
public async deleteRelease(request: LensApiRequest) {
|
||||
const { cluster, params, response } = request
|
||||
try {
|
||||
const result = await helmService.deleteRelease(cluster, params.release, params.namespace)
|
||||
this.respondJson(response, result)
|
||||
} catch (error) {
|
||||
logger.debug(error)
|
||||
this.respondText(response, error, 422)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const helmRoute = new HelmApiRoute()
|
||||
@@ -0,0 +1,6 @@
|
||||
export * from "./kubeconfig-route"
|
||||
export * from "./metrics-route"
|
||||
export * from "./port-forward-route"
|
||||
export * from "./watch-route"
|
||||
export * from "./helm-route"
|
||||
export * from "./resource-applier-route"
|
||||
@@ -4,7 +4,7 @@ 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")
|
||||
const tokenData = Buffer.from(secret.data["token"], "base64")
|
||||
return {
|
||||
'apiVersion': 'v1',
|
||||
'kind': 'Config',
|
||||
@@ -44,7 +44,7 @@ class KubeconfigRoute extends LensApi {
|
||||
public async routeServiceAccountRoute(request: LensApiRequest) {
|
||||
const { params, response, cluster} = request
|
||||
|
||||
const client = cluster.proxyKubeconfig().makeApiClient(CoreV1Api);
|
||||
const client = cluster.getProxyKubeconfig().makeApiClient(CoreV1Api);
|
||||
const secretList = await client.listNamespacedSecret(params.namespace)
|
||||
const secret = secretList.body.items.find(secret => {
|
||||
const { annotations } = secret.metadata;
|
||||
@@ -1,34 +1,25 @@
|
||||
import { LensApiRequest } from "../router"
|
||||
import { LensApi } from "../lens-api"
|
||||
import requestPromise from "request-promise-native"
|
||||
import { PrometheusProviderRegistry, PrometheusProvider, PrometheusNodeQuery, PrometheusClusterQuery, PrometheusPodQuery, PrometheusPvcQuery, PrometheusIngressQuery, PrometheusQueryOpts} from "../prometheus/provider-registry"
|
||||
import { apiPrefix } from "../../common/vars";
|
||||
import { PrometheusClusterQuery, PrometheusIngressQuery, PrometheusNodeQuery, PrometheusPodQuery, PrometheusProvider, PrometheusPvcQuery, PrometheusQueryOpts } from "../prometheus/provider-registry"
|
||||
|
||||
export type IMetricsQuery = string | string[] | {
|
||||
[metricName: string]: string;
|
||||
}
|
||||
|
||||
class MetricsRoute extends LensApi {
|
||||
|
||||
public async routeMetrics(request: LensApiRequest) {
|
||||
const { response, cluster} = request
|
||||
const query: IMetricsQuery = request.payload;
|
||||
const serverUrl = `http://127.0.0.1:${cluster.port}${apiPrefix.KUBE_BASE}`
|
||||
const headers = {
|
||||
"Host": `${cluster.id}.localhost:${cluster.port}`,
|
||||
"Content-type": "application/json",
|
||||
}
|
||||
async routeMetrics(request: LensApiRequest) {
|
||||
const { response, cluster, payload } = request
|
||||
const queryParams: IMetricsQuery = {}
|
||||
request.query.forEach((value: string, key: string) => {
|
||||
queryParams[key] = value
|
||||
})
|
||||
|
||||
let metricsUrl: string
|
||||
let prometheusPath: string
|
||||
let prometheusProvider: PrometheusProvider
|
||||
try {
|
||||
const prometheusPath = await cluster.contextHandler.getPrometheusPath()
|
||||
metricsUrl = `${serverUrl}/api/v1/namespaces/${prometheusPath}/proxy${cluster.getPrometheusApiPrefix()}/api/v1/query_range`
|
||||
prometheusProvider = await cluster.contextHandler.getPrometheusProvider()
|
||||
[prometheusPath, prometheusProvider] = await Promise.all([
|
||||
cluster.contextHandler.getPrometheusPath(),
|
||||
cluster.contextHandler.getPrometheusProvider()
|
||||
])
|
||||
} catch {
|
||||
this.respondJson(response, {})
|
||||
return
|
||||
@@ -36,18 +27,10 @@ class MetricsRoute extends LensApi {
|
||||
// prometheus metrics loader
|
||||
const attempts: { [query: string]: number } = {};
|
||||
const maxAttempts = 5;
|
||||
const loadMetrics = (orgQuery: string): Promise<any> => {
|
||||
const query = orgQuery.trim()
|
||||
const loadMetrics = (promQuery: string): Promise<any> => {
|
||||
const query = promQuery.trim()
|
||||
const attempt = attempts[query] = (attempts[query] || 0) + 1;
|
||||
return requestPromise(metricsUrl, {
|
||||
resolveWithFullResponse: false,
|
||||
headers: headers,
|
||||
json: true,
|
||||
qs: {
|
||||
query: query,
|
||||
...queryParams
|
||||
}
|
||||
}).catch(async (error) => {
|
||||
return cluster.getMetrics(prometheusPath, { query, ...queryParams }).catch(async error => {
|
||||
if (attempt < maxAttempts && (error.statusCode && error.statusCode != 404)) {
|
||||
await new Promise(resolve => setTimeout(resolve, attempt * 1000)); // add delay before repeating request
|
||||
return loadMetrics(query);
|
||||
@@ -63,16 +46,14 @@ class MetricsRoute extends LensApi {
|
||||
|
||||
// return data in same structure as query
|
||||
let data: any;
|
||||
if (typeof query === "string") {
|
||||
data = await loadMetrics(query)
|
||||
}
|
||||
else if (Array.isArray(query)) {
|
||||
data = await Promise.all(query.map(loadMetrics));
|
||||
}
|
||||
else {
|
||||
if (typeof payload === "string") {
|
||||
data = await loadMetrics(payload)
|
||||
} else if (Array.isArray(payload)) {
|
||||
data = await Promise.all(payload.map(loadMetrics));
|
||||
} else {
|
||||
data = {};
|
||||
const result = await Promise.all(
|
||||
Object.entries(query).map((queryEntry: any) => {
|
||||
Object.entries(payload).map((queryEntry: any) => {
|
||||
const queryName: string = queryEntry[0]
|
||||
const queryOpts: PrometheusQueryOpts = queryEntry[1]
|
||||
const queries = prometheusProvider.getQueries(queryOpts)
|
||||
@@ -80,7 +61,7 @@ class MetricsRoute extends LensApi {
|
||||
return loadMetrics(q)
|
||||
})
|
||||
);
|
||||
Object.keys(query).forEach((metricName, index) => {
|
||||
Object.keys(payload).forEach((metricName, index) => {
|
||||
data[metricName] = result[index];
|
||||
});
|
||||
}
|
||||
@@ -37,7 +37,7 @@ class PortForward {
|
||||
|
||||
public async start() {
|
||||
this.localPort = await getFreePort()
|
||||
const kubectlBin = await bundledKubectl.kubectlPath()
|
||||
const kubectlBin = await bundledKubectl.getPath()
|
||||
const args = [
|
||||
"--kubeconfig", this.kubeConfig,
|
||||
"port-forward",
|
||||
@@ -88,7 +88,7 @@ class PortForwardRoute extends LensApi {
|
||||
namespace: namespace,
|
||||
name: resourceName,
|
||||
port: port,
|
||||
kubeConfig: cluster.proxyKubeconfigPath()
|
||||
kubeConfig: cluster.getProxyKubeconfigPath()
|
||||
})
|
||||
const started = await portForward.start()
|
||||
if (!started) {
|
||||
@@ -0,0 +1,17 @@
|
||||
import { LensApiRequest } from "../router"
|
||||
import { LensApi } from "../lens-api"
|
||||
import { ResourceApplier } from "../resource-applier"
|
||||
|
||||
class ResourceApplierApiRoute extends LensApi {
|
||||
public async applyResource(request: LensApiRequest) {
|
||||
const { response, cluster, payload } = request
|
||||
try {
|
||||
const resource = await new ResourceApplier(cluster).apply(payload);
|
||||
this.respondJson(response, [resource], 200)
|
||||
} catch (error) {
|
||||
this.respondText(response, error, 422)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const resourceApplierRoute = new ResourceApplierApiRoute()
|
||||
@@ -87,10 +87,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))
|
||||
logger.debug("watch using kubeconfig:" + JSON.stringify(cluster.getProxyKubeconfig(), null, 2))
|
||||
|
||||
apis.forEach(apiUrl => {
|
||||
const watcher = new ApiWatcher(apiUrl, cluster.proxyKubeconfig(), response)
|
||||
const watcher = new ApiWatcher(apiUrl, cluster.getProxyKubeconfig(), response)
|
||||
watcher.start()
|
||||
watchers.push(watcher)
|
||||
})
|
||||
Reference in new issue
Block a user