Browse Source

Windows: Minimal docker top implementation

Signed-off-by: John Howard <jhoward@microsoft.com>
John Howard 9 years ago
parent
commit
52237787fa

+ 24 - 4
daemon/top_windows.go

@@ -1,12 +1,32 @@
 package daemon
 package daemon
 
 
 import (
 import (
-	"fmt"
+	"errors"
+	"strconv"
 
 
 	"github.com/docker/engine-api/types"
 	"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
 }
 }

+ 6 - 0
libcontainerd/client_linux.go

@@ -299,6 +299,12 @@ func (clnt *client) GetPidsForContainer(containerID string) ([]int, error) {
 	return pids, nil
 	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) {
 func (clnt *client) getContainerdContainer(containerID string) (*containerd.Container, error) {
 	resp, err := clnt.remote.apiClient.State(context.Background(), &containerd.StateRequest{Id: containerID})
 	resp, err := clnt.remote.apiClient.State(context.Background(), &containerd.StateRequest{Id: containerID})
 	if err != nil {
 	if err != nil {

+ 48 - 2
libcontainerd/client_windows.go

@@ -303,6 +303,7 @@ func (clnt *client) Create(containerID string, spec Spec, options ...CreateOptio
 					client:       clnt,
 					client:       clnt,
 					friendlyName: InitFriendlyName,
 					friendlyName: InitFriendlyName,
 				},
 				},
+				commandLine: strings.Join(spec.Process.Args, " "),
 			},
 			},
 			processes: make(map[string]*process),
 			processes: make(map[string]*process),
 		},
 		},
@@ -396,6 +397,7 @@ func (clnt *client) AddProcess(containerID, processFriendlyName string, procToAd
 				client:       clnt,
 				client:       clnt,
 				systemPid:    pid,
 				systemPid:    pid,
 			},
 			},
+			commandLine: createProcessParms.CommandLine,
 		}
 		}
 
 
 	// Make sure the lock is not held while calling back into the daemon
 	// 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) {
 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.
 // UpdateResources updates resources for a running container.

+ 4 - 1
libcontainerd/process_windows.go

@@ -8,7 +8,10 @@ import (
 type process struct {
 type process struct {
 	processCommon
 	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 {
 func openReaderFromPipe(p io.ReadCloser) io.Reader {

+ 1 - 0
libcontainerd/types.go

@@ -42,6 +42,7 @@ type Client interface {
 	Restore(containerID string, options ...CreateOption) error
 	Restore(containerID string, options ...CreateOption) error
 	Stats(containerID string) (*Stats, error)
 	Stats(containerID string) (*Stats, error)
 	GetPidsForContainer(containerID string) ([]int, error)
 	GetPidsForContainer(containerID string) ([]int, error)
+	Summary(containerID string) ([]Summary, error)
 	UpdateResources(containerID string, resources Resources) error
 	UpdateResources(containerID string, resources Resources) error
 }
 }
 
 

+ 3 - 0
libcontainerd/types_linux.go

@@ -36,6 +36,9 @@ type Process struct {
 // Stats contains a stats properties from containerd.
 // Stats contains a stats properties from containerd.
 type Stats containerd.StatsResponse
 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
 // User specifies linux specific user and group information for the container's
 // main process.
 // main process.
 type User specs.User
 type User specs.User

+ 6 - 0
libcontainerd/types_windows.go

@@ -11,6 +11,12 @@ type Process windowsoci.Process
 // User specifies user information for the containers main process.
 // User specifies user information for the containers main process.
 type User windowsoci.User
 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.
 // Stats contains a stats properties from containerd.
 type Stats struct{}
 type Stats struct{}