-
Notifications
You must be signed in to change notification settings - Fork 191
feat(kubevirt): Add basic VM creation toolset #386
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
9aa2732 to
4eac816
Compare
a135353 to
24ad072
Compare
This comment was marked as outdated.
This comment was marked as outdated.
@lyarwood +1 from my side on that being nice, the reason we haven't been able to add it there is that we use claude code in the non-interactive setup in |
30c0ec0 to
c01fe35
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good work Lee. Please consider creating a single VM package with tool.go that will have all VM's actions in one single place, it would help to avoid duplications and will be much better in terms of readablity and maintainability.
codingben
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Lee.
Just an opinion: For the beginning I see too many folders and scripts to achieve a few VM's actions via MCP tooling. I'd ask the project's maintainers opinion about this, eventually this repository's codebase can be very huge.
Assuming you are talking about the test directory, I agree it is indeed pretty large at the moment but I've already spoken to folks about improvements to the |
pkg/kubernetes/kubernetes.go
Outdated
| // RESTConfig returns the Kubernetes REST configuration | ||
| func (k *Kubernetes) RESTConfig() *rest.Config { | ||
| if k.manager == nil { | ||
| return nil | ||
| } | ||
| return k.manager.cfg | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's already a ToRESTConfig method to cover this functionality and implement the RESTClientGetter interface required for Helm:
kubernetes-mcp-server/pkg/kubernetes/manager.go
Lines 195 to 198 in 7f4edfd
| // ToRESTConfig returns the rest.Config object (genericclioptions.RESTClientGetter) | |
| func (m *Manager) ToRESTConfig() (*rest.Config, error) { | |
| return m.cfg, nil | |
| } |
Similarly, there's already a ToDiscoveryClient method too (I think you're creating it at some point in the toolset).
Nonetheless, we need to prevent accessing any kubernetes API without checking if the resource is allowed by configuration:
kubernetes-mcp-server/pkg/kubernetes/accesscontrol.go
Lines 11 to 36 in cad863f
| // isAllowed checks the resource is in denied list or not. | |
| // If it is in denied list, this function returns false. | |
| func isAllowed( | |
| staticConfig *config.StaticConfig, // TODO: maybe just use the denied resource slice | |
| gvk *schema.GroupVersionKind, | |
| ) bool { | |
| if staticConfig == nil { | |
| return true | |
| } | |
| for _, val := range staticConfig.DeniedResources { | |
| // If kind is empty, that means Group/Version pair is denied entirely | |
| if val.Kind == "" { | |
| if gvk.Group == val.Group && gvk.Version == val.Version { | |
| return false | |
| } | |
| } | |
| if gvk.Group == val.Group && | |
| gvk.Version == val.Version && | |
| gvk.Kind == val.Kind { | |
| return false | |
| } | |
| } | |
| return true | |
| } |
In general, we don't want to directly expose the Kuberentes API to the toolsets implementors and provide whatetever is needed in the kubernetes package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pkg/kubernetes/resources.go
Outdated
|
|
||
| // ResourcesListByGVR lists resources using a GroupVersionResource directly. | ||
| // Access control is enforced through the RESTMapper. | ||
| // Use this when you need to query arbitrary resources not covered by ResourcesList. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lyarwood what is the use case where the ResourcesList doesn't work?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah apologies, should be fixed by 9cd97b4
aec49be to
9cd97b4
Compare
Add framework support for using k8s.io/client-go/dynamic/fake in tests. This enables unit tests to inject fake Kubernetes clients without requiring a real cluster or envtest setup. Changes: 1. Add NewAccessControlClientsetForTesting() constructor - Accepts pre-built fake clients (dynamic, discovery, REST mapper) - Returns AccessControlClientset for use in tests - Located in pkg/kubernetes/accesscontrol_clientset.go 2. Add NewForTesting() constructor for Kubernetes - Creates Kubernetes instance with fake AccessControlClientset - Minimal Manager setup suitable for testing - Located in pkg/kubernetes/kubernetes.go 3. Add Config() method to AccessControlClientset - Exposes rest.Config for use by other components - Fixes NewKiali() to use Config() instead of direct field access 4. Create pkg/kubernetes/testing package with helpers - NewFakeKubernetesClient() factory function - Accepts runtime.Scheme, GVR to ListKind mapping, and initial objects - Returns fully configured Kubernetes instance with fake clients - Includes FakeRESTMapper implementing meta.ResettableRESTMapper - Includes minimal fakeDiscoveryClient for cached discovery These changes enable toolset tests (like kubevirt VM creation) to use fake clients for unit testing without external dependencies. Assisted-By: Claude <[email protected]> Signed-off-by: Lee Yarwood <[email protected]>
Introduces a new KubeVirt toolset providing virtual machine management
capabilities through MCP tools.
Features:
- Smart workload resolution: Matches user input against cluster
DataSources or built-in OS mappings (fedora, ubuntu, centos, rhel,
debian, opensuse)
- Automatic instance type selection based on size/performance hints
- Preference auto-selection matching workload names
- Supports both DataSource-backed VMs and containerdisk VMs
- Configurable runStrategy (Halted by default, Always with autostart
flag)
Assisted-By: Claude <[email protected]>
Signed-off-by: Lee Yarwood <[email protected]>
…es/preferences Previously, the VM template hardcoded instancetype and preference kinds to always use VirtualMachineClusterInstancetype and VirtualMachineClusterPreference. This prevented using namespaced VirtualMachineInstancetype and VirtualMachinePreference resources. This enables VMs to reference both cluster-wide and namespace-specific instance types and preferences correctly. Assisted-By: Claude <[email protected]> Signed-off-by: Lee Yarwood <[email protected]>
Previously, the VM storage size was hardcoded to 30Gi in the template, making it impossible to create VMs with different disk sizes without manually editing the generated YAML. Storage parameter only applies when using DataSources. Container disk VMs don't create persistent volumes, so the parameter is ignored in those cases (as noted in the parameter description). Assisted-By: Claude <[email protected]> Signed-off-by: Lee Yarwood <[email protected]>
Previously, errors encountered while listing DataSources, Preferences, and Instancetypes were silently ignored, making it difficult to debug issues when resources weren't being discovered properly. This provides better observability for debugging while maintaining the existing resilient behavior (failures don't block VM creation, they just limit available resources for auto-selection). Assisted-By: Claude <[email protected]> Signed-off-by: Lee Yarwood <[email protected]>
Previously, public functions in pkg/kubevirt/resources.go lacked detailed documentation explaining their parameters, return values, and behavior. This made the code harder to understand and maintain. Assisted-By: Claude <[email protected]> Signed-off-by: Lee Yarwood <[email protected]>
Move tests to create_test package and access functionality only through the Tools() function, ensuring tests are decoupled from internal implementation details. Assisted-By: Claude <[email protected]> Signed-off-by: Lee Yarwood <[email protected]>
Signed-off-by: Marc Nuri <[email protected]>
manusa
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thx!
I added an additional commit to move the toolset tests to the MCP layer.
We are now testing the behavior from the MCP client up to the Kube API layer at no cost.
Production code looks good; there are a few optimizations that can be done, but I suppose we can defer these to follow up PRs.
|
/lgtm |
lyarwood
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/lgtm
Cali0707
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summary
This PR introduces an initial KubeVirt toolset for the kubernetes-mcp-server, enabling AI agents to create virtual machines through MCP tools.
New Tools
vm_createProvides VM creation with automatic resource resolution:
Example Usage
Basic VM with auto-selected resources
{ "name": "vm_create", "arguments": { "namespace": "vms", "name": "my-vm", "workload": "fedora" } }VM with specific size and performance hints
{ "name": "vm_create", "arguments": { "namespace": "vms", "name": "my-vm", "workload": "rhel", "size": "large", "performance": "compute-optimized", "storage": "100Gi" } }VM with explicit instancetype and preference
{ "name": "vm_create", "arguments": { "namespace": "vms", "name": "my-vm", "workload": "ubuntu", "instancetype": "u1.medium", "preference": "ubuntu", "autostart": true } }VM with custom container disk image
{ "name": "vm_create", "arguments": { "namespace": "vms", "name": "my-vm", "workload": "quay.io/myrepo/custom-os:v1.0", "size": "xlarge", "storage": "200Gi" } }