Skip to content

Instantly share code, notes, and snippets.

@unguiculus
Last active March 23, 2023 16:25
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save unguiculus/19618ef57b1863145262191944565c9d to your computer and use it in GitHub Desktop.
Save unguiculus/19618ef57b1863145262191944565c9d to your computer and use it in GitHub Desktop.
Keycloak
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
show_help() {
cat << EOF
Usage: $(basename "$0") <options>
-h, --help Display help
-v, --verbose Display verbose output
-n, --namespace The namespace Keycloak runs in (default: dev)
-a, --action The action to perform (import|export)
-d, --dir The directory with files to import from or export to (default: impex)
EOF
}
main() {
local verbose=
local action=
local namespace=dev
local dir=impex
while :; do
case "${1:-}" in
-h|--help)
show_help
exit
;;
-v|--verbose)
verbose=true
;;
-a|--action)
case "${2:-}" in
import|export)
action="$2"
shift
;;
*)
echo "ERROR: '-a|--action' does not match (import|export)." >&2
show_help
exit 1
;;
esac
;;
-n|--namespace)
if [ -n "${2:-}" ]; then
namespace="$2"
shift
else
echo "ERROR: '-n|--namespace' cannot be empty." >&2
show_help
exit 1
fi
;;
-d|--dir)
if [ -n "${2:-}" ]; then
dir="$2"
shift
else
echo "ERROR: '-d|--dir' cannot be empty." >&2
show_help
exit 1
fi
;;
*)
break
;;
esac
shift
done
if [[ -z "$action" ]]; then
echo "ERROR: '-a|--action' is required." >&2
show_help
exit 1
fi
[[ -n "$verbose" ]] && set -x
impex "$namespace" "$action" "$dir"
}
impex() {
local namespace="$1"
local action="$2"
local dir="$3"
local server_dir
server_dir="/opt/jboss/$(basename "$dir")"
local log_file
log_file="/opt/jboss/$action.log"
# shellcheck disable=SC2064
trap "cleanup '$namespace' '$server_dir' '$log_file'" EXIT
if [[ "$action" == 'import' ]]; then
echo "Copying '$dir' to Keycloak container..."
kubectl cp --namespace "$namespace" "$dir" "keycloak-0:$server_dir"
fi
local cmd
cmd=$(create_impex_cmd "$namespace" "$action" "$dir" "$server_dir")
kubectl exec --namespace "$namespace" keycloak-0 -- sh -c "$cmd"
echo "Copying '$action.log' from container..."
kubectl cp --namespace "$namespace" "keycloak-0:$log_file" .
if [[ "$action" == 'export' ]]; then
echo "Copying '$dir' from Keycloak container..."
kubectl cp --namespace "$namespace" "keycloak-0:$server_dir" "$dir"
fi
}
create_impex_cmd() {
local namespace="$1"
local action="$2"
local dir="$3"
local server_dir="$4"
cat << EOF
# Start up non-HA Keycloak for impex only using different ports
echo "Starting up Keycloak $action instance..."
# JAVA_OPTS configures the heap. If we reuse this here we get an additional container
# with the same amount of heap. The pod would get OOMKilled.
unset JAVA_OPTS
/opt/jboss/keycloak/bin/standalone.sh \
-Dkeycloak.migration.action="$action" \
-Dkeycloak.migration.dir="$server_dir" \
-Dkeycloak.migration.strategy=OVERWRITE_EXISTING \
-Dkeycloak.migration.usersExportStrategy=SAME_FILE \
-Djboss.http.port=8888 \
-Djboss.https.port=9999 \
-Djboss.management.http.port=7777 > "$action.log" &
pid="\$!"
echo "Waiting for Keycloak $action instance to start up..."
until grep 'Deployed "keycloak-server.war"' "$action.log" ; do
printf '.'
sleep 1
done
echo '✓'
echo "Shutting down Keycloak $action instance..."
kill "\$pid"
EOF
}
cleanup() {
local namespace="$1"
local server_dir="$2"
local log_file="$3"
echo 'Performing clean-up...'
kubectl exec --namespace "$namespace" keycloak-0 -- rm -rf "$server_dir" "$log_file"
echo 'Done.'
}
main "$@"
@giannivh
Copy link

giannivh commented Jan 9, 2019

Just what I was looking for, awesome!

I forked the gist and added the possibility to override the pod name. (my pods are named like keycloak-test-0, keycloak-dev-0)

@Keithsc
Copy link

Keithsc commented May 11, 2019

Thanks for creating this script, its really easy to use and looks like it will fit in well with the other scripts that we are using to build our K8S clusters so that we don't have to manually configure Keycloak each time. I have a few questions about it though...

We ran a export (our realm & the master), then rebuilt the cluster and import the realms again but didn't remember the original keycloak password and the new one stored in the k8s secret didn't work. Is there way to reset the password ? I have figured out that if I just import our own realm then that works for us but I wonder if there's a better way then deleting the master realms files from the backup folder.

I realised that after importing our realm we had to clear the caches in Keycloak and am looking for a way to automate this, I have had a brief look at the KeyCloak CLI and I think that once I figure out how to login using the cli it looks pretty easy to script the flush commands but again I wondered if there's another way before I start hacking away.

Thanks again.
Keith.

@Keithsc
Copy link

Keithsc commented Jul 24, 2019

The script has been failing to export either the log or the realms so I changed the following line....

kubectl cp --namespace "$namespace" "keycloak-0:$log_file" .
to
kubectl cp --namespace "$namespace" "keycloak-0:$log_file" ./export.log

And now the log files gets exported and so do the realm files. It's probably my environment that has changed that causing this error. Hope this helps someone...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment