v2podman ps revert structure changes
reverting name changes to the listcontainer structure because it negatively impacted the direct consumption of the restful API. instead we now use a local structure in the CLI to modify the output as needed. Signed-off-by: Brent Baude <bbaude@redhat.com>
This commit is contained in:
		
							parent
							
								
									004826653f
								
							
						
					
					
						commit
						830f3a4462
					
				| 
						 | 
				
			
			@ -4,6 +4,8 @@ import (
 | 
			
		|||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"text/tabwriter"
 | 
			
		||||
	"text/template"
 | 
			
		||||
| 
						 | 
				
			
			@ -13,6 +15,8 @@ import (
 | 
			
		|||
	"github.com/containers/buildah/pkg/formats"
 | 
			
		||||
	"github.com/containers/libpod/cmd/podmanV2/registry"
 | 
			
		||||
	"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/spf13/cobra"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -134,6 +138,7 @@ func getResponses() ([]entities.ListContainer, error) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
func ps(cmd *cobra.Command, args []string) error {
 | 
			
		||||
	var responses []psReporter
 | 
			
		||||
	for _, f := range filters {
 | 
			
		||||
		split := strings.SplitN(f, "=", 2)
 | 
			
		||||
		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])
 | 
			
		||||
	}
 | 
			
		||||
	responses, err := getResponses()
 | 
			
		||||
	listContainers, err := getResponses()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if len(listOpts.Sort) > 0 {
 | 
			
		||||
		responses, err = entities.SortPsOutput(listOpts.Sort, responses)
 | 
			
		||||
		listContainers, err = entities.SortPsOutput(listOpts.Sort, listContainers)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if listOpts.Format == "json" {
 | 
			
		||||
		return jsonOut(responses)
 | 
			
		||||
		return jsonOut(listContainers)
 | 
			
		||||
	}
 | 
			
		||||
	if listOpts.Quiet {
 | 
			
		||||
		return quietOut(responses)
 | 
			
		||||
		return quietOut(listContainers)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, r := range listContainers {
 | 
			
		||||
		responses = append(responses, psReporter{r})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	headers, row := createPsOut()
 | 
			
		||||
	if cmd.Flag("format").Changed {
 | 
			
		||||
		row = listOpts.Format
 | 
			
		||||
| 
						 | 
				
			
			@ -175,10 +185,14 @@ func ps(cmd *cobra.Command, args []string) error {
 | 
			
		|||
	w := tabwriter.NewWriter(os.Stdout, 8, 2, 2, ' ', 0)
 | 
			
		||||
	if listOpts.Watch > 0 {
 | 
			
		||||
		for {
 | 
			
		||||
			var responses []psReporter
 | 
			
		||||
			tm.Clear()
 | 
			
		||||
			tm.MoveCursor(1, 1)
 | 
			
		||||
			tm.Flush()
 | 
			
		||||
			responses, err := getResponses()
 | 
			
		||||
			listContainers, err := getResponses()
 | 
			
		||||
			for _, r := range listContainers {
 | 
			
		||||
				responses = append(responses, psReporter{r})
 | 
			
		||||
			}
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -210,21 +224,12 @@ func createPsOut() (string, string) {
 | 
			
		|||
		return headers, row
 | 
			
		||||
	}
 | 
			
		||||
	headers := defaultHeaders
 | 
			
		||||
	if noTrunc {
 | 
			
		||||
	row += "{{.ID}}"
 | 
			
		||||
	} else {
 | 
			
		||||
		row += "{{slice .ID 0 12}}"
 | 
			
		||||
	}
 | 
			
		||||
	row += "\t{{.Image}}\t{{.Command}}\t{{.CreatedHuman}}\t{{.State}}\t{{.Ports}}\t{{.Names}}"
 | 
			
		||||
 | 
			
		||||
	if listOpts.Pod {
 | 
			
		||||
		headers += "\tPOD ID\tPODNAME"
 | 
			
		||||
		if noTrunc {
 | 
			
		||||
			row += "\t{{.Pod}}"
 | 
			
		||||
		} else {
 | 
			
		||||
			row += "\t{{slice .Pod 0 12}}"
 | 
			
		||||
		}
 | 
			
		||||
		row += "\t{{.PodName}}"
 | 
			
		||||
		row += "\t{{.Pod}}\t{{.PodName}}"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if listOpts.Size {
 | 
			
		||||
| 
						 | 
				
			
			@ -239,3 +244,171 @@ func createPsOut() (string, string) {
 | 
			
		|||
	}
 | 
			
		||||
	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())
 | 
			
		||||
		containerLatestList, err := containers.List(bt.conn, nil, nil, &latestContainers, nil, nil, nil)
 | 
			
		||||
		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())
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,23 +1,19 @@
 | 
			
		|||
package entities
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/containers/libpod/cmd/podman/shared"
 | 
			
		||||
	"github.com/containers/libpod/libpod"
 | 
			
		||||
	"github.com/cri-o/ocicni/pkg/ocicni"
 | 
			
		||||
	"github.com/docker/go-units"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Listcontainer describes a container suitable for listing
 | 
			
		||||
type ListContainer struct {
 | 
			
		||||
	// Container command
 | 
			
		||||
	Cmd []string
 | 
			
		||||
	Command []string
 | 
			
		||||
	// Container creation time
 | 
			
		||||
	Created int64
 | 
			
		||||
	// If container has exited/stopped
 | 
			
		||||
| 
						 | 
				
			
			@ -37,7 +33,7 @@ type ListContainer struct {
 | 
			
		|||
	// User volume mounts
 | 
			
		||||
	Mounts []string
 | 
			
		||||
	// The names assigned to the container
 | 
			
		||||
	ContainerNames []string
 | 
			
		||||
	Names []string
 | 
			
		||||
	// Namespaces the container belongs to.  Requires the
 | 
			
		||||
	// namespace boolean to be true
 | 
			
		||||
	Namespaces ListContainerNamespaces
 | 
			
		||||
| 
						 | 
				
			
			@ -50,69 +46,13 @@ type ListContainer struct {
 | 
			
		|||
	// boolean to be set
 | 
			
		||||
	PodName string
 | 
			
		||||
	// Port mappings
 | 
			
		||||
	PortMappings []ocicni.PortMapping
 | 
			
		||||
	Ports []ocicni.PortMapping
 | 
			
		||||
	// Size of the container rootfs.  Requires the size boolean to be true
 | 
			
		||||
	ContainerSize *shared.ContainerSize
 | 
			
		||||
	Size *shared.ContainerSize
 | 
			
		||||
	// Time when container started
 | 
			
		||||
	StartedAt int64
 | 
			
		||||
	// State of container
 | 
			
		||||
	ContainerState 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"
 | 
			
		||||
	State string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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 }
 | 
			
		||||
 | 
			
		||||
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 }
 | 
			
		||||
| 
						 | 
				
			
			@ -171,7 +111,7 @@ func (a psSortedImage) Less(i, j int) bool {
 | 
			
		|||
type psSortedNames struct{ SortListContainers }
 | 
			
		||||
 | 
			
		||||
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 }
 | 
			
		||||
| 
						 | 
				
			
			@ -189,16 +129,16 @@ func (a psSortedRunningFor) Less(i, j int) bool {
 | 
			
		|||
type psSortedStatus struct{ SortListContainers }
 | 
			
		||||
 | 
			
		||||
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 }
 | 
			
		||||
 | 
			
		||||
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 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 }
 | 
			
		||||
| 
						 | 
				
			
			@ -232,94 +172,3 @@ func SortPsOutput(sortBy string, psOutput SortListContainers) (SortListContainer
 | 
			
		|||
	}
 | 
			
		||||
	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
 | 
			
		||||
		for _, c := range allCtrs {
 | 
			
		||||
			if c.ContainerState == define.ContainerStateRunning.String() {
 | 
			
		||||
			if c.State == define.ContainerStateRunning.String() {
 | 
			
		||||
				ctrs = append(ctrs, c)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -276,7 +276,7 @@ func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []st
 | 
			
		|||
		}
 | 
			
		||||
		// narrow the list to exited only
 | 
			
		||||
		for _, c := range allCtrs {
 | 
			
		||||
			if c.ContainerState == define.ContainerStateExited.String() {
 | 
			
		||||
			if c.State == define.ContainerStateExited.String() {
 | 
			
		||||
				ctrs = append(ctrs, c)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,7 +30,7 @@ func getContainersByContext(contextWithConnection context.Context, all bool, nam
 | 
			
		|||
	for _, id := range namesOrIds {
 | 
			
		||||
		var found bool
 | 
			
		||||
		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)
 | 
			
		||||
				found = true
 | 
			
		||||
				break
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										10
									
								
								pkg/ps/ps.go
								
								
								
								
							
							
						
						
									
										10
									
								
								pkg/ps/ps.go
								
								
								
								
							| 
						 | 
				
			
			@ -148,7 +148,7 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	ps := entities.ListContainer{
 | 
			
		||||
		Cmd:            conConfig.Command,
 | 
			
		||||
		Command:   conConfig.Command,
 | 
			
		||||
		Created:   conConfig.CreatedTime.Unix(),
 | 
			
		||||
		Exited:    exited,
 | 
			
		||||
		ExitCode:  exitCode,
 | 
			
		||||
| 
						 | 
				
			
			@ -158,13 +158,13 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
 | 
			
		|||
		IsInfra:   conConfig.IsInfra,
 | 
			
		||||
		Labels:    conConfig.Labels,
 | 
			
		||||
		Mounts:    ctr.UserVolumes(),
 | 
			
		||||
		ContainerNames: []string{conConfig.Name},
 | 
			
		||||
		Names:     []string{conConfig.Name},
 | 
			
		||||
		Pid:       pid,
 | 
			
		||||
		Pod:       conConfig.Pod,
 | 
			
		||||
		PortMappings:   conConfig.PortMappings,
 | 
			
		||||
		ContainerSize:  size,
 | 
			
		||||
		Ports:     conConfig.PortMappings,
 | 
			
		||||
		Size:      size,
 | 
			
		||||
		StartedAt: startedTime.Unix(),
 | 
			
		||||
		ContainerState: conState.String(),
 | 
			
		||||
		State:     conState.String(),
 | 
			
		||||
	}
 | 
			
		||||
	if opts.Pod && len(conConfig.Pod) > 0 {
 | 
			
		||||
		pod, err := rt.GetPod(conConfig.Pod)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,8 +21,8 @@ t GET libpod/containers/json?all=true 200 \
 | 
			
		|||
  length=1 \
 | 
			
		||||
  .[0].Id~[0-9a-f]\\{12\\} \
 | 
			
		||||
  .[0].Image=$IMAGE \
 | 
			
		||||
  .[0].Cmd[0]="true" \
 | 
			
		||||
  .[0].ContainerState~\\\(exited\\\|stopped\\\) \
 | 
			
		||||
  .[0].Command[0]="true" \
 | 
			
		||||
  .[0].State~\\\(exited\\\|stopped\\\) \
 | 
			
		||||
  .[0].ExitCode=0 \
 | 
			
		||||
  .[0].IsInfra=false
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue