Skip to content

Commit 775deaf

Browse files
committed
feat(kubevirt): Add VM management toolset with plan-based creation
Introduces a new KubeVirt toolset providing virtual machine management capabilities through MCP tools. The vm_create tool generates comprehensive creation plans with pre-creation validation of instance types, preferences, and container disk images, enabling AI assistants to help users create VirtualMachines with appropriate resource configurations. The tool supports: - Workload specification via OS names or container disk URLs - Auto-selection of instance types based on size/performance hints - DataSource integration for common OS images - Comprehensive validation and planning before resource creation Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Lee Yarwood <lyarwood@redhat.com>
1 parent 7b20de4 commit 775deaf

File tree

11 files changed

+1527
-1
lines changed

11 files changed

+1527
-1
lines changed

internal/tools/update-readme/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
_ "github.com/containers/kubernetes-mcp-server/pkg/toolsets/config"
1616
_ "github.com/containers/kubernetes-mcp-server/pkg/toolsets/core"
1717
_ "github.com/containers/kubernetes-mcp-server/pkg/toolsets/helm"
18+
_ "github.com/containers/kubernetes-mcp-server/pkg/toolsets/kubevirt"
1819
)
1920

2021
type OpenShift struct{}

pkg/kubernetes-mcp-server/cmd/root_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ func TestToolsets(t *testing.T) {
137137
rootCmd := NewMCPServer(ioStreams)
138138
rootCmd.SetArgs([]string{"--help"})
139139
o, err := captureOutput(rootCmd.Execute) // --help doesn't use logger/klog, cobra prints directly to stdout
140-
if !strings.Contains(o, "Comma-separated list of MCP toolsets to use (available toolsets: config, core, helm).") {
140+
if !strings.Contains(o, "Comma-separated list of MCP toolsets to use (available toolsets: config, core, helm, kubevirt).") {
141141
t.Fatalf("Expected all available toolsets, got %s %v", o, err)
142142
}
143143
})

pkg/kubernetes/kubernetes.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package kubernetes
22

