client: refactor NetworkConnect, NetworkDisconnect, NetworkRemove

Signed-off-by: Austin Vazquez <austin.vazquez@docker.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Austin Vazquez
2025-10-22 07:39:57 -05:00
committed by Sebastiaan van Stijn
parent c755b9635d
commit e9f28e2a41
34 changed files with 389 additions and 286 deletions

View File

@@ -117,12 +117,12 @@ type ImageAPIClient interface {
// NetworkAPIClient defines API client methods for the networks // NetworkAPIClient defines API client methods for the networks
type NetworkAPIClient interface { type NetworkAPIClient interface {
NetworkConnect(ctx context.Context, network, container string, config *network.EndpointSettings) error NetworkConnect(ctx context.Context, network string, options NetworkConnectOptions) (NetworkConnectResult, error)
NetworkCreate(ctx context.Context, name string, options NetworkCreateOptions) (network.CreateResponse, error) NetworkCreate(ctx context.Context, name string, options NetworkCreateOptions) (network.CreateResponse, error)
NetworkDisconnect(ctx context.Context, network, container string, force bool) error NetworkDisconnect(ctx context.Context, network string, options NetworkDisconnectOptions) (NetworkDisconnectResult, error)
NetworkInspect(ctx context.Context, network string, options NetworkInspectOptions) (NetworkInspectResult, error) NetworkInspect(ctx context.Context, network string, options NetworkInspectOptions) (NetworkInspectResult, error)
NetworkList(ctx context.Context, options NetworkListOptions) (NetworkListResult, error) NetworkList(ctx context.Context, options NetworkListOptions) (NetworkListResult, error)
NetworkRemove(ctx context.Context, network string) error NetworkRemove(ctx context.Context, network string, options NetworkRemoveOptions) (NetworkRemoveResult, error)
NetworksPrune(ctx context.Context, opts NetworkPruneOptions) (NetworkPruneResult, error) NetworksPrune(ctx context.Context, opts NetworkPruneOptions) (NetworkPruneResult, error)
} }

View File

@@ -6,23 +6,35 @@ import (
"github.com/moby/moby/api/types/network" "github.com/moby/moby/api/types/network"
) )
// NetworkConnectOptions represents the data to be used to connect a container to the
// network.
type NetworkConnectOptions struct {
Container string
EndpointConfig *network.EndpointSettings
}
// NetworkConnectResult represents the result of a NetworkConnect operation.
type NetworkConnectResult struct {
// Currently empty; placeholder for future fields.
}
// NetworkConnect connects a container to an existent network in the docker host. // NetworkConnect connects a container to an existent network in the docker host.
func (cli *Client) NetworkConnect(ctx context.Context, networkID, containerID string, config *network.EndpointSettings) error { func (cli *Client) NetworkConnect(ctx context.Context, networkID string, options NetworkConnectOptions) (NetworkConnectResult, error) {
networkID, err := trimID("network", networkID) networkID, err := trimID("network", networkID)
if err != nil { if err != nil {
return err return NetworkConnectResult{}, err
} }
containerID, err = trimID("container", containerID) containerID, err := trimID("container", options.Container)
if err != nil { if err != nil {
return err return NetworkConnectResult{}, err
} }
req := network.ConnectRequest{ nc := network.ConnectRequest{
Container: containerID, Container: containerID,
EndpointConfig: config, EndpointConfig: options.EndpointConfig,
} }
resp, err := cli.post(ctx, "/networks/"+networkID+"/connect", nil, req, nil) resp, err := cli.post(ctx, "/networks/"+networkID+"/connect", nil, nc, nil)
defer ensureReaderClosed(resp) defer ensureReaderClosed(resp)
return err return NetworkConnectResult{}, err
} }

View File

@@ -1,10 +0,0 @@
package client
import "github.com/moby/moby/api/types/network"
// NetworkConnectOptions represents the data to be used to connect a container to the
// network.
type NetworkConnectOptions struct {
Container string
EndpointConfig *network.EndpointSettings `json:",omitempty"`
}

View File

@@ -17,15 +17,19 @@ func TestNetworkConnectError(t *testing.T) {
client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error"))) client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
assert.NilError(t, err) assert.NilError(t, err)
err = client.NetworkConnect(context.Background(), "network_id", "container_id", nil) _, err = client.NetworkConnect(context.Background(), "network_id", NetworkConnectOptions{
Container: "container_id",
})
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal)) assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
// Empty network ID or container ID // Empty network ID or container ID
err = client.NetworkConnect(context.Background(), "", "container_id", nil) _, err = client.NetworkConnect(context.Background(), "", NetworkConnectOptions{
Container: "container_id",
})
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument)) assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
assert.Check(t, is.ErrorContains(err, "value is empty")) assert.Check(t, is.ErrorContains(err, "value is empty"))
err = client.NetworkConnect(context.Background(), "network_id", "", nil) _, err = client.NetworkConnect(context.Background(), "network_id", NetworkConnectOptions{})
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument)) assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
assert.Check(t, is.ErrorContains(err, "value is empty")) assert.Check(t, is.ErrorContains(err, "value is empty"))
} }
@@ -55,7 +59,9 @@ func TestNetworkConnectEmptyNilEndpointSettings(t *testing.T) {
})) }))
assert.NilError(t, err) assert.NilError(t, err)
err = client.NetworkConnect(context.Background(), "network_id", "container_id", nil) _, err = client.NetworkConnect(context.Background(), "network_id", NetworkConnectOptions{
Container: "container_id",
})
assert.NilError(t, err) assert.NilError(t, err)
} }
@@ -67,7 +73,7 @@ func TestNetworkConnect(t *testing.T) {
return nil, err return nil, err
} }
var connect NetworkConnectOptions var connect network.ConnectRequest
if err := json.NewDecoder(req.Body).Decode(&connect); err != nil { if err := json.NewDecoder(req.Body).Decode(&connect); err != nil {
return nil, err return nil, err
} }
@@ -88,8 +94,11 @@ func TestNetworkConnect(t *testing.T) {
})) }))
assert.NilError(t, err) assert.NilError(t, err)
err = client.NetworkConnect(context.Background(), "network_id", "container_id", &network.EndpointSettings{ _, err = client.NetworkConnect(context.Background(), "network_id", NetworkConnectOptions{
Container: "container_id",
EndpointConfig: &network.EndpointSettings{
NetworkID: "NetworkID", NetworkID: "NetworkID",
},
}) })
assert.NilError(t, err) assert.NilError(t, err)
} }

View File

@@ -6,23 +6,35 @@ import (
"github.com/moby/moby/api/types/network" "github.com/moby/moby/api/types/network"
) )
// NetworkDisconnectOptions represents the data to be used to disconnect a container
// from the network.
type NetworkDisconnectOptions struct {
Container string
Force bool
}
// NetworkDisconnectResult represents the result of a NetworkDisconnect operation.
type NetworkDisconnectResult struct {
// Currently empty; placeholder for future fields.
}
// NetworkDisconnect disconnects a container from an existent network in the docker host. // NetworkDisconnect disconnects a container from an existent network in the docker host.
func (cli *Client) NetworkDisconnect(ctx context.Context, networkID, containerID string, force bool) error { func (cli *Client) NetworkDisconnect(ctx context.Context, networkID string, options NetworkDisconnectOptions) (NetworkDisconnectResult, error) {
networkID, err := trimID("network", networkID) networkID, err := trimID("network", networkID)
if err != nil { if err != nil {
return err return NetworkDisconnectResult{}, err
} }
containerID, err = trimID("container", containerID) containerID, err := trimID("container", options.Container)
if err != nil { if err != nil {
return err return NetworkDisconnectResult{}, err
} }
req := network.DisconnectRequest{ req := network.DisconnectRequest{
Container: containerID, Container: containerID,
Force: force, Force: options.Force,
} }
resp, err := cli.post(ctx, "/networks/"+networkID+"/disconnect", nil, req, nil) resp, err := cli.post(ctx, "/networks/"+networkID+"/disconnect", nil, req, nil)
defer ensureReaderClosed(resp) defer ensureReaderClosed(resp)
return err return NetworkDisconnectResult{}, err
} }

View File

@@ -1,8 +0,0 @@
package client
// NetworkDisconnectOptions represents the data to be used to disconnect a container
// from the network.
type NetworkDisconnectOptions struct {
Container string
Force bool
}

View File

@@ -17,15 +17,19 @@ func TestNetworkDisconnectError(t *testing.T) {
client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error"))) client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
assert.NilError(t, err) assert.NilError(t, err)
err = client.NetworkDisconnect(context.Background(), "network_id", "container_id", false) _, err = client.NetworkDisconnect(context.Background(), "network_id", NetworkDisconnectOptions{
Container: "container_id",
})
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal)) assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
// Empty network ID or container ID // Empty network ID or container ID
err = client.NetworkDisconnect(context.Background(), "", "container_id", false) _, err = client.NetworkDisconnect(context.Background(), "", NetworkDisconnectOptions{
Container: "container_id",
})
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument)) assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
assert.Check(t, is.ErrorContains(err, "value is empty")) assert.Check(t, is.ErrorContains(err, "value is empty"))
err = client.NetworkDisconnect(context.Background(), "network_id", "", false) _, err = client.NetworkDisconnect(context.Background(), "network_id", NetworkDisconnectOptions{})
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument)) assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
assert.Check(t, is.ErrorContains(err, "value is empty")) assert.Check(t, is.ErrorContains(err, "value is empty"))
} }
@@ -55,6 +59,6 @@ func TestNetworkDisconnect(t *testing.T) {
})) }))
assert.NilError(t, err) assert.NilError(t, err)
err = client.NetworkDisconnect(context.Background(), "network_id", "container_id", true) _, err = client.NetworkDisconnect(context.Background(), "network_id", NetworkDisconnectOptions{Container: "container_id", Force: true})
assert.NilError(t, err) assert.NilError(t, err)
} }

View File

@@ -1,14 +1,26 @@
package client package client
import "context" import (
"context"
)
// NetworkRemoveOptions specifies options for removing a network.
type NetworkRemoveOptions struct {
// No options currently; placeholder for future use.
}
// NetworkRemoveResult represents the result of a network removal operation.
type NetworkRemoveResult struct {
// No fields currently; placeholder for future use.
}
// NetworkRemove removes an existent network from the docker host. // NetworkRemove removes an existent network from the docker host.
func (cli *Client) NetworkRemove(ctx context.Context, networkID string) error { func (cli *Client) NetworkRemove(ctx context.Context, networkID string, options NetworkRemoveOptions) (NetworkRemoveResult, error) {
networkID, err := trimID("network", networkID) networkID, err := trimID("network", networkID)
if err != nil { if err != nil {
return err return NetworkRemoveResult{}, err
} }
resp, err := cli.delete(ctx, "/networks/"+networkID, nil, nil) resp, err := cli.delete(ctx, "/networks/"+networkID, nil, nil)
defer ensureReaderClosed(resp) defer ensureReaderClosed(resp)
return err return NetworkRemoveResult{}, err
} }

View File

@@ -14,14 +14,14 @@ func TestNetworkRemoveError(t *testing.T) {
client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error"))) client, err := NewClientWithOpts(WithMockClient(errorMock(http.StatusInternalServerError, "Server error")))
assert.NilError(t, err) assert.NilError(t, err)
err = client.NetworkRemove(context.Background(), "network_id") _, err = client.NetworkRemove(context.Background(), "network_id", NetworkRemoveOptions{})
assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal)) assert.Check(t, is.ErrorType(err, cerrdefs.IsInternal))
err = client.NetworkRemove(context.Background(), "") _, err = client.NetworkRemove(context.Background(), "", NetworkRemoveOptions{})
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument)) assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
assert.Check(t, is.ErrorContains(err, "value is empty")) assert.Check(t, is.ErrorContains(err, "value is empty"))
err = client.NetworkRemove(context.Background(), " ") _, err = client.NetworkRemove(context.Background(), " ", NetworkRemoveOptions{})
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument)) assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
assert.Check(t, is.ErrorContains(err, "value is empty")) assert.Check(t, is.ErrorContains(err, "value is empty"))
} }
@@ -37,6 +37,6 @@ func TestNetworkRemove(t *testing.T) {
})) }))
assert.NilError(t, err) assert.NilError(t, err)
err = client.NetworkRemove(context.Background(), "network_id") _, err = client.NetworkRemove(context.Background(), "network_id", NetworkRemoveOptions{})
assert.NilError(t, err) assert.NilError(t, err)
} }

View File

@@ -2,16 +2,16 @@ package networkbackend
import "github.com/moby/moby/api/types/network" import "github.com/moby/moby/api/types/network"
// ConnectOptions represents the data to be used to connect a container to the // ConnectRequest represents the data to be used to connect a container to the
// network. // network.
type ConnectOptions struct { type ConnectRequest struct {
Container string Container string
EndpointConfig *network.EndpointSettings `json:",omitempty"` EndpointConfig *network.EndpointSettings `json:",omitempty"`
} }
// DisconnectOptions represents the data to be used to disconnect a container // DisconnectRequest represents the data to be used to disconnect a container
// from the network. // from the network.
type DisconnectOptions struct { type DisconnectRequest struct {
Container string Container string
Force bool Force bool
} }

View File

@@ -287,7 +287,7 @@ func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseW
return err return err
} }
var connect networkbackend.ConnectOptions var connect networkbackend.ConnectRequest
if err := httputils.ReadJSON(r, &connect); err != nil { if err := httputils.ReadJSON(r, &connect); err != nil {
return err return err
} }
@@ -304,7 +304,7 @@ func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.Respon
return err return err
} }
var disconnect networkbackend.DisconnectOptions var disconnect networkbackend.DisconnectRequest
if err := httputils.ReadJSON(r, &disconnect); err != nil { if err := httputils.ReadJSON(r, &disconnect); err != nil {
return err return err
} }

