summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/containers/ps.go160
-rw-r--r--cmd/podman/containers/wait.go14
-rw-r--r--cmd/podman/images/build.go4
-rw-r--r--docs/source/markdown/podman-wait.1.md7
-rw-r--r--go.mod2
-rw-r--r--go.sum4
-rw-r--r--test/e2e/ps_test.go33
-rw-r--r--test/e2e/wait_test.go45
-rw-r--r--vendor/modules.txt2
9 files changed, 211 insertions, 60 deletions
diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go
index 8c3e2e3b7..80a50f4ef 100644
--- a/cmd/podman/containers/ps.go
+++ b/cmd/podman/containers/ps.go
@@ -371,12 +371,6 @@ func (l psReporter) CreatedHuman() string {
// 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
- }
- portDisplay := []string{}
-
if len(ports) == 0 {
return ""
}
@@ -385,41 +379,124 @@ func portsToString(ports []ocicni.PortMapping) string {
return comparePorts(ports[i], ports[j])
})
- // portGroupMap is used for grouping continuous ports.
- portGroupMap := make(map[string]*portGroup)
- var groupKeyList []string
+ portGroups := [][]ocicni.PortMapping{}
+ currentGroup := []ocicni.PortMapping{}
+ for i, v := range ports {
+ var prevPort, nextPort *int32
+ if i > 0 {
+ prevPort = &ports[i-1].ContainerPort
+ }
+ if i+1 < len(ports) {
+ nextPort = &ports[i+1].ContainerPort
+ }
- for _, v := range ports {
+ port := v.ContainerPort
- hostIP := v.HostIP
- if hostIP == "" {
- hostIP = "0.0.0.0"
+ // Helper functions
+ addToCurrentGroup := func(x ocicni.PortMapping) {
+ currentGroup = append(currentGroup, x)
}
- // 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
+
+ addToPortGroup := func(x ocicni.PortMapping) {
+ portGroups = append(portGroups, []ocicni.PortMapping{x})
+ }
+
+ finishCurrentGroup := func() {
+ portGroups = append(portGroups, currentGroup)
+ currentGroup = []ocicni.PortMapping{}
}
- portMapKey := fmt.Sprintf("%s/%s", hostIP, v.Protocol)
+ // Single entry slice
+ if prevPort == nil && nextPort == nil {
+ addToPortGroup(v)
+ }
+
+ // Start of the slice with len > 0
+ if prevPort == nil && nextPort != nil {
+ isGroup := *nextPort-1 == port
+
+ if isGroup {
+ // Start with a group
+ addToCurrentGroup(v)
+ } else {
+ // Start with single item
+ addToPortGroup(v)
+ }
- 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
+ // Middle of the slice with len > 0
+ if prevPort != nil && nextPort != nil {
+ currentIsGroup := *prevPort+1 == port
+ nextIsGroup := *nextPort-1 == port
+
+ if currentIsGroup {
+ // Maybe in the middle of a group
+ addToCurrentGroup(v)
+
+ if !nextIsGroup {
+ // End of a group
+ finishCurrentGroup()
+ }
+ } else if nextIsGroup {
+ // Start of a new group
+ addToCurrentGroup(v)
+ } else {
+ // No group at all
+ addToPortGroup(v)
+ }
+
continue
}
+
+ // End of the slice with len > 0
+ if prevPort != nil && nextPort == nil {
+ isGroup := *prevPort+1 == port
+
+ if isGroup {
+ // End group
+ addToCurrentGroup(v)
+ finishCurrentGroup()
+ } else {
+ // End single item
+ addToPortGroup(v)
+ }
+ }
}
- // For each portMapKey, format group list and append to output string.
- for _, portKey := range groupKeyList {
- group := portGroupMap[portKey]
- portDisplay = append(portDisplay, formatGroup(portKey, group.first, group.last))
+
+ portDisplay := []string{}
+ for _, group := range portGroups {
+ if len(group) == 0 {
+ // Usually should not happen, but better do not crash.
+ continue
+ }
+
+ first := group[0]
+
+ hostIP := first.HostIP
+ if hostIP == "" {
+ hostIP = "0.0.0.0"
+ }
+
+ // Single mappings
+ if len(group) == 1 {
+ portDisplay = append(portDisplay,
+ fmt.Sprintf(
+ "%s:%d->%d/%s",
+ hostIP, first.HostPort, first.ContainerPort, first.Protocol,
+ ),
+ )
+ continue
+ }
+
+ // Group mappings
+ last := group[len(group)-1]
+ portDisplay = append(portDisplay, formatGroup(
+ fmt.Sprintf("%s/%s", hostIP, first.Protocol),
+ first.HostPort, last.HostPort,
+ first.ContainerPort, last.ContainerPort,
+ ))
}
return strings.Join(portDisplay, ", ")
}
@@ -440,9 +517,10 @@ func comparePorts(i, j ocicni.PortMapping) bool {
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 {
+// formatGroup returns the group in the format:
+// <IP:firstHost:lastHost->firstCtr:lastCtr/Proto>
+// e.g 0.0.0.0:1000-1006->2000-2006/tcp.
+func formatGroup(key string, firstHost, lastHost, firstCtr, lastCtr int32) string {
parts := strings.Split(key, "/")
groupType := parts[0]
var ip string
@@ -450,12 +528,16 @@ func formatGroup(key string, start, last int32) string {
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)
+
+ group := func(first, last int32) string {
+ group := strconv.Itoa(int(first))
+ if first != last {
+ group = fmt.Sprintf("%s-%d", group, last)
+ }
+ return group
}
- return fmt.Sprintf("%s/%s", group, groupType)
+ hostGroup := group(firstHost, lastHost)
+ ctrGroup := group(firstCtr, lastCtr)
+
+ return fmt.Sprintf("%s:%s->%s/%s", ip, hostGroup, ctrGroup, groupType)
}
diff --git a/cmd/podman/containers/wait.go b/cmd/podman/containers/wait.go
index 0f9304558..b4986143b 100644
--- a/cmd/podman/containers/wait.go
+++ b/cmd/podman/containers/wait.go
@@ -23,7 +23,7 @@ var (
Short: "Block on one or more containers",
Long: waitDescription,
RunE: wait,
- Example: `podman wait --interval 5000 ctrID
+ Example: `podman wait --interval 5s ctrID
podman wait ctrID1 ctrID2`,
}
@@ -32,7 +32,7 @@ var (
Short: waitCommand.Short,
Long: waitCommand.Long,
RunE: waitCommand.RunE,
- Example: `podman container wait --interval 5000 ctrID
+ Example: `podman container wait --interval 5s ctrID
podman container wait ctrID1 ctrID2`,
}
)
@@ -40,10 +40,11 @@ var (
var (
waitOptions = entities.WaitOptions{}
waitCondition string
+ waitInterval string
)
func waitFlags(flags *pflag.FlagSet) {
- flags.DurationVarP(&waitOptions.Interval, "interval", "i", time.Duration(250), "Milliseconds to wait before polling for completion")
+ flags.StringVarP(&waitInterval, "interval", "i", "250ns", "Time Interval to wait before polling for completion")
flags.StringVar(&waitCondition, "condition", "stopped", "Condition to wait on")
}
@@ -70,8 +71,11 @@ func wait(cmd *cobra.Command, args []string) error {
err error
errs utils.OutputErrors
)
- if waitOptions.Interval == 0 {
- return errors.New("interval must be greater then 0")
+ if waitOptions.Interval, err = time.ParseDuration(waitInterval); err != nil {
+ var err1 error
+ if waitOptions.Interval, err1 = time.ParseDuration(waitInterval + "ms"); err1 != nil {
+ return err
+ }
}
if !waitOptions.Latest && len(args) == 0 {
diff --git a/cmd/podman/images/build.go b/cmd/podman/images/build.go
index f8ea4754f..18c31313b 100644
--- a/cmd/podman/images/build.go
+++ b/cmd/podman/images/build.go
@@ -282,8 +282,7 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil
flags.Layers = false
}
- var stdin, stdout, stderr, reporter *os.File
- stdin = os.Stdin
+ var stdout, stderr, reporter *os.File
stdout = os.Stdout
stderr = os.Stderr
reporter = os.Stderr
@@ -422,7 +421,6 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil
ForceRmIntermediateCtrs: flags.ForceRm,
IDMappingOptions: idmappingOptions,
IIDFile: flags.Iidfile,
- In: stdin,
Isolation: isolation,
Labels: flags.Label,
Layers: flags.Layers,
diff --git a/docs/source/markdown/podman-wait.1.md b/docs/source/markdown/podman-wait.1.md
index 1d85e9af0..f0ccb1f9e 100644
--- a/docs/source/markdown/podman-wait.1.md
+++ b/docs/source/markdown/podman-wait.1.md
@@ -23,8 +23,8 @@ Condition to wait on (default "stopped")
Print usage statement
-**--interval**, **-i**=*microseconds*
- Microseconds to wait before polling for completion
+**--interval**, **-i**=*duration*
+ Time interval to wait before polling for completion. A duration string is a sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". Time unit defaults to "ms".
**--latest**, **-l**
@@ -42,6 +42,9 @@ $ podman wait mywebserver
$ podman wait --latest
0
+$ podman wait --interval 2s
+0
+
$ podman wait 860a4b23
1
diff --git a/go.mod b/go.mod
index 29a53de13..41ea2f62e 100644
--- a/go.mod
+++ b/go.mod
@@ -72,6 +72,6 @@ require (
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
k8s.io/api v0.0.0-20190620084959-7cf5895f2711
- k8s.io/apimachinery v0.19.2
+ k8s.io/apimachinery v0.19.3
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab
)
diff --git a/go.sum b/go.sum
index 76a27d3d2..7f5e45543 100644
--- a/go.sum
+++ b/go.sum
@@ -815,8 +815,8 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt
k8s.io/api v0.0.0-20190620084959-7cf5895f2711 h1:BblVYz/wE5WtBsD/Gvu54KyBUTJMflolzc5I2DTvh50=
k8s.io/api v0.0.0-20190620084959-7cf5895f2711/go.mod h1:TBhBqb1AWbBQbW3XRusr7n7E4v2+5ZY8r8sAMnyFC5A=
k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719/go.mod h1:I4A+glKBHiTgiEjQiCCQfCAIcIMFGt291SmsvcrFzJA=
-k8s.io/apimachinery v0.19.2 h1:5Gy9vQpAGTKHPVOh5c4plE274X8D/6cuEiTO2zve7tc=
-k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
+k8s.io/apimachinery v0.19.3 h1:bpIQXlKjB4cB/oNpnNnV+BybGPR7iP5oYpsOTEJ4hgc=
+k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab h1:E8Fecph0qbNsAbijJJQryKu4Oi9QTp5cVpjTE+nqg6g=
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab/go.mod h1:E95RaSlHr79aHaX0aGSwcPNfygDiPKOVXdmivCIZT0k=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go
index 48ef566ce..c65738993 100644
--- a/test/e2e/ps_test.go
+++ b/test/e2e/ps_test.go
@@ -411,18 +411,43 @@ var _ = Describe("Podman ps", func() {
Expect(output).To(ContainSubstring(podName))
})
- It("podman ps test with port range", func() {
- session := podmanTest.RunTopContainer("")
+ It("podman ps test with single port range", func() {
+ session := podmanTest.Podman([]string{"run", "-dt", "-p", "2000-2006:2000-2006", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"run", "-dt", "-p", "2000-2006:2000-2006", ALPINE, "top"})
+ session = podmanTest.Podman([]string{"ps", "--format", "{{.Ports}}"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.OutputToString()).To(ContainSubstring("0.0.0.0:2000-2006"))
+ })
+
+ It("podman ps test with invalid port range", func() {
+ session := podmanTest.Podman([]string{
+ "run", "-p", "1000-2000:2000-3000", "-p", "1999-2999:3001-4001", ALPINE,
+ })
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(125))
+ Expect(session.ErrorToString()).To(ContainSubstring("conflicting port mappings for host port 1999"))
+ })
+
+ It("podman ps test with multiple port range", func() {
+ session := podmanTest.Podman([]string{
+ "run", "-dt",
+ "-p", "3000-3001:3000-3001",
+ "-p", "3100-3102:4000-4002",
+ "-p", "30080:30080",
+ "-p", "30443:30443",
+ "-p", "8000:8080",
+ ALPINE, "top"},
+ )
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"ps", "--format", "{{.Ports}}"})
session.WaitWithDefaultTimeout()
- Expect(session.OutputToString()).To(ContainSubstring("0.0.0.0:2000-2006"))
+ Expect(session.OutputToString()).To(ContainSubstring(
+ "0.0.0.0:3000-3001->3000-3001/tcp, 0.0.0.0:3100-3102->4000-4002/tcp, 0.0.0.0:8000->8080/tcp, 0.0.0.0:30080->30080/tcp, 0.0.0.0:30443->30443/tcp",
+ ))
})
It("podman ps sync flag", func() {
diff --git a/test/e2e/wait_test.go b/test/e2e/wait_test.go
index 4f0129a47..aa8a1f245 100644
--- a/test/e2e/wait_test.go
+++ b/test/e2e/wait_test.go
@@ -46,6 +46,7 @@ var _ = Describe("Podman wait", func() {
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"wait", cid})
session.Wait()
+ Expect(session.ExitCode()).To(Equal(0))
})
It("podman wait on a sleeping container", func() {
@@ -55,22 +56,60 @@ var _ = Describe("Podman wait", func() {
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"wait", cid})
session.Wait(20)
+ Expect(session.ExitCode()).To(Equal(0))
})
It("podman wait on latest container", func() {
session := podmanTest.Podman([]string{"run", "-d", ALPINE, "sleep", "1"})
session.Wait(20)
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"wait", "-l"})
- session.Wait(20)
+ if IsRemote() {
+ session = podmanTest.Podman([]string{"wait", session.OutputToString()})
+ } else {
+ session = podmanTest.Podman([]string{"wait", "-l"})
+ }
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
})
It("podman container wait on latest container", func() {
session := podmanTest.Podman([]string{"container", "run", "-d", ALPINE, "sleep", "1"})
session.Wait(20)
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"container", "wait", "-l"})
+ if IsRemote() {
+ session = podmanTest.Podman([]string{"container", "wait", session.OutputToString()})
+ } else {
+ session = podmanTest.Podman([]string{"container", "wait", "-l"})
+ }
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ })
+
+ It("podman container wait on latest container with --interval flag", func() {
+ session := podmanTest.Podman([]string{"container", "run", "-d", ALPINE, "sleep", "1"})
session.Wait(20)
+ Expect(session.ExitCode()).To(Equal(0))
+ session = podmanTest.Podman([]string{"container", "wait", "-i", "5000", session.OutputToString()})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ })
+
+ It("podman container wait on latest container with --interval flag", func() {
+ session := podmanTest.Podman([]string{"container", "run", "-d", ALPINE, "sleep", "1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ session = podmanTest.Podman([]string{"container", "wait", "--interval", "1s", session.OutputToString()})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ })
+
+ It("podman container wait on container with bogus --interval", func() {
+ session := podmanTest.Podman([]string{"container", "run", "-d", ALPINE, "sleep", "1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ session = podmanTest.Podman([]string{"container", "wait", "--interval", "100days", session.OutputToString()})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(125))
})
It("podman wait on three containers", func() {
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 2f8a79aa8..9840261a9 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -701,7 +701,7 @@ gopkg.in/yaml.v3
# k8s.io/api v0.0.0-20190620084959-7cf5895f2711
k8s.io/api/apps/v1
k8s.io/api/core/v1
-# k8s.io/apimachinery v0.19.2
+# k8s.io/apimachinery v0.19.3
k8s.io/apimachinery/pkg/api/errors
k8s.io/apimachinery/pkg/api/resource
k8s.io/apimachinery/pkg/apis/meta/v1