33
import (
44
"k8s.io/apimachinery/pkg/runtime"
5+
"k8s.io/client-go/rest"
56

67
"github.com/containers/kubernetes-mcp-server/pkg/helm"
78
"k8s.io/client-go/kubernetes/scheme"
@@ -30,6 +31,14 @@ func (k *Kubernetes) AccessControlClientset() *AccessControlClientset {
3031
return k.manager.accessControlClientSet
3132
}
3233

34+
// RESTConfig returns the Kubernetes REST configuration
35+
func (k *Kubernetes) RESTConfig() *rest.Config {
36+
if k.manager == nil {
37+
return nil
38+
}
39+
return k.manager.cfg
40+
}
41+
3342
var Scheme = scheme.Scheme
3443
var ParameterCodec = runtime.NewParameterCodec(Scheme)
3544

pkg/mcp/modules.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ package mcp
33
import _ "github.com/containers/kubernetes-mcp-server/pkg/toolsets/config"
44
import _ "github.com/containers/kubernetes-mcp-server/pkg/toolsets/core"
55
import _ "github.com/containers/kubernetes-mcp-server/pkg/toolsets/helm"
6+
import _ "github.com/containers/kubernetes-mcp-server/pkg/toolsets/kubevirt"

pkg/toolsets/kubevirt/toolset.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package kubevirt
2+
3+
import (
4+
"slices"
5+
6+
"github.com/containers/kubernetes-mcp-server/pkg/api"
7+
internalk8s "github.com/containers/kubernetes-mcp-server/pkg/kubernetes"
8+
"github.com/containers/kubernetes-mcp-server/pkg/toolsets"
9+
vm_create "github.com/containers/kubernetes-mcp-server/pkg/toolsets/kubevirt/vm/create"
10+
vm_troubleshoot "github.com/containers/kubernetes-mcp-server/pkg/toolsets/kubevirt/vm/troubleshoot"
11+
)
12+
13+
type Toolset struct{}
14+
15+
var _ api.Toolset = (*Toolset)(nil)
16+
17+
func (t *Toolset) GetName() string {
18+
return "kubevirt"
19+
}
20+
21+
func (t *Toolset) GetDescription() string {
22+
return "KubeVirt virtual machine management tools"
23+
}
24+
25+
func (t *Toolset) GetTools(o internalk8s.Openshift) []api.ServerTool {
26+
return slices.Concat(
27+
vm_create.Tools(),
28+
vm_troubleshoot.Tools(),
29+
)
30+
}
31+
32+
func init() {
33+
toolsets.Register(&Toolset{})
34+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# VirtualMachine Creation Plan
2+
3+
**IMPORTANT**: Always use `runStrategy` instead of the deprecated `running` field when creating VirtualMachines.
4+
5+
Use the `resources_create_or_update` tool with the following YAML:
6+
7+
```yaml
8+
apiVersion: kubevirt.io/v1
9+
kind: VirtualMachine
10+
metadata:
11+
name: {{.Name}}
12+
namespace: {{.Namespace}}
13+
spec:
14+
runStrategy: Halted
15+
{{- if .Instancetype}}
16+
instancetype:
17+
name: {{.Instancetype}}
18+
kind: VirtualMachineClusterInstancetype
19+
{{- end}}
20+
{{- if .Preference}}
21+
preference:
22+
name: {{.Preference}}
23+
kind: VirtualMachineClusterPreference
24+
{{- end}}
25+
{{- if .UseDataSource}}
26+
dataVolumeTemplates:
27+
- metadata:
28+
name: {{.Name}}-rootdisk
29+
spec:
30+
sourceRef:
31+
kind: DataSource
32+
name: {{.DataSourceName}}
33+
namespace: {{.DataSourceNamespace}}
34+
storage:
35+
resources:
36+
requests:
37+
storage: 30Gi
38+
{{- end}}
39+
template:
40+
spec:
41+
domain:
42+
devices:
43+
disks:
44+
- name: {{.Name}}-rootdisk
45+
{{- if not .Instancetype}}
46+
memory:
47+
guest: 2Gi
48+
{{- end}}
49+
volumes:
50+
- name: {{.Name}}-rootdisk
51+
{{- if .UseDataSource}}
52+
dataVolume:
53+
name: {{.Name}}-rootdisk
54+
{{- else}}
55+
containerDisk:
56+
image: {{.ContainerDisk}}
57+
{{- end}}
58+
```
59+
60+
## Run Strategy Options
61+
62+
The VM is created with `runStrategy: Halted` (stopped state). You can modify the `runStrategy` field to control the VM's execution:
63+
64+
- **`Halted`** - VM is stopped and will not run
65+
- **`Always`** - VM should always be running (restarts automatically)
66+
- **`RerunOnFailure`** - Restart the VM only if it fails
67+
- **`Manual`** - Manual start/stop control via `virtctl start/stop`
68+
- **`Once`** - Run the VM once, then stop when it terminates
69+
70+
To start the VM after creation, change `runStrategy: Halted` to `runStrategy: Always` or use the Manual strategy and start it with virtctl.
71+
72+
## Verification
73+
74+
After creating the VirtualMachine, verify it was created successfully:
75+
76+
Use the `resources_get` tool:
77+
- **apiVersion**: `kubevirt.io/v1`
78+
- **kind**: `VirtualMachine`
79+
- **namespace**: `{{.Namespace}}`
80+
- **name**: `{{.Name}}`
81+
82+
Check the resource details for any warnings or errors in the status conditions.
83+
84+
## Troubleshooting
85+
86+
If the VirtualMachine fails to create or start:
87+
88+
1. **Check the VM resource details and events**:
89+
- Use `resources_get` tool with apiVersion `kubevirt.io/v1`, kind `VirtualMachine`, namespace `{{.Namespace}}`, name `{{.Name}}`
90+
- Look for error messages in the status conditions
91+
92+
2. **Verify instance type exists** (if specified):
93+
- Use `resources_get` tool with apiVersion `instancetype.kubevirt.io/v1beta1`, kind `VirtualMachineClusterInstancetype`, name `{{.Instancetype}}`
94+
95+
3. **Verify preference exists** (if specified):
96+
- Use `resources_get` tool with apiVersion `instancetype.kubevirt.io/v1beta1`, kind `VirtualMachineClusterPreference`, name `{{.Preference}}`
97+
98+
4. **Check KubeVirt installation**:
99+
- Use `pods_list` tool with namespace `kubevirt`

0 commit comments

Comments
 (0)