View File

@@ -51,6 +51,6 @@ func InspectNoError(ctx context.Context, t *testing.T, apiClient client.APIClien
func RemoveNoError(ctx context.Context, t *testing.T, apiClient client.APIClient, name string) { func RemoveNoError(ctx context.Context, t *testing.T, apiClient client.APIClient, name string) {
t.Helper() t.Helper()
err := apiClient.NetworkRemove(ctx, name) _, err := apiClient.NetworkRemove(ctx, name, client.NetworkRemoveOptions{})
assert.NilError(t, err) assert.NilError(t, err)
} }

View File

@@ -1130,7 +1130,7 @@ func TestBridgeIPAMStatus(t *testing.T) {
}, },
}), }),
) )
defer c.NetworkRemove(ctx, netName) defer c.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
checkSubnets(netName, map[netip.Prefix]networktypes.SubnetStatus{ checkSubnets(netName, map[netip.Prefix]networktypes.SubnetStatus{
cidrv4: { cidrv4: {
@@ -1210,7 +1210,7 @@ func TestBridgeIPAMStatus(t *testing.T) {
Subnet: cidr, Subnet: cidr,
}), }),
) )
defer c.NetworkRemove(ctx, netName) defer c.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
checkSubnets(netName, map[netip.Prefix]networktypes.SubnetStatus{ checkSubnets(netName, map[netip.Prefix]networktypes.SubnetStatus{
cidr: { cidr: {
@@ -1255,7 +1255,9 @@ func TestJoinError(t *testing.T) {
assert.Equal(t, res.ExitCode, 0) assert.Equal(t, res.ExitCode, 0)
// Expect an error when connecting extNet. // Expect an error when connecting extNet.
err := c.NetworkConnect(ctx, extNet, cid, &networktypes.EndpointSettings{}) _, err := c.NetworkConnect(ctx, extNet, client.NetworkConnectOptions{
Container: cid,
})
assert.Check(t, is.ErrorContains(err, "failed to set gateway: file exists")) assert.Check(t, is.ErrorContains(err, "failed to set gateway: file exists"))
// Only intNet should show up in container inspect. // Only intNet should show up in container inspect.
@@ -1279,7 +1281,9 @@ func TestJoinError(t *testing.T) {
assert.Equal(t, res.ExitCode, 0) assert.Equal(t, res.ExitCode, 0)
// Check network connect now succeeds. // Check network connect now succeeds.
err = c.NetworkConnect(ctx, extNet, cid, &networktypes.EndpointSettings{}) _, err = c.NetworkConnect(ctx, extNet, client.NetworkConnectOptions{
Container: cid,
})
assert.Check(t, err) assert.Check(t, err)
ctrInsp = ctr.Inspect(ctx, t, c, cid) ctrInsp = ctr.Inspect(ctx, t, c, cid)
assert.Check(t, is.Len(ctrInsp.NetworkSettings.Networks, 2)) assert.Check(t, is.Len(ctrInsp.NetworkSettings.Networks, 2))

View File

@@ -4,6 +4,7 @@ import (
"errors" "errors"
"testing" "testing"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/daemon/libnetwork/drivers/bridge" "github.com/moby/moby/v2/daemon/libnetwork/drivers/bridge"
"github.com/moby/moby/v2/daemon/libnetwork/nlwrap" "github.com/moby/moby/v2/daemon/libnetwork/nlwrap"
"github.com/moby/moby/v2/integration/internal/network" "github.com/moby/moby/v2/integration/internal/network"
@@ -58,7 +59,7 @@ func TestNetworkInitErrorUserDefined(t *testing.T) {
d.SetEnvVar("DOCKER_TEST_BRIDGE_INIT_ERROR", brName) d.SetEnvVar("DOCKER_TEST_BRIDGE_INIT_ERROR", brName)
d.Restart(t) d.Restart(t)
err := c.NetworkRemove(ctx, netName) _, err := c.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
assert.NilError(t, err) assert.NilError(t, err)
d.SetEnvVar("DOCKER_TEST_BRIDGE_INIT_ERROR", "") d.SetEnvVar("DOCKER_TEST_BRIDGE_INIT_ERROR", "")

View File

@@ -51,7 +51,7 @@ func TestNetworkCreateDelete(t *testing.T) {
assert.Check(t, IsNetworkAvailable(ctx, apiClient, netName)) assert.Check(t, IsNetworkAvailable(ctx, apiClient, netName))
// delete the network and make sure it is deleted // delete the network and make sure it is deleted
err := apiClient.NetworkRemove(ctx, netName) _, err := apiClient.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, IsNetworkNotAvailable(ctx, apiClient, netName)) assert.Check(t, IsNetworkNotAvailable(ctx, apiClient, netName))
} }
@@ -70,12 +70,12 @@ func TestDockerNetworkDeletePreferID(t *testing.T) {
// Delete the network using a prefix of the first network's ID as name. // Delete the network using a prefix of the first network's ID as name.
// This should the network name with the id-prefix, not the original network. // This should the network name with the id-prefix, not the original network.
err := apiClient.NetworkRemove(ctx, testNet[:12]) _, err := apiClient.NetworkRemove(ctx, testNet[:12], client.NetworkRemoveOptions{})
assert.NilError(t, err) assert.NilError(t, err)
// Delete the network using networkID. This should remove the original // Delete the network using networkID. This should remove the original
// network, not the network with the name equal to the networkID // network, not the network with the name equal to the networkID
err = apiClient.NetworkRemove(ctx, testNet) _, err = apiClient.NetworkRemove(ctx, testNet, client.NetworkRemoveOptions{})
assert.NilError(t, err) assert.NilError(t, err)
// networks "testNet" and "idPrefixNet" should be removed, but "fullIDNet" should still exist // networks "testNet" and "idPrefixNet" should be removed, but "fullIDNet" should still exist

View File

@@ -29,7 +29,7 @@ func TestDaemonDNSFallback(t *testing.T) {
c := d.NewClientT(t) c := d.NewClientT(t)
network.CreateNoError(ctx, t, c, "test") network.CreateNoError(ctx, t, c, "test")
defer c.NetworkRemove(ctx, "test") defer c.NetworkRemove(ctx, "test", client.NetworkRemoveOptions{})
cid := container.Run(ctx, t, c, container.WithNetworkMode("test"), container.WithCmd("nslookup", "docker.com")) cid := container.Run(ctx, t, c, container.WithNetworkMode("test"), container.WithCmd("nslookup", "docker.com"))
defer c.ContainerRemove(ctx, cid, client.ContainerRemoveOptions{Force: true}) defer c.ContainerRemove(ctx, cid, client.ContainerRemoveOptions{Force: true})

View File

@@ -62,7 +62,8 @@ func TestInspectNetwork(t *testing.T) {
// object) leaking, which prevents other daemons on the same kernel from // object) leaking, which prevents other daemons on the same kernel from
// creating a new vxlan link with the same VNI. // creating a new vxlan link with the same VNI.
defer func() { defer func() {
assert.NilError(t, c1.NetworkRemove(ctx, overlayID)) _, err := c1.NetworkRemove(ctx, overlayID, client.NetworkRemoveOptions{})
assert.NilError(t, err)
poll.WaitOn(t, network.IsRemoved(ctx, w1, overlayID), swarm.NetworkPoll) poll.WaitOn(t, network.IsRemoved(ctx, w1, overlayID), swarm.NetworkPoll)
}() }()

View File

@@ -12,7 +12,7 @@ import (
"github.com/google/go-cmp/cmp/cmpopts" "github.com/google/go-cmp/cmp/cmpopts"
"github.com/moby/moby/api/types/network" "github.com/moby/moby/api/types/network"
dclient "github.com/moby/moby/client" "github.com/moby/moby/client"
"github.com/moby/moby/v2/daemon/libnetwork/netlabel" "github.com/moby/moby/v2/daemon/libnetwork/netlabel"
"github.com/moby/moby/v2/integration/internal/container" "github.com/moby/moby/v2/integration/internal/container"
net "github.com/moby/moby/v2/integration/internal/network" net "github.com/moby/moby/v2/integration/internal/network"
@@ -62,7 +62,7 @@ func TestDockerNetworkIpvlan(t *testing.T) {
for _, tc := range []struct { for _, tc := range []struct {
name string name string
test func(*testing.T, context.Context, dclient.APIClient) test func(*testing.T, context.Context, client.APIClient)
}{ }{
{ {
name: "Subinterface", name: "Subinterface",
@@ -112,27 +112,27 @@ func TestDockerNetworkIpvlan(t *testing.T) {
} }
} }
func testIpvlanSubinterface(t *testing.T, ctx context.Context, client dclient.APIClient) { func testIpvlanSubinterface(t *testing.T, ctx context.Context, apiClient client.APIClient) {
master := "di-dummy0" master := "di-dummy0"
n.CreateMasterDummy(ctx, t, master) n.CreateMasterDummy(ctx, t, master)
defer n.DeleteInterface(ctx, t, master) defer n.DeleteInterface(ctx, t, master)
netName := "di-subinterface" netName := "di-subinterface"
net.CreateNoError(ctx, t, client, netName, net.CreateNoError(ctx, t, apiClient, netName,
net.WithIPvlan("di-dummy0.60", ""), net.WithIPvlan("di-dummy0.60", ""),
) )
assert.Check(t, n.IsNetworkAvailable(ctx, client, netName)) assert.Check(t, n.IsNetworkAvailable(ctx, apiClient, netName))
// delete the network while preserving the parent link // delete the network while preserving the parent link
err := client.NetworkRemove(ctx, netName) _, err := apiClient.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, n.IsNetworkNotAvailable(ctx, client, netName)) assert.Check(t, n.IsNetworkNotAvailable(ctx, apiClient, netName))
// verify the network delete did not delete the predefined link // verify the network delete did not delete the predefined link
n.LinkExists(ctx, t, "di-dummy0") n.LinkExists(ctx, t, "di-dummy0")
} }
func testIpvlanOverlapParent(t *testing.T, ctx context.Context, client dclient.APIClient) { func testIpvlanOverlapParent(t *testing.T, ctx context.Context, client client.APIClient) {
// verify the same parent interface cannot be used if already in use by an existing network // verify the same parent interface cannot be used if already in use by an existing network
master := "di-dummy0" master := "di-dummy0"
parent := master + ".30" parent := master + ".30"
@@ -153,99 +153,99 @@ func testIpvlanOverlapParent(t *testing.T, ctx context.Context, client dclient.A
assert.Check(t, err != nil) assert.Check(t, err != nil)
} }
func testIpvlanL2NilParent(t *testing.T, ctx context.Context, client dclient.APIClient) { func testIpvlanL2NilParent(t *testing.T, ctx context.Context, apiClient client.APIClient) {
// ipvlan l2 mode - dummy parent interface is provisioned dynamically // ipvlan l2 mode - dummy parent interface is provisioned dynamically
netName := "di-nil-parent" netName := "di-nil-parent"
net.CreateNoError(ctx, t, client, netName, net.CreateNoError(ctx, t, apiClient, netName,
net.WithIPvlan("", ""), net.WithIPvlan("", ""),
) )
assert.Check(t, n.IsNetworkAvailable(ctx, client, netName)) assert.Check(t, n.IsNetworkAvailable(ctx, apiClient, netName))
id1 := container.Run(ctx, t, client, container.WithNetworkMode(netName)) id1 := container.Run(ctx, t, apiClient, container.WithNetworkMode(netName))
id2 := container.Run(ctx, t, client, container.WithNetworkMode(netName)) id2 := container.Run(ctx, t, apiClient, container.WithNetworkMode(netName))
_, err := container.Exec(ctx, client, id2, []string{"ping", "-c", "1", id1}) _, err := container.Exec(ctx, apiClient, id2, []string{"ping", "-c", "1", id1})
assert.NilError(t, err) assert.NilError(t, err)
} }
func testIpvlanL2InternalMode(t *testing.T, ctx context.Context, client dclient.APIClient) { func testIpvlanL2InternalMode(t *testing.T, ctx context.Context, apiClient client.APIClient) {
netName := "di-internal" netName := "di-internal"
net.CreateNoError(ctx, t, client, netName, net.CreateNoError(ctx, t, apiClient, netName,
net.WithIPvlan("", ""), net.WithIPvlan("", ""),
net.WithInternal(), net.WithInternal(),
) )
assert.Check(t, n.IsNetworkAvailable(ctx, client, netName)) assert.Check(t, n.IsNetworkAvailable(ctx, apiClient, netName))
id1 := container.Run(ctx, t, client, container.WithNetworkMode(netName)) id1 := container.Run(ctx, t, apiClient, container.WithNetworkMode(netName))
id2 := container.Run(ctx, t, client, container.WithNetworkMode(netName)) id2 := container.Run(ctx, t, apiClient, container.WithNetworkMode(netName))
result, _ := container.Exec(ctx, client, id1, []string{"ping", "-c", "1", "8.8.8.8"}) result, _ := container.Exec(ctx, apiClient, id1, []string{"ping", "-c", "1", "8.8.8.8"})
assert.Check(t, is.Contains(result.Combined(), "Network is unreachable")) assert.Check(t, is.Contains(result.Combined(), "Network is unreachable"))
_, err := container.Exec(ctx, client, id2, []string{"ping", "-c", "1", id1}) _, err := container.Exec(ctx, apiClient, id2, []string{"ping", "-c", "1", id1})
assert.NilError(t, err) assert.NilError(t, err)
} }
func testIpvlanL3NilParent(t *testing.T, ctx context.Context, client dclient.APIClient) { func testIpvlanL3NilParent(t *testing.T, ctx context.Context, apiClient client.APIClient) {
netName := "di-nil-parent-l3" netName := "di-nil-parent-l3"
net.CreateNoError(ctx, t, client, netName, net.CreateNoError(ctx, t, apiClient, netName,
net.WithIPvlan("", "l3"), net.WithIPvlan("", "l3"),
net.WithIPAM("172.28.230.0/24", ""), net.WithIPAM("172.28.230.0/24", ""),
net.WithIPAM("172.28.220.0/24", ""), net.WithIPAM("172.28.220.0/24", ""),
) )
assert.Check(t, n.IsNetworkAvailable(ctx, client, netName)) assert.Check(t, n.IsNetworkAvailable(ctx, apiClient, netName))
id1 := container.Run(ctx, t, client, id1 := container.Run(ctx, t, apiClient,
container.WithNetworkMode(netName), container.WithNetworkMode(netName),
container.WithIPv4(netName, "172.28.220.10"), container.WithIPv4(netName, "172.28.220.10"),
) )
id2 := container.Run(ctx, t, client, id2 := container.Run(ctx, t, apiClient,
container.WithNetworkMode(netName), container.WithNetworkMode(netName),
container.WithIPv4(netName, "172.28.230.10"), container.WithIPv4(netName, "172.28.230.10"),
) )
_, err := container.Exec(ctx, client, id2, []string{"ping", "-c", "1", id1}) _, err := container.Exec(ctx, apiClient, id2, []string{"ping", "-c", "1", id1})
assert.NilError(t, err) assert.NilError(t, err)
} }
func testIpvlanL3InternalMode(t *testing.T, ctx context.Context, client dclient.APIClient) { func testIpvlanL3InternalMode(t *testing.T, ctx context.Context, apiClient client.APIClient) {
netName := "di-internal-l3" netName := "di-internal-l3"
net.CreateNoError(ctx, t, client, netName, net.CreateNoError(ctx, t, apiClient, netName,
net.WithIPvlan("", "l3"), net.WithIPvlan("", "l3"),
net.WithInternal(), net.WithInternal(),
net.WithIPAM("172.28.230.0/24", ""), net.WithIPAM("172.28.230.0/24", ""),
net.WithIPAM("172.28.220.0/24", ""), net.WithIPAM("172.28.220.0/24", ""),
) )
assert.Check(t, n.IsNetworkAvailable(ctx, client, netName)) assert.Check(t, n.IsNetworkAvailable(ctx, apiClient, netName))
id1 := container.Run(ctx, t, client, id1 := container.Run(ctx, t, apiClient,
container.WithNetworkMode(netName), container.WithNetworkMode(netName),
container.WithIPv4(netName, "172.28.220.10"), container.WithIPv4(netName, "172.28.220.10"),
) )
id2 := container.Run(ctx, t, client, id2 := container.Run(ctx, t, apiClient,
container.WithNetworkMode(netName), container.WithNetworkMode(netName),
container.WithIPv4(netName, "172.28.230.10"), container.WithIPv4(netName, "172.28.230.10"),
) )
result, _ := container.Exec(ctx, client, id1, []string{"ping", "-c", "1", "8.8.8.8"}) result, _ := container.Exec(ctx, apiClient, id1, []string{"ping", "-c", "1", "8.8.8.8"})
assert.Check(t, is.Contains(result.Combined(), "Network is unreachable")) assert.Check(t, is.Contains(result.Combined(), "Network is unreachable"))
_, err := container.Exec(ctx, client, id2, []string{"ping", "-c", "1", id1}) _, err := container.Exec(ctx, apiClient, id2, []string{"ping", "-c", "1", id1})
assert.NilError(t, err) assert.NilError(t, err)
} }
func testIpvlanL2MultiSubnetWithParent(t *testing.T, ctx context.Context, client dclient.APIClient) { func testIpvlanL2MultiSubnetWithParent(t *testing.T, ctx context.Context, apiClient client.APIClient) {
const parentIfName = "di-dummy0" const parentIfName = "di-dummy0"
n.CreateMasterDummy(ctx, t, parentIfName) n.CreateMasterDummy(ctx, t, parentIfName)
defer n.DeleteInterface(ctx, t, parentIfName) defer n.DeleteInterface(ctx, t, parentIfName)
testIpvlanL2MultiSubnet(t, ctx, client, parentIfName) testIpvlanL2MultiSubnet(t, ctx, apiClient, parentIfName)
} }
func testIpvlanL2MultiSubnetNoParent(t *testing.T, ctx context.Context, client dclient.APIClient) { func testIpvlanL2MultiSubnetNoParent(t *testing.T, ctx context.Context, apiClient client.APIClient) {
testIpvlanL2MultiSubnet(t, ctx, client, "") testIpvlanL2MultiSubnet(t, ctx, apiClient, "")
} }
func testIpvlanL2MultiSubnet(t *testing.T, ctx context.Context, apiClient dclient.APIClient, parent string) { func testIpvlanL2MultiSubnet(t *testing.T, ctx context.Context, apiClient client.APIClient, parent string) {
netName := "dualstackl2" netName := "dualstackl2"
net.CreateNoError(ctx, t, apiClient, netName, net.CreateNoError(ctx, t, apiClient, netName,
net.WithIPvlan(parent, ""), net.WithIPvlan(parent, ""),
@@ -268,7 +268,7 @@ func testIpvlanL2MultiSubnet(t *testing.T, ctx context.Context, apiClient dclien
container.WithIPv4(netName, "172.28.200.21"), container.WithIPv4(netName, "172.28.200.21"),
container.WithIPv6(netName, "2001:db8:abc8::21"), container.WithIPv6(netName, "2001:db8:abc8::21"),
) )
c1, err := apiClient.ContainerInspect(ctx, id1, dclient.ContainerInspectOptions{}) c1, err := apiClient.ContainerInspect(ctx, id1, client.ContainerInspectOptions{})
assert.NilError(t, err) assert.NilError(t, err)
// Inspect the v4 gateway to ensure no default GW was assigned // Inspect the v4 gateway to ensure no default GW was assigned
assert.Check(t, !c1.Container.NetworkSettings.Networks[netName].Gateway.IsValid()) assert.Check(t, !c1.Container.NetworkSettings.Networks[netName].Gateway.IsValid())
@@ -293,7 +293,7 @@ func testIpvlanL2MultiSubnet(t *testing.T, ctx context.Context, apiClient dclien
container.WithIPv4(netName, "172.28.202.21"), container.WithIPv4(netName, "172.28.202.21"),
container.WithIPv6(netName, "2001:db8:abc6::21"), container.WithIPv6(netName, "2001:db8:abc6::21"),
) )
c3, err := apiClient.ContainerInspect(ctx, id3, dclient.ContainerInspectOptions{}) c3, err := apiClient.ContainerInspect(ctx, id3, client.ContainerInspectOptions{})
assert.NilError(t, err) assert.NilError(t, err)
if parent == "" { if parent == "" {
// Inspect the v4 gateway to ensure no default GW was assigned // Inspect the v4 gateway to ensure no default GW was assigned
@@ -315,9 +315,9 @@ func testIpvlanL2MultiSubnet(t *testing.T, ctx context.Context, apiClient dclien
assert.NilError(t, err) assert.NilError(t, err)
} }
func testIpvlanL3MultiSubnet(t *testing.T, ctx context.Context, client dclient.APIClient) { func testIpvlanL3MultiSubnet(t *testing.T, ctx context.Context, apiClient client.APIClient) {
netName := "dualstackl3" netName := "dualstackl3"
net.CreateNoError(ctx, t, client, netName, net.CreateNoError(ctx, t, apiClient, netName,
net.WithIPvlan("", "l3"), net.WithIPvlan("", "l3"),
net.WithIPv6(), net.WithIPv6(),
net.WithIPAM("172.28.10.0/24", ""), net.WithIPAM("172.28.10.0/24", ""),
@@ -325,48 +325,48 @@ func testIpvlanL3MultiSubnet(t *testing.T, ctx context.Context, client dclient.A
net.WithIPAM("2001:db8:abc9::/64", ""), net.WithIPAM("2001:db8:abc9::/64", ""),
net.WithIPAM("2001:db8:abc7::/64", "2001:db8:abc7::254"), net.WithIPAM("2001:db8:abc7::/64", "2001:db8:abc7::254"),
) )
assert.Check(t, n.IsNetworkAvailable(ctx, client, netName)) assert.Check(t, n.IsNetworkAvailable(ctx, apiClient, netName))
// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.100.0/24 and 2001:db8:abc2::/64 // start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.100.0/24 and 2001:db8:abc2::/64
id1 := container.Run(ctx, t, client, id1 := container.Run(ctx, t, apiClient,
container.WithNetworkMode(netName), container.WithNetworkMode(netName),
container.WithIPv4(netName, "172.28.10.20"), container.WithIPv4(netName, "172.28.10.20"),
container.WithIPv6(netName, "2001:db8:abc9::20"), container.WithIPv6(netName, "2001:db8:abc9::20"),
) )
id2 := container.Run(ctx, t, client, id2 := container.Run(ctx, t, apiClient,
container.WithNetworkMode(netName), container.WithNetworkMode(netName),
container.WithIPv4(netName, "172.28.10.21"), container.WithIPv4(netName, "172.28.10.21"),
container.WithIPv6(netName, "2001:db8:abc9::21"), container.WithIPv6(netName, "2001:db8:abc9::21"),
) )
c1, err := client.ContainerInspect(ctx, id1, dclient.ContainerInspectOptions{}) c1, err := apiClient.ContainerInspect(ctx, id1, client.ContainerInspectOptions{})
assert.NilError(t, err) assert.NilError(t, err)
// verify ipv4 connectivity to the explicit --ipv address second to first // verify ipv4 connectivity to the explicit --ipv address second to first
_, err = container.Exec(ctx, client, id2, []string{"ping", "-c", "1", c1.Container.NetworkSettings.Networks[netName].IPAddress.String()}) _, err = container.Exec(ctx, apiClient, id2, []string{"ping", "-c", "1", c1.Container.NetworkSettings.Networks[netName].IPAddress.String()})
assert.NilError(t, err) assert.NilError(t, err)
// verify ipv6 connectivity to the explicit --ipv6 address second to first // verify ipv6 connectivity to the explicit --ipv6 address second to first
_, err = container.Exec(ctx, client, id2, []string{"ping6", "-c", "1", c1.Container.NetworkSettings.Networks[netName].GlobalIPv6Address.String()}) _, err = container.Exec(ctx, apiClient, id2, []string{"ping6", "-c", "1", c1.Container.NetworkSettings.Networks[netName].GlobalIPv6Address.String()})
assert.NilError(t, err) assert.NilError(t, err)
// start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.102.0/24 and 2001:db8:abc4::/64 // start dual stack containers and verify the user specified --ip and --ip6 addresses on subnets 172.28.102.0/24 and 2001:db8:abc4::/64
id3 := container.Run(ctx, t, client, id3 := container.Run(ctx, t, apiClient,
container.WithNetworkMode(netName), container.WithNetworkMode(netName),
container.WithIPv4(netName, "172.28.12.20"), container.WithIPv4(netName, "172.28.12.20"),
container.WithIPv6(netName, "2001:db8:abc7::20"), container.WithIPv6(netName, "2001:db8:abc7::20"),
) )
id4 := container.Run(ctx, t, client, id4 := container.Run(ctx, t, apiClient,
container.WithNetworkMode(netName), container.WithNetworkMode(netName),
container.WithIPv4(netName, "172.28.12.21"), container.WithIPv4(netName, "172.28.12.21"),
container.WithIPv6(netName, "2001:db8:abc7::21"), container.WithIPv6(netName, "2001:db8:abc7::21"),
) )
c3, err := client.ContainerInspect(ctx, id3, dclient.ContainerInspectOptions{}) c3, err := apiClient.ContainerInspect(ctx, id3, client.ContainerInspectOptions{})
assert.NilError(t, err) assert.NilError(t, err)
// verify ipv4 connectivity to the explicit --ipv address from third to fourth // verify ipv4 connectivity to the explicit --ipv address from third to fourth
_, err = container.Exec(ctx, client, id4, []string{"ping", "-c", "1", c3.Container.NetworkSettings.Networks[netName].IPAddress.String()}) _, err = container.Exec(ctx, apiClient, id4, []string{"ping", "-c", "1", c3.Container.NetworkSettings.Networks[netName].IPAddress.String()})
assert.NilError(t, err) assert.NilError(t, err)
// verify ipv6 connectivity to the explicit --ipv6 address from third to fourth // verify ipv6 connectivity to the explicit --ipv6 address from third to fourth
_, err = container.Exec(ctx, client, id4, []string{"ping6", "-c", "1", c3.Container.NetworkSettings.Networks[netName].GlobalIPv6Address.String()}) _, err = container.Exec(ctx, apiClient, id4, []string{"ping6", "-c", "1", c3.Container.NetworkSettings.Networks[netName].GlobalIPv6Address.String()})
assert.NilError(t, err) assert.NilError(t, err)
// Inspect the v4 gateway to ensure no next hop is assigned in L3 mode // Inspect the v4 gateway to ensure no next hop is assigned in L3 mode
@@ -381,58 +381,58 @@ func testIpvlanL3MultiSubnet(t *testing.T, ctx context.Context, client dclient.A
// Verify ipvlan l2 mode sets the proper default gateway routes via netlink // Verify ipvlan l2 mode sets the proper default gateway routes via netlink
// for either an explicitly set route by the user or inferred via default IPAM // for either an explicitly set route by the user or inferred via default IPAM
func testIpvlanL2Addressing(t *testing.T, ctx context.Context, client dclient.APIClient) { func testIpvlanL2Addressing(t *testing.T, ctx context.Context, apiClient client.APIClient) {
const parentIfName = "di-dummy0" const parentIfName = "di-dummy0"
n.CreateMasterDummy(ctx, t, parentIfName) n.CreateMasterDummy(ctx, t, parentIfName)
defer n.DeleteInterface(ctx, t, parentIfName) defer n.DeleteInterface(ctx, t, parentIfName)
netNameL2 := "dualstackl2" netNameL2 := "dualstackl2"
net.CreateNoError(ctx, t, client, netNameL2, net.CreateNoError(ctx, t, apiClient, netNameL2,
net.WithIPvlan(parentIfName, "l2"), net.WithIPvlan(parentIfName, "l2"),
net.WithIPv6(), net.WithIPv6(),
net.WithIPAM("172.28.140.0/24", "172.28.140.254"), net.WithIPAM("172.28.140.0/24", "172.28.140.254"),
net.WithIPAM("2001:db8:abcb::/64", ""), net.WithIPAM("2001:db8:abcb::/64", ""),
) )
assert.Check(t, n.IsNetworkAvailable(ctx, client, netNameL2)) assert.Check(t, n.IsNetworkAvailable(ctx, apiClient, netNameL2))
id := container.Run(ctx, t, client, id := container.Run(ctx, t, apiClient,
container.WithNetworkMode(netNameL2), container.WithNetworkMode(netNameL2),
) )
// Check the supplied IPv4 gateway address is used in a default route. // Check the supplied IPv4 gateway address is used in a default route.
result, err := container.Exec(ctx, client, id, []string{"ip", "route"}) result, err := container.Exec(ctx, apiClient, id, []string{"ip", "route"})
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, is.Contains(result.Combined(), "default via 172.28.140.254 dev eth0")) assert.Check(t, is.Contains(result.Combined(), "default via 172.28.140.254 dev eth0"))
// No gateway address was supplied for IPv6, check that no default gateway was set up. // No gateway address was supplied for IPv6, check that no default gateway was set up.
result, err = container.Exec(ctx, client, id, []string{"ip", "-6", "route"}) result, err = container.Exec(ctx, apiClient, id, []string{"ip", "-6", "route"})
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, !strings.Contains(result.Combined(), "default via"), assert.Check(t, !strings.Contains(result.Combined(), "default via"),
"result: %s", result.Combined()) "result: %s", result.Combined())
} }
// Validate ipvlan l3 mode sets the v4 gateway to dev eth0 and disregards any explicit or inferred next-hops // Validate ipvlan l3 mode sets the v4 gateway to dev eth0 and disregards any explicit or inferred next-hops
func testIpvlanL3Addressing(t *testing.T, ctx context.Context, client dclient.APIClient) { func testIpvlanL3Addressing(t *testing.T, ctx context.Context, apiClient client.APIClient) {
const parentIfName = "di-dummy0" const parentIfName = "di-dummy0"
n.CreateMasterDummy(ctx, t, parentIfName) n.CreateMasterDummy(ctx, t, parentIfName)
defer n.DeleteInterface(ctx, t, parentIfName) defer n.DeleteInterface(ctx, t, parentIfName)
netNameL3 := "dualstackl3" netNameL3 := "dualstackl3"
net.CreateNoError(ctx, t, client, netNameL3, net.CreateNoError(ctx, t, apiClient, netNameL3,
net.WithIPvlan(parentIfName, "l3"), net.WithIPvlan(parentIfName, "l3"),
net.WithIPv6(), net.WithIPv6(),
net.WithIPAM("172.28.160.0/24", "172.28.160.254"), net.WithIPAM("172.28.160.0/24", "172.28.160.254"),
net.WithIPAM("2001:db8:abcd::/64", "2001:db8:abcd::254"), net.WithIPAM("2001:db8:abcd::/64", "2001:db8:abcd::254"),
) )
assert.Check(t, n.IsNetworkAvailable(ctx, client, netNameL3)) assert.Check(t, n.IsNetworkAvailable(ctx, apiClient, netNameL3))
id := container.Run(ctx, t, client, id := container.Run(ctx, t, apiClient,
container.WithNetworkMode(netNameL3), container.WithNetworkMode(netNameL3),
) )
// Validate ipvlan l3 mode sets the v4 gateway to dev eth0 and disregards any explicit or inferred next-hops // Validate ipvlan l3 mode sets the v4 gateway to dev eth0 and disregards any explicit or inferred next-hops
result, err := container.Exec(ctx, client, id, []string{"ip", "route"}) result, err := container.Exec(ctx, apiClient, id, []string{"ip", "route"})
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, is.Contains(result.Combined(), "default dev eth0")) assert.Check(t, is.Contains(result.Combined(), "default dev eth0"))
// Validate ipvlan l3 mode sets the v6 gateway to dev eth0 and disregards any explicit or inferred next-hops // Validate ipvlan l3 mode sets the v6 gateway to dev eth0 and disregards any explicit or inferred next-hops
result, err = container.Exec(ctx, client, id, []string{"ip", "-6", "route"}) result, err = container.Exec(ctx, apiClient, id, []string{"ip", "-6", "route"})
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, is.Contains(result.Combined(), "default dev eth0")) assert.Check(t, is.Contains(result.Combined(), "default dev eth0"))
} }
@@ -488,9 +488,9 @@ func TestIpvlanIPAM(t *testing.T) {
for _, tc := range tests { for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
ctx := testutil.StartSpan(ctx, t) ctx := testutil.StartSpan(ctx, t)
c := d.NewClientT(t, dclient.WithVersion(tc.apiVersion)) c := d.NewClientT(t, client.WithVersion(tc.apiVersion))
netOpts := []func(*dclient.NetworkCreateOptions){ netOpts := []func(*client.NetworkCreateOptions){
net.WithIPvlan("", "l3"), net.WithIPvlan("", "l3"),
net.WithIPv4(tc.enableIPv4), net.WithIPv4(tc.enableIPv4),
net.WithIPAMConfig( net.WithIPAMConfig(
@@ -509,11 +509,11 @@ func TestIpvlanIPAM(t *testing.T) {
const netName = "ipvlannet" const netName = "ipvlannet"
net.CreateNoError(ctx, t, c, netName, netOpts...) net.CreateNoError(ctx, t, c, netName, netOpts...)
defer c.NetworkRemove(ctx, netName) defer c.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
assert.Check(t, n.IsNetworkAvailable(ctx, c, netName)) assert.Check(t, n.IsNetworkAvailable(ctx, c, netName))
id := container.Run(ctx, t, c, container.WithNetworkMode(netName)) id := container.Run(ctx, t, c, container.WithNetworkMode(netName))
defer c.ContainerRemove(ctx, id, dclient.ContainerRemoveOptions{Force: true}) defer c.ContainerRemove(ctx, id, client.ContainerRemoveOptions{Force: true})
loRes := container.ExecT(ctx, t, c, id, []string{"ip", "a", "show", "dev", "lo"}) loRes := container.ExecT(ctx, t, c, id, []string{"ip", "a", "show", "dev", "lo"})
assert.Check(t, is.Contains(loRes.Combined(), " inet ")) assert.Check(t, is.Contains(loRes.Combined(), " inet "))
@@ -551,14 +551,14 @@ func TestIpvlanIPAM(t *testing.T) {
} }
assert.Check(t, is.Equal(strings.TrimSpace(sysctlRes.Combined()), expDisableIPv6)) assert.Check(t, is.Equal(strings.TrimSpace(sysctlRes.Combined()), expDisableIPv6))
cc := d.NewClientT(t, dclient.WithVersion("1.52")) cc := d.NewClientT(t, client.WithVersion("1.52"))
res, err := cc.NetworkInspect(ctx, netName, dclient.NetworkInspectOptions{}) res, err := cc.NetworkInspect(ctx, netName, client.NetworkInspectOptions{})
if assert.Check(t, err) && assert.Check(t, res.Network.Status != nil) { 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())) assert.Check(t, is.DeepEqual(wantSubnetStatus, res.Network.Status.IPAM.Subnets, cmpopts.EquateEmpty()))
} }
cc.Close() cc.Close()
cc = d.NewClientT(t, dclient.WithVersion("1.51")) cc = d.NewClientT(t, client.WithVersion("1.51"))
res, err = cc.NetworkInspect(ctx, netName, dclient.NetworkInspectOptions{}) res, err = cc.NetworkInspect(ctx, netName, client.NetworkInspectOptions{})
assert.Check(t, err) assert.Check(t, err)
assert.Check(t, res.Network.Status == nil) assert.Check(t, res.Network.Status == nil)
cc.Close() cc.Close()
@@ -585,7 +585,7 @@ func TestIpvlanIPAMOverlap(t *testing.T) {
checkNetworkIPAMState := func(networkID string, want map[netip.Prefix]network.SubnetStatus) bool { checkNetworkIPAMState := func(networkID string, want map[netip.Prefix]network.SubnetStatus) bool {
t.Helper() t.Helper()
res, err := c.NetworkInspect(ctx, networkID, dclient.NetworkInspectOptions{}) res, err := c.NetworkInspect(ctx, networkID, client.NetworkInspectOptions{})
if assert.Check(t, err) && assert.Check(t, res.Network.Status != nil) { 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 assert.Check(t, is.DeepEqual(want, res.Network.Status.IPAM.Subnets, cmpopts.EquateEmpty()))
} }
@@ -621,7 +621,7 @@ func TestIpvlanIPAMOverlap(t *testing.T) {
}, },
), ),
) )
defer c.NetworkRemove(ctx, netName1) defer c.NetworkRemove(ctx, netName1, client.NetworkRemoveOptions{})
assert.Check(t, n.IsNetworkAvailable(ctx, c, netName1)) assert.Check(t, n.IsNetworkAvailable(ctx, c, netName1))
checkNetworkIPAMState(netName1, map[netip.Prefix]network.SubnetStatus{ checkNetworkIPAMState(netName1, map[netip.Prefix]network.SubnetStatus{
@@ -650,7 +650,7 @@ func TestIpvlanIPAMOverlap(t *testing.T) {
), ),
) )
defer c.NetworkRemove(ctx, netName2) defer c.NetworkRemove(ctx, netName2, client.NetworkRemoveOptions{})
assert.Check(t, n.IsNetworkAvailable(ctx, c, netName2)) assert.Check(t, n.IsNetworkAvailable(ctx, c, netName2))
checkNetworkIPAMState(netName2, map[netip.Prefix]network.SubnetStatus{ checkNetworkIPAMState(netName2, map[netip.Prefix]network.SubnetStatus{
@@ -679,7 +679,7 @@ func TestIpvlanIPAMOverlap(t *testing.T) {
), ),
) )
defer c.NetworkRemove(ctx, netName3) defer c.NetworkRemove(ctx, netName3, client.NetworkRemoveOptions{})
assert.Check(t, n.IsNetworkAvailable(ctx, c, netName3)) assert.Check(t, n.IsNetworkAvailable(ctx, c, netName3))
checkNetworkIPAMState(netName3, map[netip.Prefix]network.SubnetStatus{ checkNetworkIPAMState(netName3, map[netip.Prefix]network.SubnetStatus{
@@ -695,7 +695,7 @@ func TestIpvlanIPAMOverlap(t *testing.T) {
// Create a container on one of the networks // Create a container on one of the networks
id := container.Run(ctx, t, c, container.WithNetworkMode(netName1)) id := container.Run(ctx, t, c, container.WithNetworkMode(netName1))
defer c.ContainerRemove(ctx, id, dclient.ContainerRemoveOptions{Force: true}) defer c.ContainerRemove(ctx, id, client.ContainerRemoveOptions{Force: true})
// Verify that the IPAM status of all three networks are affected. // Verify that the IPAM status of all three networks are affected.
checkNetworkIPAMState(netName1, map[netip.Prefix]network.SubnetStatus{ checkNetworkIPAMState(netName1, map[netip.Prefix]network.SubnetStatus{
@@ -787,17 +787,17 @@ func TestIPVlanDNS(t *testing.T) {
name := fmt.Sprintf("Mode=%v/HasParent=%v/Internal=%v", mode, tc.parent != "", tc.internal) name := fmt.Sprintf("Mode=%v/HasParent=%v/Internal=%v", mode, tc.parent != "", tc.internal)
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
ctx := testutil.StartSpan(ctx, t) ctx := testutil.StartSpan(ctx, t)
createOpts := []func(*dclient.NetworkCreateOptions){ createOpts := []func(*client.NetworkCreateOptions){
net.WithIPvlan(tc.parent, mode), net.WithIPvlan(tc.parent, mode),
} }
if tc.internal { if tc.internal {
createOpts = append(createOpts, net.WithInternal()) createOpts = append(createOpts, net.WithInternal())
} }
net.CreateNoError(ctx, t, c, netName, createOpts...) net.CreateNoError(ctx, t, c, netName, createOpts...)
defer c.NetworkRemove(ctx, netName) defer c.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
ctrId := container.Run(ctx, t, c, container.WithNetworkMode(netName)) ctrId := container.Run(ctx, t, c, container.WithNetworkMode(netName))
defer c.ContainerRemove(ctx, ctrId, dclient.ContainerRemoveOptions{Force: true}) defer c.ContainerRemove(ctx, ctrId, client.ContainerRemoveOptions{Force: true})
res, err := container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"}) res, err := container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"})
assert.NilError(t, err) assert.NilError(t, err)
if tc.expDNS { if tc.expDNS {
@@ -864,7 +864,7 @@ func TestPointToPoint(t *testing.T) {
container.WithNetworkMode(netName), container.WithNetworkMode(netName),
container.WithName(ctrName), container.WithName(ctrName),
) )
defer apiClient.ContainerRemove(ctx, id, dclient.ContainerRemoveOptions{Force: true}) defer apiClient.ContainerRemove(ctx, id, client.ContainerRemoveOptions{Force: true})
attachCtx, cancel := context.WithTimeout(ctx, 5*time.Second) attachCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel() defer cancel()
@@ -872,7 +872,7 @@ func TestPointToPoint(t *testing.T) {
container.WithCmd([]string{"ping", "-c1", "-W3", ctrName}...), container.WithCmd([]string{"ping", "-c1", "-W3", ctrName}...),
container.WithNetworkMode(netName), container.WithNetworkMode(netName),
) )
defer apiClient.ContainerRemove(ctx, res.ContainerID, dclient.ContainerRemoveOptions{Force: true}) defer apiClient.ContainerRemove(ctx, res.ContainerID, client.ContainerRemoveOptions{Force: true})
assert.Check(t, is.Equal(res.ExitCode, 0)) assert.Check(t, is.Equal(res.ExitCode, 0))
assert.Check(t, is.Equal(res.Stderr.Len(), 0)) assert.Check(t, is.Equal(res.Stderr.Len(), 0))
assert.Check(t, is.Contains(res.Stdout.String(), "1 packets transmitted, 1 packets received")) assert.Check(t, is.Contains(res.Stdout.String(), "1 packets transmitted, 1 packets received"))
@@ -903,7 +903,7 @@ func TestEndpointWithCustomIfname(t *testing.T) {
netlabel.Ifname: "foobar", netlabel.Ifname: "foobar",
}, },
})) }))
defer container.Remove(ctx, t, apiClient, ctrID, dclient.ContainerRemoveOptions{Force: true}) defer container.Remove(ctx, t, apiClient, ctrID, client.ContainerRemoveOptions{Force: true})
out, err := container.Output(ctx, apiClient, ctrID) out, err := container.Output(ctx, apiClient, ctrID)
assert.NilError(t, err) assert.NilError(t, err)

View File

@@ -110,7 +110,7 @@ func TestDockerNetworkMacvlan(t *testing.T) {
} }
} }
func testMacvlanOverlapParent(t *testing.T, ctx context.Context, client client.APIClient) { func testMacvlanOverlapParent(t *testing.T, ctx context.Context, apiClient client.APIClient) {
// verify the same parent interface can be used if already in use by an existing network // verify the same parent interface can be used if already in use by an existing network
// as long as neither are passthru // as long as neither are passthru
master := "dm-dummy0" master := "dm-dummy0"
@@ -119,35 +119,35 @@ func testMacvlanOverlapParent(t *testing.T, ctx context.Context, client client.A
netName := "dm-subinterface" netName := "dm-subinterface"
parentName := "dm-dummy0.40" parentName := "dm-dummy0.40"
net.CreateNoError(ctx, t, client, netName, net.CreateNoError(ctx, t, apiClient, netName,
net.WithMacvlan(parentName), net.WithMacvlan(parentName),
) )
assert.Check(t, n.IsNetworkAvailable(ctx, client, netName)) assert.Check(t, n.IsNetworkAvailable(ctx, apiClient, netName))
n.LinkExists(ctx, t, parentName) n.LinkExists(ctx, t, parentName)
overlapNetName := "dm-parent-net-overlap" overlapNetName := "dm-parent-net-overlap"
_, err := net.Create(ctx, client, overlapNetName, _, err := net.Create(ctx, apiClient, overlapNetName,
net.WithMacvlan(parentName), net.WithMacvlan(parentName),
) )
assert.Check(t, err) assert.Check(t, err)
// delete the second network while preserving the parent link // delete the second network while preserving the parent link
err = client.NetworkRemove(ctx, overlapNetName) _, err = apiClient.NetworkRemove(ctx, overlapNetName, client.NetworkRemoveOptions{})
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, n.IsNetworkNotAvailable(ctx, client, overlapNetName)) assert.Check(t, n.IsNetworkNotAvailable(ctx, apiClient, overlapNetName))
n.LinkExists(ctx, t, parentName) n.LinkExists(ctx, t, parentName)
// delete the first network // delete the first network
err = client.NetworkRemove(ctx, netName) _, err = apiClient.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, n.IsNetworkNotAvailable(ctx, client, netName)) assert.Check(t, n.IsNetworkNotAvailable(ctx, apiClient, netName))
n.LinkDoesntExist(ctx, t, parentName) n.LinkDoesntExist(ctx, t, parentName)
// verify the network delete did not delete the root link // verify the network delete did not delete the root link
n.LinkExists(ctx, t, master) n.LinkExists(ctx, t, master)
} }
func testMacvlanOverlapParentPassthruFirst(t *testing.T, ctx context.Context, client client.APIClient) { func testMacvlanOverlapParentPassthruFirst(t *testing.T, ctx context.Context, apiClient client.APIClient) {
// verify creating a second interface sharing a parent with another passthru interface is rejected // verify creating a second interface sharing a parent with another passthru interface is rejected
master := "dm-dummy0" master := "dm-dummy0"
n.CreateMasterDummy(ctx, t, master) n.CreateMasterDummy(ctx, t, master)
@@ -155,26 +155,26 @@ func testMacvlanOverlapParentPassthruFirst(t *testing.T, ctx context.Context, cl
netName := "dm-subinterface" netName := "dm-subinterface"
parentName := "dm-dummy0.40" parentName := "dm-dummy0.40"
net.CreateNoError(ctx, t, client, netName, net.CreateNoError(ctx, t, apiClient, netName,
net.WithMacvlanPassthru(parentName), net.WithMacvlanPassthru(parentName),
) )
assert.Check(t, n.IsNetworkAvailable(ctx, client, netName)) assert.Check(t, n.IsNetworkAvailable(ctx, apiClient, netName))
_, err := net.Create(ctx, client, "dm-parent-net-overlap", _, err := net.Create(ctx, apiClient, "dm-parent-net-overlap",
net.WithMacvlan(parentName), net.WithMacvlan(parentName),
) )
assert.Check(t, err != nil) assert.Check(t, err != nil)
// delete the network while preserving the parent link // delete the network while preserving the parent link
err = client.NetworkRemove(ctx, netName) _, err = apiClient.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, n.IsNetworkNotAvailable(ctx, client, netName)) assert.Check(t, n.IsNetworkNotAvailable(ctx, apiClient, netName))
// verify the network delete did not delete the predefined link // verify the network delete did not delete the predefined link
n.LinkExists(ctx, t, master) n.LinkExists(ctx, t, master)
} }
func testMacvlanOverlapParentPassthruSecond(t *testing.T, ctx context.Context, client client.APIClient) { func testMacvlanOverlapParentPassthruSecond(t *testing.T, ctx context.Context, apiClient client.APIClient) {
// verify creating a passthru interface sharing a parent with another interface is rejected // verify creating a passthru interface sharing a parent with another interface is rejected
master := "dm-dummy0" master := "dm-dummy0"
n.CreateMasterDummy(ctx, t, master) n.CreateMasterDummy(ctx, t, master)
@@ -182,26 +182,26 @@ func testMacvlanOverlapParentPassthruSecond(t *testing.T, ctx context.Context, c
netName := "dm-subinterface" netName := "dm-subinterface"
parentName := "dm-dummy0.40" parentName := "dm-dummy0.40"
net.CreateNoError(ctx, t, client, netName, net.CreateNoError(ctx, t, apiClient, netName,
net.WithMacvlan(parentName), net.WithMacvlan(parentName),
) )
assert.Check(t, n.IsNetworkAvailable(ctx, client, netName)) assert.Check(t, n.IsNetworkAvailable(ctx, apiClient, netName))
_, err := net.Create(ctx, client, "dm-parent-net-overlap", _, err := net.Create(ctx, apiClient, "dm-parent-net-overlap",
net.WithMacvlanPassthru(parentName), net.WithMacvlanPassthru(parentName),
) )
assert.Check(t, err != nil) assert.Check(t, err != nil)
// delete the network while preserving the parent link // delete the network while preserving the parent link
err = client.NetworkRemove(ctx, netName) _, err = apiClient.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, n.IsNetworkNotAvailable(ctx, client, netName)) assert.Check(t, n.IsNetworkNotAvailable(ctx, apiClient, netName))
// verify the network delete did not delete the predefined link // verify the network delete did not delete the predefined link
n.LinkExists(ctx, t, master) n.LinkExists(ctx, t, master)
} }
func testMacvlanOverlapDeleteCreatedSecond(t *testing.T, ctx context.Context, client client.APIClient) { func testMacvlanOverlapDeleteCreatedSecond(t *testing.T, ctx context.Context, apiClient client.APIClient) {
// verify that a shared created parent interface is kept when the original interface is deleted first // verify that a shared created parent interface is kept when the original interface is deleted first
master := "dm-dummy0" master := "dm-dummy0"
n.CreateMasterDummy(ctx, t, master) n.CreateMasterDummy(ctx, t, master)
@@ -209,34 +209,34 @@ func testMacvlanOverlapDeleteCreatedSecond(t *testing.T, ctx context.Context, cl
netName := "dm-subinterface" netName := "dm-subinterface"
parentName := "dm-dummy0.40" parentName := "dm-dummy0.40"
net.CreateNoError(ctx, t, client, netName, net.CreateNoError(ctx, t, apiClient, netName,
net.WithMacvlan(parentName), net.WithMacvlan(parentName),
) )
assert.Check(t, n.IsNetworkAvailable(ctx, client, netName)) assert.Check(t, n.IsNetworkAvailable(ctx, apiClient, netName))
overlapNetName := "dm-parent-net-overlap" overlapNetName := "dm-parent-net-overlap"
_, err := net.Create(ctx, client, overlapNetName, _, err := net.Create(ctx, apiClient, overlapNetName,
net.WithMacvlan(parentName), net.WithMacvlan(parentName),
) )
assert.Check(t, err) assert.Check(t, err)
// delete the original network while preserving the parent link // delete the original network while preserving the parent link
err = client.NetworkRemove(ctx, netName) _, err = apiClient.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, n.IsNetworkNotAvailable(ctx, client, netName)) assert.Check(t, n.IsNetworkNotAvailable(ctx, apiClient, netName))
n.LinkExists(ctx, t, parentName) n.LinkExists(ctx, t, parentName)
// delete the second network // delete the second network
err = client.NetworkRemove(ctx, overlapNetName) _, err = apiClient.NetworkRemove(ctx, overlapNetName, client.NetworkRemoveOptions{})
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, n.IsNetworkNotAvailable(ctx, client, overlapNetName)) assert.Check(t, n.IsNetworkNotAvailable(ctx, apiClient, overlapNetName))
n.LinkDoesntExist(ctx, t, parentName) n.LinkDoesntExist(ctx, t, parentName)
// verify the network delete did not delete the root link // verify the network delete did not delete the root link
n.LinkExists(ctx, t, master) n.LinkExists(ctx, t, master)
} }
func testMacvlanOverlapKeepExisting(t *testing.T, ctx context.Context, client client.APIClient) { func testMacvlanOverlapKeepExisting(t *testing.T, ctx context.Context, apiClient client.APIClient) {
// verify that deleting interfaces sharing a previously existing parent doesn't delete the // verify that deleting interfaces sharing a previously existing parent doesn't delete the
// parent // parent
master := "dm-dummy0" master := "dm-dummy0"
@@ -244,27 +244,27 @@ func testMacvlanOverlapKeepExisting(t *testing.T, ctx context.Context, client cl
defer n.DeleteInterface(ctx, t, master) defer n.DeleteInterface(ctx, t, master)
netName := "dm-subinterface" netName := "dm-subinterface"
net.CreateNoError(ctx, t, client, netName, net.CreateNoError(ctx, t, apiClient, netName,
net.WithMacvlan(master), net.WithMacvlan(master),
) )
assert.Check(t, n.IsNetworkAvailable(ctx, client, netName)) assert.Check(t, n.IsNetworkAvailable(ctx, apiClient, netName))
overlapNetName := "dm-parent-net-overlap" overlapNetName := "dm-parent-net-overlap"
_, err := net.Create(ctx, client, overlapNetName, _, err := net.Create(ctx, apiClient, overlapNetName,
net.WithMacvlan(master), net.WithMacvlan(master),
) )
assert.Check(t, err) assert.Check(t, err)
err = client.NetworkRemove(ctx, overlapNetName) _, err = apiClient.NetworkRemove(ctx, overlapNetName, client.NetworkRemoveOptions{})
assert.NilError(t, err) assert.NilError(t, err)
err = client.NetworkRemove(ctx, netName) _, err = apiClient.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
assert.NilError(t, err) assert.NilError(t, err)
// verify the network delete did not delete the root link // verify the network delete did not delete the root link
n.LinkExists(ctx, t, master) n.LinkExists(ctx, t, master)
} }
func testMacvlanSubinterface(t *testing.T, ctx context.Context, client client.APIClient) { func testMacvlanSubinterface(t *testing.T, ctx context.Context, apiClient client.APIClient) {
// verify the same parent interface cannot be used if already in use by an existing network // verify the same parent interface cannot be used if already in use by an existing network
master := "dm-dummy0" master := "dm-dummy0"
parentName := "dm-dummy0.20" parentName := "dm-dummy0.20"
@@ -273,16 +273,16 @@ func testMacvlanSubinterface(t *testing.T, ctx context.Context, client client.AP
n.CreateVlanInterface(ctx, t, master, parentName, "20") n.CreateVlanInterface(ctx, t, master, parentName, "20")
netName := "dm-subinterface" netName := "dm-subinterface"
net.CreateNoError(ctx, t, client, netName, net.CreateNoError(ctx, t, apiClient, netName,
net.WithMacvlan(parentName), net.WithMacvlan(parentName),
) )
assert.Check(t, n.IsNetworkAvailable(ctx, client, netName)) assert.Check(t, n.IsNetworkAvailable(ctx, apiClient, netName))
// delete the network while preserving the parent link // delete the network while preserving the parent link
err := client.NetworkRemove(ctx, netName) _, err := apiClient.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, n.IsNetworkNotAvailable(ctx, client, netName)) assert.Check(t, n.IsNetworkNotAvailable(ctx, apiClient, netName))
// verify the network delete did not delete the predefined link // verify the network delete did not delete the predefined link
n.LinkExists(ctx, t, parentName) n.LinkExists(ctx, t, parentName)
} }
@@ -512,7 +512,7 @@ func TestMacvlanIPAM(t *testing.T) {
const netName = "macvlannet" const netName = "macvlannet"
net.CreateNoError(ctx, t, c, netName, netOpts...) net.CreateNoError(ctx, t, c, netName, netOpts...)
defer c.NetworkRemove(ctx, netName) defer c.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
assert.Check(t, n.IsNetworkAvailable(ctx, c, netName)) assert.Check(t, n.IsNetworkAvailable(ctx, c, netName))
id := container.Run(ctx, t, c, container.WithNetworkMode(netName)) id := container.Run(ctx, t, c, container.WithNetworkMode(netName))
@@ -624,7 +624,7 @@ func TestMacvlanIPAMOverlap(t *testing.T) {
}, },
), ),
) )
defer c.NetworkRemove(ctx, netName1) defer c.NetworkRemove(ctx, netName1, client.NetworkRemoveOptions{})
assert.Check(t, n.IsNetworkAvailable(ctx, c, netName1)) assert.Check(t, n.IsNetworkAvailable(ctx, c, netName1))
checkNetworkIPAMState(netName1, map[netip.Prefix]network.SubnetStatus{ checkNetworkIPAMState(netName1, map[netip.Prefix]network.SubnetStatus{
@@ -653,7 +653,7 @@ func TestMacvlanIPAMOverlap(t *testing.T) {
), ),
) )
defer c.NetworkRemove(ctx, netName2) defer c.NetworkRemove(ctx, netName2, client.NetworkRemoveOptions{})
assert.Check(t, n.IsNetworkAvailable(ctx, c, netName2)) assert.Check(t, n.IsNetworkAvailable(ctx, c, netName2))
checkNetworkIPAMState(netName2, map[netip.Prefix]network.SubnetStatus{ checkNetworkIPAMState(netName2, map[netip.Prefix]network.SubnetStatus{
@@ -682,7 +682,7 @@ func TestMacvlanIPAMOverlap(t *testing.T) {
), ),
) )
defer c.NetworkRemove(ctx, netName3) defer c.NetworkRemove(ctx, netName3, client.NetworkRemoveOptions{})
assert.Check(t, n.IsNetworkAvailable(ctx, c, netName3)) assert.Check(t, n.IsNetworkAvailable(ctx, c, netName3))
checkNetworkIPAMState(netName3, map[netip.Prefix]network.SubnetStatus{ checkNetworkIPAMState(netName3, map[netip.Prefix]network.SubnetStatus{
@@ -795,7 +795,7 @@ func TestMACVlanDNS(t *testing.T) {
createOpts = append(createOpts, net.WithInternal()) createOpts = append(createOpts, net.WithInternal())
} }
net.CreateNoError(ctx, t, c, netName, createOpts...) net.CreateNoError(ctx, t, c, netName, createOpts...)
defer c.NetworkRemove(ctx, netName) defer c.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
ctrId := container.Run(ctx, t, c, container.WithNetworkMode(netName)) ctrId := container.Run(ctx, t, c, container.WithNetworkMode(netName))
defer c.ContainerRemove(ctx, ctrId, client.ContainerRemoveOptions{Force: true}) defer c.ContainerRemove(ctx, ctrId, client.ContainerRemoveOptions{Force: true})

View File

@@ -148,7 +148,7 @@ func TestDefaultNetworkOpts(t *testing.T) {
"com.docker.network.driver.mtu": fmt.Sprint(tc.mtu), "com.docker.network.driver.mtu": fmt.Sprint(tc.mtu),
} }
}) })
defer c.NetworkRemove(ctx, "from-net") defer c.NetworkRemove(ctx, "from-net", client.NetworkRemoveOptions{})
} }
// Create a new network // Create a new network
@@ -160,7 +160,7 @@ func TestDefaultNetworkOpts(t *testing.T) {
} }
} }
}) })
defer c.NetworkRemove(ctx, networkName) defer c.NetworkRemove(ctx, networkName, client.NetworkRemoveOptions{})
// Check the MTU of the bridge itself, before any devices are connected. (The // Check the MTU of the bridge itself, before any devices are connected. (The
// bridge's MTU will be set to the minimum MTU of anything connected to it, but // bridge's MTU will be set to the minimum MTU of anything connected to it, but
@@ -318,26 +318,38 @@ func TestConnectWithPriority(t *testing.T) {
checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET6, 4, "default via fddd:4901:f594::1 dev eth0") checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET6, 4, "default via fddd:4901:f594::1 dev eth0")
// testnet5 has a negative priority -- the default gateway should not change. // testnet5 has a negative priority -- the default gateway should not change.
err := apiClient.NetworkConnect(ctx, "testnet5", ctrID, &networktypes.EndpointSettings{GwPriority: -100}) _, err := apiClient.NetworkConnect(ctx, "testnet5", client.NetworkConnectOptions{
Container: ctrID,
EndpointConfig: &networktypes.EndpointSettings{GwPriority: -100},
})
assert.NilError(t, err) assert.NilError(t, err)
checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET, 3, "default via 10.100.10.1 dev eth0") checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET, 3, "default via 10.100.10.1 dev eth0")
checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET6, 7, "default via fddd:4901:f594::1 dev eth0") checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET6, 7, "default via fddd:4901:f594::1 dev eth0")
// testnet2 has a higher priority. It should now provide the default gateway. // testnet2 has a higher priority. It should now provide the default gateway.
err = apiClient.NetworkConnect(ctx, "testnet2", ctrID, &networktypes.EndpointSettings{GwPriority: 100}) _, err = apiClient.NetworkConnect(ctx, "testnet2", client.NetworkConnectOptions{
Container: ctrID,
EndpointConfig: &networktypes.EndpointSettings{GwPriority: 100},
})
assert.NilError(t, err) assert.NilError(t, err)
checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET, 4, "default via 10.100.20.1 dev eth2") checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET, 4, "default via 10.100.20.1 dev eth2")
checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET6, 10, "default via fd83:7683:7008::1 dev eth2") checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET6, 10, "default via fd83:7683:7008::1 dev eth2")
// testnet3 has a lower priority, so testnet2 should still provide the default gateway. // testnet3 has a lower priority, so testnet2 should still provide the default gateway.
err = apiClient.NetworkConnect(ctx, "testnet3", ctrID, &networktypes.EndpointSettings{GwPriority: 10}) _, err = apiClient.NetworkConnect(ctx, "testnet3", client.NetworkConnectOptions{
Container: ctrID,
EndpointConfig: &networktypes.EndpointSettings{GwPriority: 10},
})
assert.NilError(t, err) assert.NilError(t, err)
checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET, 5, "default via 10.100.20.1 dev eth2") checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET, 5, "default via 10.100.20.1 dev eth2")
checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET6, 13, "default via fd83:7683:7008::1 dev eth2") checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET6, 13, "default via fd83:7683:7008::1 dev eth2")
// testnet4 has the same priority as testnet3, but it sorts after in // testnet4 has the same priority as testnet3, but it sorts after in
// lexicographic order. For now, testnet2 stays the default gateway. // lexicographic order. For now, testnet2 stays the default gateway.
err = apiClient.NetworkConnect(ctx, "testnet4", ctrID, &networktypes.EndpointSettings{GwPriority: 10}) _, err = apiClient.NetworkConnect(ctx, "testnet4", client.NetworkConnectOptions{
Container: ctrID,
EndpointConfig: &networktypes.EndpointSettings{GwPriority: 10},
})
assert.NilError(t, err) assert.NilError(t, err)
checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET, 6, "default via 10.100.20.1 dev eth2") checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET, 6, "default via 10.100.20.1 dev eth2")
checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET6, 16, "default via fd83:7683:7008::1 dev eth2") checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET6, 16, "default via fd83:7683:7008::1 dev eth2")
@@ -352,19 +364,19 @@ func TestConnectWithPriority(t *testing.T) {
// Disconnect testnet2, so testnet3 should now provide the default gateway. // Disconnect testnet2, so testnet3 should now provide the default gateway.
// When two endpoints have the same priority (eg. testnet3 vs testnet4), // When two endpoints have the same priority (eg. testnet3 vs testnet4),
// the one that sorts first in lexicographic order is picked. // the one that sorts first in lexicographic order is picked.
err = apiClient.NetworkDisconnect(ctx, "testnet2", ctrID, true) _, err = apiClient.NetworkDisconnect(ctx, "testnet2", client.NetworkDisconnectOptions{Container: ctrID, Force: true})
assert.NilError(t, err) assert.NilError(t, err)
checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET, 5, "default via 10.100.30.1 dev eth3") checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET, 5, "default via 10.100.30.1 dev eth3")
checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET6, 13, "default via fd72:de0:adad::1 dev eth3") checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET6, 13, "default via fd72:de0:adad::1 dev eth3")
// Disconnect testnet3, so testnet4 should now provide the default gateway. // Disconnect testnet3, so testnet4 should now provide the default gateway.
err = apiClient.NetworkDisconnect(ctx, "testnet3", ctrID, true) _, err = apiClient.NetworkDisconnect(ctx, "testnet3", client.NetworkDisconnectOptions{Container: ctrID, Force: true})
assert.NilError(t, err) assert.NilError(t, err)
checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET, 4, "default via 10.100.40.1 dev eth4") checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET, 4, "default via 10.100.40.1 dev eth4")
checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET6, 10, "default via fd4c:c927:7d90::1 dev eth4") checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET6, 10, "default via fd4c:c927:7d90::1 dev eth4")
// Disconnect testnet4, so testnet1 should now provide the default gateway. // Disconnect testnet4, so testnet1 should now provide the default gateway.
err = apiClient.NetworkDisconnect(ctx, "testnet4", ctrID, true) _, err = apiClient.NetworkDisconnect(ctx, "testnet4", client.NetworkDisconnectOptions{Container: ctrID, Force: true})
assert.NilError(t, err) assert.NilError(t, err)
checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET, 3, "default via 10.100.10.1 dev eth0") checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET, 3, "default via 10.100.10.1 dev eth0")
checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET6, 7, "default via fddd:4901:f594::1 dev eth0") checkCtrRoutes(t, ctx, apiClient, ctrID, syscall.AF_INET6, 7, "default via fddd:4901:f594::1 dev eth0")
@@ -511,19 +523,22 @@ func TestMixL3IPVlanAndBridge(t *testing.T) {
checkCtrRoutes(t, ctx, c, ctrId, syscall.AF_INET6, 10, "default via fd6f:36f8:3005::1 dev bds") checkCtrRoutes(t, ctx, c, ctrId, syscall.AF_INET6, 10, "default via fd6f:36f8:3005::1 dev bds")
// Disconnect the dual-stack bridge network, expect the ipvlan's default route to be set up. // Disconnect the dual-stack bridge network, expect the ipvlan's default route to be set up.
c.NetworkDisconnect(ctx, br46NetName, ctrId, false) c.NetworkDisconnect(ctx, br46NetName, client.NetworkDisconnectOptions{Container: ctrId, Force: false})
checkCtrRoutes(t, ctx, c, ctrId, syscall.AF_INET, 2, "default dev eth") checkCtrRoutes(t, ctx, c, ctrId, syscall.AF_INET, 2, "default dev eth")
checkCtrRoutes(t, ctx, c, ctrId, syscall.AF_INET6, 7, "default dev eth") checkCtrRoutes(t, ctx, c, ctrId, syscall.AF_INET6, 7, "default dev eth")
// Disconnect the ipvlan, expect the IPv6-only network to be the gateway, with no IPv4 gateway. // Disconnect the ipvlan, expect the IPv6-only network to be the gateway, with no IPv4 gateway.
// (For this to work in the live-restore case the "dstName" of the interface must have been // (For this to work in the live-restore case the "dstName" of the interface must have been
// restored in the osSbox, based on matching the running interface's IPv6 address.) // restored in the osSbox, based on matching the running interface's IPv6 address.)
c.NetworkDisconnect(ctx, ipvNetName, ctrId, false) c.NetworkDisconnect(ctx, ipvNetName, client.NetworkDisconnectOptions{Container: ctrId, Force: false})
checkCtrRoutes(t, ctx, c, ctrId, syscall.AF_INET, 0, "") checkCtrRoutes(t, ctx, c, ctrId, syscall.AF_INET, 0, "")
checkCtrRoutes(t, ctx, c, ctrId, syscall.AF_INET6, 4, "default via fdc9:adaf:b5da::1 dev bss") checkCtrRoutes(t, ctx, c, ctrId, syscall.AF_INET6, 4, "default via fdc9:adaf:b5da::1 dev bss")
// Reconnect the dual-stack bridge, expect it to be the gateway for both addr families. // Reconnect the dual-stack bridge, expect it to be the gateway for both addr families.
c.NetworkConnect(ctx, br46NetName, ctrId, &networktypes.EndpointSettings{GwPriority: 1}) c.NetworkConnect(ctx, br46NetName, client.NetworkConnectOptions{
Container: ctrId,
EndpointConfig: &networktypes.EndpointSettings{GwPriority: 1},
})
checkCtrRoutes(t, ctx, c, ctrId, syscall.AF_INET, 2, "default via 192.168.123.1 dev bds") checkCtrRoutes(t, ctx, c, ctrId, syscall.AF_INET, 2, "default via 192.168.123.1 dev bds")
checkCtrRoutes(t, ctx, c, ctrId, syscall.AF_INET6, 7, "default via fd6f:36f8:3005::1 dev bds") checkCtrRoutes(t, ctx, c, ctrId, syscall.AF_INET6, 7, "default via fd6f:36f8:3005::1 dev bds")
}) })

