From 8d5e0108d7c8b69abb9821bfe55475ae5d663b3a Mon Sep 17 00:00:00 2001 From: haircommander Date: Tue, 14 Aug 2018 17:16:22 -0400 Subject: Change batchcontainer to shared To better reflect it's usage: to share functions between podman and varlink. Signed-off-by: haircommander Closes: #1275 Approved by: mheon --- cmd/podman/batchcontainer/container.go | 328 --------------------------------- cmd/podman/inspect.go | 6 +- cmd/podman/pod_ps.go | 12 +- cmd/podman/ps.go | 56 +++--- cmd/podman/shared/.pod.go.swp | Bin 0 -> 12288 bytes cmd/podman/shared/container.go | 328 +++++++++++++++++++++++++++++++++ cmd/podman/shared/pod.go | 62 +++++++ 7 files changed, 427 insertions(+), 365 deletions(-) delete mode 100644 cmd/podman/batchcontainer/container.go create mode 100644 cmd/podman/shared/.pod.go.swp create mode 100644 cmd/podman/shared/container.go create mode 100644 cmd/podman/shared/pod.go (limited to 'cmd') diff --git a/cmd/podman/batchcontainer/container.go b/cmd/podman/batchcontainer/container.go deleted file mode 100644 index 364b28d40..000000000 --- a/cmd/podman/batchcontainer/container.go +++ /dev/null @@ -1,328 +0,0 @@ -package batchcontainer - -import ( - "encoding/json" - "os" - "path/filepath" - "regexp" - "strconv" - "strings" - "time" - - "github.com/containers/libpod/libpod" - "github.com/containers/libpod/pkg/inspect" - cc "github.com/containers/libpod/pkg/spec" - "github.com/opencontainers/runtime-spec/specs-go" - "github.com/pkg/errors" - "github.com/sirupsen/logrus" -) - -// PsOptions describes the struct being formed for ps -type PsOptions struct { - All bool - Filter string - Format string - Last int - Latest bool - NoTrunc bool - Pod bool - Quiet bool - Size bool - Sort string - Label string - Namespace bool -} - -// BatchContainerStruct is the return obkect from BatchContainer and contains -// container related information -type BatchContainerStruct struct { - ConConfig *libpod.ContainerConfig - ConState libpod.ContainerStatus - ExitCode int32 - Exited bool - Pid int - StartedTime time.Time - ExitedTime time.Time - Size *ContainerSize -} - -// Namespace describes output for ps namespace -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"` -} - -// ContainerSize holds the size of the container's root filesystem and top -// read-write layer -type ContainerSize struct { - RootFsSize int64 `json:"rootFsSize"` - RwSize int64 `json:"rwSize"` -} - -// BatchContainer is used in ps to reduce performance hits by "batching" -// locks. -func BatchContainerOp(ctr *libpod.Container, opts PsOptions) (BatchContainerStruct, error) { - var ( - conConfig *libpod.ContainerConfig - conState libpod.ContainerStatus - err error - exitCode int32 - exited bool - pid int - size *ContainerSize - startedTime time.Time - exitedTime 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, 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") - } - } - if opts.Size { - size = new(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 BatchContainerStruct{}, batchErr - } - return BatchContainerStruct{ - ConConfig: conConfig, - ConState: conState, - ExitCode: exitCode, - Exited: exited, - Pid: pid, - StartedTime: startedTime, - ExitedTime: exitedTime, - Size: size, - }, nil -} - -// GetNamespaces returns a populated namespace struct -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 -} - -// 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, ",") -} - -// GetCtrInspectInfo takes container inspect data and collects all its info into a ContainerData -// structure for inspection related methods -func GetCtrInspectInfo(ctr *libpod.Container, ctrInspectData *inspect.ContainerInspectData) (*inspect.ContainerData, error) { - config := ctr.Config() - spec := config.Spec - - cpus, mems, period, quota, realtimePeriod, realtimeRuntime, shares := getCPUInfo(spec) - blkioWeight, blkioWeightDevice, blkioReadBps, blkioWriteBps, blkioReadIOPS, blkioeWriteIOPS := getBLKIOInfo(spec) - memKernel, memReservation, memSwap, memSwappiness, memDisableOOMKiller := getMemoryInfo(spec) - pidsLimit := getPidsInfo(spec) - cgroup := getCgroup(spec) - - var createArtifact cc.CreateConfig - artifact, err := ctr.GetArtifact("create-config") - if err == nil { - if err := json.Unmarshal(artifact, &createArtifact); err != nil { - return nil, err - } - } else { - logrus.Errorf("couldn't get some inspect information, error getting artifact %q: %v", ctr.ID(), err) - } - - data := &inspect.ContainerData{ - ctrInspectData, - &inspect.HostConfig{ - ConsoleSize: spec.Process.ConsoleSize, - OomScoreAdj: spec.Process.OOMScoreAdj, - CPUShares: shares, - BlkioWeight: blkioWeight, - BlkioWeightDevice: blkioWeightDevice, - BlkioDeviceReadBps: blkioReadBps, - BlkioDeviceWriteBps: blkioWriteBps, - BlkioDeviceReadIOps: blkioReadIOPS, - BlkioDeviceWriteIOps: blkioeWriteIOPS, - CPUPeriod: period, - CPUQuota: quota, - CPURealtimePeriod: realtimePeriod, - CPURealtimeRuntime: realtimeRuntime, - CPUSetCPUs: cpus, - CPUSetMems: mems, - Devices: spec.Linux.Devices, - KernelMemory: memKernel, - MemoryReservation: memReservation, - MemorySwap: memSwap, - MemorySwappiness: memSwappiness, - OomKillDisable: memDisableOOMKiller, - PidsLimit: pidsLimit, - Privileged: config.Privileged, - ReadonlyRootfs: spec.Root.Readonly, - Runtime: ctr.RuntimeName(), - NetworkMode: string(createArtifact.NetMode), - IpcMode: string(createArtifact.IpcMode), - Cgroup: cgroup, - UTSMode: string(createArtifact.UtsMode), - UsernsMode: string(createArtifact.UsernsMode), - GroupAdd: spec.Process.User.AdditionalGids, - ContainerIDFile: createArtifact.CidFile, - AutoRemove: createArtifact.Rm, - CapAdd: createArtifact.CapAdd, - CapDrop: createArtifact.CapDrop, - DNS: createArtifact.DNSServers, - DNSOptions: createArtifact.DNSOpt, - DNSSearch: createArtifact.DNSSearch, - PidMode: string(createArtifact.PidMode), - CgroupParent: createArtifact.CgroupParent, - ShmSize: createArtifact.Resources.ShmSize, - Memory: createArtifact.Resources.Memory, - Ulimits: createArtifact.Resources.Ulimit, - SecurityOpt: createArtifact.SecurityOpts, - Tmpfs: createArtifact.Tmpfs, - }, - &inspect.CtrConfig{ - Hostname: spec.Hostname, - User: spec.Process.User, - Env: spec.Process.Env, - Image: config.RootfsImageName, - WorkingDir: spec.Process.Cwd, - Labels: config.Labels, - Annotations: spec.Annotations, - Tty: spec.Process.Terminal, - OpenStdin: config.Stdin, - StopSignal: config.StopSignal, - Cmd: config.Spec.Process.Args, - Entrypoint: strings.Join(createArtifact.Entrypoint, " "), - }, - } - return data, nil -} - -func getCPUInfo(spec *specs.Spec) (string, string, *uint64, *int64, *uint64, *int64, *uint64) { - if spec.Linux.Resources == nil { - return "", "", nil, nil, nil, nil, nil - } - cpu := spec.Linux.Resources.CPU - if cpu == nil { - return "", "", nil, nil, nil, nil, nil - } - return cpu.Cpus, cpu.Mems, cpu.Period, cpu.Quota, cpu.RealtimePeriod, cpu.RealtimeRuntime, cpu.Shares -} - -func getBLKIOInfo(spec *specs.Spec) (*uint16, []specs.LinuxWeightDevice, []specs.LinuxThrottleDevice, []specs.LinuxThrottleDevice, []specs.LinuxThrottleDevice, []specs.LinuxThrottleDevice) { - if spec.Linux.Resources == nil { - return nil, nil, nil, nil, nil, nil - } - blkio := spec.Linux.Resources.BlockIO - if blkio == nil { - return nil, nil, nil, nil, nil, nil - } - return blkio.Weight, blkio.WeightDevice, blkio.ThrottleReadBpsDevice, blkio.ThrottleWriteBpsDevice, blkio.ThrottleReadIOPSDevice, blkio.ThrottleWriteIOPSDevice -} - -func getMemoryInfo(spec *specs.Spec) (*int64, *int64, *int64, *uint64, *bool) { - if spec.Linux.Resources == nil { - return nil, nil, nil, nil, nil - } - memory := spec.Linux.Resources.Memory - if memory == nil { - return nil, nil, nil, nil, nil - } - return memory.Kernel, memory.Reservation, memory.Swap, memory.Swappiness, memory.DisableOOMKiller -} - -func getPidsInfo(spec *specs.Spec) *int64 { - if spec.Linux.Resources == nil { - return nil - } - pids := spec.Linux.Resources.Pids - if pids == nil { - return nil - } - return &pids.Limit -} - -func getCgroup(spec *specs.Spec) string { - cgroup := "host" - for _, ns := range spec.Linux.Namespaces { - if ns.Type == specs.CgroupNamespace && ns.Path != "" { - cgroup = "container" - } - } - return cgroup -} diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go index 1fa8f55a2..a36f8c7a1 100644 --- a/cmd/podman/inspect.go +++ b/cmd/podman/inspect.go @@ -4,9 +4,9 @@ import ( "context" "strings" - "github.com/containers/libpod/cmd/podman/batchcontainer" "github.com/containers/libpod/cmd/podman/formats" "github.com/containers/libpod/cmd/podman/libpodruntime" + "github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/libpod" "github.com/containers/libpod/pkg/util" "github.com/pkg/errors" @@ -121,7 +121,7 @@ func iterateInput(ctx context.Context, c *cli.Context, args []string, runtime *l inspectError = errors.Wrapf(err, "error getting libpod container inspect data %q", ctr.ID) break } - data, err = batchcontainer.GetCtrInspectInfo(ctr, libpodInspectData) + data, err = shared.GetCtrInspectInfo(ctr, libpodInspectData) if err != nil { inspectError = errors.Wrapf(err, "error parsing container data %q", ctr.ID()) break @@ -156,7 +156,7 @@ func iterateInput(ctx context.Context, c *cli.Context, args []string, runtime *l inspectError = errors.Wrapf(err, "error getting libpod container inspect data %q", ctr.ID) break } - data, err = batchcontainer.GetCtrInspectInfo(ctr, libpodInspectData) + data, err = shared.GetCtrInspectInfo(ctr, libpodInspectData) if err != nil { inspectError = errors.Wrapf(err, "error parsing container data %q", ctr.ID) break diff --git a/cmd/podman/pod_ps.go b/cmd/podman/pod_ps.go index 52fbea6e5..20beae53a 100644 --- a/cmd/podman/pod_ps.go +++ b/cmd/podman/pod_ps.go @@ -7,9 +7,9 @@ import ( "strings" "time" - "github.com/containers/libpod/cmd/podman/batchcontainer" "github.com/containers/libpod/cmd/podman/formats" "github.com/containers/libpod/cmd/podman/libpodruntime" + "github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/libpod" "github.com/containers/libpod/pkg/util" "github.com/docker/go-units" @@ -28,7 +28,7 @@ const ( ) var ( - bc_opts batchcontainer.PsOptions + bc_opts shared.PsOptions ) type podPsCtrInfo struct { @@ -296,7 +296,7 @@ func generatePodFilterFuncs(filter, filterValue string, runtime *libpod.Runtime) return nil, errors.Errorf("%s is not a valid status", filterValue) } return func(p *libpod.Pod) bool { - ctr_statuses, err := p.ContainerStatus() + ctr_statuses, err := p.Status() if err != nil { return false } @@ -324,7 +324,7 @@ func generatePodFilterFuncs(filter, filterValue string, runtime *libpod.Runtime) return nil, errors.Errorf("%s is not a valid pod status", filterValue) } return func(p *libpod.Pod) bool { - status, err := p.Status() + status, err := shared.GetPodStatus(p) if err != nil { return false } @@ -473,13 +473,13 @@ func getAndSortPodJSONParams(pods []*libpod.Pod, opts podPsOptions, runtime *lib return nil, err } ctrNum := len(ctrs) - status, err := pod.Status() + status, err := shared.GetPodStatus(pod) if err != nil { return nil, err } for _, ctr := range ctrs { - batchInfo, err := batchcontainer.BatchContainerOp(ctr, bc_opts) + batchInfo, err := shared.BatchContainerOp(ctr, bc_opts) if err != nil { return nil, err } diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go index 94e8a4920..0ad511217 100644 --- a/cmd/podman/ps.go +++ b/cmd/podman/ps.go @@ -8,9 +8,9 @@ import ( "strings" "time" - "github.com/containers/libpod/cmd/podman/batchcontainer" "github.com/containers/libpod/cmd/podman/formats" "github.com/containers/libpod/cmd/podman/libpodruntime" + "github.com/containers/libpod/cmd/podman/shared" "github.com/containers/libpod/libpod" "github.com/containers/libpod/pkg/util" "github.com/cri-o/ocicni/pkg/ocicni" @@ -52,25 +52,25 @@ 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"` - ExitCode int32 `json:"exitCode"` - Exited bool `json:"exited"` - CreatedAt time.Time `json:"createdAt"` - StartedAt time.Time `json:"startedAt"` - ExitedAt time.Time `json:"exitedAt"` - Status string `json:"status"` - PID int `json:"PID"` - Ports []ocicni.PortMapping `json:"ports"` - Size *batchcontainer.ContainerSize `json:"size,omitempty"` - Names string `json:"names"` - Labels fields.Set `json:"labels"` - Mounts []string `json:"mounts"` - ContainerRunning bool `json:"ctrRunning"` - Namespaces *batchcontainer.Namespace `json:"namespace,omitempty"` - Pod string `json:"pod,omitempty"` + ID string `json:"id"` + Image string `json:"image"` + ImageID string `json:"image_id"` + Command []string `json:"command"` + ExitCode int32 `json:"exitCode"` + Exited bool `json:"exited"` + CreatedAt time.Time `json:"createdAt"` + StartedAt time.Time `json:"startedAt"` + ExitedAt time.Time `json:"exitedAt"` + Status string `json:"status"` + PID int `json:"PID"` + Ports []ocicni.PortMapping `json:"ports"` + Size *shared.ContainerSize `json:"size,omitempty"` + Names string `json:"names"` + Labels fields.Set `json:"labels"` + Mounts []string `json:"mounts"` + ContainerRunning bool `json:"ctrRunning"` + Namespaces *shared.Namespace `json:"namespace,omitempty"` + Pod string `json:"pod,omitempty"` } // Type declaration and functions for sorting the PS output @@ -218,7 +218,7 @@ func psCmd(c *cli.Context) error { format := genPsFormat(c.String("format"), c.Bool("quiet"), c.Bool("size"), c.Bool("namespace"), c.Bool("pod")) - opts := batchcontainer.PsOptions{ + opts := shared.PsOptions{ All: c.Bool("all"), Filter: c.String("filter"), Format: format, @@ -497,11 +497,11 @@ func sortPsOutput(sortBy string, psOutput psSorted) (psSorted, error) { } // getTemplateOutput returns the modified container information -func getTemplateOutput(psParams []psJSONParams, opts batchcontainer.PsOptions) ([]psTemplateParams, error) { +func getTemplateOutput(psParams []psJSONParams, opts shared.PsOptions) ([]psTemplateParams, error) { var ( psOutput []psTemplateParams pod, status, size string - ns *batchcontainer.Namespace + ns *shared.Namespace ) // If the user is trying to filter based on size, or opted to sort on size // the size bool must be set. @@ -589,13 +589,13 @@ func getTemplateOutput(psParams []psJSONParams, opts batchcontainer.PsOptions) ( } // getAndSortJSONOutput returns the container info in its raw, sorted form -func getAndSortJSONParams(containers []*libpod.Container, opts batchcontainer.PsOptions) ([]psJSONParams, error) { +func getAndSortJSONParams(containers []*libpod.Container, opts shared.PsOptions) ([]psJSONParams, error) { var ( psOutput psSorted - ns *batchcontainer.Namespace + ns *shared.Namespace ) for _, ctr := range containers { - batchInfo, err := batchcontainer.BatchContainerOp(ctr, opts) + batchInfo, err := shared.BatchContainerOp(ctr, opts) if err != nil { if errors.Cause(err) == libpod.ErrNoSuchCtr { logrus.Warn(err) @@ -605,7 +605,7 @@ func getAndSortJSONParams(containers []*libpod.Container, opts batchcontainer.Ps } if opts.Namespace { - ns = batchcontainer.GetNamespaces(batchInfo.Pid) + ns = shared.GetNamespaces(batchInfo.Pid) } params := psJSONParams{ ID: ctr.ID(), @@ -634,7 +634,7 @@ func getAndSortJSONParams(containers []*libpod.Container, opts batchcontainer.Ps return sortPsOutput(opts.Sort, psOutput) } -func generatePsOutput(containers []*libpod.Container, opts batchcontainer.PsOptions) error { +func generatePsOutput(containers []*libpod.Container, opts shared.PsOptions) error { if len(containers) == 0 && opts.Format != formats.JSONString { return nil } diff --git a/cmd/podman/shared/.pod.go.swp b/cmd/podman/shared/.pod.go.swp new file mode 100644 index 000000000..a8565e752 Binary files /dev/null and b/cmd/podman/shared/.pod.go.swp differ diff --git a/cmd/podman/shared/container.go b/cmd/podman/shared/container.go new file mode 100644 index 000000000..7a5455046 --- /dev/null +++ b/cmd/podman/shared/container.go @@ -0,0 +1,328 @@ +package shared + +import ( + "encoding/json" + "os" + "path/filepath" + "regexp" + "strconv" + "strings" + "time" + + "github.com/containers/libpod/libpod" + "github.com/containers/libpod/pkg/inspect" + cc "github.com/containers/libpod/pkg/spec" + "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +// PsOptions describes the struct being formed for ps +type PsOptions struct { + All bool + Filter string + Format string + Last int + Latest bool + NoTrunc bool + Pod bool + Quiet bool + Size bool + Sort string + Label string + Namespace bool +} + +// BatchContainerStruct is the return obkect from BatchContainer and contains +// container related information +type BatchContainerStruct struct { + ConConfig *libpod.ContainerConfig + ConState libpod.ContainerStatus + ExitCode int32 + Exited bool + Pid int + StartedTime time.Time + ExitedTime time.Time + Size *ContainerSize +} + +// Namespace describes output for ps namespace +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"` +} + +// ContainerSize holds the size of the container's root filesystem and top +// read-write layer +type ContainerSize struct { + RootFsSize int64 `json:"rootFsSize"` + RwSize int64 `json:"rwSize"` +} + +// BatchContainer is used in ps to reduce performance hits by "batching" +// locks. +func BatchContainerOp(ctr *libpod.Container, opts PsOptions) (BatchContainerStruct, error) { + var ( + conConfig *libpod.ContainerConfig + conState libpod.ContainerStatus + err error + exitCode int32 + exited bool + pid int + size *ContainerSize + startedTime time.Time + exitedTime 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, 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") + } + } + if opts.Size { + size = new(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 BatchContainerStruct{}, batchErr + } + return BatchContainerStruct{ + ConConfig: conConfig, + ConState: conState, + ExitCode: exitCode, + Exited: exited, + Pid: pid, + StartedTime: startedTime, + ExitedTime: exitedTime, + Size: size, + }, nil +} + +// GetNamespaces returns a populated namespace struct +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 +} + +// 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, ",") +} + +// GetCtrInspectInfo takes container inspect data and collects all its info into a ContainerData +// structure for inspection related methods +func GetCtrInspectInfo(ctr *libpod.Container, ctrInspectData *inspect.ContainerInspectData) (*inspect.ContainerData, error) { + config := ctr.Config() + spec := config.Spec + + cpus, mems, period, quota, realtimePeriod, realtimeRuntime, shares := getCPUInfo(spec) + blkioWeight, blkioWeightDevice, blkioReadBps, blkioWriteBps, blkioReadIOPS, blkioeWriteIOPS := getBLKIOInfo(spec) + memKernel, memReservation, memSwap, memSwappiness, memDisableOOMKiller := getMemoryInfo(spec) + pidsLimit := getPidsInfo(spec) + cgroup := getCgroup(spec) + + var createArtifact cc.CreateConfig + artifact, err := ctr.GetArtifact("create-config") + if err == nil { + if err := json.Unmarshal(artifact, &createArtifact); err != nil { + return nil, err + } + } else { + logrus.Errorf("couldn't get some inspect information, error getting artifact %q: %v", ctr.ID(), err) + } + + data := &inspect.ContainerData{ + ctrInspectData, + &inspect.HostConfig{ + ConsoleSize: spec.Process.ConsoleSize, + OomScoreAdj: spec.Process.OOMScoreAdj, + CPUShares: shares, + BlkioWeight: blkioWeight, + BlkioWeightDevice: blkioWeightDevice, + BlkioDeviceReadBps: blkioReadBps, + BlkioDeviceWriteBps: blkioWriteBps, + BlkioDeviceReadIOps: blkioReadIOPS, + BlkioDeviceWriteIOps: blkioeWriteIOPS, + CPUPeriod: period, + CPUQuota: quota, + CPURealtimePeriod: realtimePeriod, + CPURealtimeRuntime: realtimeRuntime, + CPUSetCPUs: cpus, + CPUSetMems: mems, + Devices: spec.Linux.Devices, + KernelMemory: memKernel, + MemoryReservation: memReservation, + MemorySwap: memSwap, + MemorySwappiness: memSwappiness, + OomKillDisable: memDisableOOMKiller, + PidsLimit: pidsLimit, + Privileged: config.Privileged, + ReadonlyRootfs: spec.Root.Readonly, + Runtime: ctr.RuntimeName(), + NetworkMode: string(createArtifact.NetMode), + IpcMode: string(createArtifact.IpcMode), + Cgroup: cgroup, + UTSMode: string(createArtifact.UtsMode), + UsernsMode: string(createArtifact.UsernsMode), + GroupAdd: spec.Process.User.AdditionalGids, + ContainerIDFile: createArtifact.CidFile, + AutoRemove: createArtifact.Rm, + CapAdd: createArtifact.CapAdd, + CapDrop: createArtifact.CapDrop, + DNS: createArtifact.DNSServers, + DNSOptions: createArtifact.DNSOpt, + DNSSearch: createArtifact.DNSSearch, + PidMode: string(createArtifact.PidMode), + CgroupParent: createArtifact.CgroupParent, + ShmSize: createArtifact.Resources.ShmSize, + Memory: createArtifact.Resources.Memory, + Ulimits: createArtifact.Resources.Ulimit, + SecurityOpt: createArtifact.SecurityOpts, + Tmpfs: createArtifact.Tmpfs, + }, + &inspect.CtrConfig{ + Hostname: spec.Hostname, + User: spec.Process.User, + Env: spec.Process.Env, + Image: config.RootfsImageName, + WorkingDir: spec.Process.Cwd, + Labels: config.Labels, + Annotations: spec.Annotations, + Tty: spec.Process.Terminal, + OpenStdin: config.Stdin, + StopSignal: config.StopSignal, + Cmd: config.Spec.Process.Args, + Entrypoint: strings.Join(createArtifact.Entrypoint, " "), + }, + } + return data, nil +} + +func getCPUInfo(spec *specs.Spec) (string, string, *uint64, *int64, *uint64, *int64, *uint64) { + if spec.Linux.Resources == nil { + return "", "", nil, nil, nil, nil, nil + } + cpu := spec.Linux.Resources.CPU + if cpu == nil { + return "", "", nil, nil, nil, nil, nil + } + return cpu.Cpus, cpu.Mems, cpu.Period, cpu.Quota, cpu.RealtimePeriod, cpu.RealtimeRuntime, cpu.Shares +} + +func getBLKIOInfo(spec *specs.Spec) (*uint16, []specs.LinuxWeightDevice, []specs.LinuxThrottleDevice, []specs.LinuxThrottleDevice, []specs.LinuxThrottleDevice, []specs.LinuxThrottleDevice) { + if spec.Linux.Resources == nil { + return nil, nil, nil, nil, nil, nil + } + blkio := spec.Linux.Resources.BlockIO + if blkio == nil { + return nil, nil, nil, nil, nil, nil + } + return blkio.Weight, blkio.WeightDevice, blkio.ThrottleReadBpsDevice, blkio.ThrottleWriteBpsDevice, blkio.ThrottleReadIOPSDevice, blkio.ThrottleWriteIOPSDevice +} + +func getMemoryInfo(spec *specs.Spec) (*int64, *int64, *int64, *uint64, *bool) { + if spec.Linux.Resources == nil { + return nil, nil, nil, nil, nil + } + memory := spec.Linux.Resources.Memory + if memory == nil { + return nil, nil, nil, nil, nil + } + return memory.Kernel, memory.Reservation, memory.Swap, memory.Swappiness, memory.DisableOOMKiller +} + +func getPidsInfo(spec *specs.Spec) *int64 { + if spec.Linux.Resources == nil { + return nil + } + pids := spec.Linux.Resources.Pids + if pids == nil { + return nil + } + return &pids.Limit +} + +func getCgroup(spec *specs.Spec) string { + cgroup := "host" + for _, ns := range spec.Linux.Namespaces { + if ns.Type == specs.CgroupNamespace && ns.Path != "" { + cgroup = "container" + } + } + return cgroup +} diff --git a/cmd/podman/shared/pod.go b/cmd/podman/shared/pod.go new file mode 100644 index 000000000..50c642d59 --- /dev/null +++ b/cmd/podman/shared/pod.go @@ -0,0 +1,62 @@ +package shared + +import ( + "github.com/projectatomic/libpod/libpod" +) + +const ( + stopped = "Stopped" + running = "Running" + paused = "Paused" + exited = "Exited" + errored = "Error" + created = "Created" +) + +// GetPodStatus determines the status of the pod based on the +// statuses of the containers in the pod. +// Returns a string representation of the pod status +func GetPodStatus(pod *libpod.Pod) (string, error) { + ctrStatuses, err := pod.Status() + if err != nil { + return errored, err + } + ctrNum := len(ctrStatuses) + if ctrNum == 0 { + return created, nil + } + statuses := map[string]int{ + stopped: 0, + running: 0, + paused: 0, + created: 0, + errored: 0, + } + for _, ctrStatus := range ctrStatuses { + switch ctrStatus { + case libpod.ContainerStateStopped: + statuses[stopped]++ + case libpod.ContainerStateRunning: + statuses[running]++ + case libpod.ContainerStatePaused: + statuses[paused]++ + case libpod.ContainerStateCreated, libpod.ContainerStateConfigured: + statuses[created]++ + default: + statuses[errored]++ + } + } + + if statuses[running] > 0 { + return running, nil + } else if statuses[paused] == ctrNum { + return paused, nil + } else if statuses[stopped] == ctrNum { + return exited, nil + } else if statuses[stopped] > 0 { + return stopped, nil + } else if statuses[errored] > 0 { + return errored, nil + } + return created, nil +} -- cgit v1.2.3-54-g00ecf