Implement mcp purge command for registry cleanup

Add PurgeComponent RPC to the agent service that removes stale registry
entries for components that are both gone (observed state is removed,
unknown, or exited) and unwanted (not in any current service definition).
Refuses to purge components with running or stopped containers. When all
components of a service are purged, the service row is deleted too.
Supports --dry-run to preview without modifying the database.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-26 22:30:45 -07:00
parent 1afbf5e1f6
commit 1e58dcce27
8 changed files with 1001 additions and 36 deletions

View File

@@ -28,6 +28,7 @@ const (
McpAgentService_GetServiceStatus_FullMethodName = "/mcp.v1.McpAgentService/GetServiceStatus"
McpAgentService_LiveCheck_FullMethodName = "/mcp.v1.McpAgentService/LiveCheck"
McpAgentService_AdoptContainers_FullMethodName = "/mcp.v1.McpAgentService/AdoptContainers"
McpAgentService_PurgeComponent_FullMethodName = "/mcp.v1.McpAgentService/PurgeComponent"
McpAgentService_PushFile_FullMethodName = "/mcp.v1.McpAgentService/PushFile"
McpAgentService_PullFile_FullMethodName = "/mcp.v1.McpAgentService/PullFile"
McpAgentService_NodeStatus_FullMethodName = "/mcp.v1.McpAgentService/NodeStatus"
@@ -50,6 +51,8 @@ type McpAgentServiceClient interface {
LiveCheck(ctx context.Context, in *LiveCheckRequest, opts ...grpc.CallOption) (*LiveCheckResponse, error)
// Adopt
AdoptContainers(ctx context.Context, in *AdoptContainersRequest, opts ...grpc.CallOption) (*AdoptContainersResponse, error)
// Purge
PurgeComponent(ctx context.Context, in *PurgeRequest, opts ...grpc.CallOption) (*PurgeResponse, error)
// File transfer
PushFile(ctx context.Context, in *PushFileRequest, opts ...grpc.CallOption) (*PushFileResponse, error)
PullFile(ctx context.Context, in *PullFileRequest, opts ...grpc.CallOption) (*PullFileResponse, error)
@@ -155,6 +158,16 @@ func (c *mcpAgentServiceClient) AdoptContainers(ctx context.Context, in *AdoptCo
return out, nil
}
func (c *mcpAgentServiceClient) PurgeComponent(ctx context.Context, in *PurgeRequest, opts ...grpc.CallOption) (*PurgeResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(PurgeResponse)
err := c.cc.Invoke(ctx, McpAgentService_PurgeComponent_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *mcpAgentServiceClient) PushFile(ctx context.Context, in *PushFileRequest, opts ...grpc.CallOption) (*PushFileResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(PushFileResponse)
@@ -202,6 +215,8 @@ type McpAgentServiceServer interface {
LiveCheck(context.Context, *LiveCheckRequest) (*LiveCheckResponse, error)
// Adopt
AdoptContainers(context.Context, *AdoptContainersRequest) (*AdoptContainersResponse, error)
// Purge
PurgeComponent(context.Context, *PurgeRequest) (*PurgeResponse, error)
// File transfer
PushFile(context.Context, *PushFileRequest) (*PushFileResponse, error)
PullFile(context.Context, *PullFileRequest) (*PullFileResponse, error)
@@ -244,6 +259,9 @@ func (UnimplementedMcpAgentServiceServer) LiveCheck(context.Context, *LiveCheckR
func (UnimplementedMcpAgentServiceServer) AdoptContainers(context.Context, *AdoptContainersRequest) (*AdoptContainersResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AdoptContainers not implemented")
}
func (UnimplementedMcpAgentServiceServer) PurgeComponent(context.Context, *PurgeRequest) (*PurgeResponse, error) {
return nil, status.Error(codes.Unimplemented, "method PurgeComponent not implemented")
}
func (UnimplementedMcpAgentServiceServer) PushFile(context.Context, *PushFileRequest) (*PushFileResponse, error) {
return nil, status.Error(codes.Unimplemented, "method PushFile not implemented")
}
@@ -436,6 +454,24 @@ func _McpAgentService_AdoptContainers_Handler(srv interface{}, ctx context.Conte
return interceptor(ctx, in, info, handler)
}
func _McpAgentService_PurgeComponent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(PurgeRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(McpAgentServiceServer).PurgeComponent(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: McpAgentService_PurgeComponent_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(McpAgentServiceServer).PurgeComponent(ctx, req.(*PurgeRequest))
}
return interceptor(ctx, in, info, handler)
}
func _McpAgentService_PushFile_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(PushFileRequest)
if err := dec(in); err != nil {
@@ -533,6 +569,10 @@ var McpAgentService_ServiceDesc = grpc.ServiceDesc{
MethodName: "AdoptContainers",
Handler: _McpAgentService_AdoptContainers_Handler,
},
{
MethodName: "PurgeComponent",
Handler: _McpAgentService_PurgeComponent_Handler,
},
{
MethodName: "PushFile",
Handler: _McpAgentService_PushFile_Handler,