View File

@@ -373,7 +373,7 @@ func TestServiceWithDataPathPortInit(t *testing.T) {
assert.NilError(t, err) assert.NilError(t, err)
poll.WaitOn(t, noServices(ctx, c), swarm.ServicePoll) poll.WaitOn(t, noServices(ctx, c), swarm.ServicePoll)
poll.WaitOn(t, swarm.NoTasks(ctx, c), swarm.ServicePoll) poll.WaitOn(t, swarm.NoTasks(ctx, c), swarm.ServicePoll)
err = c.NetworkRemove(ctx, overlayID) _, err = c.NetworkRemove(ctx, overlayID, client.NetworkRemoveOptions{})
assert.NilError(t, err) assert.NilError(t, err)
c.Close() c.Close()
err = d.SwarmLeave(ctx, t, true) err = d.SwarmLeave(ctx, t, true)
@@ -406,7 +406,7 @@ func TestServiceWithDataPathPortInit(t *testing.T) {
assert.NilError(t, err) assert.NilError(t, err)
poll.WaitOn(t, noServices(ctx, nc), swarm.ServicePoll) poll.WaitOn(t, noServices(ctx, nc), swarm.ServicePoll)
poll.WaitOn(t, swarm.NoTasks(ctx, nc), swarm.ServicePoll) poll.WaitOn(t, swarm.NoTasks(ctx, nc), swarm.ServicePoll)
err = nc.NetworkRemove(ctx, overlayID) _, err = nc.NetworkRemove(ctx, overlayID, client.NetworkRemoveOptions{})
assert.NilError(t, err) assert.NilError(t, err)
err = d.SwarmLeave(ctx, t, true) err = d.SwarmLeave(ctx, t, true)
assert.NilError(t, err) assert.NilError(t, err)
@@ -463,7 +463,7 @@ func TestServiceWithDefaultAddressPoolInit(t *testing.T) {
poll.WaitOn(t, noServices(ctx, cli), swarm.ServicePoll) poll.WaitOn(t, noServices(ctx, cli), swarm.ServicePoll)
poll.WaitOn(t, swarm.NoTasks(ctx, cli), swarm.ServicePoll) poll.WaitOn(t, swarm.NoTasks(ctx, cli), swarm.ServicePoll)
assert.NilError(t, err) assert.NilError(t, err)
err = cli.NetworkRemove(ctx, overlayID) _, err = cli.NetworkRemove(ctx, overlayID, client.NetworkRemoveOptions{})
assert.NilError(t, err) assert.NilError(t, err)
err = d.SwarmLeave(ctx, t, true) err = d.SwarmLeave(ctx, t, true)
assert.NilError(t, err) assert.NilError(t, err)
@@ -501,7 +501,7 @@ func TestCustomIfnameIsPreservedOnLiveRestore(t *testing.T) {
// On live-restore, the daemon rebuilds the list of interfaces for all // On live-restore, the daemon rebuilds the list of interfaces for all
// containers. Call NetworkDisconnect here to make sure that the right // containers. Call NetworkDisconnect here to make sure that the right
// dstName is used internally. // dstName is used internally.
err = apiClient.NetworkDisconnect(ctx, "bridge", ctrId, true) _, err = apiClient.NetworkDisconnect(ctx, "bridge", client.NetworkDisconnectOptions{Container: ctrId, Force: true})
assert.NilError(t, err) assert.NilError(t, err)
} }
@@ -525,9 +525,12 @@ func TestCustomIfnameCollidesWithExistingIface(t *testing.T) {
container.WithEndpointSettings("bridge", &networktypes.EndpointSettings{})) container.WithEndpointSettings("bridge", &networktypes.EndpointSettings{}))
defer container.Remove(ctx, t, apiClient, ctrId, client.ContainerRemoveOptions{Force: true}) defer container.Remove(ctx, t, apiClient, ctrId, client.ContainerRemoveOptions{Force: true})
err := apiClient.NetworkConnect(ctx, testnet, ctrId, &networktypes.EndpointSettings{DriverOpts: map[string]string{ _, err := apiClient.NetworkConnect(ctx, testnet, client.NetworkConnectOptions{
Container: ctrId,
EndpointConfig: &networktypes.EndpointSettings{DriverOpts: map[string]string{
netlabel.Ifname: "eth0", netlabel.Ifname: "eth0",
}}) }},
})
assert.ErrorContains(t, err, "error renaming interface") assert.ErrorContains(t, err, "error renaming interface")
assert.ErrorContains(t, err, "file exists") assert.ErrorContains(t, err, "file exists")
} }
@@ -573,18 +576,22 @@ func TestCustomIfnameWithMatchingDynamicPrefix(t *testing.T) {
checkIfaceAddr(t, ctx, apiClient, ctrId, "eth0", "inet 10.0.1.2/24") checkIfaceAddr(t, ctx, apiClient, ctrId, "eth0", "inet 10.0.1.2/24")
checkIfaceAddr(t, ctx, apiClient, ctrId, "eth1", "inet 10.0.0.2/24") checkIfaceAddr(t, ctx, apiClient, ctrId, "eth1", "inet 10.0.0.2/24")
err := apiClient.NetworkConnect(ctx, "testnet2", ctrId, nil) _, err := apiClient.NetworkConnect(ctx, "testnet2", client.NetworkConnectOptions{
Container: ctrId,
})
assert.NilError(t, err) assert.NilError(t, err)
checkIfaceAddr(t, ctx, apiClient, ctrId, "eth2", "inet 10.0.2.2/24") checkIfaceAddr(t, ctx, apiClient, ctrId, "eth2", "inet 10.0.2.2/24")
// Disconnect from testnet1 (ie. eth0), and testnet2 (ie. eth2) // Disconnect from testnet1 (ie. eth0), and testnet2 (ie. eth2)
err = apiClient.NetworkDisconnect(ctx, "testnet1", ctrId, false) _, err = apiClient.NetworkDisconnect(ctx, "testnet1", client.NetworkDisconnectOptions{Container: ctrId, Force: false})
assert.NilError(t, err) assert.NilError(t, err)
err = apiClient.NetworkDisconnect(ctx, "testnet2", ctrId, false) _, err = apiClient.NetworkDisconnect(ctx, "testnet2", client.NetworkDisconnectOptions{Container: ctrId, Force: false})
assert.NilError(t, err) assert.NilError(t, err)
// Reconnect to testnet2 -- it should now provide eth0. // Reconnect to testnet2 -- it should now provide eth0.
err = apiClient.NetworkConnect(ctx, "testnet2", ctrId, nil) _, err = apiClient.NetworkConnect(ctx, "testnet2", client.NetworkConnectOptions{
Container: ctrId,
})
assert.NilError(t, err) assert.NilError(t, err)
checkIfaceAddr(t, ctx, apiClient, ctrId, "eth0", "inet 10.0.2.2/24") checkIfaceAddr(t, ctx, apiClient, ctrId, "eth0", "inet 10.0.2.2/24")
} }

