diff --git a/cmd/nerdctl/network/network_inspect_test.go b/cmd/nerdctl/network/network_inspect_test.go index 980ade0ad57..84e5e6f9dcb 100644 --- a/cmd/nerdctl/network/network_inspect_test.go +++ b/cmd/nerdctl/network/network_inspect_test.go @@ -62,7 +62,6 @@ func TestNetworkInspectBasic(t *testing.T) { }, { Description: "none", - Require: nerdtest.NerdctlNeedsFixing("no issue opened"), Command: test.Command("network", "inspect", "none"), Expected: test.Expects(0, nil, func(stdout string, t tig.T) { var dc []dockercompat.Network @@ -74,7 +73,6 @@ func TestNetworkInspectBasic(t *testing.T) { }, { Description: "host", - Require: nerdtest.NerdctlNeedsFixing("no issue opened"), Command: test.Command("network", "inspect", "host"), Expected: test.Expects(0, nil, func(stdout string, t tig.T) { var dc []dockercompat.Network diff --git a/pkg/netutil/cni_plugin.go b/pkg/netutil/cni_plugin.go index f4d65359f2e..b44e76042e2 100644 --- a/pkg/netutil/cni_plugin.go +++ b/pkg/netutil/cni_plugin.go @@ -20,6 +20,14 @@ type CNIPlugin interface { GetPluginType() string } +type pseudoNetworkPlugin struct { + PluginType string `json:"type"` +} + +func (p *pseudoNetworkPlugin) GetPluginType() string { + return p.PluginType +} + type IPAMRange struct { Subnet string `json:"subnet"` RangeStart string `json:"rangeStart,omitempty"` diff --git a/pkg/netutil/netutil.go b/pkg/netutil/netutil.go index c3312bb5191..5f213d8692f 100644 --- a/pkg/netutil/netutil.go +++ b/pkg/netutil/netutil.go @@ -60,8 +60,17 @@ func (e *CNIEnv) ListNetworksMatch(reqs []string, allowPseudoNetwork bool) (list list = make(map[string][]*NetworkConfig) for _, req := range reqs { - if !allowPseudoNetwork && (req == "host" || req == "none") { - errs = append(errs, fmt.Errorf("pseudo network not allowed: %s", req)) + if req == "host" || req == "none" { + if !allowPseudoNetwork { + errs = append(errs, fmt.Errorf("pseudo network not allowed: %s", req)) + continue + } + cfg, err := newPseudoNetworkConfig(req) + if err != nil { + errs = append(errs, err) + continue + } + list[req] = []*NetworkConfig{cfg} continue } @@ -88,6 +97,30 @@ func (e *CNIEnv) ListNetworksMatch(reqs []string, allowPseudoNetwork bool) (list return list, errs } +func newPseudoNetworkConfig(name string) (*NetworkConfig, error) { + confJSON, err := json.Marshal(&cniNetworkConfig{ + CNIVersion: "1.0.0", + Name: name, + // Pseudo networks are not backed by real CNI config files. We still need a + // parseable config object so network inspect can render them consistently. + Plugins: []CNIPlugin{ + &pseudoNetworkPlugin{PluginType: "nerdctl-pseudo"}, + }, + }) + if err != nil { + return nil, err + } + + confList, err := libcni.ConfListFromBytes(confJSON) + if err != nil { + return nil, err + } + + return &NetworkConfig{ + NetworkConfigList: confList, + }, nil +} + func UsedNetworks(ctx context.Context, client *containerd.Client) (map[string][]string, error) { nsService := client.NamespaceService() nsList, err := nsService.List(ctx) @@ -288,8 +321,8 @@ type NetworkConfig struct { type cniNetworkConfig struct { CNIVersion string `json:"cniVersion"` Name string `json:"name"` - ID string `json:"nerdctlID"` - Labels map[string]string `json:"nerdctlLabels"` + ID string `json:"nerdctlID,omitempty"` + Labels map[string]string `json:"nerdctlLabels,omitempty"` Plugins []CNIPlugin `json:"plugins"` } diff --git a/pkg/netutil/netutil_test.go b/pkg/netutil/netutil_test.go index 383054ebd3e..f818c59a1b2 100644 --- a/pkg/netutil/netutil_test.go +++ b/pkg/netutil/netutil_test.go @@ -379,3 +379,33 @@ func TestFSExistsPropagatesStatError(t *testing.T) { assert.Assert(t, !exists) assert.Assert(t, err != nil) } + +func TestListNetworksMatchIncludesPseudoNetworks(t *testing.T) { + cniConfTestDir := t.TempDir() + cniEnv := CNIEnv{ + Path: t.TempDir(), + NetconfPath: cniConfTestDir, + } + + values := map[string]string{ + "network_name": "regular-network", + "subnet": "10.7.1.0/24", + "gateway": "10.7.1.1", + } + tpl, err := template.New("test").Parse(preExistingNetworkConfigTemplate) + assert.NilError(t, err) + buf := &bytes.Buffer{} + assert.NilError(t, tpl.ExecuteTemplate(buf, "test", values)) + + testConfFile := filepath.Join(cniConfTestDir, fmt.Sprintf("%s.conf", testutil.Identifier(t))) + assert.NilError(t, filesystem.WriteFile(testConfFile, buf.Bytes(), 0600)) + + matches, errs := cniEnv.ListNetworksMatch([]string{"host", "none", "regular-network"}, true) + assert.Assert(t, len(errs) == 0) + assert.Equal(t, len(matches["host"]), 1) + assert.Equal(t, matches["host"][0].Name, "host") + assert.Equal(t, len(matches["none"]), 1) + assert.Equal(t, matches["none"][0].Name, "none") + assert.Equal(t, len(matches["regular-network"]), 1) + assert.Equal(t, matches["regular-network"][0].Name, "regular-network") +}