mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
chore: Change refactoring of implementation to maintain behaviour
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
8395c262ad
commit
dcc5495312
@ -9,33 +9,35 @@ import apiKubeInjectable from "../../../renderer/k8s/api-kube.injectable";
|
||||
import type { StatefulSetApi } from "../endpoints";
|
||||
import statefulSetApiInjectable from "../endpoints/stateful-set.api.injectable";
|
||||
import type { KubeJsonApi } from "../kube-json-api";
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import { flushPromises } from "@k8slens/test-utils";
|
||||
|
||||
describe("StatefulSetApi", () => {
|
||||
let statefulSetApi: StatefulSetApi;
|
||||
let kubeJsonApi: jest.Mocked<KubeJsonApi>;
|
||||
let kubeJsonApiPatchMock: AsyncFnMock<KubeJsonApi["patch"]>;
|
||||
let kubeJsonApiGetMock: AsyncFnMock<KubeJsonApi["get"]>;
|
||||
|
||||
beforeEach(() => {
|
||||
const di = getDiForUnitTesting();
|
||||
|
||||
di.override(storesAndApisCanBeCreatedInjectable, () => true);
|
||||
kubeJsonApi = {
|
||||
getResponse: jest.fn(),
|
||||
get: jest.fn(),
|
||||
post: jest.fn(),
|
||||
put: jest.fn(),
|
||||
patch: jest.fn(),
|
||||
del: jest.fn(),
|
||||
} as never;
|
||||
di.override(apiKubeInjectable, () => kubeJsonApi);
|
||||
kubeJsonApiPatchMock = asyncFn();
|
||||
kubeJsonApiGetMock = asyncFn();
|
||||
di.override(apiKubeInjectable, () => ({
|
||||
get: kubeJsonApiGetMock,
|
||||
patch: kubeJsonApiPatchMock,
|
||||
} as Partial<KubeJsonApi> as KubeJsonApi));
|
||||
|
||||
statefulSetApi = di.inject(statefulSetApiInjectable);
|
||||
});
|
||||
|
||||
describe("scale", () => {
|
||||
it("requests Kubernetes API with PATCH verb and correct amount of replicas", () => {
|
||||
statefulSetApi.scale({ namespace: "default", name: "statefulset-1" }, 5);
|
||||
it("requests Kubernetes API with PATCH verb and correct amount of replicas", async () => {
|
||||
const req = statefulSetApi.scale({ namespace: "default", name: "statefulset-1" }, 5);
|
||||
|
||||
expect(kubeJsonApi.patch).toHaveBeenCalledWith("/apis/apps/v1/namespaces/default/statefulsets/statefulset-1/scale", {
|
||||
await flushPromises();
|
||||
expect(kubeJsonApiPatchMock).toHaveBeenCalledWith("/apis/apps/v1/namespaces/default/statefulsets/statefulset-1/scale", {
|
||||
data: {
|
||||
spec: {
|
||||
replicas: 5,
|
||||
@ -47,6 +49,19 @@ describe("StatefulSetApi", () => {
|
||||
"content-type": "application/merge-patch+json",
|
||||
},
|
||||
});
|
||||
|
||||
await kubeJsonApiPatchMock.resolve({});
|
||||
await req;
|
||||
});
|
||||
|
||||
it("requests Kubernetes API with GET verb and correct sub-resource", async () => {
|
||||
const req = statefulSetApi.getReplicas({ namespace: "default", name: "statefulset-1" });
|
||||
|
||||
await flushPromises();
|
||||
expect(kubeJsonApiGetMock).toHaveBeenCalledWith("/apis/apps/v1/namespaces/default/statefulsets/statefulset-1/scale");
|
||||
await kubeJsonApiGetMock.resolve({ status: { replicas: 10 }});
|
||||
|
||||
expect(await req).toBe(10);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -8,7 +8,6 @@ import moment from "moment";
|
||||
import type { DerivedKubeApiOptions, KubeApiDependencies, NamespacedResourceDescriptor } from "../kube-api";
|
||||
import { KubeApi } from "../kube-api";
|
||||
import { Deployment } from "@k8slens/kube-object";
|
||||
import { hasTypedProperty, isNumber, isObject } from "@k8slens/utilities";
|
||||
|
||||
export class DeploymentApi extends KubeApi<Deployment> {
|
||||
constructor(deps: KubeApiDependencies, opts?: DerivedKubeApiOptions) {
|
||||
@ -18,33 +17,14 @@ export class DeploymentApi extends KubeApi<Deployment> {
|
||||
});
|
||||
}
|
||||
|
||||
protected getScaleApiUrl(params: NamespacedResourceDescriptor) {
|
||||
return `${this.formatUrlForNotListing(params)}/scale`;
|
||||
}
|
||||
|
||||
async getReplicas(params: NamespacedResourceDescriptor): Promise<number> {
|
||||
const { status } = await this.request.get(this.getScaleApiUrl(params));
|
||||
const { status } = await this.getResourceScale(params);
|
||||
|
||||
if (isObject(status) && hasTypedProperty(status, "replicas", isNumber)) {
|
||||
return status.replicas;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return status.replicas;
|
||||
}
|
||||
|
||||
scale(params: NamespacedResourceDescriptor, replicas: number) {
|
||||
return this.request.patch(this.getScaleApiUrl(params), {
|
||||
data: {
|
||||
spec: {
|
||||
replicas,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"content-type": "application/merge-patch+json",
|
||||
},
|
||||
});
|
||||
return this.scaleResource(params, { spec: { replicas }});
|
||||
}
|
||||
|
||||
restart(params: NamespacedResourceDescriptor) {
|
||||
|
||||
@ -15,24 +15,13 @@ export class ReplicaSetApi extends KubeApi<ReplicaSet> {
|
||||
});
|
||||
}
|
||||
|
||||
protected getScaleApiUrl(params: NamespacedResourceDescriptor) {
|
||||
return `${this.formatUrlForNotListing(params)}/scale`;
|
||||
}
|
||||
|
||||
async getReplicas(params: NamespacedResourceDescriptor): Promise<number> {
|
||||
const { status } = await this.request.get(this.getScaleApiUrl(params));
|
||||
const { status } = await this.getResourceScale(params);
|
||||
|
||||
return (status as { replicas: number })?.replicas;
|
||||
return status.replicas;
|
||||
}
|
||||
|
||||
scale(params: NamespacedResourceDescriptor, replicas: number) {
|
||||
return this.request.put(this.getScaleApiUrl(params), {
|
||||
data: {
|
||||
metadata: params,
|
||||
spec: {
|
||||
replicas,
|
||||
},
|
||||
},
|
||||
});
|
||||
return this.scaleResource(params, { spec: { replicas }});
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,17 +25,6 @@ export class ReplicationControllerApi extends KubeApi<ReplicationController> {
|
||||
}
|
||||
|
||||
scale(params: NamespacedResourceDescriptor, replicas: number): Promise<Scale> {
|
||||
return this.request.patch(this.getScaleApiUrl(params), {
|
||||
data: {
|
||||
metadata: params,
|
||||
spec: {
|
||||
replicas,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
headers: {
|
||||
"content-type": "application/strategic-merge-patch+json",
|
||||
},
|
||||
});
|
||||
return this.scaleResource(params, { spec: { replicas }});
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,23 +17,14 @@ export class StatefulSetApi extends KubeApi<StatefulSet> {
|
||||
});
|
||||
}
|
||||
|
||||
protected getScaleApiUrl(params: NamespacedResourceDescriptor) {
|
||||
return `${this.formatUrlForNotListing(params)}/scale`;
|
||||
}
|
||||
|
||||
async getReplicas(params: NamespacedResourceDescriptor): Promise<number> {
|
||||
const apiUrl = this.getScaleApiUrl(params);
|
||||
const { status = 0 } = await this.request.get(apiUrl) as { status?: number };
|
||||
const { status } = await this.getResourceScale(params);
|
||||
|
||||
return status;
|
||||
return status.replicas;
|
||||
}
|
||||
|
||||
scale(params: NamespacedResourceDescriptor, replicas: number) {
|
||||
return this.patch(params, {
|
||||
spec: {
|
||||
replicas,
|
||||
},
|
||||
}, "merge");
|
||||
return this.scaleResource(params, { spec: { replicas }});
|
||||
}
|
||||
|
||||
restart(params: NamespacedResourceDescriptor) {
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
import { merge } from "lodash";
|
||||
import { stringify } from "querystring";
|
||||
import { createKubeApiURL, parseKubeApi } from "./kube-api-parse";
|
||||
import type { KubeObjectConstructor, KubeJsonApiDataFor, KubeObjectMetadata, KubeJsonApiData, KubeObject, KubeObjectScope } from "@k8slens/kube-object";
|
||||
import type { KubeObjectConstructor, KubeJsonApiDataFor, KubeObjectMetadata, KubeJsonApiData, KubeObject, KubeObjectScope, Scale } from "@k8slens/kube-object";
|
||||
import { isJsonApiData, isJsonApiDataList, isPartialJsonApiData, KubeStatus, isKubeStatusData } from "@k8slens/kube-object";
|
||||
import byline from "byline";
|
||||
import type { IKubeWatchEvent } from "./kube-watch-event";
|
||||
@ -22,6 +22,7 @@ import type { PartialDeep } from "type-fest";
|
||||
import type { Logger } from "../logger";
|
||||
import { matches } from "lodash/fp";
|
||||
import { makeObservable, observable } from "mobx";
|
||||
import type { ScaleCreateOptions } from "@k8slens/kube-object/src/types/scale";
|
||||
|
||||
/**
|
||||
* The options used for creating a `KubeApi`
|
||||
@ -213,6 +214,10 @@ export interface ResourceDescriptor {
|
||||
namespace?: string;
|
||||
}
|
||||
|
||||
export interface SubResourceDescriptor {
|
||||
subResource: string;
|
||||
}
|
||||
|
||||
export type SpecificResourceDescriptor<Scope extends KubeObjectScope> = {
|
||||
/**
|
||||
* The name of the kubernetes resource
|
||||
@ -592,6 +597,37 @@ export class KubeApi<
|
||||
return parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal method for requesting the `/scale` sub-resource if it exists
|
||||
*/
|
||||
protected async getResourceScale(desc: ResourceDescriptor): Promise<Scale> {
|
||||
await this.checkPreferredVersion();
|
||||
const apiUrl = this.formatUrlForNotListing(desc);
|
||||
|
||||
const res = await this.request.get(`${apiUrl}/scale`);
|
||||
|
||||
return res as Scale;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An internal method for requesting the `/scale` sub-resource if it exists
|
||||
*/
|
||||
protected async scaleResource(desc: ResourceDescriptor, data: ScaleCreateOptions): Promise<Scale> {
|
||||
await this.checkPreferredVersion();
|
||||
const apiUrl = this.formatUrlForNotListing(desc);
|
||||
|
||||
const res = await this.request.patch(`${apiUrl}/scale`, {
|
||||
data: { ...data },
|
||||
}, {
|
||||
headers: {
|
||||
"content-type": patchTypeHeaders.merge,
|
||||
},
|
||||
});
|
||||
|
||||
return res as Scale;
|
||||
}
|
||||
|
||||
async patch(desc: ResourceDescriptor, data: PartialDeep<Object>): Promise<Object | null>;
|
||||
async patch(desc: ResourceDescriptor, data: PartialDeep<Object>, strategy: "strategic" | "merge"): Promise<Object | null>;
|
||||
async patch(desc: ResourceDescriptor, data: Patch, strategy: "json"): Promise<Object | null>;
|
||||
|
||||
@ -3,28 +3,10 @@
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type {
|
||||
KubeObjectMetadata,
|
||||
KubeObjectStatus,
|
||||
NamespaceScopedMetadata,
|
||||
BaseKubeObjectCondition,
|
||||
} from "../api-types";
|
||||
import type { KubeObjectStatus, NamespaceScopedMetadata, BaseKubeObjectCondition } from "../api-types";
|
||||
import { KubeObject } from "../kube-object";
|
||||
import type { PodTemplateSpec } from "../types/pod-template-spec";
|
||||
|
||||
export interface Scale {
|
||||
apiVersion: "autoscaling/v1";
|
||||
kind: "Scale";
|
||||
metadata: KubeObjectMetadata;
|
||||
spec: {
|
||||
replicas: number;
|
||||
};
|
||||
status: {
|
||||
replicas: number;
|
||||
selector: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ReplicationControllerSpec {
|
||||
/**
|
||||
* Minimum number of seconds for which a newly created pod should be ready without any of its container crashing,
|
||||
|
||||
27
packages/kube-object/src/types/scale.ts
Normal file
27
packages/kube-object/src/types/scale.ts
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import type { KubeObjectMetadata } from "../api-types";
|
||||
|
||||
export interface Scale {
|
||||
apiVersion: "autoscaling/v1";
|
||||
kind: "Scale";
|
||||
metadata: KubeObjectMetadata;
|
||||
spec: {
|
||||
replicas: number;
|
||||
};
|
||||
status: {
|
||||
replicas: number;
|
||||
selector: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ScaleCreateOptions {
|
||||
apiVersion?: "autoscaling/v1";
|
||||
kind?: "Scale";
|
||||
spec: {
|
||||
replicas: number;
|
||||
};
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user