View File

@@ -1519,7 +1519,9 @@ func TestGatewaySelection(t *testing.T) {
// Connect the IPv6-only network. The IPv6 endpoint should become the // Connect the IPv6-only network. The IPv6 endpoint should become the
// gateway for IPv6, the IPv4 endpoint should be reconfigured as the // gateway for IPv6, the IPv4 endpoint should be reconfigured as the
// gateway for IPv4 only. // gateway for IPv4 only.
err := c.NetworkConnect(ctx, netId6, ctrId, nil) _, err := c.NetworkConnect(ctx, netId6, client.NetworkConnectOptions{
Container: ctrId,
})
assert.NilError(t, err) assert.NilError(t, err)
checkProxies(ctx, t, c, d.Pid(), []expProxyCfg{ checkProxies(ctx, t, c, d.Pid(), []expProxyCfg{
{"tcp", "0.0.0.0", "8080", ctrName, netName4, true, "80"}, {"tcp", "0.0.0.0", "8080", ctrName, netName4, true, "80"},
@@ -1528,7 +1530,7 @@ func TestGatewaySelection(t *testing.T) {
// Disconnect the IPv6-only network, the IPv4 should get back the mapping // Disconnect the IPv6-only network, the IPv4 should get back the mapping
// from host-IPv6. // from host-IPv6.
err = c.NetworkDisconnect(ctx, netId6, ctrId, false) _, err = c.NetworkDisconnect(ctx, netId6, client.NetworkDisconnectOptions{Container: ctrId, Force: false})
assert.NilError(t, err) assert.NilError(t, err)
checkProxies(ctx, t, c, d.Pid(), []expProxyCfg{ checkProxies(ctx, t, c, d.Pid(), []expProxyCfg{
{"tcp", "0.0.0.0", "8080", ctrName, netName4, true, "80"}, {"tcp", "0.0.0.0", "8080", ctrName, netName4, true, "80"},
@@ -1536,7 +1538,9 @@ func TestGatewaySelection(t *testing.T) {
}) })
// Connect the dual-stack network, it should become the gateway for v6 and v4. // Connect the dual-stack network, it should become the gateway for v6 and v4.
err = c.NetworkConnect(ctx, netId46, ctrId, nil) _, err = c.NetworkConnect(ctx, netId46, client.NetworkConnectOptions{
Container: ctrId,
})
assert.NilError(t, err) assert.NilError(t, err)
checkProxies(ctx, t, c, d.Pid(), []expProxyCfg{ checkProxies(ctx, t, c, d.Pid(), []expProxyCfg{
{"tcp", "0.0.0.0", "8080", ctrName, netName46, true, "80"}, {"tcp", "0.0.0.0", "8080", ctrName, netName46, true, "80"},
@@ -1544,7 +1548,7 @@ func TestGatewaySelection(t *testing.T) {
}) })
// Go back to the IPv4-only gateway, with proxy from host IPv6. // Go back to the IPv4-only gateway, with proxy from host IPv6.
err = c.NetworkDisconnect(ctx, netId46, ctrId, false) _, err = c.NetworkDisconnect(ctx, netId46, client.NetworkDisconnectOptions{Container: ctrId, Force: false})
assert.NilError(t, err) assert.NilError(t, err)
checkProxies(ctx, t, c, d.Pid(), []expProxyCfg{ checkProxies(ctx, t, c, d.Pid(), []expProxyCfg{
{"tcp", "0.0.0.0", "8080", ctrName, netName4, true, "80"}, {"tcp", "0.0.0.0", "8080", ctrName, netName4, true, "80"},
@@ -1553,7 +1557,9 @@ func TestGatewaySelection(t *testing.T) {
// Connect the IPv6-only ipvlan network, its new Endpoint should become the IPv6 // Connect the IPv6-only ipvlan network, its new Endpoint should become the IPv6
// gateway, so the IPv4-only bridge is expected to drop its mapping from host IPv6. // gateway, so the IPv4-only bridge is expected to drop its mapping from host IPv6.
err = c.NetworkConnect(ctx, netIdIpvlan6, ctrId, nil) _, err = c.NetworkConnect(ctx, netIdIpvlan6, client.NetworkConnectOptions{
Container: ctrId,
})
assert.NilError(t, err) assert.NilError(t, err)
checkProxies(ctx, t, c, d.Pid(), []expProxyCfg{ checkProxies(ctx, t, c, d.Pid(), []expProxyCfg{
{"tcp", "0.0.0.0", "8080", ctrName, netName4, true, "80"}, {"tcp", "0.0.0.0", "8080", ctrName, netName4, true, "80"},

View File

@@ -157,27 +157,31 @@ func TestEtcHostsDisconnect(t *testing.T) {
// Connect a second network (don't do this in the Run, because then the /etc/hosts // Connect a second network (don't do this in the Run, because then the /etc/hosts
// entries for the two networks can end up in either order). // entries for the two networks can end up in either order).
err = c.NetworkConnect(ctx, netName2, ctrName, nil) _, err = c.NetworkConnect(ctx, netName2, client.NetworkConnectOptions{
Container: ctrName,
})
assert.Check(t, err) assert.Check(t, err)
golden.Assert(t, getEtcHosts(), "TestEtcHostsDisconnect1.golden") golden.Assert(t, getEtcHosts(), "TestEtcHostsDisconnect1.golden")
// Disconnect net1, its hosts entries are currently before net2's. // Disconnect net1, its hosts entries are currently before net2's.
err = c.NetworkDisconnect(ctx, netName1, ctrName, false) _, err = c.NetworkDisconnect(ctx, netName1, client.NetworkDisconnectOptions{Container: ctrName, Force: false})
assert.Check(t, err) assert.Check(t, err)
golden.Assert(t, getEtcHosts(), "TestEtcHostsDisconnect2.golden") golden.Assert(t, getEtcHosts(), "TestEtcHostsDisconnect2.golden")
// Reconnect net1, so that its entries will follow net2's. // Reconnect net1, so that its entries will follow net2's.
err = c.NetworkConnect(ctx, netName1, ctrName, nil) _, err = c.NetworkConnect(ctx, netName1, client.NetworkConnectOptions{
Container: ctrName,
})
assert.Check(t, err) assert.Check(t, err)
golden.Assert(t, getEtcHosts(), "TestEtcHostsDisconnect3.golden") golden.Assert(t, getEtcHosts(), "TestEtcHostsDisconnect3.golden")
// Disconnect net1 again, removing its entries from the end of the file. // Disconnect net1 again, removing its entries from the end of the file.
err = c.NetworkDisconnect(ctx, netName1, ctrName, false) _, err = c.NetworkDisconnect(ctx, netName1, client.NetworkDisconnectOptions{Container: ctrName, Force: false})
assert.Check(t, err) assert.Check(t, err)
golden.Assert(t, getEtcHosts(), "TestEtcHostsDisconnect4.golden") golden.Assert(t, getEtcHosts(), "TestEtcHostsDisconnect4.golden")
// Disconnect net2, the only network. // Disconnect net2, the only network.
err = c.NetworkDisconnect(ctx, netName2, ctrName, false) _, err = c.NetworkDisconnect(ctx, netName2, client.NetworkDisconnectOptions{Container: ctrName, Force: false})
assert.Check(t, err) assert.Check(t, err)
golden.Assert(t, getEtcHosts(), "TestEtcHostsDisconnect5.golden") golden.Assert(t, getEtcHosts(), "TestEtcHostsDisconnect5.golden")
} }

View File

@@ -109,7 +109,9 @@ func TestInternalNetworkDNS(t *testing.T) {
// Connect the container to the internal network as well. // Connect the container to the internal network as well.
// External DNS should still be used. // External DNS should still be used.
err = c.NetworkConnect(ctx, intNetName, ctrId, nil) _, err = c.NetworkConnect(ctx, intNetName, client.NetworkConnectOptions{
Container: ctrId,
})
assert.NilError(t, err) assert.NilError(t, err)
res, err = container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"}) res, err = container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"})
assert.NilError(t, err) assert.NilError(t, err)
@@ -118,7 +120,7 @@ func TestInternalNetworkDNS(t *testing.T) {
// Disconnect from the external network. // Disconnect from the external network.
// Expect no access to the external DNS. // Expect no access to the external DNS.
err = c.NetworkDisconnect(ctx, extNetName, ctrId, true) _, err = c.NetworkDisconnect(ctx, extNetName, client.NetworkDisconnectOptions{Container: ctrId, Force: true})
assert.NilError(t, err) assert.NilError(t, err)
res, err = container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"}) res, err = container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"})
assert.NilError(t, err) assert.NilError(t, err)
@@ -127,7 +129,9 @@ func TestInternalNetworkDNS(t *testing.T) {
// Reconnect the external network. // Reconnect the external network.
// Check that the external DNS server is used again. // Check that the external DNS server is used again.
err = c.NetworkConnect(ctx, extNetName, ctrId, nil) _, err = c.NetworkConnect(ctx, extNetName, client.NetworkConnectOptions{
Container: ctrId,
})
assert.NilError(t, err) assert.NilError(t, err)
res, err = container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"}) res, err = container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"})
assert.NilError(t, err) assert.NilError(t, err)

View File

@@ -122,7 +122,7 @@ func TestCreateServiceMultipleTimes(t *testing.T) {
poll.WaitOn(t, swarm.NoTasksForService(ctx, apiClient, serviceID2), swarm.ServicePoll) poll.WaitOn(t, swarm.NoTasksForService(ctx, apiClient, serviceID2), swarm.ServicePoll)
for retry := 0; retry < 5; retry++ { for retry := 0; retry < 5; retry++ {
err = apiClient.NetworkRemove(ctx, overlayID) _, err = apiClient.NetworkRemove(ctx, overlayID, client.NetworkRemoveOptions{})
// TODO(dperny): using strings.Contains for error checking is awful, // TODO(dperny): using strings.Contains for error checking is awful,
// but so is the fact that swarm functions don't return errdefs errors. // but so is the fact that swarm functions don't return errdefs errors.
// I don't have time at this moment to fix the latter, so I guess I'll // I don't have time at this moment to fix the latter, so I guess I'll

View File

@@ -47,10 +47,13 @@ func TestDockerNetworkConnectAliasPreV144(t *testing.T) {
} }
}) })
err := apiClient.NetworkConnect(ctx, name, cID1, &network.EndpointSettings{ _, err := apiClient.NetworkConnect(ctx, name, client.NetworkConnectOptions{
Container: cID1,
EndpointConfig: &network.EndpointSettings{
Aliases: []string{ Aliases: []string{
"aaa", "aaa",
}, },
},
}) })
assert.NilError(t, err) assert.NilError(t, err)
@@ -70,10 +73,13 @@ func TestDockerNetworkConnectAliasPreV144(t *testing.T) {
} }
}) })
err = apiClient.NetworkConnect(ctx, name, cID2, &network.EndpointSettings{ _, err = apiClient.NetworkConnect(ctx, name, client.NetworkConnectOptions{
Container: cID2,
EndpointConfig: &network.EndpointSettings{
Aliases: []string{ Aliases: []string{
"bbb", "bbb",
}, },
},
}) })
assert.NilError(t, err) assert.NilError(t, err)
@@ -108,7 +114,10 @@ func TestDockerNetworkReConnect(t *testing.T) {
} }
}) })
err := apiClient.NetworkConnect(ctx, name, c1, &network.EndpointSettings{}) _, err := apiClient.NetworkConnect(ctx, name, client.NetworkConnectOptions{
Container: c1,
EndpointConfig: &network.EndpointSettings{},
})
assert.NilError(t, err) assert.NilError(t, err)
_, err = apiClient.ContainerStart(ctx, c1, client.ContainerStartOptions{}) _, err = apiClient.ContainerStart(ctx, c1, client.ContainerStartOptions{})
@@ -117,7 +126,10 @@ func TestDockerNetworkReConnect(t *testing.T) {
n1, err := apiClient.ContainerInspect(ctx, c1, client.ContainerInspectOptions{}) n1, err := apiClient.ContainerInspect(ctx, c1, client.ContainerInspectOptions{})
assert.NilError(t, err) assert.NilError(t, err)
err = apiClient.NetworkConnect(ctx, name, c1, &network.EndpointSettings{}) _, err = apiClient.NetworkConnect(ctx, name, client.NetworkConnectOptions{
Container: c1,
EndpointConfig: &network.EndpointSettings{},
})
assert.ErrorContains(t, err, "is already attached to network") assert.ErrorContains(t, err, "is already attached to network")
n2, err := apiClient.ContainerInspect(ctx, c1, client.ContainerInspectOptions{}) n2, err := apiClient.ContainerInspect(ctx, c1, client.ContainerInspectOptions{})

View File

@@ -275,7 +275,7 @@ func TestServiceUpdateNetwork(t *testing.T) {
assert.NilError(t, err) assert.NilError(t, err)
assert.Assert(t, len(netInfo.Network.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) _, err = apiClient.NetworkRemove(ctx, overlayID, client.NetworkRemoveOptions{})
assert.NilError(t, err) assert.NilError(t, err)
_, err = apiClient.ServiceRemove(ctx, serviceID, client.ServiceRemoveOptions{}) _, err = apiClient.ServiceRemove(ctx, serviceID, client.ServiceRemoveOptions{})

View File

@@ -157,7 +157,7 @@ func deleteAllNetworks(ctx context.Context, t testing.TB, c client.NetworkAPICli
// nat is a pre-defined network on Windows and cannot be removed // nat is a pre-defined network on Windows and cannot be removed
continue continue
} }
err := c.NetworkRemove(ctx, nw.ID) _, err := c.NetworkRemove(ctx, nw.ID, client.NetworkRemoveOptions{})
assert.Check(t, err, "failed to remove network %s", nw.ID) assert.Check(t, err, "failed to remove network %s", nw.ID)
} }
} }

