Skip to content

Commit dce438f

Browse files
authored
Merge pull request #4052 from tushar5526/add-containers-to-inspect-output
feat: Add "Containers" propery in the "nerdctl network inspect" command.
2 parents b1f6646 + a7d46bc commit dce438f

File tree

5 files changed

+102
-8
lines changed

5 files changed

+102
-8
lines changed

cmd/nerdctl/network/network_inspect.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/containerd/nerdctl/v2/cmd/nerdctl/completion"
2323
"github.com/containerd/nerdctl/v2/cmd/nerdctl/helpers"
2424
"github.com/containerd/nerdctl/v2/pkg/api/types"
25+
"github.com/containerd/nerdctl/v2/pkg/clientutil"
2526
"github.com/containerd/nerdctl/v2/pkg/cmd/network"
2627
)
2728

@@ -59,13 +60,22 @@ func inspectAction(cmd *cobra.Command, args []string) error {
5960
if err != nil {
6061
return err
6162
}
62-
return network.Inspect(cmd.Context(), types.NetworkInspectOptions{
63+
64+
options := types.NetworkInspectOptions{
6365
GOptions: globalOptions,
6466
Mode: mode,
6567
Format: format,
6668
Networks: args,
6769
Stdout: cmd.OutOrStdout(),
68-
})
70+
}
71+
72+
client, ctx, cancel, err := clientutil.NewClient(cmd.Context(), options.GOptions.Namespace, options.GOptions.Address)
73+
if err != nil {
74+
return err
75+
}
76+
defer cancel()
77+
78+
return network.Inspect(ctx, client, options)
6979
}
7080

7181
func networkInspectShellComplete(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {

cmd/nerdctl/network/network_inspect_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/containerd/nerdctl/mod/tigron/test"
3030

3131
"github.com/containerd/nerdctl/v2/pkg/inspecttypes/dockercompat"
32+
"github.com/containerd/nerdctl/v2/pkg/testutil"
3233
"github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest"
3334
)
3435

@@ -278,6 +279,42 @@ func TestNetworkInspect(t *testing.T) {
278279
}
279280
},
280281
},
282+
{
283+
Description: "Verify that only active containers appear in the network inspect output",
284+
Setup: func(data test.Data, helpers test.Helpers) {
285+
helpers.Ensure("network", "create", data.Identifier("nginx-network-1"))
286+
helpers.Ensure("network", "create", data.Identifier("nginx-network-2"))
287+
helpers.Ensure("create", "--name", data.Identifier("nginx-container-1"), "--network", data.Identifier("nginx-network-1"), testutil.NginxAlpineImage)
288+
helpers.Ensure("create", "--name", data.Identifier("nginx-container-2"), "--network", data.Identifier("nginx-network-1"), testutil.NginxAlpineImage)
289+
helpers.Ensure("create", "--name", data.Identifier("nginx-container-on-diff-network"), "--network", data.Identifier("nginx-network-2"), testutil.NginxAlpineImage)
290+
helpers.Ensure("start", data.Identifier("nginx-container-1"), data.Identifier("nginx-container-on-diff-network"))
291+
data.Set("nginx-container-1-id", strings.Trim(helpers.Capture("inspect", data.Identifier("nginx-container-1"), "--format", "{{.Id}}"), "\n"))
292+
},
293+
Cleanup: func(data test.Data, helpers test.Helpers) {
294+
helpers.Anyhow("rm", "-f", data.Identifier("nginx-container-1"))
295+
helpers.Anyhow("rm", "-f", data.Identifier("nginx-container-2"))
296+
helpers.Anyhow("rm", "-f", data.Identifier("nginx-container-on-diff-network"))
297+
helpers.Anyhow("network", "remove", data.Identifier("nginx-network-1"))
298+
helpers.Anyhow("network", "remove", data.Identifier("nginx-network-2"))
299+
},
300+
Command: func(data test.Data, helpers test.Helpers) test.TestableCommand {
301+
return helpers.Command("network", "inspect", data.Identifier("nginx-network-1"))
302+
},
303+
Expected: func(data test.Data, helpers test.Helpers) *test.Expected {
304+
return &test.Expected{
305+
Output: func(stdout string, info string, t *testing.T) {
306+
var dc []dockercompat.Network
307+
err := json.Unmarshal([]byte(stdout), &dc)
308+
assert.NilError(t, err, "Unable to unmarshal output\n"+info)
309+
assert.Equal(t, 1, len(dc), "Unexpectedly got multiple results\n"+info)
310+
assert.Equal(t, dc[0].Name, data.Identifier("nginx-network-1"))
311+
// Assert only the "running" containers on the same network are returned.
312+
assert.Equal(t, 1, len(dc[0].Containers), "Expected a single container as per configuration, but got multiple.")
313+
assert.Equal(t, data.Identifier("nginx-container-1"), dc[0].Containers[data.Get("nginx-container-1-id")].Name)
314+
},
315+
}
316+
},
317+
},
281318
}
282319

283320
testCase.Run(t)

