Skip to content

Commit 2e0748f

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 0cfea7d commit 2e0748f

3 files changed

Lines changed: 57 additions & 15 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"
@@ -40,6 +42,16 @@ func (p Platform) String() string {
4042
return platforms.FormatAll(p.Platform)
4143
}
4244

45+
// NetworkIP describes an IP-address and the network it's associated with.
46+
type NetworkIP struct {
47+
Network string `json:"Network,omitempty"`
48+
IP string `json:"IP"`
49+
}
50+
51+
func (p NetworkIP) String() string {
52+
return p.Network + "/" + p.IP
53+
}
54+
4355
// NewContainerFormat returns a Format for rendering using a Context
4456
func NewContainerFormat(source string, quiet bool, size bool) Format {
4557
switch source {
@@ -346,19 +358,30 @@ func (c *ContainerContext) Networks() string {
346358
// IPAddresses returns the list of IP-addresses assigned to the container
347359
// IP-addresses are prefixed with the name of the network, separated with a colon.
348360
// For example: "bridge:192.168.1.10"
349-
func (c *ContainerContext) IPAddresses() []string {
350-
ipAddresses := []string{}
351-
if c.c.NetworkSettings == nil {
352-
return ipAddresses
361+
func (c *ContainerContext) IPAddresses() []NetworkIP {
362+
if c.c.NetworkSettings == nil || len(c.c.NetworkSettings.Networks) == 0 {
363+
return []NetworkIP{}
353364
}
365+
ipAddresses := make([]NetworkIP, 0, len(c.c.NetworkSettings.Networks))
354366
for name, nw := range c.c.NetworkSettings.Networks {
355367
if nw.IPAddress != "" {
356-
ipAddresses = append(ipAddresses, name+":"+nw.IPAddress)
368+
ipAddresses = append(ipAddresses, NetworkIP{
369+
Network: name,
370+
IP: nw.IPAddress,
371+
})
357372
}
358373
if nw.GlobalIPv6Address != "" {
359-
ipAddresses = append(ipAddresses, name+":"+nw.GlobalIPv6Address)
374+
ipAddresses = append(ipAddresses, NetworkIP{
375+
Network: name,
376+
IP: nw.GlobalIPv6Address,
377+
})
360378
}
361379
}
380+
381+
slices.SortFunc(ipAddresses, func(a, b NetworkIP) int {
382+
return cmp.Compare(a.String(), b.String())
383+
})
384+
362385
return ipAddresses
363386
}
364387

cli/command/formatter/container_test.go

Lines changed: 26 additions & 7 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: "172.17.0.1",
484+
GlobalIPv6Address: "ff02::1",
485+
},
486+
"my-net": {
487+
IPAddress: "172.18.0.1",
488+
GlobalIPv6Address: "ff02::2",
489+
},
490+
},
491+
},
481492
ImageManifestDescriptor: &ocispec.Descriptor{Platform: &ocispec.Platform{Architecture: "amd64", OS: "linux"}},
482493
},
483494
{
@@ -496,6 +507,7 @@ func TestContainerContextWriteJSON(t *testing.T) {
496507
"Command": `""`,
497508
"CreatedAt": expectedCreated,
498509
"ID": "containerID1",
510+
"IPAddresses": []any{},
499511
"Image": "ubuntu",
500512
"Labels": "",
501513
"LocalVolumes": "0",
@@ -510,15 +522,21 @@ func TestContainerContextWriteJSON(t *testing.T) {
510522
"Status": "",
511523
},
512524
{
513-
"Command": `""`,
514-
"CreatedAt": expectedCreated,
515-
"ID": "containerID2",
525+
"Command": `""`,
526+
"CreatedAt": expectedCreated,
527+
"ID": "containerID2",
528+
"IPAddresses": []any{
529+
map[string]any{"IP": "172.17.0.1", "Network": "bridge"},
530+
map[string]any{"IP": "ff02::1", "Network": "bridge"},
531+
map[string]any{"IP": "172.18.0.1", "Network": "my-net"},
532+
map[string]any{"IP": "ff02::2", "Network": "my-net"},
533+
},
516534
"Image": "ubuntu",
517535
"Labels": "",
518536
"LocalVolumes": "0",
519537
"Mounts": "",
520538
"Names": "foobar_bar",
521-
"Networks": "",
539+
"Networks": "bridge,my-net",
522540
"Platform": map[string]any{"architecture": "amd64", "os": "linux"},
523541
"Ports": "",
524542
"RunningFor": "About a minute ago",
@@ -530,6 +548,7 @@ func TestContainerContextWriteJSON(t *testing.T) {
530548
"Command": `""`,
531549
"CreatedAt": expectedCreated,
532550
"ID": "containerID3",
551+
"IPAddresses": []any{},
533552
"Image": "ubuntu",
534553
"Labels": "",
535554
"LocalVolumes": "0",
@@ -602,8 +621,8 @@ func TestContainerContextIPAddresses(t *testing.T) {
602621
out := bytes.NewBufferString("")
603622
err := ContainerWrite(Context{Format: "{{.IPAddresses}}", Output: out}, containers)
604623
assert.NilError(t, err)
605-
assert.Equal(t, out.String(), `[one:192.168.1.2 two:192.168.178.2]
606-
[one:192.168.1.3 two:192.168.178.3]
624+
assert.Equal(t, out.String(), `[one/192.168.1.2 two/192.168.178.2]
625+
[one/192.168.1.3 two/192.168.178.3]
607626
`)
608627
}
609628

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)