From dcc01ecd2001e9f6382a6666e1ac0d65e4154389 Mon Sep 17 00:00:00 2001 From: Danyal Berchtold Date: Wed, 20 May 2026 10:09:16 +0200 Subject: [PATCH 1/5] refactor(roles/nextcloud): parameterize OS-specific names for multi-OS support Move the hardcoded RHEL-specific web server user/group (apache), the PHP-FPM service name (php-fpm) and the base package list out of the role logic into vars/RedHat.yml, loaded via shared/platform-variables.yml. Expose nextcloud__webserver_user, nextcloud__webserver_group and nextcloud__php_fpm_service_name as overridable variables and use them throughout the tasks, the deployed systemd services and the notify_push unit, as well as the nextcloud-update script. Guard the SELinux restorecon tasks with the selinux status fact and switch the update script's SELinux blocks to ansible_facts["os_family"]. Only vars/RedHat.yml ships, so the role still runs on RHEL only; adding a tested vars/Debian.yml is all that is needed to extend support. --- CHANGELOG.md | 1 + roles/nextcloud/README.md | 18 +++++ roles/nextcloud/defaults/main.yml | 8 +- roles/nextcloud/tasks/create-user.yml | 4 +- roles/nextcloud/tasks/main.yml | 73 +++++++++++-------- .../system/nextcloud-app-update.service.j2 | 4 +- .../systemd/system/nextcloud-jobs.service.j2 | 4 +- .../nextcloud-ldap-show-remnants.service.j2 | 4 +- .../system/nextcloud-scan-files.service.j2 | 4 +- .../usr/local/bin/nextcloud-update.j2 | 14 ++-- roles/nextcloud/vars/RedHat.yml | 8 ++ 11 files changed, 93 insertions(+), 49 deletions(-) create mode 100644 roles/nextcloud/vars/RedHat.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index b961ce274..8bb2c2103 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +* **role:nextcloud**: Lay the groundwork for non-RHEL platforms (Debian/Ubuntu) by removing hardcoded RHEL-specific names from the role logic. The web server user/group (previously `apache`), the PHP-FPM service name (previously `php-fpm`) and the base package list (previously the RHEL names `openldap-clients`/`samba-client`) are now sourced from OS-specific `vars/` via `shared/platform-variables.yml`. The web server user/group and PHP-FPM service name are exposed as the overridable variables `nextcloud__webserver_user`, `nextcloud__webserver_group` and `nextcloud__php_fpm_service_name` and are now used throughout the tasks, the deployed systemd services and the notify_push unit (not just the `/usr/local/bin/nextcloud-update` script). The SELinux `restorecon` tasks are now guarded by `ansible_facts["selinux"]["status"] != "disabled"`, and the SELinux blocks in the update script use `ansible_facts["os_family"]` instead of `ansible_os_family`. Only `vars/RedHat.yml` ships, so the role still runs on RHEL only (see `COMPATIBILITY.md`); adding a tested `vars/Debian.yml` is all that is needed to extend support. * **playbooks**: Enable the CRB repository on Rocky 10 too, not just Rocky 9. Previously Rocky 10 hosts silently skipped this step, which could leave dependencies such as `python3-virtualenv` uninstallable. * **role:grafana**: Apply the systemd/chkconfig workaround on RHEL 10 as well, not just RHEL 9. * **role:tools**: Install the German locale package (`glibc-langpack-de`) on RHEL 10 as well. diff --git a/roles/nextcloud/README.md b/roles/nextcloud/README.md index c00f3741a..c73f8dee2 100644 --- a/roles/nextcloud/README.md +++ b/roles/nextcloud/README.md @@ -237,6 +237,12 @@ nextcloud__users: * Type: String. * Default: `'*:50:15'` +`nextcloud__php_fpm_service_name` + +* Name of the PHP-FPM systemd service that the role restarts (and that the `/usr/local/bin/nextcloud-update` script restarts). Defaults to the OS-specific value (`php-fpm` on RHEL, `php-fpm` on Debian). +* Type: String. +* Default: Have a look at [vars/](https://github.com/Linuxfabrik/lfops/blob/main/roles/nextcloud/vars/) + `nextcloud__skip_apps` * Completely skips the management of Nextcloud apps. Set this to prevent changes via the WebGUI from being overwritten. @@ -332,6 +338,18 @@ nextcloud__users: * Type: Number. * Default: `80` +`nextcloud__webserver_group` + +* Group of the web server, used for file ownership of the Nextcloud installation. Defaults to the OS-specific value (`apache` on RHEL, `www-data` on Debian). +* Type: String. +* Default: Have a look at [vars/](https://github.com/Linuxfabrik/lfops/blob/main/roles/nextcloud/vars/) + +`nextcloud__webserver_user` + +* User of the web server, used for file ownership, to run the `occ` commands and as the `User=` of the deployed systemd services. Defaults to the OS-specific value (`apache` on RHEL, `www-data` on Debian). +* Type: String. +* Default: Have a look at [vars/](https://github.com/Linuxfabrik/lfops/blob/main/roles/nextcloud/vars/) + Example: ```yaml # optional diff --git a/roles/nextcloud/defaults/main.yml b/roles/nextcloud/defaults/main.yml index 9e491ac61..67b539830 100644 --- a/roles/nextcloud/defaults/main.yml +++ b/roles/nextcloud/defaults/main.yml @@ -177,6 +177,9 @@ nextcloud__mariadb_login: '{{ mariadb_server__admin_user }}' nextcloud__on_calendar_app_update: '06,18,23:{{ 59 | random(seed=inventory_hostname) }}' nextcloud__on_calendar_jobs: '*:0/5' # every 5 minutes nextcloud__on_calendar_scan_files: '*:50:15' # every hour at hh:50:15 + +nextcloud__php_fpm_service_name: '{{ __nextcloud__php_fpm_service_name }}' + nextcloud__skip_apps: false nextcloud__skip_notify_push: false @@ -310,6 +313,9 @@ nextcloud__timer_scan_files_enabled: true # 'latest', 'latest-XX' or 'nextcloud-XX.X.XX' nextcloud__version: 'latest' +nextcloud__webserver_group: '{{ __nextcloud__webserver_group }}' +nextcloud__webserver_user: '{{ __nextcloud__webserver_user }}' + # ----------------------------------------------------------------------------- nextcloud__apache_httpd__mods__dependent_var: @@ -546,6 +552,6 @@ nextcloud__systemd_unit__services__dependent_var: Environment=PORT=7867 ExecStartPre=-/bin/chcon --type bin_t /var/www/html/nextcloud/apps/notify_push/bin/x86_64/notify_push ExecStart=/var/www/html/nextcloud/apps/notify_push/bin/x86_64/notify_push /var/www/html/nextcloud/config/config.php - User=apache + User={{ nextcloud__webserver_user }} enabled: true state: 'present' diff --git a/roles/nextcloud/tasks/create-user.yml b/roles/nextcloud/tasks/create-user.yml index c6cfb78fd..4f58d50ab 100644 --- a/roles/nextcloud/tasks/create-user.yml +++ b/roles/nextcloud/tasks/create-user.yml @@ -1,7 +1,7 @@ - name: 'Create Nextcloud user {{ ncuser["username"] }}' ansible.builtin.shell: >- export OC_PASS={{ ncuser["password"] | quote }}; - sudo -E -u apache php occ user:add + sudo -E -u {{ nextcloud__webserver_user }} php occ user:add --password-from-env --group {{ ncuser["group"] | d('""') | quote }} {{ ncuser["username"] | quote }} @@ -15,7 +15,7 @@ - name: 'Update Nextcloud settings for user {{ ncuser["username"] }}' ansible.builtin.command: | - sudo -u apache php occ user:setting {{ ncuser["username"] }} {{ item }} + sudo -u {{ nextcloud__webserver_user }} php occ user:setting {{ ncuser["username"] }} {{ item }} args: chdir: '/var/www/html/nextcloud/' # changed_when: there is no easy way to check for changes diff --git a/roles/nextcloud/tasks/main.yml b/roles/nextcloud/tasks/main.yml index 72f673a21..b03756433 100644 --- a/roles/nextcloud/tasks/main.yml +++ b/roles/nextcloud/tasks/main.yml @@ -1,12 +1,19 @@ - block: - - name: 'Install bzip2 jq openldap-clients samba-client' + - name: 'Set platform/version specific variables' + ansible.builtin.import_role: + name: 'shared' + tasks_from: 'platform-variables.yml' + + tags: + - 'always' + + +- block: + + - name: 'Install required packages' ansible.builtin.package: - name: - - 'bzip2' - - 'jq' - - 'openldap-clients' - - 'samba-client' + name: '{{ __nextcloud__packages }}' state: 'present' - name: 'wget https://download.nextcloud.com/server/releases/{{ nextcloud__version }}.tar.bz2' @@ -26,25 +33,25 @@ backup: true src: 'var/www/html/nextcloud/config/objectstore.config.php.j2' dest: '/var/www/html/nextcloud/config/objectstore.config.php' - owner: 'apache' - group: 'apache' + owner: '{{ nextcloud__webserver_user }}' + group: '{{ nextcloud__webserver_group }}' mode: 0o644 when: '(nextcloud__storage_backend_s3["bucket"] is defined and nextcloud__storage_backend_s3["bucket"] | length > 0) or (nextcloud__storage_backend_swift["bucket"] is defined and nextcloud__storage_backend_swift["bucket"] | length > 0)' - - name: 'chown -R apache:apache /var/www/html/nextcloud' + - name: 'chown -R {{ nextcloud__webserver_user }}:{{ nextcloud__webserver_group }} /var/www/html/nextcloud' ansible.builtin.file: path: '/var/www/html/nextcloud' - owner: 'apache' - group: 'apache' + owner: '{{ nextcloud__webserver_user }}' + group: '{{ nextcloud__webserver_group }}' recurse: true - - name: 'mkdir path/to/data; chown -R apache:apache path/to/data; chmod 0750 -R path/to/data' + - name: 'mkdir path/to/data; chown -R {{ nextcloud__webserver_user }}:{{ nextcloud__webserver_group }} path/to/data; chmod 0750 -R path/to/data' ansible.builtin.file: path: '{{ item }}' state: 'directory' - owner: 'apache' - group: 'apache' + owner: '{{ nextcloud__webserver_user }}' + group: '{{ nextcloud__webserver_group }}' mode: 0o750 loop: - '/data' @@ -59,6 +66,8 @@ ansible.builtin.command: 'restorecon -Fvr /data /var/www/html/nextcloud' register: 'nextcloud__restorecon_nextcloud_result' changed_when: 'nextcloud__restorecon_nextcloud_result["stdout"] | length > 0' + when: + - 'ansible_facts["selinux"]["status"] != "disabled"' - name: 'Run the Nextcloud installer' # installation hangs without "--admin-user" and "--admin-pass" @@ -76,7 +85,7 @@ chdir: '/var/www/html/nextcloud/' creates: '/var/www/html/nextcloud/config/config.php' become: true - become_user: 'apache' + become_user: '{{ nextcloud__webserver_user }}' - name: 'Convert some database columns to big int' ansible.builtin.command: | @@ -84,7 +93,7 @@ args: chdir: '/var/www/html/nextcloud/' become: true - become_user: 'apache' + become_user: '{{ nextcloud__webserver_user }}' register: 'nextcloud__convert_filecache_bigint_result' changed_when: '"All tables already up to date" not in nextcloud__convert_filecache_bigint_result["stdout"]' # changed_when: there is no easy way to check for changes @@ -98,7 +107,7 @@ - name: 'Get Nextcloud config list' ansible.builtin.command: 'php /var/www/html/nextcloud/occ --no-interaction --output=json config:list --private' become: true - become_user: 'apache' + become_user: '{{ nextcloud__webserver_user }}' changed_when: false check_mode: false register: '__nextcloud__config_list_result' @@ -111,14 +120,14 @@ state: '{{ item["state"] | d("present") }}' installed_config_json: '{{ __nextcloud__config_list_result["stdout"] | from_json }}' become: true - become_user: 'apache' + become_user: '{{ nextcloud__webserver_user }}' loop: '{{ nextcloud__sysconfig__combined_var }}' # do this straight after the installation to get NC up and running # otherwise subsequent occ commands might fail - - name: 'restart php-fpm' + - name: 'restart {{ nextcloud__php_fpm_service_name }}' ansible.builtin.service: - name: 'php-fpm' + name: '{{ nextcloud__php_fpm_service_name }}' state: 'restarted' tags: @@ -131,7 +140,7 @@ - name: 'Get Nextcloud app list' ansible.builtin.command: 'php /var/www/html/nextcloud/occ --no-interaction --output=json app:list' become: true - become_user: 'apache' + become_user: '{{ nextcloud__webserver_user }}' changed_when: false check_mode: false register: '__nextcloud__app_list_result' @@ -143,13 +152,13 @@ force: '{{ item["force"] | d(false) }}' installed_apps_json: '{{ __nextcloud__app_list_result["stdout"] | from_json }}' become: true - become_user: 'apache' + become_user: '{{ nextcloud__webserver_user }}' loop: '{{ nextcloud__apps__combined_var }}' - name: 'Get Nextcloud config list' ansible.builtin.command: 'php /var/www/html/nextcloud/occ --no-interaction --output=json config:list --private' become: true - become_user: 'apache' + become_user: '{{ nextcloud__webserver_user }}' changed_when: false check_mode: false register: '__nextcloud__config_list_result' @@ -163,12 +172,12 @@ state: '{{ item["state"] | d("present") }}' installed_config_json: '{{ __nextcloud__config_list_result["stdout"] | from_json }}' become: true - become_user: 'apache' + become_user: '{{ nextcloud__webserver_user }}' loop: '{{ nextcloud__app_configs__combined_var }}' - - name: 'restart php-fpm' + - name: 'restart {{ nextcloud__php_fpm_service_name }}' ansible.builtin.service: - name: 'php-fpm' + name: '{{ nextcloud__php_fpm_service_name }}' state: 'restarted' when: @@ -184,6 +193,8 @@ ansible.builtin.command: 'restorecon -Fvr /var/www/html/nextcloud/apps/notify_push/' register: 'nextcloud__restorecon_notify_push_result' changed_when: 'nextcloud__restorecon_notify_push_result["stdout"] | length > 0' + when: + - 'ansible_facts["selinux"]["status"] != "disabled"' - name: 'systemctl restart notify_push.service' ansible.builtin.systemd_service: @@ -196,7 +207,7 @@ args: chdir: '/var/www/html/nextcloud/' become: true - become_user: 'apache' + become_user: '{{ nextcloud__webserver_user }}' when: - 'not nextcloud__skip_notify_push' @@ -221,11 +232,11 @@ - block: - - name: 'chown -R apache:apache /var/www/html/nextcloud' + - name: 'chown -R {{ nextcloud__webserver_user }}:{{ nextcloud__webserver_group }} /var/www/html/nextcloud' ansible.builtin.file: path: '/var/www/html/nextcloud' - owner: 'apache' - group: 'apache' + owner: '{{ nextcloud__webserver_user }}' + group: '{{ nextcloud__webserver_group }}' recurse: true tags: @@ -260,7 +271,7 @@ args: chdir: '/var/www/html/nextcloud/' become: true - become_user: 'apache' + become_user: '{{ nextcloud__webserver_user }}' # changed_when: there is no easy way to check for changes - name: 'Deploy /etc/systemd/system/nextcloud-app-update.service' diff --git a/roles/nextcloud/templates/etc/systemd/system/nextcloud-app-update.service.j2 b/roles/nextcloud/templates/etc/systemd/system/nextcloud-app-update.service.j2 index 06ef0f523..a5f42bd4e 100644 --- a/roles/nextcloud/templates/etc/systemd/system/nextcloud-app-update.service.j2 +++ b/roles/nextcloud/templates/etc/systemd/system/nextcloud-app-update.service.j2 @@ -1,5 +1,5 @@ # {{ ansible_managed }} -# 2022100401 +# 2026052001 [Unit] Description=Nextcloud App Update Service @@ -8,4 +8,4 @@ Description=Nextcloud App Update Service ExecStart=/usr/bin/php occ app:update --all --no-interaction --quiet WorkingDirectory=/var/www/html/nextcloud Type=oneshot -User=apache +User={{ nextcloud__webserver_user }} diff --git a/roles/nextcloud/templates/etc/systemd/system/nextcloud-jobs.service.j2 b/roles/nextcloud/templates/etc/systemd/system/nextcloud-jobs.service.j2 index 668db63b9..4a8423ddd 100644 --- a/roles/nextcloud/templates/etc/systemd/system/nextcloud-jobs.service.j2 +++ b/roles/nextcloud/templates/etc/systemd/system/nextcloud-jobs.service.j2 @@ -1,5 +1,5 @@ # {{ ansible_managed }} -# 2023041802 +# 2026052001 [Unit] Description=Nextcloud Background Jobs Service @@ -7,6 +7,6 @@ Description=Nextcloud Background Jobs Service [Service] ExecStart=/usr/bin/php --file /var/www/html/nextcloud/cron.php Type=oneshot -User=apache +User={{ nextcloud__webserver_user }} KillMode=process TimeoutStartSec=10m diff --git a/roles/nextcloud/templates/etc/systemd/system/nextcloud-ldap-show-remnants.service.j2 b/roles/nextcloud/templates/etc/systemd/system/nextcloud-ldap-show-remnants.service.j2 index 3e69a47d1..3418eeeba 100644 --- a/roles/nextcloud/templates/etc/systemd/system/nextcloud-ldap-show-remnants.service.j2 +++ b/roles/nextcloud/templates/etc/systemd/system/nextcloud-ldap-show-remnants.service.j2 @@ -1,5 +1,5 @@ # {{ ansible_managed }} -# 2024062101 +# 2026052001 [Unit] Description=Nextcloud LDAP Show Remnants Service @@ -8,4 +8,4 @@ Description=Nextcloud LDAP Show Remnants Service # need the help of /bin/sh here, since systemd units don't understand pipes directly ExecStart=/usr/local/bin/nextcloud-ldap-show-remnants Type=oneshot -User=apache +User={{ nextcloud__webserver_user }} diff --git a/roles/nextcloud/templates/etc/systemd/system/nextcloud-scan-files.service.j2 b/roles/nextcloud/templates/etc/systemd/system/nextcloud-scan-files.service.j2 index f5b66f9eb..c45fad609 100644 --- a/roles/nextcloud/templates/etc/systemd/system/nextcloud-scan-files.service.j2 +++ b/roles/nextcloud/templates/etc/systemd/system/nextcloud-scan-files.service.j2 @@ -1,5 +1,5 @@ # {{ ansible_managed }} -# 2022110701 +# 2026052001 [Unit] Description=Nextcloud Scan Files Service @@ -8,4 +8,4 @@ Description=Nextcloud Scan Files Service ExecStart=/usr/bin/nice --adjustment 19 /usr/bin/php occ files:scan --all --unscanned WorkingDirectory=/var/www/html/nextcloud Type=oneshot -User=apache +User={{ nextcloud__webserver_user }} diff --git a/roles/nextcloud/templates/usr/local/bin/nextcloud-update.j2 b/roles/nextcloud/templates/usr/local/bin/nextcloud-update.j2 index 953c62244..c5ad20d7a 100644 --- a/roles/nextcloud/templates/usr/local/bin/nextcloud-update.j2 +++ b/roles/nextcloud/templates/usr/local/bin/nextcloud-update.j2 @@ -1,6 +1,6 @@ #!/usr/bin/env bash # {{ ansible_managed }} -# 2026051102 +# 2026052001 set -euo pipefail @@ -11,9 +11,9 @@ error_handler() { } trap 'error_handler "${LINENO}"' ERR -WEBSERVER_USER="apache" -WEBSERVER_GROUP="apache" -PHP_SERVICE_NAME="php-fpm" +WEBSERVER_USER="{{ nextcloud__webserver_user }}" +WEBSERVER_GROUP="{{ nextcloud__webserver_group }}" +PHP_SERVICE_NAME="{{ nextcloud__php_fpm_service_name }}" NC_DIR="/var/www/html/nextcloud" DATA_DIR=$(sudo -u "${WEBSERVER_USER}" php "${NC_DIR}/occ" config:system:get datadirectory) @@ -84,7 +84,7 @@ else echo 'skipping.' fi -{% if ansible_os_family == "RedHat" %} +{% if ansible_facts["os_family"] == "RedHat" %} echo echo 'setsebool httpd_unified on' echo '--------------------------' @@ -140,7 +140,7 @@ else echo 'skipping.' fi -{% if ansible_os_family == "RedHat" %} +{% if ansible_facts["os_family"] == "RedHat" %} echo echo 'setsebool httpd_unified off' echo '---------------------------' @@ -186,7 +186,7 @@ else echo 'skipping.' fi -{% if ansible_os_family == "RedHat" %} +{% if ansible_facts["os_family"] == "RedHat" %} echo echo "restorecon" echo '----------' diff --git a/roles/nextcloud/vars/RedHat.yml b/roles/nextcloud/vars/RedHat.yml new file mode 100644 index 000000000..d8f8c5311 --- /dev/null +++ b/roles/nextcloud/vars/RedHat.yml @@ -0,0 +1,8 @@ +__nextcloud__packages: + - 'bzip2' + - 'jq' + - 'openldap-clients' + - 'samba-client' +__nextcloud__php_fpm_service_name: 'php-fpm' +__nextcloud__webserver_group: 'apache' +__nextcloud__webserver_user: 'apache' From 4b0838eb05560e4cd0bf8634eb5b02df36963aba Mon Sep 17 00:00:00 2001 From: Danyal Berchtold Date: Wed, 20 May 2026 10:29:43 +0200 Subject: [PATCH 2/5] refactor(roles/nextcloud): add argument_specs and align internal var name Add meta/argument_specs.yml declaring all user-facing variables so Ansible validates required variables (nextcloud__fqdn, nextcloud__users) and types at role entry, including the new nextcloud__webserver_user, nextcloud__webserver_group and nextcloud__php_fpm_service_name. Rename the internal __nextcloud__packages to __nextcloud__required_packages for consistency with the example role's __example__required_packages. --- CHANGELOG.md | 1 + roles/nextcloud/meta/argument_specs.yml | 209 ++++++++++++++++++++++++ roles/nextcloud/tasks/main.yml | 2 +- roles/nextcloud/vars/RedHat.yml | 2 +- 4 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 roles/nextcloud/meta/argument_specs.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bb2c2103..e48575e50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +* **role:nextcloud**: Add `meta/argument_specs.yml` declaring all user-facing variables (including the new `nextcloud__webserver_user`, `nextcloud__webserver_group` and `nextcloud__php_fpm_service_name`), so Ansible validates required variables and types at role entry. * **role:tmux**: Installs tmux and deploys a system-wide `/etc/tmux.conf` with sensible defaults, such as a larger scrollback buffer and mouse support. Selections are copied to the local clipboard over SSH via OSC 52 (where the terminal emulator supports it), and `prefix + P` dumps a pane's whole scrollback buffer to a file. * **role:graylog_server**: Make more HTTP, Elasticsearch, processing/output buffer and message journal settings configurable via `graylog_server__http_external_uri`, `graylog_server__http_enable_cors`, `graylog_server__elasticsearch_max_total_connections`, `graylog_server__elasticsearch_max_total_connections_per_route`, `graylog_server__output_batch_size`, `graylog_server__processbuffer_processors`, `graylog_server__outputbuffer_processors`, `graylog_server__ring_size`, `graylog_server__inputbuffer_ring_size`, `graylog_server__message_journal_max_age` and `graylog_server__message_journal_max_size`. * **role:mariadb_server**: Make `aria_pagecache_buffer_size`, `key_buffer_size` and `sort_buffer_size` configurable via the corresponding `mariadb_server__cnf_*` variables. diff --git a/roles/nextcloud/meta/argument_specs.yml b/roles/nextcloud/meta/argument_specs.yml new file mode 100644 index 000000000..03fb1d27c --- /dev/null +++ b/roles/nextcloud/meta/argument_specs.yml @@ -0,0 +1,209 @@ +argument_specs: + main: + options: + + nextcloud__app_configs__dependent_var: + type: 'list' + elements: 'dict' + required: false + default: [] + description: 'Key-value pairs for configuring apps. Dependent-role injection.' + + nextcloud__app_configs__group_var: + type: 'list' + elements: 'dict' + required: false + default: [] + description: 'Key-value pairs for configuring apps. Group-level override.' + + nextcloud__app_configs__host_var: + type: 'list' + elements: 'dict' + required: false + default: [] + description: 'Key-value pairs for configuring apps. Host-level override.' + + nextcloud__apps__dependent_var: + type: 'list' + elements: 'dict' + required: false + default: [] + description: 'Nextcloud apps to install. Dependent-role injection.' + + nextcloud__apps__group_var: + type: 'list' + elements: 'dict' + required: false + default: [] + description: 'Nextcloud apps to install. Group-level override.' + + nextcloud__apps__host_var: + type: 'list' + elements: 'dict' + required: false + default: [] + description: 'Nextcloud apps to install. Host-level override.' + + nextcloud__database_host: + type: 'str' + required: false + default: 'localhost' + description: 'Host where MariaDB is located.' + + nextcloud__database_name: + type: 'str' + required: false + default: 'nextcloud' + description: 'Name of the Nextcloud database in MariaDB.' + + nextcloud__datadir: + type: 'str' + required: false + default: '/data' + description: 'Where to store the user files.' + + nextcloud__fqdn: + type: 'str' + required: true + description: 'The FQDN of the Nextcloud instance.' + + nextcloud__icinga2_api_url: + type: 'str' + required: false + description: 'The URL of the Icinga2 API used to set/remove a downtime in the nextcloud-update script.' + + nextcloud__icinga2_api_user_login: + type: 'dict' + required: false + description: 'The Icinga2 API user used to set/remove a downtime in the nextcloud-update script.' + + nextcloud__icinga2_hostname: + type: 'str' + required: false + description: 'The hostname of the Icinga2 host on which the downtime should be set.' + + nextcloud__mariadb_login: + type: 'dict' + required: false + description: 'The database administrator account. The Nextcloud setup will create its own database account.' + + nextcloud__on_calendar_app_update: + type: 'str' + required: false + description: 'Time to update the Nextcloud apps. See systemd.time(7) for the format.' + + nextcloud__on_calendar_jobs: + type: 'str' + required: false + default: '*:0/5' + description: 'Run interval of OCC background jobs. See systemd.time(7) for the format.' + + nextcloud__on_calendar_scan_files: + type: 'str' + required: false + default: '*:50:15' + description: 'Run interval of rescanning the filesystem. See systemd.time(7) for the format.' + + nextcloud__php_fpm_service_name: + type: 'str' + required: false + description: 'Name of the PHP-FPM systemd service that the role and the nextcloud-update script restart. OS-specific default from vars/.' + + nextcloud__skip_apps: + type: 'bool' + required: false + default: false + description: 'Completely skips the management of Nextcloud apps.' + + nextcloud__skip_notify_push: + type: 'bool' + required: false + default: false + description: 'Skips the configuration of notify_push.' + + nextcloud__storage_backend_s3: + type: 'dict' + required: false + description: 'S3 storage backend. If omitted, local storage is used.' + + nextcloud__storage_backend_swift: + type: 'dict' + required: false + description: 'Swift storage backend. If omitted, local storage is used.' + + nextcloud__sysconfig__dependent_var: + type: 'list' + elements: 'dict' + required: false + default: [] + description: 'Nextcloud system config settings. Dependent-role injection.' + + nextcloud__sysconfig__group_var: + type: 'list' + elements: 'dict' + required: false + default: [] + description: 'Nextcloud system config settings. Group-level override.' + + nextcloud__sysconfig__host_var: + type: 'list' + elements: 'dict' + required: false + default: [] + description: 'Nextcloud system config settings. Host-level override.' + + nextcloud__timer_app_update_enabled: + type: 'bool' + required: false + default: false + description: 'Enables/disables the systemd timer for updating apps.' + + nextcloud__timer_jobs_enabled: + type: 'bool' + required: false + default: true + description: 'Enables/disables the systemd timer for running OCC background jobs.' + + nextcloud__timer_ldap_show_remnants_enabled: + type: 'bool' + required: false + default: true + description: 'Enables/disables the systemd timer for mailing LDAP remnants once a month.' + + nextcloud__timer_scan_files_enabled: + type: 'bool' + required: false + default: true + description: 'Enables/disables the systemd timer for re-scanning the Nextcloud files.' + + nextcloud__users: + type: 'list' + elements: 'dict' + required: true + description: 'User accounts to create. The first user has to be the primary administrator account.' + + nextcloud__version: + type: 'str' + required: false + default: 'latest' + description: "Which version to install. One of 'latest', 'latest-XX' or 'nextcloud-XX.X.XX'." + + nextcloud__vhost_virtualhost_ip: + type: 'str' + required: false + description: 'Used within the directive.' + + nextcloud__vhost_virtualhost_port: + type: 'int' + required: false + description: 'Used within the directive.' + + nextcloud__webserver_group: + type: 'str' + required: false + description: 'Group of the web server, used for file ownership. OS-specific default from vars/.' + + nextcloud__webserver_user: + type: 'str' + required: false + description: 'User of the web server, used for file ownership, occ commands and as the User= of the deployed systemd services. OS-specific default from vars/.' diff --git a/roles/nextcloud/tasks/main.yml b/roles/nextcloud/tasks/main.yml index b03756433..330d551cf 100644 --- a/roles/nextcloud/tasks/main.yml +++ b/roles/nextcloud/tasks/main.yml @@ -13,7 +13,7 @@ - name: 'Install required packages' ansible.builtin.package: - name: '{{ __nextcloud__packages }}' + name: '{{ __nextcloud__required_packages }}' state: 'present' - name: 'wget https://download.nextcloud.com/server/releases/{{ nextcloud__version }}.tar.bz2' diff --git a/roles/nextcloud/vars/RedHat.yml b/roles/nextcloud/vars/RedHat.yml index d8f8c5311..3612dbb94 100644 --- a/roles/nextcloud/vars/RedHat.yml +++ b/roles/nextcloud/vars/RedHat.yml @@ -1,4 +1,4 @@ -__nextcloud__packages: +__nextcloud__required_packages: - 'bzip2' - 'jq' - 'openldap-clients' From ef7cf3c5cdff5f16405ae00c7e758900e536424b Mon Sep 17 00:00:00 2001 From: Danyal Berchtold Date: Thu, 4 Jun 2026 17:09:27 +0200 Subject: [PATCH 3/5] refactor(roles/nextcloud): source OS-specific names from shared and php vars, select php modules via platform_select --- CHANGELOG.md | 4 +- roles/nextcloud/README.md | 16 +------ roles/nextcloud/defaults/main.yml | 48 ++++--------------- roles/nextcloud/meta/argument_specs.yml | 12 +---- roles/nextcloud/tasks/create-user.yml | 4 +- roles/nextcloud/tasks/main.yml | 42 ++++++++-------- .../system/nextcloud-app-update.service.j2 | 2 +- .../systemd/system/nextcloud-jobs.service.j2 | 2 +- .../nextcloud-ldap-show-remnants.service.j2 | 2 +- .../system/nextcloud-scan-files.service.j2 | 2 +- .../usr/local/bin/nextcloud-update.j2 | 4 +- roles/nextcloud/vars/RedHat.yml | 3 -- roles/nextcloud/vars/main.yml | 39 +++++++++++++++ 13 files changed, 81 insertions(+), 99 deletions(-) create mode 100644 roles/nextcloud/vars/main.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index e48575e50..b358f3543 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -* **role:nextcloud**: Add `meta/argument_specs.yml` declaring all user-facing variables (including the new `nextcloud__webserver_user`, `nextcloud__webserver_group` and `nextcloud__php_fpm_service_name`), so Ansible validates required variables and types at role entry. +* **role:nextcloud**: Add `meta/argument_specs.yml` declaring all user-facing variables (including the new `nextcloud__php_fpm_service_name`), so Ansible validates required variables and types at role entry. * **role:tmux**: Installs tmux and deploys a system-wide `/etc/tmux.conf` with sensible defaults, such as a larger scrollback buffer and mouse support. Selections are copied to the local clipboard over SSH via OSC 52 (where the terminal emulator supports it), and `prefix + P` dumps a pane's whole scrollback buffer to a file. * **role:graylog_server**: Make more HTTP, Elasticsearch, processing/output buffer and message journal settings configurable via `graylog_server__http_external_uri`, `graylog_server__http_enable_cors`, `graylog_server__elasticsearch_max_total_connections`, `graylog_server__elasticsearch_max_total_connections_per_route`, `graylog_server__output_batch_size`, `graylog_server__processbuffer_processors`, `graylog_server__outputbuffer_processors`, `graylog_server__ring_size`, `graylog_server__inputbuffer_ring_size`, `graylog_server__message_journal_max_age` and `graylog_server__message_journal_max_size`. * **role:mariadb_server**: Make `aria_pagecache_buffer_size`, `key_buffer_size` and `sort_buffer_size` configurable via the corresponding `mariadb_server__cnf_*` variables. @@ -61,7 +61,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -* **role:nextcloud**: Lay the groundwork for non-RHEL platforms (Debian/Ubuntu) by removing hardcoded RHEL-specific names from the role logic. The web server user/group (previously `apache`), the PHP-FPM service name (previously `php-fpm`) and the base package list (previously the RHEL names `openldap-clients`/`samba-client`) are now sourced from OS-specific `vars/` via `shared/platform-variables.yml`. The web server user/group and PHP-FPM service name are exposed as the overridable variables `nextcloud__webserver_user`, `nextcloud__webserver_group` and `nextcloud__php_fpm_service_name` and are now used throughout the tasks, the deployed systemd services and the notify_push unit (not just the `/usr/local/bin/nextcloud-update` script). The SELinux `restorecon` tasks are now guarded by `ansible_facts["selinux"]["status"] != "disabled"`, and the SELinux blocks in the update script use `ansible_facts["os_family"]` instead of `ansible_os_family`. Only `vars/RedHat.yml` ships, so the role still runs on RHEL only (see `COMPATIBILITY.md`); adding a tested `vars/Debian.yml` is all that is needed to extend support. +* **role:nextcloud**: Lay the groundwork for non-RHEL platforms (Debian/Ubuntu) by removing hardcoded RHEL-specific names from the role logic, sourcing each OS-specific value through the mechanism that fits its scope. The web server user/group (previously the hardcoded `apache`) now come directly from the LFOps-wide shared values `__shared__apache_httpd_user`/`__shared__apache_httpd_group` (apache on RedHat, www-data on Debian, wwwrun/www on Suse) throughout the tasks, templates and systemd units, rather than through a redundant role-local variable. The base package list (previously the RHEL names `openldap-clients`/`samba-client`) is sourced from the role-local `vars/RedHat.yml` via `shared/platform-variables.yml`, while the PHP-FPM service name (`nextcloud__php_fpm_service_name`) now defaults to the `php` role's own `php__fpm_service_name` instead of a duplicated role-local value, so the Debian `php-fpm` naming comes for free. The PHP module list consumed by the earlier-running `php` role (`nextcloud__php__modules__dependent_var`) is now an OS-keyed dict in `vars/main.yml` selected with the `linuxfabrik.lfops.platform_select` filter, since `vars/.yml` loads too late for that cross-role `__dependent_var` hand-off. These variables are now used throughout the tasks, the deployed systemd services and the notify_push unit (not just the `/usr/local/bin/nextcloud-update` script). The SELinux `restorecon` tasks are now guarded by `ansible_facts["selinux"]["status"] != "disabled"`, and the SELinux blocks in the update script use `ansible_facts["os_family"]` instead of `ansible_os_family`. Only RHEL package names ship so far, so the role still runs on RHEL only (see `COMPATIBILITY.md`); adding a tested `vars/Debian.yml` plus the matching `platform_select` keys is all that is needed to extend support. * **playbooks**: Enable the CRB repository on Rocky 10 too, not just Rocky 9. Previously Rocky 10 hosts silently skipped this step, which could leave dependencies such as `python3-virtualenv` uninstallable. * **role:grafana**: Apply the systemd/chkconfig workaround on RHEL 10 as well, not just RHEL 9. * **role:tools**: Install the German locale package (`glibc-langpack-de`) on RHEL 10 as well. diff --git a/roles/nextcloud/README.md b/roles/nextcloud/README.md index c73f8dee2..28b663a9a 100644 --- a/roles/nextcloud/README.md +++ b/roles/nextcloud/README.md @@ -239,9 +239,9 @@ nextcloud__users: `nextcloud__php_fpm_service_name` -* Name of the PHP-FPM systemd service that the role restarts (and that the `/usr/local/bin/nextcloud-update` script restarts). Defaults to the OS-specific value (`php-fpm` on RHEL, `php-fpm` on Debian). +* Name of the PHP-FPM systemd service that the role restarts (and that the `/usr/local/bin/nextcloud-update` script restarts). Defaults to the `php` role's `php__fpm_service_name` (`php-fpm` on RHEL, `php-fpm` on Debian). * Type: String. -* Default: Have a look at [vars/](https://github.com/Linuxfabrik/lfops/blob/main/roles/nextcloud/vars/) +* Default: `{{ php__fpm_service_name }}` `nextcloud__skip_apps` @@ -338,18 +338,6 @@ nextcloud__users: * Type: Number. * Default: `80` -`nextcloud__webserver_group` - -* Group of the web server, used for file ownership of the Nextcloud installation. Defaults to the OS-specific value (`apache` on RHEL, `www-data` on Debian). -* Type: String. -* Default: Have a look at [vars/](https://github.com/Linuxfabrik/lfops/blob/main/roles/nextcloud/vars/) - -`nextcloud__webserver_user` - -* User of the web server, used for file ownership, to run the `occ` commands and as the `User=` of the deployed systemd services. Defaults to the OS-specific value (`apache` on RHEL, `www-data` on Debian). -* Type: String. -* Default: Have a look at [vars/](https://github.com/Linuxfabrik/lfops/blob/main/roles/nextcloud/vars/) - Example: ```yaml # optional diff --git a/roles/nextcloud/defaults/main.yml b/roles/nextcloud/defaults/main.yml index 67b539830..32a2ecdbb 100644 --- a/roles/nextcloud/defaults/main.yml +++ b/roles/nextcloud/defaults/main.yml @@ -178,7 +178,8 @@ nextcloud__on_calendar_app_update: '06,18,23:{{ 59 | random(seed=inventory_hostn nextcloud__on_calendar_jobs: '*:0/5' # every 5 minutes nextcloud__on_calendar_scan_files: '*:50:15' # every hour at hh:50:15 -nextcloud__php_fpm_service_name: '{{ __nextcloud__php_fpm_service_name }}' +# The php role owns the FPM service name (php-fpm on RedHat, php-fpm on Debian); source it from there instead of duplicating it per OS. +nextcloud__php_fpm_service_name: '{{ php__fpm_service_name }}' nextcloud__skip_apps: false nextcloud__skip_notify_push: false @@ -313,9 +314,6 @@ nextcloud__timer_scan_files_enabled: true # 'latest', 'latest-XX' or 'nextcloud-XX.X.XX' nextcloud__version: 'latest' -nextcloud__webserver_group: '{{ __nextcloud__webserver_group }}' -nextcloud__webserver_user: '{{ __nextcloud__webserver_user }}' - # ----------------------------------------------------------------------------- nextcloud__apache_httpd__mods__dependent_var: @@ -477,41 +475,11 @@ nextcloud__php__ini_memory_limit__dependent_var: '1024M' nextcloud__php__ini_opcache_interned_strings_buffer__dependent_var: '20' nextcloud__php__ini_post_max_size__dependent_var: '16M' nextcloud__php__ini_upload_max_filesize__dependent_var: '10000M' -nextcloud__php__modules__dependent_var: - - name: 'php-bcmath' - state: 'present' - - name: 'php-gd' - state: 'present' - - name: 'php-gmp' - state: 'present' - - name: 'php-imap' - state: 'present' - - name: 'php-imagick' - state: 'present' - - name: 'php-intl' - state: 'present' - - name: 'php-json' - state: 'present' - - name: 'php-ldap' - state: 'present' - - name: 'php-mbstring' - state: 'present' - - name: 'php-memcached' - state: 'present' - - name: 'php-mysqlnd' - state: 'present' - - name: 'php-opcache' - state: 'present' - - name: 'php-pecl-apcu' - state: 'present' - - name: 'php-process' # posix module for oc - state: 'present' - - name: 'php-redis' - state: 'present' - - name: 'php-smbclient' - state: 'present' - - name: 'php-zip' - state: 'present' +# OS-specific package names live in vars/main.yml (see platform_select). The php role runs earlier in the play and consumes this via the __dependent_var pattern. +nextcloud__php__modules__dependent_var: '{{ + __nextcloud__php__modules__dependent_var + | linuxfabrik.lfops.platform_select(ansible_facts) + }}' nextcloud__selinux__booleans__dependent_var: - key: 'httpd_can_network_connect' @@ -552,6 +520,6 @@ nextcloud__systemd_unit__services__dependent_var: Environment=PORT=7867 ExecStartPre=-/bin/chcon --type bin_t /var/www/html/nextcloud/apps/notify_push/bin/x86_64/notify_push ExecStart=/var/www/html/nextcloud/apps/notify_push/bin/x86_64/notify_push /var/www/html/nextcloud/config/config.php - User={{ nextcloud__webserver_user }} + User={{ __shared__apache_httpd_user }} enabled: true state: 'present' diff --git a/roles/nextcloud/meta/argument_specs.yml b/roles/nextcloud/meta/argument_specs.yml index 03fb1d27c..0e6961045 100644 --- a/roles/nextcloud/meta/argument_specs.yml +++ b/roles/nextcloud/meta/argument_specs.yml @@ -107,7 +107,7 @@ argument_specs: nextcloud__php_fpm_service_name: type: 'str' required: false - description: 'Name of the PHP-FPM systemd service that the role and the nextcloud-update script restart. OS-specific default from vars/.' + description: "Name of the PHP-FPM systemd service that the role and the nextcloud-update script restart. Defaults to the php role's php__fpm_service_name (php-fpm on RedHat, php-fpm on Debian)." nextcloud__skip_apps: type: 'bool' @@ -197,13 +197,3 @@ argument_specs: type: 'int' required: false description: 'Used within the directive.' - - nextcloud__webserver_group: - type: 'str' - required: false - description: 'Group of the web server, used for file ownership. OS-specific default from vars/.' - - nextcloud__webserver_user: - type: 'str' - required: false - description: 'User of the web server, used for file ownership, occ commands and as the User= of the deployed systemd services. OS-specific default from vars/.' diff --git a/roles/nextcloud/tasks/create-user.yml b/roles/nextcloud/tasks/create-user.yml index 4f58d50ab..a0f288a64 100644 --- a/roles/nextcloud/tasks/create-user.yml +++ b/roles/nextcloud/tasks/create-user.yml @@ -1,7 +1,7 @@ - name: 'Create Nextcloud user {{ ncuser["username"] }}' ansible.builtin.shell: >- export OC_PASS={{ ncuser["password"] | quote }}; - sudo -E -u {{ nextcloud__webserver_user }} php occ user:add + sudo -E -u {{ __shared__apache_httpd_user }} php occ user:add --password-from-env --group {{ ncuser["group"] | d('""') | quote }} {{ ncuser["username"] | quote }} @@ -15,7 +15,7 @@ - name: 'Update Nextcloud settings for user {{ ncuser["username"] }}' ansible.builtin.command: | - sudo -u {{ nextcloud__webserver_user }} php occ user:setting {{ ncuser["username"] }} {{ item }} + sudo -u {{ __shared__apache_httpd_user }} php occ user:setting {{ ncuser["username"] }} {{ item }} args: chdir: '/var/www/html/nextcloud/' # changed_when: there is no easy way to check for changes diff --git a/roles/nextcloud/tasks/main.yml b/roles/nextcloud/tasks/main.yml index 330d551cf..80a173fc8 100644 --- a/roles/nextcloud/tasks/main.yml +++ b/roles/nextcloud/tasks/main.yml @@ -33,25 +33,25 @@ backup: true src: 'var/www/html/nextcloud/config/objectstore.config.php.j2' dest: '/var/www/html/nextcloud/config/objectstore.config.php' - owner: '{{ nextcloud__webserver_user }}' - group: '{{ nextcloud__webserver_group }}' + owner: '{{ __shared__apache_httpd_user }}' + group: '{{ __shared__apache_httpd_group }}' mode: 0o644 when: '(nextcloud__storage_backend_s3["bucket"] is defined and nextcloud__storage_backend_s3["bucket"] | length > 0) or (nextcloud__storage_backend_swift["bucket"] is defined and nextcloud__storage_backend_swift["bucket"] | length > 0)' - - name: 'chown -R {{ nextcloud__webserver_user }}:{{ nextcloud__webserver_group }} /var/www/html/nextcloud' + - name: 'chown -R {{ __shared__apache_httpd_user }}:{{ __shared__apache_httpd_group }} /var/www/html/nextcloud' ansible.builtin.file: path: '/var/www/html/nextcloud' - owner: '{{ nextcloud__webserver_user }}' - group: '{{ nextcloud__webserver_group }}' + owner: '{{ __shared__apache_httpd_user }}' + group: '{{ __shared__apache_httpd_group }}' recurse: true - - name: 'mkdir path/to/data; chown -R {{ nextcloud__webserver_user }}:{{ nextcloud__webserver_group }} path/to/data; chmod 0750 -R path/to/data' + - name: 'mkdir path/to/data; chown -R {{ __shared__apache_httpd_user }}:{{ __shared__apache_httpd_group }} path/to/data; chmod 0750 -R path/to/data' ansible.builtin.file: path: '{{ item }}' state: 'directory' - owner: '{{ nextcloud__webserver_user }}' - group: '{{ nextcloud__webserver_group }}' + owner: '{{ __shared__apache_httpd_user }}' + group: '{{ __shared__apache_httpd_group }}' mode: 0o750 loop: - '/data' @@ -85,7 +85,7 @@ chdir: '/var/www/html/nextcloud/' creates: '/var/www/html/nextcloud/config/config.php' become: true - become_user: '{{ nextcloud__webserver_user }}' + become_user: '{{ __shared__apache_httpd_user }}' - name: 'Convert some database columns to big int' ansible.builtin.command: | @@ -93,7 +93,7 @@ args: chdir: '/var/www/html/nextcloud/' become: true - become_user: '{{ nextcloud__webserver_user }}' + become_user: '{{ __shared__apache_httpd_user }}' register: 'nextcloud__convert_filecache_bigint_result' changed_when: '"All tables already up to date" not in nextcloud__convert_filecache_bigint_result["stdout"]' # changed_when: there is no easy way to check for changes @@ -107,7 +107,7 @@ - name: 'Get Nextcloud config list' ansible.builtin.command: 'php /var/www/html/nextcloud/occ --no-interaction --output=json config:list --private' become: true - become_user: '{{ nextcloud__webserver_user }}' + become_user: '{{ __shared__apache_httpd_user }}' changed_when: false check_mode: false register: '__nextcloud__config_list_result' @@ -120,7 +120,7 @@ state: '{{ item["state"] | d("present") }}' installed_config_json: '{{ __nextcloud__config_list_result["stdout"] | from_json }}' become: true - become_user: '{{ nextcloud__webserver_user }}' + become_user: '{{ __shared__apache_httpd_user }}' loop: '{{ nextcloud__sysconfig__combined_var }}' # do this straight after the installation to get NC up and running @@ -140,7 +140,7 @@ - name: 'Get Nextcloud app list' ansible.builtin.command: 'php /var/www/html/nextcloud/occ --no-interaction --output=json app:list' become: true - become_user: '{{ nextcloud__webserver_user }}' + become_user: '{{ __shared__apache_httpd_user }}' changed_when: false check_mode: false register: '__nextcloud__app_list_result' @@ -152,13 +152,13 @@ force: '{{ item["force"] | d(false) }}' installed_apps_json: '{{ __nextcloud__app_list_result["stdout"] | from_json }}' become: true - become_user: '{{ nextcloud__webserver_user }}' + become_user: '{{ __shared__apache_httpd_user }}' loop: '{{ nextcloud__apps__combined_var }}' - name: 'Get Nextcloud config list' ansible.builtin.command: 'php /var/www/html/nextcloud/occ --no-interaction --output=json config:list --private' become: true - become_user: '{{ nextcloud__webserver_user }}' + become_user: '{{ __shared__apache_httpd_user }}' changed_when: false check_mode: false register: '__nextcloud__config_list_result' @@ -172,7 +172,7 @@ state: '{{ item["state"] | d("present") }}' installed_config_json: '{{ __nextcloud__config_list_result["stdout"] | from_json }}' become: true - become_user: '{{ nextcloud__webserver_user }}' + become_user: '{{ __shared__apache_httpd_user }}' loop: '{{ nextcloud__app_configs__combined_var }}' - name: 'restart {{ nextcloud__php_fpm_service_name }}' @@ -207,7 +207,7 @@ args: chdir: '/var/www/html/nextcloud/' become: true - become_user: '{{ nextcloud__webserver_user }}' + become_user: '{{ __shared__apache_httpd_user }}' when: - 'not nextcloud__skip_notify_push' @@ -232,11 +232,11 @@ - block: - - name: 'chown -R {{ nextcloud__webserver_user }}:{{ nextcloud__webserver_group }} /var/www/html/nextcloud' + - name: 'chown -R {{ __shared__apache_httpd_user }}:{{ __shared__apache_httpd_group }} /var/www/html/nextcloud' ansible.builtin.file: path: '/var/www/html/nextcloud' - owner: '{{ nextcloud__webserver_user }}' - group: '{{ nextcloud__webserver_group }}' + owner: '{{ __shared__apache_httpd_user }}' + group: '{{ __shared__apache_httpd_group }}' recurse: true tags: @@ -271,7 +271,7 @@ args: chdir: '/var/www/html/nextcloud/' become: true - become_user: '{{ nextcloud__webserver_user }}' + become_user: '{{ __shared__apache_httpd_user }}' # changed_when: there is no easy way to check for changes - name: 'Deploy /etc/systemd/system/nextcloud-app-update.service' diff --git a/roles/nextcloud/templates/etc/systemd/system/nextcloud-app-update.service.j2 b/roles/nextcloud/templates/etc/systemd/system/nextcloud-app-update.service.j2 index a5f42bd4e..eea108ae0 100644 --- a/roles/nextcloud/templates/etc/systemd/system/nextcloud-app-update.service.j2 +++ b/roles/nextcloud/templates/etc/systemd/system/nextcloud-app-update.service.j2 @@ -8,4 +8,4 @@ Description=Nextcloud App Update Service ExecStart=/usr/bin/php occ app:update --all --no-interaction --quiet WorkingDirectory=/var/www/html/nextcloud Type=oneshot -User={{ nextcloud__webserver_user }} +User={{ __shared__apache_httpd_user }} diff --git a/roles/nextcloud/templates/etc/systemd/system/nextcloud-jobs.service.j2 b/roles/nextcloud/templates/etc/systemd/system/nextcloud-jobs.service.j2 index 4a8423ddd..15b2d4773 100644 --- a/roles/nextcloud/templates/etc/systemd/system/nextcloud-jobs.service.j2 +++ b/roles/nextcloud/templates/etc/systemd/system/nextcloud-jobs.service.j2 @@ -7,6 +7,6 @@ Description=Nextcloud Background Jobs Service [Service] ExecStart=/usr/bin/php --file /var/www/html/nextcloud/cron.php Type=oneshot -User={{ nextcloud__webserver_user }} +User={{ __shared__apache_httpd_user }} KillMode=process TimeoutStartSec=10m diff --git a/roles/nextcloud/templates/etc/systemd/system/nextcloud-ldap-show-remnants.service.j2 b/roles/nextcloud/templates/etc/systemd/system/nextcloud-ldap-show-remnants.service.j2 index 3418eeeba..4eb81d05c 100644 --- a/roles/nextcloud/templates/etc/systemd/system/nextcloud-ldap-show-remnants.service.j2 +++ b/roles/nextcloud/templates/etc/systemd/system/nextcloud-ldap-show-remnants.service.j2 @@ -8,4 +8,4 @@ Description=Nextcloud LDAP Show Remnants Service # need the help of /bin/sh here, since systemd units don't understand pipes directly ExecStart=/usr/local/bin/nextcloud-ldap-show-remnants Type=oneshot -User={{ nextcloud__webserver_user }} +User={{ __shared__apache_httpd_user }} diff --git a/roles/nextcloud/templates/etc/systemd/system/nextcloud-scan-files.service.j2 b/roles/nextcloud/templates/etc/systemd/system/nextcloud-scan-files.service.j2 index c45fad609..cc06b147b 100644 --- a/roles/nextcloud/templates/etc/systemd/system/nextcloud-scan-files.service.j2 +++ b/roles/nextcloud/templates/etc/systemd/system/nextcloud-scan-files.service.j2 @@ -8,4 +8,4 @@ Description=Nextcloud Scan Files Service ExecStart=/usr/bin/nice --adjustment 19 /usr/bin/php occ files:scan --all --unscanned WorkingDirectory=/var/www/html/nextcloud Type=oneshot -User={{ nextcloud__webserver_user }} +User={{ __shared__apache_httpd_user }} diff --git a/roles/nextcloud/templates/usr/local/bin/nextcloud-update.j2 b/roles/nextcloud/templates/usr/local/bin/nextcloud-update.j2 index c5ad20d7a..fd73932ae 100644 --- a/roles/nextcloud/templates/usr/local/bin/nextcloud-update.j2 +++ b/roles/nextcloud/templates/usr/local/bin/nextcloud-update.j2 @@ -11,8 +11,8 @@ error_handler() { } trap 'error_handler "${LINENO}"' ERR -WEBSERVER_USER="{{ nextcloud__webserver_user }}" -WEBSERVER_GROUP="{{ nextcloud__webserver_group }}" +WEBSERVER_USER="{{ __shared__apache_httpd_user }}" +WEBSERVER_GROUP="{{ __shared__apache_httpd_group }}" PHP_SERVICE_NAME="{{ nextcloud__php_fpm_service_name }}" NC_DIR="/var/www/html/nextcloud" diff --git a/roles/nextcloud/vars/RedHat.yml b/roles/nextcloud/vars/RedHat.yml index 3612dbb94..cef93f116 100644 --- a/roles/nextcloud/vars/RedHat.yml +++ b/roles/nextcloud/vars/RedHat.yml @@ -3,6 +3,3 @@ __nextcloud__required_packages: - 'jq' - 'openldap-clients' - 'samba-client' -__nextcloud__php_fpm_service_name: 'php-fpm' -__nextcloud__webserver_group: 'apache' -__nextcloud__webserver_user: 'apache' diff --git a/roles/nextcloud/vars/main.yml b/roles/nextcloud/vars/main.yml new file mode 100644 index 000000000..2d68653bb --- /dev/null +++ b/roles/nextcloud/vars/main.yml @@ -0,0 +1,39 @@ +# OS-specific values consumed by a *different* role that runs *earlier* in the same play (the `__dependent_var` pattern). vars/.yml would load too late for an earlier consumer, but vars/main.yml is auto-loaded at play parse and is visible to every role in the play. The public variables in defaults/main.yml select from these dicts with the linuxfabrik.lfops.platform_select filter; to extend platform support, add a Debian / Suse key here. + +# PHP modules installed by the linuxfabrik.lfops.php role via nextcloud__php__modules__dependent_var. +__nextcloud__php__modules__dependent_var: + RedHat: + - name: 'php-bcmath' + state: 'present' + - name: 'php-gd' + state: 'present' + - name: 'php-gmp' + state: 'present' + - name: 'php-imap' + state: 'present' + - name: 'php-imagick' + state: 'present' + - name: 'php-intl' + state: 'present' + - name: 'php-json' + state: 'present' + - name: 'php-ldap' + state: 'present' + - name: 'php-mbstring' + state: 'present' + - name: 'php-memcached' + state: 'present' + - name: 'php-mysqlnd' + state: 'present' + - name: 'php-opcache' + state: 'present' + - name: 'php-pecl-apcu' + state: 'present' + - name: 'php-process' # posix module for oc + state: 'present' + - name: 'php-redis' + state: 'present' + - name: 'php-smbclient' + state: 'present' + - name: 'php-zip' + state: 'present' From 6017ba571d69c183dcd49e691e158122ef0b1fd8 Mon Sep 17 00:00:00 2001 From: Danyal Berchtold Date: Mon, 8 Jun 2026 10:16:25 +0200 Subject: [PATCH 4/5] fix(roles/nextcloud): source ldap-show-remnants recipients from nextcloud__mailto_root__to The nextcloud-ldap-show-remnants script referenced setup_basic__skip_mailto_root, a setup_basic playbook variable that is undefined when the role runs from setup_nextcloud (e.g. with --tags nextcloud:cron), aborting the nextcloud:cron deploy. Add a namespaced nextcloud__mailto_root__to role variable (defaulting to the global mailto_root__to) and gate the template on it: mail the report when recipients are set, print to stdout otherwise. Declared in argument_specs and documented in the README. --- CHANGELOG.md | 1 + roles/nextcloud/README.md | 6 ++++++ roles/nextcloud/defaults/main.yml | 3 ++- roles/nextcloud/meta/argument_specs.yml | 6 ++++++ .../usr/local/bin/nextcloud-ldap-show-remnants.j2 | 13 ++++++------- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d625c7117..2b02be71c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -146,6 +146,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +* **role:nextcloud**: The `nextcloud-ldap-show-remnants` script no longer aborts the `nextcloud:cron` deploy with `'setup_basic__skip_mailto_root' is undefined` when the role runs outside the `setup_basic` playbook (e.g. via `--tags nextcloud:cron` in `setup_nextcloud`). The report recipients now come from the new role variable `nextcloud__mailto_root__to` (defaulting to the global `mailto_root__to`); the report is mailed when recipients are set and printed to stdout otherwise. * **role:php**: php-fpm workers now run with a defined `PATH`. Previously the worker environment was cleared, leaving `getenv("PATH")` empty, which broke PHP code that shells out to system binaries and tripped Nextcloud's "PHP getenv" setup warning. * **role:redis**: The Redis configuration file is no longer world-readable. It is now deployed as `root:redis` with mode `0640`, so its contents (e.g. a configured password) can no longer be read by other local users. * **role:acme_sh**: No longer reinstalls every certificate and reloads the web server on every run. Certificates are only reinstalled when they were just (re)issued or when the installed file is missing, so repeated runs are idempotent. diff --git a/roles/nextcloud/README.md b/roles/nextcloud/README.md index eb991d536..7c63cfa05 100644 --- a/roles/nextcloud/README.md +++ b/roles/nextcloud/README.md @@ -219,6 +219,12 @@ nextcloud__users: * Type: String. * Default: `'{{ ansible_facts["nodename"] }}'` +`nextcloud__mailto_root__to` + +* Recipients of the monthly `ldap:show-remnants` report (users removed from LDAP that still have remnants in Nextcloud) sent by `/usr/local/bin/nextcloud-ldap-show-remnants`. Defaults to the global `mailto_root__to`; when empty the report is printed to stdout instead of being mailed. +* Type: List. +* Default: `'{{ mailto_root__to | d([]) }}'` + `nextcloud__mariadb_login` * The user account for the database administrator. The Nextcloud setup will create its own database account. diff --git a/roles/nextcloud/defaults/main.yml b/roles/nextcloud/defaults/main.yml index ebc560cca..b58f94b2f 100644 --- a/roles/nextcloud/defaults/main.yml +++ b/roles/nextcloud/defaults/main.yml @@ -172,13 +172,14 @@ nextcloud__icinga2_api_url: 'https://{{ icinga2_agent__icinga2_master_host | d(" nextcloud__icinga2_api_user_login: '{{ system_update__icinga2_api_user_login }}' nextcloud__icinga2_hostname: '{{ ansible_facts["nodename"] }}' +nextcloud__mailto_root__to: '{{ mailto_root__to | d([]) }}' + nextcloud__mariadb_login: '{{ mariadb_server__admin_user }}' nextcloud__on_calendar_app_update: '06,18,23:{{ 59 | random(seed=inventory_hostname) }}' nextcloud__on_calendar_jobs: '*:0/5' # every 5 minutes nextcloud__on_calendar_scan_files: '*:50:15' # every hour at hh:50:15 -# The php role owns the FPM service name (php-fpm on RedHat, php-fpm on Debian); source it from there instead of duplicating it per OS. nextcloud__php_fpm_service_name: '{{ php__fpm_service_name }}' nextcloud__skip_apps: false diff --git a/roles/nextcloud/meta/argument_specs.yml b/roles/nextcloud/meta/argument_specs.yml index b8bd799cb..e95248558 100644 --- a/roles/nextcloud/meta/argument_specs.yml +++ b/roles/nextcloud/meta/argument_specs.yml @@ -90,6 +90,12 @@ argument_specs: required: false description: 'The URL of the Icinga2 API used to set a downtime during a server update.' + nextcloud__mailto_root__to: + type: 'list' + elements: 'str' + required: false + description: 'Recipients of the ldap-show-remnants report. Defaults to the global mailto_root__to; empty means stdout only.' + nextcloud__on_calendar_app_update: type: 'str' required: false diff --git a/roles/nextcloud/templates/usr/local/bin/nextcloud-ldap-show-remnants.j2 b/roles/nextcloud/templates/usr/local/bin/nextcloud-ldap-show-remnants.j2 index 0479167c7..49f14258c 100644 --- a/roles/nextcloud/templates/usr/local/bin/nextcloud-ldap-show-remnants.j2 +++ b/roles/nextcloud/templates/usr/local/bin/nextcloud-ldap-show-remnants.j2 @@ -1,6 +1,6 @@ #!/usr/bin/env bash # {{ ansible_managed }} -# 2026042001 +# 2026060801 output=$(/usr/bin/php /var/www/html/nextcloud/occ ldap:show-remnants) if [ -z "$output" ]; then @@ -8,11 +8,10 @@ if [ -z "$output" ]; then exit 0 fi -{% if setup_basic__skip_mailto_root %} -echo "$output" -exit 0 +{% if nextcloud__mailto_root__to | length > 0 %} +# only mail the output if recipients are configured +echo "$output" | /usr/bin/mail -s "$(hostname --short) - Users not available on LDAP anymore, but have remnants in Nextcloud" {{ nextcloud__mailto_root__to | join(' ') }} {% else %} -# only send output if there is any -echo "$output" | /usr/bin/mail -s "$(hostname --short) - Users not available on LDAP anymore, but have remnants in Nextcloud" {{ mailto_root__to | join(' ') }} -exit 0 +echo "$output" {% endif %} +exit 0 From 56a100f844fc3afef9ce6ebb8162c8ad58f16e11 Mon Sep 17 00:00:00 2001 From: Danyal Berchtold Date: Mon, 8 Jun 2026 10:45:43 +0200 Subject: [PATCH 5/5] docs(roles/nextcloud): correct app-update timer default in README --- roles/nextcloud/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/nextcloud/README.md b/roles/nextcloud/README.md index 7c63cfa05..957cb2ddb 100644 --- a/roles/nextcloud/README.md +++ b/roles/nextcloud/README.md @@ -14,7 +14,7 @@ After installing Nextcloud, head over to your http(s)://nextcloud/index.php/sett ## How the Role Behaves -* App updates are applied automatically by the `nextcloud-app-update.timer` (disabled by default, enable via `nextcloud__timer_app_update_enabled`). The timer runs `/usr/local/bin/nextcloud-app-update`, which first checks whether any app update is pending. Nextcloud is switched into maintenance mode only when there is something to update; when everything is up to date the instance keeps serving requests untouched. After updating, the recommended database migrations (`db:add-missing-indices`, `db:add-missing-columns`, `db:add-missing-primary-keys`) are applied. A failed run leaves maintenance mode disabled again, so the instance does not stay offline, and reports the failure to systemd. +* App updates are applied automatically by the `nextcloud-app-update.timer` (enabled by default, disable via `nextcloud__timer_app_update_enabled`). The timer runs `/usr/local/bin/nextcloud-app-update`, which first checks whether any app update is pending. Nextcloud is switched into maintenance mode only when there is something to update; when everything is up to date the instance keeps serving requests untouched. After updating, the recommended database migrations (`db:add-missing-indices`, `db:add-missing-columns`, `db:add-missing-primary-keys`) are applied. A failed run leaves maintenance mode disabled again, so the instance does not stay offline, and reports the failure to systemd. * This automatic update covers app updates only. Updating the Nextcloud server itself is a separate, manual step via `/usr/local/bin/nextcloud-update`.