testcontainers / testcontainers/testcontainers-java

RemoveNetwork.close() never throws exception and keeps a network running causing Status 409: {"message":"network with name bdd49174-d251-4503-b1c2-d05c57206967 already exists"}

Open
#3,518 0 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Java
Stars
8.7k
Forks
1.9k
Avg merge
2d 17h
Merged PRs (30d)
9

Description

Hi,
first let me take this to thank you for the framework, it is super helpful to write docker based tests.

I found this issue in the latest version regarding how the network is closed, please if I'm not using properly the framework let me know 😄

In my setup I have 2 containers running with one network I created. The test manages the network, so no RYUK used here. After tests have run, I'm cleaning the resources i.e. containers and network and calling Network.close() for each container I shut down to let the network know the container left it.

But I get this error when I call Network.getId() after shutting down the second container to clean up the network:
`
com.github.dockerjava.api.exception.ConflictException: Status 409: {"message":"network with name bdd49174-d251-4503-b1c2-d05c57206967 already exists"}

at org.testcontainers.shaded.com.github.dockerjava.core.DefaultInvocationBuilder.execute(DefaultInvocationBuilder.java:245)
at org.testcontainers.shaded.com.github.dockerjava.core.DefaultInvocationBuilder.post(DefaultInvocationBuilder.java:125)
at org.testcontainers.shaded.com.github.dockerjava.core.exec.CreateNetworkCmdExec.execute(CreateNetworkCmdExec.java:27)
at org.testcontainers.shaded.com.github.dockerjava.core.exec.CreateNetworkCmdExec.execute(CreateNetworkCmdExec.java:12)
at org.testcontainers.shaded.com.github.dockerjava.core.exec.AbstrSyncDockerCmdExec.exec(AbstrSyncDockerCmdExec.java:21)
at org.testcontainers.shaded.com.github.dockerjava.core.command.AbstrDockerCmd.exec(AbstrDockerCmd.java:35)
at org.testcontainers.containers.Network$NetworkImpl.create(Network.java:92)
at org.testcontainers.containers.Network$NetworkImpl.getId(Network.java:63)

`

Here is why this error happens from what I found out.
When I shut down the first container, I then call Network.getId() to get the Network ID for logging and managing network IDs. This method does not only return an ID, but in fact it creates a network if the network does not exist.

https://github.com/testcontainers/testcontainers-java/blob/c381a64a6623fe71e95cfb73173907246a21e685/core/src/main/java/org/testcontainers/containers/Network.java#L63

public synchronized String getId() {
if (initialized.compareAndSet(false, true)) {
id = create();
}
return id;
}

The name getId() is misleading, as it means return an ID for this network and does not suggest a docker network ... command will in fact be invoked if the network does not exist, and that it will create a network.
Then I call Network.close(), which does this:

if (initialized.getAndSet(false)) { ResourceReaper.instance().removeNetworkById(id); }
Initialized is set to false, then the network is removed, but here is what happens in the removeNetworkById(...)
It calls removeNetwork(String id), which then fails silently if the network cannot be closed. In my scenario it cannot be closed as there is the second container still using it:

https://github.com/testcontainers/testcontainers-java/blob/c381a64a6623fe71e95cfb73173907246a21e685/core/src/main/java/org/testcontainers/utility/ResourceReaper.java#L353

} catch (Exception e) { LOGGER.trace("Error encountered removing network (name: {}) - it may not have been removed", network.getName()); }

The problem is that the network is now not initialized but still exists as it was not closed.

When I shut down the second container, then I call Network.getId() to log and manage the network ID, this method will run this:

https://github.com/testcontainers/testcontainers-java/blob/c381a64a6623fe71e95cfb73173907246a21e685/core/src/main/java/org/testcontainers/containers/Network.java#L61

`
if (initialized.compareAndSet(false, true)) {
id = create();
}

        return id;

`

But because this network is not initialized anymore but still exists as the tests tried to close it, create() is called on an existing network and fail to do so rightfully with this error:
network with name bdd49174-d251-4503-b1c2-d05c57206967 already exists

And the tests fail.

I think the getId() should really just return the ID and a Network.create() method is needed that just does that, and the ResourceReaper.removeNetwork() should throw exceptions and not ignore them so one can deal with it as one needs to.
Add a test in the NetworkTest class that try to close a network which is still in use and ask for its ID through the getId() to trigger this issue.

The NetworkTest class did not catch this as it closes a Network that does not have containers attached to it.
https://github.com/testcontainers/testcontainers-java/blob/c381a64a6623fe71e95cfb73173907246a21e685/core/src/test/java/org/testcontainers/containers/NetworkTest.java#L100

lmk if I can help in reviewing or else.
Best,
Johnny

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with Network.java and ResourceReaper.java, especially Network.getId(), Network.close(), and removeNetworkById(), then inspect the existing case in NetworkTest around line 100. Reproduce the sequence with a network still attached to a container and verify that requesting its ID after cleanup does not trigger the reported conflict; add a regression test for the corrected lifecycle behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, java
Domain
testing
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.