client: NetworkInspect: wrap result and remove NetworkInspectWithRaw

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn
2025-10-21 17:26:24 +02:00
parent ac9838ffd1
commit 3fbf5a3bd1
16 changed files with 124 additions and 142 deletions

View File

@@ -130,8 +130,7 @@ type NetworkAPIClient interface {
NetworkConnect(ctx context.Context, network, container string, config *network.EndpointSettings) error
NetworkCreate(ctx context.Context, name string, options NetworkCreateOptions) (network.CreateResponse, error)
NetworkDisconnect(ctx context.Context, network, container string, force bool) error
NetworkInspect(ctx context.Context, network string, options NetworkInspectOptions) (network.Inspect, error)
NetworkInspectWithRaw(ctx context.Context, network string, options NetworkInspectOptions) (network.Inspect, []byte, error)
NetworkInspect(ctx context.Context, network string, options NetworkInspectOptions) (NetworkInspectResult, error)
NetworkList(ctx context.Context, options NetworkListOptions) ([]network.Summary, error)
NetworkRemove(ctx context.Context, network string) error
NetworksPrune(ctx context.Context, opts NetworkPruneOptions) (NetworkPruneResult, error)

View File

@@ -1,26 +1,23 @@
package client
import (
"bytes"
"context"
"encoding/json"
"io"
"net/url"
"github.com/moby/moby/api/types/network"
)
// NetworkInspect returns the information for a specific network configured in the docker host.
func (cli *Client) NetworkInspect(ctx context.Context, networkID string, options NetworkInspectOptions) (network.Inspect, error) {
networkResource, _, err := cli.NetworkInspectWithRaw(ctx, networkID, options)
return networkResource, err
// NetworkInspectResult contains the result of a network inspection.
type NetworkInspectResult struct {
Network network.Inspect
Raw []byte
}
// NetworkInspectWithRaw returns the information for a specific network configured in the docker host and its raw representation.
func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string, options NetworkInspectOptions) (network.Inspect, []byte, error) {
// NetworkInspect returns the information for a specific network configured in the docker host.
func (cli *Client) NetworkInspect(ctx context.Context, networkID string, options NetworkInspectOptions) (NetworkInspectResult, error) {
networkID, err := trimID("network", networkID)
if err != nil {
return network.Inspect{}, nil, err
return NetworkInspectResult{}, err
}
query := url.Values{}
if options.Verbose {
@@ -33,15 +30,10 @@ func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string,
resp, err := cli.get(ctx, "/networks/"+networkID, query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return network.Inspect{}, nil, err
return NetworkInspectResult{}, err
}
raw, err := io.ReadAll(resp.Body)
if err != nil {
return network.Inspect{}, nil, err
}
var nw network.Inspect
err = json.NewDecoder(bytes.NewReader(raw)).Decode(&nw)
return nw, raw, err
var out NetworkInspectResult
out.Raw, err = decodeWithRaw(resp, &out.Network)
return out, err
}

View File

@@ -77,13 +77,13 @@ func TestNetworkInspect(t *testing.T) {
t.Run("no options", func(t *testing.T) {
r, err := client.NetworkInspect(context.Background(), "network_id", NetworkInspectOptions{})
assert.NilError(t, err)
assert.Check(t, is.Equal(r.Name, "mynetwork"))
assert.Check(t, is.Equal(r.Network.Name, "mynetwork"))
})
t.Run("verbose", func(t *testing.T) {
r, err := client.NetworkInspect(context.Background(), "network_id", NetworkInspectOptions{Verbose: true})
assert.NilError(t, err)
assert.Check(t, is.Equal(r.Name, "mynetwork"))
_, ok := r.Services["web"]
assert.Check(t, is.Equal(r.Network.Name, "mynetwork"))
_, ok := r.Network.Services["web"]
assert.Check(t, ok, "expected service `web` missing in the verbose output")
})
t.Run("global scope", func(t *testing.T) {

View File

@@ -1025,10 +1025,10 @@ func (s *DockerSwarmSuite) TestAPINetworkInspectWithScope(c *testing.T) {
resp, err := apiclient.NetworkCreate(ctx, name, client.NetworkCreateOptions{Driver: "overlay"})
assert.NilError(c, err)
nw, err := apiclient.NetworkInspect(ctx, name, client.NetworkInspectOptions{})
res, err := apiclient.NetworkInspect(ctx, name, client.NetworkInspectOptions{})
assert.NilError(c, err)
assert.Check(c, is.Equal("swarm", nw.Scope))
assert.Check(c, is.Equal(resp.ID, nw.ID))
assert.Check(c, is.Equal("swarm", res.Network.Scope))
assert.Check(c, is.Equal(resp.ID, res.Network.ID))
_, err = apiclient.NetworkInspect(ctx, name, client.NetworkInspectOptions{Scope: "local"})
assert.Check(c, is.ErrorType(err, cerrdefs.IsNotFound))

View File

@@ -153,9 +153,9 @@ func TestDaemonHostGatewayIP(t *testing.T) {
assert.NilError(t, err)
assert.Assert(t, is.Len(res.Stderr(), 0))
assert.Equal(t, 0, res.ExitCode)
inspect, err := c.NetworkInspect(ctx, "bridge", client.NetworkInspectOptions{})
resp, err := c.NetworkInspect(ctx, "bridge", client.NetworkInspectOptions{})
assert.NilError(t, err)
assert.Check(t, is.Contains(res.Stdout(), inspect.IPAM.Config[0].Gateway.String()))
assert.Check(t, is.Contains(res.Stdout(), resp.Network.IPAM.Config[0].Gateway.String()))
c.ContainerRemove(ctx, cID, client.ContainerRemoveOptions{Force: true})
d.Stop(t)

View File

@@ -420,7 +420,7 @@ func testDefaultBridgeIPAM(ctx context.Context, t *testing.T, tc defaultBridgeIP
c := d.NewClientT(t)
defer c.Close()
insp, err := c.NetworkInspect(ctx, network.NetworkBridge, client.NetworkInspectOptions{})
res, err := c.NetworkInspect(ctx, network.NetworkBridge, client.NetworkInspectOptions{})
assert.NilError(t, err)
expIPAMConfig := slices.Clone(tc.expIPAMConfig)
for i := range expIPAMConfig {
@@ -428,7 +428,7 @@ func testDefaultBridgeIPAM(ctx context.Context, t *testing.T, tc defaultBridgeIP
expIPAMConfig[i].Gateway = llAddr
}
}
assert.Check(t, is.DeepEqual(insp.IPAM.Config, expIPAMConfig, cmpopts.EquateComparable(netip.Addr{}, netip.Prefix{})))
assert.Check(t, is.DeepEqual(res.Network.IPAM.Config, expIPAMConfig, cmpopts.EquateComparable(netip.Addr{}, netip.Prefix{})))
})
})
}

View File

@@ -65,10 +65,10 @@ func TestCreateWithIPv6DefaultsToULAPrefix(t *testing.T) {
network.CreateNoError(ctx, t, apiClient, nwName, network.WithIPv6())
defer network.RemoveNoError(ctx, t, apiClient, nwName)
nw, err := apiClient.NetworkInspect(ctx, "testnetula", client.NetworkInspectOptions{})
res, err := apiClient.NetworkInspect(ctx, "testnetula", client.NetworkInspectOptions{})
assert.NilError(t, err)
for _, ipam := range nw.IPAM.Config {
for _, ipam := range res.Network.IPAM.Config {
if netip.MustParsePrefix("fd00::/8").Overlaps(ipam.Subnet) {
return
}
@@ -91,10 +91,10 @@ func TestCreateWithIPv6WithoutEnableIPv6Flag(t *testing.T) {
network.CreateNoError(ctx, t, apiClient, nwName)
defer network.RemoveNoError(ctx, t, apiClient, nwName)
nw, err := apiClient.NetworkInspect(ctx, "testnetula", client.NetworkInspectOptions{})
res, err := apiClient.NetworkInspect(ctx, "testnetula", client.NetworkInspectOptions{})
assert.NilError(t, err)
for _, ipam := range nw.IPAM.Config {
for _, ipam := range res.Network.IPAM.Config {
if netip.MustParsePrefix("fd00::/8").Overlaps(ipam.Subnet) {
return
}
@@ -135,20 +135,20 @@ func TestDefaultIPvOptOverride(t *testing.T) {
network.CreateNoError(ctx, t, c, netName, nopts...)
defer network.RemoveNoError(ctx, t, c, netName)
insp, err := c.NetworkInspect(ctx, netName, client.NetworkInspectOptions{})
res, err := c.NetworkInspect(ctx, netName, client.NetworkInspectOptions{})
assert.NilError(t, err)
t.Log("override4", override4, "override6", override6, "->", insp.Options)
t.Log("override4", override4, "override6", override6, "->", res.Network.Options)
gotOpt4, have4 := insp.Options[netlabel.EnableIPv4]
gotOpt4, have4 := res.Network.Options[netlabel.EnableIPv4]
assert.Check(t, is.Equal(have4, !override4))
assert.Check(t, is.Equal(insp.EnableIPv4, override4))
assert.Check(t, is.Equal(res.Network.EnableIPv4, override4))
if have4 {
assert.Check(t, is.Equal(gotOpt4, opt4))
}
gotOpt6, have6 := insp.Options[netlabel.EnableIPv6]
gotOpt6, have6 := res.Network.Options[netlabel.EnableIPv6]
assert.Check(t, is.Equal(have6, !override6))
assert.Check(t, is.Equal(insp.EnableIPv6, true))
assert.Check(t, is.Equal(res.Network.EnableIPv6, true))
if have6 {
assert.Check(t, is.Equal(gotOpt6, opt6))
}
@@ -1074,9 +1074,9 @@ func TestBridgeIPAMStatus(t *testing.T) {
netName string, want networktypes.SubnetStatuses,
) bool {
t.Helper()
nw, err := c.NetworkInspect(ctx, netName, client.NetworkInspectOptions{})
if assert.Check(t, err) && assert.Check(t, nw.Status != nil) {
return assert.Check(t, is.DeepEqual(want, nw.Status.IPAM.Subnets))
res, err := c.NetworkInspect(ctx, netName, client.NetworkInspectOptions{})
if assert.Check(t, err) && assert.Check(t, res.Network.Status != nil) {
return assert.Check(t, is.DeepEqual(want, res.Network.Status.IPAM.Subnets))
}
return false
}
@@ -1188,9 +1188,9 @@ func TestBridgeIPAMStatus(t *testing.T) {
})
oldc := d.NewClientT(t, client.WithVersion("1.51"))
nw, err := oldc.NetworkInspect(ctx, netName, client.NetworkInspectOptions{})
res, err := oldc.NetworkInspect(ctx, netName, client.NetworkInspectOptions{})
if assert.Check(t, err) {
assert.Check(t, nw.Status == nil, "expected nil Status with API version 1.51")
assert.Check(t, res.Network.Status == nil, "expected nil Status with API version 1.51")
}
})
@@ -1260,7 +1260,7 @@ func TestJoinError(t *testing.T) {
// extNet should not report any attached containers
extNetInsp, err := c.NetworkInspect(ctx, extNet, client.NetworkInspectOptions{})
assert.Check(t, err)
assert.Check(t, is.Len(extNetInsp.Containers, 0))
assert.Check(t, is.Len(extNetInsp.Network.Containers, 0))
// The container should have an eth0, but no eth1.
res = ctr.ExecT(ctx, t, c, cid, []string{"ip", "link", "show", "eth0"})
@@ -1281,7 +1281,7 @@ func TestJoinError(t *testing.T) {
assert.Check(t, is.Contains(ctrInsp.NetworkSettings.Networks, extNet))
extNetInsp, err = c.NetworkInspect(ctx, extNet, client.NetworkInspectOptions{})
assert.Check(t, err)
assert.Check(t, is.Len(extNetInsp.Containers, 1))
assert.Check(t, is.Len(extNetInsp.Network.Containers, 1))
res = ctr.ExecT(ctx, t, c, cid, []string{"ip", "link", "show", "eth0"})
assert.Check(t, is.Equal(res.ExitCode, 0), "container should have an eth0")
res = ctr.ExecT(ctx, t, c, cid, []string{"ip", "link", "show", "eth1"})

View File

@@ -125,34 +125,34 @@ func TestInspectNetwork(t *testing.T) {
for _, d := range append([]*daemon.Daemon{worker1}, mgr[:]...) {
t.Logf("--- Node %s (%s) ---", d.ID(), d.NodeID())
c := d.NewClientT(t)
nw, err := c.NetworkInspect(ctx, tc.network, tc.opts)
res, err := c.NetworkInspect(ctx, tc.network, tc.opts)
if !assert.Check(t, err) {
continue
}
assert.Check(t, nw.IPAM.Config != nil)
for _, cfg := range nw.IPAM.Config {
assert.Check(t, res.Network.IPAM.Config != nil)
for _, cfg := range res.Network.IPAM.Config {
assert.Assert(t, cfg.Gateway.IsValid())
assert.Assert(t, cfg.Subnet.IsValid())
}
if d.CachedInfo.Swarm.ControlAvailable {
// The global view of the network status is only available from manager nodes.
if assert.Check(t, nw.Status != nil) {
if assert.Check(t, res.Network.Status != nil) {
wantSubnetStatus := map[netip.Prefix]networktypes.SubnetStatus{
cidrv4: {
IPsInUse: uint64(1 + instances + len(mgr) + 1),
DynamicIPsAvailable: uint64(128 - (instances + len(mgr) + 1)),
},
}
assert.Check(t, is.DeepEqual(wantSubnetStatus, nw.Status.IPAM.Subnets))
assert.Check(t, is.DeepEqual(wantSubnetStatus, res.Network.Status.IPAM.Subnets))
}
} else {
// Services are only inspectable on nodes that have the network instantiated in
// libnetwork, i.e. nodes with tasks attached to the network. In this test, only
// the one worker node has tasks assigned.
if assert.Check(t, is.Contains(nw.Services, serviceName)) {
assert.Check(t, is.Len(nw.Services[serviceName].Tasks, instances))
if assert.Check(t, is.Contains(res.Network.Services, serviceName)) {
assert.Check(t, is.Len(res.Network.Services[serviceName].Tasks, instances))
}
}
c.Close()

View File

@@ -552,15 +552,15 @@ func TestIpvlanIPAM(t *testing.T) {
assert.Check(t, is.Equal(strings.TrimSpace(sysctlRes.Combined()), expDisableIPv6))
cc := d.NewClientT(t, dclient.WithVersion("1.52"))
inspect, err := cc.NetworkInspect(ctx, netName, dclient.NetworkInspectOptions{})
if assert.Check(t, err) && assert.Check(t, inspect.Status != nil) {
assert.Check(t, is.DeepEqual(wantSubnetStatus, inspect.Status.IPAM.Subnets, cmpopts.EquateEmpty()))
res, err := cc.NetworkInspect(ctx, netName, dclient.NetworkInspectOptions{})
if assert.Check(t, err) && assert.Check(t, res.Network.Status != nil) {
assert.Check(t, is.DeepEqual(wantSubnetStatus, res.Network.Status.IPAM.Subnets, cmpopts.EquateEmpty()))
}
cc.Close()
cc = d.NewClientT(t, dclient.WithVersion("1.51"))
inspect, err = cc.NetworkInspect(ctx, netName, dclient.NetworkInspectOptions{})
res, err = cc.NetworkInspect(ctx, netName, dclient.NetworkInspectOptions{})
assert.Check(t, err)
assert.Check(t, inspect.Status == nil)
assert.Check(t, res.Network.Status == nil)
cc.Close()
})
}
@@ -585,9 +585,9 @@ func TestIpvlanIPAMOverlap(t *testing.T) {
checkNetworkIPAMState := func(networkID string, want map[netip.Prefix]network.SubnetStatus) bool {
t.Helper()
nw, err := c.NetworkInspect(ctx, networkID, dclient.NetworkInspectOptions{})
if assert.Check(t, err) && assert.Check(t, nw.Status != nil) {
return assert.Check(t, is.DeepEqual(want, nw.Status.IPAM.Subnets, cmpopts.EquateEmpty()))
res, err := c.NetworkInspect(ctx, networkID, dclient.NetworkInspectOptions{})
if assert.Check(t, err) && assert.Check(t, res.Network.Status != nil) {
return assert.Check(t, is.DeepEqual(want, res.Network.Status.IPAM.Subnets, cmpopts.EquateEmpty()))
}
return false
}

View File

@@ -555,16 +555,16 @@ func TestMacvlanIPAM(t *testing.T) {
assert.Check(t, is.Equal(strings.TrimSpace(sysctlRes.Combined()), expDisableIPv6))
cc := d.NewClientT(t, client.WithVersion("1.52"))
inspect, err := cc.NetworkInspect(ctx, netName, client.NetworkInspectOptions{})
if assert.Check(t, err) && assert.Check(t, inspect.Status != nil) {
assert.Check(t, is.DeepEqual(wantSubnetStatus, inspect.Status.IPAM.Subnets, cmpopts.EquateEmpty()))
res, err := cc.NetworkInspect(ctx, netName, client.NetworkInspectOptions{})
if assert.Check(t, err) && assert.Check(t, res.Network.Status != nil) {
assert.Check(t, is.DeepEqual(wantSubnetStatus, res.Network.Status.IPAM.Subnets, cmpopts.EquateEmpty()))
}
cc.Close()
_ = cc.Close()
cc = d.NewClientT(t, client.WithVersion("1.51"))
inspect, err = cc.NetworkInspect(ctx, netName, client.NetworkInspectOptions{})
res, err = cc.NetworkInspect(ctx, netName, client.NetworkInspectOptions{})
assert.Check(t, err)
assert.Check(t, inspect.Status == nil)
cc.Close()
assert.Check(t, res.Network.Status == nil)
_ = cc.Close()
})
}
}
@@ -588,9 +588,9 @@ func TestMacvlanIPAMOverlap(t *testing.T) {
checkNetworkIPAMState := func(networkID string, want map[netip.Prefix]network.SubnetStatus) bool {
t.Helper()
nw, err := c.NetworkInspect(ctx, networkID, client.NetworkInspectOptions{})
if assert.Check(t, err) && assert.Check(t, nw.Status != nil) {
return assert.Check(t, is.DeepEqual(want, nw.Status.IPAM.Subnets, cmpopts.EquateEmpty()))
res, err := c.NetworkInspect(ctx, networkID, client.NetworkInspectOptions{})
if assert.Check(t, err) && assert.Check(t, res.Network.Status != nil) {
return assert.Check(t, is.DeepEqual(want, res.Network.Status.IPAM.Subnets, cmpopts.EquateEmpty()))
}
return false
}

View File

@@ -88,17 +88,17 @@ func TestHostIPv4BridgeLabel(t *testing.T) {
network.WithOption("com.docker.network.bridge.name", bridgeName),
)
defer network.RemoveNoError(ctx, t, c, bridgeName)
out, err := c.NetworkInspect(ctx, bridgeName, client.NetworkInspectOptions{Verbose: true})
res, err := c.NetworkInspect(ctx, bridgeName, client.NetworkInspectOptions{Verbose: true})
assert.NilError(t, err)
assert.Assert(t, len(out.IPAM.Config) > 0)
assert.Assert(t, len(res.Network.IPAM.Config) > 0)
// Make sure the SNAT rule exists
if strings.HasPrefix(testEnv.FirewallBackendDriver(), "nftables") {
chain := testutil.RunCommand(ctx, "nft", "--stateless", "list", "chain", "ip", "docker-bridges", "nat-postrouting-out__hostIPv4Bridge").Combined()
exp := fmt.Sprintf(`oifname != "hostIPv4Bridge" ip saddr %s counter snat to %s comment "SNAT"`,
out.IPAM.Config[0].Subnet, ipv4SNATAddr)
res.Network.IPAM.Config[0].Subnet, ipv4SNATAddr)
assert.Check(t, is.Contains(chain, exp))
} else {
testutil.RunCommand(ctx, "iptables", "-t", "nat", "-C", "POSTROUTING", "-s", out.IPAM.Config[0].Subnet.String(), "!", "-o", bridgeName, "-j", "SNAT", "--to-source", ipv4SNATAddr).Assert(t, icmd.Success)
testutil.RunCommand(ctx, "iptables", "-t", "nat", "-C", "POSTROUTING", "-s", res.Network.IPAM.Config[0].Subnet.String(), "!", "-o", bridgeName, "-j", "SNAT", "--to-source", ipv4SNATAddr).Assert(t, icmd.Success)
}
}

View File

@@ -45,9 +45,9 @@ func TestDaemonRestartWithLiveRestore(t *testing.T) {
defer c.Close()
// Verify bridge network's subnet
out, err := c.NetworkInspect(ctx, "bridge", client.NetworkInspectOptions{})
res, err := c.NetworkInspect(ctx, "bridge", client.NetworkInspectOptions{})
assert.NilError(t, err)
subnet := out.IPAM.Config[0].Subnet
subnet := res.Network.IPAM.Config[0].Subnet
d.Restart(t,
"--live-restore=true",
@@ -55,10 +55,10 @@ func TestDaemonRestartWithLiveRestore(t *testing.T) {
"--default-address-pool", "base=175.33.0.0/16,size=24",
)
out1, err := c.NetworkInspect(ctx, "bridge", client.NetworkInspectOptions{})
res1, err := c.NetworkInspect(ctx, "bridge", client.NetworkInspectOptions{})
assert.NilError(t, err)
// Make sure docker0 doesn't get override with new IP in live restore case
assert.Equal(t, out1.IPAM.Config[0].Subnet, subnet)
assert.Equal(t, res1.Network.IPAM.Config[0].Subnet, subnet)
}
func TestDaemonDefaultNetworkPools(t *testing.T) {
@@ -82,9 +82,9 @@ func TestDaemonDefaultNetworkPools(t *testing.T) {
defer c.Close()
// Verify bridge network's subnet
out, err := c.NetworkInspect(ctx, "bridge", client.NetworkInspectOptions{})
res, err := c.NetworkInspect(ctx, "bridge", client.NetworkInspectOptions{})
assert.NilError(t, err)
assert.Equal(t, out.IPAM.Config[0].Subnet, netip.MustParsePrefix("175.30.0.0/16"))
assert.Equal(t, res.Network.IPAM.Config[0].Subnet, netip.MustParsePrefix("175.30.0.0/16"))
// Create a bridge network and verify its subnet is the second default pool
name := "elango" + t.Name()
@@ -92,9 +92,9 @@ func TestDaemonDefaultNetworkPools(t *testing.T) {
network.WithDriver("bridge"),
)
defer network.RemoveNoError(ctx, t, c, name)
out, err = c.NetworkInspect(ctx, name, client.NetworkInspectOptions{})
res, err = c.NetworkInspect(ctx, name, client.NetworkInspectOptions{})
assert.NilError(t, err)
assert.Check(t, is.Equal(out.IPAM.Config[0].Subnet, netip.MustParsePrefix("175.33.0.0/24")))
assert.Check(t, is.Equal(res.Network.IPAM.Config[0].Subnet, netip.MustParsePrefix("175.33.0.0/24")))
// Create a bridge network and verify its subnet is the third default pool
name = "saanvi" + t.Name()
@@ -102,9 +102,9 @@ func TestDaemonDefaultNetworkPools(t *testing.T) {
network.WithDriver("bridge"),
)
defer network.RemoveNoError(ctx, t, c, name)
out, err = c.NetworkInspect(ctx, name, client.NetworkInspectOptions{})
res, err = c.NetworkInspect(ctx, name, client.NetworkInspectOptions{})
assert.NilError(t, err)
assert.Check(t, is.Equal(out.IPAM.Config[0].Subnet, netip.MustParsePrefix("175.33.1.0/24")))
assert.Check(t, is.Equal(res.Network.IPAM.Config[0].Subnet, netip.MustParsePrefix("175.33.1.0/24")))
}
func TestDaemonRestartWithExistingNetwork(t *testing.T) {
@@ -127,9 +127,9 @@ func TestDaemonRestartWithExistingNetwork(t *testing.T) {
defer network.RemoveNoError(ctx, t, c, name)
// Verify bridge network's subnet
out, err := c.NetworkInspect(ctx, name, client.NetworkInspectOptions{})
res, err := c.NetworkInspect(ctx, name, client.NetworkInspectOptions{})
assert.NilError(t, err)
networkip := out.IPAM.Config[0].Subnet
networkip := res.Network.IPAM.Config[0].Subnet
// Restart daemon with default address pool option
d.Restart(t,
@@ -137,9 +137,9 @@ func TestDaemonRestartWithExistingNetwork(t *testing.T) {
"--default-address-pool", "base=175.33.0.0/16,size=24")
defer delInterface(ctx, t, "docker0")
out1, err := c.NetworkInspect(ctx, name, client.NetworkInspectOptions{})
res2, err := c.NetworkInspect(ctx, name, client.NetworkInspectOptions{})
assert.NilError(t, err)
assert.Equal(t, out1.IPAM.Config[0].Subnet, networkip)
assert.Equal(t, res2.Network.IPAM.Config[0].Subnet, networkip)
}
func TestDaemonRestartWithExistingNetworkWithDefaultPoolRange(t *testing.T) {
@@ -163,9 +163,9 @@ func TestDaemonRestartWithExistingNetworkWithDefaultPoolRange(t *testing.T) {
defer network.RemoveNoError(ctx, t, c, name)
// Verify bridge network's subnet
out, err := c.NetworkInspect(ctx, name, client.NetworkInspectOptions{})
res, err := c.NetworkInspect(ctx, name, client.NetworkInspectOptions{})
assert.NilError(t, err)
networkip := out.IPAM.Config[0].Subnet
networkip := res.Network.IPAM.Config[0].Subnet
// Create a bridge network
name = "sthira" + t.Name()
@@ -173,9 +173,9 @@ func TestDaemonRestartWithExistingNetworkWithDefaultPoolRange(t *testing.T) {
network.WithDriver("bridge"),
)
defer network.RemoveNoError(ctx, t, c, name)
out, err = c.NetworkInspect(ctx, name, client.NetworkInspectOptions{})
res, err = c.NetworkInspect(ctx, name, client.NetworkInspectOptions{})
assert.NilError(t, err)
networkip2 := out.IPAM.Config[0].Subnet
networkip2 := res.Network.IPAM.Config[0].Subnet
// Restart daemon with default address pool option
d.Restart(t,
@@ -190,11 +190,11 @@ func TestDaemonRestartWithExistingNetworkWithDefaultPoolRange(t *testing.T) {
network.WithDriver("bridge"),
)
defer network.RemoveNoError(ctx, t, c, name)
out1, err := c.NetworkInspect(ctx, name, client.NetworkInspectOptions{})
res1, err := c.NetworkInspect(ctx, name, client.NetworkInspectOptions{})
assert.NilError(t, err)
assert.Check(t, out1.IPAM.Config[0].Subnet != networkip)
assert.Check(t, out1.IPAM.Config[0].Subnet != networkip2)
assert.Check(t, res1.Network.IPAM.Config[0].Subnet != networkip)
assert.Check(t, res1.Network.IPAM.Config[0].Subnet != networkip2)
}
func TestDaemonWithBipAndDefaultNetworkPool(t *testing.T) {
@@ -217,10 +217,10 @@ func TestDaemonWithBipAndDefaultNetworkPool(t *testing.T) {
defer c.Close()
// Verify bridge network's subnet
out, err := c.NetworkInspect(ctx, "bridge", client.NetworkInspectOptions{})
res, err := c.NetworkInspect(ctx, "bridge", client.NetworkInspectOptions{})
assert.NilError(t, err)
// Make sure BIP IP doesn't get override with new default address pool .
assert.Equal(t, out.IPAM.Config[0].Subnet, netip.MustParsePrefix("172.60.0.0/16"))
assert.Equal(t, res.Network.IPAM.Config[0].Subnet, netip.MustParsePrefix("172.60.0.0/16"))
}
func TestServiceWithPredefinedNetwork(t *testing.T) {
@@ -297,33 +297,33 @@ func TestServiceRemoveKeepsIngressNetwork(t *testing.T) {
// Ensure that "ingress" is not removed or corrupted
time.Sleep(10 * time.Second)
netInfo, err := c.NetworkInspect(ctx, ingressNet, client.NetworkInspectOptions{
res, err := c.NetworkInspect(ctx, ingressNet, client.NetworkInspectOptions{
Verbose: true,
Scope: "swarm",
})
assert.NilError(t, err, "Ingress network was removed after removing service!")
assert.Assert(t, len(netInfo.Containers) != 0, "No load balancing endpoints in ingress network")
assert.Assert(t, len(netInfo.Peers) != 0, "No peers (including self) in ingress network")
_, ok := netInfo.Containers["ingress-sbox"]
assert.Assert(t, len(res.Network.Containers) != 0, "No load balancing endpoints in ingress network")
assert.Assert(t, len(res.Network.Peers) != 0, "No peers (including self) in ingress network")
_, ok := res.Network.Containers["ingress-sbox"]
assert.Assert(t, ok, "ingress-sbox not present in ingress network")
}
//nolint:unused // for some reason, the "unused" linter marks this function as "unused"
func swarmIngressReady(ctx context.Context, apiClient client.NetworkAPIClient) func(log poll.LogT) poll.Result {
return func(log poll.LogT) poll.Result {
netInfo, err := apiClient.NetworkInspect(ctx, ingressNet, client.NetworkInspectOptions{
res, err := apiClient.NetworkInspect(ctx, ingressNet, client.NetworkInspectOptions{
Verbose: true,
Scope: "swarm",
})
if err != nil {
return poll.Error(err)
}
np := len(netInfo.Peers)
nc := len(netInfo.Containers)
np := len(res.Network.Peers)
nc := len(res.Network.Containers)
if np == 0 || nc == 0 {
return poll.Continue("ingress not ready: %d peers and %d containers", nc, np)
}
_, ok := netInfo.Containers["ingress-sbox"]
_, ok := res.Network.Containers["ingress-sbox"]
if !ok {
return poll.Continue("ingress not ready: does not contain the ingress-sbox")
}
@@ -443,21 +443,21 @@ func TestServiceWithDefaultAddressPoolInit(t *testing.T) {
_, _, err := cli.ServiceInspectWithRaw(ctx, serviceID, client.ServiceInspectOptions{})
assert.NilError(t, err)
out, err := cli.NetworkInspect(ctx, overlayID, client.NetworkInspectOptions{Verbose: true})
res, err := cli.NetworkInspect(ctx, overlayID, client.NetworkInspectOptions{Verbose: true})
assert.NilError(t, err)
t.Logf("%s: NetworkInspect: %+v", t.Name(), out)
assert.Assert(t, len(out.IPAM.Config) > 0)
t.Logf("%s: NetworkInspect: %+v", t.Name(), res)
assert.Assert(t, len(res.Network.IPAM.Config) > 0)
// As of docker/swarmkit#2890, the ingress network uses the default address
// pool (whereas before, the subnet for the ingress network was hard-coded.
// This means that the ingress network gets the subnet 20.20.0.0/24, and
// the network we just created gets subnet 20.20.1.0/24.
assert.Equal(t, out.IPAM.Config[0].Subnet, netip.MustParsePrefix("20.20.1.0/24"))
assert.Equal(t, res.Network.IPAM.Config[0].Subnet, netip.MustParsePrefix("20.20.1.0/24"))
// Also inspect ingress network and make sure its in the same subnet
out, err = cli.NetworkInspect(ctx, "ingress", client.NetworkInspectOptions{Verbose: true})
res, err = cli.NetworkInspect(ctx, "ingress", client.NetworkInspectOptions{Verbose: true})
assert.NilError(t, err)
assert.Assert(t, len(out.IPAM.Config) > 0)
assert.Equal(t, out.IPAM.Config[0].Subnet, netip.MustParsePrefix("20.20.0.0/24"))
assert.Assert(t, len(res.Network.IPAM.Config) > 0)
assert.Equal(t, res.Network.IPAM.Config[0].Subnet, netip.MustParsePrefix("20.20.0.0/24"))
err = cli.ServiceRemove(ctx, serviceID)
poll.WaitOn(t, noServices(ctx, cli), swarm.ServicePoll)

View File

@@ -584,9 +584,9 @@ func TestAccessToPublishedPort(t *testing.T) {
// Use the default bridge addresses as host addresses (like "host-gateway", but
// there's no way to tell wget to prefer ipv4/ipv6 transport, so just use the
// addresses directly).
insp, err := c.NetworkInspect(ctx, "bridge", client.NetworkInspectOptions{})
res, err := c.NetworkInspect(ctx, "bridge", client.NetworkInspectOptions{})
assert.NilError(t, err)
for _, ipamCfg := range insp.IPAM.Config {
for _, ipamCfg := range res.Network.IPAM.Config {
ipv := "ipv4"
if ipamCfg.Gateway.Is6() {
ipv = "ipv6"
@@ -1900,9 +1900,9 @@ func TestNetworkInspectGateway(t *testing.T) {
assert.NilError(t, err)
defer network.RemoveNoError(ctx, t, c, netName)
insp, err := c.NetworkInspect(ctx, nid, client.NetworkInspectOptions{})
res, err := c.NetworkInspect(ctx, nid, client.NetworkInspectOptions{})
assert.NilError(t, err)
for _, ipamCfg := range insp.IPAM.Config {
for _, ipamCfg := range res.Network.IPAM.Config {
assert.Check(t, ipamCfg.Gateway.IsValid())
}
}

View File

@@ -227,7 +227,7 @@ func TestServiceUpdateNetwork(t *testing.T) {
Scope: "swarm",
})
assert.NilError(t, err)
assert.Assert(t, len(netInfo.Containers) == 2, "Expected 2 endpoints, one for container and one for LB Sandbox")
assert.Assert(t, len(netInfo.Network.Containers) == 2, "Expected 2 endpoints, one for container and one for LB Sandbox")
// Remove network from service
service.Spec.TaskTemplate.Networks = []swarmtypes.NetworkAttachmentConfig{}
@@ -241,7 +241,7 @@ func TestServiceUpdateNetwork(t *testing.T) {
})
assert.NilError(t, err)
assert.Assert(t, len(netInfo.Containers) == 0, "Load balancing endpoint still exists in network")
assert.Assert(t, len(netInfo.Network.Containers) == 0, "Load balancing endpoint still exists in network")
err = apiClient.NetworkRemove(ctx, overlayID)
assert.NilError(t, err)

View File

@@ -130,8 +130,7 @@ type NetworkAPIClient interface {
NetworkConnect(ctx context.Context, network, container string, config *network.EndpointSettings) error
NetworkCreate(ctx context.Context, name string, options NetworkCreateOptions) (network.CreateResponse, error)
NetworkDisconnect(ctx context.Context, network, container string, force bool) error
NetworkInspect(ctx context.Context, network string, options NetworkInspectOptions) (network.Inspect, error)
NetworkInspectWithRaw(ctx context.Context, network string, options NetworkInspectOptions) (network.Inspect, []byte, error)
NetworkInspect(ctx context.Context, network string, options NetworkInspectOptions) (NetworkInspectResult, error)
NetworkList(ctx context.Context, options NetworkListOptions) ([]network.Summary, error)
NetworkRemove(ctx context.Context, network string) error
NetworksPrune(ctx context.Context, opts NetworkPruneOptions) (NetworkPruneResult, error)

View File

@@ -1,26 +1,23 @@
package client
import (
"bytes"
"context"
"encoding/json"
"io"
"net/url"
"github.com/moby/moby/api/types/network"
)
// NetworkInspect returns the information for a specific network configured in the docker host.
func (cli *Client) NetworkInspect(ctx context.Context, networkID string, options NetworkInspectOptions) (network.Inspect, error) {
networkResource, _, err := cli.NetworkInspectWithRaw(ctx, networkID, options)
return networkResource, err
// NetworkInspectResult contains the result of a network inspection.
type NetworkInspectResult struct {
Network network.Inspect
Raw []byte
}
// NetworkInspectWithRaw returns the information for a specific network configured in the docker host and its raw representation.
func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string, options NetworkInspectOptions) (network.Inspect, []byte, error) {
// NetworkInspect returns the information for a specific network configured in the docker host.
func (cli *Client) NetworkInspect(ctx context.Context, networkID string, options NetworkInspectOptions) (NetworkInspectResult, error) {
networkID, err := trimID("network", networkID)
if err != nil {
return network.Inspect{}, nil, err
return NetworkInspectResult{}, err
}
query := url.Values{}
if options.Verbose {
@@ -33,15 +30,10 @@ func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string,
resp, err := cli.get(ctx, "/networks/"+networkID, query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return network.Inspect{}, nil, err
return NetworkInspectResult{}, err
}
raw, err := io.ReadAll(resp.Body)
if err != nil {
return network.Inspect{}, nil, err
}
var nw network.Inspect
err = json.NewDecoder(bytes.NewReader(raw)).Decode(&nw)
return nw, raw, err
var out NetworkInspectResult
out.Raw, err = decodeWithRaw(resp, &out.Network)
return out, err
}