View File

@@ -117,12 +117,12 @@ type ImageAPIClient interface {
// NetworkAPIClient defines API client methods for the networks // NetworkAPIClient defines API client methods for the networks
type NetworkAPIClient interface { type NetworkAPIClient interface {
NetworkConnect(ctx context.Context, network, container string, config *network.EndpointSettings) error NetworkConnect(ctx context.Context, network string, options NetworkConnectOptions) (NetworkConnectResult, error)
NetworkCreate(ctx context.Context, name string, options NetworkCreateOptions) (network.CreateResponse, error) NetworkCreate(ctx context.Context, name string, options NetworkCreateOptions) (network.CreateResponse, error)
NetworkDisconnect(ctx context.Context, network, container string, force bool) error NetworkDisconnect(ctx context.Context, network string, options NetworkDisconnectOptions) (NetworkDisconnectResult, error)
NetworkInspect(ctx context.Context, network string, options NetworkInspectOptions) (NetworkInspectResult, error) NetworkInspect(ctx context.Context, network string, options NetworkInspectOptions) (NetworkInspectResult, error)
NetworkList(ctx context.Context, options NetworkListOptions) (NetworkListResult, error) NetworkList(ctx context.Context, options NetworkListOptions) (NetworkListResult, error)
NetworkRemove(ctx context.Context, network string) error NetworkRemove(ctx context.Context, network string, options NetworkRemoveOptions) (NetworkRemoveResult, error)
NetworksPrune(ctx context.Context, opts NetworkPruneOptions) (NetworkPruneResult, error) NetworksPrune(ctx context.Context, opts NetworkPruneOptions) (NetworkPruneResult, error)
} }

View File

@@ -6,23 +6,35 @@ import (
"github.com/moby/moby/api/types/network" "github.com/moby/moby/api/types/network"
) )
// NetworkConnectOptions represents the data to be used to connect a container to the
// network.
type NetworkConnectOptions struct {
Container string
EndpointConfig *network.EndpointSettings
}
// NetworkConnectResult represents the result of a NetworkConnect operation.
type NetworkConnectResult struct {
// Currently empty; placeholder for future fields.
}
// NetworkConnect connects a container to an existent network in the docker host. // NetworkConnect connects a container to an existent network in the docker host.
func (cli *Client) NetworkConnect(ctx context.Context, networkID, containerID string, config *network.EndpointSettings) error { func (cli *Client) NetworkConnect(ctx context.Context, networkID string, options NetworkConnectOptions) (NetworkConnectResult, error) {
networkID, err := trimID("network", networkID) networkID, err := trimID("network", networkID)
if err != nil { if err != nil {
return err return NetworkConnectResult{}, err
} }
containerID, err = trimID("container", containerID) containerID, err := trimID("container", options.Container)
if err != nil { if err != nil {
return err return NetworkConnectResult{}, err
} }
req := network.ConnectRequest{ nc := network.ConnectRequest{
Container: containerID, Container: containerID,
EndpointConfig: config, EndpointConfig: options.EndpointConfig,
} }
resp, err := cli.post(ctx, "/networks/"+networkID+"/connect", nil, req, nil) resp, err := cli.post(ctx, "/networks/"+networkID+"/connect", nil, nc, nil)
defer ensureReaderClosed(resp) defer ensureReaderClosed(resp)
return err return NetworkConnectResult{}, err
} }

