Add component-level targeting to start, stop, and restart
Allow start/stop/restart to target a single component via <service>/<component> syntax, matching deploy/logs/purge. When a component is specified, start/stop skip toggling the service-level active flag. Agent-side filtering returns NotFound for unknown components. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,9 +12,9 @@ import (
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// StopService stops all components of a service.
|
||||
// StopService stops all components of a service, or a single component if specified.
|
||||
func (a *Agent) StopService(ctx context.Context, req *mcpv1.StopServiceRequest) (*mcpv1.StopServiceResponse, error) {
|
||||
a.Logger.Info("StopService", "service", req.GetName())
|
||||
a.Logger.Info("StopService", "service", req.GetName(), "component", req.GetComponent())
|
||||
|
||||
if req.GetName() == "" {
|
||||
return nil, status.Error(codes.InvalidArgument, "service name is required")
|
||||
@@ -25,6 +25,13 @@ func (a *Agent) StopService(ctx context.Context, req *mcpv1.StopServiceRequest)
|
||||
return nil, status.Errorf(codes.Internal, "list components: %v", err)
|
||||
}
|
||||
|
||||
if target := req.GetComponent(); target != "" {
|
||||
components, err = filterComponents(components, req.GetName(), target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var results []*mcpv1.ComponentResult
|
||||
for _, c := range components {
|
||||
containerName := ContainerNameFor(req.GetName(), c.Name)
|
||||
@@ -59,10 +66,10 @@ func (a *Agent) StopService(ctx context.Context, req *mcpv1.StopServiceRequest)
|
||||
return &mcpv1.StopServiceResponse{Results: results}, nil
|
||||
}
|
||||
|
||||
// StartService starts all components of a service. If a container already
|
||||
// exists but is stopped, it is removed first so a fresh one can be created.
|
||||
// StartService starts all components of a service, or a single component if specified.
|
||||
// If a container already exists but is stopped, it is removed first so a fresh one can be created.
|
||||
func (a *Agent) StartService(ctx context.Context, req *mcpv1.StartServiceRequest) (*mcpv1.StartServiceResponse, error) {
|
||||
a.Logger.Info("StartService", "service", req.GetName())
|
||||
a.Logger.Info("StartService", "service", req.GetName(), "component", req.GetComponent())
|
||||
|
||||
if req.GetName() == "" {
|
||||
return nil, status.Error(codes.InvalidArgument, "service name is required")
|
||||
@@ -73,6 +80,13 @@ func (a *Agent) StartService(ctx context.Context, req *mcpv1.StartServiceRequest
|
||||
return nil, status.Errorf(codes.Internal, "list components: %v", err)
|
||||
}
|
||||
|
||||
if target := req.GetComponent(); target != "" {
|
||||
components, err = filterComponents(components, req.GetName(), target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var results []*mcpv1.ComponentResult
|
||||
for _, c := range components {
|
||||
r := startComponent(ctx, a, req.GetName(), &c)
|
||||
@@ -82,10 +96,10 @@ func (a *Agent) StartService(ctx context.Context, req *mcpv1.StartServiceRequest
|
||||
return &mcpv1.StartServiceResponse{Results: results}, nil
|
||||
}
|
||||
|
||||
// RestartService restarts all components of a service by stopping, removing,
|
||||
// and re-creating each container. The desired_state is not changed.
|
||||
// RestartService restarts all components of a service, or a single component if specified,
|
||||
// by stopping, removing, and re-creating each container. The desired_state is not changed.
|
||||
func (a *Agent) RestartService(ctx context.Context, req *mcpv1.RestartServiceRequest) (*mcpv1.RestartServiceResponse, error) {
|
||||
a.Logger.Info("RestartService", "service", req.GetName())
|
||||
a.Logger.Info("RestartService", "service", req.GetName(), "component", req.GetComponent())
|
||||
|
||||
if req.GetName() == "" {
|
||||
return nil, status.Error(codes.InvalidArgument, "service name is required")
|
||||
@@ -96,6 +110,13 @@ func (a *Agent) RestartService(ctx context.Context, req *mcpv1.RestartServiceReq
|
||||
return nil, status.Errorf(codes.Internal, "list components: %v", err)
|
||||
}
|
||||
|
||||
if target := req.GetComponent(); target != "" {
|
||||
components, err = filterComponents(components, req.GetName(), target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var results []*mcpv1.ComponentResult
|
||||
for _, c := range components {
|
||||
r := restartComponent(ctx, a, req.GetName(), &c)
|
||||
@@ -167,6 +188,16 @@ func componentToSpec(service string, c *registry.Component) runtime.ContainerSpe
|
||||
}
|
||||
}
|
||||
|
||||
// filterComponents returns only the component matching target, or an error if not found.
|
||||
func filterComponents(components []registry.Component, service, target string) ([]registry.Component, error) {
|
||||
for _, c := range components {
|
||||
if c.Name == target {
|
||||
return []registry.Component{c}, nil
|
||||
}
|
||||
}
|
||||
return nil, status.Errorf(codes.NotFound, "component %q not found in service %q", target, service)
|
||||
}
|
||||
|
||||
// componentExists checks whether a component already exists in the registry.
|
||||
func componentExists(db *sql.DB, service, name string) bool {
|
||||
_, err := registry.GetComponent(db, service, name)
|
||||
|
||||
Reference in New Issue
Block a user