Skip to content

Commit f827615

Browse files
authored
Merge pull request #53016 from ozangunalp/dev_services_network_id_fix
Move network creation from IntegrationTestUtil into the DevServicesProcessor build step
2 parents 49be4d1 + 0c0d56f commit f827615

File tree

4 files changed

+61
-75
lines changed

4 files changed

+61
-75
lines changed

core/deployment/src/main/java/io/quarkus/deployment/builditem/DevServicesNetworkIdBuildItem.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
/**
66
* The network id of the network that the dev services are running on.
7+
* This is intended to be consumed in the IntegrationTest launcher to ensure that the application is running on the same network
8+
* as the dev services.
9+
* <p>
10+
* In the future if extensions consume this build item, it would create the shared network if it doesn't exist,
11+
* and use it for the dev services and the test containers.
712
*/
813
public final class DevServicesNetworkIdBuildItem extends SimpleBuildItem {
914

extensions/devservices/deployment/src/main/java/io/quarkus/devservices/deployment/DevServicesProcessor.java

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import static io.quarkus.devservices.common.ConfigureUtil.shouldConfigureSharedServiceLabel;
1212
import static io.quarkus.devservices.deployment.IsRuntimeModuleAvailable.IO_QUARKUS_DEVSERVICES_CONFIG_BUILDER_CLASS;
1313

14-
import java.lang.reflect.Field;
14+
import java.lang.reflect.Method;
1515
import java.util.ArrayList;
1616
import java.util.Arrays;
1717
import java.util.Collections;
@@ -27,6 +27,8 @@
2727
import java.util.concurrent.SubmissionPublisher;
2828
import java.util.function.Supplier;
2929

30+
import org.eclipse.microprofile.config.ConfigProvider;
31+
import org.jboss.logging.Logger;
3032
import org.testcontainers.DockerClientFactory;
3133
import org.testcontainers.containers.GenericContainer;
3234
import org.testcontainers.containers.Network;
@@ -51,6 +53,7 @@
5153
import io.quarkus.deployment.builditem.DevServicesNetworkIdBuildItem;
5254
import io.quarkus.deployment.builditem.DevServicesRegistryBuildItem;
5355
import io.quarkus.deployment.builditem.DevServicesResultBuildItem;
56+
import io.quarkus.deployment.builditem.DevServicesSharedNetworkBuildItem;
5457
import io.quarkus.deployment.builditem.DockerStatusBuildItem;
5558
import io.quarkus.deployment.builditem.LaunchModeBuildItem;
5659
import io.quarkus.deployment.builditem.RunTimeConfigBuilderBuildItem;
@@ -72,6 +75,8 @@
7275

7376
public class DevServicesProcessor {
7477

78+
private static final Logger log = Logger.getLogger(DevServicesProcessor.class);
79+
7580
private static final String EXEC_FORMAT = "%s exec -it %s /bin/bash";
7681

7782
static volatile ConsoleStateManager.ConsoleContext context;
@@ -80,15 +85,47 @@ public class DevServicesProcessor {
8085

8186
@BuildStep
8287
public DevServicesNetworkIdBuildItem networkId(
83-
Optional<DevServicesLauncherConfigResultBuildItem> devServicesLauncherConfig,
88+
DevServicesConfig devServicesConfig,
89+
List<DevServicesSharedNetworkBuildItem> sharedNetworkBuildItems,
8490
Optional<DevServicesComposeProjectBuildItem> composeProjectBuildItem) {
85-
String networkId = composeProjectBuildItem
86-
.map(DevServicesComposeProjectBuildItem::getDefaultNetworkId)
87-
.or(() -> devServicesLauncherConfig.flatMap(ignored -> getSharedNetworkId()))
88-
.orElse(null);
91+
Optional<String> configuredNetwork = ConfigProvider.getConfig().getOptionalValue(
92+
"quarkus.test.container.network", String.class);
93+
String networkId = configuredNetwork.flatMap(this::getOrCreateNetworkId)
94+
.or(() -> composeProjectBuildItem.map(DevServicesComposeProjectBuildItem::getDefaultNetworkId))
95+
.orElseGet(() -> (devServicesConfig.launchOnSharedNetwork() || !sharedNetworkBuildItems.isEmpty())
96+
? getSharedNetworkId()
97+
: null);
8998
return new DevServicesNetworkIdBuildItem(networkId);
9099
}
91100

101+
private Optional<String> getOrCreateNetworkId(String name) {
102+
var networks = DockerClientFactory.lazyClient().listNetworksCmd().exec();
103+
for (var network : networks) {
104+
if (network.getName().equals(name)) {
105+
return Optional.of(network.getId());
106+
}
107+
}
108+
// if the network doesn't exist, create it
109+
try {
110+
// do the cleanup in a shutdown hook because there might be more services (launched via QuarkusTestResourceLifecycleManager) connected to the network
111+
String id = DockerClientFactory.lazyClient().createNetworkCmd().withName(name).exec().getId();
112+
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
113+
@Override
114+
public void run() {
115+
try {
116+
DockerClientFactory.lazyClient().removeNetworkCmd(id).exec();
117+
} catch (Exception e) {
118+
log.errorf("Unable to delete container network '%s'", id);
119+
}
120+
}
121+
}));
122+
return Optional.of(id);
123+
} catch (Exception e) {
124+
log.warnf(e, "Creating container network '%s' completed unsuccessfully", name);
125+
return Optional.empty();
126+
}
127+
}
128+
92129
@BuildStep(onlyIf = IsDevServicesSupportedByLaunchMode.class)
93130
@Produce(ServiceStartBuildItem.class)
94131
public DevServicesCustomizerBuildItem containerCustomizer(LaunchModeBuildItem launchModeBuildItem,
@@ -114,29 +151,27 @@ public DevServicesCustomizerBuildItem containerCustomizer(LaunchModeBuildItem la
114151
}
115152

116153
/**
117-
* Get the network id from the shared testcontainers network, without forcing the creation of the network.
154+
* Get the network id from the shared testcontainers network, Creates the SHARED Network instance if not already created
118155
*
119-
* @return the network id if available, empty otherwise
156+
* @return the network id if available, null otherwise
120157
*/
121-
private Optional<String> getSharedNetworkId() {
158+
private String getSharedNetworkId() {
122159
try {
123-
Field id;
160+
Method id;
124161
Object sharedNetwork;
125162
var tccl = Thread.currentThread().getContextClassLoader();
126163
if (tccl.getName().contains("Deployment")) {
127164
Class<?> networkClass = tccl.getParent().loadClass("org.testcontainers.containers.Network");
128165
sharedNetwork = networkClass.getField("SHARED").get(null);
129166
Class<?> networkImplClass = tccl.getParent().loadClass("org.testcontainers.containers.Network$NetworkImpl");
130-
id = networkImplClass.getDeclaredField("id");
167+
id = networkImplClass.getDeclaredMethod("getId");
131168
} else {
132169
sharedNetwork = Network.SHARED;
133-
id = Network.NetworkImpl.class.getDeclaredField("id");
170+
id = Network.NetworkImpl.class.getDeclaredMethod("getId");
134171
}
135-
id.setAccessible(true);
136-
String value = (String) id.get(sharedNetwork);
137-
return Optional.ofNullable(value);
172+
return (String) id.invoke(sharedNetwork);
138173
} catch (Exception e) {
139-
return Optional.empty();
174+
return null;
140175
}
141176
}
142177

test-framework/common/src/main/java/io/quarkus/test/common/ArtifactLauncher.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ interface DevServicesLaunchResult extends AutoCloseable {
4848

4949
String networkId();
5050

51+
@Deprecated
5152
boolean manageNetwork();
5253

5354
CuratedApplication getCuratedApplication();

test-framework/junit/src/main/java/io/quarkus/test/junit/IntegrationTestUtil.java

Lines changed: 4 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package io.quarkus.test.junit;
22

3-
import static io.quarkus.deployment.util.ContainerRuntimeUtil.detectContainerRuntime;
43
import static io.quarkus.runtime.configuration.QuarkusConfigBuilderCustomizer.QUARKUS_PROFILE;
54
import static io.quarkus.test.common.PathTestHelper.getAppClassLocationForTestLocation;
65
import static io.quarkus.test.common.PathTestHelper.getTestClassesLocation;
@@ -25,8 +24,6 @@
2524

2625
import jakarta.inject.Inject;
2726

28-
import org.apache.commons.lang3.RandomStringUtils;
29-
import org.eclipse.microprofile.config.ConfigProvider;
3027
import org.eclipse.microprofile.config.inject.ConfigProperty;
3128
import org.eclipse.microprofile.config.spi.ConfigSource;
3229
import org.jboss.jandex.Index;
@@ -46,7 +43,6 @@
4643
import io.quarkus.deployment.builditem.DevServicesLauncherConfigResultBuildItem;
4744
import io.quarkus.deployment.builditem.DevServicesNetworkIdBuildItem;
4845
import io.quarkus.deployment.builditem.DevServicesRegistryBuildItem;
49-
import io.quarkus.deployment.util.ContainerRuntimeUtil;
5046
import io.quarkus.paths.PathList;
5147
import io.quarkus.runtime.LaunchMode;
5248
import io.quarkus.runtime.logging.LoggingSetupRecorder;
@@ -58,7 +54,6 @@
5854
import io.quarkus.test.common.http.TestHTTPResourceManager;
5955
import io.quarkus.test.config.ValueRegistryInjector;
6056
import io.quarkus.value.registry.ValueRegistry;
61-
import io.smallrye.common.process.ProcessBuilder;
6257
import io.smallrye.config.SmallRyeConfig;
6358

6459
public final class IntegrationTestUtil {
@@ -235,7 +230,6 @@ public void accept(String configProfile) {
235230

236231
Map<String, String> propertyMap = new HashMap<>();
237232
AugmentAction augmentAction;
238-
String networkId = null;
239233
if (isDockerAppLaunch) {
240234
// when the application is going to be launched as a docker container, we need to make containers started by DevServices
241235
// use a shared network that the application container can then use as well
@@ -254,55 +248,8 @@ public void accept(String s, String s2) {
254248
}, DevServicesLauncherConfigResultBuildItem.class.getName(), DevServicesNetworkIdBuildItem.class.getName(),
255249
DevServicesRegistryBuildItem.class.getName(), DevServicesCustomizerBuildItem.class.getName());
256250

257-
networkId = propertyMap.get("quarkus.test.container.network");
258-
boolean manageNetwork = false;
259-
if (isDockerAppLaunch) {
260-
if (networkId == null) {
261-
// use the network the use has specified or else just generate one if none is configured
262-
Optional<String> networkIdOpt = ConfigProvider.getConfig().getOptionalValue(
263-
"quarkus.test.container.network", String.class);
264-
if (networkIdOpt.isPresent()) {
265-
networkId = networkIdOpt.get();
266-
} else {
267-
networkId = "quarkus-integration-test-" + RandomStringUtils.insecure().next(5, true, false);
268-
manageNetwork = true;
269-
}
270-
}
271-
}
272-
273-
DefaultDevServicesLaunchResult result = new DefaultDevServicesLaunchResult(propertyMap, networkId, manageNetwork,
274-
curatedApplication);
275-
createNetworkIfNecessary(result);
276-
return result;
277-
}
278-
279-
// this probably isn't the best place for this method, but we need to create the docker container before
280-
// user code is aware of the network
281-
private static void createNetworkIfNecessary(
282-
final ArtifactLauncher.InitContext.DevServicesLaunchResult devServicesLaunchResult) {
283-
if (devServicesLaunchResult.manageNetwork() && (devServicesLaunchResult.networkId() != null)) {
284-
ContainerRuntimeUtil.ContainerRuntime containerRuntime = detectContainerRuntime(true);
285-
286-
try {
287-
ProcessBuilder.exec(containerRuntime.getExecutableName(), "network", "create",
288-
devServicesLaunchResult.networkId());
289-
// do the cleanup in a shutdown hook because there might be more services (launched via QuarkusTestResourceLifecycleManager) connected to the network
290-
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
291-
@Override
292-
public void run() {
293-
try {
294-
ProcessBuilder.exec(containerRuntime.getExecutableName(), "network", "rm",
295-
devServicesLaunchResult.networkId());
296-
} catch (Exception e) {
297-
System.out.printf("Unable to delete container network '%s'", devServicesLaunchResult.networkId());
298-
}
299-
}
300-
}));
301-
} catch (Exception e) {
302-
throw new RuntimeException("Creating container network '%s' completed unsuccessfully"
303-
.formatted(devServicesLaunchResult.networkId()), e);
304-
}
305-
}
251+
String networkId = propertyMap.get("quarkus.test.container.network");
252+
return new DefaultDevServicesLaunchResult(propertyMap, networkId, curatedApplication);
306253
}
307254

308255
static void activateLogging() {
@@ -323,14 +270,12 @@ static void activateLogging() {
323270
static class DefaultDevServicesLaunchResult implements ArtifactLauncher.InitContext.DevServicesLaunchResult {
324271
private final Map<String, String> properties;
325272
private final String networkId;
326-
private final boolean manageNetwork;
327273
private final CuratedApplication curatedApplication;
328274

329275
DefaultDevServicesLaunchResult(Map<String, String> properties, String networkId,
330-
boolean manageNetwork, CuratedApplication curatedApplication) {
276+
CuratedApplication curatedApplication) {
331277
this.properties = properties;
332278
this.networkId = networkId;
333-
this.manageNetwork = manageNetwork;
334279
this.curatedApplication = curatedApplication;
335280
}
336281

@@ -344,7 +289,7 @@ public String networkId() {
344289

345290
@Override
346291
public boolean manageNetwork() {
347-
return manageNetwork;
292+
return false;
348293
}
349294

350295
@Override

0 commit comments

Comments
 (0)