pkg/cmd/network/inspect.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,19 @@ import (
2222
"errors"
2323
"fmt"
2424

25+
containerd "github.com/containerd/containerd/v2/client"
2526
"github.com/containerd/log"
2627

2728
"github.com/containerd/nerdctl/v2/pkg/api/types"
29+
"github.com/containerd/nerdctl/v2/pkg/containerinspector"
2830
"github.com/containerd/nerdctl/v2/pkg/formatter"
2931
"github.com/containerd/nerdctl/v2/pkg/inspecttypes/dockercompat"
3032
"github.com/containerd/nerdctl/v2/pkg/inspecttypes/native"
33+
"github.com/containerd/nerdctl/v2/pkg/labels"
3134
"github.com/containerd/nerdctl/v2/pkg/netutil"
3235
)
3336

34-
func Inspect(ctx context.Context, options types.NetworkInspectOptions) error {
37+
func Inspect(ctx context.Context, client *containerd.Client, options types.NetworkInspectOptions) error {
3538
if options.Mode != "native" && options.Mode != "dockercompat" {
3639
return fmt.Errorf("unknown mode %q", options.Mode)
3740
}
@@ -53,12 +56,35 @@ func Inspect(ctx context.Context, options types.NetworkInspectOptions) error {
5356
errs = append(errs, fmt.Errorf("no network found matching: %s", req))
5457
continue
5558
}
59+
5660
network := netList[0]
61+
var filters = []string{fmt.Sprintf("labels.%q==%q", labels.Networks, []string{network.Name})}
62+
63+
filteredContainers, err := client.Containers(ctx, filters...)
64+
65+
if err != nil {
66+
return err
67+
}
68+
69+
var containers []*native.Container
70+
71+
for _, container := range filteredContainers {
72+
nativeContainer, err := containerinspector.Inspect(ctx, container)
73+
if err != nil {
74+
continue
75+
}
76+
if nativeContainer.Process == nil || nativeContainer.Process.Status.Status != containerd.Running {
77+
continue
78+
}
79+
containers = append(containers, nativeContainer)
80+
}
81+
5782
r := &native.Network{
5883
CNI: json.RawMessage(network.Bytes),
5984
NerdctlID: network.NerdctlID,
6085
NerdctlLabels: network.NerdctlLabels,
6186
File: network.File,
87+
Containers: containers,
6288
}
6389
switch options.Mode {
6490
case "native":

pkg/inspecttypes/dockercompat/dockercompat.go

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -902,13 +902,22 @@ type IPAM struct {
902902
// Network mimics a `docker network inspect` object.
903903
// From https://github.com/moby/moby/blob/v20.10.7/api/types/types.go#L430-L448
904904
type Network struct {
905-
Name string `json:"Name"`
906-
ID string `json:"Id,omitempty"` // optional in nerdctl
907-
IPAM IPAM `json:"IPAM,omitempty"`
908-
Labels map[string]string `json:"Labels"`
905+
Name string `json:"Name"`
906+
ID string `json:"Id,omitempty"` // optional in nerdctl
907+
IPAM IPAM `json:"IPAM,omitempty"`
908+
Labels map[string]string `json:"Labels"`
909+
Containers map[string]EndpointResource `json:"Containers"` // Containers contains endpoints belonging to the network
909910
// Scope, Driver, etc. are omitted
910911
}
911912

913+
type EndpointResource struct {
914+
Name string `json:"Name"`
915+
// EndpointID string `json:"EndpointID"`
916+
// MacAddress string `json:"MacAddress"`
917+
// IPv4Address string `json:"IPv4Address"`
918+
// IPv6Address string `json:"IPv6Address"`
919+
}
920+
912921
type structuredCNI struct {
913922
Name string `json:"name"`
914923
Plugins []struct {
@@ -948,6 +957,17 @@ func NetworkFromNative(n *native.Network) (*Network, error) {
948957
res.Labels = *n.NerdctlLabels
949958
}
950959

960+
res.Containers = make(map[string]EndpointResource)
961+
for _, container := range n.Containers {
962+
res.Containers[container.ID] = EndpointResource{
963+
Name: container.Labels[labels.Name],
964+
// EndpointID: container.EndpointID,
965+
// MacAddress: container.MacAddress,
966+
// IPv4Address: container.IPv4Address,
967+
// IPv6Address: container.IPv6Address,
968+
}
969+
}
970+
951971
return &res, nil
952972
}
953973

pkg/inspecttypes/native/network.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ package native
1818

1919
import "encoding/json"
2020

21-
// Network corresponds to pkg/netutil.NetworkConfigList
21+
// Network corresponds to pkg/netutil.NetworkConfig
2222
type Network struct {
2323
CNI json.RawMessage `json:"CNI,omitempty"`
2424
NerdctlID *string `json:"NerdctlID"`
2525
NerdctlLabels *map[string]string `json:"NerdctlLabels,omitempty"`
2626
File string `json:"File,omitempty"`
27+
Containers []*Container `json:"Containers"`
2728
}

0 commit comments

Comments
 (0)