Skip to content

Commit 2e56c36

Browse files
committed
WIP use structured type
Still failing when joining; docker container ls --format 'table {{.ID}}\t{{join .IPAddresses ", "}}' CONTAINER ID IP ADDRESSES 245bd1d81375 bridge/172.17.0.2, foo/172.19.0.2 docker container ls --format '{{json .IPAddresses}}' [{"Network":"bridge","IP":"172.17.0.2"},{"Network":"foo","IP":"172.19.0.2"}] Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
1 parent 994afbc commit 2e56c36

3 files changed

Lines changed: 54 additions & 12 deletions

File tree

cli/command/formatter/container.go

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
package formatter
55

66
import (
7+
"cmp"
78
"fmt"
89
"net"
10+
"slices"
911
"sort"
1012
"strconv"
1113
"strings"
@@ -41,6 +43,16 @@ func (p Platform) String() string {
4143
return platforms.FormatAll(p.Platform)
4244
}
4345

46+
// NetworkIP describes an IP-address and the network it's associated with.
47+
type NetworkIP struct {
48+
Network string `json:"Network,omitempty"`
49+
IP string `json:"IP"`
50+
}
51+
52+
func (p NetworkIP) String() string {
53+
return p.Network + "/" + p.IP
54+
}
55+
4456
// NewContainerFormat returns a Format for rendering using a Context
4557
func NewContainerFormat(source string, quiet bool, size bool) Format {
4658
switch source {
@@ -388,19 +400,30 @@ func (c *ContainerContext) HealthStatus() string {
388400
// IPAddresses returns the list of IP-addresses assigned to the container
389401
// IP-addresses are prefixed with the name of the network, separated with a colon.
390402
// For example: "bridge:192.168.1.10"
391-
func (c *ContainerContext) IPAddresses() []string {
392-
ipAddresses := []string{}
393-
if c.c.NetworkSettings == nil {
394-
return ipAddresses
403+
func (c *ContainerContext) IPAddresses() []NetworkIP {
404+
if c.c.NetworkSettings == nil || len(c.c.NetworkSettings.Networks) == 0 {
405+
return []NetworkIP{}
395406
}
407+
ipAddresses := make([]NetworkIP, 0, len(c.c.NetworkSettings.Networks))
396408
for name, nw := range c.c.NetworkSettings.Networks {
397409
if nw.IPAddress.IsValid() {
398-
ipAddresses = append(ipAddresses, name+":"+nw.IPAddress.String())
410+
ipAddresses = append(ipAddresses, NetworkIP{
411+
Network: name,
412+
IP: nw.IPAddress.String(),
413+
})
399414
}
400415
if nw.GlobalIPv6Address.IsValid() {
401-
ipAddresses = append(ipAddresses, name+":"+nw.GlobalIPv6Address.String())
416+
ipAddresses = append(ipAddresses, NetworkIP{
417+
Network: name,
418+
IP: nw.GlobalIPv6Address.String(),
419+
})
402420
}
403421
}
422+
423+
slices.SortFunc(ipAddresses, func(a, b NetworkIP) int {
424+
return cmp.Compare(a.String(), b.String())
425+
})
426+
404427
return ipAddresses
405428
}
406429

cli/command/formatter/container_test.go

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,18 @@ func TestContainerContextWriteJSON(t *testing.T) {
477477
Image: "ubuntu",
478478
Created: unix,
479479
State: container.StateRunning,
480-
480+
NetworkSettings: &container.NetworkSettingsSummary{
481+
Networks: map[string]*network.EndpointSettings{
482+
"bridge": {
483+
IPAddress: netip.MustParseAddr("172.17.0.1"),
484+
GlobalIPv6Address: netip.MustParseAddr("ff02::1"),
485+
},
486+
"my-net": {
487+
IPAddress: netip.MustParseAddr("172.18.0.1"),
488+
GlobalIPv6Address: netip.MustParseAddr("ff02::2"),
489+
},
490+
},
491+
},
481492
ImageManifestDescriptor: &ocispec.Descriptor{Platform: &ocispec.Platform{Architecture: "amd64", OS: "linux"}},
482493
},
483494
{
@@ -497,6 +508,7 @@ func TestContainerContextWriteJSON(t *testing.T) {
497508
"CreatedAt": expectedCreated,
498509
"HealthStatus": "",
499510
"ID": "containerID1",
511+
"IPAddresses": []any{},
500512
"Image": "ubuntu",
501513
"Labels": "",
502514
"LocalVolumes": "0",
@@ -515,12 +527,18 @@ func TestContainerContextWriteJSON(t *testing.T) {
515527
"CreatedAt": expectedCreated,
516528
"HealthStatus": "",
517529
"ID": "containerID2",
530+
"IPAddresses": []any{
531+
map[string]any{"IP": "172.17.0.1", "Network": "bridge"},
532+
map[string]any{"IP": "ff02::1", "Network": "bridge"},
533+
map[string]any{"IP": "172.18.0.1", "Network": "my-net"},
534+
map[string]any{"IP": "ff02::2", "Network": "my-net"},
535+
},
518536
"Image": "ubuntu",
519537
"Labels": "",
520538
"LocalVolumes": "0",
521539
"Mounts": "",
522540
"Names": "foobar_bar",
523-
"Networks": "",
541+
"Networks": "bridge,my-net",
524542
"Platform": map[string]any{"architecture": "amd64", "os": "linux"},
525543
"Ports": "",
526544
"RunningFor": "About a minute ago",
@@ -533,6 +551,7 @@ func TestContainerContextWriteJSON(t *testing.T) {
533551
"CreatedAt": expectedCreated,
534552
"HealthStatus": "",
535553
"ID": "containerID3",
554+
"IPAddresses": []any{},
536555
"Image": "ubuntu",
537556
"Labels": "",
538557
"LocalVolumes": "0",
@@ -605,8 +624,8 @@ func TestContainerContextIPAddresses(t *testing.T) {
605624
out := bytes.NewBufferString("")
606625
err := ContainerWrite(Context{Format: "{{.IPAddresses}}", Output: out}, containers)
607626
assert.NilError(t, err)
608-
assert.Equal(t, out.String(), `[one:192.168.1.2 two:192.168.178.2]
609-
[one:192.168.1.3 two:192.168.178.3]
627+
assert.Equal(t, out.String(), `[one/192.168.1.2 two/192.168.178.2]
628+
[one/192.168.1.3 two/192.168.178.3]
610629
`)
611630
}
612631

docs/reference/commandline/container_ls.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,6 @@ Show the IP-addresses that containers have:
455455
$ docker ps --format "table {{.ID}}\\t{{join .IPAddresses \", \"}}"
456456

457457
CONTAINER ID IP ADDRESSES
458-
c0cf2877da71 bridge:172.17.0.3
459-
17e7d1910fc0 bridge:172.17.0.2, mynetwork:172.19.0.2
458+
c0cf2877da71 bridge/172.17.0.3
459+
17e7d1910fc0 bridge/172.17.0.2, mynetwork/172.19.0.2
460460
```

0 commit comments

Comments
 (0)