mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Allow extensions to define cluster features (#1125)
Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
1 parent
f3a0059355
commit
62ae7771df
81 files changed
+4069
-510
No files matched your search
@@ -3,11 +3,10 @@ import { KubeApi } from "../kube-api";
|
||||
|
||||
export class ClusterRoleBinding extends RoleBinding {
|
||||
static kind = "ClusterRoleBinding"
|
||||
static namespaced = false
|
||||
static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings"
|
||||
}
|
||||
|
||||
export const clusterRoleBindingApi = new KubeApi({
|
||||
kind: ClusterRoleBinding.kind,
|
||||
apiBase: "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings",
|
||||
isNamespaced: false,
|
||||
objectConstructor: ClusterRoleBinding,
|
||||
});
|
||||
@@ -5,11 +5,10 @@ import { KubeApi } from "../kube-api";
|
||||
@autobind()
|
||||
export class ClusterRole extends Role {
|
||||
static kind = "ClusterRole"
|
||||
static namespaced = false
|
||||
static apiBase = "/apis/rbac.authorization.k8s.io/v1/clusterroles"
|
||||
}
|
||||
|
||||
export const clusterRoleApi = new KubeApi({
|
||||
kind: ClusterRole.kind,
|
||||
apiBase: "/apis/rbac.authorization.k8s.io/v1/clusterroles",
|
||||
isNamespaced: false,
|
||||
objectConstructor: ClusterRole,
|
||||
});
|
||||
@@ -3,6 +3,9 @@ import { KubeObject } from "../kube-object";
|
||||
import { KubeApi } from "../kube-api";
|
||||
|
||||
export class ClusterApi extends KubeApi<Cluster> {
|
||||
static kind = "Cluster"
|
||||
static namespaced = true
|
||||
|
||||
async getMetrics(nodeNames: string[], params?: IMetricsReqParams): Promise<IClusterMetrics> {
|
||||
const nodes = nodeNames.join("|");
|
||||
const opts = { category: "cluster", nodes: nodes }
|
||||
@@ -49,6 +52,7 @@ export interface IClusterMetrics<T = IMetrics> {
|
||||
|
||||
export class Cluster extends KubeObject {
|
||||
static kind = "Cluster";
|
||||
static apiBase = "/apis/cluster.k8s.io/v1alpha1/clusters"
|
||||
|
||||
spec: {
|
||||
clusterNetwork?: {
|
||||
@@ -91,8 +95,5 @@ export class Cluster extends KubeObject {
|
||||
}
|
||||
|
||||
export const clusterApi = new ClusterApi({
|
||||
kind: Cluster.kind,
|
||||
apiBase: "/apis/cluster.k8s.io/v1alpha1/clusters",
|
||||
isNamespaced: true,
|
||||
objectConstructor: Cluster,
|
||||
});
|
||||
@@ -9,6 +9,8 @@ export interface IComponentStatusCondition {
|
||||
|
||||
export class ComponentStatus extends KubeObject {
|
||||
static kind = "ComponentStatus"
|
||||
static namespaced = false
|
||||
static apiBase = "/api/v1/componentstatuses"
|
||||
|
||||
conditions: IComponentStatusCondition[]
|
||||
|
||||
@@ -18,8 +20,5 @@ export class ComponentStatus extends KubeObject {
|
||||
}
|
||||
|
||||
export const componentStatusApi = new KubeApi({
|
||||
kind: ComponentStatus.kind,
|
||||
apiBase: "/api/v1/componentstatuses",
|
||||
isNamespaced: false,
|
||||
objectConstructor: ComponentStatus,
|
||||
});
|
||||
@@ -6,6 +6,8 @@ import { KubeApi } from "../kube-api";
|
||||
@autobind()
|
||||
export class ConfigMap extends KubeObject {
|
||||
static kind = "ConfigMap";
|
||||
static namespaced = true;
|
||||
static apiBase = "/api/v1/configmaps"
|
||||
|
||||
constructor(data: KubeJsonApiData) {
|
||||
super(data);
|
||||
@@ -22,8 +24,5 @@ export class ConfigMap extends KubeObject {
|
||||
}
|
||||
|
||||
export const configMapApi = new KubeApi({
|
||||
kind: ConfigMap.kind,
|
||||
apiBase: "/api/v1/configmaps",
|
||||
isNamespaced: true,
|
||||
objectConstructor: ConfigMap,
|
||||
});
|
||||
@@ -19,6 +19,8 @@ type AdditionalPrinterColumnsV1Beta = AdditionalPrinterColumnsCommon & {
|
||||
|
||||
export class CustomResourceDefinition extends KubeObject {
|
||||
static kind = "CustomResourceDefinition";
|
||||
static namespaced = false;
|
||||
static apiBase = "/apis/apiextensions.k8s.io/v1/customresourcedefinitions"
|
||||
|
||||
spec: {
|
||||
group: string;
|
||||
@@ -145,9 +147,6 @@ export class CustomResourceDefinition extends KubeObject {
|
||||
}
|
||||
|
||||
export const crdApi = new VersionedKubeApi<CustomResourceDefinition>({
|
||||
kind: CustomResourceDefinition.kind,
|
||||
apiBase: "/apis/apiextensions.k8s.io/v1/customresourcedefinitions",
|
||||
isNamespaced: false,
|
||||
objectConstructor: CustomResourceDefinition
|
||||
});
|
||||
|
||||
@@ -8,6 +8,8 @@ import { KubeApi } from "../kube-api";
|
||||
@autobind()
|
||||
export class CronJob extends KubeObject {
|
||||
static kind = "CronJob"
|
||||
static namespaced = true
|
||||
static apiBase = "/apis/batch/v1beta1/cronjobs"
|
||||
|
||||
kind: string
|
||||
apiVersion: string
|
||||
@@ -88,8 +90,5 @@ export class CronJob extends KubeObject {
|
||||
}
|
||||
|
||||
export const cronJobApi = new KubeApi({
|
||||
kind: CronJob.kind,
|
||||
apiBase: "/apis/batch/v1beta1/cronjobs",
|
||||
isNamespaced: true,
|
||||
objectConstructor: CronJob,
|
||||
});
|
||||
@@ -7,6 +7,8 @@ import { KubeApi } from "../kube-api";
|
||||
@autobind()
|
||||
export class DaemonSet extends WorkloadKubeObject {
|
||||
static kind = "DaemonSet"
|
||||
static namespaced = true
|
||||
static apiBase = "/apis/apps/v1/daemonsets"
|
||||
|
||||
spec: {
|
||||
selector: {
|
||||
@@ -69,8 +71,5 @@ export class DaemonSet extends WorkloadKubeObject {
|
||||
}
|
||||
|
||||
export const daemonSetApi = new KubeApi({
|
||||
kind: DaemonSet.kind,
|
||||
apiBase: "/apis/apps/v1/daemonsets",
|
||||
isNamespaced: true,
|
||||
objectConstructor: DaemonSet,
|
||||
});
|
||||
@@ -28,6 +28,8 @@ export class DeploymentApi extends KubeApi<Deployment> {
|
||||
@autobind()
|
||||
export class Deployment extends WorkloadKubeObject {
|
||||
static kind = "Deployment"
|
||||
static namespaced = true
|
||||
static apiBase = "/apis/apps/v1/deployments"
|
||||
|
||||
spec: {
|
||||
replicas: number;
|
||||
@@ -164,8 +166,5 @@ export class Deployment extends WorkloadKubeObject {
|
||||
}
|
||||
|
||||
export const deploymentApi = new DeploymentApi({
|
||||
kind: Deployment.kind,
|
||||
apiBase: "/apis/apps/v1/deployments",
|
||||
isNamespaced: true,
|
||||
objectConstructor: Deployment,
|
||||
});
|
||||
@@ -99,6 +99,8 @@ export class EndpointSubset implements IEndpointSubset {
|
||||
@autobind()
|
||||
export class Endpoint extends KubeObject {
|
||||
static kind = "Endpoints"
|
||||
static namespaced = true
|
||||
static apiBase = "/api/v1/endpoints"
|
||||
|
||||
subsets: IEndpointSubset[]
|
||||
|
||||
@@ -118,8 +120,5 @@ export class Endpoint extends KubeObject {
|
||||
}
|
||||
|
||||
export const endpointApi = new KubeApi({
|
||||
kind: Endpoint.kind,
|
||||
apiBase: "/api/v1/endpoints",
|
||||
isNamespaced: true,
|
||||
objectConstructor: Endpoint,
|
||||
});
|
||||
@@ -7,6 +7,8 @@ import { KubeApi } from "../kube-api";
|
||||
@autobind()
|
||||
export class KubeEvent extends KubeObject {
|
||||
static kind = "Event"
|
||||
static namespaced = true
|
||||
static apiBase = "/api/v1/events"
|
||||
|
||||
involvedObject: {
|
||||
kind: string;
|
||||
@@ -52,8 +54,5 @@ export class KubeEvent extends KubeObject {
|
||||
}
|
||||
|
||||
export const eventApi = new KubeApi({
|
||||
kind: KubeEvent.kind,
|
||||
apiBase: "/api/v1/events",
|
||||
isNamespaced: true,
|
||||
objectConstructor: KubeEvent,
|
||||
})
|
||||
@@ -40,6 +40,8 @@ export interface IHpaMetric {
|
||||
|
||||
export class HorizontalPodAutoscaler extends KubeObject {
|
||||
static kind = "HorizontalPodAutoscaler";
|
||||
static namespaced = true;
|
||||
static apiBase = "/apis/autoscaling/v2beta1/horizontalpodautoscalers"
|
||||
|
||||
spec: {
|
||||
scaleTargetRef: {
|
||||
@@ -133,8 +135,5 @@ export class HorizontalPodAutoscaler extends KubeObject {
|
||||
}
|
||||
|
||||
export const hpaApi = new KubeApi({
|
||||
kind: HorizontalPodAutoscaler.kind,
|
||||
apiBase: "/apis/autoscaling/v2beta1/horizontalpodautoscalers",
|
||||
isNamespaced: true,
|
||||
objectConstructor: HorizontalPodAutoscaler,
|
||||
});
|
||||
@@ -32,6 +32,8 @@ export interface ILoadBalancerIngress {
|
||||
@autobind()
|
||||
export class Ingress extends KubeObject {
|
||||
static kind = "Ingress"
|
||||
static namespaced = true
|
||||
static apiBase = "/apis/extensions/v1beta1/ingresses"
|
||||
|
||||
spec: {
|
||||
tls: {
|
||||
@@ -110,8 +112,5 @@ export class Ingress extends KubeObject {
|
||||
}
|
||||
|
||||
export const ingressApi = new IngressApi({
|
||||
kind: Ingress.kind,
|
||||
apiBase: "/apis/extensions/v1beta1/ingresses",
|
||||
isNamespaced: true,
|
||||
objectConstructor: Ingress,
|
||||
});
|
||||
@@ -8,6 +8,8 @@ import { JsonApiParams } from "../json-api";
|
||||
@autobind()
|
||||
export class Job extends WorkloadKubeObject {
|
||||
static kind = "Job"
|
||||
static namespaced = true
|
||||
static apiBase = "/apis/batch/v1/jobs"
|
||||
|
||||
spec: {
|
||||
parallelism?: number;
|
||||
@@ -102,8 +104,5 @@ export class Job extends WorkloadKubeObject {
|
||||
}
|
||||
|
||||
export const jobApi = new KubeApi({
|
||||
kind: Job.kind,
|
||||
apiBase: "/apis/batch/v1/jobs",
|
||||
isNamespaced: true,
|
||||
objectConstructor: Job,
|
||||
});
|
||||
@@ -10,6 +10,8 @@ export enum NamespaceStatus {
|
||||
@autobind()
|
||||
export class Namespace extends KubeObject {
|
||||
static kind = "Namespace";
|
||||
static namespaced = false;
|
||||
static apiBase = "/api/v1/namespaces";
|
||||
|
||||
status?: {
|
||||
phase: string;
|
||||
@@ -21,8 +23,5 @@ export class Namespace extends KubeObject {
|
||||
}
|
||||
|
||||
export const namespacesApi = new KubeApi({
|
||||
kind: Namespace.kind,
|
||||
apiBase: "/api/v1/namespaces",
|
||||
isNamespaced: false,
|
||||
objectConstructor: Namespace,
|
||||
});
|
||||
@@ -38,6 +38,8 @@ export interface IPolicyEgress {
|
||||
@autobind()
|
||||
export class NetworkPolicy extends KubeObject {
|
||||
static kind = "NetworkPolicy"
|
||||
static namespaced = true
|
||||
static apiBase = "/apis/networking.k8s.io/v1/networkpolicies"
|
||||
|
||||
spec: {
|
||||
podSelector: {
|
||||
@@ -65,8 +67,5 @@ export class NetworkPolicy extends KubeObject {
|
||||
}
|
||||
|
||||
export const networkPolicyApi = new KubeApi({
|
||||
kind: NetworkPolicy.kind,
|
||||
apiBase: "/apis/networking.k8s.io/v1/networkpolicies",
|
||||
isNamespaced: true,
|
||||
objectConstructor: NetworkPolicy,
|
||||
});
|
||||
@@ -31,6 +31,8 @@ export interface INodeMetrics<T = IMetrics> {
|
||||
@autobind()
|
||||
export class Node extends KubeObject {
|
||||
static kind = "Node"
|
||||
static namespaced = false
|
||||
static apiBase = "/api/v1/nodes"
|
||||
|
||||
spec: {
|
||||
podCIDR: string;
|
||||
@@ -156,8 +158,5 @@ export class Node extends KubeObject {
|
||||
}
|
||||
|
||||
export const nodesApi = new NodesApi({
|
||||
kind: Node.kind,
|
||||
apiBase: "/api/v1/nodes",
|
||||
isNamespaced: false,
|
||||
objectConstructor: Node,
|
||||
});
|
||||
@@ -24,6 +24,8 @@ export interface IPvcMetrics<T = IMetrics> {
|
||||
@autobind()
|
||||
export class PersistentVolumeClaim extends KubeObject {
|
||||
static kind = "PersistentVolumeClaim"
|
||||
static namespaced = true
|
||||
static apiBase = "/api/v1/persistentvolumeclaims"
|
||||
|
||||
spec: {
|
||||
accessModes: string[];
|
||||
@@ -81,8 +83,5 @@ export class PersistentVolumeClaim extends KubeObject {
|
||||
}
|
||||
|
||||
export const pvcApi = new PersistentVolumeClaimsApi({
|
||||
kind: PersistentVolumeClaim.kind,
|
||||
apiBase: "/api/v1/persistentvolumeclaims",
|
||||
isNamespaced: true,
|
||||
objectConstructor: PersistentVolumeClaim,
|
||||
});
|
||||
@@ -6,6 +6,8 @@ import { KubeApi } from "../kube-api";
|
||||
@autobind()
|
||||
export class PersistentVolume extends KubeObject {
|
||||
static kind = "PersistentVolume"
|
||||
static namespaced = false
|
||||
static apiBase = "/api/v1/persistentvolumes"
|
||||
|
||||
spec: {
|
||||
capacity: {
|
||||
@@ -64,8 +66,5 @@ export class PersistentVolume extends KubeObject {
|
||||
}
|
||||
|
||||
export const persistentVolumeApi = new KubeApi({
|
||||
kind: PersistentVolume.kind,
|
||||
apiBase: "/api/v1/persistentvolumes",
|
||||
isNamespaced: false,
|
||||
objectConstructor: PersistentVolume,
|
||||
});
|
||||
@@ -2,6 +2,10 @@ import { KubeObject } from "../kube-object";
|
||||
import { KubeApi } from "../kube-api";
|
||||
|
||||
export class PodMetrics extends KubeObject {
|
||||
static kind = "Pod"
|
||||
static namespaced = true
|
||||
static apiBase = "/apis/metrics.k8s.io/v1beta1/pods"
|
||||
|
||||
timestamp: string
|
||||
window: string
|
||||
containers: {
|
||||
@@ -14,8 +18,5 @@ export class PodMetrics extends KubeObject {
|
||||
}
|
||||
|
||||
export const podMetricsApi = new KubeApi({
|
||||
kind: PodMetrics.kind,
|
||||
apiBase: "/apis/metrics.k8s.io/v1beta1/pods",
|
||||
isNamespaced: true,
|
||||
objectConstructor: PodMetrics,
|
||||
});
|
||||
@@ -5,6 +5,8 @@ import { KubeApi } from "../kube-api";
|
||||
@autobind()
|
||||
export class PodDisruptionBudget extends KubeObject {
|
||||
static kind = "PodDisruptionBudget";
|
||||
static namespaced = true;
|
||||
static apiBase = "/apis/policy/v1beta1/poddisruptionbudgets";
|
||||
|
||||
spec: {
|
||||
minAvailable: string;
|
||||
@@ -42,8 +44,5 @@ export class PodDisruptionBudget extends KubeObject {
|
||||
}
|
||||
|
||||
export const pdbApi = new KubeApi({
|
||||
kind: PodDisruptionBudget.kind,
|
||||
apiBase: "/apis/policy/v1beta1/poddisruptionbudgets",
|
||||
isNamespaced: true,
|
||||
objectConstructor: PodDisruptionBudget,
|
||||
});
|
||||
@@ -163,6 +163,8 @@ export interface IPodContainerStatus {
|
||||
@autobind()
|
||||
export class Pod extends WorkloadKubeObject {
|
||||
static kind = "Pod"
|
||||
static namespaced = true
|
||||
static apiBase = "/api/v1/pods"
|
||||
|
||||
spec: {
|
||||
volumes?: {
|
||||
@@ -419,8 +421,5 @@ export class Pod extends WorkloadKubeObject {
|
||||
}
|
||||
|
||||
export const podsApi = new PodsApi({
|
||||
kind: Pod.kind,
|
||||
apiBase: "/api/v1/pods",
|
||||
isNamespaced: true,
|
||||
objectConstructor: Pod,
|
||||
});
|
||||
@@ -5,6 +5,8 @@ import { KubeApi } from "../kube-api";
|
||||
@autobind()
|
||||
export class PodSecurityPolicy extends KubeObject {
|
||||
static kind = "PodSecurityPolicy"
|
||||
static namespaced = false
|
||||
static apiBase = "/apis/policy/v1beta1/podsecuritypolicies"
|
||||
|
||||
spec: {
|
||||
allowPrivilegeEscalation?: boolean;
|
||||
@@ -87,8 +89,5 @@ export class PodSecurityPolicy extends KubeObject {
|
||||
}
|
||||
|
||||
export const pspApi = new KubeApi({
|
||||
kind: PodSecurityPolicy.kind,
|
||||
apiBase: "/apis/policy/v1beta1/podsecuritypolicies",
|
||||
isNamespaced: false,
|
||||
objectConstructor: PodSecurityPolicy,
|
||||
});
|
||||
@@ -7,6 +7,8 @@ import { KubeApi } from "../kube-api";
|
||||
@autobind()
|
||||
export class ReplicaSet extends WorkloadKubeObject {
|
||||
static kind = "ReplicaSet"
|
||||
static namespaced = true
|
||||
static apiBase = "/apis/apps/v1/replicasets"
|
||||
|
||||
spec: {
|
||||
replicas?: number;
|
||||
@@ -51,8 +53,5 @@ export class ReplicaSet extends WorkloadKubeObject {
|
||||
}
|
||||
|
||||
export const replicaSetApi = new KubeApi({
|
||||
kind: ReplicaSet.kind,
|
||||
apiBase: "/apis/apps/v1/replicasets",
|
||||
isNamespaced: true,
|
||||
objectConstructor: ReplicaSet,
|
||||
});
|
||||
@@ -32,6 +32,8 @@ export interface IResourceQuotaValues {
|
||||
|
||||
export class ResourceQuota extends KubeObject {
|
||||
static kind = "ResourceQuota"
|
||||
static namespaced = true
|
||||
static apiBase = "/api/v1/resourcequotas"
|
||||
|
||||
constructor(data: KubeJsonApiData) {
|
||||
super(data);
|
||||
@@ -61,8 +63,5 @@ export class ResourceQuota extends KubeObject {
|
||||
}
|
||||
|
||||
export const resourceQuotaApi = new KubeApi({
|
||||
kind: ResourceQuota.kind,
|
||||
apiBase: "/api/v1/resourcequotas",
|
||||
isNamespaced: true,
|
||||
objectConstructor: ResourceQuota,
|
||||
});
|
||||
@@ -12,6 +12,8 @@ export interface IRoleBindingSubject {
|
||||
@autobind()
|
||||
export class RoleBinding extends KubeObject {
|
||||
static kind = "RoleBinding"
|
||||
static namespaced = true
|
||||
static apiBase = "/apis/rbac.authorization.k8s.io/v1/rolebindings"
|
||||
|
||||
subjects?: IRoleBindingSubject[]
|
||||
roleRef: {
|
||||
@@ -30,8 +32,5 @@ export class RoleBinding extends KubeObject {
|
||||
}
|
||||
|
||||
export const roleBindingApi = new KubeApi({
|
||||
kind: RoleBinding.kind,
|
||||
apiBase: "/apis/rbac.authorization.k8s.io/v1/rolebindings",
|
||||
isNamespaced: true,
|
||||
objectConstructor: RoleBinding,
|
||||
});
|
||||
@@ -3,6 +3,8 @@ import { KubeApi } from "../kube-api";
|
||||
|
||||
export class Role extends KubeObject {
|
||||
static kind = "Role"
|
||||
static namespaced = true
|
||||
static apiBase = "/apis/rbac.authorization.k8s.io/v1/roles"
|
||||
|
||||
rules: {
|
||||
verbs: string[];
|
||||
@@ -17,8 +19,5 @@ export class Role extends KubeObject {
|
||||
}
|
||||
|
||||
export const roleApi = new KubeApi({
|
||||
kind: Role.kind,
|
||||
apiBase: "/apis/rbac.authorization.k8s.io/v1/roles",
|
||||
isNamespaced: true,
|
||||
objectConstructor: Role,
|
||||
});
|
||||
@@ -22,6 +22,8 @@ export interface ISecretRef {
|
||||
@autobind()
|
||||
export class Secret extends KubeObject {
|
||||
static kind = "Secret"
|
||||
static namespaced = true
|
||||
static apiBase = "/api/v1/secrets"
|
||||
|
||||
type: SecretType;
|
||||
data: {
|
||||
@@ -44,8 +46,5 @@ export class Secret extends KubeObject {
|
||||
}
|
||||
|
||||
export const secretsApi = new KubeApi({
|
||||
kind: Secret.kind,
|
||||
apiBase: "/api/v1/secrets",
|
||||
isNamespaced: true,
|
||||
objectConstructor: Secret,
|
||||
});
|
||||
@@ -22,6 +22,8 @@ export interface ISelfSubjectReviewRule {
|
||||
|
||||
export class SelfSubjectRulesReview extends KubeObject {
|
||||
static kind = "SelfSubjectRulesReview"
|
||||
static namespaced = false
|
||||
static apiBase = "/apis/authorization.k8s.io/v1/selfsubjectrulesreviews"
|
||||
|
||||
spec: {
|
||||
// todo: add more types from api docs
|
||||
@@ -61,8 +63,5 @@ export class SelfSubjectRulesReview extends KubeObject {
|
||||
}
|
||||
|
||||
export const selfSubjectRulesReviewApi = new SelfSubjectRulesReviewApi({
|
||||
kind: SelfSubjectRulesReview.kind,
|
||||
apiBase: "/apis/authorization.k8s.io/v1/selfsubjectrulesreviews",
|
||||
isNamespaced: false,
|
||||
objectConstructor: SelfSubjectRulesReview,
|
||||
});
|
||||
@@ -5,6 +5,8 @@ import { KubeApi } from "../kube-api";
|
||||
@autobind()
|
||||
export class ServiceAccount extends KubeObject {
|
||||
static kind = "ServiceAccount";
|
||||
static namespaced = true;
|
||||
static apiBase = "/api/v1/serviceaccounts"
|
||||
|
||||
secrets?: {
|
||||
name: string;
|
||||
@@ -23,8 +25,5 @@ export class ServiceAccount extends KubeObject {
|
||||
}
|
||||
|
||||
export const serviceAccountsApi = new KubeApi<ServiceAccount>({
|
||||
kind: ServiceAccount.kind,
|
||||
apiBase: "/api/v1/serviceaccounts",
|
||||
isNamespaced: true,
|
||||
objectConstructor: ServiceAccount,
|
||||
});
|
||||
@@ -32,6 +32,8 @@ export class ServicePort implements IServicePort {
|
||||
@autobind()
|
||||
export class Service extends KubeObject {
|
||||
static kind = "Service"
|
||||
static namespaced = true
|
||||
static apiBase = "/api/v1/services"
|
||||
|
||||
spec: {
|
||||
type: string;
|
||||
@@ -93,8 +95,5 @@ export class Service extends KubeObject {
|
||||
}
|
||||
|
||||
export const serviceApi = new KubeApi({
|
||||
kind: Service.kind,
|
||||
apiBase: "/api/v1/services",
|
||||
isNamespaced: true,
|
||||
objectConstructor: Service,
|
||||
});
|
||||
@@ -7,6 +7,8 @@ import { KubeApi } from "../kube-api";
|
||||
@autobind()
|
||||
export class StatefulSet extends WorkloadKubeObject {
|
||||
static kind = "StatefulSet"
|
||||
static namespaced = true
|
||||
static apiBase = "/apis/apps/v1/statefulsets"
|
||||
|
||||
spec: {
|
||||
serviceName: string;
|
||||
@@ -77,8 +79,5 @@ export class StatefulSet extends WorkloadKubeObject {
|
||||
}
|
||||
|
||||
export const statefulSetApi = new KubeApi({
|
||||
kind: StatefulSet.kind,
|
||||
apiBase: "/apis/apps/v1/statefulsets",
|
||||
isNamespaced: true,
|
||||
objectConstructor: StatefulSet,
|
||||
});
|
||||
@@ -5,6 +5,8 @@ import { KubeApi } from "../kube-api";
|
||||
@autobind()
|
||||
export class StorageClass extends KubeObject {
|
||||
static kind = "StorageClass"
|
||||
static namespaced = false
|
||||
static apiBase = "/apis/storage.k8s.io/v1/storageclasses"
|
||||
|
||||
provisioner: string; // e.g. "storage.k8s.io/v1"
|
||||
mountOptions?: string[];
|
||||
@@ -32,8 +34,5 @@ export class StorageClass extends KubeObject {
|
||||
}
|
||||
|
||||
export const storageClassApi = new KubeApi({
|
||||
kind: StorageClass.kind,
|
||||
apiBase: "/apis/storage.k8s.io/v1/storageclasses",
|
||||
isNamespaced: false,
|
||||
objectConstructor: StorageClass,
|
||||
});
|
||||
@@ -8,13 +8,15 @@ import { apiKube } from "./index";
|
||||
import { kubeWatchApi } from "./kube-watch-api";
|
||||
import { apiManager } from "./api-manager";
|
||||
import { createKubeApiURL, parseKubeApi } from "./kube-api-parse";
|
||||
import { apiKubePrefix, isDevelopment } from "../../common/vars";
|
||||
import * as URL from "url"
|
||||
|
||||
export interface IKubeApiOptions<T extends KubeObject> {
|
||||
kind: string; // resource type within api-group, e.g. "Namespace"
|
||||
apiBase: string; // base api-path for listing all resources, e.g. "/api/v1/pods"
|
||||
isNamespaced: boolean;
|
||||
apiBase?: string; // base api-path for listing all resources, e.g. "/api/v1/pods"
|
||||
objectConstructor?: IKubeObjectConstructor<T>;
|
||||
request?: KubeJsonApi;
|
||||
isNamespaced?: boolean;
|
||||
kind?: string;
|
||||
}
|
||||
|
||||
export interface IKubeApiQueryParams {
|
||||
@@ -25,6 +27,25 @@ export interface IKubeApiQueryParams {
|
||||
continue?: string; // might be used with ?limit from second request
|
||||
}
|
||||
|
||||
export interface IKubeApiCluster {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export function forCluster<T extends KubeObject>(cluster: IKubeApiCluster, kubeClass: IKubeObjectConstructor<T>): KubeApi<T> {
|
||||
const request = new KubeJsonApi({
|
||||
apiBase: apiKubePrefix,
|
||||
debug: isDevelopment,
|
||||
}, {
|
||||
headers: {
|
||||
"X-Cluster-ID": cluster.id
|
||||
}
|
||||
});
|
||||
return new KubeApi({
|
||||
objectConstructor: kubeClass,
|
||||
request: request
|
||||
})
|
||||
}
|
||||
|
||||
export class KubeApi<T extends KubeObject = any> {
|
||||
static parseApi = parseKubeApi;
|
||||
|
||||
@@ -48,11 +69,14 @@ export class KubeApi<T extends KubeObject = any> {
|
||||
|
||||
constructor(protected options: IKubeApiOptions<T>) {
|
||||
const {
|
||||
kind,
|
||||
isNamespaced = false,
|
||||
objectConstructor = KubeObject as IKubeObjectConstructor,
|
||||
request = apiKube
|
||||
request = apiKube,
|
||||
kind = options.objectConstructor?.kind,
|
||||
isNamespaced = options.objectConstructor?.namespaced
|
||||
} = options || {};
|
||||
if (!options.apiBase) {
|
||||
options.apiBase = objectConstructor.apiBase
|
||||
}
|
||||
const { apiBase, apiPrefix, apiGroup, apiVersion, apiVersionWithGroup, resource } = KubeApi.parseApi(options.apiBase);
|
||||
|
||||
this.kind = kind;
|
||||
@@ -174,4 +198,4 @@ export class KubeApi<T extends KubeObject = any> {
|
||||
}
|
||||
}
|
||||
|
||||
export * from "./kube-api-parse"
|
||||
export * from "./kube-api-parse"
|
||||
@@ -10,6 +10,8 @@ import { resourceApplierApi } from "./endpoints/resource-applier.api";
|
||||
|
||||
export type IKubeObjectConstructor<T extends KubeObject = any> = (new (data: KubeJsonApiData | any) => T) & {
|
||||
kind?: string;
|
||||
namespaced?: boolean;
|
||||
apiBase?: string;
|
||||
};
|
||||
|
||||
export interface IKubeObjectMetadata {
|
||||
@@ -43,6 +45,7 @@ export type IKubeMetaField = keyof IKubeObjectMetadata;
|
||||
@autobind()
|
||||
export class KubeObject implements ItemObject {
|
||||
static readonly kind: string;
|
||||
static readonly namespaced: boolean;
|
||||
|
||||
static create(data: any) {
|
||||
return new KubeObject(data);
|
||||
@@ -157,4 +160,4 @@ export class KubeObject implements ItemObject {
|
||||
delete(params?: JsonApiParams) {
|
||||
return apiKube.del(this.selfLink, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +1,87 @@
|
||||
import React from "react";
|
||||
import { observable, reaction, comparer } from "mobx";
|
||||
import { observer, disposeOnUnmount } from "mobx-react";
|
||||
import { clusterIpc } from "../../../../common/cluster-ipc";
|
||||
import { Cluster } from "../../../../main/cluster";
|
||||
import { Button } from "../../button";
|
||||
import { Notifications } from "../../notifications";
|
||||
import { Spinner } from "../../spinner";
|
||||
import { ClusterFeature } from "../../../../extensions/cluster-feature";
|
||||
import { interval } from "../../../utils";
|
||||
|
||||
interface Props {
|
||||
cluster: Cluster
|
||||
feature: string
|
||||
feature: ClusterFeature
|
||||
}
|
||||
|
||||
@observer
|
||||
export class InstallFeature extends React.Component<Props> {
|
||||
@observable loading = false;
|
||||
@observable message = "";
|
||||
|
||||
componentDidMount() {
|
||||
const feature = this.props.feature
|
||||
const cluster = this.props.cluster
|
||||
const statusUpdate = interval(20, () => {
|
||||
feature.updateStatus(cluster)
|
||||
})
|
||||
statusUpdate.start(true)
|
||||
|
||||
disposeOnUnmount(this, () => {
|
||||
statusUpdate.stop()
|
||||
})
|
||||
|
||||
disposeOnUnmount(this,
|
||||
reaction(() => this.props.cluster.features[this.props.feature], () => {
|
||||
reaction(() => feature.status.installed, () => {
|
||||
this.loading = false;
|
||||
this.message = ""
|
||||
}, { equals: comparer.structural })
|
||||
);
|
||||
}
|
||||
|
||||
getActionButtons() {
|
||||
const { cluster, feature } = this.props;
|
||||
const features = cluster.features[feature];
|
||||
const disabled = !cluster.isAdmin || this.loading;
|
||||
const loadingIcon = this.loading ? <Spinner/> : null;
|
||||
if (!features) return null;
|
||||
return (
|
||||
<div className="flex gaps align-center">
|
||||
{features.canUpgrade &&
|
||||
{feature.status.canUpgrade &&
|
||||
<Button
|
||||
primary
|
||||
disabled={disabled}
|
||||
onClick={this.runAction(() =>
|
||||
clusterIpc.upgradeFeature.invokeFromRenderer(cluster.id, feature))
|
||||
}
|
||||
feature.upgrade(cluster)
|
||||
)}
|
||||
>
|
||||
Upgrade
|
||||
</Button>
|
||||
}
|
||||
{features.installed &&
|
||||
{feature.status.installed &&
|
||||
<Button
|
||||
accent
|
||||
disabled={disabled}
|
||||
onClick={this.runAction(() =>
|
||||
clusterIpc.uninstallFeature.invokeFromRenderer(cluster.id, feature))
|
||||
}
|
||||
onClick={this.runAction(async () => {
|
||||
this.message = "Uninstalling feature ..."
|
||||
feature.uninstall(cluster)
|
||||
})}
|
||||
>
|
||||
Uninstall
|
||||
</Button>
|
||||
}
|
||||
{!features.installed && !features.canUpgrade &&
|
||||
{!feature.status.installed && !feature.status.canUpgrade &&
|
||||
<Button
|
||||
primary
|
||||
disabled={disabled}
|
||||
onClick={this.runAction(() =>
|
||||
clusterIpc.installFeature.invokeFromRenderer(cluster.id, feature))
|
||||
}
|
||||
onClick={this.runAction(async () =>{
|
||||
this.message = "Installing feature ..."
|
||||
feature.install(cluster)
|
||||
})}
|
||||
>
|
||||
Install
|
||||
</Button>
|
||||
}
|
||||
{loadingIcon}
|
||||
{!cluster.isAdmin && <span className='admin-note'>Actions can only be performed by admins.</span>}
|
||||
{cluster.isAdmin && this.loading && this.message !== "" && <span className='admin-note'>{this.message}</span>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -90,4 +105,4 @@ export class InstallFeature extends React.Component<Props> {
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,7 @@ import React from "react";
|
||||
import { Cluster } from "../../../main/cluster";
|
||||
import { InstallFeature } from "./components/install-feature";
|
||||
import { SubTitle } from "../layout/sub-title";
|
||||
import { MetricsFeature } from "../../../features/metrics";
|
||||
import { UserModeFeature } from "../../../features/user-mode";
|
||||
import { clusterFeatureRegistry } from "../../../extensions/registries/cluster-feature-registry";
|
||||
|
||||
interface Props {
|
||||
cluster: Cluster;
|
||||
@@ -12,31 +11,20 @@ interface Props {
|
||||
export class Features extends React.Component<Props> {
|
||||
render() {
|
||||
const { cluster } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>Features</h2>
|
||||
<InstallFeature cluster={cluster} feature={MetricsFeature.id}>
|
||||
<>
|
||||
<SubTitle title="Metrics"/>
|
||||
<p>
|
||||
Enable timeseries data visualization (Prometheus stack) for your cluster.
|
||||
Install this only if you don't have existing Prometheus stack installed.
|
||||
You can see preview of manifests{" "}
|
||||
<a href="https://github.com/lensapp/lens/tree/master/src/features/metrics" target="_blank">here</a>.
|
||||
</p>
|
||||
</>
|
||||
</InstallFeature>
|
||||
<InstallFeature cluster={cluster} feature={UserModeFeature.id}>
|
||||
<>
|
||||
<SubTitle title="User Mode"/>
|
||||
<p>
|
||||
User Mode feature enables non-admin users to see namespaces they have access to.{" "}
|
||||
This is achieved by configuring RBAC rules so that every authenticated user is granted to list namespaces.
|
||||
</p>
|
||||
</>
|
||||
</InstallFeature>
|
||||
{ clusterFeatureRegistry.getItems().map((f) => {
|
||||
return (
|
||||
<InstallFeature cluster={cluster} feature={f.feature}>
|
||||
<>
|
||||
<SubTitle title={f.title}/>
|
||||
<p><f.components.Description /></p>
|
||||
</>
|
||||
</InstallFeature>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user