View File

@@ -1,10 +0,0 @@
package client
import "github.com/moby/moby/api/types/network"
// NetworkConnectOptions represents the data to be used to connect a container to the
// network.
type NetworkConnectOptions struct {
Container string
EndpointConfig *network.EndpointSettings `json:",omitempty"`
}

View File

@@ -6,23 +6,35 @@ import (
"github.com/moby/moby/api/types/network" "github.com/moby/moby/api/types/network"
) )
// NetworkDisconnectOptions represents the data to be used to disconnect a container
// from the network.
type NetworkDisconnectOptions struct {
Container string
Force bool
}
// NetworkDisconnectResult represents the result of a NetworkDisconnect operation.
type NetworkDisconnectResult struct {
// Currently empty; placeholder for future fields.
}
// NetworkDisconnect disconnects a container from an existent network in the docker host. // NetworkDisconnect disconnects a container from an existent network in the docker host.
func (cli *Client) NetworkDisconnect(ctx context.Context, networkID, containerID string, force bool) error { func (cli *Client) NetworkDisconnect(ctx context.Context, networkID string, options NetworkDisconnectOptions) (NetworkDisconnectResult, error) {
networkID, err := trimID("network", networkID) networkID, err := trimID("network", networkID)
if err != nil { if err != nil {
return err return NetworkDisconnectResult{}, err
} }
containerID, err = trimID("container", containerID) containerID, err := trimID("container", options.Container)
if err != nil { if err != nil {
return err return NetworkDisconnectResult{}, err
} }
req := network.DisconnectRequest{ req := network.DisconnectRequest{
Container: containerID, Container: containerID,
Force: force, Force: options.Force,
} }
resp, err := cli.post(ctx, "/networks/"+networkID+"/disconnect", nil, req, nil) resp, err := cli.post(ctx, "/networks/"+networkID+"/disconnect", nil, req, nil)
defer ensureReaderClosed(resp) defer ensureReaderClosed(resp)
return err return NetworkDisconnectResult{}, err
} }

