Skip to content

Commit

Permalink
chore: print all available logs containers in logs command completions
Browse files Browse the repository at this point in the history
This is a small quality of life improvement that allows `logs` subcommand to suggest all available logs.

Signed-off-by: Dmitriy Matrenichev <dmitry.matrenichev@siderolabs.com>
  • Loading branch information
DmitriyMV committed Mar 11, 2024
1 parent e89d755 commit 32e0877
Show file tree
Hide file tree
Showing 15 changed files with 2,612 additions and 1,937 deletions.
11 changes: 11 additions & 0 deletions api/machine/machine.proto
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ service MachineService {
rpc DiskUsage(DiskUsageRequest) returns (stream DiskUsageInfo);
rpc LoadAvg(google.protobuf.Empty) returns (LoadAvgResponse);
rpc Logs(LogsRequest) returns (stream common.Data);
rpc LogsContainers(google.protobuf.Empty) returns (LogsContainersResponse);
rpc Memory(google.protobuf.Empty) returns (MemoryResponse);
rpc Mounts(google.protobuf.Empty) returns (MountsResponse);
rpc NetworkDeviceStats(google.protobuf.Empty) returns (NetworkDeviceStatsResponse);
Expand Down Expand Up @@ -570,6 +571,16 @@ message ReadRequest {
string path = 1;
}

// LogsContainer desribes all avalaible registered log containers.
message LogsContainer {
common.Metadata metadata = 1;
repeated string ids = 2;
}

message LogsContainersResponse {
repeated LogsContainer messages = 1;
}

// rpc rollback
message RollbackRequest {}

Expand Down
27 changes: 25 additions & 2 deletions cmd/talosctl/cmd/talos/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ import (
criconstants "github.com/containerd/containerd/pkg/cri/constants"
"github.com/siderolabs/gen/xslices"
"github.com/spf13/cobra"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/peer"

"github.com/siderolabs/talos/pkg/cli"
"github.com/siderolabs/talos/pkg/machinery/api/common"
Expand All @@ -29,7 +31,6 @@ var (
tailLines int32
)

// logsCmd represents the logs command.
var logsCmd = &cobra.Command{
Use: "logs <service name>",
Short: "Retrieve logs for a service",
Expand All @@ -44,7 +45,7 @@ var logsCmd = &cobra.Command{
return getContainersFromNode(kubernetes), cobra.ShellCompDirectiveNoFileComp
}

return mergeSuggestions(getServiceFromNode(), getContainersFromNode(kubernetes)), cobra.ShellCompDirectiveNoFileComp
return mergeSuggestions(getServiceFromNode(), getContainersFromNode(kubernetes), getLogsContainers()), cobra.ShellCompDirectiveNoFileComp
},
RunE: func(cmd *cobra.Command, args []string) error {
return WithClient(func(ctx context.Context, c *client.Client) error {
Expand Down Expand Up @@ -206,6 +207,28 @@ func (slicer *lineSlicer) run(stream machine.MachineService_LogsClient) {
}
}

func getLogsContainers() []string {
var result []string

//nolint:errcheck
WithClient(
func(ctx context.Context, c *client.Client) error {
var remotePeer peer.Peer

resp, err := c.LogsContainers(ctx, grpc.Peer(&remotePeer))
if err != nil {
return err
}

result = xslices.FlatMap(resp.Messages, func(lc *machine.LogsContainer) []string { return lc.Ids })

return nil
},
)

return result
}

func init() {
logsCmd.Flags().BoolVarP(&kubernetes, "kubernetes", "k", false, "use the k8s.io containerd namespace")
logsCmd.Flags().BoolVarP(&follow, "follow", "f", false, "specify if the logs should be streamed")
Expand Down
20 changes: 4 additions & 16 deletions cmd/talosctl/cmd/talos/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"fmt"
"io"
"slices"
"sort"
"strings"

criconstants "github.com/containerd/containerd/pkg/cri/constants"
Expand Down Expand Up @@ -222,23 +221,12 @@ func getContainersFromNode(kubernetes bool) []string {
return containerIDs
}

func mergeSuggestions(a, b []string) []string {
merged := append(slices.Clone(a), b...)
func mergeSuggestions(s ...[]string) []string {
merged := slices.Concat(s...)

sort.Strings(merged)
slices.Sort(merged)

n := 1

for i := 1; i < len(merged); i++ {
if merged[i] != merged[i-1] {
merged[n] = merged[i]
n++
}
}

merged = merged[:n]

return merged
return slices.Compact(merged)
}

func relativeTo(fullPath string, filter string) bool {
Expand Down
6 changes: 3 additions & 3 deletions cmd/talosctl/pkg/talos/action/tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"fmt"
"io"
"os"
"sort"
"slices"
"strings"
"time"

Expand Down Expand Up @@ -229,7 +229,7 @@ func (a *Tracker) Run() error {
})

if len(failedNodes) > 0 {
sort.Strings(failedNodes)
slices.Sort(failedNodes)

fmt.Fprintf(os.Stderr, "console logs for nodes %q:\n", failedNodes)

Expand Down Expand Up @@ -288,7 +288,7 @@ func (a *Tracker) processNodeUpdate(update nodeUpdate) reporter.Update {
}

nodes := maps.Keys(a.nodeToLatestStatusUpdate)
sort.Strings(nodes)
slices.Sort(nodes)

messages := make([]string, 0, len(nodes)+1)
messages = append(messages, fmt.Sprintf("watching nodes: %v", nodes))
Expand Down
11 changes: 11 additions & 0 deletions internal/app/machined/internal/server/v1alpha1/v1alpha1_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -1223,6 +1223,17 @@ func (s *Server) Logs(req *machine.LogsRequest, l machine.MachineService_LogsSer
return nil
}

// LogsContainers provide a list of registered log containers.
func (s *Server) LogsContainers(context.Context, *emptypb.Empty) (*machine.LogsContainersResponse, error) {
return &machine.LogsContainersResponse{
Messages: []*machine.LogsContainer{
{
Ids: s.Controller.Runtime().Logging().RegisteredLogs(),
},
},
}, nil
}

func k8slogs(ctx context.Context, req *machine.LogsRequest) (chunker.Chunker, io.Closer, error) {
inspector, err := getContainerInspector(ctx, req.Namespace, req.Driver)
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions internal/app/machined/pkg/runtime/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ type LoggingManager interface {
//
// SetSenders should be thread-safe.
SetSenders(senders []LogSender) []LogSender

// RegisteredLogs returns a list of registered logs containers.
RegisteredLogs() []string
}

// LogOptions for LogHandler.Reader.
Expand Down
13 changes: 13 additions & 0 deletions internal/app/machined/pkg/runtime/logging/circular.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,19 @@ func (manager *CircularBufferLoggingManager) getBuffer(id string, create bool) (
return buf.(*circular.Buffer), nil
}

// RegisteredLogs implements runtime.LoggingManager interface.
func (manager *CircularBufferLoggingManager) RegisteredLogs() []string {
var result []string

manager.buffers.Range(func(key, val any) bool {
result = append(result, key.(string))

return true
})

return result
}

type circularHandler struct {
manager *CircularBufferLoggingManager
id string
Expand Down
25 changes: 24 additions & 1 deletion internal/app/machined/pkg/runtime/logging/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"path/filepath"
"strings"

"github.com/siderolabs/gen/containers"
"github.com/siderolabs/go-tail"

"github.com/siderolabs/talos/internal/app/machined/pkg/runtime"
Expand All @@ -22,6 +23,8 @@ import (
// FileLoggingManager implements simple logging to files.
type FileLoggingManager struct {
logDirectory string

registeredLogs containers.ConcurrentMap[string, struct{}]
}

// NewFileLoggingManager initializes new FileLoggingManager.
Expand All @@ -36,6 +39,7 @@ func (manager *FileLoggingManager) ServiceLog(id string) runtime.LogHandler {
return &fileLogHandler{
logDirectory: manager.logDirectory,
id: id,
manager: manager,
}
}

Expand All @@ -44,11 +48,23 @@ func (manager *FileLoggingManager) SetSenders([]runtime.LogSender) []runtime.Log
return nil
}

// RegisteredLogs implements runtime.LoggingManager interface.
func (manager *FileLoggingManager) RegisteredLogs() []string {
var result []string

manager.registeredLogs.ForEach(func(key string, _ struct{}) {
result = append(result, key)
})

return result
}

type fileLogHandler struct {
path string

logDirectory string
id string
manager *FileLoggingManager
}

func (handler *fileLogHandler) buildPath() error {
Expand All @@ -67,7 +83,14 @@ func (handler *fileLogHandler) Writer() (io.WriteCloser, error) {
return nil, err
}

return os.OpenFile(handler.path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o666)
result, err := os.OpenFile(handler.path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0o666)
if err != nil {
return nil, err
}

handler.manager.registeredLogs.GetOrCreate(handler.id, struct{}{})

return result, nil
}

// Reader implements runtime.LogHandler interface.
Expand Down
5 changes: 5 additions & 0 deletions internal/app/machined/pkg/runtime/logging/null.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ func (*NullLoggingManager) SetSenders([]runtime.LogSender) []runtime.LogSender {
return nil
}

// RegisteredLogs implements runtime.LoggingManager interface (by doing nothing).
func (*NullLoggingManager) RegisteredLogs() []string {
return nil
}

type nullLogHandler struct{}

func (*nullLogHandler) Writer() (io.WriteCloser, error) {
Expand Down
1 change: 1 addition & 0 deletions internal/app/machined/pkg/system/services/machined.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ var rules = map[string]role.Set{
"/machine.MachineService/List": role.MakeSet(role.Admin, role.Operator, role.Reader),
"/machine.MachineService/LoadAvg": role.MakeSet(role.Admin, role.Operator, role.Reader),
"/machine.MachineService/Logs": role.MakeSet(role.Admin, role.Operator, role.Reader),
"/machine.MachineService/LogsContainers": role.MakeSet(role.Admin, role.Operator, role.Reader),
"/machine.MachineService/Memory": role.MakeSet(role.Admin, role.Operator, role.Reader),
"/machine.MachineService/MetaWrite": role.MakeSet(role.Admin),
"/machine.MachineService/MetaDelete": role.MakeSet(role.Admin),
Expand Down
Loading

0 comments on commit 32e0877

Please sign in to comment.