mirror of
https://github.com/containers/podman.git
synced 2025-06-25 12:20:42 +08:00
Merge pull request #5808 from baude/v2psformat2
v2podman ps revert structure changes
This commit is contained in:
@ -4,6 +4,8 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
"text/template"
|
"text/template"
|
||||||
@ -13,6 +15,8 @@ import (
|
|||||||
"github.com/containers/buildah/pkg/formats"
|
"github.com/containers/buildah/pkg/formats"
|
||||||
"github.com/containers/libpod/cmd/podmanV2/registry"
|
"github.com/containers/libpod/cmd/podmanV2/registry"
|
||||||
"github.com/containers/libpod/pkg/domain/entities"
|
"github.com/containers/libpod/pkg/domain/entities"
|
||||||
|
"github.com/cri-o/ocicni/pkg/ocicni"
|
||||||
|
"github.com/docker/go-units"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@ -134,6 +138,7 @@ func getResponses() ([]entities.ListContainer, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ps(cmd *cobra.Command, args []string) error {
|
func ps(cmd *cobra.Command, args []string) error {
|
||||||
|
var responses []psReporter
|
||||||
for _, f := range filters {
|
for _, f := range filters {
|
||||||
split := strings.SplitN(f, "=", 2)
|
split := strings.SplitN(f, "=", 2)
|
||||||
if len(split) == 1 {
|
if len(split) == 1 {
|
||||||
@ -141,22 +146,27 @@ func ps(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
listOpts.Filters[split[0]] = append(listOpts.Filters[split[0]], split[1])
|
listOpts.Filters[split[0]] = append(listOpts.Filters[split[0]], split[1])
|
||||||
}
|
}
|
||||||
responses, err := getResponses()
|
listContainers, err := getResponses()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if len(listOpts.Sort) > 0 {
|
if len(listOpts.Sort) > 0 {
|
||||||
responses, err = entities.SortPsOutput(listOpts.Sort, responses)
|
listContainers, err = entities.SortPsOutput(listOpts.Sort, listContainers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if listOpts.Format == "json" {
|
if listOpts.Format == "json" {
|
||||||
return jsonOut(responses)
|
return jsonOut(listContainers)
|
||||||
}
|
}
|
||||||
if listOpts.Quiet {
|
if listOpts.Quiet {
|
||||||
return quietOut(responses)
|
return quietOut(listContainers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, r := range listContainers {
|
||||||
|
responses = append(responses, psReporter{r})
|
||||||
|
}
|
||||||
|
|
||||||
headers, row := createPsOut()
|
headers, row := createPsOut()
|
||||||
if cmd.Flag("format").Changed {
|
if cmd.Flag("format").Changed {
|
||||||
row = listOpts.Format
|
row = listOpts.Format
|
||||||
@ -175,10 +185,14 @@ func ps(cmd *cobra.Command, args []string) error {
|
|||||||
w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0)
|
w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0)
|
||||||
if listOpts.Watch > 0 {
|
if listOpts.Watch > 0 {
|
||||||
for {
|
for {
|
||||||
|
var responses []psReporter
|
||||||
tm.Clear()
|
tm.Clear()
|
||||||
tm.MoveCursor(1, 1)
|
tm.MoveCursor(1, 1)
|
||||||
tm.Flush()
|
tm.Flush()
|
||||||
responses, err := getResponses()
|
listContainers, err := getResponses()
|
||||||
|
for _, r := range listContainers {
|
||||||
|
responses = append(responses, psReporter{r})
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -210,21 +224,12 @@ func createPsOut() (string, string) {
|
|||||||
return headers, row
|
return headers, row
|
||||||
}
|
}
|
||||||
headers := defaultHeaders
|
headers := defaultHeaders
|
||||||
if noTrunc {
|
row += "{{.ID}}"
|
||||||
row += "{{.ID}}"
|
|
||||||
} else {
|
|
||||||
row += "{{slice .ID 0 12}}"
|
|
||||||
}
|
|
||||||
row += "\t{{.Image}}\t{{.Command}}\t{{.CreatedHuman}}\t{{.State}}\t{{.Ports}}\t{{.Names}}"
|
row += "\t{{.Image}}\t{{.Command}}\t{{.CreatedHuman}}\t{{.State}}\t{{.Ports}}\t{{.Names}}"
|
||||||
|
|
||||||
if listOpts.Pod {
|
if listOpts.Pod {
|
||||||
headers += "\tPOD ID\tPODNAME"
|
headers += "\tPOD ID\tPODNAME"
|
||||||
if noTrunc {
|
row += "\t{{.Pod}}\t{{.PodName}}"
|
||||||
row += "\t{{.Pod}}"
|
|
||||||
} else {
|
|
||||||
row += "\t{{slice .Pod 0 12}}"
|
|
||||||
}
|
|
||||||
row += "\t{{.PodName}}"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if listOpts.Size {
|
if listOpts.Size {
|
||||||
@ -239,3 +244,171 @@ func createPsOut() (string, string) {
|
|||||||
}
|
}
|
||||||
return headers, row
|
return headers, row
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type psReporter struct {
|
||||||
|
entities.ListContainer
|
||||||
|
}
|
||||||
|
|
||||||
|
// ID returns the ID of the container
|
||||||
|
func (l psReporter) ID() string {
|
||||||
|
if !noTrunc {
|
||||||
|
return l.ListContainer.ID[0:12]
|
||||||
|
}
|
||||||
|
return l.ListContainer.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pod returns the ID of the pod the container
|
||||||
|
// belongs to and appropriately truncates the ID
|
||||||
|
func (l psReporter) Pod() string {
|
||||||
|
if !noTrunc && len(l.ListContainer.Pod) > 0 {
|
||||||
|
return l.ListContainer.Pod[0:12]
|
||||||
|
}
|
||||||
|
return l.ListContainer.Pod
|
||||||
|
}
|
||||||
|
|
||||||
|
// State returns the container state in human duration
|
||||||
|
func (l psReporter) State() string {
|
||||||
|
var state string
|
||||||
|
switch l.ListContainer.State {
|
||||||
|
case "running":
|
||||||
|
t := units.HumanDuration(time.Since(time.Unix(l.StartedAt, 0)))
|
||||||
|
state = "Up " + t + " ago"
|
||||||
|
case "configured":
|
||||||
|
state = "Created"
|
||||||
|
case "exited", "stopped":
|
||||||
|
t := units.HumanDuration(time.Since(time.Unix(l.ExitedAt, 0)))
|
||||||
|
state = fmt.Sprintf("Exited (%d) %s ago", l.ExitCode, t)
|
||||||
|
default:
|
||||||
|
state = l.ListContainer.State
|
||||||
|
}
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command returns the container command in string format
|
||||||
|
func (l psReporter) Command() string {
|
||||||
|
return strings.Join(l.ListContainer.Command, " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the rootfs and virtual sizes in human duration in
|
||||||
|
// and output form (string) suitable for ps
|
||||||
|
func (l psReporter) Size() string {
|
||||||
|
virt := units.HumanSizeWithPrecision(float64(l.ListContainer.Size.RootFsSize), 3)
|
||||||
|
s := units.HumanSizeWithPrecision(float64(l.ListContainer.Size.RwSize), 3)
|
||||||
|
return fmt.Sprintf("%s (virtual %s)", s, virt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Names returns the container name in string format
|
||||||
|
func (l psReporter) Names() string {
|
||||||
|
return l.ListContainer.Names[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ports converts from Portmappings to the string form
|
||||||
|
// required by ps
|
||||||
|
func (l psReporter) Ports() string {
|
||||||
|
if len(l.ListContainer.Ports) < 1 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return portsToString(l.ListContainer.Ports)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreatedAt returns the container creation time in string format. podman
|
||||||
|
// and docker both return a timestamped value for createdat
|
||||||
|
func (l psReporter) CreatedAt() string {
|
||||||
|
return time.Unix(l.Created, 0).String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateHuman allows us to output the created time in human readable format
|
||||||
|
func (l psReporter) CreatedHuman() string {
|
||||||
|
return units.HumanDuration(time.Since(time.Unix(l.Created, 0))) + " ago"
|
||||||
|
}
|
||||||
|
|
||||||
|
// portsToString converts the ports used to a string of the from "port1, port2"
|
||||||
|
// and also groups a continuous list of ports into a readable format.
|
||||||
|
func portsToString(ports []ocicni.PortMapping) string {
|
||||||
|
type portGroup struct {
|
||||||
|
first int32
|
||||||
|
last int32
|
||||||
|
}
|
||||||
|
var portDisplay []string
|
||||||
|
if len(ports) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
//Sort the ports, so grouping continuous ports become easy.
|
||||||
|
sort.Slice(ports, func(i, j int) bool {
|
||||||
|
return comparePorts(ports[i], ports[j])
|
||||||
|
})
|
||||||
|
|
||||||
|
// portGroupMap is used for grouping continuous ports.
|
||||||
|
portGroupMap := make(map[string]*portGroup)
|
||||||
|
var groupKeyList []string
|
||||||
|
|
||||||
|
for _, v := range ports {
|
||||||
|
|
||||||
|
hostIP := v.HostIP
|
||||||
|
if hostIP == "" {
|
||||||
|
hostIP = "0.0.0.0"
|
||||||
|
}
|
||||||
|
// If hostPort and containerPort are not same, consider as individual port.
|
||||||
|
if v.ContainerPort != v.HostPort {
|
||||||
|
portDisplay = append(portDisplay, fmt.Sprintf("%s:%d->%d/%s", hostIP, v.HostPort, v.ContainerPort, v.Protocol))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
portMapKey := fmt.Sprintf("%s/%s", hostIP, v.Protocol)
|
||||||
|
|
||||||
|
portgroup, ok := portGroupMap[portMapKey]
|
||||||
|
if !ok {
|
||||||
|
portGroupMap[portMapKey] = &portGroup{first: v.ContainerPort, last: v.ContainerPort}
|
||||||
|
// This list is required to traverse portGroupMap.
|
||||||
|
groupKeyList = append(groupKeyList, portMapKey)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if portgroup.last == (v.ContainerPort - 1) {
|
||||||
|
portgroup.last = v.ContainerPort
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// For each portMapKey, format group list and appned to output string.
|
||||||
|
for _, portKey := range groupKeyList {
|
||||||
|
group := portGroupMap[portKey]
|
||||||
|
portDisplay = append(portDisplay, formatGroup(portKey, group.first, group.last))
|
||||||
|
}
|
||||||
|
return strings.Join(portDisplay, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func comparePorts(i, j ocicni.PortMapping) bool {
|
||||||
|
if i.ContainerPort != j.ContainerPort {
|
||||||
|
return i.ContainerPort < j.ContainerPort
|
||||||
|
}
|
||||||
|
|
||||||
|
if i.HostIP != j.HostIP {
|
||||||
|
return i.HostIP < j.HostIP
|
||||||
|
}
|
||||||
|
|
||||||
|
if i.HostPort != j.HostPort {
|
||||||
|
return i.HostPort < j.HostPort
|
||||||
|
}
|
||||||
|
|
||||||
|
return i.Protocol < j.Protocol
|
||||||
|
}
|
||||||
|
|
||||||
|
// formatGroup returns the group as <IP:startPort:lastPort->startPort:lastPort/Proto>
|
||||||
|
// e.g 0.0.0.0:1000-1006->1000-1006/tcp.
|
||||||
|
func formatGroup(key string, start, last int32) string {
|
||||||
|
parts := strings.Split(key, "/")
|
||||||
|
groupType := parts[0]
|
||||||
|
var ip string
|
||||||
|
if len(parts) > 1 {
|
||||||
|
ip = parts[0]
|
||||||
|
groupType = parts[1]
|
||||||
|
}
|
||||||
|
group := strconv.Itoa(int(start))
|
||||||
|
if start != last {
|
||||||
|
group = fmt.Sprintf("%s-%d", group, last)
|
||||||
|
}
|
||||||
|
if ip != "" {
|
||||||
|
group = fmt.Sprintf("%s:%s->%s", ip, group, group)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s/%s", group, groupType)
|
||||||
|
}
|
||||||
|
@ -509,7 +509,7 @@ var _ = Describe("Podman containers ", func() {
|
|||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
containerLatestList, err := containers.List(bt.conn, nil, nil, &latestContainers, nil, nil, nil)
|
containerLatestList, err := containers.List(bt.conn, nil, nil, &latestContainers, nil, nil, nil)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
err = containers.Kill(bt.conn, containerLatestList[0].Names(), "SIGTERM")
|
err = containers.Kill(bt.conn, containerLatestList[0].Names[0], "SIGTERM")
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,23 +1,19 @@
|
|||||||
package entities
|
package entities
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/containers/libpod/cmd/podman/shared"
|
"github.com/containers/libpod/cmd/podman/shared"
|
||||||
"github.com/containers/libpod/libpod"
|
"github.com/containers/libpod/libpod"
|
||||||
"github.com/cri-o/ocicni/pkg/ocicni"
|
"github.com/cri-o/ocicni/pkg/ocicni"
|
||||||
"github.com/docker/go-units"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Listcontainer describes a container suitable for listing
|
// Listcontainer describes a container suitable for listing
|
||||||
type ListContainer struct {
|
type ListContainer struct {
|
||||||
// Container command
|
// Container command
|
||||||
Cmd []string
|
Command []string
|
||||||
// Container creation time
|
// Container creation time
|
||||||
Created int64
|
Created int64
|
||||||
// If container has exited/stopped
|
// If container has exited/stopped
|
||||||
@ -37,7 +33,7 @@ type ListContainer struct {
|
|||||||
// User volume mounts
|
// User volume mounts
|
||||||
Mounts []string
|
Mounts []string
|
||||||
// The names assigned to the container
|
// The names assigned to the container
|
||||||
ContainerNames []string
|
Names []string
|
||||||
// Namespaces the container belongs to. Requires the
|
// Namespaces the container belongs to. Requires the
|
||||||
// namespace boolean to be true
|
// namespace boolean to be true
|
||||||
Namespaces ListContainerNamespaces
|
Namespaces ListContainerNamespaces
|
||||||
@ -50,69 +46,13 @@ type ListContainer struct {
|
|||||||
// boolean to be set
|
// boolean to be set
|
||||||
PodName string
|
PodName string
|
||||||
// Port mappings
|
// Port mappings
|
||||||
PortMappings []ocicni.PortMapping
|
Ports []ocicni.PortMapping
|
||||||
// Size of the container rootfs. Requires the size boolean to be true
|
// Size of the container rootfs. Requires the size boolean to be true
|
||||||
ContainerSize *shared.ContainerSize
|
Size *shared.ContainerSize
|
||||||
// Time when container started
|
// Time when container started
|
||||||
StartedAt int64
|
StartedAt int64
|
||||||
// State of container
|
// State of container
|
||||||
ContainerState string
|
State string
|
||||||
}
|
|
||||||
|
|
||||||
// State returns the container state in human duration
|
|
||||||
func (l ListContainer) State() string {
|
|
||||||
var state string
|
|
||||||
switch l.ContainerState {
|
|
||||||
case "running":
|
|
||||||
t := units.HumanDuration(time.Since(time.Unix(l.StartedAt, 0)))
|
|
||||||
state = "Up " + t + " ago"
|
|
||||||
case "configured":
|
|
||||||
state = "Created"
|
|
||||||
case "exited", "stopped":
|
|
||||||
t := units.HumanDuration(time.Since(time.Unix(l.ExitedAt, 0)))
|
|
||||||
state = fmt.Sprintf("Exited (%d) %s ago", l.ExitCode, t)
|
|
||||||
default:
|
|
||||||
state = l.ContainerState
|
|
||||||
}
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
|
|
||||||
// Command returns the container command in string format
|
|
||||||
func (l ListContainer) Command() string {
|
|
||||||
return strings.Join(l.Cmd, " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Size returns the rootfs and virtual sizes in human duration in
|
|
||||||
// and output form (string) suitable for ps
|
|
||||||
func (l ListContainer) Size() string {
|
|
||||||
virt := units.HumanSizeWithPrecision(float64(l.ContainerSize.RootFsSize), 3)
|
|
||||||
s := units.HumanSizeWithPrecision(float64(l.ContainerSize.RwSize), 3)
|
|
||||||
return fmt.Sprintf("%s (virtual %s)", s, virt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Names returns the container name in string format
|
|
||||||
func (l ListContainer) Names() string {
|
|
||||||
return l.ContainerNames[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ports converts from Portmappings to the string form
|
|
||||||
// required by ps
|
|
||||||
func (l ListContainer) Ports() string {
|
|
||||||
if len(l.PortMappings) < 1 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return portsToString(l.PortMappings)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreatedAt returns the container creation time in string format. podman
|
|
||||||
// and docker both return a timestamped value for createdat
|
|
||||||
func (l ListContainer) CreatedAt() string {
|
|
||||||
return time.Unix(l.Created, 0).String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateHuman allows us to output the created time in human readable format
|
|
||||||
func (l ListContainer) CreatedHuman() string {
|
|
||||||
return units.HumanDuration(time.Since(time.Unix(l.Created, 0))) + " ago"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListContainer Namespaces contains the identifiers of the container's Linux namespaces
|
// ListContainer Namespaces contains the identifiers of the container's Linux namespaces
|
||||||
@ -153,7 +93,7 @@ func (a SortListContainers) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
|||||||
type psSortedCommand struct{ SortListContainers }
|
type psSortedCommand struct{ SortListContainers }
|
||||||
|
|
||||||
func (a psSortedCommand) Less(i, j int) bool {
|
func (a psSortedCommand) Less(i, j int) bool {
|
||||||
return strings.Join(a.SortListContainers[i].Cmd, " ") < strings.Join(a.SortListContainers[j].Cmd, " ")
|
return strings.Join(a.SortListContainers[i].Command, " ") < strings.Join(a.SortListContainers[j].Command, " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
type psSortedId struct{ SortListContainers }
|
type psSortedId struct{ SortListContainers }
|
||||||
@ -171,7 +111,7 @@ func (a psSortedImage) Less(i, j int) bool {
|
|||||||
type psSortedNames struct{ SortListContainers }
|
type psSortedNames struct{ SortListContainers }
|
||||||
|
|
||||||
func (a psSortedNames) Less(i, j int) bool {
|
func (a psSortedNames) Less(i, j int) bool {
|
||||||
return a.SortListContainers[i].ContainerNames[0] < a.SortListContainers[j].ContainerNames[0]
|
return a.SortListContainers[i].Names[0] < a.SortListContainers[j].Names[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
type psSortedPod struct{ SortListContainers }
|
type psSortedPod struct{ SortListContainers }
|
||||||
@ -189,16 +129,16 @@ func (a psSortedRunningFor) Less(i, j int) bool {
|
|||||||
type psSortedStatus struct{ SortListContainers }
|
type psSortedStatus struct{ SortListContainers }
|
||||||
|
|
||||||
func (a psSortedStatus) Less(i, j int) bool {
|
func (a psSortedStatus) Less(i, j int) bool {
|
||||||
return a.SortListContainers[i].ContainerState < a.SortListContainers[j].ContainerState
|
return a.SortListContainers[i].State < a.SortListContainers[j].State
|
||||||
}
|
}
|
||||||
|
|
||||||
type psSortedSize struct{ SortListContainers }
|
type psSortedSize struct{ SortListContainers }
|
||||||
|
|
||||||
func (a psSortedSize) Less(i, j int) bool {
|
func (a psSortedSize) Less(i, j int) bool {
|
||||||
if a.SortListContainers[i].ContainerSize == nil || a.SortListContainers[j].ContainerSize == nil {
|
if a.SortListContainers[i].Size == nil || a.SortListContainers[j].Size == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return a.SortListContainers[i].ContainerSize.RootFsSize < a.SortListContainers[j].ContainerSize.RootFsSize
|
return a.SortListContainers[i].Size.RootFsSize < a.SortListContainers[j].Size.RootFsSize
|
||||||
}
|
}
|
||||||
|
|
||||||
type PsSortedCreateTime struct{ SortListContainers }
|
type PsSortedCreateTime struct{ SortListContainers }
|
||||||
@ -232,94 +172,3 @@ func SortPsOutput(sortBy string, psOutput SortListContainers) (SortListContainer
|
|||||||
}
|
}
|
||||||
return psOutput, nil
|
return psOutput, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// portsToString converts the ports used to a string of the from "port1, port2"
|
|
||||||
// and also groups a continuous list of ports into a readable format.
|
|
||||||
func portsToString(ports []ocicni.PortMapping) string {
|
|
||||||
type portGroup struct {
|
|
||||||
first int32
|
|
||||||
last int32
|
|
||||||
}
|
|
||||||
var portDisplay []string
|
|
||||||
if len(ports) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
//Sort the ports, so grouping continuous ports become easy.
|
|
||||||
sort.Slice(ports, func(i, j int) bool {
|
|
||||||
return comparePorts(ports[i], ports[j])
|
|
||||||
})
|
|
||||||
|
|
||||||
// portGroupMap is used for grouping continuous ports.
|
|
||||||
portGroupMap := make(map[string]*portGroup)
|
|
||||||
var groupKeyList []string
|
|
||||||
|
|
||||||
for _, v := range ports {
|
|
||||||
|
|
||||||
hostIP := v.HostIP
|
|
||||||
if hostIP == "" {
|
|
||||||
hostIP = "0.0.0.0"
|
|
||||||
}
|
|
||||||
// If hostPort and containerPort are not same, consider as individual port.
|
|
||||||
if v.ContainerPort != v.HostPort {
|
|
||||||
portDisplay = append(portDisplay, fmt.Sprintf("%s:%d->%d/%s", hostIP, v.HostPort, v.ContainerPort, v.Protocol))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
portMapKey := fmt.Sprintf("%s/%s", hostIP, v.Protocol)
|
|
||||||
|
|
||||||
portgroup, ok := portGroupMap[portMapKey]
|
|
||||||
if !ok {
|
|
||||||
portGroupMap[portMapKey] = &portGroup{first: v.ContainerPort, last: v.ContainerPort}
|
|
||||||
// This list is required to traverse portGroupMap.
|
|
||||||
groupKeyList = append(groupKeyList, portMapKey)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if portgroup.last == (v.ContainerPort - 1) {
|
|
||||||
portgroup.last = v.ContainerPort
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// For each portMapKey, format group list and appned to output string.
|
|
||||||
for _, portKey := range groupKeyList {
|
|
||||||
group := portGroupMap[portKey]
|
|
||||||
portDisplay = append(portDisplay, formatGroup(portKey, group.first, group.last))
|
|
||||||
}
|
|
||||||
return strings.Join(portDisplay, ", ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func comparePorts(i, j ocicni.PortMapping) bool {
|
|
||||||
if i.ContainerPort != j.ContainerPort {
|
|
||||||
return i.ContainerPort < j.ContainerPort
|
|
||||||
}
|
|
||||||
|
|
||||||
if i.HostIP != j.HostIP {
|
|
||||||
return i.HostIP < j.HostIP
|
|
||||||
}
|
|
||||||
|
|
||||||
if i.HostPort != j.HostPort {
|
|
||||||
return i.HostPort < j.HostPort
|
|
||||||
}
|
|
||||||
|
|
||||||
return i.Protocol < j.Protocol
|
|
||||||
}
|
|
||||||
|
|
||||||
// formatGroup returns the group as <IP:startPort:lastPort->startPort:lastPort/Proto>
|
|
||||||
// e.g 0.0.0.0:1000-1006->1000-1006/tcp.
|
|
||||||
func formatGroup(key string, start, last int32) string {
|
|
||||||
parts := strings.Split(key, "/")
|
|
||||||
groupType := parts[0]
|
|
||||||
var ip string
|
|
||||||
if len(parts) > 1 {
|
|
||||||
ip = parts[0]
|
|
||||||
groupType = parts[1]
|
|
||||||
}
|
|
||||||
group := strconv.Itoa(int(start))
|
|
||||||
if start != last {
|
|
||||||
group = fmt.Sprintf("%s-%d", group, last)
|
|
||||||
}
|
|
||||||
if ip != "" {
|
|
||||||
group = fmt.Sprintf("%s:%s->%s", ip, group, group)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s/%s", group, groupType)
|
|
||||||
}
|
|
||||||
|
@ -242,7 +242,7 @@ func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds [
|
|||||||
}
|
}
|
||||||
// narrow the list to running only
|
// narrow the list to running only
|
||||||
for _, c := range allCtrs {
|
for _, c := range allCtrs {
|
||||||
if c.ContainerState == define.ContainerStateRunning.String() {
|
if c.State == define.ContainerStateRunning.String() {
|
||||||
ctrs = append(ctrs, c)
|
ctrs = append(ctrs, c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -276,7 +276,7 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
|
|||||||
}
|
}
|
||||||
// narrow the list to exited only
|
// narrow the list to exited only
|
||||||
for _, c := range allCtrs {
|
for _, c := range allCtrs {
|
||||||
if c.ContainerState == define.ContainerStateExited.String() {
|
if c.State == define.ContainerStateExited.String() {
|
||||||
ctrs = append(ctrs, c)
|
ctrs = append(ctrs, c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ func getContainersByContext(contextWithConnection context.Context, all bool, nam
|
|||||||
for _, id := range namesOrIds {
|
for _, id := range namesOrIds {
|
||||||
var found bool
|
var found bool
|
||||||
for _, con := range c {
|
for _, con := range c {
|
||||||
if id == con.ID || strings.HasPrefix(con.ID, id) || util.StringInSlice(id, con.ContainerNames) {
|
if id == con.ID || strings.HasPrefix(con.ID, id) || util.StringInSlice(id, con.Names) {
|
||||||
cons = append(cons, con)
|
cons = append(cons, con)
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
|
34
pkg/ps/ps.go
34
pkg/ps/ps.go
@ -148,23 +148,23 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
|
|||||||
}
|
}
|
||||||
|
|
||||||
ps := entities.ListContainer{
|
ps := entities.ListContainer{
|
||||||
Cmd: conConfig.Command,
|
Command: conConfig.Command,
|
||||||
Created: conConfig.CreatedTime.Unix(),
|
Created: conConfig.CreatedTime.Unix(),
|
||||||
Exited: exited,
|
Exited: exited,
|
||||||
ExitCode: exitCode,
|
ExitCode: exitCode,
|
||||||
ExitedAt: exitedTime.Unix(),
|
ExitedAt: exitedTime.Unix(),
|
||||||
ID: conConfig.ID,
|
ID: conConfig.ID,
|
||||||
Image: conConfig.RootfsImageName,
|
Image: conConfig.RootfsImageName,
|
||||||
IsInfra: conConfig.IsInfra,
|
IsInfra: conConfig.IsInfra,
|
||||||
Labels: conConfig.Labels,
|
Labels: conConfig.Labels,
|
||||||
Mounts: ctr.UserVolumes(),
|
Mounts: ctr.UserVolumes(),
|
||||||
ContainerNames: []string{conConfig.Name},
|
Names: []string{conConfig.Name},
|
||||||
Pid: pid,
|
Pid: pid,
|
||||||
Pod: conConfig.Pod,
|
Pod: conConfig.Pod,
|
||||||
PortMappings: conConfig.PortMappings,
|
Ports: conConfig.PortMappings,
|
||||||
ContainerSize: size,
|
Size: size,
|
||||||
StartedAt: startedTime.Unix(),
|
StartedAt: startedTime.Unix(),
|
||||||
ContainerState: conState.String(),
|
State: conState.String(),
|
||||||
}
|
}
|
||||||
if opts.Pod && len(conConfig.Pod) > 0 {
|
if opts.Pod && len(conConfig.Pod) > 0 {
|
||||||
pod, err := rt.GetPod(conConfig.Pod)
|
pod, err := rt.GetPod(conConfig.Pod)
|
||||||
|
@ -21,8 +21,8 @@ t GET libpod/containers/json?all=true 200 \
|
|||||||
length=1 \
|
length=1 \
|
||||||
.[0].Id~[0-9a-f]\\{12\\} \
|
.[0].Id~[0-9a-f]\\{12\\} \
|
||||||
.[0].Image=$IMAGE \
|
.[0].Image=$IMAGE \
|
||||||
.[0].Cmd[0]="true" \
|
.[0].Command[0]="true" \
|
||||||
.[0].ContainerState~\\\(exited\\\|stopped\\\) \
|
.[0].State~\\\(exited\\\|stopped\\\) \
|
||||||
.[0].ExitCode=0 \
|
.[0].ExitCode=0 \
|
||||||
.[0].IsInfra=false
|
.[0].IsInfra=false
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user