feat: add support for replica ranges and HorizontalPodAutoscaler integration
This commit is contained in:
@@ -20,7 +20,12 @@ function object(
|
||||
},
|
||||
): KubernetesObject {
|
||||
return {
|
||||
apiVersion: kind === "Deployment" ? "apps/v1" : "v1",
|
||||
apiVersion:
|
||||
kind === "Deployment"
|
||||
? "apps/v1"
|
||||
: kind === "HorizontalPodAutoscaler"
|
||||
? "autoscaling/v2"
|
||||
: "v1",
|
||||
kind,
|
||||
metadata: { name, namespace: workspace.project, uid, labels },
|
||||
};
|
||||
@@ -222,6 +227,115 @@ describe("server management service", () => {
|
||||
);
|
||||
});
|
||||
|
||||
test("stop deletes matching HPAs before scaling selected deployments", async () => {
|
||||
const calls: string[] = [];
|
||||
const service = createManagementService(
|
||||
dependencies({
|
||||
listDeployments: async () =>
|
||||
["api", "worker", "batch"].map(
|
||||
(name) =>
|
||||
object("Deployment", name, `${name}-uid`) as V1Deployment,
|
||||
),
|
||||
listProjectResources: async () => [
|
||||
object("HorizontalPodAutoscaler", "api", "api-hpa-uid", undefined),
|
||||
object("HorizontalPodAutoscaler", "worker", "worker-hpa-uid", undefined),
|
||||
object("HorizontalPodAutoscaler", "batch", "batch-hpa-uid", undefined),
|
||||
],
|
||||
scaleDeployment: async (_project, name, replicas) => {
|
||||
calls.push(`scale:${name}:${replicas}`);
|
||||
},
|
||||
deleteResource: async (item) => {
|
||||
calls.push(`delete:${item.kind}:${item.name}`);
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(await service.stop(workspace, ["api", "worker"])).toEqual([
|
||||
"api",
|
||||
"worker",
|
||||
]);
|
||||
expect(calls).toEqual([
|
||||
"delete:HorizontalPodAutoscaler:api",
|
||||
"delete:HorizontalPodAutoscaler:worker",
|
||||
"scale:api:0",
|
||||
"scale:worker:0",
|
||||
]);
|
||||
});
|
||||
|
||||
test("stop deletes HPAs for all deployments and leaves unrelated HPAs alone", async () => {
|
||||
const calls: string[] = [];
|
||||
const service = createManagementService(
|
||||
dependencies({
|
||||
listDeployments: async () =>
|
||||
["api", "worker"].map(
|
||||
(name) =>
|
||||
object("Deployment", name, `${name}-uid`) as V1Deployment,
|
||||
),
|
||||
listProjectResources: async () => [
|
||||
object("HorizontalPodAutoscaler", "api", "api-hpa-uid", undefined),
|
||||
object("HorizontalPodAutoscaler", "worker", "worker-hpa-uid", undefined),
|
||||
object("HorizontalPodAutoscaler", "legacy", "legacy-hpa-uid", undefined),
|
||||
],
|
||||
scaleDeployment: async (_project, name, replicas) => {
|
||||
calls.push(`scale:${name}:${replicas}`);
|
||||
},
|
||||
deleteResource: async (item) => {
|
||||
calls.push(`delete:${item.kind}:${item.name}`);
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(await service.stop(workspace)).toEqual(["api", "worker"]);
|
||||
expect(calls).toEqual([
|
||||
"delete:HorizontalPodAutoscaler:api",
|
||||
"delete:HorizontalPodAutoscaler:worker",
|
||||
"scale:api:0",
|
||||
"scale:worker:0",
|
||||
]);
|
||||
});
|
||||
|
||||
test("refuses to delete an HPA not owned by the workspace", async () => {
|
||||
const service = createManagementService(
|
||||
dependencies({
|
||||
listDeployments: async () =>
|
||||
[object("Deployment", "api", "api-uid") as V1Deployment],
|
||||
listProjectResources: async () => [
|
||||
object("HorizontalPodAutoscaler", "api", "api-hpa-uid", {
|
||||
"app.kubernetes.io/managed-by": "kuber",
|
||||
[WORKSPACE_UID_LABEL]: "someone-else",
|
||||
}),
|
||||
],
|
||||
}),
|
||||
);
|
||||
|
||||
await expect(service.stop(workspace, ["api"])).rejects.toThrow(
|
||||
"is not owned by workspace",
|
||||
);
|
||||
});
|
||||
|
||||
test("stop scales deployments to zero when there are no HPAs", async () => {
|
||||
const calls: string[] = [];
|
||||
const service = createManagementService(
|
||||
dependencies({
|
||||
listDeployments: async () =>
|
||||
["api", "worker"].map(
|
||||
(name) =>
|
||||
object("Deployment", name, `${name}-uid`) as V1Deployment,
|
||||
),
|
||||
listProjectResources: async () => [
|
||||
object("ConfigMap", "env", "env-uid"),
|
||||
object("Service", "api", "api-svc-uid"),
|
||||
],
|
||||
scaleDeployment: async (_project, name, replicas) => {
|
||||
calls.push(`scale:${name}:${replicas}`);
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(await service.stop(workspace)).toEqual(["api", "worker"]);
|
||||
expect(calls).toEqual(["scale:api:0", "scale:worker:0"]);
|
||||
});
|
||||
|
||||
test("protects reserved namespaces before consulting Kubernetes", async () => {
|
||||
let read = false;
|
||||
const service = createManagementService(
|
||||
|
||||
Reference in New Issue
Block a user