Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build-parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
<elasticsearch.protocol>http</elasticsearch.protocol>
<opensearch-server.version>3.1.0</opensearch-server.version>
<opensearch.image>docker.io/opensearchproject/opensearch:${opensearch-server.version}</opensearch.image>
<opensearch-dashboards.image>docker.io/opensearchproject/opensearch-dashboards:${opensearch-server.version}</opensearch-dashboards.image>
<opensearch.protocol>http</opensearch.protocol>
<junit-pioneer.version>2.2.0</junit-pioneer.version>

Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package io.quarkus.elasticsearch.restclient.common.deployment;

import static io.quarkus.devservices.common.ContainerLocator.locateContainerWithLabels;
import static io.quarkus.elasticsearch.restclient.common.deployment.DevservicesElasticsearchProcessorUtils.DEV_SERVICE_ELASTICSEARCH;
import static io.quarkus.elasticsearch.restclient.common.deployment.DevservicesElasticsearchProcessorUtils.DEV_SERVICE_LABEL;
import static io.quarkus.elasticsearch.restclient.common.deployment.DevservicesElasticsearchProcessorUtils.DEV_SERVICE_OPENSEARCH;
import static io.quarkus.elasticsearch.restclient.common.deployment.DevservicesElasticsearchProcessorUtils.ELASTICSEARCH_PORT;
import static io.quarkus.elasticsearch.restclient.common.deployment.DevservicesElasticsearchProcessorUtils.NEW_DEV_SERVICE_LABEL;
import static io.quarkus.elasticsearch.restclient.common.deployment.DevservicesElasticsearchProcessorUtils.buildPropertiesMap;
import static io.quarkus.elasticsearch.restclient.common.deployment.DevservicesElasticsearchProcessorUtils.getElasticsearchHosts;
import static io.quarkus.elasticsearch.restclient.common.deployment.DevservicesElasticsearchProcessorUtils.resolveDistribution;

