Browse code

Windows: Minimal docker top implementation

Signed-off-by: John Howard <jhoward@microsoft.com>

John Howard authored on 2016/03/21 07:58:23
Showing 7 changed files
... ...
@@ -1,12 +1,32 @@
1 1
 package daemon
2 2
 
3 3
 import (
4
-	"fmt"
4
+	"errors"
5
+	"strconv"
5 6
 
6 7
 	"github.com/docker/engine-api/types"
7 8
 )
8 9
 
9
-// ContainerTop is not supported on Windows and returns an error.
10
-func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.ContainerProcessList, error) {
11
-	return nil, fmt.Errorf("Top is not supported on Windows")
10
+// ContainerTop is a minimal implementation on Windows currently.
11
+// TODO Windows: This needs more work, but needs platform API support.
12
+// All we can currently return (particularly in the case of Hyper-V containers)
13
+// is a PID and the command.
14
+func (daemon *Daemon) ContainerTop(containerID string, psArgs string) (*types.ContainerProcessList, error) {
15
+
16
+	// It's really not an equivalent to linux 'ps' on Windows
17
+	if psArgs != "" {
18
+		return nil, errors.New("Windows does not support arguments to top")
19
+	}
20
+
21
+	s, err := daemon.containerd.Summary(containerID)
22
+	if err != nil {
23
+		return nil, err
24
+	}
25
+
26
+	procList := &types.ContainerProcessList{}
27
+
28
+	for _, v := range s {
29
+		procList.Titles = append(procList.Titles, strconv.Itoa(int(v.Pid))+" "+v.Command)
30
+	}
31
+	return procList, nil
12 32
 }
... ...
@@ -299,6 +299,12 @@ func (clnt *client) GetPidsForContainer(containerID string) ([]int, error) {
299 299
 	return pids, nil
300 300
 }
301 301
 
302
+// Summary returns a summary of the processes running in a container.
303
+// This is a no-op on Linux.
304
+func (clnt *client) Summary(containerID string) ([]Summary, error) {
305
+	return nil, nil
306
+}
307
+
302 308
 func (clnt *client) getContainerdContainer(containerID string) (*containerd.Container, error) {
303 309
 	resp, err := clnt.remote.apiClient.State(context.Background(), &containerd.StateRequest{Id: containerID})
304 310
 	if err != nil {
... ...
@@ -303,6 +303,7 @@ func (clnt *client) Create(containerID string, spec Spec, options ...CreateOptio
303 303
 					client:       clnt,
304 304
 					friendlyName: InitFriendlyName,
305 305
 				},
306
+				commandLine: strings.Join(spec.Process.Args, " "),
306 307
 			},
307 308
 			processes: make(map[string]*process),
308 309
 		},
... ...
@@ -396,6 +397,7 @@ func (clnt *client) AddProcess(containerID, processFriendlyName string, procToAd
396 396
 				client:       clnt,
397 397
 				systemPid:    pid,
398 398
 			},
399
+			commandLine: createProcessParms.CommandLine,
399 400
 		}
400 401
 
401 402
 	// 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)
508 508
 	})
509 509
 }
510 510
 
511
-// GetPidsForContainers is not implemented on Windows.
511
+// GetPidsForContainer returns a list of process IDs running in a container.
512
+// Although implemented, this is not used in Windows.
512 513
 func (clnt *client) GetPidsForContainer(containerID string) ([]int, error) {
513
-	return nil, errors.New("GetPidsForContainer: GetPidsForContainer() not implemented")
514
+	var pids []int
515
+	clnt.lock(containerID)
516
+	defer clnt.unlock(containerID)
517
+	cont, err := clnt.getContainer(containerID)
518
+	if err != nil {
519
+		return nil, err
520
+	}
521
+
522
+	// Add the first process
523
+	pids = append(pids, int(cont.containerCommon.systemPid))
524
+	// And add all the exec'd processes
525
+	for _, p := range cont.processes {
526
+		pids = append(pids, int(p.processCommon.systemPid))
527
+	}
528
+	return pids, nil
529
+}
530
+
531
+// Summary returns a summary of the processes running in a container.
532
+// This is present in Windows to support docker top. In linux, the
533
+// engine shells out to ps to get process information. On Windows, as
534
+// the containers could be Hyper-V containers, they would not be
535
+// visible on the container host. However, libcontainerd does have
536
+// that information.
537
+func (clnt *client) Summary(containerID string) ([]Summary, error) {
538
+	var s []Summary
539
+	clnt.lock(containerID)
540
+	defer clnt.unlock(containerID)
541
+	cont, err := clnt.getContainer(containerID)
542
+	if err != nil {
543
+		return nil, err
544
+	}
545
+
546
+	// Add the first process
547
+	s = append(s, Summary{
548
+		Pid:     cont.containerCommon.systemPid,
549
+		Command: cont.ociSpec.Process.Args[0]})
550
+	// And add all the exec'd processes
551
+	for _, p := range cont.processes {
552
+		s = append(s, Summary{
553
+			Pid:     p.processCommon.systemPid,
554
+			Command: p.commandLine})
555
+	}
556
+	return s, nil
557
+
514 558
 }
515 559
 
516 560
 // UpdateResources updates resources for a running container.
... ...
@@ -8,7 +8,10 @@ import (
8 8
 type process struct {
9 9
 	processCommon
10 10
 
11
-	// Platform specific fields are below here. There are none presently on Windows.
11
+	// Platform specific fields are below here.
12
+
13
+	// commandLine is to support returning summary information for docker top
14
+	commandLine string
12 15
 }
13 16
 
14 17
 func openReaderFromPipe(p io.ReadCloser) io.Reader {
... ...
@@ -42,6 +42,7 @@ type Client interface {
42 42
 	Restore(containerID string, options ...CreateOption) error
43 43
 	Stats(containerID string) (*Stats, error)
44 44
 	GetPidsForContainer(containerID string) ([]int, error)
45
+	Summary(containerID string) ([]Summary, error)
45 46
 	UpdateResources(containerID string, resources Resources) error
46 47
 }
47 48
 
... ...
@@ -36,6 +36,9 @@ type Process struct {
36 36
 // Stats contains a stats properties from containerd.
37 37
 type Stats containerd.StatsResponse
38 38
 
39
+// Summary container a container summary from containerd
40
+type Summary struct{}
41
+
39 42
 // User specifies linux specific user and group information for the container's
40 43
 // main process.
41 44
 type User specs.User
... ...
@@ -11,6 +11,12 @@ type Process windowsoci.Process
11 11
 // User specifies user information for the containers main process.
12 12
 type User windowsoci.User
13 13
 
14
+// Summary container a container summary from containerd
15
+type Summary struct {
16
+	Pid     uint32
17
+	Command string
18
+}
19
+
14 20
 // Stats contains a stats properties from containerd.
15 21
 type Stats struct{}
16 22