4 Commits

Author SHA1 Message Date
a6a2be4373 Optimized Listmonk variables 2025-09-12 13:04:06 +02:00
b7a7be4737 Fix XWiki automation bootstrap:
- Accept HTTP 302 (Distribution Wizard redirects) in REST readiness and extension checks
- Treat 302 as missing admin user during bootstrap
- Move superadmin password to xwiki.cfg (correct location)
- Disable automatic Distribution Wizard start in xwiki.properties
- Standardize run_once includes for postgres, cdn, and xwiki roles

See: https://chatgpt.com/share/68c3a67b-80b4-800f-8a90-ebdcd4abb86c
2025-09-12 06:50:24 +02:00
2d71c461de web-app-xwiki: add SuperAdmin bootstrap support
- Added schema entry for superadminpassword
- Added vars for XWIKI_SUPERADMIN_USERNAME/PASSWORD
- Extended xwiki.properties.j2 to configure superadminpassword
- Added 02_bootstrap_admin.yml to create XWiki admin via REST using SuperAdmin
- Updated REST URLs to use XWIKI_REST_GENERAL
- Enabled CSP flag unsafe-inline

Conversation: https://chatgpt.com/share/68c39ddb-e9cc-800f-b32f-9d4c1e09e43e
2025-09-12 06:13:34 +02:00
07b7c6484f xwiki: switch to PostgreSQL and remove custom Hibernate override
Config: set database.type=postgres; use image tag lts-<dbtype>-tomcat; make DB_TYPE templated; derive database_type from app config.

Cleanup: delete hibernate.cfg.xml template and volume mounts; remove XWIKI_HOST_HIBERNATE_PATH; stop rendering hibernate.cfg.xml.

web-svc-cdn: run_once task fix.

Context: troubleshooting on 2025-09-12. Conversation link: https://chatgpt.com/share/68c3978e-77cc-800f-beda-19220f70855f
2025-09-12 05:46:45 +02:00
17 changed files with 95 additions and 52 deletions

View File

@@ -25,3 +25,5 @@
community.general.pacman:
name: python-psycopg2
state: present
- include_tasks: utils/run_once.yml

View File

@@ -1,6 +1,5 @@
- block:
- include_tasks: 01_core.yml
- include_tasks: utils/run_once.yml
vars:
# Force the flush of the pg handler on the first run
flush_handlers: true

View File

@@ -27,4 +27,5 @@
group: "{{ NGINX.USER }}"
mode: "0755"
loop: "{{ CDN_DIRS_GLOBAL }}"
- include_tasks: utils/run_once.yml

View File

@@ -3,8 +3,9 @@
include_role:
name: sys-stk-full-stateful
vars:
docker_compose_flush_handlers: false
proxy_extra_configuration: >-
{% if not applications | get_app_conf(application_id, 'public_api_activated', True) %}
{% if not LISTMONK_PUBLIC_API_ENABLED | bool %}
{{ lookup('file', '{{ playbook_dir }}/roles/web-app-listmonk/files/deactivate-public-api.conf') }}
{% else %}
""

View File

@@ -1,16 +1,14 @@
# General
application_id: "web-app-listmonk"
database_type: "postgres"
container_port: "{{ applications | get_app_conf(application_id, 'docker.services.listmonk.port') }}"
# Docker
docker_compose_flush_handlers: false
application_id: "web-app-listmonk"
database_type: "postgres"
container_port: "{{ applications | get_app_conf(application_id, 'docker.services.listmonk.port') }}"
# Listmonk
LISTMONK_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.listmonk.version') }}"
LISTMONK_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.listmonk.image') }}"
LISTMONK_NAME: "{{ applications | get_app_conf(application_id, 'docker.services.listmonk.name') }}"
LISTMONK_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.listmonk.version') }}"
LISTMONK_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.listmonk.image') }}"
LISTMONK_NAME: "{{ applications | get_app_conf(application_id, 'docker.services.listmonk.name') }}"
LISTMONK_PUBLIC_API_ENABLED: "{{ applications | get_app_conf(application_id, 'public_api_activated') }}"
LISTMONK_SETTINGS:
- key: "app.root_url"

View File

@@ -5,9 +5,10 @@ docker:
enabled: false
database:
enabled: true
type: postgres
xwiki:
image: xwiki
version: stable-mariadb-tomcat
version: lts-<< defaults_applications[web-app-xwiki].docker.services.database.type >>-tomcat
name: xwiki
backup:
no_stop_required: true
@@ -24,7 +25,9 @@ features:
server:
csp:
whitelist: {}
flags: {}
flags:
script-src-elem:
unsafe-inline: true
domains:
canonical:
- "x.wiki.{{ PRIMARY_DOMAIN }}"

View File

@@ -0,0 +1,6 @@
credentials:
superadminpassword:
description: "Password for the xwiki superadmin"
algorithm: "alphanumeric"
validation:
min_length: 50

View File

