127569ed2f
Closes #14003
271 lines
No EOL
13 KiB
Markdown
271 lines
No EOL
13 KiB
Markdown
# Contributing guide
|
|
|
|
## Keycloak Quarkus Extension
|
|
|
|
Keycloak on Quarkus is basically a Quarkus Extension. For more details about extensions, please take a look at [Writing Your Own Extension](https://quarkus.io/guides/writing-extensions) guide.
|
|
|
|
As an extension, the server can be embedded in any Quarkus application by adding the following dependency:
|
|
|
|
```
|
|
<dependencies>
|
|
<dependency>
|
|
<groupId>org.keycloak</groupId>
|
|
<artifactId>keycloak-quarkus-server</artifactId>
|
|
</dependency>
|
|
</dependencies>
|
|
```
|
|
|
|
Just like any other extension, the server extension has two main modules:
|
|
|
|
* `deployment`
|
|
* `runtime`
|
|
|
|
Within the `deployment` module you'll find the implementation for the build steps that run when (re)augmenting the application. This module
|
|
is responsible for all metadata processing, such as:
|
|
|
|
* Lookup SPIs and their providers and enable/disable them accordingly
|
|
* Create a closed-world assumption about the providers that should be registered to the `KeycloakSessionFactory`
|
|
* Customizations to how Hibernate, Resteasy, Liquibase, Infinispan, and other dependencies are configured and bootstrapped
|
|
* Creating Jandex indexes for some server dependencies
|
|
|
|
The output of this module is bytecode generated by Quarkus that improves the server startup time and memory usage so that any processing
|
|
done during (re)augmentation does not happen again when actually starting the server. Note that the code from this module does
|
|
not run at all at runtime (when running the server) but only when building the project (the `server` module in particular, more on that later) or when triggering
|
|
a re-augmentation when running the `build` command.
|
|
|
|
Within the `runtime` module you'll find the code that is run at runtime when starting and running the server. The main link between
|
|
the `deployment` and `runtime` modules is the `org.keycloak.quarkus.runtime.KeycloakRecorder` class. The `KeycloakRecorder` holds
|
|
a set of methods that are invoked from build steps that will end up in recorded bytecode. The recorded bytecode executes those methods at runtime
|
|
just like they were called when a build step is run, with the exact same arguments and values, if any.
|
|
|
|
As an example, let us look at how the SPIs and their providers are discovered and how the `KeycloakSessionFactory` is created.
|
|
Quarkus will run the `org.keycloak.quarkus.deployment.KeycloakProcessor.configureProviders` build step whenever you are (re)augmenting the server. The main outcome from this method
|
|
is to invoke the `org.keycloak.quarkus.runtime.KeycloakRecorder.configSessionFactory` so that the code from this method is executed at
|
|
*runtime* with a closed-world assumption about the providers that should be registered to the `KeycloakSessionFactory`. At runtime the code from that method is executed
|
|
and a `KeycloakSessionFactory` is created without any processing to discover SPIs and their providers.
|
|
|
|
There are a few reasons why we have Keycloak as a Quarkus extension:
|
|
|
|
* More control over the build-time augmentation and runtime stages.
|
|
* More flexibility when extending Quarkus itself and the extensions used by the server (e.g.: Hibernate, Resteasy, etc.)
|
|
* Make it easier to embed the server into Quarkus applications
|
|
* Make it possible to allow Keycloak developers to customize the server distribution
|
|
|
|
## Keycloak Server
|
|
|
|
The `server` module holds the Keycloak Server itself. It is basically a regular Quarkus application using the `keycloak-quarkus-server` extension. If you look at the
|
|
[pom.xml](server/pom.xml) from this module you'll notice that it is a very simple Quarkus application with the bare minimum configuration
|
|
to actually build and run the server.
|
|
|
|
As Quarkus application, the server is a [mutable](https://quarkus.io/guides/reaugmentation#how-to-re-augment-a-quarkus-application) application using the
|
|
[mutable-jar](server/src/main/resources/application.properties) package type. As a mutable application, Keycloak is able to allow
|
|
users to configure some aspects of the server without having to re-build this module, something impractical from a user perspective.
|
|
|
|
The mutability of the server is directly related to the `build` command. As mentioned before, the build steps from the `deployment` module
|
|
are only run when (re)augmenting the server and when running the `build` command, the server will indicate to Quarkus that the build steps
|
|
should re-run and the recorded bytecode should be updated to reflect any change to the server configuration.
|
|
|
|
From a Quarkus perspective, the server is also a [Command Mode Application](https://quarkus.io/guides/command-mode-reference) and provides
|
|
a CLI based on [Picocli](https://picocli.info/). As such, there is a single entrypoint that executes the code to execute the CLI and bootstrap the server. This entry point
|
|
is the `org.keycloak.quarkus.runtime.KeycloakMain` class from the `runtime` module.
|
|
|
|
## Keycloak Distribution
|
|
|
|
The server distribution is created by build the `dist` module. This module basically consists of packaging the `deployment`, `runtime`,
|
|
and `server` modules artifacts and their dependencies to a `ZIP` or tarball file.
|
|
|
|
Within this directory you'll find the directory structure of the distribution and what is included in it.
|
|
|
|
## Running the server in development mode
|
|
|
|
As a regular Quarkus application, you are able to run the `server` module in [dev mode](https://quarkus.io/guides/maven-tooling#dev-mode) just like any regular application:
|
|
|
|
```
|
|
cd server
|
|
mvn clean quarkus:dev -Dquarkus.args="start-dev"
|
|
```
|
|
|
|
You can set any command or configuration option to the server by setting the `quarkus.args` environment variable.
|
|
|
|
When running in dev mode, you can benefit from the dev mode capabilities from Quarkus but with some limitations. The main limitations you'll find
|
|
at the moment are:
|
|
|
|
* Changes are only automatically reflected at runtime if you are changing resources from the `deployment`, `runtime`, and `server` modules. Other modules, such as `keycloak-services` still rely on Hot Swap in Java debuggers to reload classes.
|
|
* There is nothing in the Dev UI related to the server itself, although you can still change some configuration from there.
|
|
* There are some limitations when passing some options when running in dev mode. You should expect more improvements in this area.
|
|
|
|
We are working to improve the dev experience, and you should expect improvements over time.
|
|
|
|
## Debugging the server distribution
|
|
|
|
The `kc.sh|bat` script allows you to remotely debug the distribution. For that, you should run the server as follows:
|
|
|
|
```
|
|
kc.sh --debug start-dev
|
|
```
|
|
|
|
By default, the debug port is available at `8787`.
|
|
|
|
An additional environment variable `DEBUG_SUSPEND` can be set to suspend the JVM, when launched in debug mode. The `DEBUG_SUSPEND` variable supports the following values:
|
|
|
|
* `y` - The debug mode JVM launch is suspended
|
|
* `n` - The debug mode JVM is started without suspending
|
|
|
|
Suspending the JVM when in debug mode is useful if you want to debug the early stages of the bootstrap code.
|
|
|
|
When making changes to the `deployment`, `runtime`, or `server` modules, you can update the distribution with the new artifacts by executing
|
|
the following command:
|
|
|
|
```
|
|
mvn -DskipTests clean install
|
|
```
|
|
|
|
After the `quarkus` module and sub-modules are built, you can update the distribution as follows:
|
|
|
|
```
|
|
cp -r server/target/lib ${KC_HOME_DIR}
|
|
```
|
|
|
|
In the example above, the `${KC_HOME_DIR}` variable points to the root directory of the distribution.
|
|
|
|
You should also be able to update a server dependency directly. For that, copy the jar to the following location:
|
|
|
|
```
|
|
cp services/target/keycloak-services-${KC_VERSION}.jar ${KC_HOME_DIR}/lib/lib/main/org.keycloak.keycloak-services-${KC_VERSION}.jar
|
|
```
|
|
|
|
## Running tests
|
|
|
|
The distribution has its own distribution and the main tests are within the [tests/integration](tests/integration) module.
|
|
|
|
The test suite has two main types of tests:
|
|
|
|
* `jvm`
|
|
* `distribution`
|
|
|
|
The `jvm` tests execute both the test class and server within the same JVM. While the `distribution` tests execute the server
|
|
by running the distribution in a separte JVM.
|
|
|
|
The `distribution` tests are marked as such using the `DistributionTest` annotation. If not marked with this annotation, the test is a `JVM` test.
|
|
|
|
To run the tests, execute the following command within the `quarkus` module:
|
|
|
|
```
|
|
mvn clean install
|
|
```
|
|
|
|
By default, the tests will run using a raw distribution. If you want to run tests from the [tests/integration](tests/integration) module directly,
|
|
please make sure the distribution was built with the latest changes you did to it and its dependencies.
|
|
|
|
### Running tests using a container
|
|
|
|
You can also run tests using a container instead of the raw distribution by setting the `kc.quarkus.tests.dist` property as follows:
|
|
|
|
```
|
|
mvn clean install -Dkc.quarkus.tests.dist=docker
|
|
```
|
|
|
|
When setting the `kc.quarkus.tests.dist` to `docker` tests will run using a container instead of the raw distribution.
|
|
|
|
### Running storage tests
|
|
|
|
The storage tests are disabled by default but can be activated using the `test-database` profile:
|
|
|
|
```
|
|
mvn clean install -Ptest-database -Dtest=PostgreSQLDistTest
|
|
```
|
|
|
|
### Running tests from the IDE
|
|
|
|
You are also able to run tests from your IDE. For that, choose a test from the [tests/integration](tests/integration) module
|
|
and execute it accordingly.
|
|
|
|
### Running tests from the `base` testsuite
|
|
|
|
Sometimes you might want to run the tests from the `base` test suite using the distribution. For that, make sure you have built the `quarkus` module
|
|
and then execute the following command from the project root directory:
|
|
|
|
```
|
|
mvn -f testsuite/integration-arquillian/pom.xml clean install -Pauth-server-quarkus -Dtest=OIDCProtocolMappersTest
|
|
```
|
|
|
|
## Documentation
|
|
|
|
The documentation is a set of guides available from the [docs](../docs/guides/src/main/server) module. Please,
|
|
look at the this [guide](../docs/building.md) about how to update and build the distribution guides.
|
|
|
|
## Before contributing the changes
|
|
|
|
Before contributing changes, make to read the main [Keycloak Contributing Guide](https://github.com/keycloak/keycloak/blob/main/CONTRIBUTING.md).
|
|
|
|
Please, make sure:
|
|
|
|
* Documentation is updated if you are introducing any new behavior or changing an existing one that needs to be communicated
|
|
* Make sure you have a test within the [tests/integration](tests/integration) module to cover the changes
|
|
* You probably want to run a full build of the `quarkus` module, including running tests, to make sure you won't be surprised by failures in CI.
|
|
|
|
## Upgrading Quarkus Version
|
|
|
|
Upgrading Quarkus requires a few steps:
|
|
|
|
* Change the Quarkus version
|
|
* Change the dependencies we are using from Quarkus
|
|
* Run a build to make sure the server extension is not broken
|
|
|
|
The steps still require a lot of manual work, and we should be improving this.
|
|
|
|
### Changing the Quarkus version
|
|
|
|
To change the Quarkus version, you can run the following script:
|
|
|
|
```bash
|
|
./set-quarkus-version.sh <version>
|
|
```
|
|
|
|
The `set-quarkus-version.sh` script is enough to change the version for all dependencies we are
|
|
using from Quarkus.
|
|
|
|
The `<version>` should point to a branch or a tag from Quarkus repository.
|
|
|
|
It is also possible to change to a snapshot version by running:
|
|
|
|
```bash
|
|
./set-quarkus-version.sh
|
|
```
|
|
|
|
### Run a local build
|
|
|
|
After changing the dependency versions, you can run a local build to make sure the server extension is not broken by API changes and if
|
|
all tests are passing:
|
|
|
|
```
|
|
mvn clean install
|
|
```
|
|
|
|
### Changing versions of JDBC Extensions
|
|
|
|
It might happen that when upgrading a version for any of the JDBC extensions (e.g.: `quarkus-jdbc-postgresql`) you also need to make sure the server extension is using the same JDBC Drivers.
|
|
|
|
For that, you should look at the `deployment` module of the corresponding JDBC extension from Quarkus (e.g.: https://github.com/quarkusio/quarkus/blob/main/extensions/jdbc/jdbc-postgresql/deployment/src/main/java/io/quarkus/jdbc/postgresql/deployment/JDBCPostgreSQLProcessor.java) to check if they match with the drivers used by the server extension by looking at the `org.keycloak.config.database.Database` class.
|
|
|
|
### Changing versions of Quarkiverse dependencies
|
|
|
|
Make sure the Quarkiverse dependencies are also updated and in sync with the Quarkus version you are upgrading.
|
|
|
|
For now, we only have this Quarkiverse dependency:
|
|
|
|
* https://github.com/quarkiverse/quarkus-vault
|
|
|
|
### What can go wrong when upgrading?
|
|
|
|
The perfect scenario is that after performing all the steps above the server extension will compile, the distribution can be built,
|
|
and all tests will pass.
|
|
|
|
However, it is expected breaking changes between Quarkus upgrades that break the integration code we have in both [deployment](deployment) and [runtime](runtime) modules. When this happens,
|
|
you should understand what is breaking and upgrade the integration code accordingly.
|
|
|
|
## References
|
|
|
|
* [Configuration Guide](https://www.keycloak.org/server/configuration)
|
|
* [Re-augmentation](https://quarkus.io/guides/reaugmentation)
|
|
* [Command Mode Application](https://quarkus.io/guides/command-mode-reference) |