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
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)
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)
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)
}

View File

@@ -6,23 +6,35 @@ 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
}
// 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.
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)
if err != nil {
return err
return NetworkConnectResult{}, err
}
containerID, err = trimID("container", containerID)
containerID, err := trimID("container", options.Container)
if err != nil {
return err
return NetworkConnectResult{}, err
}
req := network.ConnectRequest{
nc := network.ConnectRequest{
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)
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")))
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))
// 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.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.ErrorContains(err, "value is empty"))
}
@@ -55,7 +59,9 @@ func TestNetworkConnectEmptyNilEndpointSettings(t *testing.T) {
}))
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)
}
@@ -67,7 +73,7 @@ func TestNetworkConnect(t *testing.T) {
return nil, err
}
var connect NetworkConnectOptions
var connect network.ConnectRequest
if err := json.NewDecoder(req.Body).Decode(&connect); err != nil {
return nil, err
}
@@ -88,8 +94,11 @@ func TestNetworkConnect(t *testing.T) {
}))
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",
},
})
assert.NilError(t, err)
}

View File

@@ -6,23 +6,35 @@ import (
"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.
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)
if err != nil {
return err
return NetworkDisconnectResult{}, err
}
containerID, err = trimID("container", containerID)
containerID, err := trimID("container", options.Container)
if err != nil {
return err
return NetworkDisconnectResult{}, err
}
req := network.DisconnectRequest{
Container: containerID,
Force: force,
Force: options.Force,
}
resp, err := cli.post(ctx, "/networks/"+networkID+"/disconnect", nil, req, nil)
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")))
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))
// 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.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.ErrorContains(err, "value is empty"))
}
@@ -55,6 +59,6 @@ func TestNetworkDisconnect(t *testing.T) {
}))
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)
}

View File

@@ -1,14 +1,26 @@
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.
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)
if err != nil {
return err
return NetworkRemoveResult{}, err
}
resp, err := cli.delete(ctx, "/networks/"+networkID, nil, nil)
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")))
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))
err = client.NetworkRemove(context.Background(), "")
_, err = client.NetworkRemove(context.Background(), "", NetworkRemoveOptions{})
assert.Check(t, is.ErrorType(err, cerrdefs.IsInvalidArgument))
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.ErrorContains(err, "value is empty"))
}
@@ -37,6 +37,6 @@ func TestNetworkRemove(t *testing.T) {
}))
assert.NilError(t, err)
err = client.NetworkRemove(context.Background(), "network_id")
_, err = client.NetworkRemove(context.Background(), "network_id", NetworkRemoveOptions{})
assert.NilError(t, err)
}

View File

