diff --git a/top.go b/top.go index 59d63ad94bc..9521f287412 100644 --- a/top.go +++ b/top.go @@ -18,6 +18,7 @@ package main import ( "bytes" + "context" "fmt" "os/exec" "regexp" @@ -26,6 +27,7 @@ import ( "text/tabwriter" "github.com/containerd/containerd" + "github.com/containerd/nerdctl/pkg/idutil/containerwalker" "github.com/pkg/errors" "github.com/urfave/cli/v2" ) @@ -53,10 +55,34 @@ var topCommand = &cli.Command{ } func topAction(clicontext *cli.Context) error { + if clicontext.NArg() < 1 { return errors.Errorf("requires at least 1 argument") } - return containerTop(clicontext, clicontext.Args().First(), strings.Join(clicontext.Args().Tail(), " ")) + + client, ctx, cancel, err := newClient(clicontext) + if err != nil { + return err + } + defer cancel() + + walker := &containerwalker.ContainerWalker{ + Client: client, + OnFound: func(ctx context.Context, found containerwalker.Found) error { + if err := containerTop(ctx, clicontext, client, found.Container.ID(), strings.Join(clicontext.Args().Tail(), " ")); err != nil { + return err + } + return nil + }, + } + + n, err := walker.Walk(ctx, clicontext.Args().First()) + if err != nil { + return err + } else if n == 0 { + return errors.Errorf("no such container %s", clicontext.Args().First()) + } + return nil } //function from moby/moby/daemon/top_unix.go @@ -185,7 +211,7 @@ func parsePSOutput(output []byte, procs []uint32) (*ContainerTopOKBody, error) { // "-ef" if no args are given. An error is returned if the container // is not found, or is not running, or if there are any problems // running ps, or parsing the output. -func containerTop(clicontext *cli.Context, name string, psArgs string) error { +func containerTop(ctx context.Context, clicontext *cli.Context, client *containerd.Client, id string, psArgs string) error { if psArgs == "" { psArgs = "-ef" } @@ -194,13 +220,7 @@ func containerTop(clicontext *cli.Context, name string, psArgs string) error { return err } - client, ctx, cancel, err := newClient(clicontext) - if err != nil { - return err - } - defer cancel() - - container, err := client.LoadContainer(ctx, name) + container, err := client.LoadContainer(ctx, id) if err != nil { return err } diff --git a/top_test.go b/top_test.go new file mode 100644 index 00000000000..6fd01daf373 --- /dev/null +++ b/top_test.go @@ -0,0 +1,36 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package main + +import ( + "testing" + + "github.com/containerd/nerdctl/pkg/testutil" +) + +func TestTop(t *testing.T) { + const ( + testContainerName = "nerdctl-test-top" + ) + + base := testutil.NewBase(t) + defer base.Cmd("rm", "-f", testContainerName).Run() + + base.Cmd("run", "-d", "--name", testContainerName, testutil.AlpineImage, "sleep", "4").AssertOK() + base.Cmd("top", testContainerName, "-o", "pid,user,cmd").AssertOK() + +}