mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
added new cluster method: cluster.isAllowedResource
Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
parent
da3aa618d7
commit
cc8897e6e7
@ -7,50 +7,40 @@ export type KubeResource =
|
|||||||
"endpoints" | "customresourcedefinitions" | "horizontalpodautoscalers" | "podsecuritypolicies" | "poddisruptionbudgets";
|
"endpoints" | "customresourcedefinitions" | "horizontalpodautoscalers" | "podsecuritypolicies" | "poddisruptionbudgets";
|
||||||
|
|
||||||
export interface KubeApiResource {
|
export interface KubeApiResource {
|
||||||
kind: string; // resource type
|
kind: string; // resource type (e.g. "Namespace")
|
||||||
resource: KubeResource; // valid resource name
|
apiName: KubeResource; // valid api resource name (e.g. "namespaces")
|
||||||
group?: string; // api-group
|
group?: string; // api-group
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: auto-populate all resources dynamically (see: kubectl api-resources -o=wide -v=7)
|
// TODO: auto-populate all resources dynamically (see: kubectl api-resources -o=wide -v=7)
|
||||||
export const apiResources: KubeApiResource[] = [
|
export const apiResources: KubeApiResource[] = [
|
||||||
{ kind: "ConfigMap", resource: "configmaps" },
|
{ kind: "ConfigMap", apiName: "configmaps" },
|
||||||
{ kind: "CronJob", resource: "cronjobs", group: "batch" },
|
{ kind: "CronJob", apiName: "cronjobs", group: "batch" },
|
||||||
{ kind: "CustomResourceDefinition", resource: "customresourcedefinitions", group: "apiextensions.k8s.io" },
|
{ kind: "CustomResourceDefinition", apiName: "customresourcedefinitions", group: "apiextensions.k8s.io" },
|
||||||
{ kind: "DaemonSet", resource: "daemonsets", group: "apps" },
|
{ kind: "DaemonSet", apiName: "daemonsets", group: "apps" },
|
||||||
{ kind: "Deployment", resource: "deployments", group: "apps" },
|
{ kind: "Deployment", apiName: "deployments", group: "apps" },
|
||||||
{ kind: "Endpoint", resource: "endpoints" },
|
{ kind: "Endpoint", apiName: "endpoints" },
|
||||||
{ kind: "Event", resource: "events" },
|
{ kind: "Event", apiName: "events" },
|
||||||
{ kind: "HorizontalPodAutoscaler", resource: "horizontalpodautoscalers" },
|
{ kind: "HorizontalPodAutoscaler", apiName: "horizontalpodautoscalers" },
|
||||||
{ kind: "Ingress", resource: "ingresses", group: "networking.k8s.io" },
|
{ kind: "Ingress", apiName: "ingresses", group: "networking.k8s.io" },
|
||||||
{ kind: "Job", resource: "jobs", group: "batch" },
|
{ kind: "Job", apiName: "jobs", group: "batch" },
|
||||||
{ kind: "Namespace", resource: "namespaces" },
|
{ kind: "Namespace", apiName: "namespaces" },
|
||||||
{ kind: "LimitRange", resource: "limitranges" },
|
{ kind: "LimitRange", apiName: "limitranges" },
|
||||||
{ kind: "NetworkPolicy", resource: "networkpolicies", group: "networking.k8s.io" },
|
{ kind: "NetworkPolicy", apiName: "networkpolicies", group: "networking.k8s.io" },
|
||||||
{ kind: "Node", resource: "nodes" },
|
{ kind: "Node", apiName: "nodes" },
|
||||||
{ kind: "PersistentVolume", resource: "persistentvolumes" },
|
{ kind: "PersistentVolume", apiName: "persistentvolumes" },
|
||||||
{ kind: "PersistentVolumeClaim", resource: "persistentvolumeclaims" },
|
{ kind: "PersistentVolumeClaim", apiName: "persistentvolumeclaims" },
|
||||||
{ kind: "Pod", resource: "pods" },
|
{ kind: "Pod", apiName: "pods" },
|
||||||
{ kind: "PodDisruptionBudget", resource: "poddisruptionbudgets" },
|
{ kind: "PodDisruptionBudget", apiName: "poddisruptionbudgets" },
|
||||||
{ kind: "PodSecurityPolicy", resource: "podsecuritypolicies" },
|
{ kind: "PodSecurityPolicy", apiName: "podsecuritypolicies" },
|
||||||
{ kind: "ResourceQuota", resource: "resourcequotas" },
|
{ kind: "ResourceQuota", apiName: "resourcequotas" },
|
||||||
{ kind: "ReplicaSet", resource: "replicasets", group: "apps" },
|
{ kind: "ReplicaSet", apiName: "replicasets", group: "apps" },
|
||||||
{ kind: "Secret", resource: "secrets" },
|
{ kind: "Secret", apiName: "secrets" },
|
||||||
{ kind: "Service", resource: "services" },
|
{ kind: "Service", apiName: "services" },
|
||||||
{ kind: "StatefulSet", resource: "statefulsets", group: "apps" },
|
{ kind: "StatefulSet", apiName: "statefulsets", group: "apps" },
|
||||||
{ kind: "StorageClass", resource: "storageclasses", group: "storage.k8s.io" },
|
{ kind: "StorageClass", apiName: "storageclasses", group: "storage.k8s.io" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export function isAllowedResourceType(kind: string): boolean {
|
|
||||||
const apiResource = apiResources.find(resource => resource.kind === kind);
|
|
||||||
|
|
||||||
if (apiResource) {
|
|
||||||
return getHostedCluster().allowedResources.includes(apiResource.resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true; // allowed by default for other resources
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isAllowedResource(resources: KubeResource | KubeResource[]) {
|
export function isAllowedResource(resources: KubeResource | KubeResource[]) {
|
||||||
if (!Array.isArray(resources)) {
|
if (!Array.isArray(resources)) {
|
||||||
resources = [resources];
|
resources = [resources];
|
||||||
|
|||||||
@ -216,7 +216,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
* @computed
|
* @computed
|
||||||
*/
|
*/
|
||||||
@computed get name() {
|
@computed get name() {
|
||||||
return this.preferences.clusterName || this.contextName;
|
return this.preferences.clusterName || this.contextName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -271,7 +271,8 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
* @param port port where internal auth proxy is listening
|
* @param port port where internal auth proxy is listening
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@action async init(port: number) {
|
@action
|
||||||
|
async init(port: number) {
|
||||||
try {
|
try {
|
||||||
this.contextHandler = new ContextHandler(this);
|
this.contextHandler = new ContextHandler(this);
|
||||||
this.kubeconfigManager = await KubeconfigManager.create(this, this.contextHandler, port);
|
this.kubeconfigManager = await KubeconfigManager.create(this, this.contextHandler, port);
|
||||||
@ -323,7 +324,8 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
* @param force force activation
|
* @param force force activation
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@action async activate(force = false) {
|
@action
|
||||||
|
async activate(force = false) {
|
||||||
if (this.activated && !force) {
|
if (this.activated && !force) {
|
||||||
return this.pushState();
|
return this.pushState();
|
||||||
}
|
}
|
||||||
@ -362,7 +364,8 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@action async reconnect() {
|
@action
|
||||||
|
async reconnect() {
|
||||||
logger.info(`[CLUSTER]: reconnect`, this.getMeta());
|
logger.info(`[CLUSTER]: reconnect`, this.getMeta());
|
||||||
this.contextHandler?.stopServer();
|
this.contextHandler?.stopServer();
|
||||||
await this.contextHandler?.ensureServer();
|
await this.contextHandler?.ensureServer();
|
||||||
@ -389,7 +392,8 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
* @internal
|
* @internal
|
||||||
* @param opts refresh options
|
* @param opts refresh options
|
||||||
*/
|
*/
|
||||||
@action async refresh(opts: ClusterRefreshOptions = {}) {
|
@action
|
||||||
|
async refresh(opts: ClusterRefreshOptions = {}) {
|
||||||
logger.info(`[CLUSTER]: refresh`, this.getMeta());
|
logger.info(`[CLUSTER]: refresh`, this.getMeta());
|
||||||
await this.whenInitialized;
|
await this.whenInitialized;
|
||||||
await this.refreshConnectionStatus();
|
await this.refreshConnectionStatus();
|
||||||
@ -409,7 +413,8 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@action async refreshMetadata() {
|
@action
|
||||||
|
async refreshMetadata() {
|
||||||
logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta());
|
logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta());
|
||||||
const metadata = await detectorRegistry.detectForCluster(this);
|
const metadata = await detectorRegistry.detectForCluster(this);
|
||||||
const existingMetadata = this.metadata;
|
const existingMetadata = this.metadata;
|
||||||
@ -420,7 +425,8 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@action async refreshConnectionStatus() {
|
@action
|
||||||
|
async refreshConnectionStatus() {
|
||||||
const connectionStatus = await this.getConnectionStatus();
|
const connectionStatus = await this.getConnectionStatus();
|
||||||
|
|
||||||
this.online = connectionStatus > ClusterStatus.Offline;
|
this.online = connectionStatus > ClusterStatus.Offline;
|
||||||
@ -430,7 +436,8 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@action async refreshAllowedResources() {
|
@action
|
||||||
|
async refreshAllowedResources() {
|
||||||
this.allowedNamespaces = await this.getAllowedNamespaces();
|
this.allowedNamespaces = await this.getAllowedNamespaces();
|
||||||
this.allowedResources = await this.getAllowedResources();
|
this.allowedResources = await this.getAllowedResources();
|
||||||
}
|
}
|
||||||
@ -657,7 +664,7 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
for (const namespace of this.allowedNamespaces.slice(0, 10)) {
|
for (const namespace of this.allowedNamespaces.slice(0, 10)) {
|
||||||
if (!this.resourceAccessStatuses.get(apiResource)) {
|
if (!this.resourceAccessStatuses.get(apiResource)) {
|
||||||
const result = await this.canI({
|
const result = await this.canI({
|
||||||
resource: apiResource.resource,
|
resource: apiResource.apiName,
|
||||||
group: apiResource.group,
|
group: apiResource.group,
|
||||||
verb: "list",
|
verb: "list",
|
||||||
namespace
|
namespace
|
||||||
@ -672,9 +679,19 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
|
|
||||||
return apiResources
|
return apiResources
|
||||||
.filter((resource) => this.resourceAccessStatuses.get(resource))
|
.filter((resource) => this.resourceAccessStatuses.get(resource))
|
||||||
.map(apiResource => apiResource.resource);
|
.map(apiResource => apiResource.apiName);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isAllowedResource(kind: string): boolean {
|
||||||
|
const apiResource = apiResources.find(resource => resource.kind === kind || resource.apiName === kind);
|
||||||
|
|
||||||
|
if (apiResource) {
|
||||||
|
return this.allowedResources.includes(apiResource.apiName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; // allowed by default for other resources
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import type { Cluster } from "../main/cluster";
|
||||||
import { action, observable, reaction } from "mobx";
|
import { action, observable, reaction } from "mobx";
|
||||||
import { autobind } from "./utils";
|
import { autobind } from "./utils";
|
||||||
import { KubeObject } from "./api/kube-object";
|
import { KubeObject } from "./api/kube-object";
|
||||||
@ -6,7 +7,6 @@ import { ItemStore } from "./item.store";
|
|||||||
import { apiManager } from "./api/api-manager";
|
import { apiManager } from "./api/api-manager";
|
||||||
import { IKubeApiQueryParams, KubeApi } from "./api/kube-api";
|
import { IKubeApiQueryParams, KubeApi } from "./api/kube-api";
|
||||||
import { KubeJsonApiData } from "./api/kube-json-api";
|
import { KubeJsonApiData } from "./api/kube-json-api";
|
||||||
import { isAllowedResourceType } from "../common/rbac";
|
|
||||||
|
|
||||||
export interface KubeObjectStoreLoadingParams {
|
export interface KubeObjectStoreLoadingParams {
|
||||||
namespaces: string[];
|
namespaces: string[];
|
||||||
@ -76,8 +76,16 @@ export abstract class KubeObjectStore<T extends KubeObject = any> extends ItemSt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async resolveCluster(): Promise<Cluster> {
|
||||||
|
const { getHostedCluster } = await import("../common/cluster-store");
|
||||||
|
|
||||||
|
return getHostedCluster();
|
||||||
|
}
|
||||||
|
|
||||||
protected async loadItems({ namespaces, api }: KubeObjectStoreLoadingParams): Promise<T[]> {
|
protected async loadItems({ namespaces, api }: KubeObjectStoreLoadingParams): Promise<T[]> {
|
||||||
if (isAllowedResourceType(api.kind)) {
|
const cluster = await this.resolveCluster();
|
||||||
|
|
||||||
|
if (cluster.isAllowedResource(api.kind)) {
|
||||||
if (api.isNamespaced) {
|
if (api.isNamespaced) {
|
||||||
return Promise
|
return Promise
|
||||||
.all(namespaces.map(namespace => api.list({ namespace })))
|
.all(namespaces.map(namespace => api.list({ namespace })))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user