summaryrefslogtreecommitdiff
path: root/cmd/kpod/ps.go
diff options
context:
space:
mode:
authorDaniel J Walsh <dwalsh@redhat.com>2017-12-15 16:58:36 -0500
committerAtomic Bot <atomic-devel@projectatomic.io>2017-12-18 16:46:05 +0000
commit5770dc2640c216525ab84031e3712fcc46b3b087 (patch)
tree8a1c5c4e4a6ce6a35a3767247623a62bfd698f77 /cmd/kpod/ps.go
parentde3468e120d489d046c08dad72ba2262e222ccb1 (diff)
downloadpodman-5770dc2640c216525ab84031e3712fcc46b3b087.tar.gz
podman-5770dc2640c216525ab84031e3712fcc46b3b087.tar.bz2
podman-5770dc2640c216525ab84031e3712fcc46b3b087.zip
Rename all references to kpod to podman
The decision is in, kpod is going to be named podman. Signed-off-by: Daniel J Walsh <dwalsh@redhat.com> Closes: #145 Approved by: umohnani8
Diffstat (limited to 'cmd/kpod/ps.go')
-rw-r--r--cmd/kpod/ps.go606
1 files changed, 0 insertions, 606 deletions
diff --git a/cmd/kpod/ps.go b/cmd/kpod/ps.go
deleted file mode 100644
index 6b807671e..000000000
--- a/cmd/kpod/ps.go
+++ /dev/null
@@ -1,606 +0,0 @@
-package main
-
-import (
- "fmt"
- "os"
- "path/filepath"
- "reflect"
- "regexp"
- "strconv"
- "strings"
- "time"
-
- "github.com/docker/go-units"
- specs "github.com/opencontainers/runtime-spec/specs-go"
- "github.com/pkg/errors"
- "github.com/projectatomic/libpod/cmd/kpod/formats"
- "github.com/projectatomic/libpod/libpod"
- "github.com/urfave/cli"
- "k8s.io/apimachinery/pkg/fields"
-)
-
-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
- Command string
- CreatedAt string
- RunningFor string
- Status string
- Ports string
- Size string
- Names string
- Labels string
- Mounts string
- PID int
- Cgroup string
- IPC string
- MNT string
- NET string
- PIDNS string
- User string
- UTS string
-}
-
-// psJSONParams is only used when the JSON format is specified,
-// and is better for data processing from JSON.
-// 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 map[string]struct{} `json:"ports"`
- Size uint `json:"size"`
- 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"`
-}
-
-var (
- psFlags = []cli.Flag{
- cli.BoolFlag{
- Name: "all, a",
- Usage: "Show all the containers, default is only running containers",
- },
- cli.StringFlag{
- Name: "filter, f",
- Usage: "Filter output based on conditions given",
- },
- cli.StringFlag{
- Name: "format",
- Usage: "Pretty-print containers to JSON or using a Go template",
- },
- cli.IntFlag{
- Name: "last, n",
- Usage: "Print the n last created containers (all states)",
- Value: -1,
- },
- cli.BoolFlag{
- Name: "latest, l",
- Usage: "Show the latest container created (all states)",
- },
- cli.BoolFlag{
- Name: "no-trunc",
- Usage: "Display the extended information",
- },
- cli.BoolFlag{
- Name: "quiet, q",
- Usage: "Print the numeric IDs of the containers only",
- },
- cli.BoolFlag{
- Name: "size, s",
- Usage: "Display the total file sizes",
- },
- cli.BoolFlag{
- Name: "namespace, ns",
- Usage: "Display namespace information",
- },
- }
- psDescription = "Prints out information about the containers"
- psCommand = cli.Command{
- Name: "ps",
- Usage: "List containers",
- Description: psDescription,
- Flags: psFlags,
- Action: psCmd,
- ArgsUsage: "",
- UseShortOptionHandling: true,
- }
-)
-
-func psCmd(c *cli.Context) error {
- if err := validateFlags(c, psFlags); err != nil {
- return err
- }
-
- if err := checkFlagsPassed(c); err != nil {
- return errors.Wrapf(err, "error with flags passed")
- }
-
- runtime, err := getRuntime(c)
- if err != nil {
- return errors.Wrapf(err, "error creating libpod runtime")
- }
-
- defer runtime.Shutdown(false)
-
- if len(c.Args()) > 0 {
- return errors.Errorf("too many arguments, ps takes no arguments")
- }
-
- 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"),
- }
-
- 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 {
- // only get running containers
- filterFuncs = append(filterFuncs, func(c *libpod.Container) bool {
- state, _ := c.State()
- return state == libpod.ContainerStateRunning
- })
- }
-
- if opts.filter != "" {
- filters := strings.Split(opts.filter, ",")
- for _, f := range filters {
- filterSplit := strings.Split(f, "=")
- if len(filterSplit) < 2 {
- return errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
- }
- generatedFunc, err := generateContainerFilterFuncs(filterSplit[0], filterSplit[1], runtime)
- if err != nil {
- return errors.Wrapf(err, "invalid filter")
- }
- filterFuncs = append(filterFuncs, generatedFunc)
- }
- }
-
- containers, err := runtime.GetContainers(filterFuncs...)
- var outputContainers []*libpod.Container
- 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 {
- outputContainers = containers
- }
-
- return generatePsOutput(outputContainers, opts)
-}
-
-// checkFlagsPassed checks if mutually exclusive flags are passed together
-func checkFlagsPassed(c *cli.Context) error {
- // latest, and last are mutually exclusive.
- if c.Int("last") >= 0 && c.Bool("latest") {
- return errors.Errorf("last and latest are mutually exclusive")
- }
- // quiet, size, namespace, and format with Go template are mutually exclusive
- flags := 0
- if c.Bool("quiet") {
- flags++
- }
- if c.Bool("size") {
- flags++
- }
- if c.Bool("namespace") {
- flags++
- }
- if c.IsSet("format") && c.String("format") != formats.JSONString {
- flags++
- }
- if flags > 1 {
- return errors.Errorf("quiet, size, namespace, and format with Go template are mutually exclusive")
- }
- return nil
-}
-
-func generateContainerFilterFuncs(filter, filterValue string, runtime *libpod.Runtime) (func(container *libpod.Container) bool, error) {
- switch filter {
- case "id":
- return func(c *libpod.Container) bool {
- return c.ID() == filterValue
- }, nil
- case "label":
- return func(c *libpod.Container) bool {
- for _, label := range c.Labels() {
- if label == filterValue {
- return true
- }
- }
- return false
- }, nil
- case "name":
- return func(c *libpod.Container) bool {
- return c.Name() == filterValue
- }, nil
- case "exited":
- exitCode, err := strconv.ParseInt(filterValue, 10, 32)
- if err != nil {
- return nil, errors.Wrapf(err, "exited code out of range %q", filterValue)
- }
- return func(c *libpod.Container) bool {
- ec, err := c.ExitCode()
- if ec == int32(exitCode) && err == nil {
- return true
- }
- return false
- }, nil
- case "status":
- if !libpod.StringInSlice(filterValue, []string{"created", "restarting", "running", "paused", "exited", "unknown"}) {
- return nil, errors.Errorf("%s is not a valid status", filterValue)
- }
- return func(c *libpod.Container) bool {
- status, err := c.State()
- if err != nil {
- return false
- }
- return status.String() == filterValue
- }, nil
- case "ancestor":
- // This needs to refine to match docker
- // - ancestor=(<image-name>[:tag]|<image-id>| ⟨image@digest⟩) - containers created from an image or a descendant.
- return func(c *libpod.Container) bool {
- containerConfig := c.Config()
- if containerConfig.RootfsImageID == filterValue || containerConfig.RootfsImageName == filterValue {
- return true
- }
- return false
- }, nil
- case "before":
- ctr, err := runtime.LookupContainer(filterValue)
- if err != nil {
- return nil, errors.Errorf("unable to find container by name or id of %s", filterValue)
- }
- containerConfig := ctr.Config()
- createTime := containerConfig.CreatedTime
- return func(c *libpod.Container) bool {
- cc := c.Config()
- return createTime.After(cc.CreatedTime)
- }, nil
- case "since":
- ctr, err := runtime.LookupContainer(filterValue)
- if err != nil {
- return nil, errors.Errorf("unable to find container by name or id of %s", filterValue)
- }
- containerConfig := ctr.Config()
- createTime := containerConfig.CreatedTime
- return func(c *libpod.Container) bool {
- cc := c.Config()
- return createTime.Before(cc.CreatedTime)
- }, nil
- case "volume":
- //- volume=(<volume-name>|<mount-point-destination>)
- return func(c *libpod.Container) bool {
- containerConfig := c.Config()
- //TODO We need to still lookup against volumes too
- return containerConfig.MountLabel == filterValue
- }, nil
- }
- return nil, errors.Errorf("%s is an invalid filter", filter)
-}
-
-// generate the template based on conditions given
-func genPsFormat(format string, quiet, size, namespace bool) string {
- if format != "" {
- // "\t" from the command line is not being recognized as a tab
- // replacing the string "\t" to a tab character if the user passes in "\t"
- return strings.Replace(format, `\t`, "\t", -1)
- }
- if quiet {
- return formats.IDString
- }
- if namespace {
- return "table {{.ID}}\t{{.Names}}\t{{.PID}}\t{{.Cgroup}}\t{{.IPC}}\t{{.MNT}}\t{{.NET}}\t{{.PIDNS}}\t{{.User}}\t{{.UTS}}\t"
- }
- format = "table {{.ID}}\t{{.Image}}\t{{.Command}}\t{{.CreatedAt}}\t{{.Status}}\t{{.Ports}}\t{{.Names}}\t"
- if size {
- format += "{{.Size}}\t"
- }
- return format
-}
-
-func psToGeneric(templParams []psTemplateParams, JSONParams []psJSONParams) (genericParams []interface{}) {
- if len(templParams) > 0 {
- for _, v := range templParams {
- genericParams = append(genericParams, interface{}(v))
- }
- return
- }
- for _, v := range JSONParams {
- genericParams = append(genericParams, interface{}(v))
- }
- return
-}
-
-// generate the accurate header based on template given
-func (p *psTemplateParams) headerMap() map[string]string {
- v := reflect.Indirect(reflect.ValueOf(p))
- values := make(map[string]string)
-
- for i := 0; i < v.NumField(); i++ {
- key := v.Type().Field(i).Name
- value := key
- if value == "ID" {
- value = "Container" + value
- }
- values[key] = strings.ToUpper(splitCamelCase(value))
- }
- return values
-}
-
-// getTemplateOutput returns the modified container information
-func getTemplateOutput(containers []*libpod.Container, opts psOptions) ([]psTemplateParams, error) {
- var psOutput []psTemplateParams
- var status string
- for _, ctr := range containers {
- ctrID := ctr.ID()
- conConfig := ctr.Config()
- conState, err := ctr.State()
- if err != nil {
- return psOutput, errors.Wrapf(err, "unable to obtain container state")
- }
- exitCode, err := ctr.ExitCode()
- if err != nil {
- return psOutput, errors.Wrapf(err, "unable to obtain container exit code")
- }
- pid, err := ctr.PID()
- if err != nil {
- return psOutput, errors.Wrapf(err, "unable to obtain container pid")
- }
- runningFor := units.HumanDuration(time.Since(conConfig.CreatedTime))
- createdAt := runningFor + " ago"
- imageName := conConfig.RootfsImageName
-
- // TODO We currently dont have the ability to get many of
- // these data items. Uncomment as progress is made
-
- //command := getStrFromSquareBrackets(ctr.ImageCreatedBy)
- command := strings.Join(ctr.Spec().Process.Args, " ")
- //mounts := getMounts(ctr.Mounts, opts.noTrunc)
- //ports := getPorts(ctr.Config.ExposedPorts)
- //size := units.HumanSize(float64(ctr.SizeRootFs))
- labels := formatLabels(ctr.Labels())
- ns := getNamespaces(pid)
-
- switch conState {
- case libpod.ContainerStateStopped:
- status = fmt.Sprintf("Exited (%d) %s ago", exitCode, runningFor)
- case libpod.ContainerStateRunning:
- status = "Up " + runningFor + " ago"
- case libpod.ContainerStatePaused:
- status = "Paused"
- case libpod.ContainerStateCreated:
- status = "Created"
- default:
- status = "Dead"
- }
-
- if !opts.noTrunc {
- ctrID = ctr.ID()[:idTruncLength]
- imageName = conConfig.RootfsImageName
- }
-
- // TODO We currently dont have the ability to get many of
- // these data items. Uncomment as progress is made
-
- params := psTemplateParams{
- ID: ctrID,
- Image: imageName,
- Command: command,
- CreatedAt: createdAt,
- RunningFor: runningFor,
- Status: status,
- //Ports: ports,
- //Size: size,
- Names: ctr.Name(),
- Labels: labels,
- //Mounts: mounts,
- PID: pid,
- Cgroup: ns.Cgroup,
- IPC: ns.IPC,
- MNT: ns.MNT,
- NET: ns.NET,
- PIDNS: ns.PID,
- User: ns.User,
- UTS: ns.UTS,
- }
- psOutput = append(psOutput, params)
- }
- 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, nSpace bool) ([]psJSONParams, error) {
- var psOutput []psJSONParams
- var ns *namespace
- for _, ctr := range containers {
- pid, err := ctr.PID()
- if err != nil {
- return psOutput, errors.Wrapf(err, "unable to obtain container pid")
- }
- if nSpace {
- ns = getNamespaces(pid)
- }
- cc := ctr.Config()
- conState, err := ctr.State()
- if err != nil {
- return psOutput, errors.Wrapf(err, "unable to obtain container state for JSON output")
- }
- params := psJSONParams{
- // TODO When we have ability to obtain the commented out data, we need
- // TODO to add it
- ID: ctr.ID(),
- Image: cc.RootfsImageName,
- ImageID: cc.RootfsImageID,
- //Command: getStrFromSquareBrackets(ctr.ImageCreatedBy),
- Command: strings.Join(ctr.Spec().Process.Args, " "),
- CreatedAt: cc.CreatedTime,
- RunningFor: time.Since(cc.CreatedTime),
- Status: conState.String(),
- //Ports: cc.Spec.Linux.Resources.Network.
- //Size: ctr.SizeRootFs,
- Names: cc.Name,
- Labels: cc.Labels,
- Mounts: cc.Spec.Mounts,
- ContainerRunning: conState == libpod.ContainerStateRunning,
- Namespaces: ns,
- }
- psOutput = append(psOutput, params)
- }
- return psOutput, nil
-}
-
-func generatePsOutput(containers []*libpod.Container, opts psOptions) error {
- if len(containers) == 0 && opts.format != formats.JSONString {
- return nil
- }
- var out formats.Writer
-
- switch opts.format {
- case formats.JSONString:
- psOutput, err := getJSONOutput(containers, opts.namespace)
- if err != nil {
- return errors.Wrapf(err, "unable to create JSON for output")
- }
- out = formats.JSONStructArray{Output: psToGeneric([]psTemplateParams{}, psOutput)}
- default:
- psOutput, err := getTemplateOutput(containers, opts)
- 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()}
- }
-
- 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
- if len(labels) > 0 {
- for key, val := range labels {
- temp := key + "=" + val
- arr = append(arr, temp)
- }
- return strings.Join(arr, ",")
- }
- return ""
-}
-
-/*
-// getMounts converts the volumes mounted to a string of the form "mount1, mount2"
-// it truncates it if noTrunc is false
-func getMounts(mounts []specs.Mount, noTrunc bool) string {
- var arr []string
- if len(mounts) == 0 {
- return ""
- }
- for _, mount := range mounts {
- if noTrunc {
- arr = append(arr, mount.Source)
- continue
- }
- tempArr := strings.SplitAfter(mount.Source, "/")
- if len(tempArr) >= 3 {
- arr = append(arr, strings.Join(tempArr[:3], ""))
- } else {
- arr = append(arr, mount.Source)
- }
- }
- return strings.Join(arr, ",")
-}
-// getPorts converts the ports used to a string of the from "port1, port2"
-func getPorts(ports map[string]struct{}) string {
- var arr []string
- if len(ports) == 0 {
- return ""
- }
- for key := range ports {
- arr = append(arr, key)
- }
- return strings.Join(arr, ",")
-}
-*/