Skip to content

Commit c8655b7

Browse files
Merge pull request #51 from swghosh/plan-mg-tool
MG-34: Add oc cli like must-gather collection with ServerPrompt
2 parents 8be953d + 7652ca9 commit c8655b7

File tree

12 files changed

+1440
-0
lines changed

12 files changed

+1440
-0
lines changed

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ The following sets of tools are available (toolsets marked with ✓ in the Defau
255255
| core | Most common tools for Kubernetes management (Pods, Generic Resources, Events, etc.) ||
256256
| helm | Tools for managing Helm charts and releases ||
257257
| kcp | Manage kcp workspaces and multi-tenancy features | |
258+
| openshift | OpenShift-specific tools for cluster management and troubleshooting, check the [OpenShift documentation](docs/OPENSHIFT.md) for more details. | |
258259
| kubevirt | KubeVirt virtual machine management tools | |
259260
| observability | Cluster observability tools for querying Prometheus metrics and Alertmanager alerts ||
260261
| ossm | Most common tools for managing OSSM, check the [OSSM documentation](https://github.com/openshift/openshift-mcp-server/blob/main/docs/OSSM.md) for more details. | |
@@ -553,6 +554,25 @@ Common use cases:
553554

554555
</details>
555556

557+
<details>
558+
559+
<summary>openshift</summary>
560+
561+
- **plan_mustgather** - Plan for collecting a must-gather archive from an OpenShift cluster, must-gather is a tool for collecting cluster data related to debugging and troubleshooting like logs, kubernetes resources, etc.
562+
- `node_name` (`string`) - Optional node to run the mustgather pod. If not provided, a random control-plane node will be selected automatically
563+
- `node_selector` (`string`) - Optional node label selector to use, only relevant when specifying a command and image which needs to capture data on a set of cluster nodes simultaneously
564+
- `host_network` (`boolean`) - Optionally run the must-gather pods in the host network of the node. This is only relevant if a specific gather image needs to capture host-level data
565+
- `gather_command` (`string`) - Optionally specify a custom gather command to run a specialized script, eg. /usr/bin/gather_audit_logs (default: /usr/bin/gather)
566+
- `all_component_images` (`boolean`) - Optional when enabled, collects and runs multiple must gathers for all operators and components on the cluster that have an annotated must-gather image available
567+
- `images` (`array`) - Optional list of images to use for gathering custom information about specific operators or cluster components. If not specified, OpenShift's default must-gather image will be used by default
568+
- `source_dir` (`string`) - Optional to set a specific directory where the pod will copy gathered data from (default: /must-gather)
569+
- `timeout` (`string`) - Timeout of the gather process eg. 30s, 6m20s, or 2h10m30s
570+
- `namespace` (`string`) - Optional to specify an existing privileged namespace where must-gather pods should run. If not provided, a temporary namespace will be created
571+
- `keep_resources` (`boolean`) - Optional to retain all temporary resources when the mustgather completes, otherwise temporary resources created will be advised to be cleaned up
572+
- `since` (`string`) - Optional to collect logs newer than a relative duration like 5s, 2m5s, or 3h6m10s. If unspecified, all available logs will be collected
573+
574+
</details>
575+
556576

557577
<!-- AVAILABLE-TOOLSETS-TOOLS-END -->
558578

docs/OPENSHIFT.md

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
# OpenShift Toolset
2+
3+
This toolset provides OpenShift-specific prompts for cluster management and troubleshooting.
4+
5+
## Prompts
6+
7+
### plan_mustgather
8+
9+
Plan for collecting a must-gather archive from an OpenShift cluster. Must-gather is a tool for collecting cluster data related to debugging and troubleshooting like logs, Kubernetes resources, and more.
10+
11+
This prompt generates YAML manifests for the must-gather resources that can be applied to the cluster.
12+
13+
**Arguments:**
14+
- `node_name` (optional) - Specific node name to run must-gather pod on
15+
- `node_selector` (optional) - Node selector in `key=value,key2=value2` format to filter nodes for the pod
16+
- `source_dir` (optional) - Custom gather directory inside pod (default: `/must-gather`)
17+
- `namespace` (optional) - Privileged namespace to use for must-gather (auto-generated if not specified)
18+
- `gather_command` (optional) - Custom gather command e.g. `/usr/bin/gather_audit_logs` (default: `/usr/bin/gather`)
19+
- `timeout` (optional) - Timeout duration for gather command (e.g., `30m`, `1h`)
20+
- `since` (optional) - Only gather data newer than this duration (e.g., `5s`, `2m5s`, or `3h6m10s`), defaults to all data
21+
- `host_network` (optional) - Use host network for must-gather pod (`true`/`false`)
22+
- `keep_resources` (optional) - Keep pod resources after collection (`true`/`false`, default: `false`)
23+
- `all_component_images` (optional) - Include must-gather images from all installed operators (`true`/`false`)
24+
- `images` (optional) - Comma-separated list of custom must-gather container images
25+
26+
**Example:**
27+
```
28+
# Basic must-gather collection
29+
{}
30+
31+
# Collect with custom timeout and since
32+
{
33+
"timeout": "30m",
34+
"since": "1h"
35+
}
36+
37+
# Collect from all component images
38+
{
39+
"all_component_images": "true"
40+
}
41+
42+
# Collect from specific operator image
43+
{
44+
"images": "registry.redhat.io/openshift-logging/cluster-logging-rhel9-operator@sha256:..."
45+
}
46+
```
47+
48+
## Enable the OpenShift Toolset
49+
50+
### Option 1: Command Line
51+
52+
```bash
53+
kubernetes-mcp-server --toolsets core,config,helm,openshift
54+
```
55+
56+
### Option 2: Configuration File
57+
58+
```toml
59+
toolsets = ["core", "config", "helm", "openshift"]
60+
```
61+
62+
### Option 3: MCP Client Configuration
63+
64+
```json
65+
{
66+
"mcpServers": {
67+
"kubernetes": {
68+
"command": "npx",
69+
"args": ["-y", "kubernetes-mcp-server@latest", "--toolsets", "core,config,helm,openshift"]
70+
}
71+
}
72+
}
73+
```
74+
75+
## Prerequisites
76+
77+
The OpenShift toolset requires:
78+
79+
1. **OpenShift cluster** - These prompts are designed for OpenShift and automatically detect the cluster type
80+
2. **Proper RBAC** - The user/service account must have permissions to:
81+
- Create namespaces
82+
- Create service accounts
83+
- Create cluster role bindings
84+
- Create pods with privileged access
85+
- List ClusterOperators and ClusterServiceVersions (for `all_component_images`)
86+
87+
## How It Works
88+
89+
### Must-Gather Plan Generation
90+
91+
The `plan_mustgather` prompt generates YAML manifests for collecting diagnostic data from an OpenShift cluster:
92+
93+
1. **Namespace** - A temporary namespace (e.g., `openshift-must-gather-xyz`) is created unless an existing namespace is specified
94+
2. **ServiceAccount** - A service account with cluster-admin permissions is created for the must-gather pod
95+
3. **ClusterRoleBinding** - Binds the service account to the cluster-admin role
96+
4. **Pod** - Runs the must-gather container(s) with the specified configuration
97+
98+
### Component Image Discovery
99+
100+
When `all_component_images` is enabled, the prompt discovers must-gather images from:
101+
- **ClusterOperators** - Looks for the `operators.openshift.io/must-gather-image` annotation
102+
- **ClusterServiceVersions** - Checks OLM-installed operators for the same annotation
103+
104+
### Multiple Images Support
105+
106+
Up to 8 gather images can be run concurrently. Each image runs in a separate container within the same pod, sharing the output volume.
107+
108+
## Common Use Cases
109+
110+
### Basic Cluster Diagnostics
111+
112+
Collect general cluster diagnostics:
113+
```json
114+
{}
115+
```
116+
117+
### Audit Logs Collection
118+
119+
Collect audit logs with a custom gather command:
120+
```json
121+
{
122+
"gather_command": "/usr/bin/gather_audit_logs",
123+
"timeout": "2h"
124+
}
125+
```
126+
127+
### Recent Logs Only
128+
129+
Collect logs from the last 30 minutes:
130+
```json
131+
{
132+
"since": "30m"
133+
}
134+
```
135+
136+
### Specific Operator Diagnostics
137+
138+
Collect diagnostics for a specific operator:
139+
```json
140+
{
141+
"images": "registry.redhat.io/openshift-logging/cluster-logging-rhel9-operator@sha256:..."
142+
}
143+
```
144+
145+
### Host Network Access
146+
147+
For gather scripts that need host-level network access:
148+
```json
149+
{
150+
"host_network": "true"
151+
}
152+
```
153+
154+
### All Component Diagnostics
155+
156+
Collect diagnostics from all operators with must-gather images:
157+
```json
158+
{
159+
"all_component_images": "true",
160+
"timeout": "1h"
161+
}
162+
```
163+
164+
## Troubleshooting
165+
166+
### Permission Errors
167+
168+
If you see permission warnings, ensure your user has the required RBAC permissions:
169+
```bash
170+
oc auth can-i create namespaces
171+
oc auth can-i create clusterrolebindings
172+
oc auth can-i create pods --as=system:serviceaccount:openshift-must-gather-xxx:must-gather-collector
173+
```
174+
175+
### Pod Not Starting
176+
177+
Check if the node has enough resources and can pull the must-gather image:
178+
```bash
179+
oc get pods -n openshift-must-gather-xxx
180+
oc describe pod <pod-name> -n openshift-must-gather-xxx
181+
```
182+
183+
### Timeout Issues
184+
185+
For large clusters or audit log collection, increase the timeout:
186+
```json
187+
{
188+
"timeout": "2h"
189+
}
190+
```
191+
192+
### Image Pull Errors
193+
194+
Ensure the must-gather image is accessible:
195+
```bash
196+
oc get secret -n openshift-config pull-secret
197+
```
198+
199+
## Security Considerations
200+
201+
### Privileged Access
202+
203+
The must-gather pods run with:
204+
- `cluster-admin` ClusterRoleBinding
205+
- `system-cluster-critical` priority class
206+
- Tolerations for all taints
207+
- Optional host network access
208+
209+
### Temporary Resources
210+
211+
By default, all created resources (namespace, service account, cluster role binding) should be cleaned up after the must-gather collection is complete. Use `"keep_resources": "true"` to retain them for debugging.
212+
213+
### Image Sources
214+
215+
The prompt uses these default images:
216+
- **Must-gather**: `registry.redhat.io/openshift4/ose-must-gather:latest`
217+
- **Wait container**: `registry.redhat.io/ubi9/ubi-minimal`
218+
219+
Custom images should be from trusted sources.

pkg/mcp/modules.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ import (
99
_ "github.com/containers/kubernetes-mcp-server/pkg/toolsets/kubevirt"
1010
_ "github.com/containers/kubernetes-mcp-server/pkg/toolsets/netedge"
1111
_ "github.com/containers/kubernetes-mcp-server/pkg/toolsets/observability"
12+
_ "github.com/containers/kubernetes-mcp-server/pkg/toolsets/openshift"
1213
)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
[
2+
{
3+
"name": "plan_mustgather",
4+
"description": "Plan for collecting a must-gather archive from an OpenShift cluster. Must-gather is a tool for collecting cluster data related to debugging and troubleshooting like logs, kubernetes resources, etc.",
5+
"arguments": [
6+
{
7+
"name": "node_name",
8+
"description": "Specific node name to run must-gather pod on"
9+
},
10+
{
11+
"name": "node_selector",
12+
"description": "Node selector in key=value,key2=value2 format to filter nodes for the pod"
13+
},
14+
{
15+
"name": "source_dir",
16+
"description": "Custom gather directory inside pod (default: /must-gather)"
17+
},
18+
{
19+
"name": "namespace",
20+
"description": "Privileged namespace to use for must-gather (auto-generated if not specified)"
21+
},
22+
{
23+
"name": "gather_command",
24+
"description": "Custom gather command eg. /usr/bin/gather_audit_logs (default: /usr/bin/gather)"
25+
},
26+
{
27+
"name": "timeout",
28+
"description": "Timeout duration for gather command (eg. 30m, 1h)"
29+
},
30+
{
31+
"name": "since",
32+
"description": "Only gather data newer than this duration (eg. 5s, 2m5s, or 3h6m10s) defaults to all data."
33+
},
34+
{
35+
"name": "host_network",
36+
"description": "Use host network for must-gather pod (true/false)"
37+
},
38+
{
39+
"name": "keep_resources",
40+
"description": "Keep pod resources after collection (true/false, default: false)"
41+
},
42+
{
43+
"name": "all_component_images",
44+
"description": "Include must-gather images from all installed operators (true/false)"
45+
},
46+
{
47+
"name": "images",
48+
"description": "Comma-separated list of custom must-gather container images"
49+
}
50+
]
51+
}
52+
]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[]

pkg/mcp/toolsets_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"github.com/containers/kubernetes-mcp-server/pkg/toolsets/kcp"
2020
"github.com/containers/kubernetes-mcp-server/pkg/toolsets/kiali"
2121
"github.com/containers/kubernetes-mcp-server/pkg/toolsets/kubevirt"
22+
"github.com/containers/kubernetes-mcp-server/pkg/toolsets/openshift"
2223
"github.com/modelcontextprotocol/go-sdk/mcp"
2324
"github.com/stretchr/testify/suite"
2425
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
@@ -180,6 +181,42 @@ func (s *ToolsetsSuite) TestGranularToolsetsTools() {
180181
}
181182
}
182183

184+
func (s *ToolsetsSuite) TestOpenShiftToolset() {
185+
s.Run("OpenShift toolset in OpenShift cluster", func() {
186+
s.Handle(test.NewInOpenShiftHandler())
187+
toolsets.Clear()
188+
toolsets.Register(&openshift.Toolset{})
189+
s.Cfg.Toolsets = []string{"openshift"}
190+
s.InitMcpClient()
191+
tools, err := s.ListTools()
192+
s.Run("ListTools returns tools", func() {
193+
s.NotNil(tools, "Expected tools from ListTools")
194+
s.NoError(err, "Expected no error from ListTools")
195+
})
196+
s.Run("ListTools returns correct Tool metadata", func() {
197+
s.assertJsonSnapshot("toolsets-openshift-tools.json", tools.Tools)
198+
})
199+
})
200+
}
201+
202+
func (s *ToolsetsSuite) TestOpenShiftToolsetPrompts() {
203+
s.Run("OpenShift toolset prompts in OpenShift cluster", func() {
204+
s.Handle(test.NewInOpenShiftHandler())
205+
toolsets.Clear()
206+
toolsets.Register(&openshift.Toolset{})
207+
s.Cfg.Toolsets = []string{"openshift"}
208+
s.InitMcpClient()
209+
prompts, err := s.ListPrompts()
210+
s.Run("ListPrompts returns prompts", func() {
211+
s.NotNil(prompts, "Expected prompts from ListPrompts")
212+
s.NoError(err, "Expected no error from ListPrompts")
213+
})
214+
s.Run("ListPrompts returns correct Prompt metadata", func() {
215+
s.assertJsonSnapshot("toolsets-openshift-prompts.json", prompts.Prompts)
216+
})
217+
})
218+
}
219+
183220
func (s *ToolsetsSuite) TestInputSchemaEdgeCases() {
184221
//https://github.com/containers/kubernetes-mcp-server/issues/340
185222
s.Run("InputSchema for no-arg tool is object with empty properties", func() {

0 commit comments

Comments
 (0)