package tools import ( "context" "fmt" "net/url" "github.com/modelcontextprotocol/go-sdk/mcp" ) // vm_cloudinit.go — настройка cloud-init гостя (только QEMU): ciuser, // cipassword, ipconfig0/1.., sshkeys. Структурная мутация → confirm + gate. // Для гостей-ВМ; LXC-cloud-init не поддерживается PVE API. func registerVMCloudInitTools(s *mcp.Server) { registerPatternTool(s, &mcp.Tool{ Name: "vm_set_cloudinit", Description: "Set cloud-init options of a QEMU VM: user, password, per-NIC ipconfig, SSH keys. Requires confirm + write permission.", InputSchema: schema(map[string]any{ "node": strProps("Node name", true), "vmid": strProps("VM ID", true), "ciuser": strProps("Cloud-init login user", false), "cipassword": strProps("Cloud-init login password", false), "sshkeys": strProps("Public SSH key(s) for the user", false), "ipconfig0": strProps("ipconfig0 spec, e.g. ip=dhcp or ip=192.168.1.10/24,gw=192.168.102.100", false), "confirm": strProps("Set to \"true\" to confirm", true, "true"), }, []string{"node", "vmid", "confirm"}), }, vmPatterns, vmSetCloudInitHandler) } func vmSetCloudInitHandler(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) { t, err := tenantFor(ctx, req) if err != nil { return errorResult(err.Error()), nil } args := requestArgs(req) node, vmid, host, r := resolveVMArgs(t, args) if r != nil { return r, nil } if err := confirm(args, "vm_set_cloudinit"); err != nil { return errorResult(err.Error()), nil } if err := gateVMWrite(t, host, vmid); err != nil { return errorResult(err.Error()), nil } form := url.Values{} for _, k := range []string{"ciuser", "cipassword", "sshkeys", "ipconfig0"} { if v := getString(args, k, ""); v != "" { form.Set(k, v) } } if len(form) == 0 { return errorResult("at least one cloud-init field is required"), nil } // Включаем cloud-init диск (для OVMF/машин с cidata) — обычно ide2:cloudinit. upid, err := t.ConfigPost(ctx, host, node, vmTypeQEMU, vmid, form) if err != nil { return errorResult(err.Error()), nil } return textResult(upidMsg("vm_set_cloudinit", fmt.Sprintf("%s/%d", node, vmid), upid)), nil }