From 375a2797850b65926700f018af5a33d30c7d8edc Mon Sep 17 00:00:00 2001 From: Dominik Menke Date: Tue, 17 Dec 2024 11:00:07 +0100 Subject: [PATCH] top: expose container labels Signed-off-by: Dominik Menke --- cmd/compose/top.go | 13 +++- cmd/compose/top_test.go | 135 +++++++++++++++++++++++----------------- pkg/api/api.go | 1 + pkg/compose/top.go | 1 + 4 files changed, 90 insertions(+), 60 deletions(-) diff --git a/cmd/compose/top.go b/cmd/compose/top.go index 2ec318bc0..14f9d0054 100644 --- a/cmd/compose/top.go +++ b/cmd/compose/top.go @@ -73,14 +73,23 @@ func runTop(ctx context.Context, dockerCli command.Cli, backend api.Service, opt func collectTop(containers []api.ContainerProcSummary) (topHeader, []topEntries) { // map column name to its header (should keep working if backend.Top returns // varying columns for different containers) - header := topHeader{"SERVICE": 0} + header := topHeader{"SERVICE": 0, "#": 1} // assume one process per container and grow if needed entries := make([]topEntries, 0, len(containers)) for _, container := range containers { for _, proc := range container.Processes { - entry := topEntries{"SERVICE": container.Name} + svc := container.Name + if tmp, ok := container.Labels[api.ServiceLabel]; ok { + svc = tmp + } + replica := "-" + if tmp, ok := container.Labels[api.ContainerNumberLabel]; ok { + replica = tmp + } + + entry := topEntries{"SERVICE": svc, "#": replica} for i, title := range container.Titles { if _, exists := header[title]; !exists { diff --git a/cmd/compose/top_test.go b/cmd/compose/top_test.go index 9a79ea148..cc7470f4d 100644 --- a/cmd/compose/top_test.go +++ b/cmd/compose/top_test.go @@ -39,7 +39,7 @@ var topTestCases = []struct { name: "noprocs", titles: []string{"UID", "PID", "PPID", "C", "STIME", "TTY", "TIME", "CMD"}, procs: [][]string{}, - header: topHeader{"SERVICE": 0}, + header: topHeader{"SERVICE": 0, "#": 1}, entries: []topEntries{}, output: "", }, @@ -49,18 +49,20 @@ var topTestCases = []struct { procs: [][]string{{"root", "1", "1", "0", "12:00", "?", "00:00:01", "/entrypoint"}}, header: topHeader{ "SERVICE": 0, - "UID": 1, - "PID": 2, - "PPID": 3, - "C": 4, - "STIME": 5, - "TTY": 6, - "TIME": 7, - "CMD": 8, + "#": 1, + "UID": 2, + "PID": 3, + "PPID": 4, + "C": 5, + "STIME": 6, + "TTY": 7, + "TIME": 8, + "CMD": 9, }, entries: []topEntries{ { "SERVICE": "simple", + "#": "1", "UID": "root", "PID": "1", "PPID": "1", @@ -72,8 +74,8 @@ var topTestCases = []struct { }, }, output: trim(` - SERVICE UID PID PPID C STIME TTY TIME CMD - simple root 1 1 0 12:00 ? 00:00:01 /entrypoint + SERVICE # UID PID PPID C STIME TTY TIME CMD + simple 1 root 1 1 0 12:00 ? 00:00:01 /entrypoint `), }, { @@ -82,17 +84,19 @@ var topTestCases = []struct { procs: [][]string{{"root", "1", "0", "12:00", "?", "00:00:02", "/entrypoint"}}, header: topHeader{ "SERVICE": 0, - "UID": 1, - "PID": 2, - "C": 3, - "STIME": 4, - "TTY": 5, - "TIME": 6, - "CMD": 7, + "#": 1, + "UID": 2, + "PID": 3, + "C": 4, + "STIME": 5, + "TTY": 6, + "TIME": 7, + "CMD": 8, }, entries: []topEntries{ { "SERVICE": "noppid", + "#": "1", "UID": "root", "PID": "1", "C": "0", @@ -103,8 +107,8 @@ var topTestCases = []struct { }, }, output: trim(` - SERVICE UID PID C STIME TTY TIME CMD - noppid root 1 0 12:00 ? 00:00:02 /entrypoint + SERVICE # UID PID C STIME TTY TIME CMD + noppid 1 root 1 0 12:00 ? 00:00:02 /entrypoint `), }, { @@ -113,19 +117,21 @@ var topTestCases = []struct { procs: [][]string{{"root", "1", "1", "1", "0", "12:00", "?", "00:00:03", "/entrypoint"}}, header: topHeader{ "SERVICE": 0, - "UID": 1, - "GID": 2, - "PID": 3, - "PPID": 4, - "C": 5, - "STIME": 6, - "TTY": 7, - "TIME": 8, - "CMD": 9, + "#": 1, + "UID": 2, + "GID": 3, + "PID": 4, + "PPID": 5, + "C": 6, + "STIME": 7, + "TTY": 8, + "TIME": 9, + "CMD": 10, }, entries: []topEntries{ { "SERVICE": "extra-hdr", + "#": "1", "UID": "root", "GID": "1", "PID": "1", @@ -138,8 +144,8 @@ var topTestCases = []struct { }, }, output: trim(` - SERVICE UID GID PID PPID C STIME TTY TIME CMD - extra-hdr root 1 1 1 0 12:00 ? 00:00:03 /entrypoint + SERVICE # UID GID PID PPID C STIME TTY TIME CMD + extra-hdr 1 root 1 1 1 0 12:00 ? 00:00:03 /entrypoint `), }, { @@ -151,18 +157,20 @@ var topTestCases = []struct { }, header: topHeader{ "SERVICE": 0, - "UID": 1, - "PID": 2, - "PPID": 3, - "C": 4, - "STIME": 5, - "TTY": 6, - "TIME": 7, - "CMD": 8, + "#": 1, + "UID": 2, + "PID": 3, + "PPID": 4, + "C": 5, + "STIME": 6, + "TTY": 7, + "TIME": 8, + "CMD": 9, }, entries: []topEntries{ { "SERVICE": "multiple", + "#": "1", "UID": "root", "PID": "1", "PPID": "1", @@ -174,6 +182,7 @@ var topTestCases = []struct { }, { "SERVICE": "multiple", + "#": "1", "UID": "root", "PID": "123", "PPID": "1", @@ -185,9 +194,9 @@ var topTestCases = []struct { }, }, output: trim(` - SERVICE UID PID PPID C STIME TTY TIME CMD - multiple root 1 1 0 12:00 ? 00:00:04 /entrypoint - multiple root 123 1 0 12:00 ? 00:00:42 sleep infinity + SERVICE # UID PID PPID C STIME TTY TIME CMD + multiple 1 root 1 1 0 12:00 ? 00:00:04 /entrypoint + multiple 1 root 123 1 0 12:00 ? 00:00:42 sleep infinity `), }, } @@ -201,9 +210,13 @@ func TestRunTopCore(t *testing.T) { for _, tc := range topTestCases { summary := api.ContainerProcSummary{ - Name: tc.name, + Name: "not used", Titles: tc.titles, Processes: tc.procs, + Labels: map[string]string{ + api.ServiceLabel: tc.name, + api.ContainerNumberLabel: "1", + }, } all = append(all, summary) @@ -224,19 +237,21 @@ func TestRunTopCore(t *testing.T) { header, entries := collectTop(all) assert.EqualValues(t, topHeader{ "SERVICE": 0, - "UID": 1, - "PID": 2, - "PPID": 3, - "C": 4, - "STIME": 5, - "TTY": 6, - "TIME": 7, - "CMD": 8, - "GID": 9, + "#": 1, + "UID": 2, + "PID": 3, + "PPID": 4, + "C": 5, + "STIME": 6, + "TTY": 7, + "TIME": 8, + "CMD": 9, + "GID": 10, }, header) assert.EqualValues(t, []topEntries{ { "SERVICE": "simple", + "#": "1", "UID": "root", "PID": "1", "PPID": "1", @@ -247,6 +262,7 @@ func TestRunTopCore(t *testing.T) { "CMD": "/entrypoint", }, { "SERVICE": "noppid", + "#": "1", "UID": "root", "PID": "1", "C": "0", @@ -256,6 +272,7 @@ func TestRunTopCore(t *testing.T) { "CMD": "/entrypoint", }, { "SERVICE": "extra-hdr", + "#": "1", "UID": "root", "GID": "1", "PID": "1", @@ -267,6 +284,7 @@ func TestRunTopCore(t *testing.T) { "CMD": "/entrypoint", }, { "SERVICE": "multiple", + "#": "1", "UID": "root", "PID": "1", "PPID": "1", @@ -277,6 +295,7 @@ func TestRunTopCore(t *testing.T) { "CMD": "/entrypoint", }, { "SERVICE": "multiple", + "#": "1", "UID": "root", "PID": "123", "PPID": "1", @@ -292,12 +311,12 @@ func TestRunTopCore(t *testing.T) { err := topPrint(&buf, header, entries) require.NoError(t, err) assert.Equal(t, trim(` - SERVICE UID PID PPID C STIME TTY TIME CMD GID - simple root 1 1 0 12:00 ? 00:00:01 /entrypoint - - noppid root 1 - 0 12:00 ? 00:00:02 /entrypoint - - extra-hdr root 1 1 0 12:00 ? 00:00:03 /entrypoint 1 - multiple root 1 1 0 12:00 ? 00:00:04 /entrypoint - - multiple root 123 1 0 12:00 ? 00:00:42 sleep infinity - + SERVICE # UID PID PPID C STIME TTY TIME CMD GID + simple 1 root 1 1 0 12:00 ? 00:00:01 /entrypoint - + noppid 1 root 1 - 0 12:00 ? 00:00:02 /entrypoint - + extra-hdr 1 root 1 1 0 12:00 ? 00:00:03 /entrypoint 1 + multiple 1 root 1 1 0 12:00 ? 00:00:04 /entrypoint - + multiple 1 root 123 1 0 12:00 ? 00:00:42 sleep infinity - `), buf.String()) }) diff --git a/pkg/api/api.go b/pkg/api/api.go index 4f59a30fb..99d1015d9 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -523,6 +523,7 @@ type ContainerProcSummary struct { Name string Processes [][]string Titles []string + Labels map[string]string } // ImageSummary holds container image description diff --git a/pkg/compose/top.go b/pkg/compose/top.go index b615870a1..7e136cca0 100644 --- a/pkg/compose/top.go +++ b/pkg/compose/top.go @@ -47,6 +47,7 @@ func (s *composeService) Top(ctx context.Context, projectName string, services [ Name: getCanonicalContainerName(ctr), Processes: topContent.Processes, Titles: topContent.Titles, + Labels: container.Labels, } return nil })