mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-11-06 05:08:16 +00:00
Compare commits
6 Commits
37b213f96a
...
feature/dr
| Author | SHA1 | Date | |
|---|---|---|---|
| 9e874408a7 | |||
| bebf76951c | |||
| aa1a901309 | |||
| d61c81634c | |||
| 265f815b48 | |||
| f8e5110730 |
@@ -114,6 +114,8 @@ defaults_networks:
|
|||||||
subnet: 192.168.104.48/28
|
subnet: 192.168.104.48/28
|
||||||
web-app-mini-qr:
|
web-app-mini-qr:
|
||||||
subnet: 192.168.104.64/28
|
subnet: 192.168.104.64/28
|
||||||
|
web-app-drupal:
|
||||||
|
subnet: 192.168.104.80/28
|
||||||
|
|
||||||
# /24 Networks / 254 Usable Clients
|
# /24 Networks / 254 Usable Clients
|
||||||
web-app-bigbluebutton:
|
web-app-bigbluebutton:
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ ports:
|
|||||||
web-app-minio_api: 8057
|
web-app-minio_api: 8057
|
||||||
web-app-minio_console: 8058
|
web-app-minio_console: 8058
|
||||||
web-app-mini-qr: 8059
|
web-app-mini-qr: 8059
|
||||||
|
web-app-drupal: 8060
|
||||||
web-app-bigbluebutton: 48087 # This port is predefined by bbb. @todo Try to change this to a 8XXX port
|
web-app-bigbluebutton: 48087 # This port is predefined by bbb. @todo Try to change this to a 8XXX port
|
||||||
public:
|
public:
|
||||||
# The following ports should be changed to 22 on the subdomain via stream mapping
|
# The following ports should be changed to 22 on the subdomain via stream mapping
|
||||||
|
|||||||
29
roles/web-app-drupal/Administration.md
Normal file
29
roles/web-app-drupal/Administration.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# Administration
|
||||||
|
|
||||||
|
## Shell access
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose exec -it application /bin/bash
|
||||||
|
```
|
||||||
|
|
||||||
|
## Drush (inside the container)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
drush --version
|
||||||
|
drush cr # Cache rebuild
|
||||||
|
drush status # Site status
|
||||||
|
drush cim -y # Config import (if using config sync)
|
||||||
|
drush updb -y # Run DB updates
|
||||||
|
```
|
||||||
|
|
||||||
|
## Database access (local DB service)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose exec -it database /bin/mysql -u drupal -p
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test Email
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose exec -it application /bin/bash -lc 'echo "Test Email" | sendmail -v your-email@example.com'
|
||||||
|
```
|
||||||
32
roles/web-app-drupal/README.md
Normal file
32
roles/web-app-drupal/README.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# Drupal
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
[Drupal](https://www.drupal.org/) is a powerful open-source CMS for building secure, extensible, and content-rich digital experiences.
|
||||||
|
This role deploys a containerized **Drupal 10/11** instance optimized for production, including **msmtp** for outbound email, **Drush** for CLI administration, and **OpenID Connect (OIDC)** for SSO (e.g., Keycloak, Auth0, Azure AD).
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
* **Flexible Content Model:** Entities, fields, and views for complex data needs.
|
||||||
|
* **Security & Roles:** Fine-grained access control and active security team.
|
||||||
|
* **Robust Ecosystem:** Thousands of modules and themes.
|
||||||
|
* **CLI Automation:** Drush for installs, updates, and configuration import.
|
||||||
|
* **OIDC SSO:** First-class login via external Identity Providers.
|
||||||
|
|
||||||
|
This automated Docker Compose deployment builds a custom Drupal image with Drush and msmtp, wires database credentials and config overrides via environment, and applies OIDC configuration via Ansible/Drush.
|
||||||
|
|
||||||
|
## OIDC
|
||||||
|
|
||||||
|
This role enables **OpenID Connect** via the `openid_connect` module and configures a **client entity** (e.g., `keycloak`) including endpoints and scopes. Global OIDC behavior (auto-create, link existing users, privacy) is set via `openid_connect.settings`.
|
||||||
|
|
||||||
|
## Further Resources
|
||||||
|
|
||||||
|
* [Drupal.org](https://www.drupal.org/)
|
||||||
|
* [OpenID Connect module](https://www.drupal.org/project/openid_connect)
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
Developed and maintained by **Kevin Veen-Birkenbach**
|
||||||
|
Learn more at [veen.world](https://veen.world)
|
||||||
|
Part of the [Infinito.Nexus Project](https://s.infinito.nexus/code)
|
||||||
|
License: [Infinito.Nexus NonCommercial License](https://s.infinito.nexus/license)
|
||||||
41
roles/web-app-drupal/config/main.yml
Normal file
41
roles/web-app-drupal/config/main.yml
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
title: "Site"
|
||||||
|
max_upload_size: "256M"
|
||||||
|
features:
|
||||||
|
matomo: true
|
||||||
|
css: false
|
||||||
|
desktop: true
|
||||||
|
oidc: true
|
||||||
|
central_database: true
|
||||||
|
logout: true
|
||||||
|
|
||||||
|
server:
|
||||||
|
csp:
|
||||||
|
flags: {}
|
||||||
|
whitelist: {}
|
||||||
|
domains:
|
||||||
|
canonical:
|
||||||
|
- "drupal.{{ PRIMARY_DOMAIN }}"
|
||||||
|
aliases: []
|
||||||
|
|
||||||
|
docker:
|
||||||
|
services:
|
||||||
|
database:
|
||||||
|
enabled: true
|
||||||
|
drupal:
|
||||||
|
# Use a PHP 8.2+ base image to ensure compatibility with OIDC 2.x syntax
|
||||||
|
version: "10-php8.2-apache"
|
||||||
|
image: drupal
|
||||||
|
name: drupal
|
||||||
|
backup:
|
||||||
|
no_stop_required: true
|
||||||
|
volumes:
|
||||||
|
data: drupal_data
|
||||||
|
|
||||||
|
rbac:
|
||||||
|
roles:
|
||||||
|
authenticated:
|
||||||
|
description: "Logged-in user"
|
||||||
|
content_editor:
|
||||||
|
description: "Can create and edit content"
|
||||||
|
site_admin:
|
||||||
|
description: "Full site administration"
|
||||||
23
roles/web-app-drupal/meta/main.yml
Normal file
23
roles/web-app-drupal/meta/main.yml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
galaxy_info:
|
||||||
|
author: "Kevin Veen-Birkenbach"
|
||||||
|
description: >
|
||||||
|
Drupal CMS in Docker with Drush, msmtp, and OpenID Connect (OIDC) SSO.
|
||||||
|
license: "Infinito.Nexus NonCommercial License"
|
||||||
|
license_url: "https://s.infinito.nexus/license"
|
||||||
|
company: |
|
||||||
|
Kevin Veen-Birkenbach
|
||||||
|
Consulting & Coaching Solutions
|
||||||
|
https://www.veen.world
|
||||||
|
galaxy_tags:
|
||||||
|
- drupal
|
||||||
|
- docker
|
||||||
|
- cms
|
||||||
|
- oidc
|
||||||
|
- sso
|
||||||
|
repository: "https://s.infinito.nexus/code"
|
||||||
|
issue_tracker_url: "https://s.infinito.nexus/issues"
|
||||||
|
documentation: "https://docs.infinito.nexus"
|
||||||
|
logo:
|
||||||
|
class: "fa-solid fa-droplet"
|
||||||
|
run_after:
|
||||||
|
- web-app-keycloak
|
||||||
9
roles/web-app-drupal/schema/main.yml
Normal file
9
roles/web-app-drupal/schema/main.yml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
credentials:
|
||||||
|
administrator_password:
|
||||||
|
description: "Initial password for the Drupal admin account"
|
||||||
|
algorithm: "sha256"
|
||||||
|
validation: "^[a-f0-9]{64}$"
|
||||||
|
hash_salt:
|
||||||
|
description: "Drupal hash_salt value used for one-time logins, CSRF tokens, etc."
|
||||||
|
algorithm: "sha256"
|
||||||
|
validation: "^[a-f0-9]{64}$"
|
||||||
11
roles/web-app-drupal/tasks/00_permissions.yml
Normal file
11
roles/web-app-drupal/tasks/00_permissions.yml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
- name: "Ensure sites/default/files exists and is writable"
|
||||||
|
command: >
|
||||||
|
docker exec -u root {{ DRUPAL_CONTAINER }} bash -lc
|
||||||
|
"set -e;
|
||||||
|
d='{{ DRUPAL_DOCKER_HTML_PATH }}/sites/default';
|
||||||
|
f=\"$d/files\";
|
||||||
|
mkdir -p \"$f\";
|
||||||
|
chown -R {{ DRUPAL_USER }}:{{ DRUPAL_USER }} \"$d\";
|
||||||
|
find \"$d\" -type d -exec chmod 775 {} +;
|
||||||
|
find \"$d\" -type f -exec chmod 664 {} +;"
|
||||||
|
changed_when: true
|
||||||
25
roles/web-app-drupal/tasks/01_settings_local_include.yml
Normal file
25
roles/web-app-drupal/tasks/01_settings_local_include.yml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
- name: "Ensure settings.php exists and includes settings.local.php"
|
||||||
|
command: >
|
||||||
|
docker exec -u root {{ DRUPAL_CONTAINER }} bash -lc
|
||||||
|
"set -e;
|
||||||
|
f='{{ DRUPAL_DOCKER_CONF_PATH }}/settings.php';
|
||||||
|
df='{{ DRUPAL_DOCKER_CONF_PATH }}/default.settings.php';
|
||||||
|
if [ ! -f \"$f\" ] && [ -f \"$df\" ]; then
|
||||||
|
cp \"$df\" \"$f\";
|
||||||
|
chown www-data:www-data \"$f\";
|
||||||
|
chmod 644 \"$f\";
|
||||||
|
fi;
|
||||||
|
php -r '
|
||||||
|
$f=\"{{ DRUPAL_DOCKER_CONF_PATH }}/settings.php\";
|
||||||
|
if (!file_exists($f)) { exit(0); }
|
||||||
|
$c=file_get_contents($f);
|
||||||
|
$inc=\"\\nif (file_exists(\\\"\$app_root/\$site_path/settings.local.php\\\")) { include \$app_root/\$site_path/settings.local.php; }\\n\";
|
||||||
|
if (strpos($c, \"settings.local.php\") === false) {
|
||||||
|
file_put_contents($f, $c.$inc);
|
||||||
|
echo \"patched\";
|
||||||
|
} else {
|
||||||
|
echo \"exists\";
|
||||||
|
}
|
||||||
|
'"
|
||||||
|
register: settings_local_include
|
||||||
|
changed_when: "'patched' in settings_local_include.stdout"
|
||||||
32
roles/web-app-drupal/tasks/02_install.yml
Normal file
32
roles/web-app-drupal/tasks/02_install.yml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
- name: "Wait for database readiness"
|
||||||
|
command: >
|
||||||
|
docker exec {{ DRUPAL_CONTAINER }} bash -lc
|
||||||
|
"php -r '
|
||||||
|
$h=\"{{ database_host }}\"; $p={{ database_port }};
|
||||||
|
$d=\"{{ database_name }}\"; $u=\"{{ database_username }}\"; $pw=\"{{ database_password }}\";
|
||||||
|
$t=microtime(true)+60; $ok=false;
|
||||||
|
while (microtime(true)<$t) {
|
||||||
|
try { new PDO(\"mysql:host=$h;port=$p;dbname=$d;charset=utf8mb4\", $u, $pw,[PDO::ATTR_TIMEOUT=>2]); $ok=true; break; }
|
||||||
|
catch (Exception $e) { usleep(300000); }
|
||||||
|
}
|
||||||
|
if (!$ok) { fwrite(STDERR, \"DB not ready\\n\"); exit(1); }'"
|
||||||
|
register: db_wait
|
||||||
|
retries: 1
|
||||||
|
failed_when: db_wait.rc != 0
|
||||||
|
|
||||||
|
- name: "Run Drupal site:install via Drush"
|
||||||
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||||
|
command: >
|
||||||
|
docker exec {{ DRUPAL_CONTAINER }} bash -lc
|
||||||
|
"/opt/drupal/vendor/bin/drush -r {{ DRUPAL_DOCKER_HTML_PATH }} site:install standard -y
|
||||||
|
--db-url='mysql://{{ database_username }}:{{ database_password }}@{{ database_host }}:{{ database_port }}/{{ database_name }}'
|
||||||
|
--site-name='{{ applications | get_app_conf(application_id, 'title', True) }}'
|
||||||
|
--account-name='{{ applications | get_app_conf(application_id, 'users.administrator.username') }}'
|
||||||
|
--account-mail='{{ applications | get_app_conf(application_id, 'users.administrator.email', True) }}'
|
||||||
|
--account-pass='{{ applications | get_app_conf(application_id, 'credentials.administrator_password', True) }}'
|
||||||
|
--uri='{{ DRUPAL_URL }}'"
|
||||||
|
args:
|
||||||
|
chdir: "{{ docker_compose.directories.instance }}"
|
||||||
|
register: drupal_install
|
||||||
|
changed_when: "'Installation complete' in drupal_install.stdout"
|
||||||
|
failed_when: false
|
||||||
12
roles/web-app-drupal/tasks/03_enable_modules.yml
Normal file
12
roles/web-app-drupal/tasks/03_enable_modules.yml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
- name: "Enable OpenID Connect core module"
|
||||||
|
command: >
|
||||||
|
docker exec {{ DRUPAL_CONTAINER }} bash -lc
|
||||||
|
"drush -r {{ DRUPAL_DOCKER_HTML_PATH }} en openid_connect -y"
|
||||||
|
changed_when: true
|
||||||
|
|
||||||
|
- name: "Enable OpenID Connect Keycloak preset (submodule of openid_connect)"
|
||||||
|
command: >
|
||||||
|
docker exec {{ DRUPAL_CONTAINER }} bash -lc
|
||||||
|
"drush -r {{ DRUPAL_DOCKER_HTML_PATH }} en openid_connect_client_keycloak -y"
|
||||||
|
changed_when: true
|
||||||
|
failed_when: false
|
||||||
79
roles/web-app-drupal/tasks/04_configure_oidc.yml
Normal file
79
roles/web-app-drupal/tasks/04_configure_oidc.yml
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
- name: "Load OIDC vars"
|
||||||
|
include_vars:
|
||||||
|
file: "{{ role_path }}/vars/oidc.yml"
|
||||||
|
name: oidc_vars
|
||||||
|
|
||||||
|
- name: "Apply openid_connect.settings (global)"
|
||||||
|
loop: "{{ oidc_vars.oidc_settings | dict2items }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.key }}"
|
||||||
|
command: >
|
||||||
|
docker exec {{ DRUPAL_CONTAINER }} bash -lc
|
||||||
|
"drush -r {{ DRUPAL_DOCKER_HTML_PATH }} cset -y
|
||||||
|
openid_connect.settings {{ item.key }}
|
||||||
|
{{ (item.value | to_json) if item.value is mapping or item.value is sequence else item.value }}"
|
||||||
|
|
||||||
|
- name: "Ensure/Update OIDC client entity (generic)"
|
||||||
|
vars:
|
||||||
|
client_id: "{{ oidc_vars.oidc_client.id }}"
|
||||||
|
client_label: "{{ oidc_vars.oidc_client.label }}"
|
||||||
|
plugin_id: "{{ oidc_vars.oidc_client.plugin }}"
|
||||||
|
settings_b64: "{{ oidc_vars.oidc_client.settings | to_json | b64encode }}"
|
||||||
|
command: >
|
||||||
|
docker exec {{ DRUPAL_CONTAINER }} bash -lc
|
||||||
|
"drush -r {{ DRUPAL_DOCKER_HTML_PATH }} eval '
|
||||||
|
$id=\"{{ client_id }}\";
|
||||||
|
$label=\"{{ client_label }}\";
|
||||||
|
$plugin=\"{{ plugin_id }}\";
|
||||||
|
$settings=json_decode(base64_decode(\"{{ settings_b64 }}\"), TRUE);
|
||||||
|
$storage=\\Drupal::entityTypeManager()->getStorage(\"openid_connect_client\");
|
||||||
|
$e=$storage->load($id);
|
||||||
|
if (!$e) {
|
||||||
|
$e=$storage->create([
|
||||||
|
\"id\"=> $id,
|
||||||
|
\"label\"=> $label,
|
||||||
|
\"status\"=> TRUE,
|
||||||
|
\"plugin\"=> $plugin,
|
||||||
|
\"settings\"=> $settings,
|
||||||
|
]);
|
||||||
|
$e->save();
|
||||||
|
print \"created\";
|
||||||
|
} else {
|
||||||
|
$e->set(\"label\", $label);
|
||||||
|
$e->set(\"plugin\", $plugin);
|
||||||
|
$e->set(\"settings\", $settings);
|
||||||
|
$e->set(\"status\", TRUE);
|
||||||
|
$e->save();
|
||||||
|
print \"updated\";
|
||||||
|
}
|
||||||
|
'"
|
||||||
|
register: client_apply
|
||||||
|
changed_when: "'created' in client_apply.stdout or 'updated' in client_apply.stdout"
|
||||||
|
|
||||||
|
- name: "Apply OIDC client settings"
|
||||||
|
vars:
|
||||||
|
client_id: "{{ oidc_vars.oidc_client.id }}"
|
||||||
|
settings_map: "{{ oidc_vars.oidc_client.settings }}"
|
||||||
|
kv: "{{ settings_map | dict2items }}"
|
||||||
|
loop: "{{ kv }}"
|
||||||
|
loop_control:
|
||||||
|
label: "{{ item.key }}"
|
||||||
|
command: >
|
||||||
|
docker exec {{ DRUPAL_CONTAINER }} bash -lc
|
||||||
|
"drush -r {{ DRUPAL_DOCKER_HTML_PATH }} eval '
|
||||||
|
$id=\"{{ client_id }}\";
|
||||||
|
$key=\"{{ item.key }}\";
|
||||||
|
$val=json_decode(base64_decode(\"{{ (item.value | to_json | b64encode) }}\"), true);
|
||||||
|
$storage=\Drupal::entityTypeManager()->getStorage(\"openid_connect_client\");
|
||||||
|
$c=$storage->load($id);
|
||||||
|
$s=$c->get(\"settings\");
|
||||||
|
$s[$key]=$val;
|
||||||
|
$c->set(\"settings\", $s);
|
||||||
|
$c->save();'"
|
||||||
|
changed_when: true
|
||||||
|
|
||||||
|
- name: "Clear caches after OIDC config"
|
||||||
|
command: >
|
||||||
|
docker exec {{ DRUPAL_CONTAINER }} bash -lc
|
||||||
|
"drush -r {{ DRUPAL_DOCKER_HTML_PATH }} cr"
|
||||||
|
changed_when: false
|
||||||
19
roles/web-app-drupal/tasks/05_trusted_hosts.yml
Normal file
19
roles/web-app-drupal/tasks/05_trusted_hosts.yml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
- name: "Set trusted_host_patterns for canonical domains"
|
||||||
|
vars:
|
||||||
|
patterns: "{{ DRUPAL_DOMAINS
|
||||||
|
| map('regex_replace','\\\\.','\\\\\\\\.')
|
||||||
|
| map('regex_replace','^','^')
|
||||||
|
| map('regex_replace','$','$')
|
||||||
|
| list }}"
|
||||||
|
php_array: "{{ patterns | to_json }}"
|
||||||
|
command: >
|
||||||
|
docker exec -u root {{ DRUPAL_CONTAINER }} bash -lc
|
||||||
|
"php -r '
|
||||||
|
$f="{{ DRUPAL_DOCKER_CONF_PATH }}/settings.local.php";
|
||||||
|
$c=file_exists($f)?file_get_contents($f):"<?php\n";
|
||||||
|
// Remove existing assignment of $settings[\"trusted_host_patterns\"] (if any)
|
||||||
|
$c=preg_replace(\"/(\\\\$settings\\['trusted_host_patterns'\\]\\s*=).*?;/s\", \"\", $c);
|
||||||
|
$c.="\n\$settings[\'trusted_host_patterns\'] = ".var_export(json_decode("{{ php_array|e }}", true), true).";\n";
|
||||||
|
file_put_contents($f,$c);
|
||||||
|
'"
|
||||||
|
changed_when: true
|
||||||
58
roles/web-app-drupal/tasks/main.yml
Normal file
58
roles/web-app-drupal/tasks/main.yml
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
- name: "Include role sys-stk-front-proxy for {{ application_id }}"
|
||||||
|
include_role:
|
||||||
|
name: sys-stk-front-proxy
|
||||||
|
loop: "{{ DRUPAL_DOMAINS }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: domain
|
||||||
|
vars:
|
||||||
|
proxy_extra_configuration: "client_max_body_size {{ DRUPAL_MAX_UPLOAD_SIZE }};"
|
||||||
|
http_port: "{{ ports.localhost.http[application_id] }}"
|
||||||
|
|
||||||
|
- name: "Load docker and DB for {{ application_id }}"
|
||||||
|
include_role:
|
||||||
|
name: sys-stk-back-stateful
|
||||||
|
vars:
|
||||||
|
docker_compose_flush_handlers: false
|
||||||
|
|
||||||
|
- name: "Transfer upload.ini to {{ DRUPAL_CONFIG_UPLOAD_ABS }}"
|
||||||
|
template:
|
||||||
|
src: upload.ini.j2
|
||||||
|
dest: "{{ DRUPAL_CONFIG_UPLOAD_ABS }}"
|
||||||
|
notify:
|
||||||
|
- docker compose up
|
||||||
|
- docker compose build
|
||||||
|
|
||||||
|
- name: "Transfer msmtprc to {{ DRUPAL_MSMTP_ABS }}"
|
||||||
|
template:
|
||||||
|
src: "{{ DRUPAL_MSMTP_SRC }}"
|
||||||
|
dest: "{{ DRUPAL_MSMTP_ABS }}"
|
||||||
|
notify: docker compose up
|
||||||
|
|
||||||
|
- name: "Transfer settings.local.php overrides"
|
||||||
|
template:
|
||||||
|
src: settings.local.php.j2
|
||||||
|
dest: "{{ DRUPAL_SETTINGS_LOCAL_ABS }}"
|
||||||
|
notify: docker compose up
|
||||||
|
|
||||||
|
- name: Flush handlers to make container ready
|
||||||
|
meta: flush_handlers
|
||||||
|
|
||||||
|
- name: "Fix permissions for sites/default/files"
|
||||||
|
include_tasks: 00_permissions.yml
|
||||||
|
|
||||||
|
- name: "Ensure settings.php includes settings.local.php"
|
||||||
|
include_tasks: 01_settings_local_include.yml
|
||||||
|
|
||||||
|
- name: "Install Drupal (site:install)"
|
||||||
|
include_tasks: 02_install.yml
|
||||||
|
|
||||||
|
- name: "Enable OIDC modules"
|
||||||
|
include_tasks: 03_enable_modules.yml
|
||||||
|
when: applications | get_app_conf(application_id, 'features.oidc')
|
||||||
|
|
||||||
|
- name: "Configure OIDC (global + client)"
|
||||||
|
include_tasks: 04_configure_oidc.yml
|
||||||
|
when: applications | get_app_conf(application_id, 'features.oidc')
|
||||||
|
|
||||||
|
- name: "Harden trusted host patterns"
|
||||||
|
include_tasks: 05_trusted_hosts.yml
|
||||||
83
roles/web-app-drupal/templates/Dockerfile.j2
Normal file
83
roles/web-app-drupal/templates/Dockerfile.j2
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
FROM {{ DRUPAL_IMAGE }}:{{ DRUPAL_VERSION }}
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
# System dependencies (mail support + MySQL client + basic tools)
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y msmtp msmtp-mta git unzip zip less nano curl vim mariadb-client && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
# PHP extensions required by Drupal/Drush bootstrap
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
RUN docker-php-ext-install -j"$(nproc)" pdo_mysql
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
# Install Composer
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
|
||||||
|
&& php composer-setup.php --install-dir=/usr/local/bin --filename=composer \
|
||||||
|
&& rm composer-setup.php
|
||||||
|
|
||||||
|
ENV COMPOSER_ALLOW_SUPERUSER=1
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
# Build Drupal project with Drush + OpenID Connect
|
||||||
|
# IMPORTANT:
|
||||||
|
# - The Drupal base image uses /var/www/html as a symlink to {{ DRUPAL_DOCKER_HTML_PATH }}
|
||||||
|
# - Therefore, the actual project root must be placed in /opt/drupal
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
RUN set -eux; \
|
||||||
|
builddir="$(mktemp -d)"; \
|
||||||
|
composer create-project --no-interaction --no-ansi --no-progress drupal/recommended-project:^10 "$builddir"; \
|
||||||
|
composer --working-dir="$builddir" require -n drush/drush:^13 drupal/openid_connect:^2@beta; \
|
||||||
|
rm -rf /opt/drupal/* /opt/drupal/.[!.]* /opt/drupal/..?* 2>/dev/null || true; \
|
||||||
|
mkdir -p /opt/drupal; \
|
||||||
|
cp -a "$builddir"/. /opt/drupal/; \
|
||||||
|
rm -rf "$builddir"
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
# Make vendor binaries available in PATH
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
RUN ln -sf /opt/drupal/vendor/bin/drush /usr/local/bin/drush
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
# PHP upload configuration
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
COPY {{ DRUPAL_CONFIG_UPLOAD_REL }} $PHP_INI_DIR/conf.d/
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
# Permissions and ownership fixes
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
RUN set -eux; \
|
||||||
|
# Ensure all directories are traversable
|
||||||
|
chmod 755 /var /var/www /opt /opt/drupal; \
|
||||||
|
# Ensure correct ownership for Drupal files
|
||||||
|
chown -R www-data:www-data /opt/drupal; \
|
||||||
|
# Apply default permissions
|
||||||
|
find /opt/drupal -type d -exec chmod 755 {} +; \
|
||||||
|
find /opt/drupal -type f -exec chmod 644 {} +; \
|
||||||
|
# Ensure vendor binaries are executable
|
||||||
|
if [ -d /opt/drupal/vendor/bin ]; then chmod a+rx /opt/drupal/vendor/bin/*; fi; \
|
||||||
|
if [ -f /opt/drupal/vendor/drush/drush/drush ]; then chmod a+rx /opt/drupal/vendor/drush/drush/drush; fi; \
|
||||||
|
# Ensure the docroot ({{ DRUPAL_DOCKER_HTML_PATH }}) is accessible
|
||||||
|
if [ -d {{ DRUPAL_DOCKER_HTML_PATH }} ]; then \
|
||||||
|
chmod 755 {{ DRUPAL_DOCKER_HTML_PATH }}; \
|
||||||
|
find {{ DRUPAL_DOCKER_HTML_PATH }} -type d -exec chmod 755 {} +; \
|
||||||
|
fi; \
|
||||||
|
# Ensure settings.local.php exists and is owned by www-data
|
||||||
|
install -o www-data -g www-data -m 640 /dev/null {{ DRUPAL_DOCKER_HTML_PATH }}/sites/default/settings.local.php
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
# Runtime defaults
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
USER www-data
|
||||||
|
WORKDIR /var/www/html # symlink pointing to {{ DRUPAL_DOCKER_HTML_PATH }}
|
||||||
|
|
||||||
|
# Ensure PATH for non-login shells includes /usr/local/bin
|
||||||
|
ENV PATH="/usr/local/bin:/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
# Build-time check (optional)
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
RUN /usr/local/bin/drush --version
|
||||||
22
roles/web-app-drupal/templates/docker-compose.yml.j2
Normal file
22
roles/web-app-drupal/templates/docker-compose.yml.j2
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{% include 'roles/docker-compose/templates/base.yml.j2' %}
|
||||||
|
application:
|
||||||
|
{% include 'roles/docker-container/templates/base.yml.j2' %}
|
||||||
|
image: {{ DRUPAL_CUSTOM_IMAGE }}
|
||||||
|
container_name: {{ DRUPAL_CONTAINER }}
|
||||||
|
{{ lookup('template', 'roles/docker-container/templates/build.yml.j2') | indent(4) }}
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:{{ ports.localhost.http[application_id] }}:80"
|
||||||
|
volumes:
|
||||||
|
- data:{{ DRUPAL_DOCKER_HTML_PATH }}/sites/default/files
|
||||||
|
- {{ DRUPAL_MSMTP_ABS }}:/etc/msmtprc
|
||||||
|
- {{ DRUPAL_SETTINGS_LOCAL_ABS }}:{{ DRUPAL_DOCKER_CONF_PATH }}/settings.local.php
|
||||||
|
|
||||||
|
{% include 'roles/docker-container/templates/healthcheck/msmtp_curl.yml.j2' %}
|
||||||
|
{% include 'roles/docker-container/templates/depends_on/dmbs_excl.yml.j2' %}
|
||||||
|
{% include 'roles/docker-container/templates/networks.yml.j2' %}
|
||||||
|
|
||||||
|
{% include 'roles/docker-compose/templates/networks.yml.j2' %}
|
||||||
|
|
||||||
|
{% include 'roles/docker-compose/templates/volumes.yml.j2' %}
|
||||||
|
data:
|
||||||
|
name: "{{ DRUPAL_VOLUME }}"
|
||||||
7
roles/web-app-drupal/templates/env.j2
Normal file
7
roles/web-app-drupal/templates/env.j2
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
DRUPAL_DB_HOST= "{{ database_host }}:{{ database_port }}"
|
||||||
|
DRUPAL_DB_USER= "{{ database_username }}"
|
||||||
|
DRUPAL_DB_PASSWORD= "{{ database_password }}"
|
||||||
|
DRUPAL_DB_NAME= "{{ database_name }}"
|
||||||
|
|
||||||
|
# Debug flags (optional)
|
||||||
|
DRUPAL_DEBUG={{ MODE_DEBUG | lower }}
|
||||||
49
roles/web-app-drupal/templates/settings.local.php.j2
Normal file
49
roles/web-app-drupal/templates/settings.local.php.j2
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Local settings overrides generated by Ansible.
|
||||||
|
* - Reads DB + OIDC endpoints from environment variables.
|
||||||
|
* - Sets $databases and selected $config overrides.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$env = getenv();
|
||||||
|
|
||||||
|
/** Database **/
|
||||||
|
$host = getenv('DRUPAL_DB_HOST') ?: '{{ database_host }}:{{ database_port }}';
|
||||||
|
$db = getenv('DRUPAL_DB_NAME') ?: '{{ database_name }}';
|
||||||
|
$user = getenv('DRUPAL_DB_USER') ?: '{{ database_username }}';
|
||||||
|
$pass = getenv('DRUPAL_DB_PASSWORD') ?: '{{ database_password }}';
|
||||||
|
|
||||||
|
$parts = explode(':', $host, 2);
|
||||||
|
$hostname = $parts[0];
|
||||||
|
$port = isset($parts[1]) ? (int)$parts[1] : 3306;
|
||||||
|
|
||||||
|
$databases['default']['default'] = [
|
||||||
|
'database' => $db,
|
||||||
|
'username' => $user,
|
||||||
|
'password' => $pass,
|
||||||
|
'prefix' => '',
|
||||||
|
'host' => $hostname,
|
||||||
|
'port' => $port,
|
||||||
|
'namespace'=> 'Drupal\\Core\\Database\\Driver\\mysql',
|
||||||
|
'driver' => 'mysql',
|
||||||
|
];
|
||||||
|
|
||||||
|
/** OIDC endpoint hints (optional) — the real config is applied via Drush. */
|
||||||
|
$config['openid_connect.settings']['automatic_account_creation'] = true;
|
||||||
|
$config['openid_connect.settings']['always_save_userinfo'] = true;
|
||||||
|
$config['openid_connect.settings']['link_existing_users'] = true;
|
||||||
|
|
||||||
|
/** Trusted host patterns can be extended by Ansible task 04_trusted_hosts.yml */
|
||||||
|
|
||||||
|
/** Enable local services YML if present */
|
||||||
|
$settings['container_yamls'][] = $app_root . '/' . $site_path . '/services.local.yml';
|
||||||
|
|
||||||
|
// Reverse proxy optional über ENV setzen (z.B. "10.0.0.0/8, 172.16.0.0/12")
|
||||||
|
$proxy = getenv('REVERSE_PROXY_ADDRESSES');
|
||||||
|
if ($proxy) {
|
||||||
|
$settings['reverse_proxy'] = TRUE;
|
||||||
|
$settings['reverse_proxy_addresses'] = array_map('trim', explode(',', $proxy));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Hash salt (from schema/credentials, hashed with SHA-256) */
|
||||||
|
$settings['hash_salt'] = '{{ applications | get_app_conf(application_id, "credentials.hash_salt", True) }}';
|
||||||
8
roles/web-app-drupal/templates/upload.ini.j2
Normal file
8
roles/web-app-drupal/templates/upload.ini.j2
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
file_uploads = On
|
||||||
|
memory_limit = {{ DRUPAL_MAX_UPLOAD_SIZE }}
|
||||||
|
upload_max_filesize = {{ DRUPAL_MAX_UPLOAD_SIZE }}
|
||||||
|
post_max_size = {{ DRUPAL_MAX_UPLOAD_SIZE }}
|
||||||
|
max_execution_time = 300
|
||||||
|
|
||||||
|
; Use msmtp as the Mail Transfer Agent
|
||||||
|
sendmail_path = "/usr/bin/msmtp -t"
|
||||||
4
roles/web-app-drupal/users/main.yml
Normal file
4
roles/web-app-drupal/users/main.yml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
users:
|
||||||
|
administrator:
|
||||||
|
username: "administrator"
|
||||||
|
email: "administrator@{{ PRIMARY_DOMAIN }}"
|
||||||
28
roles/web-app-drupal/vars/main.yml
Normal file
28
roles/web-app-drupal/vars/main.yml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# General
|
||||||
|
|
||||||
|
application_id: "web-app-drupal"
|
||||||
|
database_type: "mariadb"
|
||||||
|
|
||||||
|
# Drupal
|
||||||
|
|
||||||
|
DRUPAL_URL: "{{ domains | get_url(application_id, WEB_PROTOCOL) }}"
|
||||||
|
DRUPAL_CUSTOM_IMAGE: "drupal_custom"
|
||||||
|
DRUPAL_DOCKER_HTML_PATH: "/opt/drupal/web"
|
||||||
|
DRUPAL_DOCKER_CONF_PATH: "{{ DRUPAL_DOCKER_HTML_PATH }}/sites/default"
|
||||||
|
DRUPAL_VERSION: "{{ applications | get_app_conf(application_id, 'docker.services.drupal.version') }}"
|
||||||
|
DRUPAL_IMAGE: "{{ applications | get_app_conf(application_id, 'docker.services.drupal.image') }}"
|
||||||
|
DRUPAL_CONTAINER: "{{ applications | get_app_conf(application_id, 'docker.services.drupal.name') }}"
|
||||||
|
DRUPAL_VOLUME: "{{ applications | get_app_conf(application_id, 'docker.volumes.data') }}"
|
||||||
|
DRUPAL_DOMAINS: "{{ applications | get_app_conf(application_id, 'server.domains.canonical') }}"
|
||||||
|
DRUPAL_USER: "www-data"
|
||||||
|
|
||||||
|
DRUPAL_CONFIG_UPLOAD_REL: "config/upload.ini"
|
||||||
|
DRUPAL_CONFIG_UPLOAD_ABS: "{{ [docker_compose.directories.instance, DRUPAL_CONFIG_UPLOAD_REL] | path_join }}"
|
||||||
|
|
||||||
|
DRUPAL_SETTINGS_LOCAL_REL: "config/settings.local.php"
|
||||||
|
DRUPAL_SETTINGS_LOCAL_ABS: "{{ [docker_compose.directories.instance, DRUPAL_SETTINGS_LOCAL_REL] | path_join }}"
|
||||||
|
|
||||||
|
DRUPAL_MSMTP_SRC: "{{ [ playbook_dir, 'roles/sys-svc-msmtp/templates/msmtprc.conf.j2' ] | path_join }}"
|
||||||
|
DRUPAL_MSMTP_ABS: "{{ [ docker_compose.directories.config, 'msmtprc.conf'] | path_join }}"
|
||||||
|
|
||||||
|
DRUPAL_MAX_UPLOAD_SIZE: "{{ applications | get_app_conf(application_id, 'max_upload_size') }}"
|
||||||
34
roles/web-app-drupal/vars/oidc.yml
Normal file
34
roles/web-app-drupal/vars/oidc.yml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# OIDC configuration for Drupal's OpenID Connect module.
|
||||||
|
|
||||||
|
# Global settings for openid_connect.settings
|
||||||
|
|
||||||
|
oidc_settings:
|
||||||
|
automatic_account_creation: true # Auto-create users on first login
|
||||||
|
always_save_userinfo: true # Store latest userinfo on each login
|
||||||
|
link_existing_users: true # Match existing users by email
|
||||||
|
login_display: "button" # 'button' or 'form'
|
||||||
|
enforced: false # If true, require login for the whole site
|
||||||
|
|
||||||
|
# OIDC client entity (e.g., 'keycloak')
|
||||||
|
|
||||||
|
oidc_client:
|
||||||
|
id: "keycloak"
|
||||||
|
label: "Keycloak"
|
||||||
|
plugin: "generic" # use the built-in generic OIDC client plugin
|
||||||
|
settings:
|
||||||
|
client_id: "{{ OIDC.CLIENT.ID }}"
|
||||||
|
client_secret: "{{ OIDC.CLIENT.SECRET }}"
|
||||||
|
authorization_endpoint: "{{ OIDC.CLIENT.AUTHORIZE_URL }}"
|
||||||
|
token_endpoint: "{{ OIDC.CLIENT.TOKEN_URL }}"
|
||||||
|
userinfo_endpoint: "{{ OIDC.CLIENT.USER_INFO_URL }}"
|
||||||
|
end_session_endpoint: "{{ OIDC.CLIENT.LOGOUT_URL }}"
|
||||||
|
scopes:
|
||||||
|
- "openid"
|
||||||
|
- "email"
|
||||||
|
- "profile"
|
||||||
|
use_standard_claims: true
|
||||||
|
# Optional claim mapping examples:
|
||||||
|
# username_claim: "{{ OIDC.ATTRIBUTES.USERNAME }}"
|
||||||
|
# email_claim: "{{ OIDC.ATTRIBUTES.EMAIL }}"
|
||||||
|
# given_name_claim: "{{ OIDC.ATTRIBUTES.GIVEN_NAME }}"
|
||||||
|
# family_name_claim: "{{ OIDC.ATTRIBUTES.FAMILY_NAME }}"
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
# (Optional) specifically wait for the CLI installer script
|
# (Optional) specifically wait for the CLI installer script
|
||||||
- name: "Check for CLI installer"
|
- name: "Check for CLI installer"
|
||||||
command:
|
command:
|
||||||
argv: [ docker, exec, "{{ JOOMLA_CONTAINER }}", test, -f, /var/www/html/installation/joomla.php ]
|
argv: [ docker, exec, "{{ JOOMLA_CONTAINER }}", test, -f, "{{ JOOMLA_INSTALLER_CLI_FILE }}" ]
|
||||||
register: has_installer
|
register: has_installer
|
||||||
changed_when: false
|
changed_when: false
|
||||||
failed_when: false
|
failed_when: false
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
- exec
|
- exec
|
||||||
- "{{ JOOMLA_CONTAINER }}"
|
- "{{ JOOMLA_CONTAINER }}"
|
||||||
- php
|
- php
|
||||||
- /var/www/html/installation/joomla.php
|
- "{{ JOOMLA_INSTALLER_CLI_FILE }}"
|
||||||
- install
|
- install
|
||||||
- "--db-type={{ JOOMLA_DB_CONNECTOR }}"
|
- "--db-type={{ JOOMLA_DB_CONNECTOR }}"
|
||||||
- "--db-host={{ database_host }}"
|
- "--db-host={{ database_host }}"
|
||||||
|
|||||||
18
roles/web-app-joomla/tasks/05_reset_admin_password.yml
Normal file
18
roles/web-app-joomla/tasks/05_reset_admin_password.yml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
# Reset Joomla admin password via CLI (inside the container)
|
||||||
|
- name: "Reset Joomla admin password (non-interactive CLI)"
|
||||||
|
command:
|
||||||
|
argv:
|
||||||
|
- docker
|
||||||
|
- exec
|
||||||
|
- "{{ JOOMLA_CONTAINER }}"
|
||||||
|
- php
|
||||||
|
- "{{ JOOMLA_CLI_FILE }}"
|
||||||
|
- user:reset-password
|
||||||
|
- "--username"
|
||||||
|
- "{{ JOOMLA_USER_NAME }}"
|
||||||
|
- "--password"
|
||||||
|
- "{{ JOOMLA_USER_PASSWORD }}"
|
||||||
|
register: j_password_reset
|
||||||
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||||
|
changed_when: j_password_reset.rc == 0
|
||||||
@@ -24,3 +24,7 @@
|
|||||||
- name: Include assert routines
|
- name: Include assert routines
|
||||||
include_tasks: "04_assert.yml"
|
include_tasks: "04_assert.yml"
|
||||||
when: MODE_ASSERT | bool
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
|
- name: Reset Admin Password
|
||||||
|
include_tasks: 05_reset_admin_password.yml
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ JOOMLA_DOMAINS: "{{ applications | get_app_conf(application_id
|
|||||||
JOOMLA_SITE_NAME: "{{ SOFTWARE_NAME }} Joomla - CMS"
|
JOOMLA_SITE_NAME: "{{ SOFTWARE_NAME }} Joomla - CMS"
|
||||||
JOOMLA_DB_CONNECTOR: "{{ 'pgsql' if database_type == 'postgres' else 'mysqli' }}"
|
JOOMLA_DB_CONNECTOR: "{{ 'pgsql' if database_type == 'postgres' else 'mysqli' }}"
|
||||||
JOOMLA_CONFIG_FILE: "/var/www/html/configuration.php"
|
JOOMLA_CONFIG_FILE: "/var/www/html/configuration.php"
|
||||||
|
JOOMLA_INSTALLER_CLI_FILE: "/var/www/html/installation/joomla.php"
|
||||||
|
JOOMLA_CLI_FILE: "/var/www/html/cli/joomla.php"
|
||||||
|
|
||||||
# User
|
# User
|
||||||
JOOMLA_USER_NAME: "{{ users.administrator.username }}"
|
JOOMLA_USER_NAME: "{{ users.administrator.username }}"
|
||||||
|
|||||||
@@ -13,6 +13,16 @@ server:
|
|||||||
aliases: []
|
aliases: []
|
||||||
status_codes:
|
status_codes:
|
||||||
default: 404
|
default: 404
|
||||||
|
csp:
|
||||||
|
flags:
|
||||||
|
script-src-elem:
|
||||||
|
unsafe-inline: true
|
||||||
|
whitelist:
|
||||||
|
script-src-elem:
|
||||||
|
- "https://www.hcaptcha.com"
|
||||||
|
- "https://js.hcaptcha.com"
|
||||||
|
frame-src:
|
||||||
|
- "https://newassets.hcaptcha.com/"
|
||||||
docker:
|
docker:
|
||||||
services:
|
services:
|
||||||
database:
|
database:
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ server:
|
|||||||
script-src-attr:
|
script-src-attr:
|
||||||
unsafe-eval: true
|
unsafe-eval: true
|
||||||
whitelist:
|
whitelist:
|
||||||
|
script-src-elem:
|
||||||
|
- "https://www.hcaptcha.com"
|
||||||
|
- "https://js.hcaptcha.com"
|
||||||
font-src:
|
font-src:
|
||||||
- "data:"
|
- "data:"
|
||||||
connect-src:
|
connect-src:
|
||||||
@@ -19,6 +22,7 @@ server:
|
|||||||
frame-src:
|
frame-src:
|
||||||
- "{{ WEBSOCKET_PROTOCOL }}://collabora.{{ PRIMARY_DOMAIN }}"
|
- "{{ WEBSOCKET_PROTOCOL }}://collabora.{{ PRIMARY_DOMAIN }}"
|
||||||
- "{{ WEB_PROTOCOL }}://collabora.{{ PRIMARY_DOMAIN }}"
|
- "{{ WEB_PROTOCOL }}://collabora.{{ PRIMARY_DOMAIN }}"
|
||||||
|
- "https://newassets.hcaptcha.com/"
|
||||||
worker-src:
|
worker-src:
|
||||||
- "blob:"
|
- "blob:"
|
||||||
domains:
|
domains:
|
||||||
|
|||||||
@@ -7,6 +7,9 @@
|
|||||||
command: "{{ NEXTCLOUD_DOCKER_EXEC_OCC }} maintenance:repair --include-expensive"
|
command: "{{ NEXTCLOUD_DOCKER_EXEC_OCC }} maintenance:repair --include-expensive"
|
||||||
register: occ_repair
|
register: occ_repair
|
||||||
changed_when: "'No repairs needed' not in occ_repair.stdout"
|
changed_when: "'No repairs needed' not in occ_repair.stdout"
|
||||||
|
retries: 3
|
||||||
|
delay: 10
|
||||||
|
until: occ_repair.rc == 0
|
||||||
|
|
||||||
- name: Nextcloud | App update (retry once)
|
- name: Nextcloud | App update (retry once)
|
||||||
command: "{{ NEXTCLOUD_DOCKER_EXEC_OCC }} app:update --all"
|
command: "{{ NEXTCLOUD_DOCKER_EXEC_OCC }} app:update --all"
|
||||||
|
|||||||
@@ -16,6 +16,13 @@
|
|||||||
- name: Flush all handlers immediately so that occ can be used
|
- name: Flush all handlers immediately so that occ can be used
|
||||||
meta: flush_handlers
|
meta: flush_handlers
|
||||||
|
|
||||||
|
- name: Wait until Redis is ready (PONG)
|
||||||
|
command: "docker exec {{ NEXTCLOUD_REDIS_CONTAINER }} redis-cli ping"
|
||||||
|
register: redis_ping
|
||||||
|
retries: 60
|
||||||
|
delay: 2
|
||||||
|
until: (redis_ping.stdout | default('')) is search('PONG')
|
||||||
|
|
||||||
- name: Update\Upgrade Nextcloud
|
- name: Update\Upgrade Nextcloud
|
||||||
include_tasks: 03_upgrade.yml
|
include_tasks: 03_upgrade.yml
|
||||||
when: MODE_UPDATE | bool
|
when: MODE_UPDATE | bool
|
||||||
|
|||||||
@@ -141,4 +141,7 @@ NEXTCLOUD_DOCKER_USER: "www-data" # Name of the www-data user
|
|||||||
## Execution
|
## Execution
|
||||||
NEXTCLOUD_INTERNAL_OCC_COMMAND: "{{ [ NEXTCLOUD_DOCKER_WORK_DIRECTORY, 'occ'] | path_join }}"
|
NEXTCLOUD_INTERNAL_OCC_COMMAND: "{{ [ NEXTCLOUD_DOCKER_WORK_DIRECTORY, 'occ'] | path_join }}"
|
||||||
NEXTCLOUD_DOCKER_EXEC: "docker exec -u {{ NEXTCLOUD_DOCKER_USER }} {{ NEXTCLOUD_CONTAINER }}" # General execute composition
|
NEXTCLOUD_DOCKER_EXEC: "docker exec -u {{ NEXTCLOUD_DOCKER_USER }} {{ NEXTCLOUD_CONTAINER }}" # General execute composition
|
||||||
NEXTCLOUD_DOCKER_EXEC_OCC: "{{ NEXTCLOUD_DOCKER_EXEC }} {{ NEXTCLOUD_INTERNAL_OCC_COMMAND }}" # Execute docker occ command
|
NEXTCLOUD_DOCKER_EXEC_OCC: "{{ NEXTCLOUD_DOCKER_EXEC }} {{ NEXTCLOUD_INTERNAL_OCC_COMMAND }}" # Execute docker occ command
|
||||||
|
|
||||||
|
## Redis
|
||||||
|
NEXTCLOUD_REDIS_CONTAINER: "{{ entity_name }}-redis"
|
||||||
Reference in New Issue
Block a user