go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/resources/processes/dockertop.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package processes
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"strconv"
    10  
    11  	"go.mondoo.com/cnquery/providers/os/connection"
    12  	"go.mondoo.com/cnquery/providers/os/connection/shared"
    13  )
    14  
    15  type DockerTopManager struct {
    16  	conn shared.Connection
    17  }
    18  
    19  func (lpm *DockerTopManager) Name() string {
    20  	return "Docker Top Process Manager"
    21  }
    22  
    23  // List lists the processes running in a Docker container. Note that currently this function returns child
    24  // processes as well.
    25  func (lpm *DockerTopManager) List() ([]*OSProcess, error) {
    26  	dockerConn, ok := lpm.conn.(*connection.DockerContainerConnection)
    27  	if !ok {
    28  		return nil, fmt.Errorf("wrong transport type")
    29  	}
    30  
    31  	ctx := context.Background()
    32  	client := dockerConn.Client
    33  
    34  	// The Docker API uses ps underneath so we can provide any ps arguments we want here.
    35  	resp, err := client.ContainerTop(ctx, dockerConn.ContainerId(), []string{"-o", "pid,user,comm,s,command"})
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  
    40  	// The docker API returns a list of strings for each process with the following format:
    41  	// [0]: PID
    42  	// [1]: USER
    43  	// [2]: executable
    44  	// [3]: state
    45  	// [4]: command
    46  	var procs []*OSProcess
    47  	for _, p := range resp.Processes {
    48  		pid, err := strconv.Atoi(p[0])
    49  		if err != nil {
    50  			continue
    51  		}
    52  		procs = append(procs, &OSProcess{
    53  			Pid:          int64(pid), // This will be the PID inside the container
    54  			Executable:   p[2],
    55  			Command:      p[4],
    56  			State:        p[3],
    57  			SocketInodes: nil,
    58  		})
    59  	}
    60  
    61  	return procs, nil
    62  }
    63  
    64  // check that the pid directory exists
    65  func (lpm *DockerTopManager) Exists(pid int64) (bool, error) {
    66  	procs, err := lpm.List()
    67  	if err != nil {
    68  		return false, err
    69  	}
    70  
    71  	for _, p := range procs {
    72  		if p.Pid == pid {
    73  			return true, nil
    74  		}
    75  	}
    76  
    77  	return false, nil
    78  }
    79  
    80  func (lpm *DockerTopManager) Process(pid int64) (*OSProcess, error) {
    81  	procs, err := lpm.List()
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  
    86  	for _, p := range procs {
    87  		if p.Pid == pid {
    88  			return p, nil
    89  		}
    90  	}
    91  	return nil, fmt.Errorf("process with PID %d does not exist", pid)
    92  }