diff --git a/build/container/amazon-opensearch-serverless.Dockerfile b/build/container/amazon-opensearch-serverless.Dockerfile new file mode 100644 index 00000000000..dbce938321d --- /dev/null +++ b/build/container/amazon-opensearch-serverless.Dockerfile @@ -0,0 +1,3 @@ +# OpenSearch +# See https://hub.docker.com/r/opensearchproject/opensearch/tags +FROM docker.io/opensearchproject/opensearch:2.11.0 \ No newline at end of file diff --git a/build/container/elasticsearch.Dockerfile b/build/container/elastic.Dockerfile similarity index 100% rename from build/container/elasticsearch.Dockerfile rename to build/container/elastic.Dockerfile diff --git a/build/parents/build/pom.xml b/build/parents/build/pom.xml index e559714d7cc..635d0e45a86 100644 --- a/build/parents/build/pom.xml +++ b/build/parents/build/pom.xml @@ -218,7 +218,6 @@ because we will be able to change the configuration without re-compiling the configuration file (which is located in a dependency of the integration tests modules). --> - elastic @@ -1196,10 +1195,9 @@ ${project.version} ${test.performance.enable} ${test.elasticsearch.distribution} - ${test.searchengine.run.image.name} - ${test.searchengine.run.image.tag} + ${test.elasticsearch.version} ${test.database.run.kind} - ${rootProject.directory} + ${rootProject.directory} diff --git a/build/parents/integrationtest/pom.xml b/build/parents/integrationtest/pom.xml index 9efd05a6a3d..4ef1694c541 100644 --- a/build/parents/integrationtest/pom.xml +++ b/build/parents/integrationtest/pom.xml @@ -96,31 +96,32 @@ - + - elasticsearch-run + search-container-do-not-start - + - !test.elasticsearch.connection.uris + test.elasticsearch.connection.uris - ${test.elasticsearch.run.elastic.image.name} - ${test.elasticsearch.run.elastic.image.tag} + false - + + - elasticsearch-do-not-run + elasticsearch-test-skip - test.elasticsearch.connection.uris + test.elasticsearch.skip + true - false + true @@ -143,20 +144,6 @@ - - opensearch - - - test.elasticsearch.distribution - opensearch - - - - ${test.elasticsearch.run.opensearch.image.name} - ${test.elasticsearch.run.opensearch.image.tag} - - - diff --git a/pom.xml b/pom.xml index e1d25555b71..0d030026421 100644 --- a/pom.xml +++ b/pom.xml @@ -377,24 +377,14 @@ 8.10.4 - ${version.org.elasticsearch.latest} - - true - docker.io/elastic/elasticsearch - ${test.elasticsearch.version} - - true - docker.io/opensearchproject/opensearch - ${test.elasticsearch.version} + + elastic h2 true - - - @@ -967,8 +957,14 @@ if ( isNotBlankString( '${test.database.run.kind}' ) && '${test.database.run.kind}' != 'h2') { images += parseImage( './build/container/${test.database.run.kind}.Dockerfile' ) } - if ( isTrueString( '${test.searchengine.run.image.pull}' ) && isNotBlankString( '${test.searchengine.run.image.name}' ) ) { - images += '${test.searchengine.run.image.name}:${test.searchengine.run.image.tag}' + if ( isTrueString( '${test.searchengine.run.image.pull}' ) ) { + def fromFile = parseImage( './build/container/${test.elasticsearch.distribution}.Dockerfile') + def suppliedVersion = '${test.elasticsearch.version}' + if (isNotBlankString(suppliedVersion)) { + images += fromFile.substring(0, fromFile.lastIndexOf(':')+1) + suppliedVersion + } else { + images += fromFile + } } // Exclude images from non-dockerhub repositories new File('${containerImagesListFile}').append( images.findAll{ref -> !(ref ==~ /^(?!((.*\.)?docker\.io))[\w\d\.]+\/[\w\d\.]+\/[\w\d\.]+(:.+)?$/)}.join('\n') + '\n' ) diff --git a/util/internal/integrationtest/backend/elasticsearch/src/main/java/org/hibernate/search/util/impl/integrationtest/backend/elasticsearch/SearchContainer.java b/util/internal/integrationtest/backend/elasticsearch/src/main/java/org/hibernate/search/util/impl/integrationtest/backend/elasticsearch/SearchContainer.java index b1d6bb0411c..b67aa8f90c8 100644 --- a/util/internal/integrationtest/backend/elasticsearch/src/main/java/org/hibernate/search/util/impl/integrationtest/backend/elasticsearch/SearchContainer.java +++ b/util/internal/integrationtest/backend/elasticsearch/src/main/java/org/hibernate/search/util/impl/integrationtest/backend/elasticsearch/SearchContainer.java @@ -6,7 +6,12 @@ */ package org.hibernate.search.util.impl.integrationtest.backend.elasticsearch; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.time.Duration; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.hibernate.search.backend.elasticsearch.ElasticsearchDistributionName; import org.hibernate.search.backend.elasticsearch.ElasticsearchVersion; @@ -23,12 +28,30 @@ private SearchContainer() { private static final GenericContainer SEARCH_CONTAINER; static { - String name = System.getProperty( "org.hibernate.search.integrationtest.backend.elasticsearch.name", "" ); - String tag = System.getProperty( "org.hibernate.search.integrationtest.backend.elasticsearch.tag" ); - - SEARCH_CONTAINER = name.contains( "elastic" ) - ? elasticsearch( name, tag, ElasticsearchVersion.of( ElasticsearchDistributionName.ELASTIC, tag ) ) - : opensearch( name, tag ); + ElasticsearchDistributionName distributionName = ElasticsearchDistributionName + .of( System.getProperty( "org.hibernate.search.integrationtest.backend.elasticsearch.distribution", "" ) ); + String tag = System.getProperty( "org.hibernate.search.integrationtest.backend.elasticsearch.version" ); + Path root = Path.of( System.getProperty( "org.hibernate.search.integrationtest.project.root.directory", "" ) ); + + try { + DockerImageName dockerImageName = parseDockerImageName( root.resolve( "build" ).resolve( "container" ) + .resolve( distributionName.externalRepresentation() + ".Dockerfile" ), tag ); + switch ( distributionName ) { + case ELASTIC: + SEARCH_CONTAINER = elasticsearch( dockerImageName ); + break; + case OPENSEARCH: + case AMAZON_OPENSEARCH_SERVERLESS: + SEARCH_CONTAINER = opensearch( dockerImageName ); + break; + default: + throw new IllegalStateException( "Unknown distribution " + distributionName ); + } + } + catch (IOException e) { + throw new IllegalStateException( + "Unable to initialize a Search Engine container [" + distributionName + ", " + tag + ", " + root + "]", e ); + } } public static int mappedPort(int port) { @@ -60,8 +83,8 @@ private static void startIfNeeded() { } } - private static GenericContainer elasticsearch(String name, String tag, ElasticsearchVersion version) { - GenericContainer container = common( name, tag ) + private static GenericContainer elasticsearch(DockerImageName dockerImageName) { + GenericContainer container = common( dockerImageName ) .withEnv( "logger.level", "WARN" ) .withEnv( "discovery.type", "single-node" ) // Older images require HTTP authentication for all requests; @@ -79,6 +102,9 @@ private static GenericContainer elasticsearch(String name, String tag, Elasti // See https://www.elastic.co/guide/en/elasticsearch/reference/7.17/modules-cluster.html#disk-based-shard-allocation .withEnv( "cluster.routing.allocation.disk.threshold_enabled", "false" ); + ElasticsearchVersion version = + ElasticsearchVersion.of( ElasticsearchDistributionName.ELASTIC, dockerImageName.getVersionPart() ); + if ( version.majorOptional().orElse( Integer.MIN_VALUE ) == 8 ) { if ( version.minor().orElse( Integer.MAX_VALUE ) > 7 ) { container.withEnv( "cluster.deprecation_indexing.enabled", "false" ) @@ -112,8 +138,8 @@ private static GenericContainer elasticsearch(String name, String tag, Elasti return container; } - private static GenericContainer opensearch(String name, String tag) { - return common( name, tag ) + private static GenericContainer opensearch(DockerImageName dockerImageName) { + return common( dockerImageName ) .withEnv( "logger.level", "WARN" ) .withEnv( "discovery.type", "single-node" ) // Prevent swapping @@ -137,11 +163,30 @@ private static GenericContainer opensearch(String name, String tag) { * this resource in the end. */ @SuppressWarnings("resource") - private static GenericContainer common(String image, String tag) { - return new GenericContainer<>( DockerImageName.parse( image ).withTag( tag ) ) + private static GenericContainer common(DockerImageName dockerImageName) { + return new GenericContainer<>( dockerImageName ) .withExposedPorts( 9200, 9300 ) .waitingFor( new HttpWaitStrategy().forPort( 9200 ).forStatusCode( 200 ) ) .withStartupTimeout( Duration.ofMinutes( 5 ) ) .withReuse( true ); } + + + private static DockerImageName parseDockerImageName(Path dockerfile, String tag) throws IOException { + Pattern DOCKERFILE_FROM_LINE_PATTERN = Pattern.compile( "FROM (.+)" ); + + DockerImageName dockerImageName = Files.lines( dockerfile ) + .map( DOCKERFILE_FROM_LINE_PATTERN::matcher ) + .filter( Matcher::matches ) + .map( m -> m.group( 1 ) ) + .map( DockerImageName::parse ) + .findAny().orElseThrow( () -> new IllegalStateException( + "Dockerfile " + dockerfile + " has unexpected structure. It *must* contain a single FROM line." ) ); + + if ( tag != null && !tag.trim().isEmpty() ) { + return dockerImageName.withTag( tag ); + } + + return dockerImageName; + } } diff --git a/util/internal/integrationtest/mapper/orm/src/main/java/org/hibernate/search/util/impl/integrationtest/mapper/orm/DatabaseContainer.java b/util/internal/integrationtest/mapper/orm/src/main/java/org/hibernate/search/util/impl/integrationtest/mapper/orm/DatabaseContainer.java index 7ab955dc4fe..04ea8974671 100644 --- a/util/internal/integrationtest/mapper/orm/src/main/java/org/hibernate/search/util/impl/integrationtest/mapper/orm/DatabaseContainer.java +++ b/util/internal/integrationtest/mapper/orm/src/main/java/org/hibernate/search/util/impl/integrationtest/mapper/orm/DatabaseContainer.java @@ -35,7 +35,7 @@ private DatabaseContainer() { static { String name = System.getProperty( "org.hibernate.search.integrationtest.orm.database.kind", "" ); - Path root = Path.of( System.getProperty( "org.hibernate.search.integrationtest.orm.project.root.directory", "" ) ); + Path root = Path.of( System.getProperty( "org.hibernate.search.integrationtest.project.root.directory", "" ) ); DATABASE = SupportedDatabase.from( name ); DATABASE_CONTAINER = DATABASE.container(