mcp-server-kubernetes 2.7.0 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +251 -2
- package/dist/index.d.ts +190 -27
- package/dist/index.js +7 -0
- package/dist/models/common-parameters.d.ts +15 -0
- package/dist/models/common-parameters.js +15 -0
- package/dist/models/helm-models.d.ts +18 -5
- package/dist/models/kubectl-models.d.ts +2 -0
- package/dist/tools/exec_in_pod.d.ts +7 -1
- package/dist/tools/exec_in_pod.js +7 -5
- package/dist/tools/helm-operations.d.ts +89 -11
- package/dist/tools/helm-operations.js +297 -106
- package/dist/tools/kubectl-apply.d.ts +12 -6
- package/dist/tools/kubectl-apply.js +9 -10
- package/dist/tools/kubectl-create.d.ts +12 -6
- package/dist/tools/kubectl-create.js +9 -10
- package/dist/tools/kubectl-delete.d.ts +9 -3
- package/dist/tools/kubectl-delete.js +8 -5
- package/dist/tools/kubectl-describe.d.ts +9 -3
- package/dist/tools/kubectl-describe.js +7 -5
- package/dist/tools/kubectl-generic.d.ts +7 -1
- package/dist/tools/kubectl-generic.js +7 -5
- package/dist/tools/kubectl-get.d.ts +9 -3
- package/dist/tools/kubectl-get.js +7 -5
- package/dist/tools/kubectl-logs.d.ts +9 -3
- package/dist/tools/kubectl-logs.js +11 -5
- package/dist/tools/kubectl-operations.d.ts +10 -0
- package/dist/tools/kubectl-operations.js +13 -0
- package/dist/tools/kubectl-patch.d.ts +8 -2
- package/dist/tools/kubectl-patch.js +9 -10
- package/dist/tools/kubectl-rollout.d.ts +7 -1
- package/dist/tools/kubectl-rollout.js +8 -5
- package/dist/tools/kubectl-scale.d.ts +7 -1
- package/dist/tools/kubectl-scale.js +8 -5
- package/dist/tools/node-management.d.ts +100 -0
- package/dist/tools/node-management.js +291 -0
- package/dist/utils/sse.js +21 -0
- package/dist/utils/streamable-http.js +21 -0
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { execFileSync } from "child_process";
|
|
2
2
|
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
3
3
|
import { getSpawnMaxBuffer } from "../config/max-buffer.js";
|
|
4
|
+
import { contextParameter, namespaceParameter } from "../models/common-parameters.js";
|
|
4
5
|
export const kubectlRolloutSchema = {
|
|
5
6
|
name: "kubectl_rollout",
|
|
6
7
|
description: "Manage the rollout of a resource (e.g., deployment, daemonset, statefulset)",
|
|
@@ -23,11 +24,7 @@ export const kubectlRolloutSchema = {
|
|
|
23
24
|
type: "string",
|
|
24
25
|
description: "Name of the resource",
|
|
25
26
|
},
|
|
26
|
-
namespace:
|
|
27
|
-
type: "string",
|
|
28
|
-
description: "Namespace of the resource",
|
|
29
|
-
default: "default",
|
|
30
|
-
},
|
|
27
|
+
namespace: namespaceParameter,
|
|
31
28
|
revision: {
|
|
32
29
|
type: "number",
|
|
33
30
|
description: "Revision to rollback to (for undo subcommand)",
|
|
@@ -45,6 +42,7 @@ export const kubectlRolloutSchema = {
|
|
|
45
42
|
description: "Watch the rollout status in real-time until completion",
|
|
46
43
|
default: false,
|
|
47
44
|
},
|
|
45
|
+
context: contextParameter,
|
|
48
46
|
},
|
|
49
47
|
required: ["subCommand", "resourceType", "name", "namespace"],
|
|
50
48
|
},
|
|
@@ -53,6 +51,7 @@ export async function kubectlRollout(k8sManager, input) {
|
|
|
53
51
|
try {
|
|
54
52
|
const namespace = input.namespace || "default";
|
|
55
53
|
const watch = input.watch || false;
|
|
54
|
+
const context = input.context || "";
|
|
56
55
|
const command = "kubectl";
|
|
57
56
|
const args = [
|
|
58
57
|
"rollout",
|
|
@@ -73,6 +72,10 @@ export async function kubectlRollout(k8sManager, input) {
|
|
|
73
72
|
if (input.timeout) {
|
|
74
73
|
args.push(`--timeout=${input.timeout}`);
|
|
75
74
|
}
|
|
75
|
+
// Add context if provided
|
|
76
|
+
if (context) {
|
|
77
|
+
args.push("--context", context);
|
|
78
|
+
}
|
|
76
79
|
// Execute the command
|
|
77
80
|
try {
|
|
78
81
|
// For status command with watch flag, we need to handle it differently
|
|
@@ -10,7 +10,7 @@ export declare const kubectlScaleSchema: {
|
|
|
10
10
|
description: string;
|
|
11
11
|
};
|
|
12
12
|
namespace: {
|
|
13
|
-
type: string;
|
|
13
|
+
type: "string";
|
|
14
14
|
description: string;
|
|
15
15
|
default: string;
|
|
16
16
|
};
|
|
@@ -23,6 +23,11 @@ export declare const kubectlScaleSchema: {
|
|
|
23
23
|
description: string;
|
|
24
24
|
default: string;
|
|
25
25
|
};
|
|
26
|
+
context: {
|
|
27
|
+
type: "string";
|
|
28
|
+
description: string;
|
|
29
|
+
default: string;
|
|
30
|
+
};
|
|
26
31
|
};
|
|
27
32
|
required: string[];
|
|
28
33
|
};
|
|
@@ -32,6 +37,7 @@ export declare function kubectlScale(k8sManager: KubernetesManager, input: {
|
|
|
32
37
|
namespace?: string;
|
|
33
38
|
replicas: number;
|
|
34
39
|
resourceType?: string;
|
|
40
|
+
context?: string;
|
|
35
41
|
}): Promise<{
|
|
36
42
|
content: {
|
|
37
43
|
success: boolean;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { execFileSync } from "child_process";
|
|
2
2
|
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
3
3
|
import { getSpawnMaxBuffer } from "../config/max-buffer.js";
|
|
4
|
+
import { contextParameter, namespaceParameter } from "../models/common-parameters.js";
|
|
4
5
|
export const kubectlScaleSchema = {
|
|
5
6
|
name: "kubectl_scale",
|
|
6
7
|
description: "Scale a Kubernetes deployment",
|
|
@@ -11,11 +12,7 @@ export const kubectlScaleSchema = {
|
|
|
11
12
|
type: "string",
|
|
12
13
|
description: "Name of the deployment to scale",
|
|
13
14
|
},
|
|
14
|
-
namespace:
|
|
15
|
-
type: "string",
|
|
16
|
-
description: "Namespace of the deployment",
|
|
17
|
-
default: "default",
|
|
18
|
-
},
|
|
15
|
+
namespace: namespaceParameter,
|
|
19
16
|
replicas: {
|
|
20
17
|
type: "number",
|
|
21
18
|
description: "Number of replicas to scale to",
|
|
@@ -25,6 +22,7 @@ export const kubectlScaleSchema = {
|
|
|
25
22
|
description: "Resource type to scale (deployment, replicaset, statefulset)",
|
|
26
23
|
default: "deployment",
|
|
27
24
|
},
|
|
25
|
+
context: contextParameter,
|
|
28
26
|
},
|
|
29
27
|
required: ["name", "replicas"],
|
|
30
28
|
},
|
|
@@ -33,6 +31,7 @@ export async function kubectlScale(k8sManager, input) {
|
|
|
33
31
|
try {
|
|
34
32
|
const namespace = input.namespace || "default";
|
|
35
33
|
const resourceType = input.resourceType || "deployment";
|
|
34
|
+
const context = input.context || "";
|
|
36
35
|
const command = "kubectl";
|
|
37
36
|
const args = [
|
|
38
37
|
"scale",
|
|
@@ -41,6 +40,10 @@ export async function kubectlScale(k8sManager, input) {
|
|
|
41
40
|
`--replicas=${input.replicas}`,
|
|
42
41
|
`--namespace=${namespace}`,
|
|
43
42
|
];
|
|
43
|
+
// Add context if provided
|
|
44
|
+
if (context) {
|
|
45
|
+
args.push("--context", context);
|
|
46
|
+
}
|
|
44
47
|
// Execute the command
|
|
45
48
|
try {
|
|
46
49
|
const result = execFileSync(command, args, {
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: node_management
|
|
3
|
+
* Manage Kubernetes nodes with cordon, drain, and uncordon operations.
|
|
4
|
+
* Provides safety features for node operations and implements proper error handling
|
|
5
|
+
* and confirmation requirements for destructive operations.
|
|
6
|
+
* Note: Use kubectl_get with resourceType="nodes" to list nodes.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Schema for node_management tool.
|
|
10
|
+
* - operation: Node operation to perform (cordon, drain, uncordon)
|
|
11
|
+
* - nodeName: Name of the node to operate on (required for cordon, drain, uncordon)
|
|
12
|
+
* - force: Force the operation even if there are unmanaged pods (for drain)
|
|
13
|
+
* - gracePeriod: Grace period for pod termination (for drain)
|
|
14
|
+
* - deleteLocalData: Delete local data even if emptyDir volumes are used (for drain)
|
|
15
|
+
* - ignoreDaemonsets: Ignore DaemonSet-managed pods (for drain)
|
|
16
|
+
* - timeout: Timeout for drain operation
|
|
17
|
+
* - dryRun: Show what would be done without actually doing it (for drain)
|
|
18
|
+
* - confirmDrain: Explicit confirmation to drain the node (required for drain)
|
|
19
|
+
*/
|
|
20
|
+
export declare const nodeManagementSchema: {
|
|
21
|
+
name: string;
|
|
22
|
+
description: string;
|
|
23
|
+
inputSchema: {
|
|
24
|
+
type: string;
|
|
25
|
+
properties: {
|
|
26
|
+
operation: {
|
|
27
|
+
type: string;
|
|
28
|
+
description: string;
|
|
29
|
+
enum: string[];
|
|
30
|
+
};
|
|
31
|
+
nodeName: {
|
|
32
|
+
type: string;
|
|
33
|
+
description: string;
|
|
34
|
+
};
|
|
35
|
+
force: {
|
|
36
|
+
type: string;
|
|
37
|
+
description: string;
|
|
38
|
+
default: boolean;
|
|
39
|
+
};
|
|
40
|
+
gracePeriod: {
|
|
41
|
+
type: string;
|
|
42
|
+
description: string;
|
|
43
|
+
default: number;
|
|
44
|
+
};
|
|
45
|
+
deleteLocalData: {
|
|
46
|
+
type: string;
|
|
47
|
+
description: string;
|
|
48
|
+
default: boolean;
|
|
49
|
+
};
|
|
50
|
+
ignoreDaemonsets: {
|
|
51
|
+
type: string;
|
|
52
|
+
description: string;
|
|
53
|
+
default: boolean;
|
|
54
|
+
};
|
|
55
|
+
timeout: {
|
|
56
|
+
type: string;
|
|
57
|
+
description: string;
|
|
58
|
+
default: string;
|
|
59
|
+
};
|
|
60
|
+
dryRun: {
|
|
61
|
+
type: string;
|
|
62
|
+
description: string;
|
|
63
|
+
default: boolean;
|
|
64
|
+
};
|
|
65
|
+
confirmDrain: {
|
|
66
|
+
type: string;
|
|
67
|
+
description: string;
|
|
68
|
+
default: boolean;
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
required: string[];
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Interface for node_management tool parameters.
|
|
76
|
+
*/
|
|
77
|
+
interface NodeManagementParams {
|
|
78
|
+
operation: "cordon" | "drain" | "uncordon";
|
|
79
|
+
nodeName?: string;
|
|
80
|
+
force?: boolean;
|
|
81
|
+
gracePeriod?: number;
|
|
82
|
+
deleteLocalData?: boolean;
|
|
83
|
+
ignoreDaemonsets?: boolean;
|
|
84
|
+
timeout?: string;
|
|
85
|
+
dryRun?: boolean;
|
|
86
|
+
confirmDrain?: boolean;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Main node_management function that handles all node operations.
|
|
90
|
+
* Implements safety features and proper error handling for node management tasks.
|
|
91
|
+
* @param params - Node management parameters
|
|
92
|
+
* @returns Promise with operation results
|
|
93
|
+
*/
|
|
94
|
+
export declare function nodeManagement(params: NodeManagementParams): Promise<{
|
|
95
|
+
content: {
|
|
96
|
+
type: string;
|
|
97
|
+
text: string;
|
|
98
|
+
}[];
|
|
99
|
+
}>;
|
|
100
|
+
export {};
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: node_management
|
|
3
|
+
* Manage Kubernetes nodes with cordon, drain, and uncordon operations.
|
|
4
|
+
* Provides safety features for node operations and implements proper error handling
|
|
5
|
+
* and confirmation requirements for destructive operations.
|
|
6
|
+
* Note: Use kubectl_get with resourceType="nodes" to list nodes.
|
|
7
|
+
*/
|
|
8
|
+
import { execFileSync } from "child_process";
|
|
9
|
+
import { getSpawnMaxBuffer } from "../config/max-buffer.js";
|
|
10
|
+
/**
|
|
11
|
+
* Schema for node_management tool.
|
|
12
|
+
* - operation: Node operation to perform (cordon, drain, uncordon)
|
|
13
|
+
* - nodeName: Name of the node to operate on (required for cordon, drain, uncordon)
|
|
14
|
+
* - force: Force the operation even if there are unmanaged pods (for drain)
|
|
15
|
+
* - gracePeriod: Grace period for pod termination (for drain)
|
|
16
|
+
* - deleteLocalData: Delete local data even if emptyDir volumes are used (for drain)
|
|
17
|
+
* - ignoreDaemonsets: Ignore DaemonSet-managed pods (for drain)
|
|
18
|
+
* - timeout: Timeout for drain operation
|
|
19
|
+
* - dryRun: Show what would be done without actually doing it (for drain)
|
|
20
|
+
* - confirmDrain: Explicit confirmation to drain the node (required for drain)
|
|
21
|
+
*/
|
|
22
|
+
export const nodeManagementSchema = {
|
|
23
|
+
name: "node_management",
|
|
24
|
+
description: "Manage Kubernetes nodes with cordon, drain, and uncordon operations",
|
|
25
|
+
inputSchema: {
|
|
26
|
+
type: "object",
|
|
27
|
+
properties: {
|
|
28
|
+
operation: {
|
|
29
|
+
type: "string",
|
|
30
|
+
description: "Node operation to perform",
|
|
31
|
+
enum: ["cordon", "drain", "uncordon"],
|
|
32
|
+
},
|
|
33
|
+
nodeName: {
|
|
34
|
+
type: "string",
|
|
35
|
+
description: "Name of the node to operate on (required for cordon, drain, uncordon)",
|
|
36
|
+
},
|
|
37
|
+
force: {
|
|
38
|
+
type: "boolean",
|
|
39
|
+
description: "Force the operation even if there are pods not managed by a ReplicationController, ReplicaSet, Job, DaemonSet or StatefulSet (for drain operation)",
|
|
40
|
+
default: false,
|
|
41
|
+
},
|
|
42
|
+
gracePeriod: {
|
|
43
|
+
type: "number",
|
|
44
|
+
description: "Period of time in seconds given to each pod to terminate gracefully (for drain operation). If set to -1, uses the kubectl default grace period.",
|
|
45
|
+
default: -1,
|
|
46
|
+
},
|
|
47
|
+
deleteLocalData: {
|
|
48
|
+
type: "boolean",
|
|
49
|
+
description: "Delete local data even if emptyDir volumes are used (for drain operation)",
|
|
50
|
+
default: false,
|
|
51
|
+
},
|
|
52
|
+
ignoreDaemonsets: {
|
|
53
|
+
type: "boolean",
|
|
54
|
+
description: "Ignore DaemonSet-managed pods (for drain operation)",
|
|
55
|
+
default: true,
|
|
56
|
+
},
|
|
57
|
+
timeout: {
|
|
58
|
+
type: "string",
|
|
59
|
+
description: "The length of time to wait before giving up (for drain operation, e.g., '5m', '1h')",
|
|
60
|
+
default: "0",
|
|
61
|
+
},
|
|
62
|
+
dryRun: {
|
|
63
|
+
type: "boolean",
|
|
64
|
+
description: "Show what would be done without actually doing it (for drain operation)",
|
|
65
|
+
default: false,
|
|
66
|
+
},
|
|
67
|
+
confirmDrain: {
|
|
68
|
+
type: "boolean",
|
|
69
|
+
description: "Explicit confirmation to drain the node (required for drain operation)",
|
|
70
|
+
default: false,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
required: ["operation"],
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Execute a command using child_process.execFileSync with proper error handling.
|
|
78
|
+
* @param command - The command to execute
|
|
79
|
+
* @param args - Array of command arguments
|
|
80
|
+
* @returns The command output as a string
|
|
81
|
+
* @throws Error if command execution fails
|
|
82
|
+
*/
|
|
83
|
+
const executeCommand = (command, args) => {
|
|
84
|
+
try {
|
|
85
|
+
return execFileSync(command, args, {
|
|
86
|
+
encoding: "utf8",
|
|
87
|
+
timeout: 300000, // 5 minutes timeout for node operations
|
|
88
|
+
maxBuffer: getSpawnMaxBuffer(),
|
|
89
|
+
env: { ...process.env, KUBECONFIG: process.env.KUBECONFIG },
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
throw new Error(`${command} command failed: ${error.message}`);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Get the status of a specific node.
|
|
98
|
+
* @param nodeName - Name of the node to get status for
|
|
99
|
+
* @returns Node status as JSON object
|
|
100
|
+
* @throws Error if node status retrieval fails
|
|
101
|
+
*/
|
|
102
|
+
const getNodeStatus = (nodeName) => {
|
|
103
|
+
try {
|
|
104
|
+
const output = executeCommand("kubectl", ["get", "node", nodeName, "-o", "json"]);
|
|
105
|
+
return JSON.parse(output);
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
throw new Error(`Failed to get node status: ${error.message}`);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* Main node_management function that handles all node operations.
|
|
113
|
+
* Implements safety features and proper error handling for node management tasks.
|
|
114
|
+
* @param params - Node management parameters
|
|
115
|
+
* @returns Promise with operation results
|
|
116
|
+
*/
|
|
117
|
+
export async function nodeManagement(params) {
|
|
118
|
+
const { operation, nodeName, force = false, gracePeriod = -1, deleteLocalData = false, ignoreDaemonsets = true, timeout = "0", dryRun = false, confirmDrain = false } = params;
|
|
119
|
+
try {
|
|
120
|
+
switch (operation) {
|
|
121
|
+
case "cordon":
|
|
122
|
+
return handleCordonNode(nodeName);
|
|
123
|
+
case "uncordon":
|
|
124
|
+
return handleUncordonNode(nodeName);
|
|
125
|
+
case "drain":
|
|
126
|
+
return handleDrainNode({
|
|
127
|
+
nodeName: nodeName,
|
|
128
|
+
force,
|
|
129
|
+
gracePeriod,
|
|
130
|
+
deleteLocalData,
|
|
131
|
+
ignoreDaemonsets,
|
|
132
|
+
timeout,
|
|
133
|
+
dryRun,
|
|
134
|
+
confirmDrain
|
|
135
|
+
});
|
|
136
|
+
default:
|
|
137
|
+
throw new Error(`Unknown operation: ${operation}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
return {
|
|
142
|
+
content: [
|
|
143
|
+
{
|
|
144
|
+
type: "text",
|
|
145
|
+
text: `Node management operation failed: ${error.message}`
|
|
146
|
+
}
|
|
147
|
+
]
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Handle the cordon node operation.
|
|
153
|
+
* @param nodeName - Name of the node to cordon
|
|
154
|
+
* @returns Promise with cordon operation results
|
|
155
|
+
*/
|
|
156
|
+
async function handleCordonNode(nodeName) {
|
|
157
|
+
try {
|
|
158
|
+
// Check if node exists and get current status
|
|
159
|
+
const nodeStatus = getNodeStatus(nodeName);
|
|
160
|
+
const isSchedulable = !nodeStatus.spec.unschedulable;
|
|
161
|
+
if (!isSchedulable) {
|
|
162
|
+
return {
|
|
163
|
+
content: [
|
|
164
|
+
{
|
|
165
|
+
type: "text",
|
|
166
|
+
text: `Node '${nodeName}' is already cordoned (unschedulable)`
|
|
167
|
+
}
|
|
168
|
+
]
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
// Cordon the node
|
|
172
|
+
executeCommand("kubectl", ["cordon", nodeName]);
|
|
173
|
+
return {
|
|
174
|
+
content: [
|
|
175
|
+
{
|
|
176
|
+
type: "text",
|
|
177
|
+
text: `Successfully cordoned node '${nodeName}'. The node is now unschedulable.`
|
|
178
|
+
}
|
|
179
|
+
]
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
throw new Error(`Failed to cordon node: ${error.message}`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Handle the uncordon node operation.
|
|
188
|
+
* @param nodeName - Name of the node to uncordon
|
|
189
|
+
* @returns Promise with uncordon operation results
|
|
190
|
+
*/
|
|
191
|
+
async function handleUncordonNode(nodeName) {
|
|
192
|
+
try {
|
|
193
|
+
// Check if node exists and get current status
|
|
194
|
+
const nodeStatus = getNodeStatus(nodeName);
|
|
195
|
+
const isSchedulable = !nodeStatus.spec.unschedulable;
|
|
196
|
+
if (isSchedulable) {
|
|
197
|
+
return {
|
|
198
|
+
content: [
|
|
199
|
+
{
|
|
200
|
+
type: "text",
|
|
201
|
+
text: `Node '${nodeName}' is already uncordoned (schedulable)`
|
|
202
|
+
}
|
|
203
|
+
]
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
// Uncordon the node
|
|
207
|
+
executeCommand("kubectl", ["uncordon", nodeName]);
|
|
208
|
+
return {
|
|
209
|
+
content: [
|
|
210
|
+
{
|
|
211
|
+
type: "text",
|
|
212
|
+
text: `Successfully uncordoned node '${nodeName}'. The node is now schedulable.`
|
|
213
|
+
}
|
|
214
|
+
]
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
throw new Error(`Failed to uncordon node: ${error.message}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Handle the drain node operation with safety checks and confirmation.
|
|
223
|
+
* @param params - Drain operation parameters
|
|
224
|
+
* @returns Promise with drain operation results
|
|
225
|
+
*/
|
|
226
|
+
async function handleDrainNode(params) {
|
|
227
|
+
const { nodeName, force, gracePeriod, deleteLocalData, ignoreDaemonsets, timeout, dryRun, confirmDrain } = params;
|
|
228
|
+
try {
|
|
229
|
+
// Check if node exists and get current status
|
|
230
|
+
const nodeStatus = getNodeStatus(nodeName);
|
|
231
|
+
const isSchedulable = !nodeStatus.spec.unschedulable;
|
|
232
|
+
if (!isSchedulable) {
|
|
233
|
+
return {
|
|
234
|
+
content: [
|
|
235
|
+
{
|
|
236
|
+
type: "text",
|
|
237
|
+
text: `Node '${nodeName}' is already cordoned (unschedulable). Drain operation may not be necessary.`
|
|
238
|
+
}
|
|
239
|
+
]
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
// Check for confirmation if not in dry run mode
|
|
243
|
+
if (!dryRun && !confirmDrain) {
|
|
244
|
+
return {
|
|
245
|
+
content: [
|
|
246
|
+
{
|
|
247
|
+
type: "text",
|
|
248
|
+
text: `Drain operation requires explicit confirmation. Set confirmDrain=true to proceed with draining node '${nodeName}'.`
|
|
249
|
+
}
|
|
250
|
+
]
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
// Build drain command arguments
|
|
254
|
+
const drainArgs = ["drain", nodeName];
|
|
255
|
+
if (force)
|
|
256
|
+
drainArgs.push("--force");
|
|
257
|
+
if (gracePeriod >= 0)
|
|
258
|
+
drainArgs.push("--grace-period", gracePeriod.toString());
|
|
259
|
+
if (deleteLocalData)
|
|
260
|
+
drainArgs.push("--delete-local-data");
|
|
261
|
+
if (ignoreDaemonsets)
|
|
262
|
+
drainArgs.push("--ignore-daemonsets");
|
|
263
|
+
if (timeout !== "0")
|
|
264
|
+
drainArgs.push("--timeout", timeout);
|
|
265
|
+
if (dryRun)
|
|
266
|
+
drainArgs.push("--dry-run=client");
|
|
267
|
+
// Execute drain command
|
|
268
|
+
const drainOutput = executeCommand("kubectl", drainArgs);
|
|
269
|
+
if (dryRun) {
|
|
270
|
+
return {
|
|
271
|
+
content: [
|
|
272
|
+
{
|
|
273
|
+
type: "text",
|
|
274
|
+
text: `Dry run drain operation for node '${nodeName}':\n\n${drainOutput}\n\nTo perform the actual drain, set dryRun=false and confirmDrain=true.`
|
|
275
|
+
}
|
|
276
|
+
]
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
return {
|
|
280
|
+
content: [
|
|
281
|
+
{
|
|
282
|
+
type: "text",
|
|
283
|
+
text: `Successfully drained node '${nodeName}'.\n\n${drainOutput}`
|
|
284
|
+
}
|
|
285
|
+
]
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
catch (error) {
|
|
289
|
+
throw new Error(`Failed to drain node: ${error.message}`);
|
|
290
|
+
}
|
|
291
|
+
}
|
package/dist/utils/sse.js
CHANGED
|
@@ -21,6 +21,27 @@ export function startSSEServer(server) {
|
|
|
21
21
|
.send("Not found. Must pass valid sessionId as query param.");
|
|
22
22
|
}
|
|
23
23
|
});
|
|
24
|
+
app.get("/health", async (req, res) => {
|
|
25
|
+
res.json({ status: "ok" });
|
|
26
|
+
});
|
|
27
|
+
app.get("/ready", async (req, res) => {
|
|
28
|
+
try {
|
|
29
|
+
// We can add more checks if required
|
|
30
|
+
// For now, we'll consider the server ready if it can respond to this request
|
|
31
|
+
res.json({
|
|
32
|
+
status: "ready",
|
|
33
|
+
timestamp: new Date().toISOString(),
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.error("Readiness check failed:", error);
|
|
38
|
+
res.status(503).json({
|
|
39
|
+
status: "not ready",
|
|
40
|
+
reason: "Server initialization incomplete",
|
|
41
|
+
timestamp: new Date().toISOString()
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
});
|
|
24
45
|
let port = 3000;
|
|
25
46
|
try {
|
|
26
47
|
port = parseInt(process.env.PORT || "3000", 10);
|
|
@@ -64,6 +64,27 @@ export function startStreamableHTTPServer(server) {
|
|
|
64
64
|
id: null,
|
|
65
65
|
}));
|
|
66
66
|
});
|
|
67
|
+
app.get("/health", async (req, res) => {
|
|
68
|
+
res.json({ status: "ok" });
|
|
69
|
+
});
|
|
70
|
+
app.get("/ready", async (req, res) => {
|
|
71
|
+
try {
|
|
72
|
+
// We can add more checks if required
|
|
73
|
+
// For now, we'll consider the server ready if it can respond to this request
|
|
74
|
+
res.json({
|
|
75
|
+
status: "ready",
|
|
76
|
+
timestamp: new Date().toISOString(),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
console.error("Readiness check failed:", error);
|
|
81
|
+
res.status(503).json({
|
|
82
|
+
status: "not ready",
|
|
83
|
+
reason: "Server initialization incomplete",
|
|
84
|
+
timestamp: new Date().toISOString()
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
});
|
|
67
88
|
let port = 3000;
|
|
68
89
|
try {
|
|
69
90
|
port = parseInt(process.env.PORT || "3000", 10);
|