From 20dc85ae0c644a9580e12314d443c3356dcab4ca Mon Sep 17 00:00:00 2001 From: Christian Pointner Date: Wed, 6 Jul 2022 23:16:29 +0200 Subject: ele-media: nextcloud base install --- roles/elevate/media/defaults/main.yml | 5 +- roles/elevate/media/tasks/main.yml | 8 +- roles/elevate/media/tasks/nextcloud-app.yml | 128 +++++++++++++++++++++ .../elevate/media/tasks/nextcloud-custom-image.yml | 31 +++++ roles/elevate/media/tasks/nextcloud.yml | 4 +- roles/elevate/media/tasks/samba.yml | 6 + .../media/templates/nextcloud-apache-site.conf.j2 | 10 ++ .../media/templates/nextcloud-cron-.timer.j2 | 9 ++ .../media/templates/nextcloud-cron@.service.j2 | 15 +++ roles/elevate/media/templates/nextcloud-occ.j2 | 19 +++ .../nextcloud-pod-spec-with-mariadb.yml.j2 | 79 +++++++++++++ .../media/templates/nextcloud-run-cron.sh.j2 | 7 ++ roles/elevate/media/templates/nextcloud-upgrade.j2 | 62 ++++++++++ 13 files changed, 374 insertions(+), 9 deletions(-) create mode 100644 roles/elevate/media/tasks/nextcloud-app.yml create mode 100644 roles/elevate/media/tasks/nextcloud-custom-image.yml create mode 100644 roles/elevate/media/templates/nextcloud-apache-site.conf.j2 create mode 100644 roles/elevate/media/templates/nextcloud-cron-.timer.j2 create mode 100644 roles/elevate/media/templates/nextcloud-cron@.service.j2 create mode 100755 roles/elevate/media/templates/nextcloud-occ.j2 create mode 100644 roles/elevate/media/templates/nextcloud-pod-spec-with-mariadb.yml.j2 create mode 100644 roles/elevate/media/templates/nextcloud-run-cron.sh.j2 create mode 100755 roles/elevate/media/templates/nextcloud-upgrade.j2 (limited to 'roles') diff --git a/roles/elevate/media/defaults/main.yml b/roles/elevate/media/defaults/main.yml index 5cde7860..c16a38a0 100644 --- a/roles/elevate/media/defaults/main.yml +++ b/roles/elevate/media/defaults/main.yml @@ -4,10 +4,13 @@ elevate_media_share_gid: "800" # elevate_media_share_storage: # ... - +elevate_media_nextcloud_db_uid: "801" +elevate_media_nextcloud_db_gid: "801" +# elevate_media_nextcloud_base_path: /srv/nextcloud # elevate_media_nextcloud_storage: # ... +# elevate_media_nextcloud_instance_name: media.elevate.at # elevate_media_nextcloud_instance: # ... diff --git a/roles/elevate/media/tasks/main.yml b/roles/elevate/media/tasks/main.yml index 097f0c1b..910104f8 100644 --- a/roles/elevate/media/tasks/main.yml +++ b/roles/elevate/media/tasks/main.yml @@ -1,11 +1,5 @@ --- -- name: install samba - apt: - name: - - samba - state: present - -- name: configure samba +- name: install and configure samba import_tasks: samba.yml - name: install and configure nextcloud diff --git a/roles/elevate/media/tasks/nextcloud-app.yml b/roles/elevate/media/tasks/nextcloud-app.yml new file mode 100644 index 00000000..fd864893 --- /dev/null +++ b/roles/elevate/media/tasks/nextcloud-app.yml @@ -0,0 +1,128 @@ +--- +- name: prepare storage volume for nextcloud + vars: + storage_volume: "{{ elevate_media_nextcloud_storage | combine({'dest': elevate_media_nextcloud_base_path}) }}" + include_role: + name: "storage/{{ elevate_media_nextcloud_storage.type }}/volume" + +- name: create nextcloud app subdirectory + file: + path: "{{ elevate_media_nextcloud_base_path }}/{{ elevate_media_nextcloud_instance_name }}/nextcloud" + owner: "{{ elevate_media_share_uid }}" + group: "{{ elevate_media_share_gid }}" + state: directory + + +- name: add group for nextcloud db + group: + name: nc-db + gid: "{{ elevate_media_nextcloud_db_gid }}" + +- name: add user for nextcloud db + user: + name: nc-db + uid: "{{ elevate_media_nextcloud_db_uid }}" + group: nc-db + password: "!" + +- name: create nextcloud database subdirectory + file: + path: "{{ elevate_media_nextcloud_base_path }}/{{ elevate_media_nextcloud_instance_name }}/{{ elevate_media_nextcloud_instance.database.type }}" + owner: "{{ elevate_media_nextcloud_db_uid }}" + group: "{{ elevate_media_nextcloud_db_gid }}" + state: directory + + +- name: create auxiliary config directory + file: + path: "{{ elevate_media_nextcloud_base_path }}/{{ elevate_media_nextcloud_instance_name }}/config" + state: directory + +- name: create apache vhost config + template: + src: nextcloud-apache-site.conf.j2 + dest: "{{ elevate_media_nextcloud_base_path }}/{{ elevate_media_nextcloud_instance_name }}/config/apache-site.conf" + +- name: configure apache to run on port 8080 only + copy: + content: | + Listen 8080 + dest: "{{ elevate_media_nextcloud_base_path }}/{{ elevate_media_nextcloud_instance_name }}/config/ports.conf" + + +- name: build custom image + include_tasks: nextcloud-custom-image.yml + +- name: install pod manifest + vars: + kubernetes_standalone_pod: + name: "nextcloud-{{ elevate_media_nextcloud_instance_name }}" + spec: "{{ lookup('template', 'nextcloud-pod-spec-with-{{ elevate_media_nextcloud_instance.database.type }}.yml.j2') }}" + mode: "0600" + config_hash_items: + - path: "{{ elevate_media_nextcloud_base_path }}/{{ elevate_media_nextcloud_instance_name }}/config/apache-site.conf" + properties: + - checksum + - path: "{{ elevate_media_nextcloud_base_path }}/{{ elevate_media_nextcloud_instance_name }}/config/ports.conf" + properties: + - checksum + - path: "{{ elevate_media_nextcloud_base_path }}/{{ elevate_media_nextcloud_instance_name }}/build/Dockerfile" + properties: + - checksum + include_role: + name: kubernetes/standalone/pod + + +- name: install cron trigger script + template: + src: nextcloud-run-cron.sh.j2 + dest: "{{ elevate_media_nextcloud_base_path }}/{{ elevate_media_nextcloud_instance_name }}/config/run-cron.sh" + mode: 0755 + +- name: install template systemd unit for cron trigger + template: + src: nextcloud-cron@.service.j2 + dest: /etc/systemd/system/nextcloud-cron@.service + +- name: install systemd timer unit + template: + src: nextcloud-cron-.timer.j2 + dest: "/etc/systemd/system/nextcloud-cron-{{ elevate_media_nextcloud_instance_name }}.timer" + +- name: start/enable cron trigger systemd timer + systemd: + daemon_reload: yes + name: "nextcloud-cron-{{ elevate_media_nextcloud_instance_name }}.timer" + state: started + enabled: yes + + +- name: configure nginx vhost + vars: + nginx_vhost: + name: "nextcloud-{{ elevate_media_nextcloud_instance_name }}" + template: generic-proxy-no-buffering-with-acme + acme: true + hostnames: "{{ elevate_media_nextcloud_instance.hostnames }}" + locations: + '/': + proxy_pass: "http://127.0.0.1:{{ elevate_media_nextcloud_instance.port }}" + proxy_redirect: + - redirect: "http://$host/" + replacement: "https://$host/" + - redirect: "http://$host:8080/" + replacement: "https://$host/" + extra_directives: |- + client_max_body_size 0; + include_role: + name: nginx/vhost + + +- name: install management scripts + loop: + - nextcloud-upgrade + - nextcloud-occ + template: + src: "{{ item }}.j2" + dest: "/usr/local/bin/{{ item }}" + mode: 0755 diff --git a/roles/elevate/media/tasks/nextcloud-custom-image.yml b/roles/elevate/media/tasks/nextcloud-custom-image.yml new file mode 100644 index 00000000..46f06dbf --- /dev/null +++ b/roles/elevate/media/tasks/nextcloud-custom-image.yml @@ -0,0 +1,31 @@ +--- +- name: create build directory for custom image + file: + path: "{{ elevate_media_nextcloud_base_path }}/{{ elevate_media_nextcloud_instance_name }}/build" + state: directory + +- name: generate Dockerfile for custom image + copy: + content: | + FROM {{ elevate_media_nextcloud_instance.custom_image.from | default('nextcloud:' + elevate_media_nextcloud_instance.version) }} + + RUN set -x \ + && addgroup --gid {{ elevate_media_share_gid }} nc-app \ + && adduser --uid {{ elevate_media_share_uid }} --gid {{ elevate_media_share_gid }} --system --no-create-home --home /var/www/html --disabled-login --disabled-password nc-app + {% if 'custom_image' in elevate_media_nextcloud_instance %} + + {{ elevate_media_nextcloud_instance.custom_image.dockerfile }} + {% endif %} + dest: "{{ elevate_media_nextcloud_base_path }}/{{ elevate_media_nextcloud_instance_name }}/build/Dockerfile" + register: nextcloud_custom_image_docker + +- name: build custom image + docker_image: + name: "nextcloud/{{ elevate_media_nextcloud_instance_name }}:{{ elevate_media_nextcloud_instance.version }}" + state: present + force_source: "{{ nextcloud_custom_image_docker is changed }}" + source: build + build: + path: "{{ elevate_media_nextcloud_base_path }}/{{ elevate_media_nextcloud_instance_name }}/build" + network: host + pull: yes diff --git a/roles/elevate/media/tasks/nextcloud.yml b/roles/elevate/media/tasks/nextcloud.yml index e24bf32d..1b875f2b 100644 --- a/roles/elevate/media/tasks/nextcloud.yml +++ b/roles/elevate/media/tasks/nextcloud.yml @@ -1,5 +1,7 @@ --- -## TODO: include role: apps/nextcloud +## TODO: convert to new apps/nexctloud/instance role once this is done! +- name: basic nextcloud config + import_tasks: nextcloud-app.yml # - name: configure nextcloud upload file size limit # loop: diff --git a/roles/elevate/media/tasks/samba.yml b/roles/elevate/media/tasks/samba.yml index 3101a82a..67a511de 100644 --- a/roles/elevate/media/tasks/samba.yml +++ b/roles/elevate/media/tasks/samba.yml @@ -1,4 +1,10 @@ --- +- name: install samba + apt: + name: + - samba + state: present + - name: create group for shared access group: name: share diff --git a/roles/elevate/media/templates/nextcloud-apache-site.conf.j2 b/roles/elevate/media/templates/nextcloud-apache-site.conf.j2 new file mode 100644 index 00000000..a52a7fc5 --- /dev/null +++ b/roles/elevate/media/templates/nextcloud-apache-site.conf.j2 @@ -0,0 +1,10 @@ + + ServerAdmin webmaster@localhost + DocumentRoot /var/www/html + + UseCanonicalName Off + UseCanonicalPhysicalPort Off + + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined + diff --git a/roles/elevate/media/templates/nextcloud-cron-.timer.j2 b/roles/elevate/media/templates/nextcloud-cron-.timer.j2 new file mode 100644 index 00000000..b8caa377 --- /dev/null +++ b/roles/elevate/media/templates/nextcloud-cron-.timer.j2 @@ -0,0 +1,9 @@ +[Unit] +Description=Nextcloud cron.php job timer for %i + +[Timer] +OnCalendar=*:{{ 5 | random(seed=elevate_media_nextcloud_instance_name) }}/5 +Unit=nextcloud-cron@{{ elevate_media_nextcloud_instance_name }}.service + +[Install] +WantedBy=timers.target diff --git a/roles/elevate/media/templates/nextcloud-cron@.service.j2 b/roles/elevate/media/templates/nextcloud-cron@.service.j2 new file mode 100644 index 00000000..33623c16 --- /dev/null +++ b/roles/elevate/media/templates/nextcloud-cron@.service.j2 @@ -0,0 +1,15 @@ +[Unit] +Description=Nextcloud cron.php job for %i + +[Service] +Type=oneshot +ExecStart={{ elevate_media_nextcloud_base_path }}/%i/config/run-cron.sh +NoNewPrivileges=yes +PrivateTmp=yes +PrivateDevices=yes +ProtectSystem=strict +ProtectHome=yes +ProtectKernelTunables=yes +ProtectControlGroups=yes +RestrictRealtime=yes +RestrictAddressFamilies=AF_UNIX AF_INET diff --git a/roles/elevate/media/templates/nextcloud-occ.j2 b/roles/elevate/media/templates/nextcloud-occ.j2 new file mode 100755 index 00000000..f12f1259 --- /dev/null +++ b/roles/elevate/media/templates/nextcloud-occ.j2 @@ -0,0 +1,19 @@ +#!/bin/bash + +INST_NAME="$1" +shift + +if [ -z "$INST_NAME" ]; then + echo "Usage: $0 [ ... ]" + exit 1 +fi + +set -eu + +pod_id=$(crictl pods -q --state ready --name "^nextcloud-$INST_NAME-{{ ansible_nodename }}$") +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 $@ diff --git a/roles/elevate/media/templates/nextcloud-pod-spec-with-mariadb.yml.j2 b/roles/elevate/media/templates/nextcloud-pod-spec-with-mariadb.yml.j2 new file mode 100644 index 00000000..b67066fc --- /dev/null +++ b/roles/elevate/media/templates/nextcloud-pod-spec-with-mariadb.yml.j2 @@ -0,0 +1,79 @@ +securityContext: + allowPrivilegeEscalation: false +containers: +- name: nextcloud + image: "nextcloud/{{ elevate_media_nextcloud_instance_name }}:{{ elevate_media_nextcloud_instance.version }}" + securityContext: + runAsUser: {{ elevate_media_share_uid }} + runAsGroup: {{ elevate_media_share_gid }} + resources: + limits: + memory: "4Gi" +{% if 'new' in elevate_media_nextcloud_instance and elevate_media_nextcloud_instance.new %} + env: + - name: NEXTCLOUD_TRUSTED_DOMAINS + value: "{{ elevate_media_nextcloud_instance.hostnames | join(' ') }}" + - name: OVERWRITEPROTOCOL + value: "https" + - name: MYSQL_HOST + value: 127.0.0.1 + - name: MYSQL_DATABASE + value: nextcloud + - name: MYSQL_USER + value: nextcloud + - name: MYSQL_PASSWORD + value: "{{ elevate_media_nextcloud_instance.database.password }}" +{% endif %} + volumeMounts: + - name: nextcloud + mountPath: /var/www/html + - name: config + mountPath: /etc/apache2/sites-available/000-default.conf + subPath: apache-site.conf + readOnly: true + - name: config + mountPath: /etc/apache2/ports.conf + subPath: ports.conf + readOnly: true + ports: + - containerPort: 8080 + hostPort: {{ elevate_media_nextcloud_instance.port }} + hostIP: 127.0.0.1 +- name: database + image: "mariadb:{{ elevate_media_nextcloud_instance.database.version }}" + args: + - --transaction-isolation=READ-COMMITTED + - --binlog-format=ROW + securityContext: + runAsUser: {{ elevate_media_nextcloud_db_uid }} + runAsGroup: {{ elevate_media_nextcloud_db_gid }} + resources: + limits: + memory: "2Gi" +{% if 'new' in elevate_media_nextcloud_instance and elevate_media_nextcloud_instance.new %} + env: + - name: MYSQL_RANDOM_ROOT_PASSWORD + value: "true" + - name: MYSQL_DATABASE + value: nextcloud + - name: MYSQL_USER + value: nextcloud + - name: MYSQL_PASSWORD + value: "{{ elevate_media_nextcloud_instance.database.password }}" +{% endif %} + volumeMounts: + - name: database + mountPath: /var/lib/mysql +volumes: +- name: config + hostPath: + path: "{{ elevate_media_nextcloud_base_path }}/{{ elevate_media_nextcloud_instance_name }}/config/" + type: Directory +- name: nextcloud + hostPath: + path: "{{ elevate_media_nextcloud_base_path }}/{{ elevate_media_nextcloud_instance_name }}/nextcloud" + type: Directory +- name: database + hostPath: + path: "{{ elevate_media_nextcloud_base_path }}/{{ elevate_media_nextcloud_instance_name }}/{{ elevate_media_nextcloud_instance.database.type }}" + type: Directory diff --git a/roles/elevate/media/templates/nextcloud-run-cron.sh.j2 b/roles/elevate/media/templates/nextcloud-run-cron.sh.j2 new file mode 100644 index 00000000..0824d6ba --- /dev/null +++ b/roles/elevate/media/templates/nextcloud-run-cron.sh.j2 @@ -0,0 +1,7 @@ +#!/bin/bash + +POD_NAME="{{ elevate_media_nextcloud_instance_name }}-$(hostname)" +POD_ID=$(crictl pods --name "$POD_NAME" --state ready -q) +CONTAINER_ID=$(crictl ps --pod "$POD_ID" --name nextcloud -q) + +exec crictl exec "$CONTAINER_ID" php -f /var/www/html/cron.php diff --git a/roles/elevate/media/templates/nextcloud-upgrade.j2 b/roles/elevate/media/templates/nextcloud-upgrade.j2 new file mode 100755 index 00000000..a4221edc --- /dev/null +++ b/roles/elevate/media/templates/nextcloud-upgrade.j2 @@ -0,0 +1,62 @@ +#!/bin/bash + +INST_NAME="$1" +VERSION="$2" +if [ -z "$INST_NAME" ] || [ -z "$VERSION" ]; then + echo "Usage: $0 " + exit 1 +fi + +set -eu + +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/" +K8S_MANIFEST_FILE="$K8S_MANIFEST_D/nextcloud-$INST_NAME.yml" +if [ ! -e "$K8S_MANIFEST_FILE" ]; then + echo "could not find manifest file: $K8S_MANIFEST_FILE" + exit 2 +fi + +TMP_D=$(mktemp -d -t nextcloud-upgrade.XXXXXXX) +function cleanup { + rm -rf "$TMP_D" +} +trap cleanup EXIT + +IMAGE_BUILD_D="{{ elevate_media_nextcloud_base_path }}/$INST_NAME/build" +IMAGE_NAME="nextcloud" +if [ -e "$IMAGE_BUILD_D/Dockerfile" ]; then + ## this only works if docker is installed... + echo "*** Building custom image" + echo "" + sed "0,/FROM \(.*\):.*/s//FROM \1:$VERSION/" -i "$IMAGE_BUILD_D/Dockerfile" + IMAGE_NAME="nextcloud/$INST_NAME" + docker build --rm --network host -t "$IMAGE_NAME:$VERSION" "$IMAGE_BUILD_D" + echo "" +else + echo "*** Pre-Pulling the image" + echo "" + crictl pull "docker.io/library/nextcloud:$VERSION" + echo "" +fi + +echo "*** Rebuilding config-hash file" +echo "" +cat "$K8S_CONFIG_HASH_FILE" | grep '^/.*:' | sed 's/:$//' | xargs sha256sum | awk '{ print($2":\n checksum: "$1) }' > "$TMP_D/config-hash.yml" +CONFIG_HASH=$(sha256sum "$TMP_D/config-hash.yml" | awk '{ print($1) }') + +echo "*** Patching manifest file" +echo "" +sed -e "s#image: \"$IMAGE_NAME:.*\"#image: \"$IMAGE_NAME:$VERSION\"#" -e "s#config-hash: \".*\"#config-hash: \"$CONFIG_HASH\"#" "$K8S_MANIFEST_FILE" > "$TMP_D/manifest.yml" +set +e +diff -u "$K8S_MANIFEST_FILE" "$TMP_D/manifest.yml" +if [ $? -eq 0 ]; then + echo "patching file failed?" + exit 2 +fi +cat "$TMP_D/config-hash.yml" > "$K8S_CONFIG_HASH_FILE" +cat "$TMP_D/manifest.yml" > "$K8S_MANIFEST_FILE" +echo "" + +exit 0 -- cgit v1.2.3