diff --git a/docs/guides/observability/partials/ispn_enable_metrics.adoc b/docs/guides/observability/partials/ispn_enable_metrics.adoc index 75f9c187de2..17469a0180e 100644 --- a/docs/guides/observability/partials/ispn_enable_metrics.adoc +++ b/docs/guides/observability/partials/ispn_enable_metrics.adoc @@ -2,7 +2,6 @@ {jdgserver_name} exposes metrics in the endpoint `/metrics`. By default, they are enabled. -We recommend enabling the attribute `name-as-tags` as it makes the metrics name independent on the cache name. To configure metrics in the {jdgserver_name} server, just enabled as shown in the XML below. @@ -11,7 +10,7 @@ To configure metrics in the {jdgserver_name} server, just enabled as shown in th ---- - + ---- diff --git a/model/infinispan/pom.xml b/model/infinispan/pom.xml index bf1f9fb07dc..f65926e0ff5 100755 --- a/model/infinispan/pom.xml +++ b/model/infinispan/pom.xml @@ -74,16 +74,6 @@ org.infinispan infinispan-cachestore-remote - - - org.infinispan - infinispan-remote-query-client - - - - org.infinispan - infinispan-query-dsl - org.infinispan infinispan-component-annotations diff --git a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/TopologyInfo.java b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/TopologyInfo.java index c1470bab8be..c339e9002fd 100644 --- a/model/infinispan/src/main/java/org/keycloak/connections/infinispan/TopologyInfo.java +++ b/model/infinispan/src/main/java/org/keycloak/connections/infinispan/TopologyInfo.java @@ -28,9 +28,7 @@ import org.infinispan.distribution.DistributionManager; import org.infinispan.factories.GlobalComponentRegistry; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.remoting.transport.Address; -import org.infinispan.remoting.transport.LocalModeAddress; import org.infinispan.remoting.transport.Transport; -import org.infinispan.remoting.transport.jgroups.JGroupsAddress; import org.infinispan.remoting.transport.jgroups.JGroupsTransport; import org.jboss.logging.Logger; import org.jgroups.stack.IpAddress; @@ -116,12 +114,9 @@ public class TopologyInfo { public boolean amIOwner(Cache cache, Object key) { Address myAddress = cache.getCacheManager().getAddress(); Address objectOwnerAddress = getOwnerAddress(cache, key); - - // NOTE: For scattered caches, this will always return true, which may not be correct. Need to review this if we add support for scattered caches return Objects.equals(myAddress, objectOwnerAddress); } - /** * Get route to be used as the identifier for sticky session. Return null if I am not able to find the appropriate route (or in case of local mode) * @deprecated Use {@link org.keycloak.sessions.StickySessionEncoderProvider#sessionIdRoute(String)} instead. @@ -140,11 +135,11 @@ public class TopologyInfo { Address address = getOwnerAddress(cache, key); // Local mode - if (address == null || (address == LocalModeAddress.INSTANCE)) { + if (address == null || (address == Address.LOCAL)) { return myNodeName; } - org.jgroups.Address jgroupsAddress = toJGroupsAddress(address); + org.jgroups.Address jgroupsAddress = Address.toExtendedUUID(address); String name = NameCache.get(jgroupsAddress); // If no logical name exists, create one using physical address @@ -169,16 +164,4 @@ public class TopologyInfo { DistributionManager dist = cache.getAdvancedCache().getDistributionManager(); return dist == null ? cache.getCacheManager().getAddress() : dist.getCacheTopology().getDistribution(key).primary(); } - - - // See org.wildfly.clustering.server.group.CacheGroup - private static org.jgroups.Address toJGroupsAddress(Address address) { - if ((address == null) || (address == LocalModeAddress.INSTANCE)) return null; - if (address instanceof JGroupsAddress jgroupsAddress) { - return jgroupsAddress.getJGroupsAddress(); - } - throw new IllegalArgumentException(address.toString()); - } - - } diff --git a/model/infinispan/src/main/java/org/keycloak/jgroups/protocol/KEYCLOAK_JDBC_PING2.java b/model/infinispan/src/main/java/org/keycloak/jgroups/protocol/KEYCLOAK_JDBC_PING2.java index c69fe31b96a..f6c25d21408 100644 --- a/model/infinispan/src/main/java/org/keycloak/jgroups/protocol/KEYCLOAK_JDBC_PING2.java +++ b/model/infinispan/src/main/java/org/keycloak/jgroups/protocol/KEYCLOAK_JDBC_PING2.java @@ -18,222 +18,18 @@ package org.keycloak.jgroups.protocol; import java.sql.Connection; -import java.sql.SQLException; -import java.util.Collections; -import java.util.List; import java.util.Objects; -import java.util.stream.Collectors; import org.keycloak.connections.jpa.JpaConnectionProviderFactory; -import org.jgroups.Address; -import org.jgroups.Event; -import org.jgroups.PhysicalAddress; -import org.jgroups.View; import org.jgroups.protocols.JDBC_PING2; import org.jgroups.protocols.PingData; -import org.jgroups.stack.Protocol; -import org.jgroups.util.ExtendedUUID; -import org.jgroups.util.NameCache; -import org.jgroups.util.Responses; import org.jgroups.util.UUID; -/** - * Enhanced JDBC_PING2 to handle entries transactionally. - *

- * Workaround for issue JGRP-2870 - */ public class KEYCLOAK_JDBC_PING2 extends JDBC_PING2 { private JpaConnectionProviderFactory factory; - @Override - protected void handleView(View new_view, View old_view, boolean coord_changed) { - // If we are the coordinator, it is good to learn about new entries that have been added before we delete them. - // If we are not the coordinator, it is good to learn the new entries added by the coordinator. - // This avoids a "JGRP000032: %s: no physical address for %s, dropping message" that leads to split clusters at concurrent startup. - learnExistingAddresses(); - - // This is an updated logic where we do not call removeAll but instead remove those obsolete entries. - // This avoids the short moment where the table is empty and a new node might not see any other node. - if (is_coord) { - if (remove_old_coords_on_view_change) { - Address old_coord = old_view != null ? old_view.getCreator() : null; - if (old_coord != null) - remove(cluster_name, old_coord); - } - Address[] left = View.diff(old_view, new_view)[1]; - if (coord_changed || update_store_on_view_change || left.length > 0) { - writeAll(left); - if (remove_all_data_on_view_change) { - removeAllNotInCurrentView(); - } - if (remove_all_data_on_view_change || remove_old_coords_on_view_change) { - startInfoWriter(); - } - } - } else if (coord_changed && !remove_all_data_on_view_change) { - // I'm no longer the coordinator, usually due to a merge. - // The new coordinator will update my status to non-coordinator, and remove me fully - // if 'remove_all_data_on_view_change' is enabled and I'm no longer part of the view. - // Maybe this branch even be removed completely, but for JDBC_PING 'remove_all_data_on_view_change' is always set to true. - PhysicalAddress physical_addr = (PhysicalAddress) down(new Event(Event.GET_PHYSICAL_ADDRESS, local_addr)); - PingData coord_data = new PingData(local_addr, true, NameCache.get(local_addr), physical_addr).coord(is_coord); - write(Collections.singletonList(coord_data), cluster_name); - } - } - - @Override - protected void removeAll(String clustername) { - // This is unsafe as even if we would fill the table a moment later, a new node might see an empty table and become a coordinator - throw new RuntimeException("Not implemented as it is unsafe"); - } - - private void removeAllNotInCurrentView() { - try { - List list = readFromDB(getClusterName()); - for (PingData data : list) { - Address addr = data.getAddress(); - if (view != null && !view.containsMember(addr)) { - addDiscoveryResponseToCaches(addr, data.getLogicalName(), data.getPhysicalAddr()); - remove(cluster_name, addr); - } - } - } catch (Exception e) { - log.error(String.format("%s: failed reading from the DB", local_addr), e); - } - } - - protected void learnExistingAddresses() { - try { - List list = readFromDB(getClusterName()); - for (PingData data : list) { - Address addr = data.getAddress(); - if (local_addr != null && !local_addr.equals(addr)) { - addDiscoveryResponseToCaches(addr, data.getLogicalName(), data.getPhysicalAddr()); - } - } - } catch (Exception e) { - log.error(String.format("%s: failed reading from the DB", local_addr), e); - } - } - - @Override - public synchronized boolean isInfoWriterRunning() { - // Do not rely on the InfoWriter, instead always write the missing information on find if it is missing. Find is also triggered by MERGE. - return false; - } - - @Override - public void findMembers(List

members, boolean initial_discovery, Responses responses) { - if (initial_discovery) { - try { - List pingData = readFromDB(cluster_name); - PhysicalAddress physical_addr = (PhysicalAddress) down(new Event(Event.GET_PHYSICAL_ADDRESS, local_addr)); - // Sending the discovery here, as parent class will not execute it once there is data in the table - sendDiscoveryResponse(local_addr, physical_addr, NameCache.get(local_addr), null, is_coord); - PingData coord_data = new PingData(local_addr, true, NameCache.get(local_addr), physical_addr).coord(is_coord); - write(Collections.singletonList(coord_data), cluster_name); - while (pingData.stream().noneMatch(PingData::isCoord)) { - // Do a quick check if more nodes have arrived, to have a more complete list of nodes to start with. - List newPingData = readFromDB(cluster_name); - if (newPingData.stream().map(PingData::getAddress).collect(Collectors.toSet()).equals(pingData.stream().map(PingData::getAddress).collect(Collectors.toSet())) - || pingData.stream().anyMatch(PingData::isCoord)) { - break; - } - pingData = newPingData; - } - } catch (Exception e) { - log.error(String.format("%s: failed reading from the DB", local_addr), e); - } - } - - super.findMembers(members, initial_discovery, responses); - } - - @Override - protected void writeToDB(PingData data, String clustername) throws SQLException { - lock.lock(); - try (Connection connection = getConnection()) { - if(call_insert_sp != null && insert_sp != null) - callInsertStoredProcedure(connection, data, clustername); - else { - boolean isAutocommit = connection.getAutoCommit(); - try { - if (isAutocommit) { - // Always use a transaction for the delete+insert to make it atomic - // to avoid the short moment where there is no entry in the table. - connection.setAutoCommit(false); - } else { - log.warn("Autocommit is disabled. This indicates a transaction context that might batch statements and can lead to deadlocks."); - } - delete(connection, clustername, data.getAddress()); - insert(connection, data, clustername); - if (isAutocommit) { - connection.commit(); - } - } catch (SQLException e) { - if (isAutocommit) { - connection.rollback(); - } - throw e; - } finally { - if (isAutocommit) { - connection.setAutoCommit(true); - } - } - } - } finally { - lock.unlock(); - } - - } - - /* START: JDBC_PING2 does not handle ExtendedUUID yet, see - https://github.com/belaban/JGroups/pull/901 - until this is backported, we convert all of them. - */ - - @Override - public T addr(Address addr) { - addr = toUUID(addr); - return super.addr(addr); - } - - @Override - public T setAddress(Address addr) { - addr = toUUID(addr); - return super.setAddress(addr); - } - - @Override - protected void delete(Connection conn, String clustername, Address addressToDelete) throws SQLException { - super.delete(conn, clustername, toUUID(addressToDelete)); - } - - @Override - protected void delete(String clustername, Address addressToDelete) throws SQLException { - super.delete(clustername, toUUID(addressToDelete)); - } - - @Override - protected void insert(Connection connection, PingData data, String clustername) throws SQLException { - if (data.getAddress() instanceof ExtendedUUID) { - data = new PingData(toUUID(data.getAddress()), data.isServer(), data.getLogicalName(), data.getPhysicalAddr()).coord(data.isCoord()); - } - super.insert(connection, data, clustername); - } - - private static Address toUUID(Address addr) { - if (addr instanceof ExtendedUUID eUUID) { - addr = new UUID(eUUID.getMostSignificantBits(), eUUID.getLeastSignificantBits()); - } - return addr; - } - - /* END: JDBC_PING2 does not handle ExtendedUUID yet, see - https://github.com/belaban/JGroups/pull/901 - until this is backported, we convert all of them. - */ - @Override protected void loadDriver() { //no-op, using JpaConnectionProviderFactory diff --git a/model/infinispan/src/main/java/org/keycloak/marshalling/KeycloakModelSchema.java b/model/infinispan/src/main/java/org/keycloak/marshalling/KeycloakModelSchema.java index 771db6d9887..fc5262ed571 100644 --- a/model/infinispan/src/main/java/org/keycloak/marshalling/KeycloakModelSchema.java +++ b/model/infinispan/src/main/java/org/keycloak/marshalling/KeycloakModelSchema.java @@ -118,6 +118,7 @@ import org.infinispan.protostream.types.java.CommonTypes; schemaPackageName = Marshalling.PROTO_SCHEMA_PACKAGE, schemaFilePath = "proto/generated", allowNullFields = true, + orderedMarshallers = true, // common-types for UUID dependsOn = CommonTypes.class, diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProviderFactory.java index fabbc3a7da4..ea13e83b3a2 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanStickySessionEncoderProviderFactory.java @@ -34,7 +34,7 @@ import org.keycloak.sessions.StickySessionEncoderProvider; import org.keycloak.sessions.StickySessionEncoderProviderFactory; import org.infinispan.Cache; -import org.infinispan.remoting.transport.jgroups.JGroupsAddress; +import org.infinispan.remoting.transport.Address; import org.jboss.logging.Logger; import org.jgroups.util.NameCache; @@ -153,6 +153,6 @@ public class InfinispanStickySessionEncoderProviderFactory implements StickySess // Return null if the logical name is not available yet. // The following request may be redirected to the wrong instance, but that's ok. // In a healthy/stable cluster, the name cache is correctly populated. - return primaryOwner instanceof JGroupsAddress jgrpAddr ? NameCache.get(jgrpAddr.getJGroupsAddress()) : null; + return primaryOwner == null ? null : NameCache.get(Address.toExtendedUUID(primaryOwner)); } } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/query/QueryHelper.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/query/QueryHelper.java index 6289369fa10..54850c04ec7 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/query/QueryHelper.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/query/QueryHelper.java @@ -32,7 +32,7 @@ import java.util.stream.StreamSupport; import org.infinispan.client.hotrod.impl.query.RemoteQuery; import org.infinispan.commons.api.query.Query; -import org.infinispan.query.dsl.QueryResult; +import org.infinispan.commons.api.query.QueryResult; public final class QueryHelper { @@ -195,7 +195,7 @@ public final class QueryHelper { return; } currentOffset += resultList.size(); - if (rsp.count().isExact() && currentOffset >= rsp.count().value()) { + if (rsp.count().exact() && currentOffset >= rsp.count().value()) { completed = true; return; } diff --git a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remote/RemoteUserSessionProvider.java b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remote/RemoteUserSessionProvider.java index 84ae02f9401..ab18675a087 100644 --- a/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remote/RemoteUserSessionProvider.java +++ b/model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/remote/RemoteUserSessionProvider.java @@ -439,10 +439,10 @@ public class RemoteUserSessionProvider implements UserSessionProvider { private Stream streamUserSessionByClientId(RealmModel realm, String clientId, boolean offline, Integer offset, Integer maxResults) { var userSessionIdQuery = ClientSessionQueries.fetchUserSessionIdForClientId(getClientSessionTransaction(offline).getCache(), realm.getId(), clientId); - if (offset != null) { + if (offset != null && offset > -1) { userSessionIdQuery.startOffset(offset); } - userSessionIdQuery.maxResults(maxResults == null ? Integer.MAX_VALUE : maxResults); + userSessionIdQuery.maxResults(maxResults == null || maxResults == -1 ? Integer.MAX_VALUE : maxResults); var userSessionTx = getUserSessionTransaction(offline); return Flowable.fromIterable(QueryHelper.toCollection(userSessionIdQuery, QueryHelper.SINGLE_PROJECTION_TO_STRING)) .flatMapMaybe(userSessionTx::maybeGet, false, MAX_CONCURRENT_REQUESTS) diff --git a/model/infinispan/src/main/java/org/keycloak/spi/infinispan/impl/embedded/CacheConfigurator.java b/model/infinispan/src/main/java/org/keycloak/spi/infinispan/impl/embedded/CacheConfigurator.java index 62c942d74b2..489fe371a39 100644 --- a/model/infinispan/src/main/java/org/keycloak/spi/infinispan/impl/embedded/CacheConfigurator.java +++ b/model/infinispan/src/main/java/org/keycloak/spi/infinispan/impl/embedded/CacheConfigurator.java @@ -33,6 +33,7 @@ import org.keycloak.models.sessions.infinispan.entities.RemoteUserSessionEntity; import org.keycloak.models.sessions.infinispan.entities.RootAuthenticationSessionEntity; import org.infinispan.commons.dataconversion.MediaType; +import org.infinispan.commons.util.TimeQuantity; import org.infinispan.configuration.cache.AbstractStoreConfiguration; import org.infinispan.configuration.cache.BackupConfiguration; import org.infinispan.configuration.cache.BackupFailurePolicy; @@ -394,13 +395,17 @@ public final class CacheConfigurator { } private static ConfigurationBuilder remoteCacheConfigurationBuilder(String name, Config.Scope config, String[] sites, Class indexedEntity, long expirationWakeupPeriodMillis) { + return remoteCacheConfigurationBuilder(name, config, sites, indexedEntity, TimeQuantity.valueOf(expirationWakeupPeriodMillis)); + } + + private static ConfigurationBuilder remoteCacheConfigurationBuilder(String name, Config.Scope config, String[] sites, Class indexedEntity, TimeQuantity expirationWakeupPeriod) { var builder = new ConfigurationBuilder(); builder.clustering().cacheMode(CacheMode.DIST_SYNC); builder.clustering().hash().numOwners(Math.max(MIN_NUM_OWNERS_REMOTE_CACHE, config.getInt(numOwnerConfigKey(name), MIN_NUM_OWNERS_REMOTE_CACHE))); builder.clustering().stateTransfer().chunkSize(STATE_TRANSFER_CHUNK_SIZE); builder.encoding().mediaType(MediaType.APPLICATION_PROTOSTREAM); builder.statistics().enable(); - builder.expiration().enableReaper().wakeUpInterval(expirationWakeupPeriodMillis); + builder.expiration().enableReaper().wakeUpInterval(expirationWakeupPeriod.longValue()); if (indexedEntity != null) { builder.indexing().enable().addIndexedEntities(Marshalling.protoEntity(indexedEntity)); diff --git a/model/infinispan/src/main/java/org/keycloak/spi/infinispan/impl/embedded/DefaultCacheEmbeddedConfigProviderFactory.java b/model/infinispan/src/main/java/org/keycloak/spi/infinispan/impl/embedded/DefaultCacheEmbeddedConfigProviderFactory.java index cc4f8991e7a..835a51058fb 100644 --- a/model/infinispan/src/main/java/org/keycloak/spi/infinispan/impl/embedded/DefaultCacheEmbeddedConfigProviderFactory.java +++ b/model/infinispan/src/main/java/org/keycloak/spi/infinispan/impl/embedded/DefaultCacheEmbeddedConfigProviderFactory.java @@ -241,8 +241,8 @@ public class DefaultCacheEmbeddedConfigProviderFactory implements CacheEmbeddedC .meterRegistry(Metrics.globalRegistry); builder.cacheContainer().statistics(true); builder.metrics() - .namesAsTags(true) - .histograms(keycloakConfig.getBoolean(HISTOGRAMS, Boolean.FALSE)); + .histograms(keycloakConfig.getBoolean(HISTOGRAMS, Boolean.FALSE)) + .legacy(true); holder.getNamedConfigurationBuilders() .values() .stream() diff --git a/model/infinispan/src/main/resources/default-configs/default-keycloak-jgroups-udp.xml b/model/infinispan/src/main/resources/default-configs/default-keycloak-jgroups-udp.xml deleted file mode 100644 index 9f6d6bf0376..00000000000 --- a/model/infinispan/src/main/resources/default-configs/default-keycloak-jgroups-udp.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/operator/src/test/resources/cache-ispn.xml b/operator/src/test/resources/cache-ispn.xml index b3920d7cf8c..4a845d5378e 100644 --- a/operator/src/test/resources/cache-ispn.xml +++ b/operator/src/test/resources/cache-ispn.xml @@ -18,8 +18,8 @@ + xsi:schemaLocation="urn:infinispan:config:16.0 https://infinispan.org/schemas/infinispan-config-16.0.xsd" + xmlns="urn:infinispan:config:16.0"> diff --git a/pom.xml b/pom.xml index 20d1f0be379..ca559805cc2 100644 --- a/pom.xml +++ b/pom.xml @@ -91,9 +91,9 @@ 2.4.240 6.2.13.Final 6.2.13.Final - 15.0.19.Final 9.0.1.Final - 5.0.14.Final + 16.0.5 + 6.0.3 ${protostream.version} diff --git a/quarkus/runtime/pom.xml b/quarkus/runtime/pom.xml index 54bfaa67657..c92b7a387f4 100644 --- a/quarkus/runtime/pom.xml +++ b/quarkus/runtime/pom.xml @@ -672,16 +672,6 @@ infinispan-component-annotations provided - - - org.infinispan - infinispan-remote-query-client - - - - org.infinispan - infinispan-query-dsl - jakarta.xml.bind jakarta.xml.bind-api diff --git a/quarkus/runtime/src/main/resources/cache-ispn.xml b/quarkus/runtime/src/main/resources/cache-ispn.xml index b3920d7cf8c..4a845d5378e 100644 --- a/quarkus/runtime/src/main/resources/cache-ispn.xml +++ b/quarkus/runtime/src/main/resources/cache-ispn.xml @@ -18,8 +18,8 @@ + xsi:schemaLocation="urn:infinispan:config:16.0 https://infinispan.org/schemas/infinispan-config-16.0.xsd" + xmlns="urn:infinispan:config:16.0"> diff --git a/quarkus/runtime/src/main/resources/cache-local.xml b/quarkus/runtime/src/main/resources/cache-local.xml index d1e33c30eae..68839a31407 100644 --- a/quarkus/runtime/src/main/resources/cache-local.xml +++ b/quarkus/runtime/src/main/resources/cache-local.xml @@ -18,7 +18,7 @@ + xsi:schemaLocation="urn:infinispan:config:16.0 https://infinispan.org/schemas/infinispan-config-16.0.xsd" + xmlns="urn:infinispan:config:16.0"> diff --git a/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/ClusterConfigKeepAliveDistTest.java b/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/ClusterConfigKeepAliveDistTest.java index 24cc58c271e..86aceddc9db 100644 --- a/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/ClusterConfigKeepAliveDistTest.java +++ b/quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/ClusterConfigKeepAliveDistTest.java @@ -148,9 +148,7 @@ public class ClusterConfigKeepAliveDistTest { .prettyPrint(); ConfigurationBuilderHolder configHolder = new ParserRegistry().parse(configJson, MediaType.APPLICATION_JSON); - // Workaround for ISPN-16595 - String cacheName = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, cache); - return configHolder.getNamedConfigurationBuilders().get(cacheName).build(); + return configHolder.getNamedConfigurationBuilders().get(cache).build(); } private record CacheOwners(String name, int owners) { diff --git a/quarkus/tests/integration/src/test/resources/ExternalInfinispan/kcb-infinispan-cache-remote-store-config.xml b/quarkus/tests/integration/src/test/resources/ExternalInfinispan/kcb-infinispan-cache-remote-store-config.xml deleted file mode 100644 index 213f4f6d215..00000000000 --- a/quarkus/tests/integration/src/test/resources/ExternalInfinispan/kcb-infinispan-cache-remote-store-config.xml +++ /dev/null @@ -1,263 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/quarkus/tests/integration/src/test/resources/cache-ispn-custom-cache.xml b/quarkus/tests/integration/src/test/resources/cache-ispn-custom-cache.xml index 72b8e052693..afef3e95cc0 100644 --- a/quarkus/tests/integration/src/test/resources/cache-ispn-custom-cache.xml +++ b/quarkus/tests/integration/src/test/resources/cache-ispn-custom-cache.xml @@ -18,8 +18,8 @@ + xsi:schemaLocation="urn:infinispan:config:16.0 https://infinispan.org/schemas/infinispan-config-16.0.xsd" + xmlns="urn:infinispan:config:16.0"> diff --git a/quarkus/tests/integration/src/test/resources/cache-ispn-custom-user-cache.xml b/quarkus/tests/integration/src/test/resources/cache-ispn-custom-user-cache.xml index fa936dfead4..62eb211b23f 100644 --- a/quarkus/tests/integration/src/test/resources/cache-ispn-custom-user-cache.xml +++ b/quarkus/tests/integration/src/test/resources/cache-ispn-custom-user-cache.xml @@ -18,8 +18,8 @@ + xsi:schemaLocation="urn:infinispan:config:16.0 https://infinispan.org/schemas/infinispan-config-16.0.xsd" + xmlns="urn:infinispan:config:16.0"> diff --git a/quarkus/tests/junit5/pom.xml b/quarkus/tests/junit5/pom.xml index 4446135b1f6..b54c1017a5b 100644 --- a/quarkus/tests/junit5/pom.xml +++ b/quarkus/tests/junit5/pom.xml @@ -57,9 +57,8 @@ org.infinispan - infinispan-server-testdriver-core + testcontainers-infinispan - junit junit diff --git a/quarkus/tests/junit5/src/main/java/org/keycloak/it/junit5/extension/CLITestExtension.java b/quarkus/tests/junit5/src/main/java/org/keycloak/it/junit5/extension/CLITestExtension.java index 5c2d02f85a8..fe654a76d58 100644 --- a/quarkus/tests/junit5/src/main/java/org/keycloak/it/junit5/extension/CLITestExtension.java +++ b/quarkus/tests/junit5/src/main/java/org/keycloak/it/junit5/extension/CLITestExtension.java @@ -345,7 +345,12 @@ public class CLITestExtension extends QuarkusMainTestExtension { private static InfinispanContainer configureExternalInfinispan(ExtensionContext context) { if (getAnnotationFromTestContext(context, WithExternalInfinispan.class) != null) { InfinispanContainer infinispanContainer = new InfinispanContainer(); - infinispanContainer.start(); + try { + infinispanContainer.start(); + } catch (RuntimeException e) { + infinispanContainer.stop(); + throw e; + } return infinispanContainer; } diff --git a/quarkus/tests/junit5/src/main/java/org/keycloak/it/junit5/extension/InfinispanContainer.java b/quarkus/tests/junit5/src/main/java/org/keycloak/it/junit5/extension/InfinispanContainer.java index 0636f9655a6..24a0c1b9b47 100644 --- a/quarkus/tests/junit5/src/main/java/org/keycloak/it/junit5/extension/InfinispanContainer.java +++ b/quarkus/tests/junit5/src/main/java/org/keycloak/it/junit5/extension/InfinispanContainer.java @@ -21,12 +21,14 @@ import java.util.Arrays; import org.keycloak.connections.infinispan.InfinispanConnectionProvider; +import com.github.dockerjava.api.command.InspectContainerResponse; import org.infinispan.client.hotrod.RemoteCacheManager; +import org.infinispan.client.hotrod.configuration.ConfigurationBuilder; import org.infinispan.commons.configuration.StringConfiguration; import org.jboss.logging.Logger; import org.testcontainers.images.PullPolicy; -public class InfinispanContainer extends org.infinispan.server.test.core.InfinispanContainer { +public class InfinispanContainer extends org.infinispan.testcontainers.InfinispanContainer { private final Logger LOG = Logger.getLogger(getClass()); public static final String PORT = System.getProperty("keycloak.externalInfinispan.port", "11222"); @@ -50,7 +52,6 @@ public class InfinispanContainer extends org.infinispan.server.test.core.Infinis if (getImageName().startsWith("quay.io/infinispan-test")) { withImagePullPolicy(PullPolicy.alwaysPull()); } - } private static String getImageName() { @@ -72,17 +73,23 @@ public class InfinispanContainer extends org.infinispan.server.test.core.Infinis remoteCacheManager.administration().removeCache(cache); } - private void establishHotRodConnection() { - remoteCacheManager = getRemoteCacheManager(); - } - @Override public void start() { logger().info("Starting ISPN container"); super.start(); - establishHotRodConnection(); + remoteCacheManager = new RemoteCacheManager( + new ConfigurationBuilder() + .addServer() + .host(getHost()) + .port(getMappedPort(DEFAULT_HOTROD_PORT)) + .security() + .authentication() + .username(getEnvMap().get(USER)) + .password(getEnvMap().get(PASS)) + .build() + ); Arrays.stream(InfinispanConnectionProvider.CLUSTERED_CACHE_NAMES) .forEach(cacheName -> { @@ -91,6 +98,27 @@ public class InfinispanContainer extends org.infinispan.server.test.core.Infinis }); } + @Override + protected void containerIsStopping(InspectContainerResponse containerInfo) { + // graceful shutdown + if (containerInfo.getState() != null && Boolean.TRUE.equals(containerInfo.getState().getRunning())) { + dockerClient.killContainerCmd(getContainerId()).withSignal("TERM").exec(); + } + + while (true) { + InspectContainerResponse info = dockerClient.inspectContainerCmd(getContainerId()).exec(); + if (!(info.getState() != null && Boolean.TRUE.equals(info.getState().getRunning()))) { + break; + } + try { + Thread.sleep(100); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + } + } + @Override public void stop() { logger().info("Stopping ISPN container"); diff --git a/test-framework/clustering/src/main/java/org/keycloak/testframework/server/ClusteredKeycloakServer.java b/test-framework/clustering/src/main/java/org/keycloak/testframework/server/ClusteredKeycloakServer.java index d921e5a3024..54e10c36eea 100644 --- a/test-framework/clustering/src/main/java/org/keycloak/testframework/server/ClusteredKeycloakServer.java +++ b/test-framework/clustering/src/main/java/org/keycloak/testframework/server/ClusteredKeycloakServer.java @@ -27,7 +27,6 @@ import org.keycloak.testframework.clustering.LoadBalancer; import org.keycloak.testframework.infinispan.CacheType; import org.keycloak.testframework.logging.JBossLogConsumer; -import org.infinispan.server.test.core.CountdownLatchLoggingConsumer; import org.jboss.logging.Logger; import org.testcontainers.images.RemoteDockerImage; import org.testcontainers.utility.DockerImageName; diff --git a/test-framework/clustering/src/main/java/org/keycloak/testframework/server/CountdownLatchLoggingConsumer.java b/test-framework/clustering/src/main/java/org/keycloak/testframework/server/CountdownLatchLoggingConsumer.java new file mode 100644 index 00000000000..c8c480ec41f --- /dev/null +++ b/test-framework/clustering/src/main/java/org/keycloak/testframework/server/CountdownLatchLoggingConsumer.java @@ -0,0 +1,34 @@ +package org.keycloak.testframework.server; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.regex.Pattern; + +import org.testcontainers.containers.output.BaseConsumer; +import org.testcontainers.containers.output.OutputFrame; + +class CountdownLatchLoggingConsumer extends BaseConsumer { + + private final CountDownLatch latch; + private final Pattern pattern; + + public CountdownLatchLoggingConsumer(int count, String regex) { + this.latch = new CountDownLatch(count); + this.pattern = Pattern.compile(regex, Pattern.DOTALL); + } + + @Override + public void accept(OutputFrame outputFrame) { + String log = outputFrame.getUtf8String(); + if (pattern.matcher(log).matches()) { + latch.countDown(); + } + } + + public void await(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException { + if (!latch.await(timeout, unit)) { + throw new TimeoutException(String.format("After the await period %d %s the count down should be 0 and is %d", timeout, unit, latch.getCount())); + } + } +} diff --git a/test-framework/core/src/main/java/org/keycloak/testframework/infinispan/InfinispanExternalServer.java b/test-framework/core/src/main/java/org/keycloak/testframework/infinispan/InfinispanExternalServer.java index b21b5142b59..f37ff898b27 100644 --- a/test-framework/core/src/main/java/org/keycloak/testframework/infinispan/InfinispanExternalServer.java +++ b/test-framework/core/src/main/java/org/keycloak/testframework/infinispan/InfinispanExternalServer.java @@ -5,7 +5,7 @@ import java.util.Map; import org.keycloak.testframework.logging.JBossLogConsumer; import org.keycloak.testframework.util.ContainerImages; -import org.infinispan.server.test.core.InfinispanContainer; +import org.infinispan.testcontainers.InfinispanContainer; import org.jboss.logging.Logger; public class InfinispanExternalServer extends InfinispanContainer implements InfinispanServer { diff --git a/tests/base/src/test/resources/embedded-infinispan-config/infinispan-xml-kc26.xml b/tests/base/src/test/resources/embedded-infinispan-config/infinispan-xml-kc26.xml index 377591d7154..fa7f8ab28ed 100644 --- a/tests/base/src/test/resources/embedded-infinispan-config/infinispan-xml-kc26.xml +++ b/tests/base/src/test/resources/embedded-infinispan-config/infinispan-xml-kc26.xml @@ -18,8 +18,8 @@ + xsi:schemaLocation="urn:infinispan:config:16.0 https://infinispan.org/schemas/infinispan-config-16.0.xsd" + xmlns="urn:infinispan:config:16.0"> diff --git a/testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/cluster-ha.xml b/testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/cluster-ha.xml index aef111f5f88..25c7edcf83f 100644 --- a/testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/cluster-ha.xml +++ b/testsuite/integration-arquillian/servers/auth-server/quarkus/src/main/content/conf/cluster-ha.xml @@ -18,63 +18,17 @@ + xsi:schemaLocation="urn:infinispan:config:16.0 https://www.infinispan.org/schemas/infinispan-config-16.0.xsd" + xmlns="urn:infinispan:config:16.0"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/testsuite/model/pom.xml b/testsuite/model/pom.xml index 112bb5658ae..bc481e80e62 100644 --- a/testsuite/model/pom.xml +++ b/testsuite/model/pom.xml @@ -119,11 +119,6 @@ infinispan-component-annotations provided - - org.infinispan - infinispan-remote-query-server - - org.awaitility awaitility diff --git a/testsuite/model/src/main/java/org/keycloak/testsuite/model/HotRodServerRule.java b/testsuite/model/src/main/java/org/keycloak/testsuite/model/HotRodServerRule.java index b9b5e9e25a5..f8a6fd72da5 100644 --- a/testsuite/model/src/main/java/org/keycloak/testsuite/model/HotRodServerRule.java +++ b/testsuite/model/src/main/java/org/keycloak/testsuite/model/HotRodServerRule.java @@ -69,10 +69,13 @@ public class HotRodServerRule extends ExternalResource { HotRodServerConfiguration build = new HotRodServerConfigurationBuilder().build(); hotRodServer = new HotRodServer(); hotRodServer.start(build, hotRodCacheManager); + hotRodServer.postStart(); HotRodServerConfiguration build2 = new HotRodServerConfigurationBuilder().port(11333).build(); hotRodServer2 = new HotRodServer(); hotRodServer2.start(build2, hotRodCacheManager2); + hotRodServer2.postStart(); + // Create a Hot Rod client org.infinispan.client.hotrod.configuration.ConfigurationBuilder remoteBuilder = new org.infinispan.client.hotrod.configuration.ConfigurationBuilder(); diff --git a/testsuite/model/src/test/resources/test-ispn.xml b/testsuite/model/src/test/resources/test-ispn.xml index b305b4cd68e..a47407a5c49 100644 --- a/testsuite/model/src/test/resources/test-ispn.xml +++ b/testsuite/model/src/test/resources/test-ispn.xml @@ -18,16 +18,16 @@ + xsi:schemaLocation="urn:infinispan:config:16.0 https://infinispan.org/schemas/infinispan-config-16.0.xsd + urn:org:jgroups http://www.jgroups.org/schema/jgroups-5.4.xsd" + xmlns="urn:infinispan:config:16.0" + xmlns:ispn="urn:infinispan:config:16.0"> diff --git a/testsuite/utils/src/main/resources/cluster-test-ispn.xml b/testsuite/utils/src/main/resources/cluster-test-ispn.xml index 043f47c0067..a3915e10d76 100644 --- a/testsuite/utils/src/main/resources/cluster-test-ispn.xml +++ b/testsuite/utils/src/main/resources/cluster-test-ispn.xml @@ -18,10 +18,10 @@ + xsi:schemaLocation="urn:infinispan:config:16.0 https://infinispan.org/schemas/infinispan-config-16.0.xsd + urn:org:jgroups http://www.jgroups.org/schema/jgroups-5.4.xsd" + xmlns="urn:infinispan:config:16.0" + xmlns:ispn="urn:infinispan:config:16.0"> @@ -30,7 +30,7 @@ diff --git a/testsuite/utils/src/main/resources/local-test-ispn.xml b/testsuite/utils/src/main/resources/local-test-ispn.xml index c42b3b91525..cb6ac3a48c7 100644 --- a/testsuite/utils/src/main/resources/local-test-ispn.xml +++ b/testsuite/utils/src/main/resources/local-test-ispn.xml @@ -18,8 +18,8 @@ + xsi:schemaLocation="urn:infinispan:config:16.0 https://infinispan.org/schemas/infinispan-config-16.0.xsd" + xmlns="urn:infinispan:config:16.0">