mirror of
https://github.com/containers/podman.git
synced 2025-08-06 11:32:07 +08:00
podmanv2 ps
add the ability to list containers Signed-off-by: Brent Baude <bbaude@redhat.com>
This commit is contained in:
@ -4,21 +4,16 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/containers/libpod/pkg/api/handlers/compat"
|
||||
|
||||
"github.com/containers/libpod/cmd/podman/shared"
|
||||
"github.com/containers/libpod/libpod"
|
||||
"github.com/containers/libpod/libpod/define"
|
||||
"github.com/containers/libpod/pkg/api/handlers/compat"
|
||||
"github.com/containers/libpod/pkg/api/handlers/utils"
|
||||
"github.com/containers/libpod/pkg/domain/entities"
|
||||
"github.com/containers/libpod/pkg/ps"
|
||||
"github.com/gorilla/schema"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func ContainerExists(w http.ResponseWriter, r *http.Request) {
|
||||
@ -38,8 +33,8 @@ func ContainerExists(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func ListContainers(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
filterFuncs []libpod.ContainerFilter
|
||||
pss []ListContainer
|
||||
//filterFuncs []libpod.ContainerFilter
|
||||
//pss []entities.ListContainer
|
||||
)
|
||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
||||
query := struct {
|
||||
@ -61,66 +56,19 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||
opts := shared.PsOptions{
|
||||
opts := entities.ContainerListOptions{
|
||||
All: query.All,
|
||||
Last: query.Last,
|
||||
Size: query.Size,
|
||||
Sort: "",
|
||||
Namespace: query.Namespace,
|
||||
NoTrunc: true,
|
||||
Pod: query.Pod,
|
||||
Sync: query.Sync,
|
||||
}
|
||||
|
||||
all := query.All
|
||||
if len(query.Filters) > 0 {
|
||||
for k, v := range query.Filters {
|
||||
for _, val := range v {
|
||||
generatedFunc, err := shared.GenerateContainerFilterFuncs(k, val, runtime)
|
||||
if err != nil {
|
||||
utils.InternalServerError(w, err)
|
||||
return
|
||||
}
|
||||
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(query.Filters["status"]) > 0 {
|
||||
all = true
|
||||
}
|
||||
if !all {
|
||||
runningOnly, err := shared.GenerateContainerFilterFuncs("status", define.ContainerStateRunning.String(), runtime)
|
||||
if err != nil {
|
||||
utils.InternalServerError(w, err)
|
||||
return
|
||||
}
|
||||
filterFuncs = append(filterFuncs, runningOnly)
|
||||
}
|
||||
|
||||
cons, err := runtime.GetContainers(filterFuncs...)
|
||||
pss, err := ps.GetContainerLists(runtime, opts)
|
||||
if err != nil {
|
||||
utils.InternalServerError(w, err)
|
||||
}
|
||||
if query.Last > 0 {
|
||||
// Sort the containers we got
|
||||
sort.Sort(psSortCreateTime{cons})
|
||||
// we should perform the lopping before we start getting
|
||||
// the expensive information on containers
|
||||
if query.Last < len(cons) {
|
||||
cons = cons[len(cons)-query.Last:]
|
||||
}
|
||||
}
|
||||
for _, con := range cons {
|
||||
listCon, err := ListContainerBatch(runtime, con, opts)
|
||||
if err != nil {
|
||||
utils.InternalServerError(w, err)
|
||||
return
|
||||
}
|
||||
pss = append(pss, listCon)
|
||||
|
||||
return
|
||||
}
|
||||
utils.WriteResponse(w, http.StatusOK, pss)
|
||||
}
|
||||
@ -212,125 +160,6 @@ func ShowMountedContainers(w http.ResponseWriter, r *http.Request) {
|
||||
utils.WriteResponse(w, http.StatusOK, response)
|
||||
}
|
||||
|
||||
// BatchContainerOp is used in ps to reduce performance hits by "batching"
|
||||
// locks.
|
||||
func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts shared.PsOptions) (ListContainer, error) {
|
||||
var (
|
||||
conConfig *libpod.ContainerConfig
|
||||
conState define.ContainerStatus
|
||||
err error
|
||||
exitCode int32
|
||||
exited bool
|
||||
pid int
|
||||
size *shared.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, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "cgroup"))
|
||||
ipc, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "ipc"))
|
||||
mnt, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "mnt"))
|
||||
net, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "net"))
|
||||
pidns, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "pid"))
|
||||
user, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "user"))
|
||||
uts, _ = shared.GetNamespaceInfo(filepath.Join("/proc", ctrPID, "ns", "uts"))
|
||||
}
|
||||
if opts.Size {
|
||||
size = new(shared.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 ListContainer{}, batchErr
|
||||
}
|
||||
|
||||
ps := ListContainer{
|
||||
Command: conConfig.Command,
|
||||
Created: conConfig.CreatedTime.Unix(),
|
||||
Exited: exited,
|
||||
ExitCode: exitCode,
|
||||
ExitedAt: exitedTime.Unix(),
|
||||
ID: conConfig.ID,
|
||||
Image: conConfig.RootfsImageName,
|
||||
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 ListContainer{}, err
|
||||
}
|
||||
ps.PodName = pod.Name()
|
||||
}
|
||||
|
||||
if opts.Namespace {
|
||||
ns := ListContainerNamespaces{
|
||||
Cgroup: cgroup,
|
||||
IPC: ipc,
|
||||
MNT: mnt,
|
||||
NET: net,
|
||||
PIDNS: pidns,
|
||||
User: user,
|
||||
UTS: uts,
|
||||
}
|
||||
ps.Namespaces = ns
|
||||
}
|
||||
return ps, nil
|
||||
}
|
||||
|
||||
func Checkpoint(w http.ResponseWriter, r *http.Request) {
|
||||
var targetFile string
|
||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
||||
|
@ -17,7 +17,7 @@ const DefaultPodmanSwaggerSpec = "/usr/share/containers/podman/swagger.yaml"
|
||||
// swagger:response ListContainers
|
||||
type swagInspectPodResponse struct {
|
||||
// in:body
|
||||
Body []ListContainer
|
||||
Body []entities.ListContainer
|
||||
}
|
||||
|
||||
// Inspect Manifest
|
||||
|
@ -1,82 +0,0 @@
|
||||
package libpod
|
||||
|
||||
import (
|
||||
"github.com/containers/libpod/cmd/podman/shared"
|
||||
"github.com/containers/libpod/libpod"
|
||||
"github.com/cri-o/ocicni/pkg/ocicni"
|
||||
)
|
||||
|
||||
// Listcontainer describes a container suitable for listing
|
||||
type ListContainer struct {
|
||||
// Container command
|
||||
Command []string
|
||||
// Container creation time
|
||||
Created int64
|
||||
// If container has exited/stopped
|
||||
Exited bool
|
||||
// Time container exited
|
||||
ExitedAt int64
|
||||
// If container has exited, the return code from the command
|
||||
ExitCode int32
|
||||
// The unique identifier for the container
|
||||
ID string `json:"Id"`
|
||||
// Container image
|
||||
Image string
|
||||
// If this container is a Pod infra container
|
||||
IsInfra bool
|
||||
// Labels for container
|
||||
Labels map[string]string
|
||||
// User volume mounts
|
||||
Mounts []string
|
||||
// The names assigned to the container
|
||||
Names []string
|
||||
// Namespaces the container belongs to. Requires the
|
||||
// namespace boolean to be true
|
||||
Namespaces ListContainerNamespaces
|
||||
// The process id of the container
|
||||
Pid int
|
||||
// If the container is part of Pod, the Pod ID. Requires the pod
|
||||
// boolean to be set
|
||||
Pod string
|
||||
// If the container is part of Pod, the Pod name. Requires the pod
|
||||
// boolean to be set
|
||||
PodName string
|
||||
// Port mappings
|
||||
Ports []ocicni.PortMapping
|
||||
// Size of the container rootfs. Requires the size boolean to be true
|
||||
Size *shared.ContainerSize
|
||||
// Time when container started
|
||||
StartedAt int64
|
||||
// State of container
|
||||
State string
|
||||
}
|
||||
|
||||
// ListContainer Namespaces contains the identifiers of the container's Linux namespaces
|
||||
type ListContainerNamespaces struct {
|
||||
// Mount namespace
|
||||
MNT string `json:"Mnt,omitempty"`
|
||||
// Cgroup namespace
|
||||
Cgroup string `json:"Cgroup,omitempty"`
|
||||
// IPC namespace
|
||||
IPC string `json:"Ipc,omitempty"`
|
||||
// Network namespace
|
||||
NET string `json:"Net,omitempty"`
|
||||
// PID namespace
|
||||
PIDNS string `json:"Pidns,omitempty"`
|
||||
// UTS namespace
|
||||
UTS string `json:"Uts,omitempty"`
|
||||
// User namespace
|
||||
User string `json:"User,omitempty"`
|
||||
}
|
||||
|
||||
// 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 psSortCreateTime struct{ sortContainers }
|
||||
|
||||
func (a psSortCreateTime) Less(i, j int) bool {
|
||||
return a.sortContainers[i].CreatedTime().Before(a.sortContainers[j].CreatedTime())
|
||||
}
|
Reference in New Issue
Block a user