From 52237787fa82c12b018d71b1e00f28492be35dad Mon Sep 17 00:00:00 2001 From: John Howard Date: Sun, 20 Mar 2016 15:58:23 -0700 Subject: [PATCH] Windows: Minimal docker top implementation Signed-off-by: John Howard --- daemon/top_windows.go | 28 +++++++++++++++--- libcontainerd/client_linux.go | 6 ++++ libcontainerd/client_windows.go | 50 ++++++++++++++++++++++++++++++-- libcontainerd/process_windows.go | 5 +++- libcontainerd/types.go | 1 + libcontainerd/types_linux.go | 3 ++ libcontainerd/types_windows.go | 6 ++++ 7 files changed, 92 insertions(+), 7 deletions(-) diff --git a/daemon/top_windows.go b/daemon/top_windows.go index 8b4fb2c6f0..ea79ac86ac 100644 --- a/daemon/top_windows.go +++ b/daemon/top_windows.go @@ -1,12 +1,32 @@ package daemon import ( - "fmt" + "errors" + "strconv" "github.com/docker/engine-api/types" ) -// ContainerTop is not supported on Windows and returns an error. -func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.ContainerProcessList, error) { - return nil, fmt.Errorf("Top is not supported on Windows") +// ContainerTop is a minimal implementation on Windows currently. +// TODO Windows: This needs more work, but needs platform API support. +// All we can currently return (particularly in the case of Hyper-V containers) +// is a PID and the command. +func (daemon *Daemon) ContainerTop(containerID string, psArgs string) (*types.ContainerProcessList, error) { + + // It's really not an equivalent to linux 'ps' on Windows + if psArgs != "" { + return nil, errors.New("Windows does not support arguments to top") + } + + s, err := daemon.containerd.Summary(containerID) + if err != nil { + return nil, err + } + + procList := &types.ContainerProcessList{} + + for _, v := range s { + procList.Titles = append(procList.Titles, strconv.Itoa(int(v.Pid))+" "+v.Command) + } + return procList, nil } diff --git a/libcontainerd/client_linux.go b/libcontainerd/client_linux.go index 189345b286..9fd3d60175 100644 --- a/libcontainerd/client_linux.go +++ b/libcontainerd/client_linux.go @@ -299,6 +299,12 @@ func (clnt *client) GetPidsForContainer(containerID string) ([]int, error) { return pids, nil } +// Summary returns a summary of the processes running in a container. +// This is a no-op on Linux. +func (clnt *client) Summary(containerID string) ([]Summary, error) { + return nil, nil +} + func (clnt *client) getContainerdContainer(containerID string) (*containerd.Container, error) { resp, err := clnt.remote.apiClient.State(context.Background(), &containerd.StateRequest{Id: containerID}) if err != nil { diff --git a/libcontainerd/client_windows.go b/libcontainerd/client_windows.go index 020bc894c1..50cb4168f7 100644 --- a/libcontainerd/client_windows.go +++ b/libcontainerd/client_windows.go @@ -303,6 +303,7 @@ func (clnt *client) Create(containerID string, spec Spec, options ...CreateOptio client: clnt, friendlyName: InitFriendlyName, }, + commandLine: strings.Join(spec.Process.Args, " "), }, processes: make(map[string]*process), }, @@ -396,6 +397,7 @@ func (clnt *client) AddProcess(containerID, processFriendlyName string, procToAd client: clnt, systemPid: pid, }, + commandLine: createProcessParms.CommandLine, } // Make sure the lock is not held while calling back into the daemon @@ -508,9 +510,53 @@ func (clnt *client) Restore(containerID string, unusedOnWindows ...CreateOption) }) } -// GetPidsForContainers is not implemented on Windows. +// GetPidsForContainer returns a list of process IDs running in a container. +// Although implemented, this is not used in Windows. func (clnt *client) GetPidsForContainer(containerID string) ([]int, error) { - return nil, errors.New("GetPidsForContainer: GetPidsForContainer() not implemented") + var pids []int + clnt.lock(containerID) + defer clnt.unlock(containerID) + cont, err := clnt.getContainer(containerID) + if err != nil { + return nil, err + } + + // Add the first process + pids = append(pids, int(cont.containerCommon.systemPid)) + // And add all the exec'd processes + for _, p := range cont.processes { + pids = append(pids, int(p.processCommon.systemPid)) + } + return pids, nil +} + +// Summary returns a summary of the processes running in a container. +// This is present in Windows to support docker top. In linux, the +// engine shells out to ps to get process information. On Windows, as +// the containers could be Hyper-V containers, they would not be +// visible on the container host. However, libcontainerd does have +// that information. +func (clnt *client) Summary(containerID string) ([]Summary, error) { + var s []Summary + clnt.lock(containerID) + defer clnt.unlock(containerID) + cont, err := clnt.getContainer(containerID) + if err != nil { + return nil, err + } + + // Add the first process + s = append(s, Summary{ + Pid: cont.containerCommon.systemPid, + Command: cont.ociSpec.Process.Args[0]}) + // And add all the exec'd processes + for _, p := range cont.processes { + s = append(s, Summary{ + Pid: p.processCommon.systemPid, + Command: p.commandLine}) + } + return s, nil + } // UpdateResources updates resources for a running container. diff --git a/libcontainerd/process_windows.go b/libcontainerd/process_windows.go index bb142243a3..0371aec91f 100644 --- a/libcontainerd/process_windows.go +++ b/libcontainerd/process_windows.go @@ -8,7 +8,10 @@ import ( type process struct { processCommon - // Platform specific fields are below here. There are none presently on Windows. + // Platform specific fields are below here. + + // commandLine is to support returning summary information for docker top + commandLine string } func openReaderFromPipe(p io.ReadCloser) io.Reader { diff --git a/libcontainerd/types.go b/libcontainerd/types.go index 85b9a30218..bb82fe407c 100644 --- a/libcontainerd/types.go +++ b/libcontainerd/types.go @@ -42,6 +42,7 @@ type Client interface { Restore(containerID string, options ...CreateOption) error Stats(containerID string) (*Stats, error) GetPidsForContainer(containerID string) ([]int, error) + Summary(containerID string) ([]Summary, error) UpdateResources(containerID string, resources Resources) error } diff --git a/libcontainerd/types_linux.go b/libcontainerd/types_linux.go index 7cbfe79d6f..bee12d9122 100644 --- a/libcontainerd/types_linux.go +++ b/libcontainerd/types_linux.go @@ -36,6 +36,9 @@ type Process struct { // Stats contains a stats properties from containerd. type Stats containerd.StatsResponse +// Summary container a container summary from containerd +type Summary struct{} + // User specifies linux specific user and group information for the container's // main process. type User specs.User diff --git a/libcontainerd/types_windows.go b/libcontainerd/types_windows.go index 69cfb27d07..2a915ff1e2 100644 --- a/libcontainerd/types_windows.go +++ b/libcontainerd/types_windows.go @@ -11,6 +11,12 @@ type Process windowsoci.Process // User specifies user information for the containers main process. type User windowsoci.User +// Summary container a container summary from containerd +type Summary struct { + Pid uint32 + Command string +} + // Stats contains a stats properties from containerd. type Stats struct{}