@@ -16,44 +16,40 @@
dest: "{{ XWIKI_HOST_PROPERTIES_PATH }}"
notify: docker compose up
- name: "Render hibernate.cfg.xml"
template:
src: "hibernate.cfg.xml.j2"
dest: "{{ XWIKI_HOST_HIBERNATE_PATH }}"
notify: docker compose up
- name: "flush docker compose for '{{ application_id }}'"
meta: flush_handlers
- name: "Wait until XWiki REST is ready"
uri:
url: "http://127.0.0.1:{{ XWIKI_HOST_PORT }}/xwiki/rest/"
status_code: [200, 401]
status_code: [200, 401, 302]
return_content: no
register: xwiki_rest_up
retries: 60
delay: 5
until: xwiki_rest_up is succeeded
- include_tasks: 02_bootstrap_admin.yml
- name: "Check if OIDC extension installed"
uri:
url: "http://127.0.0.1:{{ XWIKI_HOST_PORT }}/xwiki/rest/wikis/xwiki/extensions/{{ XWIKI_EXT_OIDC_ID | urlencode }}"
url: "{{ XWIKI_REST_GENERAL }}/extensions/{{ XWIKI_EXT_OIDC_ID | urlencode }}"
method: GET
user: "{{ XWIKI_ADMIN_USER }}"
password: "{{ XWIKI_ADMIN_PASS }}"
force_basic_auth: yes
status_code: [200,404]
status_code: [200, 404, 302]
register: xwiki_oidc_ext
when: XWIKI_OIDC_ENABLED | bool
- name: "Check if LDAP extension installed"
uri:
url: "http://127.0.0.1:{{ XWIKI_HOST_PORT }}/xwiki/rest/wikis/xwiki/extensions/{{ XWIKI_EXT_LDAP_ID | urlencode }}"
url: "{{ XWIKI_REST_GENERAL }}/extensions/{{ XWIKI_EXT_LDAP_ID | urlencode }}"
method: GET
user: "{{ XWIKI_ADMIN_USER }}"
password: "{{ XWIKI_ADMIN_PASS }}"
force_basic_auth: yes
status_code: [200,404]
status_code: [200, 404, 302]
register: xwiki_ldap_ext
when: XWIKI_LDAP_ENABLED | bool
@@ -71,4 +67,4 @@
- (XWIKI_OIDC_ENABLED | bool and xwiki_oidc_ext.status == 404) or
(XWIKI_LDAP_ENABLED | bool and (xwiki_ldap_ext is not skipped) and xwiki_ldap_ext.status == 404)
- include_tasks: utils/run_once.yml
- include_tasks: utils/run_once.yml

View File

@@ -0,0 +1,43 @@
---
# Wait until REST endpoint is available (01_core usually ensures this, but add safety)
- name: "XWIKI | Wait until REST answers"
uri:
url: "http://127.0.0.1:{{ XWIKI_HOST_PORT }}/xwiki/rest/"
status_code: [200, 401]
register: _rest_ping
retries: 60
delay: 5
until: _rest_ping is succeeded
# Check if the target admin already exists
# 404 => missing, 302 => DW redirect (treat as missing for bootstrap)
- name: "XWIKI | Check if target admin user exists"
uri:
url: "{{ XWIKI_REST_GENERAL }}/users/{{ XWIKI_ADMIN_USER | urlencode }}"
method: GET
user: "{{ XWIKI_SUPERADMIN_USERNAME }}"
password: "{{ XWIKI_SUPERADMIN_PASSWORD }}"
force_basic_auth: true
status_code: [200, 404, 302]
register: _admin_exists
# Create admin user if not existing (or DW still redirecting)
- name: "XWIKI | Create admin user via REST"
uri:
url: "{{ XWIKI_REST_GENERAL }}/users"
method: POST
user: "{{ XWIKI_SUPERADMIN_USERNAME }}"
password: "{{ XWIKI_SUPERADMIN_PASSWORD }}"
force_basic_auth: true
status_code: 201
headers:
Content-Type: "application/xml"
body: |
<user>
<firstName>{{ users.administrator.firstname | default('Admin') }}</firstName>
<lastName>{{ users.administrator.lastname | default('User') }}</lastName>
<email>{{ users.administrator.email }}</email>
<username>{{ XWIKI_ADMIN_USER }}</username>
<password>{{ XWIKI_ADMIN_PASS }}</password>
</user>
when: _admin_exists.status in [404, 302]

View File

@@ -11,8 +11,6 @@
volumes:
- "{{ XWIKI_HOST_CONF_PATH }}:/usr/local/xwiki/xwiki.cfg"
- "{{ XWIKI_HOST_PROPERTIES_PATH }}:/usr/local/xwiki/xwiki.properties"
- "{{ XWIKI_HOST_HIBERNATE_PATH }}:/usr/local/xwiki/hibernate.cfg.xml"
- "{{ XWIKI_HOST_HIBERNATE_PATH }}:/usr/local/tomcat/webapps/ROOT/WEB-INF/hibernate.cfg.xml"
- 'data:/usr/local/xwiki'
{% include 'roles/docker-container/templates/healthcheck/curl.yml.j2' %}
{% include 'roles/docker-container/templates/base.yml.j2' %}

