Skip to content

Commit 74a6818

Browse files
authored
Merge pull request #89 from jxs1211/feat/delete-ns
implement ns deletion
2 parents f6dd3d0 + a7e9e38 commit 74a6818

File tree

4 files changed

+146
-2
lines changed

4 files changed

+146
-2
lines changed

Diff for: src/index.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import { KubernetesManager } from "./types.js";
5151
import { serverConfig } from "./config/server-config.js";
5252
import { createDeploymentSchema } from "./config/deployment-config.js";
5353
import { listNamespacesSchema } from "./config/namespace-config.js";
54+
import { deleteNamespace, deleteNamespaceSchema } from "./tools/delete_namespace.js";
5455
import { cleanupSchema } from "./config/cleanup-config.js";
5556
import { startSSEServer } from "./utils/sse.js";
5657
import {
@@ -59,7 +60,7 @@ import {
5960
stopPortForward,
6061
StopPortForwardSchema,
6162
} from "./tools/port_forward.js";
62-
import { deleteDeployment } from "./tools/delete_deployment.js";
63+
import { deleteDeployment, deleteDeploymentSchema } from "./tools/delete_deployment.js";
6364
import { createDeployment } from "./tools/create_deployment.js";
6465
import {scaleDeployment,scaleDeploymentSchema} from "./tools/scale_deployment.js"
6566
import {
@@ -87,6 +88,8 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
8788
createPodSchema,
8889
createCronJobSchema,
8990
deletePodSchema,
91+
deleteDeploymentSchema,
92+
deleteNamespaceSchema,
9093
describeCronJobSchema,
9194
describePodSchema,
9295
describeDeploymentSchema,
@@ -390,6 +393,16 @@ server.setRequestHandler(
390393
);
391394
}
392395

396+
case "delete_namespace": {
397+
return await deleteNamespace(
398+
k8sManager,
399+
input as {
400+
name: string;
401+
ignoreNotFound?: boolean;
402+
}
403+
);
404+
}
405+
393406
case "delete_deployment": {
394407
return await deleteDeployment(
395408
k8sManager,

Diff for: src/models/response-schemas.ts

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ export const CreateNamespaceResponseSchema = z.object({
1010
content: z.array(ToolResponseContent),
1111
});
1212

13+
export const DeleteNamespaceResponseSchema = z.object({
14+
content: z.array(ToolResponseContent),
15+
});
16+
1317
export const CreatePodResponseSchema = z.object({
1418
content: z.array(ToolResponseContent),
1519
});

Diff for: src/tools/delete_namespace.ts

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { KubernetesManager } from "../types.js";
2+
3+
export const deleteNamespaceSchema = {
4+
name: "delete_namespace",
5+
description: "Delete a Kubernetes namespace",
6+
inputSchema: {
7+
type: "object",
8+
properties: {
9+
name: { type: "string" },
10+
ignoreNotFound: { type: "boolean", default: false },
11+
},
12+
required: ["name"],
13+
},
14+
} as const;
15+
16+
export async function deleteNamespace(k8sManager: KubernetesManager, input: {
17+
name: string;
18+
ignoreNotFound?: boolean;
19+
}) {
20+
try {
21+
await k8sManager.getCoreApi().deleteNamespace(input.name);
22+
return {
23+
content: [
24+
{
25+
type: "text",
26+
text: JSON.stringify(
27+
{
28+
success: true,
29+
status: "deleted",
30+
},
31+
null,
32+
2
33+
),
34+
},
35+
],
36+
};
37+
} catch (error: any) {
38+
if (input.ignoreNotFound && error.response?.statusCode === 404) {
39+
return {
40+
content: [
41+
{
42+
type: "text",
43+
text: JSON.stringify(
44+
{
45+
success: true,
46+
status: "not_found",
47+
},
48+
null,
49+
2
50+
),
51+
},
52+
],
53+
};
54+
}
55+
throw error;
56+
}
57+
}

Diff for: tests/namespace.test.ts

+71-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { expect, test, describe, beforeEach, afterEach } from "vitest";
22
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
33
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
4-
import { CreateNamespaceResponseSchema } from "../src/models/response-schemas";
4+
import { CreateNamespaceResponseSchema, DeleteNamespaceResponseSchema } from "../src/models/response-schemas";
55
import { KubernetesManager } from "../src/utils/kubernetes-manager.js";
66

77
async function sleep(ms: number): Promise<void> {
@@ -83,4 +83,74 @@ describe("kubernetes server operations", () => {
8383
const k8sManager = new KubernetesManager();
8484
await k8sManager.getCoreApi().deleteNamespace(TEST_NAMESPACE_NAME);
8585
});
86+
87+
test("delete namespace", async () => {
88+
const TEST_NAMESPACE_NAME = "test-namespace-mcp-server2";
89+
// Create namespace before test
90+
const k8sManager = new KubernetesManager();
91+
const result = await client.request(
92+
{
93+
method: "tools/call",
94+
params: {
95+
name: "create_namespace",
96+
arguments: {
97+
name: TEST_NAMESPACE_NAME,
98+
},
99+
},
100+
},
101+
CreateNamespaceResponseSchema
102+
);
103+
expect(result).toEqual({
104+
content: [
105+
{
106+
type: "text",
107+
text: JSON.stringify(
108+
{
109+
podName: TEST_NAMESPACE_NAME,
110+
status: "created",
111+
},
112+
null,
113+
2
114+
),
115+
},
116+
],
117+
});
118+
// Wait for namespace to be fully created
119+
await sleep(2000);
120+
const result2 = await client.request(
121+
{
122+
method: "tools/call",
123+
params: {
124+
name: "delete_namespace",
125+
arguments: {
126+
name: TEST_NAMESPACE_NAME,
127+
},
128+
},
129+
},
130+
DeleteNamespaceResponseSchema,
131+
);
132+
expect(result2).toEqual({
133+
content: [
134+
{
135+
type: "text",
136+
text: JSON.stringify(
137+
{
138+
success: true,
139+
status: "deleted",
140+
},
141+
null,
142+
2
143+
),
144+
}
145+
]
146+
})
147+
148+
// verify namespace is deleted
149+
const namespace = await k8sManager.getCoreApi().readNamespace(TEST_NAMESPACE_NAME);
150+
if (namespace.body) {
151+
expect(namespace.body.status?.phase).toBe("Terminating");
152+
} else {
153+
expect(namespace.body).toBeUndefined();
154+
}
155+
})
86156
});

0 commit comments

Comments
 (0)