132 lines
4.2 KiB
Go
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
|
|
}
|