78479b1915
Fixes #18864, #20648, #33561, #40901. [This GH comment][1] makes clear network name uniqueness has never been enforced due to the eventually consistent nature of Classic Swarm datastores: > there is no guaranteed way to check for duplicates across a cluster of > docker hosts. And this is further confirmed by other comments made by @mrjana in that same issue, eg. [this one][2]: > we want to adopt a schema which can pave the way in the future for a > completely decentralized cluster of docker hosts (if scalability is > needed). This decentralized model is what Classic Swarm was trying to be. It's been superseded since then by Docker Swarm, which has a centralized control plane. To circumvent this drawback, the `NetworkCreate` endpoint accepts a `CheckDuplicate` flag. However it's not perfectly reliable as it won't catch concurrent requests. Due to this design decision, API clients like Compose have to implement workarounds to make sure names are really unique (eg. docker/compose#9585). And the daemon itself has seen a string of issues due to that decision, including some that aren't fixed to this day (for instance moby/moby#40901): > The problem is, that if you specify a network for a container using > the ID, it will add that network to the container but it will then > change it to reference the network by using the name. To summarize, this "feature" is broken, has no practical use and is a source of pain for Docker users and API consumers. So let's just remove it for _all_ API versions. [1]: https://github.com/moby/moby/issues/18864#issuecomment-167201414 [2]: https://github.com/moby/moby/issues/18864#issuecomment-167202589 Signed-off-by: Albin Kerouanton <albinker@gmail.com>
89 lines
3.6 KiB
Go
89 lines
3.6 KiB
Go
package network // import "github.com/docker/docker/integration/network"
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/docker/docker/api/types"
|
|
"github.com/docker/docker/api/types/versions"
|
|
dclient "github.com/docker/docker/client"
|
|
"github.com/docker/docker/integration/internal/network"
|
|
"gotest.tools/v3/assert"
|
|
is "gotest.tools/v3/assert/cmp"
|
|
"gotest.tools/v3/skip"
|
|
)
|
|
|
|
func containsNetwork(nws []types.NetworkResource, networkID string) bool {
|
|
for _, n := range nws {
|
|
if n.ID == networkID {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// createAmbiguousNetworks creates three networks, of which the second network
|
|
// uses a prefix of the first network's ID as name. The third network uses the
|
|
// first network's ID as name.
|
|
//
|
|
// After successful creation, properties of all three networks is returned
|
|
func createAmbiguousNetworks(ctx context.Context, t *testing.T, client dclient.APIClient) (string, string, string) {
|
|
testNet := network.CreateNoError(ctx, t, client, "testNet")
|
|
idPrefixNet := network.CreateNoError(ctx, t, client, testNet[:12])
|
|
fullIDNet := network.CreateNoError(ctx, t, client, testNet)
|
|
|
|
nws, err := client.NetworkList(ctx, types.NetworkListOptions{})
|
|
assert.NilError(t, err)
|
|
|
|
assert.Check(t, is.Equal(true, containsNetwork(nws, testNet)), "failed to create network testNet")
|
|
assert.Check(t, is.Equal(true, containsNetwork(nws, idPrefixNet)), "failed to create network idPrefixNet")
|
|
assert.Check(t, is.Equal(true, containsNetwork(nws, fullIDNet)), "failed to create network fullIDNet")
|
|
return testNet, idPrefixNet, fullIDNet
|
|
}
|
|
|
|
// TestNetworkCreateDelete tests creation and deletion of a network.
|
|
func TestNetworkCreateDelete(t *testing.T) {
|
|
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
|
|
ctx := setupTest(t)
|
|
client := testEnv.APIClient()
|
|
|
|
netName := "testnetwork_" + t.Name()
|
|
network.CreateNoError(ctx, t, client, netName)
|
|
assert.Check(t, IsNetworkAvailable(ctx, client, netName))
|
|
|
|
// delete the network and make sure it is deleted
|
|
err := client.NetworkRemove(ctx, netName)
|
|
assert.NilError(t, err)
|
|
assert.Check(t, IsNetworkNotAvailable(ctx, client, netName))
|
|
}
|
|
|
|
// TestDockerNetworkDeletePreferID tests that if a network with a name
|
|
// equal to another network's ID exists, the Network with the given
|
|
// ID is removed, and not the network with the given name.
|
|
func TestDockerNetworkDeletePreferID(t *testing.T) {
|
|
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.34"), "broken in earlier versions")
|
|
skip.If(t, testEnv.DaemonInfo.OSType == "windows",
|
|
"FIXME. Windows doesn't run DinD and uses networks shared between control daemon and daemon under test")
|
|
|
|
ctx := setupTest(t)
|
|
client := testEnv.APIClient()
|
|
|
|
testNet, idPrefixNet, fullIDNet := createAmbiguousNetworks(ctx, t, client)
|
|
|
|
// 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 := client.NetworkRemove(ctx, testNet[:12])
|
|
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 = client.NetworkRemove(ctx, testNet)
|
|
assert.NilError(t, err)
|
|
|
|
// networks "testNet" and "idPrefixNet" should be removed, but "fullIDNet" should still exist
|
|
nws, err := client.NetworkList(ctx, types.NetworkListOptions{})
|
|
assert.NilError(t, err)
|
|
assert.Check(t, is.Equal(false, containsNetwork(nws, testNet)), "Network testNet not removed")
|
|
assert.Check(t, is.Equal(false, containsNetwork(nws, idPrefixNet)), "Network idPrefixNet not removed")
|
|
assert.Check(t, is.Equal(true, containsNetwork(nws, fullIDNet)), "Network fullIDNet not found")
|
|
}
|