Files
forge-tools-proxmox/internal/tools/storage.go
T

132 lines
4.2 KiB
Go

package tools
import (
"context"
"forge-tools-proxmox/internal/pve"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
// storage.go — хранилища: storage_list, storage_status (read) и содержимое
// (templates_list / isos_list). Только наблюдение: изменение хранилищ
// (Ceph/ZFS/SDN) — зона отдельного модуля (см. README «Roadmap»), чтобы не
// тащить комбайн и не рисковать дисковой подсистемой.
func registerStorageTools(s *mcp.Server) {
s.AddTool(&mcp.Tool{
Name: "storage_list",
Description: "List storage pools (type/content/usage). Read-only.",
InputSchema: schema(map[string]any{
"host": strProps("Cluster alias (default: primary)", false),
}, nil),
}, storageListHandler)
s.AddTool(&mcp.Tool{
Name: "storage_status",
Description: "Storage pool status and usage (per node). Read-only.",
InputSchema: schema(map[string]any{
"node": strProps("Node name", true),
"host": strProps("Cluster alias (default: primary)", false),
}, []string{"node"}),
}, storageStatusHandler)
s.AddTool(&mcp.Tool{
Name: "templates_list",
Description: "List LXC templates (vztmpl) on a storage. Read-only.",
InputSchema: schema(map[string]any{
"node": strProps("Node name", true),
"storage": strProps("Storage (default: local)", false),
"host": strProps("Cluster alias (default: primary)", false),
}, []string{"node"}),
}, templatesListHandler)
s.AddTool(&mcp.Tool{
Name: "isos_list",
Description: "List ISO images on a storage. Read-only.",
InputSchema: schema(map[string]any{
"node": strProps("Node name", true),
"storage": strProps("Storage (default: local)", false),
"host": strProps("Cluster alias (default: primary)", false),
}, []string{"node"}),
}, isosListHandler)
}
func storageListHandler(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
t, err := tenantFor(ctx, req)
if err != nil {
return errorResult(err.Error()), nil
}
host, err := resolveHost(t, requestArgs(req))
if err != nil {
return errorResult(err.Error()), nil
}
cctx, cancel := timeout(ctx, t)
defer cancel()
data, err := t.StorageList(cctx, host)
if err != nil {
return errorResult(err.Error()), nil
}
return textResult(pretty(data)), nil
}
func storageStatusHandler(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
// storage_status — статус хранилищ ноды (через /nodes/{node}/storage).
t, err := tenantFor(ctx, req)
if err != nil {
return errorResult(err.Error()), nil
}
args := requestArgs(req)
node, err := requireNode(args)
if err != nil {
return errorResult(err.Error()), nil
}
host, err := resolveHost(t, args)
if err != nil {
return errorResult(err.Error()), nil
}
cctx, cancel := timeout(ctx, t)
defer cancel()
data, err := t.NodeStorage(cctx, host, node)
if err != nil {
return errorResult(err.Error()), nil
}
return textResult(pretty(data)), nil
}
func templatesListHandler(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
return contentListHandler(ctx, req, "vztmpl")
}
func isosListHandler(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
return contentListHandler(ctx, req, "iso")
}
// contentListHandler — содержимое хранилища по типу (vztmpl/iso/backup/images).
func contentListHandler(ctx context.Context, req *mcp.CallToolRequest, contentType string) (*mcp.CallToolResult, error) {
t, err := tenantFor(ctx, req)
if err != nil {
return errorResult(err.Error()), nil
}
args := requestArgs(req)
node, err := requireNode(args)
if err != nil {
return errorResult(err.Error()), nil
}
storage := getString(args, "storage", "local")
if err := pve.ValidateIdentifier(storage); err != nil {
return errorResult(err.Error()), nil
}
host, err := resolveHost(t, args)
if err != nil {
return errorResult(err.Error()), nil
}
cctx, cancel := timeout(ctx, t)
defer cancel()
data, err := t.StorageContent(cctx, host, node, storage, contentType)
if err != nil {
return errorResult(err.Error()), nil
}
return textResult(pretty(data)), nil
}