Initial commit: forge-tools-proxmox — MCP-сервер для Proxmox VE
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
// backup.go — бэкапы (vzdump): list (read) и create (async UPID).
|
||||
// В v1 НЕ реализованы restore/delete/prune: это тяжёлые необратимые
|
||||
// операции, требующие выверенной семантики; их лучше сделать отдельным
|
||||
// модулем-уточнением, чем рисковать в базовом. (см. README «Roadmap».)
|
||||
|
||||
func registerBackupTools(s *mcp.Server) {
|
||||
s.AddTool(&mcp.Tool{
|
||||
Name: "backup_list",
|
||||
Description: "List recent backup (vzdump) tasks. Read-only.",
|
||||
InputSchema: schema(map[string]any{
|
||||
"node": strProps("Node name (empty = whole cluster)", false),
|
||||
"host": strProps("Cluster alias (default: primary)", false),
|
||||
}, nil),
|
||||
}, backupListHandler)
|
||||
|
||||
registerPatternTool(s, &mcp.Tool{
|
||||
Name: "backup_create",
|
||||
Description: "Create a backup (vzdump) of a VM/CT. Async — returns UPID; poll via task_status(wait). Requires confirm + write permission.",
|
||||
InputSchema: schema(map[string]any{
|
||||
"node": strProps("Node name", true),
|
||||
"vmid": strProps("VM/CT ID", true),
|
||||
"storage": strProps("Backup storage (default: node local)", false),
|
||||
"mode": strProps("Backup mode", true, "snapshot", "suspend", "stop"),
|
||||
"compress": strProps("Compression", false, "zstd", "gzip", "lzo", "none"),
|
||||
"kind": strProps("Guest type", false, "qemu", "lxc"),
|
||||
"confirm": strProps("Set to \"true\" to confirm", true, "true"),
|
||||
}, []string{"node", "vmid", "confirm"}),
|
||||
}, vmPatterns, backupCreateHandler)
|
||||
}
|
||||
|
||||
func backupListHandler(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)
|
||||
host, err := resolveHost(t, args)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
cctx, cancel := timeout(ctx, t)
|
||||
defer cancel()
|
||||
data, err := t.BackupList(cctx, host, getString(args, "node", ""))
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
return textResult(pretty(data)), nil
|
||||
}
|
||||
|
||||
func backupCreateHandler(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, "backup_create"); err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
if err := gateVMWrite(t, host, vmid); err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
kind := guestKind(args)
|
||||
// mode: snapshot/suspend/stop. Если задан storage/compress — кладём в form.
|
||||
form := url.Values{"mode": {getString(args, "mode", "snapshot")}}
|
||||
if s := getString(args, "storage", ""); s != "" {
|
||||
form.Set("storage", s)
|
||||
}
|
||||
if c := getString(args, "compress", ""); c != "" && c != "none" {
|
||||
form.Set("compress", c)
|
||||
}
|
||||
upid, err := t.BackupCreate(ctx, host, node, kind, vmid, form)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
return textResult(upidMsg("backup_create", fmt.Sprintf("%s/%d", node, vmid), upid)), nil
|
||||
}
|
||||
Reference in New Issue
Block a user