feat: support filtering service logs by machine (-m/--machine)

This commit is contained in:
Pasha Sviderski
2025-12-03 15:01:23 +10:00
parent bf65fbaca5
commit 1e6aaf451e
5 changed files with 62 additions and 53 deletions
-12
View File
@@ -149,18 +149,6 @@ func (cli *Client) PushImage(ctx context.Context, image string, opts PushImageOp
return fmt.Errorf("list machines: %w", err)
}
// Check if all specified machines were found.
if len(machineMembers) != len(opts.Machines) {
var notFound []string
for _, nameOrID := range opts.Machines {
if machineMembers.FindByNameOrID(nameOrID) == nil {
notFound = append(notFound, nameOrID)
}
}
return fmt.Errorf("machines not found: %s", strings.Join(notFound, ", "))
}
for _, mm := range machineMembers {
machines = append(machines, mm.Machine)
}
+15 -3
View File
@@ -2,6 +2,7 @@ package client
import (
"context"
"errors"
"fmt"
"io"
@@ -27,16 +28,23 @@ func (cli *Client) ServiceLogs(
return svc, nil, fmt.Errorf("no containers found for service: %s", serviceNameOrID)
}
machines, err := cli.ListMachines(ctx, nil)
machines, err := cli.ListMachines(ctx, &api.MachineFilter{
NamesOrIDs: opts.Machines,
})
if err != nil {
return svc, nil, fmt.Errorf("list machines: %w", err)
}
ctrStreams := make([]<-chan api.ServiceLogEntry, 0, len(svc.Containers))
for _, ctr := range svc.Containers {
// Try to get machine name for ServiceLogEntry metadata and friendlier error message.
machineName := ctr.MachineID
// Skip containers not running on the specified machines.
m := machines.FindByNameOrID(ctr.MachineID)
if len(opts.Machines) > 0 && m == nil {
continue
}
// Machine name for ServiceLogEntry metadata and friendlier error message.
machineName := ctr.MachineID
if m != nil {
machineName = m.Machine.Name
}
@@ -59,6 +67,10 @@ func (cli *Client) ServiceLogs(
ctrStreams = append(ctrStreams, enrichedStream)
}
if len(ctrStreams) == 0 {
return svc, nil, errors.New("no service containers found on the specified machine(s)")
}
// Use the log merger to combine streams from all containers in chronological order.
merger := NewLogMerger(ctrStreams, DefaultLogMergerOptions)
mergedStream := merger.Stream()
+31 -28
View File
@@ -2,7 +2,8 @@ package client
import (
"context"
"slices"
"fmt"
"strings"
"github.com/psviderski/uncloud/internal/machine/api/pb"
"github.com/psviderski/uncloud/pkg/api"
@@ -32,42 +33,44 @@ func (cli *Client) ListMachines(ctx context.Context, filter *api.MachineFilter)
if err != nil {
return nil, err
}
machines := api.MachineMembersList(resp.Machines)
machines := resp.Machines
if filter == nil {
return machines, nil
}
if filter != nil {
var matchedMachines api.MachineMembersList
for _, m := range machines {
if MachineMatchesFilter(m, filter) {
matchedMachines = append(matchedMachines, m)
// Apply the filter.
if len(filter.NamesOrIDs) > 0 {
var matched api.MachineMembersList
var notFound []string
for _, nameOrID := range filter.NamesOrIDs {
if m := machines.FindByNameOrID(nameOrID); m != nil {
matched = append(matched, m)
} else {
notFound = append(notFound, nameOrID)
}
}
machines = matchedMachines
machines = matched
if len(notFound) > 0 {
return nil, fmt.Errorf("machines not found: %s", strings.Join(notFound, ", "))
}
}
if filter.Available {
var available api.MachineMembersList
for _, m := range machines {
if m.State != pb.MachineMember_DOWN {
available = append(available, m)
}
}
machines = available
}
return machines, nil
}
func MachineMatchesFilter(machine *pb.MachineMember, filter *api.MachineFilter) bool {
if filter == nil {
return true
}
if filter.Available && machine.State == pb.MachineMember_DOWN {
return false
}
if len(filter.NamesOrIDs) > 0 {
if !slices.ContainsFunc(filter.NamesOrIDs, func(nameOrID string) bool {
return machine.Machine.Id == nameOrID || machine.Machine.Name == nameOrID
}) {
return false
}
}
return true
}
// UpdateMachine updates machine configuration in the cluster.
func (cli *Client) UpdateMachine(ctx context.Context, req *pb.UpdateMachineRequest) (*pb.MachineInfo, error) {
resp, err := cli.ClusterClient.UpdateMachine(ctx, req)