View File

@@ -1,8 +0,0 @@
package client
// NetworkDisconnectOptions represents the data to be used to disconnect a container
// from the network.
type NetworkDisconnectOptions struct {
Container string
Force bool
}

View File

@@ -1,14 +1,26 @@
package client package client
import "context" import (
"context"
)
// NetworkRemoveOptions specifies options for removing a network.
type NetworkRemoveOptions struct {
// No options currently; placeholder for future use.
}
// NetworkRemoveResult represents the result of a network removal operation.
type NetworkRemoveResult struct {
// No fields currently; placeholder for future use.
}
// NetworkRemove removes an existent network from the docker host. // NetworkRemove removes an existent network from the docker host.
func (cli *Client) NetworkRemove(ctx context.Context, networkID string) error { func (cli *Client) NetworkRemove(ctx context.Context, networkID string, options NetworkRemoveOptions) (NetworkRemoveResult, error) {
networkID, err := trimID("network", networkID) networkID, err := trimID("network", networkID)
if err != nil { if err != nil {
return err return NetworkRemoveResult{}, err
} }
resp, err := cli.delete(ctx, "/networks/"+networkID, nil, nil) resp, err := cli.delete(ctx, "/networks/"+networkID, nil, nil)
defer ensureReaderClosed(resp) defer ensureReaderClosed(resp)
return err return NetworkRemoveResult{}, err
} }