Run script after server startup

I would like run the following script after Keycloak startup:

#!/bin/bash

export PATH=$PATH:$JBOSS_HOME/bin

kcadm.sh config credentials --server http://localhost:8080/auth --realm master --user $KEYCLOAK_USER --password $KEYCLOAK_PASSWORD
admin_realm=$(kcadm.sh get realms/admin)
if [ -z "$admin_realm" ]; then
    kcadm.sh create realms -f admin.json
else
    echo "the realm admin already exists."
fi

Where could I place it ?, I have tried /opt/jboss/startup-scripts but the moment it is fired the server can’t respond.

Why not simply set the import options on startup?

There is an option not to overwrite an already existing realm.
When I understand your shell script right, this is exactly what you want to do.

When using the Docker image, it’s just to copy/mount the realm.json file to the container and set the env var KEYCLOAK_IMPORT to the location of your json file.

I have an SPI that trigger after realm creation and publish a message in apache Kafka topic.

If I use this approach the SPI isn’t triggered, because the import happens before it is loaded.

AFAIK there is nothing ootb.

What I could think of, is… a bit weird, but perhaps worth thinking about?

Put a script in the startup-scripts folder, which starts a decoupled bash/shell process, so that the script in the folder can be terminated immediately and does not block anything.
In the new process, you periodically poll the /auth endpoint until it is available (or until a timeout), then you can run your realm creation. After that, terminate the process.

I know, polling is not what we really want, but… often the only possibility. Kubernetes is doing the same with the readiness checks.

I got your idea, but the script inside startup-scripts folder block the server boot, and never reach his target, take a look at the script:

#!/bin/bash

export PATH=$PATH:$JBOSS_HOME/bin

for i in {1..10}; do
    kcadm.sh config credentials --server http://localhost:8080/auth --realm master --user $KEYCLOAK_USER --password $KEYCLOAK_PASSWORD
    admin_realm=$(kcadm.sh get realms/admin)
    if [ -z "$admin_realm" ]; then
        kcadm.sh create realms -f $JBOSS_HOME/dojot/admin.json
    else
        echo "the realm admin already exists."
    fi
    sleep 5s
done

It would works if there was a way to enable it runs as a decoupled process. Do you know how ?

Your pasted script should be the one being called from the one in startup-scripts.

Let’s assume, you put your script to /tmp/createRealm.sh
Then, put a script to the startup-scripts folder, e.g. .../startup-scripts/startRealmCreationCheckInOwnProcess.sh
This file should look like:

#!/bin/bash
echo "start realm creation/check in own process"
/tmp/createRealm.sh &> /dev/null & disown
echo "realm creation/check called, terminating this process"

Be aware, that with &> /dev/null, you won’t see any output of the called script. Try to omit it to see something on stdout.

See also https://stackoverflow.com/a/29681504/3535421

I didn’t test it, hopefully it works, or at least leads you to a possible solution.

P.S.: In your loop, you should of course check the availability of /auth, e.g. with curl, and only execute your kcadm commands if available. Once executed, you should exit the loop.

Thanks @dasniko, now it is working fine :grinning:

Just a curiosity, I note that the directory /opt/jboss/startup-scripts isn’t available by default inside docker image, was necessary to create it. Do you know why ?

1 Like

I don’t know exactly, but I guess it’s not existent, b/c it’s only for custom scripts, and as long as there are not scripts, no directory is needed.
Also, as it’s a container, one should not need to “created” it, but just mount volumes as such a directory into the container on startup.