Skip to content

Commit

Permalink
frontend: Create apiEndpoint using existing apiName and apiVersion in…
Browse files Browse the repository at this point in the history
…formation

Signed-off-by: Oleksandr Dubenko <[email protected]>
  • Loading branch information
sniok committed Oct 24, 2024
1 parent 5c87b2d commit 97ef2d5
Show file tree
Hide file tree
Showing 37 changed files with 51 additions and 143 deletions.
62 changes: 46 additions & 16 deletions frontend/src/lib/k8s/KubeObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,47 @@ function getAllowedNamespaces() {
}

export class KubeObject<T extends KubeObjectInterface | KubeEvent = any> {
static apiEndpoint: ReturnType<typeof apiFactoryWithNamespace | typeof apiFactory>;
static readOnlyFields: string[] = [];
static objectName: string;

jsonData: T;
/** Readonly field defined as JSONPath paths */
static readOnlyFields: string[] = [];
_clusterName: string;

/** The kind of the object. Corresponding to the resource kind in Kubernetes. */
static readonly kind: string;

/** Name of the resource, plural, used in API */
static readonly apiName: string;

/** Group and version of the resource formatted as "GROUP/VERSION", e.g. "policy.k8s.io/v1". */
static readonly apiVersion: string | string[];

/** Whether the object is namespaced. */
static readonly isNamespaced: boolean;

static _internalApiEndpoint?: ReturnType<typeof apiFactoryWithNamespace | typeof apiFactory>;

static get apiEndpoint() {
if (this._internalApiEndpoint) return this._internalApiEndpoint;

const factory = this.isNamespaced ? apiFactoryWithNamespace : apiFactory;
const versions = Array.isArray(this.apiVersion) ? this.apiVersion : [this.apiVersion];

const factoryArguments = versions.map(apiVersion => {
const [group, version] = apiVersion.includes('/') ? apiVersion.split('/') : ['', apiVersion];
const includeScaleApi = ['Deployment', 'ReplicaSet', 'StatefulSet'].includes(this.kind);

return [group, version, this.apiName, includeScaleApi];
});

const endpoint = factory(...(factoryArguments as any));
this._internalApiEndpoint = endpoint;

return endpoint;
}
static set apiEndpoint(endpoint: ReturnType<typeof apiFactoryWithNamespace | typeof apiFactory>) {
this._internalApiEndpoint = endpoint;
}

constructor(json: T, cluster?: string) {
this.jsonData = json;
this._clusterName = cluster || getCluster() || '';
Expand All @@ -44,21 +78,21 @@ export class KubeObject<T extends KubeObjectInterface | KubeEvent = any> {
}

static get className(): string {
return this.objectName;
return this.kind;
}

get detailsRoute(): string {
return this._class().detailsRoute;
}

static get detailsRoute(): string {
return this.className;
return this.kind;
}

static get pluralName(): string {
// This is a naive way to get the plural name of the object by default. It will
// work in most cases, but for exceptions (like Ingress), we must override this.
return this.className.toLowerCase() + 's';
return this.apiName;
}

get pluralName(): string {
Expand All @@ -71,7 +105,11 @@ export class KubeObject<T extends KubeObjectInterface | KubeEvent = any> {
}

static get listRoute(): string {
return this.detailsRoute + 's';
return this.apiName;
}

get kind() {
return this.jsonData.kind;
}

getDetailsLink() {
Expand Down Expand Up @@ -111,18 +149,10 @@ export class KubeObject<T extends KubeObjectInterface | KubeEvent = any> {
return this.jsonData.metadata;
}

get kind() {
return this.jsonData.kind;
}

get isNamespaced() {
return this._class().isNamespaced;
}

static get isNamespaced() {
return this.apiEndpoint.isNamespaced;
}

getEditableObject() {
const fieldsToRemove = this._class().readOnlyFields;
const code = this.jsonData ? cloneDeep(this.jsonData) : {};
Expand Down
3 changes: 0 additions & 3 deletions frontend/src/lib/k8s/clusterRole.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { apiFactory } from './apiProxy';
import { makeKubeObject } from './KubeObject';
import { KubeRole } from './role';

Expand All @@ -8,8 +7,6 @@ class ClusterRole extends makeKubeObject<KubeRole>() {
static apiVersion = 'rbac.authorization.k8s.io/v1';
static isNamespaced = false;

static apiEndpoint = apiFactory('rbac.authorization.k8s.io', 'v1', 'clusterroles');

get rules() {
return this.jsonData!.rules;
}
Expand Down
3 changes: 0 additions & 3 deletions frontend/src/lib/k8s/clusterRoleBinding.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { apiFactory } from './apiProxy';
import { makeKubeObject } from './KubeObject';
import { KubeRoleBinding } from './roleBinding';

Expand All @@ -8,8 +7,6 @@ class ClusterRoleBinding extends makeKubeObject<KubeRoleBinding>() {
static apiVersion = 'rbac.authorization.k8s.io/v1';
static isNamespaced = false;

static apiEndpoint = apiFactory('rbac.authorization.k8s.io', 'v1', 'clusterrolebindings');

get roleRef() {
return this.jsonData!.roleRef;
}
Expand Down
3 changes: 0 additions & 3 deletions frontend/src/lib/k8s/configMap.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { apiFactoryWithNamespace } from './apiProxy';
import { StringDict } from './cluster';
import { KubeObject, KubeObjectInterface } from './KubeObject';

Expand All @@ -12,8 +11,6 @@ class ConfigMap extends KubeObject<KubeConfigMap> {
static apiVersion = 'v1';
static isNamespaced = true;

static apiEndpoint = apiFactoryWithNamespace('', 'v1', 'configmaps');

get data() {
return this.jsonData.data;
}
Expand Down
4 changes: 0 additions & 4 deletions frontend/src/lib/k8s/crd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,6 @@ class CustomResourceDefinition extends KubeObject<KubeCRD> {
static apiVersion = ['apiextensions.k8s.io/v1', 'apiextensions.k8s.io/v1beta1'];
static isNamespaced = false;

static apiEndpoint = apiFactory(
['apiextensions.k8s.io', 'v1', 'customresourcedefinitions'],
['apiextensions.k8s.io', 'v1beta1', 'customresourcedefinitions']
);
static readOnlyFields = ['metadata.managedFields'];

static get listRoute(): string {
Expand Down
6 changes: 0 additions & 6 deletions frontend/src/lib/k8s/cronJob.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { apiFactoryWithNamespace } from './apiProxy';
import { KubeContainer } from './cluster';
import { KubeMetadata } from './KubeMetadata';
import { KubeObject, KubeObjectInterface } from './KubeObject';
Expand Down Expand Up @@ -42,11 +41,6 @@ class CronJob extends KubeObject<KubeCronJob> {
static apiVersion = ['batch/v1', 'batch/v1beta1'];
static isNamespaced = true;

static apiEndpoint = apiFactoryWithNamespace(
['batch', 'v1', 'cronjobs'],
['batch', 'v1beta1', 'cronjobs']
);

get spec() {
return this.getValue('spec');
}
Expand Down
3 changes: 0 additions & 3 deletions frontend/src/lib/k8s/daemonSet.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { apiFactoryWithNamespace } from './apiProxy';
import { KubeContainer, LabelSelector } from './cluster';
import { KubeMetadata } from './KubeMetadata';
import { KubeObject, KubeObjectInterface } from './KubeObject';
Expand Down Expand Up @@ -30,8 +29,6 @@ class DaemonSet extends KubeObject<KubeDaemonSet> {
static apiVersion = 'apps/v1';
static isNamespaced = true;

static apiEndpoint = apiFactoryWithNamespace('apps', 'v1', 'daemonsets');

get spec() {
return this.jsonData.spec;
}
Expand Down
3 changes: 0 additions & 3 deletions frontend/src/lib/k8s/deployment.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { apiFactoryWithNamespace } from './apiProxy';
import { KubeContainer, LabelSelector } from './cluster';
import { KubeMetadata } from './KubeMetadata';
import { KubeObject, KubeObjectInterface } from './KubeObject';
Expand Down Expand Up @@ -28,8 +27,6 @@ class Deployment extends KubeObject<KubeDeployment> {
static apiVersion = 'apps/v1';
static isNamespaced = true;

static apiEndpoint = apiFactoryWithNamespace('apps', 'v1', 'deployments', true);

get spec() {
return this.getValue('spec');
}
Expand Down
3 changes: 0 additions & 3 deletions frontend/src/lib/k8s/endpoints.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { apiFactoryWithNamespace } from './apiProxy';
import { KubeMetadata } from './KubeMetadata';
import { KubeObject, KubeObjectInterface } from './KubeObject';

Expand Down Expand Up @@ -35,8 +34,6 @@ class Endpoints extends KubeObject<KubeEndpoint> {
static apiVersion = 'v1';
static isNamespaced = true;

static apiEndpoint = apiFactoryWithNamespace('', 'v1', 'endpoints');

// @todo Remove this when we can break backward compatibility.
static get detailsRoute() {
return 'Endpoint';
Expand Down
4 changes: 1 addition & 3 deletions frontend/src/lib/k8s/event.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useMemo } from 'react';
import { ResourceClasses } from '.';
import { ApiError, apiFactoryWithNamespace, QueryParameters } from './apiProxy';
import { ApiError, QueryParameters } from './apiProxy';
import { request } from './apiProxy';
import { KubeMetadata } from './KubeMetadata';
import { KubeObject } from './KubeObject';
Expand Down Expand Up @@ -30,8 +30,6 @@ class Event extends KubeObject<KubeEvent> {

static isNamespaced = true;

static apiEndpoint = apiFactoryWithNamespace('', 'v1', 'events');

// Max number of events to fetch from the API
private static maxEventsLimit = 2000;

Expand Down
3 changes: 0 additions & 3 deletions frontend/src/lib/k8s/hpa.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { ResourceClasses } from '.';
import { apiFactoryWithNamespace } from './apiProxy';
import { KubeMetadata } from './KubeMetadata';
import { KubeObject, KubeObjectClass, KubeObjectInterface } from './KubeObject';
export interface CrossVersionObjectReference {
Expand Down Expand Up @@ -173,8 +172,6 @@ class HPA extends KubeObject<KubeHPA> {
static apiVersion = 'autoscaling/v2';
static isNamespaced = true;

static apiEndpoint = apiFactoryWithNamespace('autoscaling', 'v2', 'horizontalpodautoscalers');

get spec(): HpaSpec {
return this.jsonData.spec;
}
Expand Down
5 changes: 0 additions & 5 deletions frontend/src/lib/k8s/ingress.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { apiFactoryWithNamespace } from './apiProxy';
import { KubeObject, KubeObjectInterface } from './KubeObject';

interface LegacyIngressRule {
Expand Down Expand Up @@ -74,10 +73,6 @@ class Ingress extends KubeObject<KubeIngress> {
static apiVersion = ['networking.k8s.io/v1', 'extensions/v1beta1'];
static isNamespaced = true;

static apiEndpoint = apiFactoryWithNamespace(
['networking.k8s.io', 'v1', 'ingresses'],
['extensions', 'v1beta1', 'ingresses']
);
// Normalized, cached rules.
private cachedRules: IngressRule[] = [];

Expand Down
3 changes: 0 additions & 3 deletions frontend/src/lib/k8s/ingressClass.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { apiFactory } from './apiProxy';
import { KubeObject, KubeObjectInterface } from './KubeObject';

export interface KubeIngressClass extends KubeObjectInterface {
Expand All @@ -14,8 +13,6 @@ class IngressClass extends KubeObject<KubeIngressClass> {
static apiVersion = 'networking.k8s.io/v1';
static isNamespaced = false;

static apiEndpoint = apiFactory(['networking.k8s.io', 'v1', 'ingressclasses']);

get spec(): KubeIngressClass['spec'] {
return this.jsonData.spec;
}
Expand Down
3 changes: 0 additions & 3 deletions frontend/src/lib/k8s/job.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { apiFactoryWithNamespace } from './apiProxy';
import { KubeContainer, LabelSelector } from './cluster';
import { KubeMetadata } from './KubeMetadata';
import { KubeObject, KubeObjectInterface } from './KubeObject';
Expand All @@ -24,8 +23,6 @@ class Job extends KubeObject<KubeJob> {
static apiVersion = 'batch/v1';
static isNamespaced = true;

static apiEndpoint = apiFactoryWithNamespace('batch', 'v1', 'jobs');

get spec() {
return this.jsonData.spec;
}
Expand Down
3 changes: 0 additions & 3 deletions frontend/src/lib/k8s/lease.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { apiFactoryWithNamespace } from './apiProxy';
import { KubeObject, KubeObjectInterface } from './KubeObject';

export interface LeaseSpec {
Expand All @@ -18,8 +17,6 @@ export class Lease extends KubeObject<KubeLease> {
static apiVersion = 'coordination.k8s.io/v1';
static isNamespaced = true;

static apiEndpoint = apiFactoryWithNamespace('coordination.k8s.io', 'v1', 'leases');

get spec() {
return this.jsonData.spec;
}
Expand Down
3 changes: 0 additions & 3 deletions frontend/src/lib/k8s/limitRange.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { apiFactoryWithNamespace } from './apiProxy';
import { KubeObject, KubeObjectInterface } from './KubeObject';

export interface LimitRangeSpec {
Expand Down Expand Up @@ -33,8 +32,6 @@ export class LimitRange extends KubeObject<KubeLimitRange> {
static apiVersion = 'v1';
static isNamespaced = true;

static apiEndpoint = apiFactoryWithNamespace('', 'v1', 'limitranges');

get spec() {
return this.jsonData.spec;
}
Expand Down
7 changes: 0 additions & 7 deletions frontend/src/lib/k8s/mutatingWebhookConfiguration.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { apiFactory } from './apiProxy';
import { LabelSelector } from './cluster';
import { KubeObject, KubeObjectInterface } from './KubeObject';

Expand Down Expand Up @@ -49,12 +48,6 @@ class MutatingWebhookConfiguration extends KubeObject<KubeMutatingWebhookConfigu
static apiVersion = 'admissionregistration.k8s.io/v1';
static isNamespaced = false;

static apiEndpoint = apiFactory(
'admissionregistration.k8s.io',
'v1',
'mutatingwebhookconfigurations'
);

get webhooks(): KubeMutatingWebhookConfiguration['webhooks'] {
return this.jsonData.webhooks;
}
Expand Down
3 changes: 0 additions & 3 deletions frontend/src/lib/k8s/namespace.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { apiFactory } from './apiProxy';
import { KubeCondition } from './cluster';
import { KubeObject, KubeObjectInterface } from './KubeObject';

Expand All @@ -15,8 +14,6 @@ class Namespace extends KubeObject<KubeNamespace> {
static apiVersion = 'v1';
static isNamespaced = false;

static apiEndpoint = apiFactory('', 'v1', 'namespaces');

get status() {
return this.jsonData.status;
}
Expand Down
3 changes: 0 additions & 3 deletions frontend/src/lib/k8s/networkpolicy.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { apiFactoryWithNamespace } from './apiProxy';
import { LabelSelector } from './cluster';
import { KubeObject, KubeObjectInterface } from './KubeObject';

Expand Down Expand Up @@ -42,8 +41,6 @@ class NetworkPolicy extends KubeObject<KubeNetworkPolicy> {
static apiVersion = 'networking.k8s.io/v1';
static isNamespaced = true;

static apiEndpoint = apiFactoryWithNamespace('networking.k8s.io', 'v1', 'networkpolicies');

static get pluralName() {
return 'networkpolicies';
}
Expand Down
4 changes: 1 addition & 3 deletions frontend/src/lib/k8s/node.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { useErrorState } from '../util';
import { useConnectApi } from '.';
import { ApiError, apiFactory, metrics } from './apiProxy';
import { ApiError, metrics } from './apiProxy';
import { KubeCondition, KubeMetrics } from './cluster';
import { KubeObject, KubeObjectInterface } from './KubeObject';

Expand Down Expand Up @@ -59,8 +59,6 @@ class Node extends KubeObject<KubeNode> {
static apiVersion = 'v1';
static isNamespaced = false;

static apiEndpoint = apiFactory('', 'v1', 'nodes');

get status(): KubeNode['status'] {
return this.jsonData.status;
}
Expand Down
Loading

0 comments on commit 97ef2d5

Please sign in to comment.