Skip to content

Instantly share code, notes, and snippets.

@thomasdarimont
Last active July 4, 2024 11:38
Show Gist options
  • Save thomasdarimont/63cafa87b417cb5b3e6f9e6e04e64467 to your computer and use it in GitHub Desktop.
Save thomasdarimont/63cafa87b417cb5b3e6f9e6e04e64467 to your computer and use it in GitHub Desktop.
Example for using datasource_injecter_class in with Keycloak 25.0.1, JGroups 5.3.7 and JDBC_PING
  1. Download jgroups 5.3.7.Final
wget -O jgroups-5.3.7.Final.jar https://search.maven.org/remotecontent\?filepath\=org/jgroups/jgroups/5.3.7.Final/jgroups-5.3.7.Final.jar
  1. Build above class into a jgroups-extensions jar
  2. Run the container
docker compose up

Look for the log line:

...  [org.keycloak.support.jgroups.DataSourceProvider] (ForkJoinPool.commonPool-worker-1) Obtained DataSource from Keycloak server
<?xml version="1.0" encoding="UTF-8"?>
<infinispan
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:infinispan:config:14.0 http://www.infinispan.org/schemas/infinispan-config-14.0.xsd"
xmlns="urn:infinispan:config:14.0">
<!-- https://github.com/infinispan/infinispan.github.io/tree/develop/schemas -->
<!-- custom stack goes into the jgroups element -->
<jgroups>
<stack name="jdbc-ping-tcp" extends="tcp">
<!-- TCP local cluster with JDBCPING discovery -->
<JDBC_PING datasource_injecter_class="org.keycloak.support.jgroups.DataSourceProvider"
initialize_sql="CREATE TABLE IF NOT EXISTS JGROUPSPING (own_addr varchar(200) NOT NULL, cluster_name varchar(200) NOT NULL, ping_data BYTEA, constraint PK_JGROUPSPING PRIMARY KEY (own_addr, cluster_name));"
info_writer_sleep_time="500"
remove_all_data_on_view_change="true"
stack.combine="REPLACE"
stack.position="MPING" />
</stack>
</jgroups>
<cache-container name="keycloak">
<transport lock-timeout="60000" stack="jdbc-ping-tcp"/>
<local-cache name="realms" simple-cache="true">
<encoding>
<key media-type="application/x-java-object"/>
<value media-type="application/x-java-object"/>
</encoding>
<memory max-count="10000"/>
</local-cache>
<local-cache name="users" simple-cache="true">
<encoding>
<key media-type="application/x-java-object"/>
<value media-type="application/x-java-object"/>
</encoding>
<memory max-count="10000"/>
</local-cache>
<distributed-cache name="sessions" owners="2">
<expiration lifespan="-1"/>
</distributed-cache>
<distributed-cache name="authenticationSessions" owners="2">
<expiration lifespan="-1"/>
</distributed-cache>
<distributed-cache name="offlineSessions" owners="2">
<expiration lifespan="-1"/>
</distributed-cache>
<distributed-cache name="clientSessions" owners="2">
<expiration lifespan="-1"/>
</distributed-cache>
<distributed-cache name="offlineClientSessions" owners="2">
<expiration lifespan="-1"/>
</distributed-cache>
<distributed-cache name="loginFailures" owners="2">
<expiration lifespan="-1"/>
</distributed-cache>
<local-cache name="authorization" simple-cache="true">
<encoding>
<key media-type="application/x-java-object"/>
<value media-type="application/x-java-object"/>
</encoding>
<memory max-count="10000"/>
</local-cache>
<replicated-cache name="work">
<expiration lifespan="-1"/>
</replicated-cache>
<local-cache name="keys" simple-cache="true">
<encoding>
<key media-type="application/x-java-object"/>
<value media-type="application/x-java-object"/>
</encoding>
<expiration max-idle="3600000"/>
<memory max-count="1000"/>
</local-cache>
<distributed-cache name="actionTokens" owners="2">
<encoding>
<key media-type="application/x-java-object"/>
<value media-type="application/x-java-object"/>
</encoding>
<expiration max-idle="-1" lifespan="-1" interval="300000"/>
<memory max-count="-1"/>
</distributed-cache>
</cache-container>
</infinispan>
package org.keycloak.support.jgroups;
import jakarta.enterprise.inject.spi.CDI;
import org.jboss.logging.Logger;
import org.jgroups.protocols.JDBC_PING;
import javax.sql.DataSource;
import java.util.function.Function;
public class DataSourceProvider implements Function<JDBC_PING, DataSource> {
private static final Logger LOG = Logger.getLogger(DataSourceProvider.class);
@Override
public DataSource apply(JDBC_PING jdbcPing) {
DataSource dataSource = CDI.current().select(DataSource.class).get();
if (dataSource != null) {
LOG.info("Obtained DataSource from Keycloak server");
} else {
LOG.errorf("Could not obtain DataSource from Keycloak server");
}
return dataSource;
}
}
volumes:
postgres_data:
driver: local
services:
postgres:
image: postgres:15
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: password
ports:
- 5433:5432
healthcheck:
test: ["CMD-SHELL", "pg_isready -U keycloak"]
interval: 10s
timeout: 5s
retries: 5
keycloak:
image: quay.io/keycloak/keycloak:25.0.1
environment:
KEYCLOAK_ADMIN: admin
KC_DB: postgres
KEYCLOAK_ADMIN_PASSWORD: admin
KC_DB_SCHEMA: public
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: password
KC_DB_URL: jdbc:postgresql://postgres/keycloak
KC_HOSTNAME_STRICT: "false"
KC_HTTP_ENABLED: "true"
KC_HTTP_RELATIVE_PATH: /auth
KC_LOG_LEVEL: "INFO,org.infinispan:INFO,org.jgroups:DEBUG"
KC_METRICS_ENABLED: "true"
KC_HEALTH_ENABLED: "true"
KC_FEATURES: preview
# specify the custom cache config file here
QUARKUS_NAMING_ENABLE_JNDI: "true"
KC_CACHE_CONFIG_FILE: cache-ispn-jdbc-ping-ds-provider.xml
JAVA_OPTS_APPEND: "-Xms512m -Xmx1524m -Djgroups.thread_dumps_threshold=1"
volumes:
- ./cache-ispn-jdbc-ping-ds-provider.xml:/opt/keycloak/conf/cache-ispn-jdbc-ping-ds-provider.xml:z
- ./jgroups-5.3.7.Final.jar:/opt/keycloak/lib/lib/main/org.jgroups.jgroups-5.3.6.Final.jar:z
- ./jgroups-extensions/target/jgroups-extensions.jar:/opt/keycloak/providers/jgroups-extensions.jar:z
ports:
- 8080:8080
- 8443:8443
command:
- "--verbose"
- "start-dev"
depends_on:
- postgres
$ docker compose up --remove-orphans
[+] Running 2/0
✔ Container keycloakx-jdbcping-minimal-postgres-1 Created 0.0s
✔ Container keycloakx-jdbcping-minimal-keycloak-1 Recreated 0.1s
Attaching to keycloak-1, postgres-1
postgres-1 |
postgres-1 | PostgreSQL Database directory appears to contain a database; Skipping initialization
postgres-1 |
postgres-1 | 2024-07-04 11:32:21.670 UTC [1] LOG: starting PostgreSQL 15.4 (Debian 15.4-2.pgdg120+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit
postgres-1 | 2024-07-04 11:32:21.670 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432
postgres-1 | 2024-07-04 11:32:21.670 UTC [1] LOG: listening on IPv6 address "::", port 5432
postgres-1 | 2024-07-04 11:32:21.674 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
postgres-1 | 2024-07-04 11:32:21.680 UTC [29] LOG: database system was shut down at 2024-07-04 11:31:31 UTC
postgres-1 | 2024-07-04 11:32:21.689 UTC [1] LOG: database system is ready to accept connections
keycloak-1 | Appending additional Java properties to JAVA_OPTS
keycloak-1 | Updating the configuration and installing your custom providers, if any. Please wait.
keycloak-1 | 2024-07-04 11:32:22,508 INFO [org.key.com.Profile] (main) Preview features enabled: admin-fine-grained-authz:v1, client-secret-rotation:v1, dpop:v1, organization:v1, passkeys:v1, persistent-user-sessions:v1, recovery-codes:v1, scripts:v1, token-exchange:v1, update-email:v1
keycloak-1 | 2024-07-04 11:32:23,429 INFO [org.key.com.Profile] (main) Preview features enabled: admin-fine-grained-authz:v1, client-secret-rotation:v1, dpop:v1, organization:v1, passkeys:v1, persistent-user-sessions:v1, recovery-codes:v1, scripts:v1, token-exchange:v1, update-email:v1
keycloak-1 | 2024-07-04 11:32:32,073 INFO [io.qua.dep.QuarkusAugmentor] (main) Quarkus augmentation completed in 8962ms
keycloak-1 | 2024-07-04 11:32:32,693 INFO [org.keycloak.common.Profile] (main) Preview features enabled: admin-fine-grained-authz:v1, client-secret-rotation:v1, dpop:v1, organization:v1, passkeys:v1, persistent-user-sessions:v1, recovery-codes:v1, scripts:v1, token-exchange:v1, update-email:v1
keycloak-1 | 2024-07-04 11:32:32,799 INFO [org.keycloak.common.Profile] (main) Preview features enabled: admin-fine-grained-authz:v1, client-secret-rotation:v1, dpop:v1, organization:v1, passkeys:v1, persistent-user-sessions:v1, recovery-codes:v1, scripts:v1, token-exchange:v1, update-email:v1
keycloak-1 | 2024-07-04 11:32:35,016 INFO [org.keycloak.quarkus.runtime.storage.legacy.infinispan.CacheManagerFactory] (main) Persistent user sessions enabled and no memory limit found in configuration. Setting max entries for sessions to 10000 entries.
keycloak-1 | 2024-07-04 11:32:35,016 INFO [org.keycloak.quarkus.runtime.storage.legacy.infinispan.CacheManagerFactory] (main) Persistent user sessions enabled and no memory limit found in configuration. Setting max entries for clientSessions to 10000 entries.
keycloak-1 | 2024-07-04 11:32:35,016 INFO [org.keycloak.quarkus.runtime.storage.legacy.infinispan.CacheManagerFactory] (main) Persistent user sessions enabled and no memory limit found in configuration. Setting max entries for offlineSessions to 10000 entries.
keycloak-1 | 2024-07-04 11:32:35,017 INFO [org.keycloak.quarkus.runtime.storage.legacy.infinispan.CacheManagerFactory] (main) Persistent user sessions enabled and no memory limit found in configuration. Setting max entries for offlineClientSessions to 10000 entries.
keycloak-1 | 2024-07-04 11:32:35,353 INFO [org.infinispan.CONTAINER] (ForkJoinPool.commonPool-worker-1) ISPN000556: Starting user marshaller 'org.infinispan.jboss.marshalling.core.JBossUserMarshaller'
keycloak-1 | 2024-07-04 11:32:35,662 DEBUG [org.jgroups.protocols.TCP] (ForkJoinPool.commonPool-worker-1) thread pool min/max/keep-alive (ms): 0/200/60000
keycloak-1 | 2024-07-04 11:32:35,666 DEBUG [org.jgroups.stack.Configurator] (ForkJoinPool.commonPool-worker-1) set property [email protected]_addr to default value /224.0.75.75
keycloak-1 | 2024-07-04 11:32:35,667 INFO [org.keycloak.support.jgroups.DataSourceProvider] (ForkJoinPool.commonPool-worker-1) Obtained DataSource from Keycloak server
keycloak-1 | 2024-07-04 11:32:35,687 DEBUG [org.jgroups.protocols.JDBC_PING] (ForkJoinPool.commonPool-worker-1) Table created for JDBC_PING Discovery Protocol
keycloak-1 | 2024-07-04 11:32:35,691 INFO [org.infinispan.CLUSTER] (ForkJoinPool.commonPool-worker-1) ISPN000078: Starting JGroups channel `ISPN` with stack `jdbc-ping-tcp`
keycloak-1 | 2024-07-04 11:32:35,693 INFO [org.jgroups.JChannel] (ForkJoinPool.commonPool-worker-1) local_addr: 3e03cb49-bdfb-44de-8f2c-0b2a24a47d4c, name: 0c20d7dab5fe-57406
keycloak-1 | 2024-07-04 11:32:35,700 INFO [org.jgroups.protocols.FD_SOCK2] (ForkJoinPool.commonPool-worker-1) server listening on *.57800
keycloak-1 | 2024-07-04 11:32:35,702 DEBUG [org.jgroups.protocols.pbcast.GMS] (ForkJoinPool.commonPool-worker-1) address=0c20d7dab5fe-57406, cluster=ISPN, physical address=192.168.96.3:7800
keycloak-1 | 2024-07-04 11:32:35,727 DEBUG [org.jgroups.protocols.JDBC_PING] (ForkJoinPool.commonPool-worker-1) Removed 3e03cb49-bdfb-44de-8f2c-0b2a24a47d4c for cluster ISPN from database
keycloak-1 | 2024-07-04 11:32:35,733 DEBUG [org.jgroups.protocols.JDBC_PING] (ForkJoinPool.commonPool-worker-1) Inserted 3e03cb49-bdfb-44de-8f2c-0b2a24a47d4c for cluster ISPN into database
keycloak-1 | 2024-07-04 11:32:35,734 INFO [org.jgroups.protocols.pbcast.GMS] (ForkJoinPool.commonPool-worker-1) 0c20d7dab5fe-57406: no members discovered after 31 ms: creating cluster as coordinator
keycloak-1 | 2024-07-04 11:32:35,736 DEBUG [org.jgroups.protocols.pbcast.NAKACK2] (ForkJoinPool.commonPool-worker-1)
keycloak-1 | [0c20d7dab5fe-57406 setDigest()]
keycloak-1 | existing digest: []
keycloak-1 | new digest: 0c20d7dab5fe-57406: [0 (0)]
keycloak-1 | resulting digest: 0c20d7dab5fe-57406: [0 (0)]
keycloak-1 | 2024-07-04 11:32:35,737 DEBUG [org.jgroups.protocols.pbcast.GMS] (ForkJoinPool.commonPool-worker-1) 0c20d7dab5fe-57406: installing view [0c20d7dab5fe-57406|0] (1) [0c20d7dab5fe-57406] (0c20d7dab5fe-57406 joined)
keycloak-1 | 2024-07-04 11:32:35,738 DEBUG [org.jgroups.protocols.pbcast.STABLE] (ForkJoinPool.commonPool-worker-1) 0c20d7dab5fe-57406: resuming message garbage collection
keycloak-1 | 2024-07-04 11:32:35,743 DEBUG [org.jgroups.protocols.JDBC_PING] (ForkJoinPool.commonPool-worker-1) 0c20d7dab5fe-57406: cleared table for cluster ISPN
keycloak-1 | 2024-07-04 11:32:35,745 DEBUG [org.jgroups.protocols.JDBC_PING] (ForkJoinPool.commonPool-worker-1) Removed 3e03cb49-bdfb-44de-8f2c-0b2a24a47d4c for cluster ISPN from database
keycloak-1 | 2024-07-04 11:32:35,746 DEBUG [org.jgroups.protocols.JDBC_PING] (ForkJoinPool.commonPool-worker-1) Inserted 3e03cb49-bdfb-44de-8f2c-0b2a24a47d4c for cluster ISPN into database
keycloak-1 | 2024-07-04 11:32:35,752 INFO [org.infinispan.CLUSTER] (ForkJoinPool.commonPool-worker-1) ISPN000094: Received new cluster view for channel ISPN: [0c20d7dab5fe-57406|0] (1) [0c20d7dab5fe-57406]
keycloak-1 | 2024-07-04 11:32:35,773 DEBUG [org.jgroups.protocols.pbcast.GMS] (ForkJoinPool.commonPool-worker-1) 0c20d7dab5fe-57406: created cluster (first member). My view is [0c20d7dab5fe-57406|0], impl is CoordGmsImpl
keycloak-1 | 2024-07-04 11:32:35,781 ERROR [org.jgroups.JChannel] (ForkJoinPool.commonPool-worker-1) JGRP000016: exception in channelConnected callback: java.lang.NoSuchMethodError: 'int org.jgroups.protocols.pbcast.STABLE.getStableSent()'
keycloak-1 | 2024-07-04 11:32:35,781 INFO [org.infinispan.CLUSTER] (ForkJoinPool.commonPool-worker-1) ISPN000079: Channel `ISPN` local address is `0c20d7dab5fe-57406`, physical addresses are `[192.168.96.3:7800]`
keycloak-1 | 2024-07-04 11:32:36,326 INFO [org.keycloak.connections.infinispan.DefaultInfinispanConnectionProviderFactory] (main) Node name: 0c20d7dab5fe-57406, Site name: null
keycloak-1 | 2024-07-04 11:32:36,330 INFO [org.keycloak.broker.provider.AbstractIdentityProviderMapper] (main) Registering class org.keycloak.broker.provider.mappersync.ConfigSyncEventListener
keycloak-1 | 2024-07-04 11:32:36,761 DEBUG [org.jgroups.protocols.JDBC_PING] (jgroups-6,0c20d7dab5fe-57406) Removed 3e03cb49-bdfb-44de-8f2c-0b2a24a47d4c for cluster ISPN from database
keycloak-1 | 2024-07-04 11:32:36,777 DEBUG [org.jgroups.protocols.JDBC_PING] (jgroups-6,0c20d7dab5fe-57406) Inserted 3e03cb49-bdfb-44de-8f2c-0b2a24a47d4c for cluster ISPN into database
keycloak-1 | 2024-07-04 11:32:37,192 INFO [io.quarkus] (main) Keycloak 25.0.1 on JVM (powered by Quarkus 3.8.5) started in 5.005s. Listening on: http://0.0.0.0:8080. Management interface listening on http://0.0.0.0:9000.
keycloak-1 | 2024-07-04 11:32:37,192 INFO [io.quarkus] (main) Profile dev activated.
keycloak-1 | 2024-07-04 11:32:37,192 INFO [io.quarkus] (main) Installed features: [agroal, cdi, hibernate-orm, jdbc-postgresql, keycloak, logging-gelf, micrometer, narayana-jta, reactive-routes, resteasy-reactive, resteasy-reactive-jackson, smallrye-context-propagation, smallrye-health, vertx]
keycloak-1 | 2024-07-04 11:32:37,196 WARN [org.keycloak.quarkus.runtime.KeycloakMain] (main) Running the server in development mode. DO NOT use this configuration in production.
keycloak-1 | 2024-07-04 11:32:37,781 DEBUG [org.jgroups.protocols.JDBC_PING] (jgroups-5,0c20d7dab5fe-57406) Removed 3e03cb49-bdfb-44de-8f2c-0b2a24a47d4c for cluster ISPN from database
keycloak-1 | 2024-07-04 11:32:37,782 DEBUG [org.jgroups.protocols.JDBC_PING] (jgroups-5,0c20d7dab5fe-57406) Inserted 3e03cb49-bdfb-44de-8f2c-0b2a24a47d4c for cluster ISPN into database
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>jgroups-extensions</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.jgroups</groupId>
<artifactId>jgroups</artifactId>
<version>5.3.7.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
<version>4.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jboss.logging</groupId>
<artifactId>jboss-logging</artifactId>
<version>3.5.3.Final</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>jgroups-extensions</finalName>
</build>
</project>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment