Skip to content

Commit 74bbe72

Browse files
committed
Docker compose dev service
- Fix amqp username prop - Introduced DevServicesNetworkIdBuildItem to set the dev services network id to the startup action, Regular dev services not reuse the compose default network when available
1 parent e299fed commit 74bbe72

File tree

110 files changed

+5854
-688
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

110 files changed

+5854
-688
lines changed

core/deployment/src/main/java/io/quarkus/deployment/Feature.java

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public enum Feature {
1717
AWT,
1818
CACHE,
1919
CDI,
20+
COMPOSE,
2021
CONFIG_YAML,
2122
CONFLUENT_REGISTRY_AVRO,
2223
CONFLUENT_REGISTRY_JSON,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package io.quarkus.deployment.builditem;
2+
3+
import java.util.Arrays;
4+
import java.util.Collections;
5+
import java.util.List;
6+
import java.util.Map;
7+
import java.util.Objects;
8+
import java.util.Optional;
9+
import java.util.stream.Stream;
10+
11+
import io.quarkus.builder.item.SimpleBuildItem;
12+
import io.quarkus.deployment.dev.devservices.ContainerInfo;
13+
import io.quarkus.deployment.dev.devservices.ImageName;
14+
import io.quarkus.deployment.dev.devservices.RunningContainer;
15+
16+
/**
17+
* BuildItem for running services provided by compose
18+
*/
19+
public final class DevServicesComposeProjectBuildItem extends SimpleBuildItem {
20+
21+
public static final String COMPOSE_IGNORE = "io.quarkus.devservices.compose.ignore";
22+
23+
private final String project;
24+
25+
private final String defaultNetworkId;
26+
27+
private final Map<String, List<RunningContainer>> composeServices;
28+
29+
private final Map<String, String> config;
30+
31+
public DevServicesComposeProjectBuildItem() {
32+
this(null, null, Collections.emptyMap(), Collections.emptyMap());
33+
}
34+
35+
public DevServicesComposeProjectBuildItem(String project,
36+
String defaultNetworkId,
37+
Map<String, List<RunningContainer>> composeServices,
38+
Map<String, String> config) {
39+
this.project = project;
40+
this.defaultNetworkId = defaultNetworkId;
41+
this.composeServices = composeServices;
42+
this.config = config;
43+
}
44+
45+
public String getProject() {
46+
return project;
47+
}
48+
49+
public String getDefaultNetworkId() {
50+
return defaultNetworkId;
51+
}
52+
53+
public Map<String, String> getConfig() {
54+
return config;
55+
}
56+
57+
public Map<String, List<RunningContainer>> getComposeServices() {
58+
return composeServices;
59+
}
60+
61+
/**
62+
* Locate a running container by image partial and port
63+
* The container image partial can be a substring of the full image name
64+
*
65+
* @param imagePartials image partials
66+
* @param port exposed port
67+
* @return the running container or null if not found
68+
*/
69+
public Optional<RunningContainer> locate(List<String> imagePartials, int port) {
70+
return locateContainers(imagePartials)
71+
.filter(r -> Optional.ofNullable(r.containerInfo().exposedPorts())
72+
.map(ports -> Arrays.stream(ports)
73+
.anyMatch(p -> Objects.equals(p.privatePort(), port)))
74+
.isPresent())
75+
.findFirst();
76+
}
77+
78+
/**
79+
* Locate a running container by image partial
80+
* The container image partial can be a substring of the full image name
81+
* Ignored services are not returned
82+
*
83+
* @param imagePartials image partials
84+
* @return the list of running containers
85+
*/
86+
public List<RunningContainer> locate(List<String> imagePartials) {
87+
return locateContainers(imagePartials).toList();
88+
}
89+
90+
/**
91+
* Locate the first running container by image partial
92+
* The container image partial can be a substring of the full image name
93+
* Ignored services are not returned
94+
*
95+
* @param imagePartials image partials
96+
* @return the first running container
97+
*/
98+
public Optional<RunningContainer> locateFirst(List<String> imagePartials) {
99+
return locateContainers(imagePartials).findFirst();
100+
}
101+
102+
private Stream<RunningContainer> locateContainers(List<String> imagePartials) {
103+
return imagePartials.stream()
104+
.flatMap(imagePartial -> composeServices.values().stream().flatMap(List::stream)
105+
// Ignore service if contains ignore label
106+
.filter(c -> !isContainerIgnored(c.containerInfo()))
107+
.filter(runningContainer -> {
108+
String imageName = runningContainer.containerInfo().imageName();
109+
return imageName.contains(imagePartial)
110+
|| ImageName.parse(imageName).withLibraryPrefix().toString().contains(imagePartial);
111+
}));
112+
}
113+
114+
/**
115+
* Ignored services are not returned by locate
116+
*
117+
* @param containerInfo container info
118+
* @return true if the container should be ignored
119+
*/
120+
public static boolean isContainerIgnored(ContainerInfo containerInfo) {
121+
return Boolean.parseBoolean(containerInfo.labels().get(COMPOSE_IGNORE));
122+
}
123+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package io.quarkus.deployment.builditem;
2+
3+
import io.quarkus.builder.item.SimpleBuildItem;
4+
5+
/**
6+
* The network id of the network that the dev services are running on.
7+
*/
8+
public final class DevServicesNetworkIdBuildItem extends SimpleBuildItem {
9+
10+
private final String networkId;
11+
12+
public DevServicesNetworkIdBuildItem(String networkId) {
13+
this.networkId = networkId;
14+
}
15+
16+
public String getNetworkId() {
17+
return networkId;
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package io.quarkus.deployment.dev.devservices;
2+
3+
import io.quarkus.runtime.annotations.ConfigDocSection;
4+
import io.quarkus.runtime.annotations.ConfigPhase;
5+
import io.quarkus.runtime.annotations.ConfigRoot;
6+
import io.smallrye.config.ConfigMapping;
7+
8+
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
9+
@ConfigMapping(prefix = "quarkus.compose")
10+
public interface ComposeBuildTimeConfig {
11+
12+
/**
13+
* Compose dev services config
14+
*/
15+
@ConfigDocSection(generated = true)
16+
ComposeDevServicesBuildTimeConfig devservices();
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package io.quarkus.deployment.dev.devservices;
2+
3+
import java.time.Duration;
4+
import java.util.List;
5+
import java.util.Map;
6+
import java.util.Optional;
7+
8+
import io.quarkus.runtime.annotations.ConfigGroup;
9+
import io.smallrye.config.WithDefault;
10+
11+
@ConfigGroup
12+
public interface ComposeDevServicesBuildTimeConfig {
13+
14+
/**
15+
* Compose dev service enabled or disabled
16+
*/
17+
@WithDefault("true")
18+
boolean enabled();
19+
20+
/**
21+
* List of file paths relative to the project root for Compose dev service configuration,
22+
* if not provided will look for compose files in the project root
23+
*/
24+
Optional<List<String>> files();
25+
26+
/**
27+
* Name of the compose project, used to discover running containers,
28+
* if not provided a project name will be generated
29+
*/
30+
Optional<String> projectName();
31+
32+
/**
33+
* Compose profiles to activate
34+
*/
35+
Optional<List<String>> profiles();
36+
37+
/**
38+
* List of additional options to pass to compose command
39+
*/
40+
Optional<List<String>> options();
41+
42+
/**
43+
* Whether to run compose up and start containers at startup, when disabled, services are discovered by project name
44+
*/
45+
@WithDefault("true")
46+
boolean startServices();
47+
48+
/**
49+
* Whether to run compose down and stop containers at shutdown
50+
*/
51+
@WithDefault("true")
52+
boolean stopServices();
53+
54+
/**
55+
* Whether to use test containers Ryuk resource reaper to clean up containers
56+
*/
57+
@WithDefault("true")
58+
boolean ryukEnabled();
59+
60+
/**
61+
* Whether to remove volumes on compose down
62+
*/
63+
@WithDefault("true")
64+
boolean removeVolumes();
65+
66+
/**
67+
* Which images to remove on compose down
68+
* <p>
69+
* Locally built images, without custom tags are removed by default.
70+
*/
71+
Optional<RemoveImages> removeImages();
72+
73+
/**
74+
* --rmi option for compose down
75+
*/
76+
enum RemoveImages {
77+
ALL,
78+
LOCAL
79+
}
80+
81+
/**
82+
* Env variables to pass to all Compose instances
83+
*/
84+
Map<String, String> envVariables();
85+
86+
/**
87+
* Scale configuration for services: Configure the number of instances for specific services
88+
*/
89+
Map<String, Integer> scale();
90+
91+
/**
92+
* Whether to tail container logs to the console
93+
*/
94+
@WithDefault("false")
95+
boolean followContainerLogs();
96+
97+
/**
98+
* Whether to build images before starting containers.
99+
* <p>
100+
* When not provided, Compose images are built per-service `pull-policy`.
101+
* When `true`, forces build of all images before starting containers.
102+
* When `false`, skips re-building images before starting containers.
103+
*/
104+
Optional<Boolean> build();
105+
106+
/**
107+
* Whether to reuse the project for tests, when disabled, a new project is created for each test run
108+
*/
109+
@WithDefault("false")
110+
boolean reuseProjectForTests();
111+
112+
/**
113+
* Timeout for stopping services, after the timeout the services are forcefully stopped,
114+
*
115+
*/
116+
@WithDefault("1s")
117+
Duration stopTimeout();
118+
}

0 commit comments

Comments
 (0)