mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Tag cluster & workspace as beta features in extension api (#1589)
* mark cluster & workspace as beta Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * back to public Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
parent
a5b3106946
commit
2e2220cb60
@ -26,6 +26,11 @@ export interface WorkspaceState {
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Workspace
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
export class Workspace implements WorkspaceModel, WorkspaceState {
|
||||
/**
|
||||
* Unique id for workspace
|
||||
@ -78,23 +83,39 @@ export class Workspace implements WorkspaceModel, WorkspaceState {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is workspace managed by an extension
|
||||
*/
|
||||
get isManaged(): boolean {
|
||||
return !!this.ownerRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get workspace state
|
||||
*
|
||||
*/
|
||||
getState(): WorkspaceState {
|
||||
return toJS({
|
||||
enabled: this.enabled
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Push state
|
||||
*
|
||||
* @interal
|
||||
* @param state workspace state
|
||||
*/
|
||||
pushState(state = this.getState()) {
|
||||
logger.silly("[WORKSPACE] pushing state", {...state, id: this.id});
|
||||
broadcastMessage("workspace:state", this.id, toJS(state));
|
||||
}
|
||||
|
||||
@action
|
||||
setState(state: WorkspaceState) {
|
||||
/**
|
||||
*
|
||||
* @param state workspace state
|
||||
*/
|
||||
@action setState(state: WorkspaceState) {
|
||||
Object.assign(this, state);
|
||||
}
|
||||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
export { ExtensionStore } from "../extension-store";
|
||||
|
||||
export { clusterStore, Cluster } from "../stores/cluster-store";
|
||||
export { clusterStore, Cluster, ClusterStore } from "../stores/cluster-store";
|
||||
export type { ClusterModel, ClusterId } from "../stores/cluster-store";
|
||||
|
||||
export { workspaceStore, Workspace } from "../stores/workspace-store";
|
||||
export { workspaceStore, Workspace, WorkspaceStore } from "../stores/workspace-store";
|
||||
export type { WorkspaceId, WorkspaceModel } from "../stores/workspace-store";
|
||||
|
||||
|
||||
@ -9,6 +9,8 @@ export type { ClusterModel, ClusterId } from "../../common/cluster-store";
|
||||
|
||||
/**
|
||||
* Store for all added clusters
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
export class ClusterStore extends Singleton {
|
||||
|
||||
|
||||
@ -7,6 +7,8 @@ export type { WorkspaceId, WorkspaceModel } from "../../common/workspace-store";
|
||||
|
||||
/**
|
||||
* Stores all workspaces
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
export class WorkspaceStore extends Singleton {
|
||||
/**
|
||||
|
||||
@ -49,10 +49,31 @@ export interface ClusterState {
|
||||
allowedResources: string[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Cluster
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
export class Cluster implements ClusterModel, ClusterState {
|
||||
/** Unique id for a cluster */
|
||||
public id: ClusterId;
|
||||
/**
|
||||
* Kubectl
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public kubeCtl: Kubectl;
|
||||
/**
|
||||
* Context handler
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public contextHandler: ContextHandler;
|
||||
/**
|
||||
* Owner reference
|
||||
*
|
||||
* If extension sets this it needs to also mark cluster as enabled on activate (or when added to a store)
|
||||
*/
|
||||
public ownerRef: string;
|
||||
protected kubeconfigManager: KubeconfigManager;
|
||||
protected eventDisposers: Function[] = [];
|
||||
@ -61,34 +82,147 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
whenInitialized = when(() => this.initialized);
|
||||
whenReady = when(() => this.ready);
|
||||
|
||||
/**
|
||||
* Is cluster object initialized
|
||||
*
|
||||
* @observable
|
||||
*/
|
||||
@observable initialized = false;
|
||||
/**
|
||||
* Kubeconfig context name
|
||||
*
|
||||
* @observable
|
||||
*/
|
||||
@observable contextName: string;
|
||||
/**
|
||||
* Workspace id
|
||||
*
|
||||
* @observable
|
||||
*/
|
||||
@observable workspace: WorkspaceId;
|
||||
/**
|
||||
* Path to kubeconfig
|
||||
*
|
||||
* @observable
|
||||
*/
|
||||
@observable kubeConfigPath: string;
|
||||
/**
|
||||
* Kubernetes API server URL
|
||||
*
|
||||
* @observable
|
||||
*/
|
||||
@observable apiUrl: string; // cluster server url
|
||||
/**
|
||||
* Internal authentication proxy URL
|
||||
*
|
||||
* @observable
|
||||
* @internal
|
||||
*/
|
||||
@observable kubeProxyUrl: string; // lens-proxy to kube-api url
|
||||
/**
|
||||
* Is cluster instance enabled (disabled clusters are currently hidden)
|
||||
*
|
||||
* @observable
|
||||
*/
|
||||
@observable enabled = false; // only enabled clusters are visible to users
|
||||
/**
|
||||
* Is cluster online
|
||||
*
|
||||
* @observable
|
||||
*/
|
||||
@observable online = false; // describes if we can detect that cluster is online
|
||||
/**
|
||||
* Can user access cluster resources
|
||||
*
|
||||
* @observable
|
||||
*/
|
||||
@observable accessible = false; // if user is able to access cluster resources
|
||||
/**
|
||||
* Is cluster instance in usable state
|
||||
*
|
||||
* @observable
|
||||
*/
|
||||
@observable ready = false; // cluster is in usable state
|
||||
/**
|
||||
* Is cluster currently reconnecting
|
||||
*
|
||||
* @observable
|
||||
*/
|
||||
@observable reconnecting = false;
|
||||
@observable disconnected = true; // false if user has selected to connect
|
||||
/**
|
||||
* Is cluster disconnected. False if user has selected to connect.
|
||||
*
|
||||
* @observable
|
||||
*/
|
||||
@observable disconnected = true;
|
||||
/**
|
||||
* Connection failure reason
|
||||
*
|
||||
* @observable
|
||||
*/
|
||||
@observable failureReason: string;
|
||||
/**
|
||||
* Does user have admin like access
|
||||
*
|
||||
* @observable
|
||||
*/
|
||||
@observable isAdmin = false;
|
||||
/**
|
||||
* Preferences
|
||||
*
|
||||
* @observable
|
||||
*/
|
||||
@observable preferences: ClusterPreferences = {};
|
||||
/**
|
||||
* Metadata
|
||||
*
|
||||
* @observable
|
||||
*/
|
||||
@observable metadata: ClusterMetadata = {};
|
||||
/**
|
||||
* List of allowed namespaces
|
||||
*
|
||||
* @observable
|
||||
*/
|
||||
@observable allowedNamespaces: string[] = [];
|
||||
/**
|
||||
* List of allowed resources
|
||||
*
|
||||
* @observable
|
||||
* @internal
|
||||
*/
|
||||
@observable allowedResources: string[] = [];
|
||||
/**
|
||||
* List of accessible namespaces
|
||||
*
|
||||
* @observable
|
||||
*/
|
||||
@observable accessibleNamespaces: string[] = [];
|
||||
|
||||
/**
|
||||
* Is cluster available
|
||||
*
|
||||
* @computed
|
||||
*/
|
||||
@computed get available() {
|
||||
return this.accessible && !this.disconnected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cluster name
|
||||
*
|
||||
* @computed
|
||||
*/
|
||||
@computed get name() {
|
||||
return this.preferences.clusterName || this.contextName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prometheus preferences
|
||||
*
|
||||
* @computed
|
||||
* @internal
|
||||
*/
|
||||
@computed get prometheusPreferences(): ClusterPrometheusPreferences {
|
||||
const { prometheus, prometheusProvider } = this.preferences;
|
||||
|
||||
@ -97,6 +231,9 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Kubernetes version
|
||||
*/
|
||||
get version(): string {
|
||||
return String(this.metadata?.version) || "";
|
||||
}
|
||||
@ -110,17 +247,29 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is cluster managed by an extension
|
||||
*/
|
||||
get isManaged(): boolean {
|
||||
return !!this.ownerRef;
|
||||
}
|
||||
|
||||
@action
|
||||
updateModel(model: ClusterModel) {
|
||||
/**
|
||||
* Update cluster data model
|
||||
*
|
||||
* @param model
|
||||
*/
|
||||
@action updateModel(model: ClusterModel) {
|
||||
Object.assign(this, model);
|
||||
}
|
||||
|
||||
@action
|
||||
async init(port: number) {
|
||||
/**
|
||||
* Initialize a cluster (can be done only in main process)
|
||||
*
|
||||
* @param port port where internal auth proxy is listening
|
||||
* @internal
|
||||
*/
|
||||
@action async init(port: number) {
|
||||
try {
|
||||
this.contextHandler = new ContextHandler(this);
|
||||
this.kubeconfigManager = await KubeconfigManager.create(this, this.contextHandler, port);
|
||||
@ -139,6 +288,9 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
protected bindEvents() {
|
||||
logger.info(`[CLUSTER]: bind events`, this.getMeta());
|
||||
const refreshTimer = setInterval(() => !this.disconnected && this.refresh(), 30000); // every 30s
|
||||
@ -156,14 +308,20 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* internal
|
||||
*/
|
||||
protected unbindEvents() {
|
||||
logger.info(`[CLUSTER]: unbind events`, this.getMeta());
|
||||
this.eventDisposers.forEach(dispose => dispose());
|
||||
this.eventDisposers.length = 0;
|
||||
}
|
||||
|
||||
@action
|
||||
async activate(force = false) {
|
||||
/**
|
||||
* @param force force activation
|
||||
* @internal
|
||||
*/
|
||||
@action async activate(force = false) {
|
||||
if (this.activated && !force) {
|
||||
return this.pushState();
|
||||
}
|
||||
@ -190,22 +348,29 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
return this.pushState();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
protected async ensureKubectl() {
|
||||
this.kubeCtl = new Kubectl(this.version);
|
||||
|
||||
return this.kubeCtl.ensureKubectl(); // download kubectl in background, so it's not blocking dashboard
|
||||
}
|
||||
|
||||
@action
|
||||
async reconnect() {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@action async reconnect() {
|
||||
logger.info(`[CLUSTER]: reconnect`, this.getMeta());
|
||||
this.contextHandler?.stopServer();
|
||||
await this.contextHandler?.ensureServer();
|
||||
this.disconnected = false;
|
||||
}
|
||||
|
||||
@action
|
||||
disconnect() {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@action disconnect() {
|
||||
logger.info(`[CLUSTER]: disconnect`, this.getMeta());
|
||||
this.unbindEvents();
|
||||
this.contextHandler?.stopServer();
|
||||
@ -217,8 +382,11 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
this.pushState();
|
||||
}
|
||||
|
||||
@action
|
||||
async refresh(opts: ClusterRefreshOptions = {}) {
|
||||
/**
|
||||
* @internal
|
||||
* @param opts refresh options
|
||||
*/
|
||||
@action async refresh(opts: ClusterRefreshOptions = {}) {
|
||||
logger.info(`[CLUSTER]: refresh`, this.getMeta());
|
||||
await this.whenInitialized;
|
||||
await this.refreshConnectionStatus();
|
||||
@ -235,8 +403,10 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
this.pushState();
|
||||
}
|
||||
|
||||
@action
|
||||
async refreshMetadata() {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@action async refreshMetadata() {
|
||||
logger.info(`[CLUSTER]: refreshMetadata`, this.getMeta());
|
||||
const metadata = await detectorRegistry.detectForCluster(this);
|
||||
const existingMetadata = this.metadata;
|
||||
@ -244,16 +414,20 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
this.metadata = Object.assign(existingMetadata, metadata);
|
||||
}
|
||||
|
||||
@action
|
||||
async refreshConnectionStatus() {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@action async refreshConnectionStatus() {
|
||||
const connectionStatus = await this.getConnectionStatus();
|
||||
|
||||
this.online = connectionStatus > ClusterStatus.Offline;
|
||||
this.accessible = connectionStatus == ClusterStatus.AccessGranted;
|
||||
}
|
||||
|
||||
@action
|
||||
async refreshAllowedResources() {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@action async refreshAllowedResources() {
|
||||
this.allowedNamespaces = await this.getAllowedNamespaces();
|
||||
this.allowedResources = await this.getAllowedResources();
|
||||
}
|
||||
@ -262,10 +436,16 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
return loadConfig(this.kubeConfigPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getProxyKubeconfig(): KubeConfig {
|
||||
return loadConfig(this.getProxyKubeconfigPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
getProxyKubeconfigPath(): string {
|
||||
return this.kubeconfigManager.getPath();
|
||||
}
|
||||
@ -279,6 +459,12 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
return request(this.kubeProxyUrl + path, options);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param prometheusPath path to prometheus service
|
||||
* @param queryParams query parameters
|
||||
* @internal
|
||||
*/
|
||||
getMetrics(prometheusPath: string, queryParams: IMetricsReqParams & { query: string }) {
|
||||
const prometheusPrefix = this.preferences.prometheus?.prefix || "";
|
||||
const metricsPath = `/api/v1/namespaces/${prometheusPath}/proxy${prometheusPrefix}/api/v1/query_range`;
|
||||
@ -329,6 +515,10 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param resourceAttributes resource attributes
|
||||
*/
|
||||
async canI(resourceAttributes: V1ResourceAttributes): Promise<boolean> {
|
||||
const authApi = this.getProxyKubeconfig().makeApiClient(AuthorizationV1Api);
|
||||
|
||||
@ -347,6 +537,9 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
async isClusterAdmin(): Promise<boolean> {
|
||||
return this.canI({
|
||||
namespace: "kube-system",
|
||||
@ -372,7 +565,9 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
});
|
||||
}
|
||||
|
||||
// serializable cluster-state used for sync btw main <-> renderer
|
||||
/**
|
||||
* Serializable cluster-state used for sync btw main <-> renderer
|
||||
*/
|
||||
getState(): ClusterState {
|
||||
const state: ClusterState = {
|
||||
initialized: this.initialized,
|
||||
@ -393,11 +588,18 @@ export class Cluster implements ClusterModel, ClusterState {
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
setState(state: ClusterState) {
|
||||
/**
|
||||
* @internal
|
||||
* @param state cluster state
|
||||
*/
|
||||
@action setState(state: ClusterState) {
|
||||
Object.assign(this, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param state cluster state
|
||||
*/
|
||||
pushState(state = this.getState()) {
|
||||
logger.silly(`[CLUSTER]: push-state`, state);
|
||||
broadcastMessage("cluster:state", this.id, state);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user