Signed-off-by: John Howard <jhoward@microsoft.com>
| ... | ... |
@@ -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 |
|