summaryrefslogtreecommitdiff
path: root/cmd/podman/ps.go
diff options
context:
space:
mode:
authorbaude <bbaude@redhat.com>2018-04-27 14:00:32 -0500
committerAtomic Bot <atomic-devel@projectatomic.io>2018-05-03 17:31:33 +0000
commit8dfebd4607c1152bd26c4a586e6d56a196c56e54 (patch)
treee4fdfcc0b1813fccd2ee6134931afbf2725a8208 /cmd/podman/ps.go
parentfae5033a01b78d3e8f23c1c9438bc5534dfe0fa3 (diff)
downloadpodman-8dfebd4607c1152bd26c4a586e6d56a196c56e54.tar.gz
podman-8dfebd4607c1152bd26c4a586e6d56a196c56e54.tar.bz2
podman-8dfebd4607c1152bd26c4a586e6d56a196c56e54.zip
varlink containers
first pass at adding in the container related endpoints/methods for the libpod backend. Couple of important notes: * endpoints that can use a console are not going to be done until we have "remote" console * several of the container methods should probably be able to stream as opposed to a one-off return Signed-off-by: baude <bbaude@redhat.com> Closes: #708 Approved by: baude
Diffstat (limited to 'cmd/podman/ps.go')
-rw-r--r--cmd/podman/ps.go290
1 files changed, 75 insertions, 215 deletions
diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go
index 0893e869a..907c437b6 100644
--- a/cmd/podman/ps.go
+++ b/cmd/podman/ps.go
@@ -3,10 +3,7 @@ package main
import (
"encoding/json"
"fmt"
- "os"
- "path/filepath"
"reflect"
- "regexp"
"strconv"
"strings"
"time"
@@ -15,6 +12,7 @@ import (
"github.com/docker/go-units"
specs "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
+ "github.com/projectatomic/libpod/cmd/podman/batchcontainer"
"github.com/projectatomic/libpod/cmd/podman/formats"
"github.com/projectatomic/libpod/cmd/podman/libpodruntime"
"github.com/projectatomic/libpod/libpod"
@@ -26,19 +24,6 @@ import (
const mountTruncLength = 12
-type psOptions struct {
- all bool
- filter string
- format string
- last int
- latest bool
- noTrunc bool
- quiet bool
- size bool
- label string
- namespace bool
-}
-
type psTemplateParams struct {
ID string
Image string
@@ -66,32 +51,21 @@ type psTemplateParams struct {
// psJSONParams will be populated by data from libpod.Container,
// the members of the struct are the sama data types as their sources.
type psJSONParams struct {
- ID string `json:"id"`
- Image string `json:"image"`
- ImageID string `json:"image_id"`
- Command []string `json:"command"`
- CreatedAt time.Time `json:"createdAt"`
- RunningFor time.Duration `json:"runningFor"`
- Status string `json:"status"`
- Ports []ocicni.PortMapping `json:"ports"`
- RootFsSize int64 `json:"rootFsSize"`
- RWSize int64 `json:"rwSize"`
- Names string `json:"names"`
- Labels fields.Set `json:"labels"`
- Mounts []specs.Mount `json:"mounts"`
- ContainerRunning bool `json:"ctrRunning"`
- Namespaces *namespace `json:"namespace,omitempty"`
-}
-
-type namespace struct {
- PID string `json:"pid,omitempty"`
- Cgroup string `json:"cgroup,omitempty"`
- IPC string `json:"ipc,omitempty"`
- MNT string `json:"mnt,omitempty"`
- NET string `json:"net,omitempty"`
- PIDNS string `json:"pidns,omitempty"`
- User string `json:"user,omitempty"`
- UTS string `json:"uts,omitempty"`
+ ID string `json:"id"`
+ Image string `json:"image"`
+ ImageID string `json:"image_id"`
+ Command []string `json:"command"`
+ CreatedAt time.Time `json:"createdAt"`
+ RunningFor time.Duration `json:"runningFor"`
+ Status string `json:"status"`
+ Ports []ocicni.PortMapping `json:"ports"`
+ RootFsSize int64 `json:"rootFsSize"`
+ RWSize int64 `json:"rwSize"`
+ Names string `json:"names"`
+ Labels fields.Set `json:"labels"`
+ Mounts []specs.Mount `json:"mounts"`
+ ContainerRunning bool `json:"ctrRunning"`
+ Namespaces *batchcontainer.Namespace `json:"namespace,omitempty"`
}
var (
@@ -168,22 +142,22 @@ func psCmd(c *cli.Context) error {
format := genPsFormat(c.String("format"), c.Bool("quiet"), c.Bool("size"), c.Bool("namespace"))
- opts := psOptions{
- all: c.Bool("all"),
- filter: c.String("filter"),
- format: format,
- last: c.Int("last"),
- latest: c.Bool("latest"),
- noTrunc: c.Bool("no-trunc"),
- quiet: c.Bool("quiet"),
- size: c.Bool("size"),
- namespace: c.Bool("namespace"),
+ opts := batchcontainer.PsOptions{
+ All: c.Bool("all"),
+ Filter: c.String("filter"),
+ Format: format,
+ Last: c.Int("last"),
+ Latest: c.Bool("latest"),
+ NoTrunc: c.Bool("no-trunc"),
+ Quiet: c.Bool("quiet"),
+ Size: c.Bool("size"),
+ Namespace: c.Bool("namespace"),
}
var filterFuncs []libpod.ContainerFilter
// When we are dealing with latest or last=n, we need to
// get all containers.
- if !opts.all && !opts.latest && opts.last < 1 {
+ if !opts.All && !opts.Latest && opts.Last < 1 {
// only get running containers
filterFuncs = append(filterFuncs, func(c *libpod.Container) bool {
state, _ := c.State()
@@ -191,8 +165,8 @@ func psCmd(c *cli.Context) error {
})
}
- if opts.filter != "" {
- filters := strings.Split(opts.filter, ",")
+ if opts.Filter != "" {
+ filters := strings.Split(opts.Filter, ",")
for _, f := range filters {
filterSplit := strings.Split(f, "=")
if len(filterSplit) < 2 {
@@ -208,10 +182,10 @@ func psCmd(c *cli.Context) error {
containers, err := runtime.GetContainers(filterFuncs...)
var outputContainers []*libpod.Container
- if opts.latest && len(containers) > 0 {
+ if opts.Latest && len(containers) > 0 {
outputContainers = append(outputContainers, containers[0])
- } else if opts.last > 0 && opts.last <= len(containers) {
- outputContainers = append(outputContainers, containers[:opts.last]...)
+ } else if opts.Last > 0 && opts.Last <= len(containers) {
+ outputContainers = append(outputContainers, containers[:opts.Last]...)
} else {
outputContainers = containers
}
@@ -397,15 +371,15 @@ func (p *psTemplateParams) headerMap() map[string]string {
}
// getTemplateOutput returns the modified container information
-func getTemplateOutput(containers []*libpod.Container, opts psOptions) ([]psTemplateParams, error) {
+func getTemplateOutput(containers []*libpod.Container, opts batchcontainer.PsOptions) ([]psTemplateParams, error) {
var (
psOutput []psTemplateParams
status, size string
- ns *namespace
+ ns *batchcontainer.Namespace
)
for _, ctr := range containers {
- batchInfo, err := batchContainerOp(ctr, opts)
+ batchInfo, err := batchcontainer.BatchContainerOp(ctr, opts)
if err != nil {
// If the error was ErrNoSuchCtr, it was probably
// removed sometime after we got the initial list.
@@ -421,11 +395,11 @@ func getTemplateOutput(containers []*libpod.Container, opts psOptions) ([]psTemp
runningFor := ""
// If the container has not be started, the "zero" value of time is 0001-01-01 00:00:00 +0000 UTC
// which would make the time elapsed about a few hundred of years. So checking for the "zero" value of time.Time
- if batchInfo.startedTime != (time.Time{}) {
- runningFor = units.HumanDuration(time.Since(batchInfo.startedTime))
+ if batchInfo.StartedTime != (time.Time{}) {
+ runningFor = units.HumanDuration(time.Since(batchInfo.StartedTime))
}
- createdAt := batchInfo.conConfig.CreatedTime.Format("2006-01-02 15:04:05 -0700 MST")
- imageName := batchInfo.conConfig.RootfsImageName
+ createdAt := batchInfo.ConConfig.CreatedTime.Format("2006-01-02 15:04:05 -0700 MST")
+ imageName := batchInfo.ConConfig.RootfsImageName
var createArtifact createConfig
artifact, err := ctr.GetArtifact("create-config")
@@ -436,27 +410,27 @@ func getTemplateOutput(containers []*libpod.Container, opts psOptions) ([]psTemp
} else {
logrus.Errorf("couldn't get some ps information, error getting artifact %q: %v", ctr.ID(), err)
}
- if opts.namespace {
- ns = getNamespaces(batchInfo.pid)
+ if opts.Namespace {
+ ns = batchcontainer.GetNamespaces(batchInfo.Pid)
}
- if opts.size {
+ if opts.Size {
- size = units.HumanSizeWithPrecision(float64(batchInfo.rwSize), 3) + " (virtual " + units.HumanSizeWithPrecision(float64(batchInfo.rootFsSize), 3) + ")"
+ size = units.HumanSizeWithPrecision(float64(batchInfo.RwSize), 3) + " (virtual " + units.HumanSizeWithPrecision(float64(batchInfo.RootFsSize), 3) + ")"
}
- command := strings.Join(batchInfo.conConfig.Spec.Process.Args, " ")
- if !opts.noTrunc {
+ command := strings.Join(batchInfo.ConConfig.Spec.Process.Args, " ")
+ if !opts.NoTrunc {
if len(command) > 20 {
command = command[:19] + "..."
}
}
- ports := portsToString(batchInfo.conConfig.PortMappings)
- mounts := getMounts(createArtifact.Volumes, opts.noTrunc)
+ ports := portsToString(batchInfo.ConConfig.PortMappings)
+ mounts := getMounts(createArtifact.Volumes, opts.NoTrunc)
labels := formatLabels(ctr.Labels())
- switch batchInfo.conState {
+ switch batchInfo.ConState {
case libpod.ContainerStateStopped:
- status = fmt.Sprintf("Exited (%d) %s ago", batchInfo.exitCode, runningFor)
+ status = fmt.Sprintf("Exited (%d) %s ago", batchInfo.ExitCode, runningFor)
case libpod.ContainerStateRunning:
status = "Up " + runningFor + " ago"
case libpod.ContainerStatePaused:
@@ -467,9 +441,9 @@ func getTemplateOutput(containers []*libpod.Container, opts psOptions) ([]psTemp
status = "Dead"
}
- if !opts.noTrunc {
+ if !opts.NoTrunc {
ctrID = shortID(ctr.ID())
- imageName = batchInfo.conConfig.RootfsImageName
+ imageName = batchInfo.ConConfig.RootfsImageName
}
params := psTemplateParams{
@@ -484,10 +458,10 @@ func getTemplateOutput(containers []*libpod.Container, opts psOptions) ([]psTemp
Names: ctr.Name(),
Labels: labels,
Mounts: mounts,
- PID: batchInfo.pid,
+ PID: batchInfo.Pid,
}
- if opts.namespace {
+ if opts.Namespace {
params.Cgroup = ns.Cgroup
params.IPC = ns.IPC
params.MNT = ns.MNT
@@ -501,65 +475,35 @@ func getTemplateOutput(containers []*libpod.Container, opts psOptions) ([]psTemp
return psOutput, nil
}
-func getNamespaces(pid int) *namespace {
- 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"))
-
- return &namespace{
- PID: ctrPID,
- Cgroup: cgroup,
- IPC: ipc,
- MNT: mnt,
- NET: net,
- PIDNS: pidns,
- User: user,
- UTS: uts,
- }
-}
-
-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
-}
-
// getJSONOutput returns the container info in its raw form
-func getJSONOutput(containers []*libpod.Container, opts psOptions) ([]psJSONParams, error) {
+func getJSONOutput(containers []*libpod.Container, opts batchcontainer.PsOptions) ([]psJSONParams, error) {
var (
psOutput []psJSONParams
- ns *namespace
+ ns *batchcontainer.Namespace
)
for _, ctr := range containers {
- batchInfo, err := batchContainerOp(ctr, opts)
+ batchInfo, err := batchcontainer.BatchContainerOp(ctr, opts)
if err != nil {
return nil, err
}
- if opts.namespace {
- ns = getNamespaces(batchInfo.pid)
+ if opts.Namespace {
+ ns = batchcontainer.GetNamespaces(batchInfo.Pid)
}
params := psJSONParams{
ID: ctr.ID(),
- Image: batchInfo.conConfig.RootfsImageName,
- ImageID: batchInfo.conConfig.RootfsImageID,
- Command: batchInfo.conConfig.Spec.Process.Args,
- CreatedAt: batchInfo.conConfig.CreatedTime,
- RunningFor: time.Since(batchInfo.conConfig.CreatedTime),
- Status: batchInfo.conState.String(),
- Ports: batchInfo.conConfig.PortMappings,
- RootFsSize: batchInfo.rootFsSize,
- RWSize: batchInfo.rwSize,
- Names: batchInfo.conConfig.Name,
- Labels: batchInfo.conConfig.Labels,
- Mounts: batchInfo.conConfig.Spec.Mounts,
- ContainerRunning: batchInfo.conState == libpod.ContainerStateRunning,
+ Image: batchInfo.ConConfig.RootfsImageName,
+ ImageID: batchInfo.ConConfig.RootfsImageID,
+ Command: batchInfo.ConConfig.Spec.Process.Args,
+ CreatedAt: batchInfo.ConConfig.CreatedTime,
+ RunningFor: time.Since(batchInfo.ConConfig.CreatedTime),
+ Status: batchInfo.ConState.String(),
+ Ports: batchInfo.ConConfig.PortMappings,
+ RootFsSize: batchInfo.RootFsSize,
+ RWSize: batchInfo.RwSize,
+ Names: batchInfo.ConConfig.Name,
+ Labels: batchInfo.ConConfig.Labels,
+ Mounts: batchInfo.ConConfig.Spec.Mounts,
+ ContainerRunning: batchInfo.ConState == libpod.ContainerStateRunning,
Namespaces: ns,
}
psOutput = append(psOutput, params)
@@ -567,13 +511,13 @@ func getJSONOutput(containers []*libpod.Container, opts psOptions) ([]psJSONPara
return psOutput, nil
}
-func generatePsOutput(containers []*libpod.Container, opts psOptions) error {
- if len(containers) == 0 && opts.format != formats.JSONString {
+func generatePsOutput(containers []*libpod.Container, opts batchcontainer.PsOptions) error {
+ if len(containers) == 0 && opts.Format != formats.JSONString {
return nil
}
var out formats.Writer
- switch opts.format {
+ switch opts.Format {
case formats.JSONString:
psOutput, err := getJSONOutput(containers, opts)
if err != nil {
@@ -585,22 +529,12 @@ func generatePsOutput(containers []*libpod.Container, opts psOptions) error {
if err != nil {
return errors.Wrapf(err, "unable to create output")
}
- out = formats.StdoutTemplateArray{Output: psToGeneric(psOutput, []psJSONParams{}), Template: opts.format, Fields: psOutput[0].headerMap()}
+ out = formats.StdoutTemplateArray{Output: psToGeneric(psOutput, []psJSONParams{}), Template: opts.Format, Fields: psOutput[0].headerMap()}
}
return formats.Writer(out).Out()
}
-// getStrFromSquareBrackets gets the string inside [] from a string
-func getStrFromSquareBrackets(cmd string) string {
- reg, err := regexp.Compile(".*\\[|\\].*")
- if err != nil {
- return ""
- }
- arr := strings.Split(reg.ReplaceAllLiteralString(cmd, ""), ",")
- return strings.Join(arr, ",")
-}
-
// getLabels converts the labels to a string of the form "key=value, key2=value2"
func formatLabels(labels map[string]string) string {
var arr []string
@@ -647,77 +581,3 @@ func portsToString(ports []ocicni.PortMapping) string {
}
return strings.Join(portDisplay, ", ")
}
-
-type batchContainerStruct struct {
- conConfig *libpod.ContainerConfig
- conState libpod.ContainerStatus
- exitCode int32
- pid int
- rootFsSize, rwSize int64
- startedTime time.Time
-}
-
-func batchContainerOp(ctr *libpod.Container, opts psOptions) (batchContainerStruct, error) {
- var (
- conConfig *libpod.ContainerConfig
- conState libpod.ContainerStatus
- err error
- exitCode int32
- pid int
- rootFsSize, rwSize int64
- startedTime time.Time
- )
-
- 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, 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)
- }
-
- 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")
- }
- }
- if opts.size {
- 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)
- }
-
- }
- return nil
- })
- if batchErr != nil {
- return batchContainerStruct{}, batchErr
- }
- return batchContainerStruct{
- conConfig: conConfig,
- conState: conState,
- exitCode: exitCode,
- pid: pid,
- rootFsSize: rootFsSize,
- rwSize: rwSize,
- startedTime: startedTime,
- }, nil
-}