@@ -2,16 +2,22 @@ package mcp
2
2
3
3
import (
4
4
"context"
5
+ "encoding/json"
6
+ "fmt"
5
7
"github.com/mark3labs/mcp-go/client"
6
8
"github.com/mark3labs/mcp-go/mcp"
7
9
"github.com/mark3labs/mcp-go/server"
8
10
"github.com/spf13/afero"
9
11
corev1 "k8s.io/api/core/v1"
12
+ apiextensionsv1spec "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
13
+ apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1"
10
14
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15
+ "k8s.io/apimachinery/pkg/watch"
11
16
"k8s.io/client-go/kubernetes"
12
17
"k8s.io/client-go/rest"
13
18
"k8s.io/client-go/tools/clientcmd"
14
19
"k8s.io/client-go/tools/clientcmd/api"
20
+ toolswatch "k8s.io/client-go/tools/watch"
15
21
"net/http/httptest"
16
22
"os"
17
23
"path/filepath"
@@ -142,14 +148,74 @@ func (c *mcpContext) withEnvTest() {
142
148
c .withKubeConfig (envTestRestConfig )
143
149
}
144
150
151
+ // inOpenShift sets up the kubernetes environment to seem to be running OpenShift
152
+ func (c * mcpContext ) inOpenShift () func () {
153
+ c .withKubeConfig (envTestRestConfig )
154
+ return c .crdApply (`
155
+ {
156
+ "apiVersion": "apiextensions.k8s.io/v1",
157
+ "kind": "CustomResourceDefinition",
158
+ "metadata": {"name": "routes.route.openshift.io"},
159
+ "spec": {
160
+ "group": "route.openshift.io",
161
+ "versions": [{
162
+ "name": "v1","served": true,"storage": true,
163
+ "schema": {"openAPIV3Schema": {"type": "object","x-kubernetes-preserve-unknown-fields": true}}
164
+ }],
165
+ "scope": "Namespaced",
166
+ "names": {"plural": "routes","singular": "route","kind": "Route"}
167
+ }
168
+ }` )
169
+ }
170
+
145
171
// newKubernetesClient creates a new Kubernetes client with the current kubeconfig
146
172
func (c * mcpContext ) newKubernetesClient () * kubernetes.Clientset {
147
173
c .withEnvTest ()
148
- pathOptions := clientcmd .NewDefaultPathOptions ()
149
- cfg , _ := clientcmd .BuildConfigFromFlags ("" , pathOptions .GetDefaultFilename ())
174
+ cfg , _ := clientcmd .BuildConfigFromFlags ("" , clientcmd .NewDefaultPathOptions ().GetDefaultFilename ())
150
175
return kubernetes .NewForConfigOrDie (cfg )
151
176
}
152
177
178
+ // newApiExtensionsClient creates a new ApiExtensions client with the envTest kubeconfig
179
+ func (c * mcpContext ) newApiExtensionsClient () * apiextensionsv1.ApiextensionsV1Client {
180
+ return apiextensionsv1 .NewForConfigOrDie (envTestRestConfig )
181
+ }
182
+
183
+ // crdApply creates a CRD from the provided resource string and waits for it to be established, returns a cleanup function
184
+ func (c * mcpContext ) crdApply (resource string ) func () {
185
+ apiExtensionsV1Client := c .newApiExtensionsClient ()
186
+ var crd = & apiextensionsv1spec.CustomResourceDefinition {}
187
+ err := json .Unmarshal ([]byte (resource ), crd )
188
+ _ , err = apiExtensionsV1Client .CustomResourceDefinitions ().Create (c .ctx , crd , metav1.CreateOptions {})
189
+ if err != nil {
190
+ panic (fmt .Errorf ("failed to create CRD %v" , err ))
191
+ }
192
+ c .crdWaitUntilReady (crd .Name )
193
+ return func () {
194
+ err = apiExtensionsV1Client .CustomResourceDefinitions ().Delete (c .ctx , "routes.route.openshift.io" , metav1.DeleteOptions {})
195
+ if err != nil {
196
+ panic (fmt .Errorf ("failed to delete CRD %v" , err ))
197
+ }
198
+ }
199
+ }
200
+
201
+ // crdWaitUntilReady waits for a CRD to be established
202
+ func (c * mcpContext ) crdWaitUntilReady (name string ) {
203
+ watcher , err := c .newApiExtensionsClient ().CustomResourceDefinitions ().Watch (c .ctx , metav1.ListOptions {
204
+ FieldSelector : "metadata.name=" + name ,
205
+ })
206
+ _ , err = toolswatch .UntilWithoutRetry (c .ctx , watcher , func (event watch.Event ) (bool , error ) {
207
+ for _ , c := range event .Object .(* apiextensionsv1spec.CustomResourceDefinition ).Status .Conditions {
208
+ if c .Type == apiextensionsv1spec .Established && c .Status == apiextensionsv1spec .ConditionTrue {
209
+ return true , nil
210
+ }
211
+ }
212
+ return false , nil
213
+ })
214
+ if err != nil {
215
+ panic (fmt .Errorf ("failed to wait for CRD %v" , err ))
216
+ }
217
+ }
218
+
153
219
// callTool helper function to call a tool by name with arguments
154
220
func (c * mcpContext ) callTool (name string , args map [string ]interface {}) (* mcp.CallToolResult , error ) {
155
221
callToolRequest := mcp.CallToolRequest {}
0 commit comments