From 7c65431f03c6b8df203a038c4d0a7b1a4cf6958f Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Sun, 17 May 2020 15:17:22 +0100 Subject: [PATCH 1/5] Minor polishing of the Hibernate Multitenancy support code and tests --- .../tenant/DataSourceTenantConnectionResolver.java | 2 -- .../tenant/HibernateCurrentTenantIdentifierResolver.java | 2 +- .../tenant/HibernateMultiTenantConnectionProvider.java | 8 +++++--- .../src/main/resources/application.properties | 1 - 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/tenant/DataSourceTenantConnectionResolver.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/tenant/DataSourceTenantConnectionResolver.java index 58a5053c536fe..357615c0bbe05 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/tenant/DataSourceTenantConnectionResolver.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/tenant/DataSourceTenantConnectionResolver.java @@ -89,8 +89,6 @@ private static AgroalDataSource tenantDataSource(JPAConfig jpaConfig, String ten private static class TenantConnectionProvider extends QuarkusConnectionProvider { - private static final long serialVersionUID = 1L; - private final String tenantId; public TenantConnectionProvider(String tenantId, AgroalDataSource dataSource) { diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/tenant/HibernateCurrentTenantIdentifierResolver.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/tenant/HibernateCurrentTenantIdentifierResolver.java index 1b8924c3a9086..03e414fd90655 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/tenant/HibernateCurrentTenantIdentifierResolver.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/tenant/HibernateCurrentTenantIdentifierResolver.java @@ -12,7 +12,7 @@ * @author Michael Schnell * */ -public class HibernateCurrentTenantIdentifierResolver implements CurrentTenantIdentifierResolver { +public final class HibernateCurrentTenantIdentifierResolver implements CurrentTenantIdentifierResolver { private static final Logger LOG = Logger.getLogger(HibernateCurrentTenantIdentifierResolver.class); diff --git a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/tenant/HibernateMultiTenantConnectionProvider.java b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/tenant/HibernateMultiTenantConnectionProvider.java index 325465fd838f7..5c56ea09f3caf 100644 --- a/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/tenant/HibernateMultiTenantConnectionProvider.java +++ b/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/tenant/HibernateMultiTenantConnectionProvider.java @@ -16,7 +16,7 @@ * @author Michael Schnell * */ -public class HibernateMultiTenantConnectionProvider extends AbstractMultiTenantConnectionProvider { +public final class HibernateMultiTenantConnectionProvider extends AbstractMultiTenantConnectionProvider { private static final Logger LOG = Logger.getLogger(HibernateMultiTenantConnectionProvider.class); @@ -33,12 +33,14 @@ protected ConnectionProvider getAnyConnectionProvider() { } @Override - protected ConnectionProvider selectConnectionProvider(String tenantIdentifier) { + protected ConnectionProvider selectConnectionProvider(final String tenantIdentifier) { LOG.debugv("selectConnectionProvider({0})", tenantIdentifier); ConnectionProvider provider = providerMap.get(tenantIdentifier); if (provider == null) { - return providerMap.computeIfAbsent(tenantIdentifier, tid -> resolveConnectionProvider(tid)); + final ConnectionProvider connectionProvider = resolveConnectionProvider(tenantIdentifier); + providerMap.put(tenantIdentifier, connectionProvider); + return connectionProvider; } return provider; diff --git a/integration-tests/hibernate-tenancy/src/main/resources/application.properties b/integration-tests/hibernate-tenancy/src/main/resources/application.properties index 5ab0a1a1565ac..0e0653d042ef1 100644 --- a/integration-tests/hibernate-tenancy/src/main/resources/application.properties +++ b/integration-tests/hibernate-tenancy/src/main/resources/application.properties @@ -1,7 +1,6 @@ # Hibernate ORM settings quarkus.hibernate-orm.database.generation=none quarkus.hibernate-orm.multitenant=DATABASE -quarkus.hibernate-orm.validate-tenant-in-current-sessions=false # Maria DB URL mariadb.url=jdbc:mariadb://localhost:3306 From cc6f4d5b62072a16750e50a26f10aaf701987c96 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Sun, 17 May 2020 21:40:54 +0100 Subject: [PATCH 2/5] Reconfigure MariaDB in CI actions for multi-DB tests --- .github/workflows/ci-actions.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-actions.yml b/.github/workflows/ci-actions.yml index db0d42db6281a..2c7fc97cec231 100644 --- a/.github/workflows/ci-actions.yml +++ b/.github/workflows/ci-actions.yml @@ -144,7 +144,7 @@ jobs: MYSQL_USER: hibernate_orm_test MYSQL_PASSWORD: hibernate_orm_test MYSQL_DATABASE: hibernate_orm_test - MYSQL_RANDOM_ROOT_PASSWORD: true + MYSQL_ROOT_PASSWORD: secret ports: - 127.0.0.1:3308:3306 mssql: @@ -320,6 +320,7 @@ jobs: jpa-mssql jpa-derby jpa-without-entity + hibernate-tenancy - category: Data2 mysql: "true" postgres: "true" @@ -476,7 +477,7 @@ jobs: - name: Maria DB Service run: | docker run --rm --publish 3308:3306 --name build-mariadb \ - -e MYSQL_USER=$DB_USER -e MYSQL_PASSWORD=$DB_PASSWORD -e MYSQL_DATABASE=$DB_NAME -e MYSQL_RANDOM_ROOT_PASSWORD=true \ + -e MYSQL_USER=$DB_USER -e MYSQL_PASSWORD=$DB_PASSWORD -e MYSQL_DATABASE=$DB_NAME -e MYSQL_ROOT_PASSWORD=secret \ -d mariadb:10.4 if: matrix.mariadb - name: MS-SQL Service From bdeab9d1d72e37bf1edcd302606d66603cc93f4e Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 18 May 2020 11:20:29 +0100 Subject: [PATCH 3/5] Introduce a 'mariadb.base_url' variable for multitenancy tests --- .github/workflows/ci-actions.yml | 4 ++-- integration-tests/hibernate-tenancy/README.md | 10 +++++++++- integration-tests/hibernate-tenancy/pom.xml | 2 +- .../src/main/resources/application.properties | 9 +++------ 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci-actions.yml b/.github/workflows/ci-actions.yml index 2c7fc97cec231..a0abef78e7f5c 100644 --- a/.github/workflows/ci-actions.yml +++ b/.github/workflows/ci-actions.yml @@ -34,8 +34,8 @@ on: env: # Workaround testsuite locale issue LANG: en_US.UTF-8 - NATIVE_TEST_MAVEN_OPTS: "-B --settings .github/mvn-settings.xml --fail-at-end -Dquarkus.native.container-build=true -Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-native-image:19.3.1-java11 -Dtest-postgresql -Dtest-elasticsearch -Dtest-keycloak -Dtest-amazon-services -Dtest-mysql -Dtest-mariadb -Dmariadb.url='jdbc:mariadb://localhost:3308/hibernate_orm_test' -Dtest-mssql -Dtest-vault -Dtest-neo4j -Dtest-kafka -Dnative-image.xmx=5g -Dnative -Dformat.skip install" - JVM_TEST_MAVEN_OPTS: "-e -B --settings .github/mvn-settings.xml -Dtest-postgresql -Dtest-elasticsearch -Dtest-mysql -Dtest-mariadb -Dmariadb.url='jdbc:mariadb://localhost:3308/hibernate_orm_test' -Dtest-mssql -Dtest-amazon-services -Dtest-vault -Dtest-neo4j -Dtest-kafka -Dtest-keycloak -Dformat.skip" + NATIVE_TEST_MAVEN_OPTS: "-B --settings .github/mvn-settings.xml --fail-at-end -Dquarkus.native.container-build=true -Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-native-image:19.3.1-java11 -Dtest-postgresql -Dtest-elasticsearch -Dtest-keycloak -Dtest-amazon-services -Dtest-mysql -Dtest-mariadb -Dmariadb.base_url='jdbc:mariadb://localhost:3308' -Dmariadb.url='jdbc:mariadb://localhost:3308/hibernate_orm_test' -Dtest-mssql -Dtest-vault -Dtest-neo4j -Dtest-kafka -Dnative-image.xmx=5g -Dnative -Dformat.skip install" + JVM_TEST_MAVEN_OPTS: "-e -B --settings .github/mvn-settings.xml -Dtest-postgresql -Dtest-elasticsearch -Dtest-mysql -Dtest-mariadb -Dmariadb.base_url='jdbc:mariadb://localhost:3308' -Dmariadb.url='jdbc:mariadb://localhost:3308/hibernate_orm_test' -Dtest-mssql -Dtest-amazon-services -Dtest-vault -Dtest-neo4j -Dtest-kafka -Dtest-keycloak -Dformat.skip" DB_USER: hibernate_orm_test DB_PASSWORD: hibernate_orm_test DB_NAME: hibernate_orm_test diff --git a/integration-tests/hibernate-tenancy/README.md b/integration-tests/hibernate-tenancy/README.md index 9fa24ee757a3d..b3a88391fc620 100644 --- a/integration-tests/hibernate-tenancy/README.md +++ b/integration-tests/hibernate-tenancy/README.md @@ -27,7 +27,9 @@ You can then run the tests as follows (either with `-Dnative` or not): mvn clean install -Dtest-mariadb ``` -If you have specific requirements, you can define a specific connection URL with `-Djdbc:mariadb://localhost:3306/hibernate_orm_test`. +If you have specific requirements, you can define a specific connection URL with `-Dmariadb.base_url=jdbc:mariadb://...`. +Note that this specific integration test module module requires permissions to create additional users and databases, hence the `mariadb.base_url` variable +should not include the database name: check the `application.properties` to see how it's used. To run the MariaDB server "manually" via command line for testing, the following command line could be useful: @@ -35,6 +37,12 @@ To run the MariaDB server "manually" via command line for testing, the following docker run --ulimit memlock=-1:-1 -it --rm=true --memory-swappiness=0 --name quarkus_test_mariadb -e MYSQL_DATABASE=hibernate_orm_test -e MYSQL_ROOT_PASSWORD=secret -p 3306:3306 mariadb:10.4 ``` +or if you prefer podman, this won't need root permissions: + +``` +podman run --rm=true --net=host --memory-swappiness=0 --tmpfs /var/lib/mysql:rw --tmpfs /var/log:rw --name mariadb_demo -e MYSQL_USER=hibernate_orm_test -e MYSQL_PASSWORD=hibernate_orm_test -e MYSQL_DATABASE=hibernate_orm_test -e MYSQL_ROOT_PASSWORD=secret -p 3306:3306 mariadb:10.4 +``` + N.B. it takes a while for MariaDB to be actually booted and accepting connections. After it's fully booted, you can run all integration tests via diff --git a/integration-tests/hibernate-tenancy/pom.xml b/integration-tests/hibernate-tenancy/pom.xml index 6b5aaef4fadf5..4dd18fb1cee1b 100644 --- a/integration-tests/hibernate-tenancy/pom.xml +++ b/integration-tests/hibernate-tenancy/pom.xml @@ -16,7 +16,7 @@ Module that contains Hibernate Multitenancy related tests running with the MariaDB database - jdbc:mariadb://localhost:3306 + jdbc:mariadb://localhost:3306 mariadb:10.4 diff --git a/integration-tests/hibernate-tenancy/src/main/resources/application.properties b/integration-tests/hibernate-tenancy/src/main/resources/application.properties index 0e0653d042ef1..2f35ae7f1e1c4 100644 --- a/integration-tests/hibernate-tenancy/src/main/resources/application.properties +++ b/integration-tests/hibernate-tenancy/src/main/resources/application.properties @@ -2,14 +2,11 @@ quarkus.hibernate-orm.database.generation=none quarkus.hibernate-orm.multitenant=DATABASE -# Maria DB URL -mariadb.url=jdbc:mariadb://localhost:3306 - # Default DB Configuration quarkus.datasource.db-kind=mariadb quarkus.datasource.username=root quarkus.datasource.password=secret -quarkus.datasource.jdbc.url=${mariadb.url}/hibernate_orm_test +quarkus.datasource.jdbc.url=${mariadb.base_url}/hibernate_orm_test quarkus.datasource.jdbc.max-size=1 quarkus.datasource.jdbc.min-size=1 quarkus.flyway.migrate-at-start=true @@ -19,7 +16,7 @@ quarkus.flyway.locations=classpath:database/default quarkus.datasource.base.db-kind=mariadb quarkus.datasource.base.username=jane quarkus.datasource.base.password=abc -quarkus.datasource.base.jdbc.url=${mariadb.url}/base +quarkus.datasource.base.jdbc.url=${mariadb.base_url}/base quarkus.datasource.base.jdbc.max-size=1 quarkus.datasource.base.jdbc.min-size=1 quarkus.flyway.base.migrate-at-start=true @@ -29,7 +26,7 @@ quarkus.flyway.base.locations=classpath:database/base quarkus.datasource.mycompany.db-kind=mariadb quarkus.datasource.mycompany.username=john quarkus.datasource.mycompany.password=def -quarkus.datasource.mycompany.jdbc.url=${mariadb.url}/mycompany +quarkus.datasource.mycompany.jdbc.url=${mariadb.base_url}/mycompany quarkus.datasource.mycompany.jdbc.max-size=1 quarkus.datasource.mycompany.jdbc.min-size=1 quarkus.flyway.mycompany.migrate-at-start=true From 78548098d539ec23e1ce36bfa878dadd41c217cd Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 18 May 2020 11:40:17 +0100 Subject: [PATCH 4/5] Add podman instructions to the jpa-mariadb tests as well --- integration-tests/jpa-mariadb/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/integration-tests/jpa-mariadb/README.md b/integration-tests/jpa-mariadb/README.md index 74643acbffdd0..f6f1084468d00 100644 --- a/integration-tests/jpa-mariadb/README.md +++ b/integration-tests/jpa-mariadb/README.md @@ -35,6 +35,12 @@ To run the MariaDB server "manually" via command line for testing, the following docker run --ulimit memlock=-1:-1 -it --rm=true --memory-swappiness=0 --name quarkus_test_mariadb -e MYSQL_USER=hibernate_orm_test -e MYSQL_PASSWORD=hibernate_orm_test -e MYSQL_DATABASE=hibernate_orm_test -e MYSQL_RANDOM_ROOT_PASSWORD=true -p 3306:3306 mariadb:10.4 ``` +or if you prefer podman, this won't need root permissions: + +``` +podman run --rm=true --net=host --memory-swappiness=0 --tmpfs /var/lib/mysql:rw --tmpfs /var/log:rw --name mariadb_demo -e MYSQL_USER=hibernate_orm_test -e MYSQL_PASSWORD=hibernate_orm_test -e MYSQL_DATABASE=hibernate_orm_test -e MYSQL_ROOT_PASSWORD=secret -p 3306:3306 mariadb:10.4 +``` + N.B. it takes a while for MariaDB to be actually booted and accepting connections. After it's fully booted, you can run all integration tests via From 32019289725aa008570f560174a94582247444c2 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 18 May 2020 13:14:46 +0100 Subject: [PATCH 5/5] Flyway migrations for Multitenancy IT needs to be more resilient --- .../src/main/resources/application.properties | 4 ++++ .../resources/database/default/V1.0.0__init_databases.sql | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/integration-tests/hibernate-tenancy/src/main/resources/application.properties b/integration-tests/hibernate-tenancy/src/main/resources/application.properties index 2f35ae7f1e1c4..6ddf2937a808d 100644 --- a/integration-tests/hibernate-tenancy/src/main/resources/application.properties +++ b/integration-tests/hibernate-tenancy/src/main/resources/application.properties @@ -10,6 +10,8 @@ quarkus.datasource.jdbc.url=${mariadb.base_url}/hibernate_orm_test quarkus.datasource.jdbc.max-size=1 quarkus.datasource.jdbc.min-size=1 quarkus.flyway.migrate-at-start=true +#Reset Flyway metadata at boot, as the database might have been tainted by previous integration tests: +quarkus.flyway.clean-at-start=true quarkus.flyway.locations=classpath:database/default # DATABASE Tenant 'base' Configuration @@ -20,6 +22,7 @@ quarkus.datasource.base.jdbc.url=${mariadb.base_url}/base quarkus.datasource.base.jdbc.max-size=1 quarkus.datasource.base.jdbc.min-size=1 quarkus.flyway.base.migrate-at-start=true +quarkus.flyway.base.clean-at-start=true quarkus.flyway.base.locations=classpath:database/base # DATABASE Tenant 'mycompany' Configuration @@ -30,5 +33,6 @@ quarkus.datasource.mycompany.jdbc.url=${mariadb.base_url}/mycompany quarkus.datasource.mycompany.jdbc.max-size=1 quarkus.datasource.mycompany.jdbc.min-size=1 quarkus.flyway.mycompany.migrate-at-start=true +quarkus.flyway.mycompany.clean-at-start=true quarkus.flyway.mycompany.locations=classpath:database/mycompany diff --git a/integration-tests/hibernate-tenancy/src/main/resources/database/default/V1.0.0__init_databases.sql b/integration-tests/hibernate-tenancy/src/main/resources/database/default/V1.0.0__init_databases.sql index afb6961476893..aad4b706e5e4c 100644 --- a/integration-tests/hibernate-tenancy/src/main/resources/database/default/V1.0.0__init_databases.sql +++ b/integration-tests/hibernate-tenancy/src/main/resources/database/default/V1.0.0__init_databases.sql @@ -1,9 +1,9 @@ -CREATE DATABASE base; -CREATE USER 'jane'@'%' IDENTIFIED BY 'abc'; +CREATE DATABASE IF NOT EXISTS base; +CREATE USER IF NOT EXISTS 'jane'@'%' IDENTIFIED BY 'abc'; GRANT ALL privileges ON base.* TO 'jane'@'%'; -CREATE DATABASE mycompany; -CREATE USER 'john'@'%' IDENTIFIED BY 'def'; +CREATE DATABASE IF NOT EXISTS mycompany; +CREATE USER IF NOT EXISTS 'john'@'%' IDENTIFIED BY 'def'; GRANT ALL privileges ON mycompany.* TO 'john'@'%'; FLUSH PRIVILEGES;