View File

@@ -3,3 +3,4 @@ DB_PASSWORD="{{ database_password }}"
DB_HOST="{{ database_host }}"
DB_PORT="{{ database_port }}"
DB_DATABASE="{{ database_name }}"
DB_TYPE="{{ 'mariadb' if database_type == 'mariadb' else 'postgresql' }}"

View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- deine bestehenden DB-Props (Driver, URL, User, Pass) -->
<property name="hibernate.connection.driver_class">org.mariadb.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mariadb://{{ database_host }}:{{ database_port }}/{{ database_name }}?useUnicode=true&amp;characterEncoding=UTF-8</property>
<property name="hibernate.connection.username">{{ database_username }}</property>
<property name="hibernate.connection.password">{{ database_password }}</property>
<!-- DBCP: leichte Validierung statt Treiber-isValid / Diagnose -->
<property name="hibernate.dbcp.testOnBorrow">true</property>
<property name="hibernate.dbcp.testWhileIdle">true</property>
<property name="hibernate.dbcp.validationQuery">SELECT 1</property>
<property name="hibernate.dbcp.validationQueryTimeout">5</property>
<property name="hibernate.dbcp.timeBetweenEvictionRunsMillis">30000</property>
<property name="hibernate.dbcp.minEvictableIdleTimeMillis">60000</property>
</session-factory>
</hibernate-configuration>

View File

@@ -18,3 +18,6 @@ xwiki.authentication.ldap.update_user=1
# Fallback: Native XWiki Auth
# xwiki.authentication.authclass=com.xpn.xwiki.user.impl.xwiki.XWikiAuthServiceImpl
{% endif %}
# ---- Superadmin must live in xwiki.cfg (not in xwiki.properties)
xwiki.superadminpassword={{ XWIKI_SUPERADMIN_PASSWORD }}

View File

@@ -14,3 +14,9 @@ oidc.userinfoclaims={{ XWIKI_OIDC_GROUPS_CLAIM }}
oidc.groups.claim={{ XWIKI_OIDC_GROUPS_CLAIM }}
oidc.groups.mapping=XWiki.XWikiAdminGroup={{ XWIKI_OIDC_ADMIN_PROVIDER_GROUP }}
{% endif %}
############################################
# Distribution Wizard
# Disable automatic start so REST is reachable during automation
distribution.automaticStartOnMainWiki=false
distribution.automaticStartOnWiki=false

View File

@@ -1,6 +1,7 @@
# General
application_id: "web-app-xwiki"
database_type: "mariadb"
database_type: "{{ applications | get_app_conf(application_id, 'docker.services.database.type') }}"
container_port: 8080
container_hostname: "{{ domains | get_domain(application_id) }}"
@@ -14,7 +15,6 @@ XWIKI_HOSTNAME: "{{ container_hostname }}"
## Paths
XWIKI_HOST_CONF_PATH: "{{ [docker_compose.directories.config, 'xwiki.cfg'] | path_join }}"
XWIKI_HOST_PROPERTIES_PATH: "{{ [docker_compose.directories.config, 'xwiki.properties'] | path_join }}"
XWIKI_HOST_HIBERNATE_PATH: "{{ [docker_compose.directories.config, 'hibernate.cfg.xml'] | path_join }}"
## Docker
XWIKI_IMAGE_CUSTOM: "xwiki_custom"
@@ -32,8 +32,13 @@ XWIKI_ADMIN_USER: "{{ users.administrator.username }}"
XWIKI_ADMIN_PASS: "{{ users.administrator.password }}"
XWIKI_ADMIN_GROUP: "{{ application_id }}-administrator"
# Superadministrator
XWIKI_SUPERADMIN_PASSWORD: "{{ applications | get_app_conf(application_id, 'credentials.superadminpassword') }}"
XWIKI_SUPERADMIN_USERNAME: "superadmin"
# REST endpoint (local inside container)
XWIKI_REST_BASE: "http://127.0.0.1:{{ XWIKI_HOST_PORT }}/xwiki/rest/jobs?jobType=install&async=false"
XWIKI_REST_GENERAL: "http://127.0.0.1:{{ XWIKI_HOST_PORT }}/xwiki/rest/wikis/xwiki"
# Extension IDs + Versions (pin versions explicitly)
XWIKI_EXT_LDAP_ID: "org.xwiki.contrib.ldap:ldap-authenticator"

View File

@@ -15,4 +15,6 @@
template:
src: "nginx.conf.j2"
dest: "{{ CDN_NGINX_PATH }}"
notify: restart openresty
notify: restart openresty
- include_tasks: utils/run_once.yml

View File

@@ -1,6 +1,5 @@
- block:
- include_tasks: 01_core.yml
- include_tasks: utils/run_once.yml
when: run_once_web_svc_cdn is not defined
- include_tasks: "{{ playbook_dir }}/tasks/utils/load_handlers.yml"