github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/pkg/ps/ps.go (about)

     1  package ps
     2  
     3  import (
     4  	"path/filepath"
     5  	"sort"
     6  	"strconv"
     7  	"time"
     8  
     9  	"github.com/containers/libpod/cmd/podman/shared"
    10  	"github.com/containers/libpod/libpod"
    11  	"github.com/containers/libpod/libpod/define"
    12  	lpfilters "github.com/containers/libpod/libpod/filters"
    13  	"github.com/containers/libpod/pkg/domain/entities"
    14  	"github.com/pkg/errors"
    15  	"github.com/sirupsen/logrus"
    16  )
    17  
    18  func GetContainerLists(runtime *libpod.Runtime, options entities.ContainerListOptions) ([]entities.ListContainer, error) {
    19  	var (
    20  		filterFuncs []libpod.ContainerFilter
    21  		pss         []entities.ListContainer
    22  	)
    23  	all := options.All
    24  	if len(options.Filters) > 0 {
    25  		for k, v := range options.Filters {
    26  			for _, val := range v {
    27  				generatedFunc, err := lpfilters.GenerateContainerFilterFuncs(k, val, runtime)
    28  				if err != nil {
    29  					return nil, err
    30  				}
    31  				filterFuncs = append(filterFuncs, generatedFunc)
    32  			}
    33  		}
    34  	}
    35  
    36  	// Docker thinks that if status is given as an input, then we should override
    37  	// the all setting and always deal with all containers.
    38  	if len(options.Filters["status"]) > 0 {
    39  		all = true
    40  	}
    41  	if !all {
    42  		runningOnly, err := lpfilters.GenerateContainerFilterFuncs("status", define.ContainerStateRunning.String(), runtime)
    43  		if err != nil {
    44  			return nil, err
    45  		}
    46  		filterFuncs = append(filterFuncs, runningOnly)
    47  	}
    48  
    49  	cons, err := runtime.GetContainers(filterFuncs...)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	if options.Last > 0 {
    54  		// Sort the containers we got
    55  		sort.Sort(entities.SortCreateTime{SortContainers: cons})
    56  		// we should perform the lopping before we start getting
    57  		// the expensive information on containers
    58  		if options.Last < len(cons) {
    59  			cons = cons[len(cons)-options.Last:]
    60  		}
    61  	}
    62  	for _, con := range cons {
    63  		listCon, err := ListContainerBatch(runtime, con, options)
    64  		if err != nil {
    65  			return nil, err
    66  		}
    67  		pss = append(pss, listCon)
    68  
    69  	}
    70  	return pss, nil
    71  }
    72  
    73  // BatchContainerOp is used in ps to reduce performance hits by "batching"
    74  // locks.
    75  func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities.ContainerListOptions) (entities.ListContainer, error) {
    76  	var (
    77  		conConfig                               *libpod.ContainerConfig
    78  		conState                                define.ContainerStatus
    79  		err                                     error
    80  		exitCode                                int32
    81  		exited                                  bool
    82  		pid                                     int
    83  		size                                    *shared.ContainerSize
    84  		startedTime                             time.Time
    85  		exitedTime                              time.Time
    86  		cgroup, ipc, mnt, net, pidns, user, uts string
    87  	)
    88  
    89  	batchErr := ctr.Batch(func(c *libpod.Container) error {
    90  		conConfig = c.Config()
    91  		conState, err = c.State()
    92  		if err != nil {
    93  			return errors.Wrapf(err, "unable to obtain container state")
    94  		}
    95  
    96  		exitCode, exited, err = c.ExitCode()
    97  		if err != nil {
    98  			return errors.Wrapf(err, "unable to obtain container exit code")
    99  		}
   100  		startedTime, err = c.StartedTime()
   101  		if err != nil {
   102  			logrus.Errorf("error getting started time for %q: %v", c.ID(), err)
   103  		}
   104  		exitedTime, err = c.FinishedTime()
   105  		if err != nil {
   106  			logrus.Errorf("error getting exited time for %q: %v", c.ID(), err)
   107  		}
   108  
   109  		if !opts.Size && !opts.Namespace {
   110  			return nil
   111  		}
   112  
   113  		if opts.Namespace {
   114  			pid, err = c.PID()
   115  			if err != nil {
   116  				return errors.Wrapf(err, "unable to obtain container pid")
   117  			}
   118  			ctrPID := strconv.Itoa(pid)
   119  			cgroup, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "cgroup"))
   120  			ipc, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "ipc"))
   121  			mnt, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "mnt"))
   122  			net, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "net"))
   123  			pidns, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "pid"))
   124  			user, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "user"))
   125  			uts, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "uts"))
   126  		}
   127  		if opts.Size {
   128  			size = new(shared.ContainerSize)
   129  
   130  			rootFsSize, err := c.RootFsSize()
   131  			if err != nil {
   132  				logrus.Errorf("error getting root fs size for %q: %v", c.ID(), err)
   133  			}
   134  
   135  			rwSize, err := c.RWSize()
   136  			if err != nil {
   137  				logrus.Errorf("error getting rw size for %q: %v", c.ID(), err)
   138  			}
   139  
   140  			size.RootFsSize = rootFsSize
   141  			size.RwSize = rwSize
   142  		}
   143  		return nil
   144  	})
   145  
   146  	if batchErr != nil {
   147  		return entities.ListContainer{}, batchErr
   148  	}
   149  
   150  	ps := entities.ListContainer{
   151  		Command:   conConfig.Command,
   152  		Created:   conConfig.CreatedTime.Unix(),
   153  		Exited:    exited,
   154  		ExitCode:  exitCode,
   155  		ExitedAt:  exitedTime.Unix(),
   156  		ID:        conConfig.ID,
   157  		Image:     conConfig.RootfsImageName,
   158  		IsInfra:   conConfig.IsInfra,
   159  		Labels:    conConfig.Labels,
   160  		Mounts:    ctr.UserVolumes(),
   161  		Names:     []string{conConfig.Name},
   162  		Pid:       pid,
   163  		Pod:       conConfig.Pod,
   164  		Ports:     conConfig.PortMappings,
   165  		Size:      size,
   166  		StartedAt: startedTime.Unix(),
   167  		State:     conState.String(),
   168  	}
   169  	if opts.Pod && len(conConfig.Pod) > 0 {
   170  		pod, err := rt.GetPod(conConfig.Pod)
   171  		if err != nil {
   172  			return entities.ListContainer{}, err
   173  		}
   174  		ps.PodName = pod.Name()
   175  	}
   176  
   177  	if opts.Namespace {
   178  		ps.Namespaces = entities.ListContainerNamespaces{
   179  			Cgroup: cgroup,
   180  			IPC:    ipc,
   181  			MNT:    mnt,
   182  			NET:    net,
   183  			PIDNS:  pidns,
   184  			User:   user,
   185  			UTS:    uts,
   186  		}
   187  	}
   188  	return ps, nil
   189  }