diff --git a/docker/dev-env/Dockerfile b/docker/dev-env/Dockerfile new file mode 100644 index 000000000000..a482ffd9a237 --- /dev/null +++ b/docker/dev-env/Dockerfile @@ -0,0 +1,65 @@ +# ---------------------------------------------- +# Stage 1: Build dotCMS from our builder image +# ---------------------------------------------- +ARG DOTCMS_DOCKER_TAG="latest" + +FROM dotcms/dotcms:${DOTCMS_DOCKER_TAG} AS dotcms + +FROM ubuntu:22.04 + +# Defining default non-root user UID, GID, and name +ARG USER_UID="65001" +ARG USER_GID="65001" +ARG USER_GROUP="dotcms" +ARG USER_NAME="dotcms" + +RUN groupadd -f -g $USER_GID $USER_GROUP +# Creating default non-user +# the useradd +RUN useradd -l -d /srv -g $USER_GID -u $USER_UID $USER_NAME + +COPY --from=dotcms --chown=$USER_NAME:$USER_GROUP /srv/ /srv/ + +ARG DEBIAN_FRONTEND=noninteractive +ARG UBUNTU_RELEASE=jammy +ARG PG_VERSION=15 +ARG PGDATA=/data/postgres +ARG DEBIAN_FRONTEND=noninteractive +ARG DEBCONF_NONINTERACTIVE_SEEN=true +RUN mkdir /data +RUN chmod 777 /data + +# Installing basic packages +RUN apt-get update && \ + apt-get upgrade -y && \ + apt-get install -y --no-install-recommends bash zip unzip wget libtcnative-1\ + tzdata tini ca-certificates openssl libapr1 libpq-dev curl gnupg\ + vim libarchive-tools + + +RUN sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $UBUNTU_RELEASE-pgdg main" > /etc/apt/sources.list.d/pgdg.list' + +RUN wget -qO- https://www.postgresql.org/media/keys/ACCC4CF8.asc | tee /etc/apt/trusted.gpg.d/pgdg.asc &>/dev/null \ + && apt-get update -y \ + && apt-get upgrade -y \ + && apt-get install -y postgresql-$PG_VERSION + + +# Cleanup +RUN apt-get autoremove -y && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + + +COPY --from=opensearchproject/opensearch:1.3.11 --chown=$USER_NAME:$USER_GROUP /usr/share/opensearch /usr/share/opensearch + +RUN echo "discovery.type: single-node\nbootstrap.memory_lock: true\ncluster.routing.allocation.disk.threshold_enabled: true\ncluster.routing.allocation.disk.watermark.low: 1g\ncluster.routing.allocation.disk.watermark.high: 500m\ncluster.routing.allocation.disk.watermark.flood_stage: 400m\ncluster.info.update.interval: 5m" >> /usr/share/opensearch/config/opensearch.yml + + +ENV PATH=$PATH:/usr/share/opensearch/bin +RUN /usr/share/opensearch/opensearch-onetime-setup.sh +RUN chown -R dotcms.dotcms /usr/share/opensearch/config +COPY entrypoint.sh / +RUN chmod 755 /entrypoint.sh + +ENTRYPOINT ["/usr/bin/tini", "--", "/entrypoint.sh"] diff --git a/docker/dev-env/README.md b/docker/dev-env/README.md new file mode 100644 index 000000000000..691fda76db12 --- /dev/null +++ b/docker/dev-env/README.md @@ -0,0 +1,114 @@ +# dotCMS Development Docker Image +### All in one docker image including Postgres and Opensearch +This image, intended for development, runs Ubuntu 22.04 and contains dotCMS, Postgres 15 and Opensearch 1.x. All dotCMS, db and es index data is stored in the `/data` directory, which should be mapped in if you want your environment to persist. The beauty of this image that it can be used to CLONE an existing dotCMS instance. + + +## Running the image +This image takes all the normal dotCMS docker config switches - keep in mind that the DB and ES come pre-wired, so no need to change those. This image also takes the following env variables: + +- `DOTCMS_SOURCE_ENVIRONMENT` : the url for the environment you wish to clone, e.g. https://demo.dotcms.com . +- `DOTCMS_API_TOKEN` : A valid dotCMS API Token from an admin user in the source environment. +- `DOTCMS_USERNAME_PASSWORD` : The username:password for an admin user in the source environment. +- `DOTCMS_DEBUG` : Run dotCMS in debug mode and listen for a remote debugger on port 8000, defaults to `false`. +- `ALL_ASSETS` : Controls whether old versions of assets are included in the download, defaults to false, which means only the current live and working versions of assets will be downloaded. + + + +## Cloning a dotCMS Environment +When running this image, if you specify a source environment and a valid means to authenticate, the image will attempt to pull the **assets** and **db** from the source environment. To do this, you start the image up and pass it a `DOTCMS_SOURCE_ENVIRONMENT` and either an `DOTCMS_API_TOKEN` or `DOTCMS_USERNAME_PASSWORD` (e.g. `admin@dotcms.com:admin`). On startup, the image will try to reach out and download the database and assets from the specified dotCMS instance, load the db and assets and start dotCMS in debug mode. Once the server starts, you need to run a full reindex. + + + +#### Clone demo with a dotCMS API Token +``` +export TOK=XXXXXXX_YOUR_DOTCMS_TOKEN.eXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + +docker run --rm \ +-p 8000:8000 \ +-p 8443:8443 \ +-v $PWD/data:/data \ +-e DOTCMS_SOURCE_ENVIRONMENT=https://demo.dotcms.com \ +-e DOTCMS_API_TOKEN=$TOK \ + dotcms/dotcms-dev:latest +``` + +#### Clone demo with UserID/Password +``` +docker run --rm \ +-p 8443:8443 \ +-v $PWD/data:/data \ +-e DOTCMS_SOURCE_ENVIRONMENT=https://demo.dotcms.com \ +-e DOTCMS_USERNAME_PASSWORD="admin@dotcms.com:admin" \ + dotcms/dotcms-dev:latest +``` + +#### Run normal startup with Postgres port exposed, running debug +``` +docker run --rm \ +-p 8443:8443 \ +-p 5432:5432 \ +-p 8000:8000 \ +-v $PWD/data:/data \ +-e DOTCMS_DEBUG=true \ + dotcms/dotcms-dev:latest +``` + + +#### Troubleshooting the Download +Due to a bug in docker, downloading large environments can time out. To get around this, you can download the assets and db yourself (outside of docker) to seed your installation and add them to the data volume you map into the image. dotCMS will look for `/data/assets.zip` and/or `/data/dotcms_db.sql.gz` to import before running the normal starter import routine. + +#### Downloading your assets and db outside of Docker +dotCMS offers two admin only endpoints to download your data and assets +- `/api/v1/maintenance/_downloadAssets` +- `/api/v1/maintenance/_downloadDb` + +When downloading assets, you can specify `?oldAssets=false`, and dotCMS will only include the assets for live and working versions of your content, thus hopefully generating a MUCH smaller download + +#### Example wget to download assets +``` +wget --header="$AUTH_HEADER" -t 1 -O assets.zip $DOTCMS_SOURCE_ENVIRONMENT/api/v1/maintenance/_downloadAssets?oldAssets=false +``` + +#### Example wget to download your DB +``` +wget --header="$AUTH_HEADER" -t 1 -O dotcms_db.sql.gz $DOTCMS_SOURCE_ENVIRONMENT/api/v1/maintenance/_downloadDb + +``` + +#### Starting from a clean slate +Your development instance can be deleted and reset by deleting the ./data directory that is mapped in. + + + + +## Building this Image +By default, this image is built from the `dotcms/dotcms:latest` tagged version of dotCMS. You can specify another dotCMS version you want use for your dev instance by passing the build-arg `DOTCMS_DOCKER_TAG` to indicate which dotCMS image tag to use to build, e.g. +`--build-arg DOTCMS_DOCKER_TAG=latest` or `--build-arg DOTCMS_DOCKER_TAG=23.07` + +``` +docker build --pull --build-arg DOTCMS_DOCKER_TAG=latest . -t dotcms/dotcms-dev +``` +or +``` +docker buildx build --build-arg DOTCMS_DOCKER_TAG=master_latest_SNAPSHOT --platform linux/amd64,linux/arm64 --pull --push -t dotcms/dotcms-dev:master_latest_SNAPSHOT . +``` + +### Included Database and Elasticsearch + +This image runs the following servers internally. + +#### Opensearch 1.3.11 +Running https on +- https on port 9200 +- basic auth (admin/admin) +- data stored in /data/opensearch + + +#### Postgres 15 +Running on port 5432 and using the dotCMS defaults: +- db: dotcms +- user: dotcmsdbuser +- pass: password +- data stored in /data/postgres + +If you wish to connect to these instances remotely, you will need to expose their ports in docker when you run the image, e.g. diff --git a/docker/dev-env/entrypoint.sh b/docker/dev-env/entrypoint.sh new file mode 100644 index 000000000000..0181eceb2760 --- /dev/null +++ b/docker/dev-env/entrypoint.sh @@ -0,0 +1,177 @@ +#!/bin/bash -e + +ASSETS_BACKUP_FILE=/data/assets.zip +DB_BACKUP_FILE=/data/dotcms_db.sql.gz + +export JAVA_HOME=/usr/share/opensearch/jdk +export PATH=$PATH:$JAVA_HOME/bin:/usr/local/pgsql/bin +export ES_JAVA_OPTS=${ES_JAVA_OPTS:-"-Xmx512m"} + + +setup_postgres () { + echo "Starting Postgres Database" + if [ ! -d "/data/postgres" ]; then + mv /var/lib/postgresql/$PG_VERSION/main /data/postgres + fi + rm -rf /var/lib/postgresql/$PG_VERSION/main + ln -sf /data/postgres /var/lib/postgresql/$PG_VERSION/main + + + /etc/init.d/postgresql start + + if su -c "psql -lqt" postgres | cut -d \| -f 1 | grep -qw dotcms; then + # database exists + echo "- dotCMS db exists, skipping import" + echo "- Delete the /data/postgres folder to force a re-import" + return 0 + fi + + # creating database + su -c "psql -c \"CREATE database dotcms;\" 1> /dev/null" postgres + su -c "psql -c \"CREATE USER dotcmsdbuser WITH PASSWORD 'password';\" 1> /dev/null" postgres + su -c "psql -c \"ALTER DATABASE dotcms OWNER TO dotcmsdbuser;\" 1> /dev/null" postgres + + if [ -f "$DB_BACKUP_FILE" ]; then + echo "- Importing dotCMS db from backup" + # import database + cat $DB_BACKUP_FILE | gzip -d | PGPASSWORD=password psql -h 127.0.0.1 -Udotcmsdbuser dotcms + fi + + return 0 +} + + +setup_opensearch () { + + + if [ ! -d "/data/opensearch" ]; then + mv /usr/share/opensearch/data /data/opensearch + chown dotcms.dotcms /data/opensearch + fi + + rm -rf /usr/share/opensearch/data + ln -sf /data/opensearch /usr/share/opensearch/data + chown dotcms.dotcms /data/opensearch + + echo "Starting OPENSEARCH" + # Start up Elasticsearch + su -c "/usr/share/opensearch/bin/opensearch 1> /dev/null" dotcms & +} + + +pull_dotcms_backups () { + + # If these are 0 length files, delete them + if [ ! -s $ASSETS_BACKUP_FILE ] ; then + rm -rf $ASSETS_BACKUP_FILE + fi + + if [ ! -s $DB_BACKUP_FILE ] ; then + rm -rf $DB_BACKUP_FILE + fi + + if [ -f "$ASSETS_BACKUP_FILE" ] && [ -f $DB_BACKUP_FILE ]; then + + echo "- DB and Assets backups exist, skipping" + echo "- Delete $ASSETS_BACKUP_FILE and $DB_BACKUP_FILE to force a re-download" + return 0 + fi + + if [ -z "$DOTCMS_SOURCE_ENVIRONMENT" ]; then + echo "- No dotCMS env to clone, starting normally" + return 0 + fi + if [ -z "$DOTCMS_API_TOKEN" -a -z "$DOTCMS_USERNAME_PASSWORD" ]; then + echo "- Source environment specified, but no dotCMS auth available" + return 1 + fi + + echo "Pulling Environment from $DOTCMS_SOURCE_ENVIRONMENT" + + if [ -n "$DOTCMS_API_TOKEN" ]; then + echo "- Using Authorization: Bearer" + AUTH_HEADER="Authorization: Bearer $DOTCMS_API_TOKEN" + else + echo "- Using Authorization: Basic" + AUTH_HEADER="Authorization: Basic $(echo -n $DOTCMS_USERNAME_PASSWORD | base64)" + fi + + mkdir -p /data/shared/assets + chown -R dotcms.dotcms /data/shared + + if [ ! -f "$ASSETS_BACKUP_FILE" ]; then + su -c "rm -rf $ASSETS_BACKUP_FILE.tmp" + echo "- Downloading ASSETS" + su -c "wget --no-check-certificate --header=\"$AUTH_HEADER\" -t 1 -O $ASSETS_BACKUP_FILE.tmp $DOTCMS_SOURCE_ENVIRONMENT/api/v1/maintenance/_downloadAssets\?oldAssets=${ALL_ASSETS:-"false"} " dotcms + if [ -s $ASSETS_BACKUP_FILE.tmp ]; then + su -c "mv $ASSETS_BACKUP_FILE.tmp $ASSETS_BACKUP_FILE" + else + su -c "rm -rf $ASSETS_BACKUP_FILE.tmp" + echo "asset download failed, please check your credentials and try again" + exit 1 + fi + fi + + if [ ! -f "$DB_BACKUP_FILE" ]; then + echo "- Downloading database" + su -c "rm -rf $DB_BACKUP_FILE.tmp" + su -c "wget --no-check-certificate --header=\"$AUTH_HEADER\" -t 1 -O $DB_BACKUP_FILE.tmp $DOTCMS_SOURCE_ENVIRONMENT/api/v1/maintenance/_downloadDb" dotcms + if [ -s $DB_BACKUP_FILE.tmp ]; then + su -c "mv $DB_BACKUP_FILE.tmp $DB_BACKUP_FILE" + else + su -c "rm -rf $DB_BACKUP_FILE.tmp" + echo "database download failed, please check your credentials and try again" + exit 1 + fi + fi + +} + +unpack_assets(){ + if [ -d "/data/shared/assets/1" ]; then + echo "Assets Already Unpacked, skipping. If you would like to unpack them again, please delete the /data/shared/assets folder" + return 0 + fi + if [ ! -s "$ASSETS_BACKUP_FILE" ]; then + return 0 + fi + + + echo "Unzipping assets.zip" + su -c "unzip -u $ASSETS_BACKUP_FILE -d /data/shared" || true +} + + + +start_dotcms () { + + + if [ "$DOTCMS_DEBUG" == "true" ];then + echo "Setting java debug port to 8000. If you want to change the debug options," + echo "pass in your options using the CMS_JAVA_OPTS variable instead" + export CMS_JAVA_OPTS="$CMS_JAVA_OPTS -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=*:8000" + fi + + export DB_BASE_URL=${DB_BASE_URL:-"jdbc:postgresql://127.0.0.1/dotcms"} + export DOT_ES_ENDPOINTS=${DOT_ES_ENDPOINTS:-"https://127.0.0.1:9200"} + export DOT_DOTCMS_CLUSTER_ID=${DOT_DOTCMS_CLUSTER_ID:-"dotcms_dev"} + + echo "Starting dotCMS using" + echo " - CMS_JAVA_OPTS: $CMS_JAVA_OPTS" + echo " - ES_JAVA_OPTS: $ES_JAVA_OPTS" + echo " - DB_BASE_URL: $DB_BASE_URL" + echo " - DOT_ES_ENDPOINTS: $DOT_ES_ENDPOINTS" + echo " - DOT_DOTCMS_CLUSTER_ID: $DOT_DOTCMS_CLUSTER_ID" + + . /srv/entrypoint.sh +} + + + + + +pull_dotcms_backups && echo "" +setup_postgres && echo "" +unpack_assets && echo "" +setup_opensearch && echo "" +start_dotcms diff --git a/docker/docker-compose-examples/README.md b/docker/docker-compose-examples/README.md new file mode 100644 index 000000000000..ce303eb9110a --- /dev/null +++ b/docker/docker-compose-examples/README.md @@ -0,0 +1,22 @@ +# Docker Compose Examples + +This directory contains docker-compose examples ready to use + +The following examples are provided: + +- **cluster-mode:** dotcms instance with 2 nodes in a cluster +- **elasticsearch-with-kibana:** elasticsearch server with kibana +- **oracle-database:** oracle database running on port 1521 +- **push-publish:** dotcms environment with a sender and a receiver +- **single-node:** basic dotcms instance running with postgres database +- **single-node-debug-mode:** basic dotcms instance running with postgres database and debug mode enabled +- **single-node-demo-site:** basic dotcms instance running demo site +- **with-kibana:** basic dotcms instance running with postgres database and kibana +- **with-mssql:** basic dotcms instance running with MSSQL database +- **with-oracle:** basic dotcms instance running with oracle database +- **with-redis:** dotcms cluster with redis cache and pub/sub provider + +The following scripts are provided: + +- **dotcms-get-demo-site-starter-urls.sh:** prints demo site starter URL for each dotCMS version +- **dotcms_properties_to_env_vars.py:** prints ENV variables based on dotCMS properties in a "binary" install - helpful for upgrades diff --git a/docker/docker-compose-examples/analytics/docker-compose.yml b/docker/docker-compose-examples/analytics/docker-compose.yml new file mode 100644 index 000000000000..a43f631c49df --- /dev/null +++ b/docker/docker-compose-examples/analytics/docker-compose.yml @@ -0,0 +1,157 @@ +version: '2.2' + +services: + + postgres: + container_name: postgres + image: postgres:13.2 + restart: unless-stopped + environment: + POSTGRES_DB: ${POSTGRESQL_DB:-postgres} + POSTGRES_USER: ${POSTGRESQL_USER:-postgres} + POSTGRES_PASSWORD: ${POSTGRESQL_PASS:-postgres} + ports: + - ${POSTGRESQL_HOST_PORT:-54321}:5432 + + keycloak: + container_name: keycloak + depends_on: + - postgres + environment: + DB_VENDOR: postgres + DB_ADDR: postgres + KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN:-admin} + KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD:-keycloak} + DB_DATABASE: ${POSTGRESQL_DB:-postgres} + DB_USER: ${POSTGRESQL_USER:-postgres} + DB_PASSWORD: ${POSTGRESQL_PASS:-postgres} + image: quay.io/keycloak/keycloak:${KEYCLOAK_VERSION:-18.0.2} + volumes: + - ./setup/config/dev/keycloak/test-realm.json:/opt/keycloak/data/import/example-realm.json + entrypoint: ["/opt/keycloak/bin/kc.sh", "start-dev", "--import-realm"] + ports: + - "${KEYCLOAK_HOST_PORT:-61111}:8080" + restart: always + + dotcms-analytics: + container_name: dotcms-analytics + image: dotcms/configurator:latest + environment: + - JITSU_USE_CONFIGURATOR='true' + - JITSU_JITSU_CONFIGURATOR=http://host.docker.internal:7007/ + - JITSU_CLUSTER_TOKEN=myadmin + - JITSU_JITSU_SERVER=http://jitsu:8001/ + - QUARKUS_OIDC_AUTH_SERVER_URL=${AUTH_SERVER_URL:-http://host.docker.internal:61111/realms/dotcms} + - QUARKUS_DATASOURCE_DB_KIND=postgresql + - QUARKUS_DATASOURCE_REACTIVE_URL=postgresql://postgres:54321/${POSTGRESQL_DB:-keycloak} + - QUARKUS_DATASOURCE_USERNAME=${POSTGRESQL_USER:-postgres} + - QUARKUS_DATASOURCE_PASSWORD=${POSTGRESQL_PASS:-postgres} + - QUARKUS_HIBERNATE_ORM_DATABASE_GENERATION=drop-and-create + - QUARKUS_HIBERNATE_ORM_DATABASE_GENERATION_CREATE_SCHEMAS=true + - QUARKUS_SWAGGER_UI_ALWAYS_INCLUDE=true + - EXCLUDED_QUERY_PARAMS=${ANALYTICS_EXCLUDED_QUERY_PARAMS:-variantName,redirect} + ports: + - "${DOTCMS_ANALYTICS_HOST_PORT:-8088}:8080" + depends_on: + - keycloak + - postgres + - jitsu + - jitsu-configurator + + jitsu: + container_name: jitsu + image: jitsucom/server:latest + environment: + - CLUSTER_ADMIN_TOKEN=myadmin + - REDIS_URL=redis://jitsu_redis:6379 + - JITSU_CONFIGURATOR_URL=${JITSU_CONFIGURATOR_URL:-http://host.docker.internal:7007} +# - JITSU_CONFIGURATOR_URL=${JITSU_CONFIGURATOR_URL:-http://dotcms-analytics:8090} + - SERVER_PORT=8001 + - TERM=xterm-256color + - TLS_SKIP_VERIFY=true + depends_on: + - redis + - ch_server + volumes: + - ./setup/config/dev/jitsu/server/config:/home/eventnative/data/config + restart: always + ports: + - "${JITSU_HOST_PORT:-8081}:8001" + + jitsu-configurator: + container_name: jitsu-configurator + image: jitsucom/configurator:latest + environment: + - CLUSTER_ADMIN_TOKEN=myadmin + - REDIS_URL=redis://jitsu_redis:6379 + - JITSU_SERVER_URL=http://jitsu:8001 + - BACKEND_API_BASE=redis + - JITSU_EXTENDED_TELEMETRY_DISABLED=true + - JITSU_HTTP_CONTEXT_ENRICHMENT=true + - TERM=xterm-256color + - TLS_SKIP_VERIFY=true + depends_on: + redis: + condition: service_healthy + ch_server: + condition: service_healthy + restart: always + ports: + - "${JITSU_CONFIGURATOR_PORT:-7007}:7000" + + redis: + container_name: jitsu_redis + image: redis:6.2.6-bullseye + volumes: + - redis-data:/data + restart: always + healthcheck: + test: ["CMD-SHELL", "redis-cli -h localhost -p 6379 PING"] + interval: 1s + timeout: 30s + + cube: + container_name: cube + image: cubejs/cube:latest + ports: + - ${CUBE_HOST_PORT:-4001}:4000 + environment: + - CUBEJS_DEV_MODE=true + - CUBEJS_DB_TYPE=clickhouse + - CUBEJS_DB_HOST=${CH_SERVER:-ch_server} + - CUBEJS_DB_NAME=${CH_DB:-clickhouse_test_db} + - CUBEJS_DB_USER=${CH_USER:-clickhouse_test_user} + - CUBEJS_DB_PASS=${CH_PWD:-clickhouse_password} + - CUBEJS_JWK_URL=${JWKS_URL:-http://keycloak:61111/realms/dotcms/protocol/openid-connect/certs} + - CUBEJS_JWT_AUDIENCE=api-dotcms-analytics-audience + - CUBEJS_JWT_ISSUER=${AUTH_SERVER_URL:-http://keycloak:61111/realms/dotcms} + - CUBEJS_JWT_ALGS=RS256 + - CUBEJS_JWT_CLAIMS_NAMESPACE=https://dotcms.com/analytics + volumes: + - cube_metastore:/cube/conf/.cubestore + - ./setup/config/dev/cube/schema:/cube/conf/schema + + ch_server: + container_name: ch_server + image: dotcms/clickhouse-server:latest + ports: + - "${CH_HOST_PORT:-8124}:8123" + ulimits: + nofile: + soft: 262144 + hard: 262144 + healthcheck: + test: wget --no-verbose --tries=1 --spider http://localhost:8123 || exit 1 + environment: + - CLICKHOUSE_DB=${CH_DB:-clickhouse_test_db} + - CLICKHOUSE_USER=${CH_USER:-clickhouse_test_user} + - CLICKHOUSE_PASSWORD=${CH_PWD:-clickhouse_password} + volumes: + - ch_data:/var/lib/clickhouse + +volumes: + workspace: + ch_data: + redis-data: + redis_ur_data: + cube_metastore: diff --git a/docker/docker-compose-examples/analytics/setup/config/dev/clickhouse/clickhouse-issue-15638.xml b/docker/docker-compose-examples/analytics/setup/config/dev/clickhouse/clickhouse-issue-15638.xml new file mode 100644 index 000000000000..a77fac2669f0 --- /dev/null +++ b/docker/docker-compose-examples/analytics/setup/config/dev/clickhouse/clickhouse-issue-15638.xml @@ -0,0 +1,8 @@ + + + + 0 + 0 + + + diff --git a/docker/docker-compose-examples/analytics/setup/config/dev/cube/cube.js b/docker/docker-compose-examples/analytics/setup/config/dev/cube/cube.js new file mode 100644 index 000000000000..3bd1b3ca920c --- /dev/null +++ b/docker/docker-compose-examples/analytics/setup/config/dev/cube/cube.js @@ -0,0 +1,30 @@ +// cube.js configuration file +module.exports = { + /* + contextToAppId: ({ securityContext }) => + `CUBEJS_APP_${securityContext.customerId}`, + preAggregationsSchema: ({ securityContext }) => + `pre_aggregations_${securityContext.customerId}`, +*/ + + queryRewrite: (query, { securityContext }) => { + + + if (!securityContext) { + throw new Error('No valid token'); + } + + const tokenData = securityContext["https://dotcms.com/analytics"]; + + query.filters.push({ + member: 'Events.clusterId', + operator: 'equals', + values: [tokenData.clusterId], + }); + + + return query; + }, + + +}; \ No newline at end of file diff --git a/docker/docker-compose-examples/analytics/setup/config/dev/cube/schema/Events.js b/docker/docker-compose-examples/analytics/setup/config/dev/cube/schema/Events.js new file mode 100644 index 000000000000..9e0ecd25eb9b --- /dev/null +++ b/docker/docker-compose-examples/analytics/setup/config/dev/cube/schema/Events.js @@ -0,0 +1,151 @@ +cube(`Events`, { + sql: ` + WITH CountsAndLastURL AS (SELECT lookbackwindow, MAX(utc_time) AS maxDate + FROM events + GROUP BY lookbackwindow + ) + SELECT + E.experiment, + E.lookbackwindow, + E.variant, + E.runningid, + toDateTime(toStartOfDay(toTimeZone(toDateTime(utc_time), 'UTC'), 'UTC'), 'UTC') as day, + min(CASE WHEN (isexperimentpage = true AND event_type = 'pageview') THEN utc_time END) as firstExperimentPageVisit, + max(CASE WHEN (istargetpage = true AND event_type = 'pageview') THEN utc_time END) as lastTargetPageVisit, + firstExperimentPageVisit is not null as isSession, + COUNT(CASE WHEN event_type = 'pageview' THEN 1 ELSE 0 END) AS pageviews, + SUM(CASE WHEN (E.isexperimentpage = true AND C.maxDate = E.utc_time AND event_type = 'pageview') THEN 1 ELSE 0 END) as experimentPageLastVisited + FROM events E JOIN CountsAndLastURL C ON C.lookbackwindow = E.lookbackwindow + WHERE event_type = 'pageview' + GROUP BY experiment, runningid, lookbackwindow, variant, day + having isSession = 1 + order by day + `, + preAggregations: { + /*targetVisitedAfterAggregation: { + measures: [Events.totalSessions, Events.targetVisitedAfterSuccesses], + dimensions: [Events.experiment, Events.runningId, Events.variant], + timeDimension: Events.day, + granularity: `day`, + indexes: { + totalSessions_targetVisitedAfter_index: { + columns: [experiment, variant] + } + } + }, + bounceRateAggregation: { + measures: [Events.totalSessions, Events.bounceRateSuccesses], + dimensions: [Events.experiment, Events.variant], + timeDimension: Events.day, + granularity: `day`, + indexes: { + totalSessions_bounceRateSuccesses_index: { + columns: [totalSessions, bounceRateSuccesses] + } + } + }, + exitRateAggregation: { + measures: [Events.totalSessions, Events.exitRateSuccesses], + dimensions: [Events.experiment, Events.variant], + timeDimension: Events.day, + granularity: `day`, + indexes: { + totalSessions_exitRateSuccesses_index: { + columns: [totalSessions, exitRateSuccesses] + } + } + }*/ + }, + joins: {}, + measures: { + count: { + type: `count` + }, + totalSessions: { + type: `count_distinct`, + sql: `lookbackwindow` + }, + targetVisitedAfterSuccesses: { + type: `count_distinct`, + sql: `lookbackwindow`, + filters: [{ + sql: `firstExperimentPageVisit < lastTargetPageVisit` + }] + }, + bounceRateSuccesses: { + type: `count`, + sql: `lookbackwindow`, + filters: [{ + sql: `pageviews > 1` + }] + }, + exitRateSuccesses: { + type: `count`, + sql: `lookbackwindow`, + filters: [{ + sql: `experimentPageLastVisited == 0` + }] + }, + targetVisitedAfterConvertionRate: { + description: 'Convertion Rate', + format: `percent`, + type: 'number', + sql: `ROUND(${targetVisitedAfterSuccesses} * 100 / ${totalSessions}, 2)` + }, + bounceRateConvertionRate: { + description: 'Convertion Rate', + format: `percent`, + type: 'number', + sql: `ROUND(${bounceRateSuccesses} * 100 / ${totalSessions}, 2)` + }, + exitRateConvertionRate: { + description: 'Convertion Rate', + format: `percent`, + type: 'number', + sql: `ROUND(${exitRateSuccesses} * 100 / ${totalSessions}, 2)` + } + }, + dimensions: { + experiment: { + sql: `experiment`, + type: `string` + }, + runningId: { + sql: `runningid`, + type: `string` + }, + lookBackWindow: { + sql: `lookbackwindow`, + type: `string` + }, + variant: { + sql: `variant`, + type: `string` + }, + isExperimentSession: { + type: 'boolean', + sql: 'isSession' + }, + pageViewsTotal: { + type: 'number', + sql: 'pageviews' + }, + lastUrlVisited: { + type: 'string', + sql: 'lastUrlVisited' + }, + firstExperimentPageVisit: { + sql: `firstExperimentPageVisit`, + type: `time` + }, + lastTargetPageVisit: { + sql: `lastTargetPageVisit`, + type: `time` + }, + day: { + sql: `day`, + type: `time` + } + }, + dataSource: `default` +}); \ No newline at end of file diff --git a/docker/docker-compose-examples/analytics/setup/config/dev/jitsu/server/config/eventnative.yaml b/docker/docker-compose-examples/analytics/setup/config/dev/jitsu/server/config/eventnative.yaml new file mode 100644 index 000000000000..4407ca68bf0a --- /dev/null +++ b/docker/docker-compose-examples/analytics/setup/config/dev/jitsu/server/config/eventnative.yaml @@ -0,0 +1,102 @@ +server: + name: jitsu + port: '${env.SERVER_PORT|8001}' + disable_welcome_page: true + strict_auth_tokens: true + admin_token: '${env.CLUSTER_ADMIN_TOKEN|env.SERVER_ADMIN_TOKEN|demo___please_provide_value_in_production___}' + telemetry: + disabled: + usage: true + #telemetry: '${env.TELEMETRY_URL|}' + cache: + enabled: '${env.EVENTS_CACHE_ENABLED|true}' + events: + #default value. Amount of events which are saved per token or destination. + #If there are more events, old ones will be replaced with new ones. + size: 100 + #by default Jitsu applies rate limiting for not saving all events into the cache. + #Jitsu saves in cache ${size} events per ${time_window_sec}. Other events are skipped. + time_window_sec: 60 + #Every ${trim_interval_ms} value Jitsu will delete events from cache + #if size of the cache collection by token or destination is greater than ${size} + trim_interval_ms: 500 + #When Jitsu receives malformed event JSON, event will be cut to ${max_malformed_event_size_bytes} bytes (10KB) and saved to cache + max_malformed_event_size_bytes: 10000 + pool: + #number of goroutines which are process events cache + size: 10 + metrics: + relay: + disabled: '${env.JITSU_EXTENDED_TELEMETRY_DISABLED|false}' + deployment_id: '${env.JITSU_EXTENDED_TELEMETRY_DEPLOYMENT_ID|}' + +geo: + maxmind_path: '${env.MAX_MIND_PATH|}' + +configurator: + base_url: '${env.JITSU_CONFIGURATOR_URL|}' + admin_token: '${env.CLUSTER_ADMIN_TOKEN|env.CONFIGURATOR_ADMIN_TOKEN|demo___please_provide_value_in_production___}' + +geo_resolvers: '${env.GEO_RESOLVERS_URL|}' + + +sources: '${env.SOURCES_URL|}' + +system: '${env.SYSTEM_URL|}' + +notifications: + slack: + url: '${env.SLACK_NOTIFICATIONS_WEBHOOK|}' + +ui: + base_url: '${env.JITSU_UI_BASE_URL|}' + +users_recognition: + enabled: '${env.USER_RECOGNITION_ENABLED|false}' + anonymous_id_node: /user/anonymous_id + identification_nodes: + - /user/id + - /user/email + redis: + host: '${env.USER_RECOGNITION_REDIS_URL|}' + tls_skip_verify: '${env.TLS_SKIP_VERIFY|false}' + ttl_minutes: + anonymous_events: '${env.USER_RECOGNITION_TTL_MINUTES|10080}' + +meta: + storage: + redis: + host: '${env.REDIS_URL|}' + tls_skip_verify: '${env.TLS_SKIP_VERIFY|false}' + ttl_minutes: + anonymous_events: '${env.USER_RECOGNITION_TTL_MINUTES|10080}' + +events: + queue: + redis: + host: '${env.EVENTS_QUEUE_REDIS_URL|}' + tls_skip_verify: '${env.TLS_SKIP_VERIFY|false}' + +coordination: + type: redis + +sql_debug_log: + ddl: + enabled: '${env.SQL_DDL_LOG_ENABLED|true}' + queries: + enabled: '${env.SQL_QUERIES_LOG_ENABLED|false}' + +singer-bridge: + log: + enabled: '${env.SINGER_LOG_ENABLED|false}' + batch_size: '${env.SOURCES_SYNC_BATCH_SIZE|10000}' + +airbyte-bridge: + batch_size: '${env.SOURCES_SYNC_BATCH_SIZE|10000}' + +google-ads: + developer-token: '${env.GOOGLE_ADS_DEVELOPER_TOKEN|}' + +api_keys: '${env.API_KEYS_URL|}' + +destinations: '${env.DESTINATIONS_URL|}' diff --git a/docker/docker-compose-examples/analytics/setup/config/dev/keycloak/keycloak-keystore.jks b/docker/docker-compose-examples/analytics/setup/config/dev/keycloak/keycloak-keystore.jks new file mode 100644 index 000000000000..6961a6b1d020 Binary files /dev/null and b/docker/docker-compose-examples/analytics/setup/config/dev/keycloak/keycloak-keystore.jks differ diff --git a/docker/docker-compose-examples/analytics/setup/config/dev/keycloak/test-realm.json b/docker/docker-compose-examples/analytics/setup/config/dev/keycloak/test-realm.json new file mode 100644 index 000000000000..e0ead2e837ce --- /dev/null +++ b/docker/docker-compose-examples/analytics/setup/config/dev/keycloak/test-realm.json @@ -0,0 +1,2300 @@ +{ + "id": "c2d84f46-24fd-4e64-b0a9-f0933b0efa9d", + "realm": "dotcms", + "notBefore": 0, + "defaultSignatureAlgorithm": "RS256", + "revokeRefreshToken": false, + "refreshTokenMaxReuse": 0, + "accessTokenLifespan": 300, + "accessTokenLifespanForImplicitFlow": 900, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000, + "ssoSessionIdleTimeoutRememberMe": 0, + "ssoSessionMaxLifespanRememberMe": 0, + "offlineSessionIdleTimeout": 2592000, + "offlineSessionMaxLifespanEnabled": false, + "offlineSessionMaxLifespan": 5184000, + "clientSessionIdleTimeout": 0, + "clientSessionMaxLifespan": 0, + "clientOfflineSessionIdleTimeout": 0, + "clientOfflineSessionMaxLifespan": 0, + "accessCodeLifespan": 60, + "accessCodeLifespanUserAction": 300, + "accessCodeLifespanLogin": 1800, + "actionTokenGeneratedByAdminLifespan": 43200, + "actionTokenGeneratedByUserLifespan": 300, + "oauth2DeviceCodeLifespan": 600, + "oauth2DevicePollingInterval": 5, + "enabled": true, + "sslRequired": "external", + "registrationAllowed": false, + "registrationEmailAsUsername": false, + "rememberMe": false, + "verifyEmail": false, + "loginWithEmailAllowed": true, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": false, + "editUsernameAllowed": false, + "bruteForceProtected": false, + "permanentLockout": false, + "maxFailureWaitSeconds": 900, + "minimumQuickLoginWaitSeconds": 60, + "waitIncrementSeconds": 60, + "quickLoginCheckMilliSeconds": 1000, + "maxDeltaTimeSeconds": 43200, + "failureFactor": 30, + "roles": { + "realm": [ + { + "id": "5a71d573-601c-4770-8bd4-a19ce4a13ca9", + "name": "admin", + "composite": false, + "clientRole": false, + "containerId": "c2d84f46-24fd-4e64-b0a9-f0933b0efa9d", + "attributes": {} + }, + { + "id": "0d702c89-baa5-4a60-b818-5f73933cb9db", + "name": "default-roles-dotcms", + "description": "${role_default-roles}", + "composite": true, + "composites": { + "realm": [ + "offline_access", + "uma_authorization" + ], + "client": { + "account": [ + "view-profile", + "manage-account" + ] + } + }, + "clientRole": false, + "containerId": "c2d84f46-24fd-4e64-b0a9-f0933b0efa9d", + "attributes": {} + }, + { + "id": "9c89755d-7189-4aed-aeb3-6bc2471e7d9d", + "name": "uma_authorization", + "description": "${role_uma_authorization}", + "composite": false, + "clientRole": false, + "containerId": "c2d84f46-24fd-4e64-b0a9-f0933b0efa9d", + "attributes": {} + }, + { + "id": "3bf85699-f4bd-44a0-91b2-42f90cd7ebd6", + "name": "offline_access", + "description": "${role_offline-access}", + "composite": false, + "clientRole": false, + "containerId": "c2d84f46-24fd-4e64-b0a9-f0933b0efa9d", + "attributes": {} + }, + { + "id": "80009ebc-2cbb-4cdf-906a-6b3b58236273", + "name": "user", + "composite": false, + "clientRole": false, + "containerId": "c2d84f46-24fd-4e64-b0a9-f0933b0efa9d", + "attributes": {} + } + ], + "client": { + "realm-management": [ + { + "id": "34d74121-cdc1-4531-b952-a679e31d0cf5", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "4a5e7947-43b8-4215-82e0-d8b46e838822", + "attributes": {} + }, + { + "id": "564847a9-1541-49bf-bc0f-720bc434fe16", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-clients" + ] + } + }, + "clientRole": true, + "containerId": "4a5e7947-43b8-4215-82e0-d8b46e838822", + "attributes": {} + }, + { + "id": "77ae64e3-41af-48b4-abf4-6f90ad30ad5d", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "4a5e7947-43b8-4215-82e0-d8b46e838822", + "attributes": {} + }, + { + "id": "95bb3765-32ef-4678-a99a-6914ee8e69e4", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "4a5e7947-43b8-4215-82e0-d8b46e838822", + "attributes": {} + }, + { + "id": "d4753cbd-ec99-40a2-847a-c080f811445a", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "4a5e7947-43b8-4215-82e0-d8b46e838822", + "attributes": {} + }, + { + "id": "ca627879-0c0f-4884-8f08-1616117bc0e1", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "4a5e7947-43b8-4215-82e0-d8b46e838822", + "attributes": {} + }, + { + "id": "01c33522-cece-4d57-b633-869ce88b456e", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "4a5e7947-43b8-4215-82e0-d8b46e838822", + "attributes": {} + }, + { + "id": "75d27407-ecae-4723-8964-4d1ad3a7f650", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "4a5e7947-43b8-4215-82e0-d8b46e838822", + "attributes": {} + }, + { + "id": "218995b5-0bc5-4256-9a98-0f69c37e7100", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "4a5e7947-43b8-4215-82e0-d8b46e838822", + "attributes": {} + }, + { + "id": "c6eb238e-8fb8-4932-84ed-a67559ac80ce", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "4a5e7947-43b8-4215-82e0-d8b46e838822", + "attributes": {} + }, + { + "id": "186948f6-b9a2-47fc-9838-8602868186a8", + "name": "view-realm", + "description": "${role_view-realm}", + "composite": false, + "clientRole": true, + "containerId": "4a5e7947-43b8-4215-82e0-d8b46e838822", + "attributes": {} + }, + { + "id": "4212b14b-6bb0-4416-a496-f5eb2e136d78", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "4a5e7947-43b8-4215-82e0-d8b46e838822", + "attributes": {} + }, + { + "id": "9fa7e573-3e8c-4943-8b12-0fa0e7ba4e28", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "4a5e7947-43b8-4215-82e0-d8b46e838822", + "attributes": {} + }, + { + "id": "ad4d5230-b2d1-4e69-b96a-e151338191a0", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "4a5e7947-43b8-4215-82e0-d8b46e838822", + "attributes": {} + }, + { + "id": "7c49dc68-11d1-4ae9-9603-49ac5037656b", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-groups", + "query-users" + ] + } + }, + "clientRole": true, + "containerId": "4a5e7947-43b8-4215-82e0-d8b46e838822", + "attributes": {} + }, + { + "id": "eb319200-7657-48e1-8adc-86d2131783eb", + "name": "realm-admin", + "description": "${role_realm-admin}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "view-identity-providers", + "view-clients", + "impersonation", + "manage-identity-providers", + "view-events", + "query-groups", + "manage-clients", + "view-authorization", + "manage-authorization", + "query-users", + "view-realm", + "query-clients", + "manage-events", + "view-users", + "manage-users", + "manage-realm", + "create-client", + "query-realms" + ] + } + }, + "clientRole": true, + "containerId": "4a5e7947-43b8-4215-82e0-d8b46e838822", + "attributes": {} + }, + { + "id": "7a8ca77b-2971-4981-b882-6a5eccf298ed", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "4a5e7947-43b8-4215-82e0-d8b46e838822", + "attributes": {} + }, + { + "id": "712c071c-f458-42de-bf6c-558cafc73404", + "name": "manage-realm", + "description": "${role_manage-realm}", + "composite": false, + "clientRole": true, + "containerId": "4a5e7947-43b8-4215-82e0-d8b46e838822", + "attributes": {} + }, + { + "id": "dda4ed0f-2b4d-4a11-94c5-2770b9550281", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "4a5e7947-43b8-4215-82e0-d8b46e838822", + "attributes": {} + } + ], + "analytics-customer-customer1": [], + "security-admin-console": [], + "admin-cli": [], + "account-console": [], + "broker": [ + { + "id": "f08e8acd-9f32-4cbb-8bb4-b8f64b11a422", + "name": "read-token", + "description": "${role_read-token}", + "composite": false, + "clientRole": true, + "containerId": "f50f5154-7bfa-44d7-a125-4717dc69fc77", + "attributes": {} + } + ], + "account": [ + { + "id": "33c70297-8cae-4ea1-bbc5-05f3bb7fddcf", + "name": "delete-account", + "description": "${role_delete-account}", + "composite": false, + "clientRole": true, + "containerId": "c87b98ca-7461-48b1-aad7-35e41d5b579b", + "attributes": {} + }, + { + "id": "14c098fc-3788-4a90-9dd2-f208717ac000", + "name": "view-applications", + "description": "${role_view-applications}", + "composite": false, + "clientRole": true, + "containerId": "c87b98ca-7461-48b1-aad7-35e41d5b579b", + "attributes": {} + }, + { + "id": "5b7f8a85-41c9-4815-9ca0-011e15f44e66", + "name": "manage-account-links", + "description": "${role_manage-account-links}", + "composite": false, + "clientRole": true, + "containerId": "c87b98ca-7461-48b1-aad7-35e41d5b579b", + "attributes": {} + }, + { + "id": "94c21df9-44b5-4565-a694-0432eb03b8c1", + "name": "view-profile", + "description": "${role_view-profile}", + "composite": false, + "clientRole": true, + "containerId": "c87b98ca-7461-48b1-aad7-35e41d5b579b", + "attributes": {} + }, + { + "id": "6d169d3c-ecfc-412f-a013-c6d45fd04abc", + "name": "view-consent", + "description": "${role_view-consent}", + "composite": false, + "clientRole": true, + "containerId": "c87b98ca-7461-48b1-aad7-35e41d5b579b", + "attributes": {} + }, + { + "id": "5fcca1e6-03bb-4bb0-bf30-d2ba0e8fb2d5", + "name": "manage-account", + "description": "${role_manage-account}", + "composite": true, + "composites": { + "client": { + "account": [ + "manage-account-links" + ] + } + }, + "clientRole": true, + "containerId": "c87b98ca-7461-48b1-aad7-35e41d5b579b", + "attributes": {} + }, + { + "id": "835ebb45-9c3a-4d60-bb76-6faedac10291", + "name": "manage-consent", + "description": "${role_manage-consent}", + "composite": true, + "composites": { + "client": { + "account": [ + "view-consent" + ] + } + }, + "clientRole": true, + "containerId": "c87b98ca-7461-48b1-aad7-35e41d5b579b", + "attributes": {} + } + ] + } + }, + "groups": [], + "defaultRole": { + "id": "0d702c89-baa5-4a60-b818-5f73933cb9db", + "name": "default-roles-dotcms", + "description": "${role_default-roles}", + "composite": true, + "clientRole": false, + "containerId": "c2d84f46-24fd-4e64-b0a9-f0933b0efa9d" + }, + "requiredCredentials": [ + "password" + ], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpSupportedApplications": [ + "FreeOTP", + "Google Authenticator" + ], + "webAuthnPolicyRpEntityName": "keycloak", + "webAuthnPolicySignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyRpId": "", + "webAuthnPolicyAttestationConveyancePreference": "not specified", + "webAuthnPolicyAuthenticatorAttachment": "not specified", + "webAuthnPolicyRequireResidentKey": "not specified", + "webAuthnPolicyUserVerificationRequirement": "not specified", + "webAuthnPolicyCreateTimeout": 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyAcceptableAaguids": [], + "webAuthnPolicyPasswordlessRpEntityName": "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyPasswordlessRpId": "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", + "webAuthnPolicyPasswordlessCreateTimeout": 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyPasswordlessAcceptableAaguids": [], + "users": [ + { + "id": "6440a66e-b9da-4818-a8e5-7c443b6ce86a", + "createdTimestamp": 1663193849309, + "username": "service-account-analytics-customer-customer1", + "enabled": true, + "totp": false, + "emailVerified": false, + "serviceAccountClientId": "analytics-customer-customer1", + "disableableCredentialTypes": [], + "requiredActions": [], + "realmRoles": [ + "default-roles-dotcms" + ], + "notBefore": 0, + "groups": [] + } + ], + "scopeMappings": [ + { + "clientScope": "offline_access", + "roles": [ + "offline_access" + ] + } + ], + "clientScopeMappings": { + "account": [ + { + "client": "account-console", + "roles": [ + "manage-account" + ] + } + ] + }, + "clients": [ + { + "id": "c87b98ca-7461-48b1-aad7-35e41d5b579b", + "clientId": "account", + "name": "${client_account}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/dotcms/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/dotcms/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "98fc4fcf-ffc5-43c5-b940-781ddaef1c5e", + "clientId": "account-console", + "name": "${client_account-console}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/dotcms/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/realms/dotcms/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "d3ab518c-e2c8-47a2-a31b-258c895d1ed8", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ], + "defaultClientScopes": [ + "web-origins", + "acr", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "5a5faecf-8284-4f05-8dfb-446f792bed60", + "clientId": "admin-cli", + "name": "${client_admin-cli}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "a123e641-7747-4feb-a842-4abb90e7377d", + "clientId": "analytics-customer-customer1", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "testsecret", + "redirectUris": [ + "*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": true, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": true, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "protocolMappers": [ + { + "id": "f5279aef-8eca-405e-a0c8-c697a5f64847", + "name": "Client ID", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientId", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientId", + "jsonType.label": "String" + } + }, + { + "id": "8212d3b3-f99d-49a8-8d7c-36b00898d4dd", + "name": "dotcms-customer1-claim", + "protocol": "openid-connect", + "protocolMapper": "oidc-hardcoded-claim-mapper", + "consentRequired": false, + "config": { + "claim.value": "{\"customerId\":\"customer1\",\"clusterId\":\"cluster1\"}", + "userinfo.token.claim": "false", + "id.token.claim": "false", + "access.token.claim": "true", + "claim.name": "https://dotcms\\.com/analytics", + "jsonType.label": "JSON", + "access.tokenResponse.claim": "false" + } + }, + { + "id": "2c8d16d9-5083-4b56-b056-04415ab5273d", + "name": "Client Host", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientHost", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientHost", + "jsonType.label": "String" + } + }, + { + "id": "d3ba5236-0a6d-4776-925a-b144684c86b8", + "name": "dotcms-customer1-roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-hardcoded-claim-mapper", + "consentRequired": false, + "config": { + "claim.value": "[\"customer\"]", + "userinfo.token.claim": "false", + "id.token.claim": "false", + "access.token.claim": "true", + "claim.name": "https://dotcms\\.com/analytics/roles", + "jsonType.label": "JSON", + "access.tokenResponse.claim": "false" + } + }, + { + "id": "c36c0942-ec8d-475b-8864-8e29a09b0500", + "name": "Client IP Address", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientAddress", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientAddress", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": [ + "dotcms-analytics" + ], + "optionalClientScopes": [] + }, + { + "id": "f50f5154-7bfa-44d7-a125-4717dc69fc77", + "clientId": "broker", + "name": "${client_broker}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "4a5e7947-43b8-4215-82e0-d8b46e838822", + "clientId": "realm-management", + "name": "${client_realm-management}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "5e055154-21ac-4397-b333-8a5cc1f081b6", + "clientId": "security-admin-console", + "name": "${client_security-admin-console}", + "rootUrl": "${authAdminUrl}", + "baseUrl": "/admin/dotcms/console/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [ + "/admin/dotcms/console/*" + ], + "webOrigins": [ + "+" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "a52f02e8-5b7f-4222-bfba-0e76bb824776", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "acr", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + } + ], + "clientScopes": [ + { + "id": "1d37b12c-15c7-4a55-ba24-4cd9901e0da3", + "name": "microprofile-jwt", + "description": "Microprofile - JWT built-in scope", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "bbab86e4-c9ee-48c3-b815-513aa3d1991e", + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "multivalued": "true", + "userinfo.token.claim": "true", + "user.attribute": "foo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String" + } + }, + { + "id": "c2eb6e27-0bfc-4bfc-bcff-35654a09c259", + "name": "upn", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "upn", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "2aeb4fa0-e533-4092-a83a-71f00e44efe2", + "name": "profile", + "description": "OpenID Connect built-in scope: profile", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${profileScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "b0279360-a7a6-4b08-b051-9e7c16db8887", + "name": "updated at", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "updatedAt", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "updated_at", + "jsonType.label": "long" + } + }, + { + "id": "4eb5a55b-47d8-4808-aa82-bfa764b54b35", + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "preferred_username", + "jsonType.label": "String" + } + }, + { + "id": "95e405cc-b9c7-42c3-a693-75cb61ac667e", + "name": "given name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "firstName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "given_name", + "jsonType.label": "String" + } + }, + { + "id": "5c0411c9-fbeb-46b5-8c2f-d08aeabf28cd", + "name": "middle name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "middleName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "middle_name", + "jsonType.label": "String" + } + }, + { + "id": "34d651bf-f031-4a72-b3f6-d5b35f90b335", + "name": "nickname", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "nickname", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "nickname", + "jsonType.label": "String" + } + }, + { + "id": "c0462a4d-90e6-4c6a-b399-0d1298f0528d", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + }, + { + "id": "c5a706b4-5eea-4899-a213-40c5ef0061bc", + "name": "family name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "lastName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "family_name", + "jsonType.label": "String" + } + }, + { + "id": "0acde712-90a2-47dd-8138-67e626ec43f6", + "name": "zoneinfo", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "zoneinfo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "zoneinfo", + "jsonType.label": "String" + } + }, + { + "id": "7eecaccf-d246-4ed4-b8e0-b480e33f9d8a", + "name": "birthdate", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "birthdate", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "birthdate", + "jsonType.label": "String" + } + }, + { + "id": "1f54e46c-799f-435f-bb21-d2b54400726a", + "name": "website", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "website", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "website", + "jsonType.label": "String" + } + }, + { + "id": "c551b600-6a07-44c4-9ce5-c753e9aca6f6", + "name": "profile", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "profile", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "profile", + "jsonType.label": "String" + } + }, + { + "id": "f28bbf39-5e5f-4288-acdd-7e6eace37c94", + "name": "picture", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "picture", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "picture", + "jsonType.label": "String" + } + }, + { + "id": "f1ee2aaa-a3c5-4354-a939-669115d67693", + "name": "full name", + "protocol": "openid-connect", + "protocolMapper": "oidc-full-name-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + }, + { + "id": "3cd9d868-b85b-4501-8b05-ca890bcb926d", + "name": "gender", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "gender", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "gender", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "7ad24138-39d9-4934-8957-2b00774654d8", + "name": "phone", + "description": "OpenID Connect built-in scope: phone", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${phoneScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "66fd4328-1e1c-47ef-a7f8-e091d893b791", + "name": "phone number verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumberVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number_verified", + "jsonType.label": "boolean" + } + }, + { + "id": "e3ed0390-af13-4dfb-a471-a9d0edce8fa2", + "name": "phone number", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumber", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "b121e238-3531-4279-aa1f-d7f6d95b298f", + "name": "acr", + "description": "OpenID Connect scope for add acr (authentication context class reference) to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "b79638f0-136f-4857-97f2-71ea87f4eaa3", + "name": "acr loa level", + "protocol": "openid-connect", + "protocolMapper": "oidc-acr-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + } + ] + }, + { + "id": "2c830d64-f4ca-49f4-94a9-0bd672f6d4cb", + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "true", + "consent.screen.text": "${rolesScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "c6a49ed9-72a2-4324-af1b-600249ff85d7", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "707deecd-86db-4672-be56-19060de01964", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "5f81a25c-d313-40e0-9766-4238738964a4", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "f28cd780-61fc-41ba-969d-7901936ef24b", + "name": "email", + "description": "OpenID Connect built-in scope: email", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${emailScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "bc158984-318a-4759-b394-46972c7159da", + "name": "email verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean" + } + }, + { + "id": "2060a90f-f79e-4466-8003-b4af9d462123", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "a7b0a492-c971-4b18-8cf5-9ee423bc1809", + "name": "address", + "description": "OpenID Connect built-in scope: address", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${addressScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "d3d277e7-d797-4aa7-81ea-fb20eb0b7452", + "name": "address", + "protocol": "openid-connect", + "protocolMapper": "oidc-address-mapper", + "consentRequired": false, + "config": { + "user.attribute.formatted": "formatted", + "user.attribute.country": "country", + "user.attribute.postal_code": "postal_code", + "userinfo.token.claim": "true", + "user.attribute.street": "street", + "id.token.claim": "true", + "user.attribute.region": "region", + "access.token.claim": "true", + "user.attribute.locality": "locality" + } + } + ] + }, + { + "id": "e4151403-d94f-4393-a843-eaffd643ec49", + "name": "dotcms-analytics", + "description": "dotcms-analytics", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "5f37d200-476c-453d-9b9c-a899b943a719", + "name": "api-dotcms-analytics-audience", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "false", + "access.token.claim": "true", + "included.custom.audience": "api-dotcms-analytics-audience", + "userinfo.token.claim": "false" + } + } + ] + }, + { + "id": "d83e05ab-746e-4bfb-bebe-dcd0b3b1f357", + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false", + "consent.screen.text": "" + }, + "protocolMappers": [ + { + "id": "f9aff61f-8671-4342-8bcc-ebc652f31e55", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "757af9b7-5e38-43a2-bd01-106c67ce2dd8", + "name": "offline_access", + "description": "OpenID Connect built-in scope: offline_access", + "protocol": "openid-connect", + "attributes": { + "consent.screen.text": "${offlineAccessScopeConsentText}", + "display.on.consent.screen": "true" + } + }, + { + "id": "f432ddea-d3f4-4f9c-a773-376204dfcc99", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "fc9312d3-ef60-4c1c-bcbd-712cc68da78b", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + } + ], + "defaultDefaultClientScopes": [ + "profile", + "roles", + "acr", + "web-origins", + "email", + "role_list" + ], + "defaultOptionalClientScopes": [ + "microprofile-jwt", + "offline_access", + "phone", + "address" + ], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "xRobotsTag": "none", + "xFrameOptions": "SAMEORIGIN", + "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection": "1; mode=block", + "strictTransportSecurity": "max-age=31536000; includeSubDomains" + }, + "smtpServer": {}, + "eventsEnabled": false, + "eventsListeners": [ + "jboss-logging" + ], + "enabledEventTypes": [], + "adminEventsEnabled": false, + "adminEventsDetailsEnabled": false, + "identityProviders": [], + "identityProviderMappers": [], + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "24c97025-f0c0-442d-bb57-7278a139fdd3", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": [ + "true" + ], + "client-uris-must-match": [ + "true" + ] + } + }, + { + "id": "ffee4d74-a29d-49de-ae1a-59f3bd618b82", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": [ + "200" + ] + } + }, + { + "id": "86a7d9dc-cbe6-46d0-9467-537d74367c41", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "4ef53676-e3a0-4ac9-8996-480871f2e1dc", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "c7a16421-2a37-4a82-af86-bf4862f58284", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "dfc740b3-bc84-49b4-be55-c120debabc2d", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-role-list-mapper", + "oidc-full-name-mapper", + "oidc-address-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-usermodel-attribute-mapper", + "saml-user-property-mapper", + "oidc-usermodel-property-mapper", + "saml-user-attribute-mapper" + ] + } + }, + { + "id": "844ebf9f-2fcb-46c2-bd26-6a9d7ccd46fb", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "728d6f54-e5af-46ae-9e66-f1c48b678ad6", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-usermodel-property-mapper", + "saml-user-attribute-mapper", + "oidc-full-name-mapper", + "saml-user-property-mapper", + "oidc-usermodel-attribute-mapper", + "saml-role-list-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-address-mapper" + ] + } + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "4b965f2f-81f0-45b7-b41b-38442966280e", + "name": "rsa-enc-generated", + "providerId": "rsa-enc-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "RSA-OAEP" + ] + } + }, + { + "id": "3f0f46d2-60db-4ee2-afe2-e948ce4eb32f", + "name": "hmac-generated", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "HS256" + ] + } + }, + { + "id": "f30e4465-72cc-45c5-bbf5-9339c9f0acd0", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "d3250f0f-f995-498e-ab86-73aa64832fef", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "e7f2e461-f9ad-45d8-bb11-85b8ca4dc98e", + "alias": "Account verification options", + "description": "Method with which to verity the existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-email-verification", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false + } + ] + }, + { + "id": "4eb6626c-4cdb-47f8-9bf4-119b5798c42c", + "alias": "Authentication Options", + "description": "Authentication options.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "basic-auth", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "basic-auth-otp", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "2d8c1e79-5b37-48ad-9430-61b121df7a54", + "alias": "Browser - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "43b5ae13-2859-4e29-90b2-a12fa14f5880", + "alias": "Direct Grant - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "999fb0c5-8a20-4e4a-9d76-690255ccba4b", + "alias": "First broker login - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "1ee2a128-c3ec-4706-bf55-553475bb7b2e", + "alias": "Handle Existing Account", + "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-confirm-link", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Account verification options", + "userSetupAllowed": false + } + ] + }, + { + "id": "ff5716a9-6728-4c1e-8f2a-ded918a47ee2", + "alias": "Reset - Conditional OTP", + "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "3b16b201-b663-41b4-997c-a4b1e1bb06fe", + "alias": "User creation or linking", + "description": "Flow for the existing/non-existing user alternatives", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false + } + ] + }, + { + "id": "944849f1-b670-47e9-bdf5-6345759795f5", + "alias": "Verify Existing Account by Re-authentication", + "description": "Reauthentication of existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "First broker login - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "744664da-4702-4f0b-ba4f-fd4419a540ac", + "alias": "browser", + "description": "browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "identity-provider-redirector", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 25, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "forms", + "userSetupAllowed": false + } + ] + }, + { + "id": "56bfba5f-995b-420e-96cf-b0b841cc9d51", + "alias": "clients", + "description": "Base authentication for clients", + "providerId": "client-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "client-secret", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-secret-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-x509", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "64d644f6-5c37-435e-a5b6-34f4b30729e3", + "alias": "direct grant", + "description": "OpenID Connect Resource Owner Grant", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "direct-grant-validate-username", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "Direct Grant - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "28fb8933-c1b3-496b-9c5b-2deb5d627e4a", + "alias": "docker auth", + "description": "Used by Docker clients to authenticate against the IDP", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "docker-http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "8eb12082-1cdc-47b0-8d8e-150832f5091b", + "alias": "first broker login", + "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "review profile config", + "authenticator": "idp-review-profile", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "User creation or linking", + "userSetupAllowed": false + } + ] + }, + { + "id": "2a0fa96c-4c05-4973-8f2e-44e2c5939ce5", + "alias": "forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "b25e2a42-6b99-43eb-8630-eaa22d86393b", + "alias": "http challenge", + "description": "An authentication flow based on challenge-response HTTP Authentication Schemes", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "no-cookie-redirect", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Authentication Options", + "userSetupAllowed": false + } + ] + }, + { + "id": "9758f4a2-c995-4113-9e0c-ac07b4aae4b4", + "alias": "registration", + "description": "registration flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-page-form", + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": true, + "flowAlias": "registration form", + "userSetupAllowed": false + } + ] + }, + { + "id": "683e6b13-fd26-48ea-a427-0cb22a33f29d", + "alias": "registration form", + "description": "registration form", + "providerId": "form-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-user-creation", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-profile-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-password-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 50, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-recaptcha-action", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 60, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "4ad9683f-7e97-4ea6-902a-c3bb0af53f81", + "alias": "reset credentials", + "description": "Reset credentials for a user if they forgot their password or something", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "reset-credentials-choose-user", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-credential-email", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 40, + "autheticatorFlow": true, + "flowAlias": "Reset - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "6cb879f1-c45e-42c0-b0c3-9a1bec24ed72", + "alias": "saml ecp", + "description": "SAML ECP Profile Authentication Flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + } + ], + "authenticatorConfig": [ + { + "id": "502a8dff-26a3-4564-ad27-f3cec1d72932", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "92447eb8-7e2f-4e83-aec0-a1c461cf1ee8", + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + } + ], + "requiredActions": [ + { + "alias": "CONFIGURE_TOTP", + "name": "Configure OTP", + "providerId": "CONFIGURE_TOTP", + "enabled": true, + "defaultAction": false, + "priority": 10, + "config": {} + }, + { + "alias": "terms_and_conditions", + "name": "Terms and Conditions", + "providerId": "terms_and_conditions", + "enabled": false, + "defaultAction": false, + "priority": 20, + "config": {} + }, + { + "alias": "UPDATE_PASSWORD", + "name": "Update Password", + "providerId": "UPDATE_PASSWORD", + "enabled": true, + "defaultAction": false, + "priority": 30, + "config": {} + }, + { + "alias": "UPDATE_PROFILE", + "name": "Update Profile", + "providerId": "UPDATE_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 40, + "config": {} + }, + { + "alias": "VERIFY_EMAIL", + "name": "Verify Email", + "providerId": "VERIFY_EMAIL", + "enabled": true, + "defaultAction": false, + "priority": 50, + "config": {} + }, + { + "alias": "delete_account", + "name": "Delete Account", + "providerId": "delete_account", + "enabled": false, + "defaultAction": false, + "priority": 60, + "config": {} + }, + { + "alias": "update_user_locale", + "name": "Update User Locale", + "providerId": "update_user_locale", + "enabled": true, + "defaultAction": false, + "priority": 1000, + "config": {} + } + ], + "browserFlow": "browser", + "registrationFlow": "registration", + "directGrantFlow": "direct grant", + "resetCredentialsFlow": "reset credentials", + "clientAuthenticationFlow": "clients", + "dockerAuthenticationFlow": "docker auth", + "attributes": { + "cibaBackchannelTokenDeliveryMode": "poll", + "cibaExpiresIn": "120", + "cibaAuthRequestedUserHint": "login_hint", + "oauth2DeviceCodeLifespan": "600", + "clientOfflineSessionMaxLifespan": "0", + "oauth2DevicePollingInterval": "5", + "clientSessionIdleTimeout": "0", + "parRequestUriLifespan": "60", + "clientSessionMaxLifespan": "0", + "clientOfflineSessionIdleTimeout": "0", + "cibaInterval": "5" + }, + "keycloakVersion": "18.0.2", + "userManagedAccessAllowed": false, + "clientProfiles": { + "profiles": [] + }, + "clientPolicies": { + "policies": [] + } +} \ No newline at end of file diff --git a/docker/docker-compose-examples/analytics/setup/db/mssql/entrypoint.sh b/docker/docker-compose-examples/analytics/setup/db/mssql/entrypoint.sh new file mode 100644 index 000000000000..fb33f75de424 --- /dev/null +++ b/docker/docker-compose-examples/analytics/setup/db/mssql/entrypoint.sh @@ -0,0 +1,17 @@ +#!/bin/bash +wait_time=15s + +# wait for SQL Server to come up +echo "" +echo "---" +echo importing data will start in $wait_time... +sleep $wait_time + +echo "" +echo "---" +echo importing data... + +# run the init script to create the DB and the tables in /table +/opt/mssql-tools/bin/sqlcmd -S 0.0.0.0 -U sa -P ${MSSQL_SA_PASSWORD} -i ./init-scripts/init.sql + +echo data imported... \ No newline at end of file diff --git a/docker/docker-compose-examples/analytics/setup/db/mssql/init-scripts/init.sql b/docker/docker-compose-examples/analytics/setup/db/mssql/init-scripts/init.sql new file mode 100644 index 000000000000..a0607d491f4f --- /dev/null +++ b/docker/docker-compose-examples/analytics/setup/db/mssql/init-scripts/init.sql @@ -0,0 +1,7 @@ +CREATE DATABASE dotcms; + +ALTER DATABASE dotcms SET READ_COMMITTED_SNAPSHOT ON; +GO + +ALTER DATABASE dotcms SET ALLOW_SNAPSHOT_ISOLATION ON; +GO \ No newline at end of file diff --git a/docker/docker-compose-examples/analytics/setup/db/postgres/init-scripts/init-config.sh b/docker/docker-compose-examples/analytics/setup/db/postgres/init-scripts/init-config.sh new file mode 100644 index 000000000000..97e0cd6f80aa --- /dev/null +++ b/docker/docker-compose-examples/analytics/setup/db/postgres/init-scripts/init-config.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +set -e + +echo "Detected MAX_LOCKS_PER_TRANSACTION: '${MAX_LOCKS_PER_TRANSACTION}'" +max_locks=$(echo -e "${MAX_LOCKS_PER_TRANSACTION}" | tr -d '[:space:]') + +if [[ "${max_locks}" != '' ]]; then + sed -i "s,^#max_locks_per_transaction =.*$,max_locks_per_transaction = ${max_locks},g" /var/lib/postgresql/data/postgresql.conf \ + cat /var/lib/postgresql/data/postgresql.conf | grep 'max_locks_per_transaction' +fi diff --git a/docker/docker-compose-examples/analytics/setup/db/postgres/init-scripts/init.sql b/docker/docker-compose-examples/analytics/setup/db/postgres/init-scripts/init.sql new file mode 100644 index 000000000000..3c939294d620 --- /dev/null +++ b/docker/docker-compose-examples/analytics/setup/db/postgres/init-scripts/init.sql @@ -0,0 +1 @@ +-- CREATE LANGUAGE plpgsql; diff --git a/docker/docker-compose-examples/cluster-mode/README.md b/docker/docker-compose-examples/cluster-mode/README.md new file mode 100644 index 000000000000..5f608a3bec41 --- /dev/null +++ b/docker/docker-compose-examples/cluster-mode/README.md @@ -0,0 +1,54 @@ +# Dotcms Cluster Mode + +Cluster with 2 dotCMS instances running on ports 8080 and 8081 respectively. Database: postgres + +## Usage + +#### Environment setup + + +1) A local path to license pack must be set here: + +``` +- {license_local_path}/license.zip:/data/shared/assets/license.zip +``` + +The license pack must contain at least two licenses (one for each node in the cluster) + + +2) A local path to access data in the instance can be set uncommenting this line: + +``` +#- {local_data_path}:/data/shared +``` + +3) A custom starter can be set through this line (uncomment and change the starter url accordingly): + +``` +#"CUSTOM_STARTER_URL": 'https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/starter/20210920/starter-20210920.zip' +``` + +#### Deploying nodes: + +```bash +docker-compose -f docker-compose-node-1.yml up + +``` + +Once the node 1 is running, deploy node 2: +```bash +docker-compose -f docker-compose-node-2.yml up + +``` + + +#### Undeploying nodes: + +```bash +docker-compose -f docker-compose-node-2.yml down +docker-compose -f docker-compose-node-1.yml down +``` + +**Important note:** `ctrl+c` does not destroy instances + + diff --git a/docker/docker-compose-examples/cluster-mode/docker-compose-node-1.yml b/docker/docker-compose-examples/cluster-mode/docker-compose-node-1.yml new file mode 100644 index 000000000000..4148567bb0cd --- /dev/null +++ b/docker/docker-compose-examples/cluster-mode/docker-compose-node-1.yml @@ -0,0 +1,74 @@ +version: '3.5' + +networks: + db_net: + opensearch-net: + +volumes: + cms-shared: + dbdata: + opensearch-data: + +services: + opensearch: + image: opensearchproject/opensearch:1.3.6 + environment: + - cluster.name=elastic-cluster + - discovery.type=single-node + - data + - bootstrap.memory_lock=true + - "OPENSEARCH_JAVA_OPTS=-Xmx1G " + ulimits: + memlock: + soft: -1 # Set memlock to unlimited (no soft or hard limit) + hard: -1 + nofile: + soft: 65536 # Maximum number of open files for the opensearch user - set to at least 65536 + hard: 65536 + ports: + - 9200:9200 + - 9600:9600 + volumes: + - opensearch-data:/usr/share/opensearch/data + networks: + - opensearch-net + + dotcms-node-1: + image: dotcms/dotcms:latest + environment: + CMS_JAVA_OPTS: '-Xmx1g ' + LANG: 'C.UTF-8' + TZ: 'UTC' + DB_BASE_URL: "jdbc:postgresql://db/dotcms" + DB_USERNAME: 'dotcmsdbuser' + DB_PASSWORD: 'password' + DOT_ES_AUTH_BASIC_PASSWORD: 'admin' + DOT_ES_ENDPOINTS: 'https://opensearch:9200' + DOT_INITIAL_ADMIN_PASSWORD: 'admin' + DOT_DOTCMS_CLUSTER_ID: 'dotcms-production' + #CUSTOM_STARTER_URL: 'https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/starter/20211201/starter-20211201.zip' + depends_on: + - opensearch + - db + volumes: + #- {local_data_path}:/data/shared + - {license_local_path}/license.zip:/data/shared/assets/license.zip + networks: + - db_net + - opensearch-net + ports: + - "8082:8082" + - "8443:8443" + + db: + image: postgres:15 + command: postgres -c 'max_connections=400' -c 'shared_buffers=128MB' + environment: + "POSTGRES_USER": 'dotcmsdbuser' + "POSTGRES_PASSWORD": 'password' + "POSTGRES_DB": 'dotcms' + volumes: + - dbdata:/var/lib/postgresql/data + networks: + - db_net + diff --git a/docker/docker-compose-examples/cluster-mode/docker-compose-node-2.yml b/docker/docker-compose-examples/cluster-mode/docker-compose-node-2.yml new file mode 100644 index 000000000000..5271c3ecc0a7 --- /dev/null +++ b/docker/docker-compose-examples/cluster-mode/docker-compose-node-2.yml @@ -0,0 +1,35 @@ +version: '3.5' + +networks: + cluster-mode_db_net: + external: true + cluster-mode_opensearch-net: + external: true + +volumes: + cms-shared: + +services: + dotcms-node-2: + image: dotcms/dotcms:latest + environment: + CMS_JAVA_OPTS: '-Xmx1g ' + LANG: 'C.UTF-8' + TZ: 'UTC' + DB_BASE_URL: "jdbc:postgresql://db/dotcms" + DB_USERNAME: 'dotcmsdbuser' + DB_PASSWORD: 'password' + DOT_ES_AUTH_BASIC_PASSWORD: 'admin' + DOT_ES_ENDPOINTS: 'https://opensearch:9200' + DOT_INITIAL_ADMIN_PASSWORD: 'admin' + DOT_DOTCMS_CLUSTER_ID: 'dotcms-production' + #CUSTOM_STARTER_URL: 'https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/starter/20211201/starter-20211201.zip' + volumes: + #- {local_data_path}:/data/shared + - {license_local_path}/license.zip:/data/shared/assets/license.zip + networks: + - cluster-mode_db_net + - cluster-mode_opensearch-net + ports: + - "8081:8082" + - "8444:8443" diff --git a/docker/docker-compose-examples/push-publish/README.md b/docker/docker-compose-examples/push-publish/README.md new file mode 100644 index 000000000000..1ae8639d878c --- /dev/null +++ b/docker/docker-compose-examples/push-publish/README.md @@ -0,0 +1,48 @@ +# Dotcms Push Publish + +Push publish environment where the sender runs on port 8080 and the receiver on 8081. Database: postgres. + +**Important note:** For the endpoint configuration, the local IP address must be used instead of `localhost` or `127.0.0.1` + +## Usage + +#### Environment setup + + +1) A local path to license pack must be set here: + +``` +- {license_local_path}/license.zip:/data/shared/assets/license.zip +``` + +The license pack must contain at least two licenses (one for each node in the cluster) + + +2) A local path to access data in the instance can be set uncommenting this line: + +``` +#- {local_data_path}:/data/shared +``` + +3) A custom starter can be set through this line (uncomment and change the starter url accordingly): + +``` +#"CUSTOM_STARTER_URL": 'https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/starter/20210920/starter-20210920.zip' +``` + +#### Deploying nodes: + +```bash +docker-compose -f docker-compose-sender.yml up +docker-compose -f docker-compose-receiver.yml up + +``` + +#### Undeploying nodes: + +```bash +docker-compose -f docker-compose-sender.yml down +docker-compose -f docker-compose-receiver.yml down +``` + +**Important note:** `ctrl+c` does not destroy instances diff --git a/docker/docker-compose-examples/push-publish/docker-compose-receiver.yml b/docker/docker-compose-examples/push-publish/docker-compose-receiver.yml new file mode 100644 index 000000000000..c97370952002 --- /dev/null +++ b/docker/docker-compose-examples/push-publish/docker-compose-receiver.yml @@ -0,0 +1,74 @@ +version: '3.5' + +networks: + db_net_receiver: + opensearch-net_receiver: + +volumes: + dbdata_receiver: + opensearch-data_receiver: + +services: + opensearch-receiver: + image: opensearchproject/opensearch:1.3.6 + environment: + - cluster.name=elastic-cluster + - discovery.type=single-node + - data + - bootstrap.memory_lock=true + - "OPENSEARCH_JAVA_OPTS=-Xmx1G " + ulimits: + memlock: + soft: -1 # Set memlock to unlimited (no soft or hard limit) + hard: -1 + nofile: + soft: 65536 # Maximum number of open files for the opensearch user - set to at least 65536 + hard: 65536 + ports: + - 9201:9200 + - 9601:9600 + volumes: + - opensearch-data_receiver:/usr/share/opensearch/data + networks: + - opensearch-net_receiver + + dotcms-receiver: + image: dotcms/dotcms:latest + environment: + CMS_JAVA_OPTS: '-Xmx1g ' + LANG: 'C.UTF-8' + TZ: 'UTC' + DB_BASE_URL: "jdbc:postgresql://db-receiver/dotcms" + DB_USERNAME: 'dotcmsdbuser' + DB_PASSWORD: 'password' + DOT_ES_AUTH_BASIC_PASSWORD: 'admin' + DOT_ES_ENDPOINTS: 'https://opensearch-receiver:9200' + DOT_INITIAL_ADMIN_PASSWORD: 'admin' + DOT_DOTCMS_CLUSTER_ID: 'dotcms-receiver' + #CUSTOM_STARTER_URL: 'https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/starter/20211201/starter-20211201.zip' + depends_on: + - opensearch-receiver + - db-receiver + volumes: + #- {local_data_path}:/data/shared + - {license_local_path}/license.zip:/data/shared/assets/license.zip + networks: + - db_net_receiver + - opensearch-net_receiver + ports: + - "8081:8082" + - "8444:8443" + + db-receiver: + image: postgres:15 + command: postgres -c 'max_connections=400' -c 'shared_buffers=128MB' + environment: + "POSTGRES_USER": 'dotcmsdbuser' + "POSTGRES_PASSWORD": 'password' + "POSTGRES_DB": 'dotcms' + volumes: + - dbdata_receiver:/var/lib/postgresql/data + networks: + - db_net_receiver + + diff --git a/docker/docker-compose-examples/push-publish/docker-compose-sender.yml b/docker/docker-compose-examples/push-publish/docker-compose-sender.yml new file mode 100644 index 000000000000..433ba9c91390 --- /dev/null +++ b/docker/docker-compose-examples/push-publish/docker-compose-sender.yml @@ -0,0 +1,74 @@ +version: '3.5' + +networks: + db_net_sender: + opensearch-net_sender: + +volumes: + dbdata_sender: + opensearch-data_sender: + +services: + opensearch-sender: + image: opensearchproject/opensearch:1.3.6 + environment: + - cluster.name=elastic-cluster + - discovery.type=single-node + - data + - bootstrap.memory_lock=true + - "OPENSEARCH_JAVA_OPTS=-Xmx1G " + ulimits: + memlock: + soft: -1 # Set memlock to unlimited (no soft or hard limit) + hard: -1 + nofile: + soft: 65536 # Maximum number of open files for the opensearch user - set to at least 65536 + hard: 65536 + ports: + - 9200:9200 + - 9600:9600 + volumes: + - opensearch-data_sender:/usr/share/opensearch/data + networks: + - opensearch-net_sender + + dotcms-sender: + image: dotcms/dotcms:latest + environment: + CMS_JAVA_OPTS: '-Xmx1g ' + LANG: 'C.UTF-8' + TZ: 'UTC' + DB_BASE_URL: "jdbc:postgresql://db-sender/dotcms" + DB_USERNAME: 'dotcmsdbuser' + DB_PASSWORD: 'password' + DOT_ES_AUTH_BASIC_PASSWORD: 'admin' + DOT_ES_ENDPOINTS: 'https://opensearch-sender:9200' + DOT_INITIAL_ADMIN_PASSWORD: 'admin' + DOT_DOTCMS_CLUSTER_ID: 'dotcms-sender' + #CUSTOM_STARTER_URL: 'https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/starter/20211201/starter-20211201.zip' + depends_on: + - opensearch-sender + - db-sender + volumes: + #- {local_data_path}:/data/shared + - {license_local_path}/license.zip:/data/shared/assets/license.zip + networks: + - db_net_sender + - opensearch-net_sender + ports: + - "8082:8082" + - "8443:8443" + + db-sender: + image: postgres:15 + command: postgres -c 'max_connections=400' -c 'shared_buffers=128MB' + environment: + "POSTGRES_USER": 'dotcmsdbuser' + "POSTGRES_PASSWORD": 'password' + "POSTGRES_DB": 'dotcms' + volumes: + - dbdata_sender:/var/lib/postgresql/data + networks: + - db_net_sender + + diff --git a/docker/docker-compose-examples/push-publish/receiver/docker-compose.yml b/docker/docker-compose-examples/push-publish/receiver/docker-compose.yml new file mode 100644 index 000000000000..124260dbe491 --- /dev/null +++ b/docker/docker-compose-examples/push-publish/receiver/docker-compose.yml @@ -0,0 +1,74 @@ +version: '3.5' + +networks: + db_net_sender: + opensearch-net_sender: + +volumes: + dbdata_sender: + opensearch-data_sender: + +services: + opensearch-sender: + image: opensearchproject/opensearch:1.3.6 + environment: + - cluster.name=elastic-cluster + - discovery.type=single-node + - data + - bootstrap.memory_lock=true + - "OPENSEARCH_JAVA_OPTS=-Xmx1G " + ulimits: + memlock: + soft: -1 # Set memlock to unlimited (no soft or hard limit) + hard: -1 + nofile: + soft: 65536 # Maximum number of open files for the opensearch user - set to at least 65536 + hard: 65536 + ports: + - 9200:9200 + - 9600:9600 + volumes: + - opensearch-data_sender:/usr/share/opensearch/data + networks: + - opensearch-net_sender + + dotcms-sender: + image: dotcms/dotcms:22.12_f479a493_SNAPSHOT + environment: + CMS_JAVA_OPTS: '-Xmx1g ' + LANG: 'C.UTF-8' + TZ: 'UTC' + DB_BASE_URL: "jdbc:postgresql://db-sender/dotcms" + DB_USERNAME: 'dotcmsdbuser' + DB_PASSWORD: 'password' + DOT_ES_AUTH_BASIC_PASSWORD: 'admin' + DOT_ES_ENDPOINTS: 'https://opensearch-sender:9200' + DOT_INITIAL_ADMIN_PASSWORD: 'admin' + DOT_DOTCMS_CLUSTER_ID: 'dotcms-sender' + #CUSTOM_STARTER_URL: 'https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/starter/20211201/starter-20211201.zip' + depends_on: + - opensearch-sender + - db-sender + # volumes: + # #- {local_data_path}:/data/shared + # - {license_local_path}/license.zip:/data/shared/assets/license.zip + networks: + - db_net_sender + - opensearch-net_sender + ports: + - "8082:8082" + - "8443:8443" + + db-sender: + image: postgres:15 + command: postgres -c 'max_connections=400' -c 'shared_buffers=128MB' + environment: + "POSTGRES_USER": 'dotcmsdbuser' + "POSTGRES_PASSWORD": 'password' + "POSTGRES_DB": 'dotcms' + volumes: + - dbdata_sender:/var/lib/postgresql/data + networks: + - db_net_sender + + diff --git a/docker/docker-compose-examples/scripts/dotcms-get-demo-site-starter-urls.sh b/docker/docker-compose-examples/scripts/dotcms-get-demo-site-starter-urls.sh new file mode 100644 index 000000000000..d3f1ab883bee --- /dev/null +++ b/docker/docker-compose-examples/scripts/dotcms-get-demo-site-starter-urls.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# Prints docker-compose.yml snippets to fetch the proper +# Demo Site content for each dotCMS version + +# This clones the dotCMS core repo on its first run which will take some time + +gitdir=/var/tmp/dotcms-get-starter-urls-repo +if [ ! -d $gitdir ] +then + echo "Cloning dotcms core repo to $gitdir" + git clone https://github.com/dotCMS/core.git $gitdir +fi + +pushd $gitdir >/dev/null +git checkout -q master +git pull -q +for version in $(git tag -l v* | sed 's/^v//' | sort -n | uniq | grep -v MM.YY) +do + echo + git checkout -q v${version} + starter_date=$(grep 'starter group' dotCMS/build.gradle | grep -v empty_ | awk -F \' '{print $6}') + cat </dev/null diff --git a/docker/docker-compose-examples/scripts/dotcms_properties_to_env_vars.py b/docker/docker-compose-examples/scripts/dotcms_properties_to_env_vars.py new file mode 100644 index 000000000000..f14ba19a729f --- /dev/null +++ b/docker/docker-compose-examples/scripts/dotcms_properties_to_env_vars.py @@ -0,0 +1,199 @@ +#!/usr/bin/env python3 + +import argparse +from pathlib import Path + +epilog = """ +Retrieve settings from .properties files from "binary install" of dotCMS, +and print them out in docker or k8s yaml environment variable format + +see https://www.dotcms.com/docs/latest/configuration-properties#EnvironmentVariables +""" + + +def list_properties_files( + search_path="/home/dotcms/wwwroot/current/plugins/com.dotcms.config/conf", +): + """ + returns a list of possible dotcms properties files + """ + properties_files = [] + conf_path = Path(search_path) + if conf_path.is_file(): + properties_files = [conf_path] + elif conf_path.is_dir(): + for base in [ + "dotmarketing-config", + "dotcms-config-cluster", + "portal", + "system", + ]: + for ext in ["", "-ext"]: + for ini in ["", ".ini"]: + properties_files += list(Path(conf_path).glob(f"**/{base}{ext}.properties{ini}")) + else: + print(f"specified path '{conf_path}' is not a file or directory") + if not properties_files: + print(f"No properties files found on path: {conf_path}") + return properties_files + + +def get_property_value(line): + """ + parse a single line from a config file + return a dict e.g. + {"property" : "CMS_HEAP_SIZE", "value": "10g"} + """ + ignored_properties = [ + "DOT_ASSET_REAL_PATH", + "DOT_DOTCMS_LOGGING_HOME", + "DOT_DYNAMIC_CONTENT_PATH", + "DOT_TAIL_LOG_LOG_FOLDER", + "DOT_FELIX_BASE_DIR", + "DOT_FELIX_FELIX_FILEINSTALL_DIR", + "DOT_FELIX_FELIX_UNDEPLOYED_DIR", + "DOT_ES_PATH_DATA", + "DOT_ES_PATH_WORK", + "DOT_ES_HTTP_ENABLED", + "DOT_ES_HTTP_CORS_ENABLED", + "DOT_ES_HTTP_PORT", + "DOT_ES_HTTP_HOST", + ] + line = line.strip() + (prop, value) = line.split("=", 1) + prop = "DOT_" + prop.strip().upper().replace(".", "_") + value = value.strip() + if not value: + value = "" + # quote yaml literals and int's + value = yaml_safe_value(value) + env_var = {} + if prop not in ignored_properties: + env_var = {"property": prop, "value": value} + return env_var + + +def parse_properties_file(properties_files): + output_lines = [] + for file in properties_files: + try: + with open(file, "r") as f: + properties_contents = f.readlines() + except FileNotFoundError: + continue + for line in properties_contents: + line = line.strip() + if not line: + pass + elif "=" in line and not line.startswith("#"): + parsed_line = get_property_value(line) + if parsed_line: + output_lines.append(parsed_line) + return output_lines + + +def print_properties_docker_yml(properties): + """ + each element in "properties" should either be a dict with a "comment" key, or with both "property" and "value" keys set + """ + prepend = 6 * " " + for line in properties: + print(f'{prepend}{line["property"]}: {line["value"]}') + + +def print_properties_k8s(properties): + """ + each element in "properties" should either be a dict with a "comment" key, or with both "property" and "value" keys set + """ + prepend = 8 * " " + print(f"{prepend}env:") + for line in properties: + print(f'{prepend} - name: {line["property"]}') + print(f"{prepend} value: {line['value']}") + + +def yaml_safe_value(value): + """ + env var values which are ints or literals must be quoted in docker/k8s yaml config files else yaml processor + does not pass them to docker/k8s as strings + + we also convert yaml null to empty string, though we should not encounter nulls in this script + """ + yaml_nulls = ( + "null", + "Null", + "NULL", + ) + + yaml_bools = ( + "y", + "Y", + "yes", + "Yes", + "YES", + "n", + "N", + "no", + "No", + "NO", + "true", + "True", + "TRUE", + "false", + "False", + "FALSE", + "on", + "On", + "ON", + "off", + "Off", + "OFF", + ) + try: + value = int(value) + except (TypeError, ValueError): + pass + if isinstance(value, int) or value in yaml_bools: + value = f'"{value}"' + elif value in yaml_nulls: + value = "" + return value + + +if __name__ == "__main__": + output_choices = ["docker", "k8s"] + parser = argparse.ArgumentParser( + description="Convert dotCMS config plugin properties to ENV vars", + epilog=epilog, + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + parser.add_argument( + "--format", + choices=output_choices, + default="docker", + help="output formats: " + ",".join(output_choices), + ) + parser.add_argument( + "propfile", + help="Filesystem path to a properties file, or a conf directory containing dotcms properties files. These files will reside in plugins/com.dotcms.config/conf if a ROOT config plugin was used" + ) + args = parser.parse_args() + + properties_files = list_properties_files(args.propfile) + properties = parse_properties_file(properties_files) + + print() + if args.format == "docker": + print_properties_docker_yml(properties) + elif args.format == "k8s": + print_properties_k8s(properties) + print() + print(""" +## Be sure to verify these values before running in production! +## Remember integers and booleans should be quoted in yaml for docker compose and k8s config. +## Source properties files: +""") + for file in properties_files: + print(f"## {file}") + print() + diff --git a/docker/docker-compose-examples/single-node-debug-mode/Intellij Debug Mode.png b/docker/docker-compose-examples/single-node-debug-mode/Intellij Debug Mode.png new file mode 100644 index 000000000000..a215dfbcea4f Binary files /dev/null and b/docker/docker-compose-examples/single-node-debug-mode/Intellij Debug Mode.png differ diff --git a/docker/docker-compose-examples/single-node-debug-mode/README.md b/docker/docker-compose-examples/single-node-debug-mode/README.md new file mode 100644 index 000000000000..5f495f530136 --- /dev/null +++ b/docker/docker-compose-examples/single-node-debug-mode/README.md @@ -0,0 +1,50 @@ +# Dotcms Single Node (Debug Mode) + +A single instance of dotcms running on port 8080. Database: postgres. Debug mode enabled on port 8000 + +## Usage + +#### Environment setup + + +1) A local path to license pack must be set here: + +``` +- {license_local_path}/license.zip:/data/shared/assets/license.zip +``` + +2) A local path to access data in the instance can be set uncommenting this line: + +``` +#- {local_data_path}:/data/shared +``` + +3) A custom starter can be set through this line (uncomment and change the starter url accordingly): + +``` +#"CUSTOM_STARTER_URL": 'https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/starter/20210920/starter-20210920.zip' +``` + +#### Run an example: + +```bash +docker-compose up +``` + +#### Shut down instances: + +```bash +docker-compose down +``` + +**Important note:** `ctrl+c` does not destroy instances + + +4) Configure your IDE enabling remote debugging: + +![Remote Debugging](https://github.com/dotCMS/core/blob/new-docker-compose-examples/docker/docker-compose-examples/single-node-debug-mode/Intellij%20Debug%20Mode.png?raw=true) + + + + + diff --git a/docker/docker-compose-examples/single-node-debug-mode/docker-compose.yml b/docker/docker-compose-examples/single-node-debug-mode/docker-compose.yml new file mode 100644 index 000000000000..71f28daf57d3 --- /dev/null +++ b/docker/docker-compose-examples/single-node-debug-mode/docker-compose.yml @@ -0,0 +1,75 @@ +version: '3.5' + +networks: + db_net: + opensearch-net: + +volumes: + cms-shared: + dbdata: + opensearch-data: + +services: + opensearch: + image: opensearchproject/opensearch:1.3.6 + environment: + - cluster.name=elastic-cluster + - discovery.type=single-node + - data + - bootstrap.memory_lock=true + - "OPENSEARCH_JAVA_OPTS=-Xmx1G " + ulimits: + memlock: + soft: -1 # Set memlock to unlimited (no soft or hard limit) + hard: -1 + nofile: + soft: 65536 # Maximum number of open files for the opensearch user - set to at least 65536 + hard: 65536 + ports: + - 9200:9200 + - 9600:9600 + volumes: + - opensearch-data:/usr/share/opensearch/data + networks: + - opensearch-net + + dotcms: + image: dotcms/dotcms:latest + environment: + CMS_JAVA_OPTS: '-Xmx1g -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=*:8000 ' + LANG: 'C.UTF-8' + TZ: 'UTC' + DB_BASE_URL: "jdbc:postgresql://db/dotcms" + DB_USERNAME: 'dotcmsdbuser' + DB_PASSWORD: 'password' + DOT_ES_AUTH_BASIC_PASSWORD: 'admin' + DOT_ES_ENDPOINTS: 'https://opensearch:9200' + DOT_INITIAL_ADMIN_PASSWORD: 'admin' + DOT_DOTCMS_CLUSTER_ID: 'dotcms-production' + #CUSTOM_STARTER_URL: 'https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/starter/20211201/starter-20211201.zip' + depends_on: + - opensearch + - db + volumes: + - cms-shared:/data/shared + #- {license_local_path}/license.zip:/data/shared/assets/license.zip + networks: + - db_net + - opensearch-net + ports: + - "8082:8082" + - "8000:8000" + - "8443:8443" + + db: + image: postgres:15 + command: postgres -c 'max_connections=400' -c 'shared_buffers=128MB' + environment: + "POSTGRES_USER": 'dotcmsdbuser' + "POSTGRES_PASSWORD": 'password' + "POSTGRES_DB": 'dotcms' + volumes: + - dbdata:/var/lib/postgresql/data + networks: + - db_net + diff --git a/docker/docker-compose-examples/single-node-demo-site/README.md b/docker/docker-compose-examples/single-node-demo-site/README.md new file mode 100644 index 000000000000..db535820592a --- /dev/null +++ b/docker/docker-compose-examples/single-node-demo-site/README.md @@ -0,0 +1,33 @@ +# Dotcms Single Node With Demo Content + +A single instance of dotcms running on port 8080 that will download and install the demo site on initialization. Database: postgres + +## Usage +`scripts/dotcms-get-demo-site-starter-urls.sh` prints the correct demo site starter URL for each dotCMS version + +#### Environment setup +Specifiy a custom starter that will be included: +``` +"CUSTOM_STARTER_URL": "https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/xxxxxxxxxx.zip" +``` +A local path to license pack can be set here: + +``` +- {license_local_path}/license.zip:/data/shared/assets/license.zip +``` + +#### Run an example: + +```bash +docker-compose up +``` + +#### Shut down instances: + +```bash +docker-compose down +``` + +**Important note:** `ctrl+c` does not destroy instances + + diff --git a/docker/docker-compose-examples/single-node-demo-site/docker-compose.yml b/docker/docker-compose-examples/single-node-demo-site/docker-compose.yml new file mode 100644 index 000000000000..3e3121594059 --- /dev/null +++ b/docker/docker-compose-examples/single-node-demo-site/docker-compose.yml @@ -0,0 +1,75 @@ +version: '3.5' + +networks: + db_net: + opensearch-net: + +volumes: + cms-shared: + dbdata: + opensearch-data: + +services: + opensearch: + image: opensearchproject/opensearch:1.3.6 + environment: + - cluster.name=elastic-cluster + - discovery.type=single-node + - data + - bootstrap.memory_lock=true + - "OPENSEARCH_JAVA_OPTS=-Xmx1G " + ulimits: + memlock: + soft: -1 # Set memlock to unlimited (no soft or hard limit) + hard: -1 + nofile: + soft: 65536 # Maximum number of open files for the opensearch user - set to at least 65536 + hard: 65536 + ports: + - 9200:9200 + - 9600:9600 + volumes: + - opensearch-data:/usr/share/opensearch/data + networks: + - opensearch-net + + dotcms: + image: dotcms/dotcms:latest + environment: + CMS_JAVA_OPTS: '-Xmx1g ' + LANG: 'C.UTF-8' + TZ: 'UTC' + DB_BASE_URL: "jdbc:postgresql://db/dotcms" + DB_USERNAME: 'dotcmsdbuser' + DB_PASSWORD: 'password' + DOT_ES_AUTH_BASIC_PASSWORD: 'admin' + DOT_ES_ENDPOINTS: 'https://opensearch:9200' + DOT_INITIAL_ADMIN_PASSWORD: 'admin' + DOT_DOTCMS_CLUSTER_ID: 'dotcms-production' + CUSTOM_STARTER_URL: https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/starter/20220713/starter-20220713.zip + depends_on: + - opensearch + - db + volumes: + - cms-shared:/data/shared + #- {license_local_path}/license.zip:/data/shared/assets/license.zip + networks: + - db_net + - opensearch-net + ports: + - "8082:8082" + - "8443:8443" + + db: + image: postgres:15 + command: postgres -c 'max_connections=400' -c 'shared_buffers=128MB' + environment: + "POSTGRES_USER": 'dotcmsdbuser' + "POSTGRES_PASSWORD": 'password' + "POSTGRES_DB": 'dotcms' + volumes: + - dbdata:/var/lib/postgresql/data + networks: + - db_net + + diff --git a/docker/docker-compose-examples/single-node/README.md b/docker/docker-compose-examples/single-node/README.md new file mode 100644 index 000000000000..ce652efc1ba7 --- /dev/null +++ b/docker/docker-compose-examples/single-node/README.md @@ -0,0 +1,40 @@ +# Dotcms Single Node + +A single instance of dotcms running on port 8080. Database: postgres + +## Usage + +#### Environment setup + + +1) A local path to license pack must be set here: + +``` +- {license_local_path}/license.zip:/data/shared/assets/license.zip +``` + +2) A local path to access data in the instance can be set uncommenting this line: + +``` +#- {local_data_path}:/data/shared +``` + +3) A custom starter can be set through this line (uncomment and change the starter url accordingly): + +``` +#"CUSTOM_STARTER_URL": 'https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/starter/20210920/starter-20210920.zip' +``` + +#### Run an example: + +```bash +docker-compose up +``` + +#### Shut down instances: + +```bash +docker-compose down +``` + +**Important note:** `ctrl+c` does not destroy instances diff --git a/docker/docker-compose-examples/single-node/docker-compose.yml b/docker/docker-compose-examples/single-node/docker-compose.yml new file mode 100644 index 000000000000..aee6ebeb354b --- /dev/null +++ b/docker/docker-compose-examples/single-node/docker-compose.yml @@ -0,0 +1,74 @@ +version: '3.5' + +networks: + db_net: + opensearch-net: + +volumes: + cms-shared: + dbdata: + opensearch-data: + +services: + opensearch: + image: opensearchproject/opensearch:1.3.6 + environment: + - cluster.name=elastic-cluster + - discovery.type=single-node + - data + - bootstrap.memory_lock=true + - "OPENSEARCH_JAVA_OPTS=-Xmx1G " + ulimits: + memlock: + soft: -1 # Set memlock to unlimited (no soft or hard limit) + hard: -1 + nofile: + soft: 65536 # Maximum number of open files for the opensearch user - set to at least 65536 + hard: 65536 + ports: + - 9200:9200 + - 9600:9600 + volumes: + - opensearch-data:/usr/share/opensearch/data + networks: + - opensearch-net + + dotcms: + image: dotcms/dotcms:latest + environment: + CMS_JAVA_OPTS: '-Xmx1g ' + LANG: 'C.UTF-8' + TZ: 'UTC' + DB_BASE_URL: "jdbc:postgresql://db/dotcms" + DB_USERNAME: 'dotcmsdbuser' + DB_PASSWORD: 'password' + DOT_ES_AUTH_BASIC_PASSWORD: 'admin' + DOT_ES_ENDPOINTS: 'https://opensearch:9200' + DOT_INITIAL_ADMIN_PASSWORD: 'admin' + DOT_DOTCMS_CLUSTER_ID: 'dotcms-production' + #CUSTOM_STARTER_URL: 'https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/starter/20211201/starter-20211201.zip' + depends_on: + - opensearch + - db + volumes: + - cms-shared:/data/shared + #- {license_local_path}/license.zip:/data/shared/assets/license.zip + networks: + - db_net + - opensearch-net + ports: + - "8082:8082" + - "8443:8443" + + db: + image: postgres:15 + command: postgres -c 'max_connections=400' -c 'shared_buffers=128MB' + environment: + "POSTGRES_USER": 'dotcmsdbuser' + "POSTGRES_PASSWORD": 'password' + "POSTGRES_DB": 'dotcms' + volumes: + - dbdata:/var/lib/postgresql/data + networks: + - db_net + diff --git a/docker/docker-compose-examples/with-kibana/docker-compose.yml b/docker/docker-compose-examples/with-kibana/docker-compose.yml new file mode 100644 index 000000000000..5e8122e74b5a --- /dev/null +++ b/docker/docker-compose-examples/with-kibana/docker-compose.yml @@ -0,0 +1,72 @@ +version: '3.5' + +networks: + db_net: + es_net: + +volumes: + cms-shared: + dbdata: + esdata: + +services: + elasticsearch: + image: docker.elastic.co/elasticsearch/elasticsearch:7.9.1 + environment: + - cluster.name=elastic-cluster + - discovery.type=single-node + - data + - bootstrap.memory_lock=true + - "ES_JAVA_OPTS=-Xmx1G " + ports: + - 9200:9200 + - 9600:9600 + volumes: + - esdata:/usr/share/elasticsearch/data + networks: + - es_net + + kibana: + image: docker.elastic.co/kibana/kibana:7.9.1 + environment: + ELASTICSEARCH_HOSTS: '["http://elasticsearch:9200"]' + ports: + - "5601:5601" + networks: + - es_net + + dotcms: + image: dotcms/dotcms:latest + environment: + DB_BASE_URL: "jdbc:postgresql://db/dotcms" + DB_USERNAME: 'dotcmsdbuser' + DB_PASSWORD: 'password' + DOT_ES_AUTH_BASIC_PASSWORD: 'admin' + DOT_ES_ENDPOINTS: 'http://elasticsearch:9200' + DOT_INITIAL_ADMIN_PASSWORD: 'admin' + DOT_DOTCMS_CLUSTER_ID: 'dotcms-production' + #"CUSTOM_STARTER_URL": 'https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/starter/20220713/starter-20220713.zip' + depends_on: + - elasticsearch + - db + volumes: + #- {local_data_path}:/data/shared + - {license_local_path}/license.zip:/data/shared/assets/license.zip + networks: + - db_net + - es_net + ports: + - "8080:8080" + - "8443:8443" + + db: + image: postgres:11 + command: postgres -c 'max_connections=400' -c 'shared_buffers=128MB' + environment: + "POSTGRES_USER": 'dotcmsdbuser' + "POSTGRES_PASSWORD": 'password' + "POSTGRES_DB": 'dotcms' + volumes: + - dbdata:/var/lib/postgresql/data + networks: + - db_net diff --git a/docker/docker-compose-examples/with-opensearch-dashboard/README.md b/docker/docker-compose-examples/with-opensearch-dashboard/README.md new file mode 100644 index 000000000000..f03818c242b3 --- /dev/null +++ b/docker/docker-compose-examples/with-opensearch-dashboard/README.md @@ -0,0 +1,42 @@ +# Dotcms with Kibana + +A single instance of dotcms running on port 8080. Kibana was included for torubleshooting and runs on port 5601. Database: postgres. + +## Usage + +#### Environment setup + + +1) A local path to license pack must be set here: + +``` +- {license_local_path}/license.zip:/data/shared/assets/license.zip +``` + +2) A local path to access data in the instance can be set uncommenting this line: + +``` +#- {local_data_path}:/data/shared +``` + +3) A custom starter can be set through this line (uncomment and change the starter url accordingly): + +``` +#"CUSTOM_STARTER_URL": 'https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/starter/20210920/starter-20210920.zip' +``` + +#### Run an example: + +```bash +docker-compose up +``` + +#### Shut down instances: + +```bash +docker-compose down +``` + +**Important note:** `ctrl+c` does not destroy instances + + diff --git a/docker/docker-compose-examples/with-opensearch-dashboard/docker-compose.yml b/docker/docker-compose-examples/with-opensearch-dashboard/docker-compose.yml new file mode 100644 index 000000000000..abb42fb5d1ee --- /dev/null +++ b/docker/docker-compose-examples/with-opensearch-dashboard/docker-compose.yml @@ -0,0 +1,83 @@ +version: '3.5' + +networks: + db_net: + opensearch-net: + +volumes: + cms-shared: + dbdata: + opensearch-data: + +services: + opensearch: + image: opensearchproject/opensearch:1.3.6 + environment: + - cluster.name=elastic-cluster + - discovery.type=single-node + - data + - bootstrap.memory_lock=true + - "OPENSEARCH_JAVA_OPTS=-Xmx1G " + ulimits: + memlock: + soft: -1 # Set memlock to unlimited (no soft or hard limit) + hard: -1 + nofile: + soft: 65536 # Maximum number of open files for the opensearch user - set to at least 65536 + hard: 65536 + ports: + - 9200:9200 + - 9600:9600 + volumes: + - opensearch-data:/usr/share/opensearch/data + networks: + - opensearch-net + + dashboard: + image: opensearchproject/opensearch-dashboards:1.3.6 + environment: + OPENSEARCH_HOSTS: '["https://opensearch:9200"]' + ports: + - "5601:5601" + networks: + - opensearch-net + + dotcms: + image: dotcms/dotcms:latest + environment: + CMS_JAVA_OPTS: '-Xmx1g ' + LANG: 'C.UTF-8' + TZ: 'UTC' + DB_BASE_URL: "jdbc:postgresql://db/dotcms" + DB_USERNAME: 'dotcmsdbuser' + DB_PASSWORD: 'password' + DOT_ES_AUTH_BASIC_PASSWORD: 'admin' + DOT_ES_ENDPOINTS: 'https://opensearch:9200' + DOT_INITIAL_ADMIN_PASSWORD: 'admin' + DOT_DOTCMS_CLUSTER_ID: 'dotcms-production' + #CUSTOM_STARTER_URL: 'https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/starter/20211201/starter-20211201.zip' + depends_on: + - opensearch + - db + volumes: + - cms-shared:/data/shared + # - {license_local_path}/license.zip:/data/shared/assets/license.zip + networks: + - db_net + - opensearch-net + ports: + - "8082:8082" + - "8443:8443" + + db: + image: postgres:15 + command: postgres -c 'max_connections=400' -c 'shared_buffers=128MB' + environment: + "POSTGRES_USER": 'dotcmsdbuser' + "POSTGRES_PASSWORD": 'password' + "POSTGRES_DB": 'dotcms' + volumes: + - dbdata:/var/lib/postgresql/data + networks: + - db_net + diff --git a/docker/docker-compose-examples/with-redis-session/README.md b/docker/docker-compose-examples/with-redis-session/README.md new file mode 100644 index 000000000000..1fd4a421d8ac --- /dev/null +++ b/docker/docker-compose-examples/with-redis-session/README.md @@ -0,0 +1,111 @@ +# dotCMS Cluster Mode with Redis Session Manager + +This is an example of a 2-node dotCMS Cluster running on ports 8081 and 8082 respectively, using the Redis Session Manager feature. For more information, please refer to the plugin's repository: https://github.com/dotCMS/tomcat-redis-session-manager + +The Redis server runs on port 6379 with password `MY_SECRET_P4SS`. + +## Usage + +#### Environment setup + +1) A local path to license pack must be set here: +``` +- {license_local_path}/license.zip:/data/shared/assets/license.zip +``` +The license pack must contain at least two licenses (one for each node in the cluster). + +2) A local path to access data in the instance can be set uncommenting this line: +``` +#- {local_data_path}:/data/shared +``` + +3) A custom starter can be set through this line (uncomment and change the starter URL accordingly): +``` +#"CUSTOM_STARTER_URL": 'https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/starter/20230712/starter-20230712.zip' +``` + +4) The most important configuration parameters have already been set in both `docker-compose.yml` files. Please refer to the plugin's official repository above for additional ones. + + +#### Deploying nodes: + +```bash +docker-compose -f docker-compose-node-1.yml up +``` + +Once the node 1 is running, deploy node 2: +```bash +docker-compose -f docker-compose-node-2.yml up +``` + +#### Checking Session persistence in Redis: + +You can easily check that the dotCMS Sessions are being persisted in Redis by following these simple steps: + +1. SSH into the Redis container: +```bash +docker exec -it with-redis-session-redis-1 /bin/bash +``` +2. Run the following command to access the Redis CLI: +```bash +redis-cli -a MY_SECRET_P4SS +``` +3. Log into the dotCMS back-end in both nodes. +4. Run this command to print all the keys stored in Redis: +```bash +KEYS * +``` +4. You should see a list of keys similar to this one: +``` +1) "dotcms-redis-cluster4E5ACD893B6250FACEB24CAE6F02581E" +2) "dotcms-redis-cluster31AE4BC07CF37EDA49323954DFDC5B25" +``` + +The key is composed of (1) the current Cluster ID -- which is optional -- and the actual JSESSION ID. + +Additionally, at the beggining of the dotCMS log, you will see the folowing information related to the Redis Session Manager, and the most important configuration values that are being used to instantiate the service: +``` +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.276 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.startInternal ==================================== +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.277 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.startInternal Redis-managed Tomcat Session plugin +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.277 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.startInternal ==================================== +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.277 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.startInternal - Attaching 'com.dotcms.tomcat.redissessions.RedisSessionManager' to 'com.dotcms.tomcat.redissessions.RedisSessionHandlerValve' +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.279 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.initializeSerializer Attempting to use serializer: com.dotcms.tomcat.redissessions.JavaSerializer +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.280 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.startInternal - Initializing configuration parameters: +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.282 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.initializeConfigParams -- TOMCAT_REDIS_SESSION_HOST: redis +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.283 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.initializeConfigParams -- TOMCAT_REDIS_SESSION_PORT: 6379 +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.283 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.initializeConfigParams -- TOMCAT_REDIS_SESSION_PASSWORD: - Set - +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.284 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.initializeConfigParams -- TOMCAT_REDIS_SESSION_SSL_ENABLED: false +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.284 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.initializeConfigParams -- TOMCAT_REDIS_SESSION_SENTINEL_MASTER: null +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.285 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.initializeConfigParams -- TOMCAT_REDIS_SESSION_SENTINELS: null +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.285 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.initializeConfigParams -- TOMCAT_REDIS_SESSION_DATABASE: 0 +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.286 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.initializeConfigParams -- TOMCAT_REDIS_SESSION_TIMEOUT: 2000 +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.286 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.initializeConfigParams -- TOMCAT_REDIS_SESSION_PERSISTENT_POLICIES: DEFAULT +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.287 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.initializeConfigParams -- TOMCAT_REDIS_MAX_CONNECTIONS: 128 +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.288 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.initializeConfigParams -- TOMCAT_REDIS_MAX_IDLE_CONNECTIONS: 100 +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.288 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.initializeConfigParams -- TOMCAT_REDIS_MAX_IDLE_CONNECTIONS: 32 +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.289 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.initializeConfigParams -- DOT_DOTCMS_CLUSTER_ID (Redis Key Prefix): dotcms-redis-cluster +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.289 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.initializeConfigParams -- TOMCAT_REDIS_ENABLED_FOR_ANON_TRAFFIC: false +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.289 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.startInternal - Initializing Redis connection +with-redis-session-dotcms-node-1-1 | SLF4J: No SLF4J providers were found. +with-redis-session-dotcms-node-1-1 | +with-redis-session-dotcms-node-1-1 | +with-redis-session-dotcms-node-1-1 | SLF4J: Defaulting to no-operation (NOP) logger implementation +with-redis-session-dotcms-node-1-1 | +with-redis-session-dotcms-node-1-1 | +with-redis-session-dotcms-node-1-1 | SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details. +with-redis-session-dotcms-node-1-1 | +with-redis-session-dotcms-node-1-1 | +with-redis-session-dotcms-node-1-1 | 18-Jul-2023 18:30:02.378 INFO [main] com.dotcms.tomcat.redissessions.RedisSessionManager.startInternal - Successful! Redis-managed Tomcat Sessions will expire after 1800 seconds. +``` + + +#### Un-deploying nodes: + +```bash +docker-compose -f docker-compose-node-2.yml down +docker-compose -f docker-compose-node-1.yml down +``` + +**Important note:** `ctrl+c` does not destroy instances + + diff --git a/docker/docker-compose-examples/with-redis-session/docker-compose-node-1.yml b/docker/docker-compose-examples/with-redis-session/docker-compose-node-1.yml new file mode 100644 index 000000000000..664130ac91b4 --- /dev/null +++ b/docker/docker-compose-examples/with-redis-session/docker-compose-node-1.yml @@ -0,0 +1,90 @@ +version: '3.5' + +networks: + db_net: + opensearch-net: + redis_net: + +volumes: + cms-shared: + dbdata: + opensearch-data: + +services: + opensearch: + image: opensearchproject/opensearch:1.3.6 + environment: + - cluster.name=elastic-cluster + - discovery.type=single-node + - data + - bootstrap.memory_lock=true + - "OPENSEARCH_JAVA_OPTS=-Xmx1G " + ulimits: + memlock: + soft: -1 # Set memlock to unlimited (no soft or hard limit) + hard: -1 + nofile: + soft: 65536 # Maximum number of open files for the opensearch user - set to at least 65536 + hard: 65536 + ports: + - 9200:9200 + - 9600:9600 + volumes: + - opensearch-data:/usr/share/opensearch/data + networks: + - opensearch-net + + dotcms-node-1: + image: dotcms/dotcms:latest + environment: + CMS_JAVA_OPTS: '-Xmx1g ' + LANG: 'C.UTF-8' + TZ: 'UTC' + TOMCAT_REDIS_SESSION_ENABLED: 'true' + TOMCAT_REDIS_SESSION_HOST: 'redis' + TOMCAT_REDIS_SESSION_PORT: '6379' + TOMCAT_REDIS_SESSION_PASSWORD: 'MY_SECRET_P4SS' + TOMCAT_REDIS_SESSION_SSL_ENABLED: 'false' + TOMCAT_REDIS_SESSION_PERSISTENT_POLICIES: 'DEFAULT' + DOT_DOTCMS_CLUSTER_ID: 'dotcms-redis-cluster' + DB_BASE_URL: "jdbc:postgresql://db/dotcms" + DB_USERNAME: 'dotcmsdbuser' + DB_PASSWORD: 'password' + DOT_ES_AUTH_BASIC_PASSWORD: 'admin' + DOT_ES_ENDPOINTS: 'https://opensearch:9200' + DOT_INITIAL_ADMIN_PASSWORD: 'admin' + #CUSTOM_STARTER_URL: 'https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/starter/20230712/starter-20230712.zip' + depends_on: + - opensearch + - db + - redis + volumes: + - {local_data_path}:/data/shared + - {license_local_path}:/data/shared/assets/license.zip + networks: + - db_net + - opensearch-net + - redis_net + ports: + - "8082:8082" + - "8443:8443" + + redis: + image: "redis:latest" + command: redis-server --requirepass MY_SECRET_P4SS + ports: + - "6379:6379" + networks: + - redis_net + + db: + image: postgres:15 + command: postgres -c 'max_connections=400' -c 'shared_buffers=128MB' + environment: + "POSTGRES_USER": 'dotcmsdbuser' + "POSTGRES_PASSWORD": 'password' + "POSTGRES_DB": 'dotcms' + volumes: + - dbdata:/var/lib/postgresql/data + networks: + - db_net \ No newline at end of file diff --git a/docker/docker-compose-examples/with-redis-session/docker-compose-node-2.yml b/docker/docker-compose-examples/with-redis-session/docker-compose-node-2.yml new file mode 100644 index 000000000000..bc8987d8c122 --- /dev/null +++ b/docker/docker-compose-examples/with-redis-session/docker-compose-node-2.yml @@ -0,0 +1,42 @@ +version: '3.5' + +networks: + with-redis-session_db_net: + external: true + with-redis-session_opensearch-net: + external: true + with-redis-session_redis_net: + external: true + +volumes: + cms-shared: + +services: + dotcms-node-2: + image: dotcms/dotcms:latest + environment: + CMS_JAVA_OPTS: '-Xmx1g ' + LANG: 'C.UTF-8' + TZ: 'UTC' + TOMCAT_REDIS_SESSION_ENABLED: 'true' + TOMCAT_REDIS_SESSION_HOST: 'redis' + TOMCAT_REDIS_SESSION_PORT: '6379' + TOMCAT_REDIS_SESSION_PASSWORD: 'MY_SECRET_P4SS' + TOMCAT_REDIS_SESSION_SSL_ENABLED: 'false' + TOMCAT_REDIS_SESSION_PERSISTENT_POLICIES: 'DEFAULT' + DB_BASE_URL: "jdbc:postgresql://db/dotcms" + DB_USERNAME: 'dotcmsdbuser' + DB_PASSWORD: 'password' + DOT_ES_AUTH_BASIC_PASSWORD: 'admin' + DOT_ES_ENDPOINTS: 'https://opensearch:9200' + DOT_DOTCMS_CLUSTER_ID: 'dotcms-redis-cluster' + volumes: + - { local_data_path }:/data/shared + - {license_local_path}:/data/shared/assets/license.zip + networks: + - with-redis-session_db_net + - with-redis-session_opensearch-net + - with-redis-session_redis_net + ports: + - "8081:8082" + - "8444:8443" \ No newline at end of file diff --git a/docker/docker-compose-examples/with-redis/README.md b/docker/docker-compose-examples/with-redis/README.md new file mode 100644 index 000000000000..bca540373b42 --- /dev/null +++ b/docker/docker-compose-examples/with-redis/README.md @@ -0,0 +1,56 @@ +# Dotcms Cluster Mode with Redis + +Cluster with 2 dotCMS instances running on ports 8080 and 8081 respectively. Database: postgres. + +This environment uses Redis Pub/Sub and Cache. Redis runs on port 6379 with password `MY_SECRET_P4SS` + +## Usage + +#### Environment setup + + +1) A local path to license pack must be set here: + +``` +- {license_local_path}/license.zip:/data/shared/assets/license.zip +``` + +The license pack must contain at least two licenses (one for each node in the cluster) + + +2) A local path to access data in the instance can be set uncommenting this line: + +``` +#- {local_data_path}:/data/shared +``` + +3) A custom starter can be set through this line (uncomment and change the starter url accordingly): + +``` +#"CUSTOM_STARTER_URL": 'https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/starter/20210920/starter-20210920.zip' +``` + +#### Deploying nodes: + +```bash +docker-compose -f docker-compose-node-1.yml up + +``` + +Once the node 1 is running, deploy node 2: +```bash +docker-compose -f docker-compose-node-2.yml up + +``` + + +#### Undeploying nodes: + +```bash +docker-compose -f docker-compose-node-2.yml down +docker-compose -f docker-compose-node-1.yml down +``` + +**Important note:** `ctrl+c` does not destroy instances + + diff --git a/docker/docker-compose-examples/with-redis/docker-compose-node-1.yml b/docker/docker-compose-examples/with-redis/docker-compose-node-1.yml new file mode 100644 index 000000000000..80e93452575b --- /dev/null +++ b/docker/docker-compose-examples/with-redis/docker-compose-node-1.yml @@ -0,0 +1,88 @@ +version: '3.5' + +networks: + db_net: + opensearch-net: + redis_net: + +volumes: + cms-shared: + dbdata: + opensearch-data: + +services: + opensearch: + image: opensearchproject/opensearch:1.3.6 + environment: + - cluster.name=elastic-cluster + - discovery.type=single-node + - data + - bootstrap.memory_lock=true + - "OPENSEARCH_JAVA_OPTS=-Xmx1G " + ulimits: + memlock: + soft: -1 # Set memlock to unlimited (no soft or hard limit) + hard: -1 + nofile: + soft: 65536 # Maximum number of open files for the opensearch user - set to at least 65536 + hard: 65536 + ports: + - 9200:9200 + - 9600:9600 + volumes: + - opensearch-data:/usr/share/opensearch/data + networks: + - opensearch-net + + dotcms-node-1: + image: dotcms/dotcms:latest + environment: + CMS_JAVA_OPTS: '-Xmx1g ' + LANG: 'C.UTF-8' + TZ: 'UTC' + DB_BASE_URL: "jdbc:postgresql://db/dotcms" + DB_USERNAME: 'dotcmsdbuser' + DB_PASSWORD: 'password' + DOT_ES_AUTH_BASIC_PASSWORD: 'admin' + DOT_ES_ENDPOINTS: 'https://opensearch:9200' + DOT_INITIAL_ADMIN_PASSWORD: 'admin' + DOT_DOTCMS_CLUSTER_ID: 'dotcms-redis-cluster' + DOT_DOT_PUBSUB_PROVIDER_OVERRIDE: 'com.dotcms.dotpubsub.RedisPubSubImpl' + DOT_REDIS_LETTUCECLIENT_URLS: 'redis://MY_SECRET_P4SS@redis' + DOT_CACHE_DEFAULT_CHAIN: 'com.dotmarketing.business.cache.provider.caffine.CaffineCache,com.dotcms.cache.lettuce.RedisCache' + #CUSTOM_STARTER_URL: 'https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/starter/20211201/starter-20211201.zip' + depends_on: + - opensearch + - db + - redis + volumes: + #- {local_data_path}:/data/shared + - {license_local_path}/license.zip:/data/shared/assets/license.zip + networks: + - db_net + - opensearch-net + - redis_net + ports: + - "8082:8082" + - "8443:8443" + + redis: + image: "redis:latest" + command: redis-server --requirepass MY_SECRET_P4SS + ports: + - "6379:6379" + networks: + - redis_net + + db: + image: postgres:15 + command: postgres -c 'max_connections=400' -c 'shared_buffers=128MB' + environment: + "POSTGRES_USER": 'dotcmsdbuser' + "POSTGRES_PASSWORD": 'password' + "POSTGRES_DB": 'dotcms' + volumes: + - dbdata:/var/lib/postgresql/data + networks: + - db_net + diff --git a/docker/docker-compose-examples/with-redis/docker-compose-node-2.yml b/docker/docker-compose-examples/with-redis/docker-compose-node-2.yml new file mode 100644 index 000000000000..eb8e2e53dd6e --- /dev/null +++ b/docker/docker-compose-examples/with-redis/docker-compose-node-2.yml @@ -0,0 +1,42 @@ +version: '3.5' + +networks: + with-redis_db_net: + external: true + with-redis_opensearch-net: + external: true + with-redis_redis_net: + external: true + +volumes: + cms-shared: + +services: + dotcms-node-2: + image: dotcms/dotcms:latest + environment: + CMS_JAVA_OPTS: '-Xmx1g ' + LANG: 'C.UTF-8' + TZ: 'UTC' + DB_BASE_URL: "jdbc:postgresql://db/dotcms" + DB_USERNAME: 'dotcmsdbuser' + DB_PASSWORD: 'password' + DOT_ES_AUTH_BASIC_PASSWORD: 'admin' + DOT_ES_ENDPOINTS: 'https://opensearch:9200' + DOT_INITIAL_ADMIN_PASSWORD: 'admin' + DOT_DOTCMS_CLUSTER_ID: 'dotcms-redis-cluster' + DOT_DOT_PUBSUB_PROVIDER_OVERRIDE: 'com.dotcms.dotpubsub.RedisPubSubImpl' + DOT_REDIS_LETTUCECLIENT_URLS: 'redis://MY_SECRET_P4SS@redis' + DOT_CACHE_DEFAULT_CHAIN: 'com.dotmarketing.business.cache.provider.caffine.CaffineCache,com.dotcms.cache.lettuce.RedisCache' + #CUSTOM_STARTER_URL: 'https://repo.dotcms.com/artifactory/libs-release-local/com/dotcms/starter/20211201/starter-20211201.zip' + volumes: + #- {local_data_path}:/data/shared + - {license_local_path}/license.zip:/data/shared/assets/license.zip + networks: + - with-redis_db_net + - with-redis_opensearch-net + - with-redis_redis_net + ports: + - "8081:8082" + - "8444:8443" +