Skip to content

Commit c8e2272

Browse files
committed
Add gateway to docker inspect output
Signed-off-by: Mustaeen Ahmed <contact@mustaeen.dev> add test TestContainerInspectGateway Signed-off-by: Mustaeen Ahmed <contact@mustaeen.dev> Fix test issues Signed-off-by: Mustaeen Ahmed <contact@mustaeen.dev> Remove container.test Signed-off-by: Mustaeen Ahmed <contact@mustaeen.dev> Resolve review and tests Signed-off-by: Mustaeen Ahmed <contact@mustaeen.dev> feature: populate NetworkSettings.Gateway and add e2e coverage Signed-off-by: Mustaeen Ahmed <contact@mustaeen.dev> Resolve test issues Signed-off-by: Mustaeen Ahmed <contact@mustaeen.dev> feature: populate NetworkSettings.Gateway and add e2e coverage
1 parent e721fde commit c8e2272

File tree

6 files changed

+124
-5
lines changed

6 files changed

+124
-5
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
Copyright The containerd Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package container
18+
19+
import (
20+
"testing"
21+
22+
"gotest.tools/v3/assert"
23+
24+
"github.com/containerd/nerdctl/mod/tigron/require"
25+
"github.com/containerd/nerdctl/mod/tigron/test"
26+
"github.com/containerd/nerdctl/mod/tigron/tig"
27+
28+
"github.com/containerd/nerdctl/v2/pkg/testutil"
29+
"github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest"
30+
)
31+
32+
func TestContainerInspectGateway(t *testing.T) {
33+
testCase := nerdtest.Setup()
34+
35+
// This test validates nerdctl's inspect conversion path
36+
// Running this against Docker would not use this code path
37+
testCase.Require = require.All(
38+
require.Not(require.Windows),
39+
require.Not(nerdtest.Docker),
40+
nerdtest.Rootful,
41+
)
42+
43+
testCase.Setup = func(data test.Data, helpers test.Helpers) {
44+
helpers.Ensure("network", "create", data.Identifier("net"))
45+
46+
helpers.Ensure("run", "-d",
47+
"--name", data.Identifier("ctr"),
48+
"--network", data.Identifier("net"),
49+
testutil.CommonImage, "sleep", nerdtest.Infinity)
50+
51+
nerdtest.EnsureContainerStarted(helpers, data.Identifier("ctr"))
52+
}
53+
54+
testCase.Cleanup = func(data test.Data, helpers test.Helpers) {
55+
helpers.Anyhow("rm", "-f", data.Identifier("ctr"))
56+
helpers.Anyhow("network", "rm", data.Identifier("net"))
57+
}
58+
59+
testCase.Command = func(data test.Data, helpers test.Helpers) test.TestableCommand {
60+
return helpers.Command("container", "inspect", data.Identifier("ctr"))
61+
}
62+
63+
testCase.Expected = func(data test.Data, helpers test.Helpers) *test.Expected {
64+
return &test.Expected{
65+
ExitCode: 0,
66+
Output: func(_ string, t tig.T) {
67+
netInspect := nerdtest.InspectNetwork(helpers, data.Identifier("net"))
68+
assert.Assert(t, len(netInspect.IPAM.Config) > 0)
69+
assert.Assert(t, netInspect.IPAM.Config[0].Gateway != "")
70+
71+
ctrInspect := nerdtest.InspectContainer(helpers, data.Identifier("ctr"))
72+
assert.Assert(t, ctrInspect.NetworkSettings != nil)
73+
assert.Assert(t, ctrInspect.NetworkSettings.Gateway != "")
74+
assert.Equal(t, ctrInspect.NetworkSettings.Gateway, netInspect.IPAM.Config[0].Gateway)
75+
},
76+
}
77+
}
78+
79+
testCase.Run(t)
80+
}

pkg/containerinspector/containerinspector_linux.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"strings"
2424

2525
"github.com/containernetworking/plugins/pkg/ns"
26+
"github.com/vishvananda/netlink"
2627

2728
"github.com/containerd/nerdctl/v2/pkg/inspecttypes/native"
2829
)
@@ -55,6 +56,10 @@ func InspectNetNS(ctx context.Context, pid int) (*native.NetNS, error) {
5556
res.Interfaces[i] = x
5657
}
5758
res.PrimaryInterface = determinePrimaryInterface(res.Interfaces)
59+
routes, err := netlink.RouteList(nil, netlink.FAMILY_V4)
60+
if err == nil {
61+
res.Gateway = selectDefaultGateway(routes, res.PrimaryInterface)
62+
}
5863
return nil
5964
}
6065
if err := ns.WithNetNSPath(nsPath, fn); err != nil {
@@ -73,3 +78,27 @@ func determinePrimaryInterface(interfaces []native.NetInterface) int {
7378
}
7479
return 0
7580
}
81+
82+
func selectDefaultGateway(routes []netlink.Route, primaryIfIndex int) string {
83+
for _, route := range routes {
84+
if route.Dst != nil || route.Gw == nil {
85+
continue
86+
}
87+
if route.Gw.To4() == nil {
88+
continue
89+
}
90+
if route.LinkIndex == primaryIfIndex {
91+
return route.Gw.String()
92+
}
93+
}
94+
for _, route := range routes {
95+
if route.Dst != nil || route.Gw == nil {
96+
continue
97+
}
98+
if route.Gw.To4() == nil {
99+
continue
100+
}
101+
return route.Gw.String()
102+
}
103+
return ""
104+
}

pkg/dnsutil/hostsstore/hostsstore.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -328,23 +328,23 @@ func (x *hostsStore) updateAllHosts() (err error) {
328328
}
329329
}
330330

331-
buf.WriteString(fmt.Sprintf("# %s\n", MarkerBegin))
331+
fmt.Fprintf(&buf, "# %s\n", MarkerBegin)
332332
buf.WriteString("127.0.0.1 localhost localhost.localdomain\n")
333333
buf.WriteString("::1 localhost localhost.localdomain\n")
334334

335335
// keep extra hosts first
336336
for host, ip := range myMeta.ExtraHosts {
337-
buf.WriteString(fmt.Sprintf("%-15s %s\n", ip, host))
337+
fmt.Fprintf(&buf, "%-15s %s\n", ip, host)
338338
}
339339

340340
for ip, netName := range networkNameByIP {
341341
meta := metasByIP[ip]
342342
if line := createLine(netName, meta, myNetworks); len(line) != 0 {
343-
buf.WriteString(fmt.Sprintf("%-15s %s\n", ip, strings.Join(line, " ")))
343+
fmt.Fprintf(&buf, "%-15s %s\n", ip, strings.Join(line, " "))
344344
}
345345
}
346346

347-
buf.WriteString(fmt.Sprintf("# %s\n", MarkerEnd))
347+
fmt.Fprintf(&buf, "# %s\n", MarkerEnd)
348348

349349
var loc string
350350
loc, err = x.safeStore.Location(entry, hostsFile)

pkg/inspecttypes/dockercompat/dockercompat.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ type CPUSettings struct {
281281
// DefaultNetworkSettings is from https://github.com/moby/moby/blob/v20.10.1/api/types/types.go#L405-L414
282282
type DefaultNetworkSettings struct {
283283
// TODO EndpointID string // EndpointID uniquely represents a service endpoint in a Sandbox
284-
// TODO Gateway string // Gateway holds the gateway address for the network
284+
Gateway string // Gateway holds the gateway address for the network
285285
GlobalIPv6Address string // GlobalIPv6Address holds network's global IPv6 address
286286
GlobalIPv6PrefixLen int // GlobalIPv6PrefixLen represents mask length of network's global IPv6 address
287287
IPAddress string // IPAddress holds the IPv4 address for the network
@@ -743,6 +743,7 @@ func networkSettingsFromNative(n *native.NetNS, _ *specs.Spec) (*NetworkSettings
743743
}
744744

745745
}
746+
res.DefaultNetworkSettings.Gateway = n.Gateway
746747
if primary != nil {
747748
res.DefaultNetworkSettings.MacAddress = primary.MacAddress
748749
res.DefaultNetworkSettings.IPAddress = primary.IPAddress

pkg/inspecttypes/dockercompat/dockercompat_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ func TestNetworkSettingsFromNative(t *testing.T) {
401401
{
402402
name: "Given NetNS with single Interface with Port Annotation, Return populated NetworkSettings",
403403
n: &native.NetNS{
404+
Gateway: "10.0.4.1",
404405
Interfaces: []native.NetInterface{
405406
{
406407
Interface: net.Interface{
@@ -427,6 +428,9 @@ func TestNetworkSettingsFromNative(t *testing.T) {
427428
Annotations: map[string]string{},
428429
},
429430
expected: &NetworkSettings{
431+
DefaultNetworkSettings: DefaultNetworkSettings{
432+
Gateway: "10.0.4.1",
433+
},
430434
Ports: &nat.PortMap{
431435
nat.Port("77/tcp"): []nat.PortBinding{
432436
{
@@ -449,6 +453,7 @@ func TestNetworkSettingsFromNative(t *testing.T) {
449453
{
450454
name: "Given NetNS with single Interface without Port Annotations, Return valid NetworkSettings w/ empty Ports",
451455
n: &native.NetNS{
456+
Gateway: "10.0.4.1",
452457
Interfaces: []native.NetInterface{
453458
{
454459
Interface: net.Interface{
@@ -467,6 +472,9 @@ func TestNetworkSettingsFromNative(t *testing.T) {
467472
Annotations: map[string]string{},
468473
},
469474
expected: &NetworkSettings{
475+
DefaultNetworkSettings: DefaultNetworkSettings{
476+
Gateway: "10.0.4.1",
477+
},
470478
Ports: &nat.PortMap{},
471479
Networks: map[string]*NetworkEndpointSettings{
472480
"unknown-eth0.100": {

pkg/inspecttypes/native/container.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ type NetNS struct {
4444
// Zero means unset.
4545
PrimaryInterface int `json:"PrimaryInterface,omitempty"`
4646
Interfaces []NetInterface `json:"Interfaces,omitempty"`
47+
Gateway string `json:"Gateway,omitempty"`
4748
PortMappings []cni.PortMapping
4849
}
4950

0 commit comments

Comments
 (0)