mirror of
https://github.com/containers/podman.git
synced 2025-06-19 00:06:43 +08:00

- misspell - prealloc - unparam - nakedret Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
221 lines
6.2 KiB
Go
221 lines
6.2 KiB
Go
package ps
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/containers/libpod/libpod"
|
|
"github.com/containers/libpod/libpod/define"
|
|
lpfilters "github.com/containers/libpod/libpod/filters"
|
|
"github.com/containers/libpod/pkg/domain/entities"
|
|
psdefine "github.com/containers/libpod/pkg/ps/define"
|
|
"github.com/pkg/errors"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
func GetContainerLists(runtime *libpod.Runtime, options entities.ContainerListOptions) ([]entities.ListContainer, error) {
|
|
var (
|
|
filterFuncs []libpod.ContainerFilter
|
|
pss = []entities.ListContainer{}
|
|
)
|
|
all := options.All || options.Last > 0
|
|
if len(options.Filters) > 0 {
|
|
for k, v := range options.Filters {
|
|
for _, val := range v {
|
|
generatedFunc, err := lpfilters.GenerateContainerFilterFuncs(k, val, runtime)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
filterFuncs = append(filterFuncs, generatedFunc)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Docker thinks that if status is given as an input, then we should override
|
|
// the all setting and always deal with all containers.
|
|
if len(options.Filters["status"]) > 0 {
|
|
all = true
|
|
}
|
|
if !all {
|
|
runningOnly, err := lpfilters.GenerateContainerFilterFuncs("status", define.ContainerStateRunning.String(), runtime)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
filterFuncs = append(filterFuncs, runningOnly)
|
|
}
|
|
|
|
cons, err := runtime.GetContainers(filterFuncs...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if options.Last > 0 {
|
|
// Sort the containers we got
|
|
sort.Sort(SortCreateTime{SortContainers: cons})
|
|
// we should perform the lopping before we start getting
|
|
// the expensive information on containers
|
|
if options.Last < len(cons) {
|
|
cons = cons[len(cons)-options.Last:]
|
|
}
|
|
}
|
|
for _, con := range cons {
|
|
listCon, err := ListContainerBatch(runtime, con, options)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
pss = append(pss, listCon)
|
|
|
|
}
|
|
return pss, nil
|
|
}
|
|
|
|
// BatchContainerOp is used in ps to reduce performance hits by "batching"
|
|
// locks.
|
|
func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities.ContainerListOptions) (entities.ListContainer, error) {
|
|
var (
|
|
conConfig *libpod.ContainerConfig
|
|
conState define.ContainerStatus
|
|
err error
|
|
exitCode int32
|
|
exited bool
|
|
pid int
|
|
size *psdefine.ContainerSize
|
|
startedTime time.Time
|
|
exitedTime time.Time
|
|
cgroup, ipc, mnt, net, pidns, user, uts string
|
|
)
|
|
|
|
batchErr := ctr.Batch(func(c *libpod.Container) error {
|
|
conConfig = c.Config()
|
|
conState, err = c.State()
|
|
if err != nil {
|
|
return errors.Wrapf(err, "unable to obtain container state")
|
|
}
|
|
|
|
exitCode, exited, err = c.ExitCode()
|
|
if err != nil {
|
|
return errors.Wrapf(err, "unable to obtain container exit code")
|
|
}
|
|
startedTime, err = c.StartedTime()
|
|
if err != nil {
|
|
logrus.Errorf("error getting started time for %q: %v", c.ID(), err)
|
|
}
|
|
exitedTime, err = c.FinishedTime()
|
|
if err != nil {
|
|
logrus.Errorf("error getting exited time for %q: %v", c.ID(), err)
|
|
}
|
|
|
|
if !opts.Size && !opts.Namespace {
|
|
return nil
|
|
}
|
|
|
|
if opts.Namespace {
|
|
pid, err = c.PID()
|
|
if err != nil {
|
|
return errors.Wrapf(err, "unable to obtain container pid")
|
|
}
|
|
ctrPID := strconv.Itoa(pid)
|
|
cgroup, _ = getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "cgroup"))
|
|
ipc, _ = getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "ipc"))
|
|
mnt, _ = getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "mnt"))
|
|
net, _ = getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "net"))
|
|
pidns, _ = getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "pid"))
|
|
user, _ = getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "user"))
|
|
uts, _ = getNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "uts"))
|
|
}
|
|
if opts.Size {
|
|
size = new(psdefine.ContainerSize)
|
|
|
|
rootFsSize, err := c.RootFsSize()
|
|
if err != nil {
|
|
logrus.Errorf("error getting root fs size for %q: %v", c.ID(), err)
|
|
}
|
|
|
|
rwSize, err := c.RWSize()
|
|
if err != nil {
|
|
logrus.Errorf("error getting rw size for %q: %v", c.ID(), err)
|
|
}
|
|
|
|
size.RootFsSize = rootFsSize
|
|
size.RwSize = rwSize
|
|
}
|
|
return nil
|
|
})
|
|
|
|
if batchErr != nil {
|
|
return entities.ListContainer{}, batchErr
|
|
}
|
|
|
|
ps := entities.ListContainer{
|
|
Command: conConfig.Command,
|
|
Created: conConfig.CreatedTime.Unix(),
|
|
Exited: exited,
|
|
ExitCode: exitCode,
|
|
ExitedAt: exitedTime.Unix(),
|
|
ID: conConfig.ID,
|
|
Image: conConfig.RootfsImageName,
|
|
ImageID: conConfig.RootfsImageID,
|
|
IsInfra: conConfig.IsInfra,
|
|
Labels: conConfig.Labels,
|
|
Mounts: ctr.UserVolumes(),
|
|
Names: []string{conConfig.Name},
|
|
Pid: pid,
|
|
Pod: conConfig.Pod,
|
|
Ports: conConfig.PortMappings,
|
|
Size: size,
|
|
StartedAt: startedTime.Unix(),
|
|
State: conState.String(),
|
|
}
|
|
if opts.Pod && len(conConfig.Pod) > 0 {
|
|
pod, err := rt.GetPod(conConfig.Pod)
|
|
if err != nil {
|
|
return entities.ListContainer{}, err
|
|
}
|
|
ps.PodName = pod.Name()
|
|
}
|
|
|
|
if opts.Namespace {
|
|
ps.Namespaces = entities.ListContainerNamespaces{
|
|
Cgroup: cgroup,
|
|
IPC: ipc,
|
|
MNT: mnt,
|
|
NET: net,
|
|
PIDNS: pidns,
|
|
User: user,
|
|
UTS: uts,
|
|
}
|
|
}
|
|
return ps, nil
|
|
}
|
|
|
|
func getNamespaceInfo(path string) (string, error) {
|
|
val, err := os.Readlink(path)
|
|
if err != nil {
|
|
return "", errors.Wrapf(err, "error getting info from %q", path)
|
|
}
|
|
return getStrFromSquareBrackets(val), nil
|
|
}
|
|
|
|
// getStrFromSquareBrackets gets the string inside [] from a string.
|
|
func getStrFromSquareBrackets(cmd string) string {
|
|
reg := regexp.MustCompile(`.*\[|\].*`)
|
|
arr := strings.Split(reg.ReplaceAllLiteralString(cmd, ""), ",")
|
|
return strings.Join(arr, ",")
|
|
}
|
|
|
|
// SortContainers helps us set-up ability to sort by createTime
|
|
type SortContainers []*libpod.Container
|
|
|
|
func (a SortContainers) Len() int { return len(a) }
|
|
func (a SortContainers) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
|
|
|
type SortCreateTime struct{ SortContainers }
|
|
|
|
func (a SortCreateTime) Less(i, j int) bool {
|
|
return a.SortContainers[i].CreatedTime().Before(a.SortContainers[j].CreatedTime())
|
|
}
|