91 lines
3.2 KiB
Go
91 lines
3.2 KiB
Go
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
|
|
}
|