@@ -2,16 +2,16 @@ package networkbackend
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.
type ConnectOptions struct {
type ConnectRequest struct {
Container string
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.
type DisconnectOptions struct {
type DisconnectRequest struct {
Container string
Force bool
}

View File

@@ -287,7 +287,7 @@ func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseW
return err
}
var connect networkbackend.ConnectOptions
var connect networkbackend.ConnectRequest
if err := httputils.ReadJSON(r, &connect); err != nil {
return err
}
@@ -304,7 +304,7 @@ func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.Respon
return err
}
var disconnect networkbackend.DisconnectOptions
var disconnect networkbackend.DisconnectRequest
if err := httputils.ReadJSON(r, &disconnect); err != nil {
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) {
t.Helper()
err := apiClient.NetworkRemove(ctx, name)
_, err := apiClient.NetworkRemove(ctx, name, client.NetworkRemoveOptions{})
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{
cidrv4: {
@@ -1210,7 +1210,7 @@ func TestBridgeIPAMStatus(t *testing.T) {
Subnet: cidr,
}),
)
defer c.NetworkRemove(ctx, netName)
defer c.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
checkSubnets(netName, map[netip.Prefix]networktypes.SubnetStatus{
cidr: {
@@ -1255,7 +1255,9 @@ func TestJoinError(t *testing.T) {
assert.Equal(t, res.ExitCode, 0)
// 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"))
// Only intNet should show up in container inspect.
@@ -1279,7 +1281,9 @@ func TestJoinError(t *testing.T) {
assert.Equal(t, res.ExitCode, 0)
// 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)
ctrInsp = ctr.Inspect(ctx, t, c, cid)
assert.Check(t, is.Len(ctrInsp.NetworkSettings.Networks, 2))

View File

@@ -4,6 +4,7 @@ import (
"errors"
"testing"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/daemon/libnetwork/drivers/bridge"
"github.com/moby/moby/v2/daemon/libnetwork/nlwrap"
"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.Restart(t)
err := c.NetworkRemove(ctx, netName)
_, err := c.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
assert.NilError(t, err)
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))
// 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.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.
// 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)
// Delete the network using networkID. This should remove the original
// 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)
// 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)
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"))
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
// creating a new vxlan link with the same VNI.
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)
}()

View File

@@ -12,7 +12,7 @@ import (
"github.com/google/go-cmp/cmp/cmpopts"
"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/integration/internal/container"
net "github.com/moby/moby/v2/integration/internal/network"
@@ -62,7 +62,7 @@ func TestDockerNetworkIpvlan(t *testing.T) {
for _, tc := range []struct {
name string
test func(*testing.T, context.Context, dclient.APIClient)
test func(*testing.T, context.Context, client.APIClient)
}{
{
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"
n.CreateMasterDummy(ctx, t, master)
defer n.DeleteInterface(ctx, t, master)
netName := "di-subinterface"
net.CreateNoError(ctx, t, client, netName,
net.CreateNoError(ctx, t, apiClient, netName,
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
err := client.NetworkRemove(ctx, netName)
_, err := apiClient.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
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
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
master := "di-dummy0"
parent := master + ".30"
@@ -153,99 +153,99 @@ func testIpvlanOverlapParent(t *testing.T, ctx context.Context, client dclient.A
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
netName := "di-nil-parent"
net.CreateNoError(ctx, t, client, netName,
net.CreateNoError(ctx, t, apiClient, netName,
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))
id2 := container.Run(ctx, t, client, container.WithNetworkMode(netName))
id1 := container.Run(ctx, t, apiClient, 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)
}
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"
net.CreateNoError(ctx, t, client, netName,
net.CreateNoError(ctx, t, apiClient, netName,
net.WithIPvlan("", ""),
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))
id2 := container.Run(ctx, t, client, container.WithNetworkMode(netName))
id1 := container.Run(ctx, t, apiClient, 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"))
_, 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)
}
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"
net.CreateNoError(ctx, t, client, netName,
net.CreateNoError(ctx, t, apiClient, netName,
net.WithIPvlan("", "l3"),
net.WithIPAM("172.28.230.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.WithIPv4(netName, "172.28.220.10"),
)
id2 := container.Run(ctx, t, client,
id2 := container.Run(ctx, t, apiClient,
container.WithNetworkMode(netName),
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)
}
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"
net.CreateNoError(ctx, t, client, netName,
net.CreateNoError(ctx, t, apiClient, netName,
net.WithIPvlan("", "l3"),
net.WithInternal(),
net.WithIPAM("172.28.230.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.WithIPv4(netName, "172.28.220.10"),
)
id2 := container.Run(ctx, t, client,
id2 := container.Run(ctx, t, apiClient,
container.WithNetworkMode(netName),
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"))
_, 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)
}
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"
n.CreateMasterDummy(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) {
testIpvlanL2MultiSubnet(t, ctx, client, "")
func testIpvlanL2MultiSubnetNoParent(t *testing.T, ctx context.Context, apiClient client.APIClient) {
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"
net.CreateNoError(ctx, t, apiClient, netName,
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.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)
// Inspect the v4 gateway to ensure no default GW was assigned
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.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)
if parent == "" {
// 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)
}
func testIpvlanL3MultiSubnet(t *testing.T, ctx context.Context, client dclient.APIClient) {
func testIpvlanL3MultiSubnet(t *testing.T, ctx context.Context, apiClient client.APIClient) {
netName := "dualstackl3"
net.CreateNoError(ctx, t, client, netName,
net.CreateNoError(ctx, t, apiClient, netName,
net.WithIPvlan("", "l3"),
net.WithIPv6(),
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: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
id1 := container.Run(ctx, t, client,
id1 := container.Run(ctx, t, apiClient,
container.WithNetworkMode(netName),
container.WithIPv4(netName, "172.28.10.20"),
container.WithIPv6(netName, "2001:db8:abc9::20"),
)
id2 := container.Run(ctx, t, client,
id2 := container.Run(ctx, t, apiClient,
container.WithNetworkMode(netName),
container.WithIPv4(netName, "172.28.10.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)
// 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)
// 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)
// 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.WithIPv4(netName, "172.28.12.20"),
container.WithIPv6(netName, "2001:db8:abc7::20"),
)
id4 := container.Run(ctx, t, client,
id4 := container.Run(ctx, t, apiClient,
container.WithNetworkMode(netName),
container.WithIPv4(netName, "172.28.12.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)
// 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)
// 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)
// 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
// 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"
n.CreateMasterDummy(ctx, t, parentIfName)
defer n.DeleteInterface(ctx, t, parentIfName)
netNameL2 := "dualstackl2"
net.CreateNoError(ctx, t, client, netNameL2,
net.CreateNoError(ctx, t, apiClient, netNameL2,
net.WithIPvlan(parentIfName, "l2"),
net.WithIPv6(),
net.WithIPAM("172.28.140.0/24", "172.28.140.254"),
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),
)
// 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.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.
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.Check(t, !strings.Contains(result.Combined(), "default via"),
"result: %s", result.Combined())
}
// 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"
n.CreateMasterDummy(ctx, t, parentIfName)
defer n.DeleteInterface(ctx, t, parentIfName)
netNameL3 := "dualstackl3"
net.CreateNoError(ctx, t, client, netNameL3,
net.CreateNoError(ctx, t, apiClient, netNameL3,
net.WithIPvlan(parentIfName, "l3"),
net.WithIPv6(),
net.WithIPAM("172.28.160.0/24", "172.28.160.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),
)
// 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.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
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.Check(t, is.Contains(result.Combined(), "default dev eth0"))
}
@@ -488,9 +488,9 @@ func TestIpvlanIPAM(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.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.WithIPv4(tc.enableIPv4),
net.WithIPAMConfig(
@@ -509,11 +509,11 @@ func TestIpvlanIPAM(t *testing.T) {
const netName = "ipvlannet"
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))
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"})
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))
cc := d.NewClientT(t, dclient.WithVersion("1.52"))
res, err := cc.NetworkInspect(ctx, netName, dclient.NetworkInspectOptions{})
cc := d.NewClientT(t, client.WithVersion("1.52"))
res, err := cc.NetworkInspect(ctx, netName, client.NetworkInspectOptions{})
if assert.Check(t, err) && assert.Check(t, res.Network.Status != nil) {
assert.Check(t, is.DeepEqual(wantSubnetStatus, res.Network.Status.IPAM.Subnets, cmpopts.EquateEmpty()))
}
cc.Close()
cc = d.NewClientT(t, dclient.WithVersion("1.51"))
res, err = cc.NetworkInspect(ctx, netName, dclient.NetworkInspectOptions{})
cc = d.NewClientT(t, client.WithVersion("1.51"))
res, err = cc.NetworkInspect(ctx, netName, client.NetworkInspectOptions{})
assert.Check(t, err)
assert.Check(t, res.Network.Status == nil)
cc.Close()
@@ -585,7 +585,7 @@ func TestIpvlanIPAMOverlap(t *testing.T) {
checkNetworkIPAMState := func(networkID string, want map[netip.Prefix]network.SubnetStatus) bool {
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) {
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))
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))
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))
checkNetworkIPAMState(netName3, map[netip.Prefix]network.SubnetStatus{
@@ -695,7 +695,7 @@ func TestIpvlanIPAMOverlap(t *testing.T) {
// Create a container on one of the networks
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.
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)
t.Run(name, func(t *testing.T) {
ctx := testutil.StartSpan(ctx, t)
createOpts := []func(*dclient.NetworkCreateOptions){
createOpts := []func(*client.NetworkCreateOptions){
net.WithIPvlan(tc.parent, mode),
}
if tc.internal {
createOpts = append(createOpts, net.WithInternal())
}
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))
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"})
assert.NilError(t, err)
if tc.expDNS {
@@ -864,7 +864,7 @@ func TestPointToPoint(t *testing.T) {
container.WithNetworkMode(netName),
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)
defer cancel()
@@ -872,7 +872,7 @@ func TestPointToPoint(t *testing.T) {
container.WithCmd([]string{"ping", "-c1", "-W3", ctrName}...),
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.Stderr.Len(), 0))
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",
},
}))
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)
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
// as long as neither are passthru
master := "dm-dummy0"
@@ -119,35 +119,35 @@ func testMacvlanOverlapParent(t *testing.T, ctx context.Context, client client.A
netName := "dm-subinterface"
parentName := "dm-dummy0.40"
net.CreateNoError(ctx, t, client, netName,
net.CreateNoError(ctx, t, apiClient, netName,
net.WithMacvlan(parentName),
)
assert.Check(t, n.IsNetworkAvailable(ctx, client, netName))
assert.Check(t, n.IsNetworkAvailable(ctx, apiClient, netName))
n.LinkExists(ctx, t, parentName)
overlapNetName := "dm-parent-net-overlap"
_, err := net.Create(ctx, client, overlapNetName,
_, err := net.Create(ctx, apiClient, overlapNetName,
net.WithMacvlan(parentName),
)
assert.Check(t, err)
// 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.Check(t, n.IsNetworkNotAvailable(ctx, client, overlapNetName))
assert.Check(t, n.IsNetworkNotAvailable(ctx, apiClient, overlapNetName))
n.LinkExists(ctx, t, parentName)
// delete the first network
err = client.NetworkRemove(ctx, netName)
_, err = apiClient.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
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)
// verify the network delete did not delete the root link
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
master := "dm-dummy0"
n.CreateMasterDummy(ctx, t, master)
@@ -155,26 +155,26 @@ func testMacvlanOverlapParentPassthruFirst(t *testing.T, ctx context.Context, cl
netName := "dm-subinterface"
parentName := "dm-dummy0.40"
net.CreateNoError(ctx, t, client, netName,
net.CreateNoError(ctx, t, apiClient, netName,
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),
)
assert.Check(t, err != nil)
// 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.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
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
master := "dm-dummy0"
n.CreateMasterDummy(ctx, t, master)
@@ -182,26 +182,26 @@ func testMacvlanOverlapParentPassthruSecond(t *testing.T, ctx context.Context, c
netName := "dm-subinterface"
parentName := "dm-dummy0.40"
net.CreateNoError(ctx, t, client, netName,
net.CreateNoError(ctx, t, apiClient, netName,
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),
)
assert.Check(t, err != nil)
// 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.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
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
master := "dm-dummy0"
n.CreateMasterDummy(ctx, t, master)
@@ -209,34 +209,34 @@ func testMacvlanOverlapDeleteCreatedSecond(t *testing.T, ctx context.Context, cl
netName := "dm-subinterface"
parentName := "dm-dummy0.40"
net.CreateNoError(ctx, t, client, netName,
net.CreateNoError(ctx, t, apiClient, netName,
net.WithMacvlan(parentName),
)
assert.Check(t, n.IsNetworkAvailable(ctx, client, netName))
assert.Check(t, n.IsNetworkAvailable(ctx, apiClient, netName))
overlapNetName := "dm-parent-net-overlap"
_, err := net.Create(ctx, client, overlapNetName,
_, err := net.Create(ctx, apiClient, overlapNetName,
net.WithMacvlan(parentName),
)
assert.Check(t, err)
// 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.Check(t, n.IsNetworkNotAvailable(ctx, client, netName))
assert.Check(t, n.IsNetworkNotAvailable(ctx, apiClient, netName))
n.LinkExists(ctx, t, parentName)
// delete the second network
err = client.NetworkRemove(ctx, overlapNetName)
_, err = apiClient.NetworkRemove(ctx, overlapNetName, client.NetworkRemoveOptions{})
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)
// verify the network delete did not delete the root link
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
// parent
master := "dm-dummy0"
@@ -244,27 +244,27 @@ func testMacvlanOverlapKeepExisting(t *testing.T, ctx context.Context, client cl
defer n.DeleteInterface(ctx, t, master)
netName := "dm-subinterface"
net.CreateNoError(ctx, t, client, netName,
net.CreateNoError(ctx, t, apiClient, netName,
net.WithMacvlan(master),
)
assert.Check(t, n.IsNetworkAvailable(ctx, client, netName))
assert.Check(t, n.IsNetworkAvailable(ctx, apiClient, netName))
overlapNetName := "dm-parent-net-overlap"
_, err := net.Create(ctx, client, overlapNetName,
_, err := net.Create(ctx, apiClient, overlapNetName,
net.WithMacvlan(master),
)
assert.Check(t, err)
err = client.NetworkRemove(ctx, overlapNetName)
_, err = apiClient.NetworkRemove(ctx, overlapNetName, client.NetworkRemoveOptions{})
assert.NilError(t, err)
err = client.NetworkRemove(ctx, netName)
_, err = apiClient.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
assert.NilError(t, err)
// verify the network delete did not delete the root link
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
master := "dm-dummy0"
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")
netName := "dm-subinterface"
net.CreateNoError(ctx, t, client, netName,
net.CreateNoError(ctx, t, apiClient, netName,
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
err := client.NetworkRemove(ctx, netName)
_, err := apiClient.NetworkRemove(ctx, netName, client.NetworkRemoveOptions{})
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
n.LinkExists(ctx, t, parentName)
}
@@ -512,7 +512,7 @@ func TestMacvlanIPAM(t *testing.T) {
const netName = "macvlannet"
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))
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))
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))
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))
checkNetworkIPAMState(netName3, map[netip.Prefix]network.SubnetStatus{
@@ -795,7 +795,7 @@ func TestMACVlanDNS(t *testing.T) {
createOpts = append(createOpts, net.WithInternal())
}
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))
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),
}
})
defer c.NetworkRemove(ctx, "from-net")
defer c.NetworkRemove(ctx, "from-net", client.NetworkRemoveOptions{})
}
// 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
// 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")
// 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)
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")
// 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)
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")
// 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)
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")
// testnet4 has the same priority as testnet3, but it sorts after in
// 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)
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")
@@ -352,19 +364,19 @@ func TestConnectWithPriority(t *testing.T) {
// Disconnect testnet2, so testnet3 should now provide the default gateway.
// When two endpoints have the same priority (eg. testnet3 vs testnet4),
// 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)
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")
// 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)
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")
// 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)
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")
@@ -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")
// 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_INET6, 7, "default dev eth")
// 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
// 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_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.
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_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)
poll.WaitOn(t, noServices(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)
c.Close()
err = d.SwarmLeave(ctx, t, true)
@@ -406,7 +406,7 @@ func TestServiceWithDataPathPortInit(t *testing.T) {
assert.NilError(t, err)
poll.WaitOn(t, noServices(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)
err = d.SwarmLeave(ctx, t, true)
assert.NilError(t, err)
@@ -463,7 +463,7 @@ func TestServiceWithDefaultAddressPoolInit(t *testing.T) {
poll.WaitOn(t, noServices(ctx, cli), swarm.ServicePoll)
poll.WaitOn(t, swarm.NoTasks(ctx, cli), swarm.ServicePoll)
assert.NilError(t, err)
err = cli.NetworkRemove(ctx, overlayID)
_, err = cli.NetworkRemove(ctx, overlayID, client.NetworkRemoveOptions{})
assert.NilError(t, err)
err = d.SwarmLeave(ctx, t, true)
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
// containers. Call NetworkDisconnect here to make sure that the right
// 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)
}
@@ -525,9 +525,12 @@ func TestCustomIfnameCollidesWithExistingIface(t *testing.T) {
container.WithEndpointSettings("bridge", &networktypes.EndpointSettings{}))
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",
}})
}},
})
assert.ErrorContains(t, err, "error renaming interface")
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, "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)
checkIfaceAddr(t, ctx, apiClient, ctrId, "eth2", "inet 10.0.2.2/24")
// 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)
err = apiClient.NetworkDisconnect(ctx, "testnet2", ctrId, false)
_, err = apiClient.NetworkDisconnect(ctx, "testnet2", client.NetworkDisconnectOptions{Container: ctrId, Force: false})
assert.NilError(t, err)
// 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)
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
// gateway for IPv6, the IPv4 endpoint should be reconfigured as the
// gateway for IPv4 only.
err := c.NetworkConnect(ctx, netId6, ctrId, nil)
_, err := c.NetworkConnect(ctx, netId6, client.NetworkConnectOptions{
Container: ctrId,
})
assert.NilError(t, err)
checkProxies(ctx, t, c, d.Pid(), []expProxyCfg{
{"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
// 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)
checkProxies(ctx, t, c, d.Pid(), []expProxyCfg{
{"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.
err = c.NetworkConnect(ctx, netId46, ctrId, nil)
_, err = c.NetworkConnect(ctx, netId46, client.NetworkConnectOptions{
Container: ctrId,
})
assert.NilError(t, err)
checkProxies(ctx, t, c, d.Pid(), []expProxyCfg{
{"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.
err = c.NetworkDisconnect(ctx, netId46, ctrId, false)
_, err = c.NetworkDisconnect(ctx, netId46, client.NetworkDisconnectOptions{Container: ctrId, Force: false})
assert.NilError(t, err)
checkProxies(ctx, t, c, d.Pid(), []expProxyCfg{
{"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
// 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)
checkProxies(ctx, t, c, d.Pid(), []expProxyCfg{
{"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
// 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)
golden.Assert(t, getEtcHosts(), "TestEtcHostsDisconnect1.golden")
// 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)
golden.Assert(t, getEtcHosts(), "TestEtcHostsDisconnect2.golden")
// 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)
golden.Assert(t, getEtcHosts(), "TestEtcHostsDisconnect3.golden")
// 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)
golden.Assert(t, getEtcHosts(), "TestEtcHostsDisconnect4.golden")
// 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)
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.
// 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)
res, err = container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"})
assert.NilError(t, err)
@@ -118,7 +120,7 @@ func TestInternalNetworkDNS(t *testing.T) {
// Disconnect from the external network.
// 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)
res, err = container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"})
assert.NilError(t, err)
@@ -127,7 +129,9 @@ func TestInternalNetworkDNS(t *testing.T) {
// Reconnect the external network.
// 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)
res, err = container.Exec(ctx, c, ctrId, []string{"nslookup", "test.example"})
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)
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,
// 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

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{
"aaa",
},
},
})
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{
"bbb",
},
},
})
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)
_, err = apiClient.ContainerStart(ctx, c1, client.ContainerStartOptions{})
@@ -117,7 +126,10 @@ func TestDockerNetworkReConnect(t *testing.T) {
n1, err := apiClient.ContainerInspect(ctx, c1, client.ContainerInspectOptions{})
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")
n2, err := apiClient.ContainerInspect(ctx, c1, client.ContainerInspectOptions{})

View File

@@ -275,7 +275,7 @@ func TestServiceUpdateNetwork(t *testing.T) {
assert.NilError(t, err)
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)
_, 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
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)
}
}

View File

@@ -117,12 +117,12 @@ type ImageAPIClient interface {
// NetworkAPIClient defines API client methods for the networks
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)
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)
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)
}

View File

@@ -6,23 +6,35 @@ 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
}
// 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.
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)
if err != nil {
return err
return NetworkConnectResult{}, err
}
containerID, err = trimID("container", containerID)
containerID, err := trimID("container", options.Container)
if err != nil {
return err
return NetworkConnectResult{}, err
}
req := network.ConnectRequest{
nc := network.ConnectRequest{
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)
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"
)
// 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.
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)
if err != nil {
return err
return NetworkDisconnectResult{}, err
}
containerID, err = trimID("container", containerID)
containerID, err := trimID("container", options.Container)
if err != nil {
return err
return NetworkDisconnectResult{}, err
}
req := network.DisconnectRequest{
Container: containerID,
Force: force,
Force: options.Force,
}
resp, err := cli.post(ctx, "/networks/"+networkID+"/disconnect", nil, req, nil)
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
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.
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)
if err != nil {
return err
return NetworkRemoveResult{}, err
}
resp, err := cli.delete(ctx, "/networks/"+networkID, nil, nil)
defer ensureReaderClosed(resp)
return err
return NetworkRemoveResult{}, err
}