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 }