diff options
Diffstat (limited to 'roles/apps/nextcloud')
13 files changed, 247 insertions, 88 deletions
diff --git a/roles/apps/nextcloud/base/defaults/main.yml b/roles/apps/nextcloud/base/defaults/main.yml new file mode 100644 index 00000000..1a8a6d52 --- /dev/null +++ b/roles/apps/nextcloud/base/defaults/main.yml @@ -0,0 +1,9 @@ +--- +nextcloud_app_uid: "950" +nextcloud_app_gid: "950" + +nextcloud_db_uid: "951" +nextcloud_db_gid: "951" + +nextcloud_redis_uid: "952" +nextcloud_redis_gid: "952" diff --git a/roles/apps/nextcloud/base/tasks/main.yml b/roles/apps/nextcloud/base/tasks/main.yml new file mode 100644 index 00000000..4c85a35c --- /dev/null +++ b/roles/apps/nextcloud/base/tasks/main.yml @@ -0,0 +1,51 @@ +--- +- name: add group for nextcloud app + group: + name: nc-app + gid: "{{ nextcloud_app_gid }}" + +- name: add user for nextcloud app + user: + name: nc-app + uid: "{{ nextcloud_app_uid }}" + group: nc-app + password: "!" + +- name: add group for nextcloud db + group: + name: nc-db + gid: "{{ nextcloud_db_gid }}" + +- name: add user for nextcloud db + user: + name: nc-db + uid: "{{ nextcloud_db_uid }}" + group: nc-db + password: "!" + +- name: add group for nextcloud redis + group: + name: nc-redis + gid: "{{ nextcloud_redis_gid }}" + +- name: add user for nextcloud redis + user: + name: nc-redis + uid: "{{ nextcloud_redis_uid }}" + group: nc-redis + password: "!" + +- name: install template systemd unit for cron trigger + template: + src: cron@.service.j2 + dest: /etc/systemd/system/nextcloud-cron@.service + +- name: install management scripts + loop: + - nextcloud-upgrade + - nextcloud-occ + - nextcloud-cron + template: + src: "{{ item }}.j2" + dest: "/usr/local/bin/{{ item }}" + mode: 0755 diff --git a/roles/apps/nextcloud/templates/cron@.service.j2 b/roles/apps/nextcloud/base/templates/cron@.service.j2 index d8cde0a3..d8cde0a3 100644 --- a/roles/apps/nextcloud/templates/cron@.service.j2 +++ b/roles/apps/nextcloud/base/templates/cron@.service.j2 diff --git a/roles/apps/nextcloud/templates/nextcloud-cron.j2 b/roles/apps/nextcloud/base/templates/nextcloud-cron.j2 index 355ae2c3..cf1d9715 100755 --- a/roles/apps/nextcloud/templates/nextcloud-cron.j2 +++ b/roles/apps/nextcloud/base/templates/nextcloud-cron.j2 @@ -16,4 +16,4 @@ if [ -z "$pod_id" ]; then echo "Pod not found"; exit 1; fi container_id=$(crictl ps -q --name '^nextcloud$' -p "$pod_id") if [ -z "$container_id" ]; then echo "Container not found"; exit 1; fi -exec crictl exec "$container_id" php -f /var/www/html/cron.php +exec crictl exec "$container_id" bash -c 'php -f /var/www/html/occ status -e; if [ $? -eq 0 ]; then php -f /var/www/html/cron.php; else echo "not running cron script when in maintenance mode"; fi' diff --git a/roles/apps/nextcloud/templates/nextcloud-occ.j2 b/roles/apps/nextcloud/base/templates/nextcloud-occ.j2 index f12f1259..01383c95 100755 --- a/roles/apps/nextcloud/templates/nextcloud-occ.j2 +++ b/roles/apps/nextcloud/base/templates/nextcloud-occ.j2 @@ -16,4 +16,4 @@ if [ -z "$pod_id" ]; then echo "Pod not found"; exit 1; fi container_id=$(crictl ps -q --name '^nextcloud$' -p "$pod_id") if [ -z "$container_id" ]; then echo "Container not found"; exit 1; fi -exec crictl exec -it "$container_id" php /var/www/html/occ $@ +exec crictl exec -it "$container_id" php -f /var/www/html/occ $@ diff --git a/roles/apps/nextcloud/templates/nextcloud-upgrade.j2 b/roles/apps/nextcloud/base/templates/nextcloud-upgrade.j2 index ffa912e8..f6edcb44 100755 --- a/roles/apps/nextcloud/templates/nextcloud-upgrade.j2 +++ b/roles/apps/nextcloud/base/templates/nextcloud-upgrade.j2 @@ -9,6 +9,13 @@ fi set -eu +CURRENT_VERSION=$(nextcloud-occ "$INST_NAME" status -n --no-warnings --output plain | tr -d '\r' | awk -F : '/versionstring/ { print($2) }' | tr -d ' ') +if [ "$CURRENT_VERSION" = "$VERSION" ]; then + echo "The current running version of nextcloud is already $CURRENT_VERSION, nothing to do here." + exit 0 +fi +echo "will upgrade nextcloud instance $INST_NAME from '$CURRENT_VERSION' to '$VERSION'" + K8S_CONFIG_HASH_D="/etc/kubernetes/config-hashes/" K8S_CONFIG_HASH_FILE="$K8S_CONFIG_HASH_D/nextcloud-$INST_NAME.yml" K8S_MANIFEST_D="/etc/kubernetes/manifests/" @@ -41,16 +48,8 @@ else echo "" fi -STORAGE_TYPE=$(findmnt -no fstype -T "$IMAGE_BUILD_D") -if [ $STORAGE_TYPE == "zfs" ]; then - echo "*** creating ZFS snapshot" - echo "" - - IMAGE_NAME_ESCAPED=${IMAGE_NAME/\//\\/} - CURRENT_VERSION=$(cat "$K8S_MANIFEST_FILE" | awk '/image: "'"$IMAGE_NAME_ESCAPED"':.*"/ { print($2) }' | tr -d '"' | cut -d ':' -f 2) - ZFS_VOLUME=$(findmnt -no source -T "$IMAGE_BUILD_D") - zfs snapshot "$ZFS_VOLUME@upgrade_$CURRENT_VERSION-to-$VERSION""_$(date '+%Y-%m-%m_%H:%M:%S')" -fi +INSTANCE_BASE_D=$(dirname "$IMAGE_BUILD_D") +"$INSTANCE_BASE_D/upgrade.sh" prepare "$CURRENT_VERSION" "$VERSION" echo "*** Rebuilding config-hash file" echo "" @@ -70,4 +69,6 @@ cat "$TMP_D/config-hash.yml" > "$K8S_CONFIG_HASH_FILE" cat "$TMP_D/manifest.yml" > "$K8S_MANIFEST_FILE" echo "" +"$INSTANCE_BASE_D/upgrade.sh" finalize "$CURRENT_VERSION" "$VERSION" + exit 0 diff --git a/roles/apps/nextcloud/defaults/main.yml b/roles/apps/nextcloud/defaults/main.yml index ac87de94..631b0a0a 100644 --- a/roles/apps/nextcloud/defaults/main.yml +++ b/roles/apps/nextcloud/defaults/main.yml @@ -1,21 +1,9 @@ --- -nextcloud_app_uid: "950" -nextcloud_app_gid: "950" - -nextcloud_db_uid: "951" -nextcloud_db_gid: "951" - -nextcloud_redis_uid: "952" -nextcloud_redis_gid: "952" - # nextcloud_instances: # example: # new: yes # version: 17.0.0 # port: 8100 -# hostnames: -# - wolke.example.com -# - cloud.example.com # storage: # type: ... # database: @@ -26,3 +14,10 @@ nextcloud_redis_gid: "952" # from: foo/bar:1.0 # optional # dockerfile: | # RUN apt-get install ... +# publish: +# zone: "{{ apps_publish_zone__foo }}" +# hostnames: +# - wolke.example.com +# - cloud.example.com +# tls: +# certificate_provider: ... diff --git a/roles/apps/nextcloud/instance/tasks/main.yml b/roles/apps/nextcloud/instance/tasks/main.yml index 373aa0a8..71a3ee79 100644 --- a/roles/apps/nextcloud/instance/tasks/main.yml +++ b/roles/apps/nextcloud/instance/tasks/main.yml @@ -47,6 +47,43 @@ dest: "{{ nextcloud_instance_basepath }}/config/ports.conf" +- name: create tls directory + file: + path: "{{ nextcloud_instance_basepath }}/tls" + owner: "{{ nextcloud_app_uid }}" + group: "{{ nextcloud_app_gid }}" + mode: 0500 + state: directory + +- name: generate/install TLS certificates for publishment + vars: + x509_certificate_name: "nextcloud-{{ nextcloud_instance }}_publish" + x509_certificate_hostnames: [] + x509_certificate_config: + ca: "{{ nextcloud_instances[nextcloud_instance].publish.zone.certificate_ca_config }}" + cert: + common_name: "nextcloud-{{ nextcloud_instance }}.{{ inventory_hostname }}" + extended_key_usage: + - serverAuth + extended_key_usage_critical: yes + create_subject_key_identifier: yes + not_after: +100w + x509_certificate_renewal: + install: + - dest: "{{ nextcloud_instance_basepath }}/tls/cert.pem" + src: + - cert + owner: "{{ nextcloud_app_uid }}" + mode: "0400" + - dest: "{{ nextcloud_instance_basepath }}/tls/key.pem" + src: + - key + owner: "{{ nextcloud_app_uid }}" + mode: "0400" + include_role: + name: "x509/{{ nextcloud_instances[nextcloud_instance].publish.zone.certificate_provider }}/cert" + + - name: build custom image # when: "'custom_image' in nextcloud_instances[nextcloud_instance]" include_tasks: custom-image.yml @@ -71,6 +108,13 @@ name: kubernetes/standalone/pod +- name: install upgrade helper script + template: + src: upgrade.sh.j2 + dest: "{{ nextcloud_instance_basepath }}/upgrade.sh" + mode: 0755 + + - name: install systemd timer unit template: src: cron-.timer.j2 @@ -84,29 +128,44 @@ enabled: yes -- name: configure nginx vhost +- name: configure nginx vhost for publishment vars: - nginx_vhost: - name: "nextcloud-{{ nextcloud_instance }}" + nginx_vhost__yaml: | + name: "nextcloud-{{ nextcloud_instance }}.{{ inventory_hostname }}" template: generic + {% if 'tls' in nextcloud_instances[nextcloud_instance].publish %} tls: - certificate_provider: "{{ acme_client }}" - hostnames: "{{ nextcloud_instances[nextcloud_instance].hostnames }}" + {{ nextcloud_instances[nextcloud_instance].publish.tls | to_nice_yaml(indent=2) | indent(2) }} + {% endif %} + hostnames: + {% for hostname in nextcloud_instances[nextcloud_instance].publish.hostnames %} + - {{ hostname }} + {% endfor %} locations: '/': - proxy_pass: "http://127.0.0.1:{{ nextcloud_instances[nextcloud_instance].port }}" + {% if nextcloud_instances[nextcloud_instance].publish.zone.publisher == inventory_hostname %} + proxy_pass: "https://127.0.0.1:{{ nextcloud_instances[nextcloud_instance].port }}" + {% else %} + proxy_pass: "https://{{ ansible_default_ipv4.address }}:{{ nextcloud_instances[nextcloud_instance].port }}" + {% endif %} proxy_redirect: - - redirect: "http://$host/" - replacement: "https://$host/" - - redirect: "http://$host:8080/" + - redirect: "https://$host:8080/" replacement: "https://$host/" + proxy_ssl: + trusted_certificate: "/etc/ssl/apps-publish-{{ nextcloud_instances[nextcloud_instance].publish.zone.name }}/apps-publish-{{ nextcloud_instances[nextcloud_instance].publish.zone.name }}-ca-crt.pem" + verify: "on" + name: "nextcloud-{{ nextcloud_instance }}.{{ inventory_hostname }}" + protocols: "TLSv1.3" extra_directives: |- client_max_body_size 0; types { text/javascript js mjs; } + nginx_vhost: "{{ nginx_vhost__yaml | from_yaml }}" include_role: name: nginx/vhost + apply: + delegate_to: "{{ nextcloud_instances[nextcloud_instance].publish.zone.publisher }}" # TODO: @@ -118,7 +177,7 @@ prompt: | ************* {{ nextcloud_instance }} is a new instance ** - ** Go to https://{{ nextcloud_instances[nextcloud_instance].hostnames[0] }} and finalize the + ** Go to https://{{ nextcloud_instances[nextcloud_instance].publish.hostnames[0] }} and finalize the ** installation. After that run the following commands: ** ** $ nextcloud-occ {{ nextcloud_instance }} config:system:set default_phone_region --value='at' diff --git a/roles/apps/nextcloud/instance/templates/apache-site.conf.j2 b/roles/apps/nextcloud/instance/templates/apache-site.conf.j2 index a52a7fc5..8df06113 100644 --- a/roles/apps/nextcloud/instance/templates/apache-site.conf.j2 +++ b/roles/apps/nextcloud/instance/templates/apache-site.conf.j2 @@ -1,3 +1,7 @@ +IncludeOptional mods-available/socache_shmcb.load +IncludeOptional mods-available/ssl.load +IncludeOptional mods-available/ssl.conf + <VirtualHost *:8080> ServerAdmin webmaster@localhost DocumentRoot /var/www/html @@ -5,6 +9,12 @@ UseCanonicalName Off UseCanonicalPhysicalPort Off + ServerName nextcloud-{{ nextcloud_instance }}.{{ inventory_hostname }} + SSLEngine on + SSLCertificateFile "/etc/ssl/publish/cert.pem" + SSLCertificateKeyFile "/etc/ssl/publish/key.pem" + SSLProtocol TLSv1.3 + ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost> diff --git a/roles/apps/nextcloud/instance/templates/pod-spec-with-mariadb.yml.j2 b/roles/apps/nextcloud/instance/templates/pod-spec-with-mariadb.yml.j2 index 42d76757..c1a4f2ea 100644 --- a/roles/apps/nextcloud/instance/templates/pod-spec-with-mariadb.yml.j2 +++ b/roles/apps/nextcloud/instance/templates/pod-spec-with-mariadb.yml.j2 @@ -13,9 +13,7 @@ containers: {% if 'new' in nextcloud_instances[nextcloud_instance] and nextcloud_instances[nextcloud_instance].new %} env: - name: NEXTCLOUD_TRUSTED_DOMAINS - value: "{{ nextcloud_instances[nextcloud_instance].hostnames | join(' ') }}" - - name: OVERWRITEPROTOCOL - value: "https" + value: "{{ nextcloud_instances[nextcloud_instance].publish.hostnames | join(' ') }}" - name: MYSQL_HOST value: 127.0.0.1 - name: MYSQL_DATABASE @@ -36,6 +34,9 @@ containers: mountPath: /etc/apache2/ports.conf subPath: ports.conf readOnly: true + - name: tls + mountPath: /etc/ssl/publish + readOnly: true ports: - containerPort: 8080 hostPort: {{ nextcloud_instances[nextcloud_instance].port }} @@ -91,6 +92,10 @@ volumes: hostPath: path: "{{ nextcloud_instance_basepath }}/config/" type: Directory +- name: tls + hostPath: + path: "{{ nextcloud_instance_basepath }}/tls/" + type: Directory - name: nextcloud hostPath: path: "{{ nextcloud_instance_basepath }}/nextcloud" diff --git a/roles/apps/nextcloud/instance/templates/upgrade.sh.j2 b/roles/apps/nextcloud/instance/templates/upgrade.sh.j2 new file mode 100644 index 00000000..62f6641e --- /dev/null +++ b/roles/apps/nextcloud/instance/templates/upgrade.sh.j2 @@ -0,0 +1,77 @@ +#!/bin/bash + +set -e + +if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]; then + echo "Usage: $0 (preapre|finalize) <old-version> <new-version>" + exit 1 +fi + +COMMAND="$1" +OLD_VERSION="$2" +NEW_VERSION="$3" +POD_NAME="{{ nextcloud_instance }}-$(hostname)" + +maintenance_mode() { + POD_ID=$(crictl pods --name "$POD_NAME" --state ready -q) + CONTAINER_ID=$(crictl ps --pod "$POD_ID" --name nextcloud -q) + crictl exec "$CONTAINER_ID" php -f /var/www/html/occ maintenance:mode "$1" +} + +wait_for_cronjobs() { + POD_ID=$(crictl pods --name "$POD_NAME" --state ready -q) + CONTAINER_ID=$(crictl ps --pod "$POD_ID" --name nextcloud -q) + crictl exec "$CONTAINER_ID" bash -c 'echo -n "waiting for running cron script "; while [ -n "$(pgrep -a php | grep cron.php)" ]; do echo -n "."; sleep 1; done; echo ""' +} + +wait_for_upgrade_complete() { + NEW_VERSION="$1" + + set +e + echo -n "waiting for new version to be ready " + while true; do + POD_ID=$(crictl pods --name "$POD_NAME" --state ready -q) + if [ -z $POD_ID ]; then continue; fi + CONTAINER_ID=$(crictl ps --pod "$POD_ID" --name nextcloud -q) + if [ -z $CONTAINER_ID ]; then continue; fi + STATUS_OUTPUT=$(crictl exec "$CONTAINER_ID" php -f /var/www/html/occ status -n --no-warnings --output plain) + if [ $? -eq 0 ]; then + RUNNING_VERSION=$(echo "$STATUS_OUTPUT" | awk -F : '/versionstring/ { print($2) }' | tr -d ' ') + if [ "$RUNNING_VERSION" = "$NEW_VERSION" ]; then + break + fi + echo -n "." + fi + sleep 1 + done + echo "" + set -e + crictl exec "$CONTAINER_ID" bash -c 'echo -n "waiting for apache to start "; while [ -z "$(pgrep apache2)" ]; do echo -n "."; sleep 1; done; echo ""' +} + +storage_snapshot() { + OLD_VERSION="$1" + NEW_VERSION="$2" + +{% if nextcloud_instances[nextcloud_instance].storage.type == 'zfs' %} + ZFS_VOLUME=$(findmnt -no source -T "{{ nextcloud_instance_basepath }}") + echo "creating snapshot for zfs volume: $ZFS_VOLUME" + zfs snapshot "$ZFS_VOLUME@upgrade_$OLD_VERSION-to-$NEW_VERSION""_$(date '+%Y-%m-%m_%H:%M:%S')" +{% endif %} +} + +case "$COMMAND" in + prepare) + maintenance_mode --on + wait_for_cronjobs + storage_snapshot "$OLD_VERSION" "$NEW_VERSION" + ;; + finalize) + wait_for_upgrade_complete "$NEW_VERSION" + maintenance_mode --off + ;; + *) + echo "unknown command: $COMMAND, must be prepare or finalize" + exit 1 + ;; +esac diff --git a/roles/apps/nextcloud/meta/main.yml b/roles/apps/nextcloud/meta/main.yml new file mode 100644 index 00000000..c00c47ce --- /dev/null +++ b/roles/apps/nextcloud/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - role: apps/nextcloud/base diff --git a/roles/apps/nextcloud/tasks/main.yml b/roles/apps/nextcloud/tasks/main.yml index 69bbba6a..6e81f351 100644 --- a/roles/apps/nextcloud/tasks/main.yml +++ b/roles/apps/nextcloud/tasks/main.yml @@ -1,55 +1,4 @@ --- -- name: add group for nextcloud app - group: - name: nc-app - gid: "{{ nextcloud_app_gid }}" - -- name: add user for nextcloud app - user: - name: nc-app - uid: "{{ nextcloud_app_uid }}" - group: nc-app - password: "!" - -- name: add group for nextcloud db - group: - name: nc-db - gid: "{{ nextcloud_db_gid }}" - -- name: add user for nextcloud db - user: - name: nc-db - uid: "{{ nextcloud_db_uid }}" - group: nc-db - password: "!" - -- name: add group for nextcloud redis - group: - name: nc-redis - gid: "{{ nextcloud_redis_gid }}" - -- name: add user for nextcloud redis - user: - name: nc-redis - uid: "{{ nextcloud_redis_uid }}" - group: nc-redis - password: "!" - -- name: install template systemd unit for cron trigger - template: - src: cron@.service.j2 - dest: /etc/systemd/system/nextcloud-cron@.service - -- name: install management scripts - loop: - - nextcloud-upgrade - - nextcloud-occ - - nextcloud-cron - template: - src: "{{ item }}.j2" - dest: "/usr/local/bin/{{ item }}" - mode: 0755 - - name: instance specific tasks loop: "{{ nextcloud_instances | list }}" loop_control: |