import java.time.Duration;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
Expand All @@ -22,6 +25,7 @@
import io.quarkus.builder.BuildException;
import io.quarkus.deployment.Feature;
import io.quarkus.deployment.IsDevServicesSupportedByLaunchMode;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.annotations.BuildSteps;
import io.quarkus.deployment.builditem.CuratedApplicationShutdownBuildItem;
Expand Down Expand Up @@ -52,22 +56,11 @@
public class DevServicesElasticsearchProcessor {
private static final Logger log = Logger.getLogger(DevServicesElasticsearchProcessor.class);

/**
* Label to add to shared Dev Service for Elasticsearch running in containers.
* This allows other applications to discover the running service and use it instead of starting a new instance.
*/
static final String DEV_SERVICE_LABEL = "quarkus-dev-service-elasticsearch";
static final String NEW_DEV_SERVICE_LABEL = "io.quarkus.devservice.elasticsearch";
static final int ELASTICSEARCH_PORT = 9200;

private static final ContainerLocator elasticsearchContainerLocator = locateContainerWithLabels(ELASTICSEARCH_PORT,
DEV_SERVICE_LABEL, NEW_DEV_SERVICE_LABEL);

private static final Distribution DEFAULT_DISTRIBUTION = Distribution.ELASTIC;
private static final String DEV_SERVICE_ELASTICSEARCH = "elasticsearch";
private static final String DEV_SERVICE_OPENSEARCH = "opensearch";

static volatile RunningDevService devService;

static volatile ElasticsearchCommonBuildTimeConfig cfg;
static volatile boolean first = true;

Expand All @@ -82,6 +75,7 @@ public DevServicesResultBuildItem startElasticsearchDevService(
CuratedApplicationShutdownBuildItem closeBuildItem,
LoggingSetupBuildItem loggingSetupBuildItem,
DevServicesConfig devServicesConfig,
BuildProducer<DevservicesElasticsearchConnectionBuildItem> connectionBuildItemProducer,
List<DevservicesElasticsearchBuildItem> devservicesElasticsearchBuildItems) throws BuildException {

if (devservicesElasticsearchBuildItems.isEmpty()) {
Expand All @@ -108,7 +102,9 @@ public DevServicesResultBuildItem startElasticsearchDevService(
boolean useSharedNetwork = DevServicesSharedNetworkBuildItem.isSharedNetworkRequired(devServicesConfig,
devServicesSharedNetworkBuildItem);
devService = startElasticsearchDevServices(dockerStatusBuildItem, composeProjectBuildItem,
configuration.devservices(), buildItemsConfig, launchMode, useSharedNetwork, devServicesConfig.timeout());
configuration.devservices(), buildItemsConfig, connectionBuildItemProducer, launchMode, useSharedNetwork,
devServicesConfig.timeout());

if (devService == null) {
compressor.closeAndDumpCaptured();
} else {
Expand Down Expand Up @@ -143,16 +139,11 @@ public DevServicesResultBuildItem startElasticsearchDevService(
"Dev Services for Elasticsearch started. Other Quarkus applications in dev mode will find the "
+ "server automatically. For Quarkus applications in production mode, you can connect to"
+ " this by configuring your application to use %s",
getElasticsearchHosts(buildItemsConfig));
getElasticsearchHosts(buildItemsConfig, devService));
}
return devService.toBuildItem();
}

public static String getElasticsearchHosts(DevservicesElasticsearchBuildItemsConfiguration buildItemsConfiguration) {
String hostsConfigProperty = buildItemsConfiguration.hostsConfigProperties.stream().findAny().get();
return devService.getConfig().get(hostsConfigProperty);
}

private void shutdownElasticsearch() {
if (devService != null) {
try {
Expand All @@ -170,6 +161,7 @@ private RunningDevService startElasticsearchDevServices(
DevServicesComposeProjectBuildItem composeProjectBuildItem,
ElasticsearchDevServicesBuildTimeConfig config,
DevservicesElasticsearchBuildItemsConfiguration buildItemConfig,
BuildProducer<DevservicesElasticsearchConnectionBuildItem> connectionBuildItemProducer,
LaunchModeBuildItem launchMode, boolean useSharedNetwork, Optional<Duration> timeout) throws BuildException {
if (!config.enabled().orElse(true)) {
// explicitly disabled
Expand Down Expand Up @@ -220,15 +212,14 @@ private RunningDevService startElasticsearchDevServices(
container.setPortBindings(List.of(config.port().get() + ":" + ELASTICSEARCH_PORT));
}
timeout.ifPresent(container::withStartupTimeout);

container.withEnv(config.containerEnv());

container.withReuse(config.reuse());

container.start();

var httpHost = createdContainer.hostName + ":"
+ (useSharedNetwork ? ELASTICSEARCH_PORT : container.getMappedPort(ELASTICSEARCH_PORT));
connectionBuildItemProducer.produce(new DevservicesElasticsearchConnectionBuildItem(createdContainer.hostName,
container.getMappedPort(ELASTICSEARCH_PORT)));
return new RunningDevService(Feature.ELASTICSEARCH_REST_CLIENT_COMMON.getName(),
container.getContainerId(),
new ContainerShutdownCloseable(container, "Elasticsearch"),
Expand All @@ -253,6 +244,9 @@ private CreatedContainer createElasticsearchContainer(ElasticsearchDevServicesBu

// Disable security as else we would need to configure it correctly to avoid tons of WARNING in the log
container.addEnv("xpack.security.enabled", "false");
// disable enrollment token to allow Kibana in a non-interactive automated way
container.addEnv("xpack.security.enrollment.enabled", "false");
container.addEnv("discovery.type", "single-node");
// Disable disk-based shard allocation thresholds:
// in a single-node setup they just don't make sense,
// and lead to problems on large disks with little space left.
Expand All @@ -265,7 +259,7 @@ private CreatedContainer createElasticsearchContainer(ElasticsearchDevServicesBu

private CreatedContainer createOpensearchContainer(ElasticsearchDevServicesBuildTimeConfig config,
DockerImageName resolvedImageName, String defaultNetworkId, boolean useSharedNetwork) {
OpensearchContainer container = new OpensearchContainer(
OpensearchContainer<?> container = new OpensearchContainer<>(
resolvedImageName.asCompatibleSubstituteFor("opensearchproject/opensearch"));
String hostName = ConfigureUtil.configureNetwork(container, defaultNetworkId, useSharedNetwork, DEV_SERVICE_OPENSEARCH);

Expand Down Expand Up @@ -296,83 +290,7 @@ private DockerImageName resolveImageName(ElasticsearchDevServicesBuildTimeConfig
: DEV_SERVICE_OPENSEARCH)));
}

private Distribution resolveDistribution(ElasticsearchDevServicesBuildTimeConfig config,
DevservicesElasticsearchBuildItemsConfiguration buildItemConfig) throws BuildException {
// First, let's see if it was explicitly configured:
if (config.distribution().isPresent()) {
return config.distribution().get();
}
// Now let's see if we can guess it from the image:
if (config.imageName().isPresent()) {
String imageNameRepository = DockerImageName.parse(config.imageName().get()).getRepository()
.toLowerCase(Locale.ROOT);
if (imageNameRepository.contains(DEV_SERVICE_OPENSEARCH)) {
return Distribution.OPENSEARCH;
}
if (imageNameRepository.contains(DEV_SERVICE_ELASTICSEARCH)) {
return Distribution.ELASTIC;
}
// no luck guessing so let's ask user to be more explicit:
throw new BuildException(
"Wasn't able to determine the distribution of the search service based on the provided image name ["
+ config.imageName().get()
+ "]. Please specify the distribution explicitly.",
Collections.emptyList());
}
// Otherwise, let's see if the build item has a value available:
if (buildItemConfig.distribution != null) {
return buildItemConfig.distribution;
}
// If we didn't get an explicit distribution
// and no image name was provided
// then elastic is a default distribution:
return DEFAULT_DISTRIBUTION;
}

private Map<String, String> buildPropertiesMap(DevservicesElasticsearchBuildItemsConfiguration buildItemConfig,
String httpHosts) {
Map<String, String> propertiesToSet = new HashMap<>();
for (String property : buildItemConfig.hostsConfigProperties) {
propertiesToSet.put(property, httpHosts);
}
return propertiesToSet;
}

private String displayProperties(Set<String> hostsConfigProperties) {
return String.join(" and ", hostsConfigProperties);
}

private static class DevservicesElasticsearchBuildItemsConfiguration {
private Set<String> hostsConfigProperties;
private String version;
private Distribution distribution;

private DevservicesElasticsearchBuildItemsConfiguration(List<DevservicesElasticsearchBuildItem> buildItems)
throws BuildException {
hostsConfigProperties = new HashSet<>(buildItems.size());

// check that all build items agree on the version and distribution to start
for (DevservicesElasticsearchBuildItem buildItem : buildItems) {
if (version == null) {
version = buildItem.getVersion();
} else if (buildItem.getVersion() != null && !version.equals(buildItem.getVersion())) {
// safety guard but should never occur as only Hibernate Search ORM Elasticsearch configure the version
throw new BuildException(
"Multiple extensions request different versions of Elasticsearch for Dev Services.",
Collections.emptyList());
}

if (distribution == null) {
distribution = buildItem.getDistribution();
} else if (buildItem.getDistribution() != null && !distribution.equals(buildItem.getDistribution())) {
// safety guard but should never occur as only Hibernate Search ORM Elasticsearch configure the distribution
throw new BuildException(
"Multiple extensions request different distributions of Elasticsearch for Dev Services.",
Collections.emptyList());
}

hostsConfigProperties.add(buildItem.getHostsConfigProperty());
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package io.quarkus.elasticsearch.restclient.common.deployment;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import io.quarkus.builder.BuildException;
import io.quarkus.elasticsearch.restclient.common.deployment.ElasticsearchCommonBuildTimeConfig.ElasticsearchDevServicesBuildTimeConfig.Distribution;

class DevservicesElasticsearchBuildItemsConfiguration {
Set<String> hostsConfigProperties;
String version;
Distribution distribution;

DevservicesElasticsearchBuildItemsConfiguration(List<DevservicesElasticsearchBuildItem> buildItems)
throws BuildException {
hostsConfigProperties = new HashSet<>(buildItems.size());

// check that all build items agree on the version and distribution to start
for (DevservicesElasticsearchBuildItem buildItem : buildItems) {
if (version == null) {
version = buildItem.getVersion();
} else if (buildItem.getVersion() != null && !version.equals(buildItem.getVersion())) {
// safety guard but should never occur as only Hibernate Search ORM Elasticsearch configure the version
throw new BuildException(
"Multiple extensions request different versions of Elasticsearch for Dev Services.",
Collections.emptyList());
}

if (distribution == null) {
distribution = buildItem.getDistribution();
} else if (buildItem.getDistribution() != null && !distribution.equals(buildItem.getDistribution())) {
// safety guard but should never occur as only Hibernate Search ORM Elasticsearch configure the distribution
throw new BuildException(
"Multiple extensions request different distributions of Elasticsearch for Dev Services.",
Collections.emptyList());
}

hostsConfigProperties.add(buildItem.getHostsConfigProperty());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.quarkus.elasticsearch.restclient.common.deployment;

import io.quarkus.builder.item.MultiBuildItem;

public final class DevservicesElasticsearchConnectionBuildItem extends MultiBuildItem {
private final String host;
private final int port;

public DevservicesElasticsearchConnectionBuildItem(String host, int port) {
this.host = host;
this.port = port;
}

public String getHost() {
return host;
}

public int getPort() {
return port;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package io.quarkus.elasticsearch.restclient.common.deployment;

import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import org.testcontainers.utility.DockerImageName;

import io.quarkus.builder.BuildException;
import io.quarkus.deployment.builditem.DevServicesResultBuildItem.RunningDevService;
import io.quarkus.elasticsearch.restclient.common.deployment.ElasticsearchCommonBuildTimeConfig.ElasticsearchDevServicesBuildTimeConfig;
import io.quarkus.elasticsearch.restclient.common.deployment.ElasticsearchCommonBuildTimeConfig.ElasticsearchDevServicesBuildTimeConfig.Distribution;

final class DevservicesElasticsearchProcessorUtils {

/**
* Label to add to shared Dev Service for Elasticsearch running in containers.
* This allows other applications to discover the running service and use it instead of starting a new instance.
*/
static final String DEV_SERVICE_LABEL = "quarkus-dev-service-elasticsearch";
static final String NEW_DEV_SERVICE_LABEL = "io.quarkus.devservice.elasticsearch";
static final String DEV_SERVICE_ELASTICSEARCH = "elasticsearch";
static final String DEV_SERVICE_OPENSEARCH = "opensearch";
static final int ELASTICSEARCH_PORT = 9200;
static final Distribution DEFAULT_DISTRIBUTION = Distribution.ELASTIC;

private DevservicesElasticsearchProcessorUtils() {
}

static String getElasticsearchHosts(DevservicesElasticsearchBuildItemsConfiguration buildItemsConfiguration,
RunningDevService devService) {
String hostsConfigProperty = buildItemsConfiguration.hostsConfigProperties.stream().findAny().get();
return devService.getConfig().get(hostsConfigProperty);
}

static Distribution resolveDistribution(ElasticsearchDevServicesBuildTimeConfig config,
DevservicesElasticsearchBuildItemsConfiguration buildItemConfig) throws BuildException {
// First, let's see if it was explicitly configured:
if (config.distribution().isPresent()) {
return config.distribution().get();
}
// Now let's see if we can guess it from the image:
if (config.imageName().isPresent()) {
String imageNameRepository = DockerImageName.parse(config.imageName().get()).getRepository()
.toLowerCase(Locale.ROOT);
if (imageNameRepository.contains(DEV_SERVICE_OPENSEARCH)) {
return Distribution.OPENSEARCH;
}
if (imageNameRepository.contains(DEV_SERVICE_ELASTICSEARCH)) {
return Distribution.ELASTIC;
}
// no luck guessing so let's ask user to be more explicit:
throw new BuildException(
"Wasn't able to determine the distribution of the search service based on the provided image name ["
+ config.imageName().get()
+ "]. Please specify the distribution explicitly.",
Collections.emptyList());
}
// Otherwise, let's see if the build item has a value available:
if (buildItemConfig.distribution != null) {
return buildItemConfig.distribution;
}
// If we didn't get an explicit distribution
// and no image name was provided
// then elastic is a default distribution:
return DEFAULT_DISTRIBUTION;
}

static Map<String, String> buildPropertiesMap(DevservicesElasticsearchBuildItemsConfiguration buildItemConfig,
String httpHosts) {
Map<String, String> propertiesToSet = new HashMap<>();
for (String property : buildItemConfig.hostsConfigProperties) {
propertiesToSet.put(property, httpHosts);
}
return propertiesToSet;
}
}
Loading
Loading