summaryrefslogtreecommitdiff
path: root/roles/apps
diff options
context:
space:
mode:
Diffstat (limited to 'roles/apps')
-rw-r--r--roles/apps/collabora/code/defaults/main.yml11
-rw-r--r--roles/apps/collabora/code/tasks/main.yml28
-rw-r--r--roles/apps/collabora/code/templates/nginx-vhost.conf.j2108
-rw-r--r--roles/apps/collabora/code/templates/pod.yml.j233
-rw-r--r--roles/apps/etherpad-lite/defaults/main.yml29
-rw-r--r--roles/apps/etherpad-lite/tasks/main.yml117
-rw-r--r--roles/apps/etherpad-lite/templates/nginx-vhost.conf.j257
-rw-r--r--roles/apps/etherpad-lite/templates/pod-with-mariadb.yml.j253
-rw-r--r--roles/apps/nextcloud/defaults/main.yml27
-rw-r--r--roles/apps/nextcloud/tasks/main.yml170
-rw-r--r--roles/apps/nextcloud/templates/apache-site.conf.j210
-rw-r--r--roles/apps/nextcloud/templates/cron-.timer.j29
-rw-r--r--roles/apps/nextcloud/templates/cron@.service.j215
-rwxr-xr-xroles/apps/nextcloud/templates/nextcloud-occ.j222
-rwxr-xr-xroles/apps/nextcloud/templates/nextcloud-upgrade.j242
-rw-r--r--roles/apps/nextcloud/templates/pod-with-mariadb.yml.j281
-rw-r--r--roles/apps/nextcloud/templates/run-cron.sh.j211
17 files changed, 823 insertions, 0 deletions
diff --git a/roles/apps/collabora/code/defaults/main.yml b/roles/apps/collabora/code/defaults/main.yml
new file mode 100644
index 00000000..f17054ed
--- /dev/null
+++ b/roles/apps/collabora/code/defaults/main.yml
@@ -0,0 +1,11 @@
+---
+collabora_code_base_path: /srv/collabora/code
+
+# collabora_code_instances:
+# example:
+# version: 4.0.6.1
+# port: 8200
+# hostnames:
+# - office.example.com
+# admin_user: admin
+# admin_password: S3cret
diff --git a/roles/apps/collabora/code/tasks/main.yml b/roles/apps/collabora/code/tasks/main.yml
new file mode 100644
index 00000000..ce88fe0d
--- /dev/null
+++ b/roles/apps/collabora/code/tasks/main.yml
@@ -0,0 +1,28 @@
+---
+- name: create collabora-code config subdirectory
+ loop: "{{ collabora_code_instances | list }}"
+ file:
+ path: "{{ collabora_code_base_path }}/{{ item }}/config"
+ state: directory
+
+## TODO: render config.xml
+
+- name: generate pod manifests
+ loop: "{{ collabora_code_instances | dict2items }}"
+ loop_control:
+ label: "{{ item.key }}"
+ template:
+ src: "pod.yml.j2"
+ dest: "/etc/kubernetes/manifests/collabora-code-{{ item.key }}.yml"
+ mode: 0600
+
+- name: configure nginx vhost
+ loop: "{{ collabora_code_instances | dict2items }}"
+ include_role:
+ name: nginx/vhost
+ vars:
+ nginx_vhost:
+ name: "collabora-code-{{ item.key }}"
+ content: "{{ lookup('template', 'nginx-vhost.conf.j2') }}"
+ acme: true
+ hostnames: "{{ item.value.hostnames }}"
diff --git a/roles/apps/collabora/code/templates/nginx-vhost.conf.j2 b/roles/apps/collabora/code/templates/nginx-vhost.conf.j2
new file mode 100644
index 00000000..cec811f9
--- /dev/null
+++ b/roles/apps/collabora/code/templates/nginx-vhost.conf.j2
@@ -0,0 +1,108 @@
+server {
+ listen 80;
+ listen [::]:80;
+ server_name {{ item.value.hostnames | join(' ') }};
+
+ include snippets/acmetool.conf;
+
+ location / {
+ return 301 https://$host$request_uri;
+ }
+}
+
+server {
+ listen 443 ssl http2;
+ listen [::]:443 ssl http2;
+ server_name {{ item.value.hostnames | join(' ') }};
+
+ include snippets/acmetool.conf;
+ include snippets/tls.conf;
+ ssl_certificate /var/lib/acme/live/{{ item.value.hostnames[0] }}/fullchain;
+ ssl_certificate_key /var/lib/acme/live/{{ item.value.hostnames[0] }}/privkey;
+ include snippets/hsts.conf;
+
+
+ client_max_body_size 128M;
+
+ # static files
+ location ^~ /loleaflet {
+ include snippets/proxy-nobuff.conf;
+ include snippets/proxy-forward-headers.conf;
+
+ proxy_set_header Host $http_host;
+ proxy_pass http://127.0.0.1:{{ item.value.port }};
+
+ proxy_redirect http://$host/ https://$host/;
+ proxy_redirect http://$host:9980/ https://$host/;
+ }
+
+ # WOPI discovery URL
+ location ^~ /hosting/discovery {
+ include snippets/proxy-nobuff.conf;
+ include snippets/proxy-forward-headers.conf;
+
+ proxy_set_header Host $http_host;
+ proxy_pass http://127.0.0.1:{{ item.value.port }};
+
+ proxy_redirect http://$host/ https://$host/;
+ proxy_redirect http://$host:9980/ https://$host/;
+ }
+
+ # Capabilities
+ location ^~ /hosting/capabilities {
+ include snippets/proxy-nobuff.conf;
+ include snippets/proxy-forward-headers.conf;
+
+ proxy_set_header Host $http_host;
+ proxy_pass http://127.0.0.1:{{ item.value.port }};
+
+ proxy_redirect http://$host/ https://$host/;
+ proxy_redirect http://$host:9980/ https://$host/;
+ }
+
+ # main websocket
+ location ~ ^/lool/(.*)/ws$ {
+ include snippets/proxy-nobuff.conf;
+ include snippets/proxy-forward-headers.conf;
+
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection $connection_upgrade;
+
+ proxy_read_timeout 36000s;
+
+ proxy_set_header Host $http_host;
+ proxy_pass http://127.0.0.1:{{ item.value.port }};
+
+ proxy_redirect http://$host/ https://$host/;
+ proxy_redirect http://$host:9980/ https://$host/;
+ }
+
+ # download, presentation and image upload
+ location ~ ^/lool {
+ include snippets/proxy-nobuff.conf;
+ include snippets/proxy-forward-headers.conf;
+
+ proxy_set_header Host $http_host;
+ proxy_pass http://127.0.0.1:{{ item.value.port }};
+
+ proxy_redirect http://$host/ https://$host/;
+ proxy_redirect http://$host:9980/ https://$host/;
+ }
+
+ # Admin Console websocket
+ location ^~ /lool/adminws {
+ include snippets/proxy-nobuff.conf;
+ include snippets/proxy-forward-headers.conf;
+
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection $connection_upgrade;
+
+ proxy_read_timeout 36000s;
+
+ proxy_set_header Host $http_host;
+ proxy_pass http://127.0.0.1:{{ item.value.port }};
+
+ proxy_redirect http://$host/ https://$host/;
+ proxy_redirect http://$host:9980/ https://$host/;
+ }
+}
diff --git a/roles/apps/collabora/code/templates/pod.yml.j2 b/roles/apps/collabora/code/templates/pod.yml.j2
new file mode 100644
index 00000000..ee4651a1
--- /dev/null
+++ b/roles/apps/collabora/code/templates/pod.yml.j2
@@ -0,0 +1,33 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: "collabora-code-{{ item.key }}"
+spec:
+ containers:
+ - name: collabora-code
+ image: "collabora/code:{{ item.value.version }}"
+ resources:
+ limits:
+ memory: "4Gi"
+ env:
+ - name: "DONT_GEN_SSL_CERT"
+ value: "1"
+ - name: "username"
+ value: "{{ item.value.admin_user }}"
+ - name: "password"
+ value: "{{ item.value.admin_password }}"
+ - name: "extra_params"
+ value: "--o:ssl.enable=false --o:ssl.termination=true"
+ volumeMounts:
+ - name: config
+ mountPath: /etc/loolwsd/loolwsd.xml
+ subPath: loolwsd.xml
+ readOnly: true
+ ports:
+ - containerPort: 9980
+ hostPort: {{ item.value.port }}
+ volumes:
+ - name: config
+ hostPath:
+ path: "{{ collabora_code_base_path }}/{{ item.key }}/config/"
+ type: Directory
diff --git a/roles/apps/etherpad-lite/defaults/main.yml b/roles/apps/etherpad-lite/defaults/main.yml
new file mode 100644
index 00000000..5281c739
--- /dev/null
+++ b/roles/apps/etherpad-lite/defaults/main.yml
@@ -0,0 +1,29 @@
+---
+etherpad_lite_app_uid: "940"
+etherpad_lite_app_gid: "940"
+
+etherpad_lite_db_uid: "941"
+etherpad_lite_db_gid: "941"
+
+# etherpad_lite_base_path: /srv/etherpad_lite
+
+# etherpad_lite_zfs:
+# pool: storage
+# name: etherpad_lite
+# size: 20G
+
+# etherpad_lite_instances:
+# example:
+# version: 1.7.5
+# port: 8300
+# hostnames:
+# - pad.example.com
+# quota: 40G
+# settings:
+# ....
+# credentials:
+# ....
+# database:
+# type: mariadb
+# version: 10.4.8
+# password: "{{ vault_etherpad_lite_database_passwords['example'] }}"
diff --git a/roles/apps/etherpad-lite/tasks/main.yml b/roles/apps/etherpad-lite/tasks/main.yml
new file mode 100644
index 00000000..6d4551db
--- /dev/null
+++ b/roles/apps/etherpad-lite/tasks/main.yml
@@ -0,0 +1,117 @@
+---
+- name: create zfs datasets
+ when: etherpad_lite_zfs is defined
+ block:
+ - name: create zfs base dataset
+ zfs:
+ name: "{{ etherpad_lite_zfs.pool }}/{{ etherpad_lite_zfs.name }}"
+ state: present
+ extra_zfs_properties:
+ quota: "{{ etherpad_lite_zfs.size }}"
+
+ - name: create zfs volumes for instances
+ loop: "{{ etherpad_lite_instances | dict2items }}"
+ loop_control:
+ label: "{{ item.key }} ({{ item.value.quota }})"
+ zfs:
+ name: "{{ etherpad_lite_zfs.pool }}/{{ etherpad_lite_zfs.name }}/{{ item.key }}"
+ state: present
+ extra_zfs_properties:
+ quota: "{{ item.value.quota }}"
+
+ - name: configure etherpad_lite base bath
+ set_fact:
+ etherpad_lite_base_path: "{{ zfs_zpools[etherpad_lite_zfs.pool].mountpoint }}/{{ etherpad_lite_zfs.name }}"
+
+
+- name: create instance subdirectories
+ when: etherpad_lite_zfs is not defined
+ loop: "{{ etherpad_lite_instances | list }}"
+ file:
+ path: "{{ etherpad_lite_base_path }}/{{ item }}"
+ state: directory
+
+
+
+- name: add group for etherpad-lite app
+ group:
+ name: epl-app
+ gid: "{{ etherpad_lite_app_gid }}"
+
+- name: add user for etherpad-lite app
+ user:
+ name: epl-app
+ uid: "{{ etherpad_lite_app_uid }}"
+ group: epl-app
+ password: "!"
+
+- name: create etherpad_lite app subdirectory
+ loop: "{{ etherpad_lite_instances | list }}"
+ file:
+ path: "{{ etherpad_lite_base_path }}/{{ item }}/etherpad-lite"
+ owner: "{{ etherpad_lite_app_uid }}"
+ group: "{{ etherpad_lite_app_gid }}"
+ state: directory
+
+
+- name: add group for etherpad-lite db
+ group:
+ name: epl-db
+ gid: "{{ etherpad_lite_db_gid }}"
+
+- name: add user for etherpad-lite db
+ user:
+ name: epl-db
+ uid: "{{ etherpad_lite_db_uid }}"
+ group: epl-db
+ password: "!"
+
+- name: create etherpad-lite database subdirectory
+ loop: "{{ etherpad_lite_instances | dict2items}}"
+ loop_control:
+ label: "{{ item.key }} ({{ item.value.database.type }})"
+ file:
+ path: "{{ etherpad_lite_base_path }}/{{ item.key }}/{{ item.value.database.type }}"
+ owner: "{{ etherpad_lite_db_uid }}"
+ group: "{{ etherpad_lite_db_gid }}"
+ state: directory
+
+
+- name: create etherpad-lite config directory
+ loop: "{{ etherpad_lite_instances | list }}"
+ file:
+ path: "{{ etherpad_lite_base_path }}/{{ item }}/config"
+ state: directory
+
+- name: create settings json
+ loop: "{{ etherpad_lite_instances | dict2items }}"
+ loop_control:
+ label: "{{ item.key }}"
+ copy:
+ content: "{{ item.value.settings | combine({'ip': '0.0.0.0', 'port': 9001}) | to_nice_json }}"
+ dest: "{{ etherpad_lite_base_path }}/{{ item.key }}/config/settings.json"
+ mode: 0600
+ owner: "{{ etherpad_lite_app_uid }}"
+ group: "{{ etherpad_lite_app_gid }}"
+
+
+- name: generate pod manifests
+ loop: "{{ etherpad_lite_instances | dict2items }}"
+ loop_control:
+ label: "{{ item.key }}"
+ template:
+ src: "pod-with-{{ item.value.database.type }}.yml.j2"
+ dest: "/etc/kubernetes/manifests/etherpad-lite-{{ item.key }}.yml"
+ mode: 0600
+
+
+- name: configure nginx vhost
+ loop: "{{ etherpad_lite_instances | dict2items }}"
+ include_role:
+ name: nginx/vhost
+ vars:
+ nginx_vhost:
+ name: "etherpad-lite-{{ item.key }}"
+ content: "{{ lookup('template', 'nginx-vhost.conf.j2') }}"
+ acme: true
+ hostnames: "{{ item.value.hostnames }}"
diff --git a/roles/apps/etherpad-lite/templates/nginx-vhost.conf.j2 b/roles/apps/etherpad-lite/templates/nginx-vhost.conf.j2
new file mode 100644
index 00000000..b59701fc
--- /dev/null
+++ b/roles/apps/etherpad-lite/templates/nginx-vhost.conf.j2
@@ -0,0 +1,57 @@
+server {
+ listen 80;
+ listen [::]:80;
+ server_name {{ item.value.hostnames | join(' ') }};
+
+ include snippets/acmetool.conf;
+
+ location / {
+ return 301 https://$host$request_uri;
+ }
+}
+
+server {
+ listen 443 ssl http2;
+ listen [::]:443 ssl http2;
+ server_name {{ item.value.hostnames | join(' ') }};
+
+ include snippets/acmetool.conf;
+ include snippets/tls.conf;
+ ssl_certificate /var/lib/acme/live/{{ item.value.hostnames[0] }}/fullchain;
+ ssl_certificate_key /var/lib/acme/live/{{ item.value.hostnames[0] }}/privkey;
+ include snippets/hsts.conf;
+
+ location / {
+ rewrite ^/$ / break;
+ rewrite ^/locales/(.*) /locales/$1 break;
+ rewrite ^/locales.json /locales.json break;
+ rewrite ^/admin(.*) /admin$1 break;
+ rewrite ^/p/(.*) /p/$1 break;
+ rewrite ^/static/(.*) /static/$1 break;
+ rewrite ^/pluginfw/(.*) /pluginfw/$1 break;
+ rewrite ^/javascripts/(.*) /javascripts/$1 break;
+ rewrite ^/socket.io/(.*) /socket.io/$1 break;
+ rewrite ^/ep/(.*) /ep/$1 break;
+ rewrite ^/minified/(.*) /minified/$1 break;
+ rewrite ^/api/(.*) /api/$1 break;
+ rewrite ^/ro/(.*) /ro/$1 break;
+ rewrite ^/error/(.*) /error/$1 break;
+ rewrite ^/jserror(.*) /jserror$1 break;
+ rewrite ^/redirect(.*) /redirect$1 break;
+ rewrite /favicon.ico /favicon.ico break;
+ rewrite /robots.txt /robots.txt break;
+ rewrite /(.*) /p/$1;
+
+ include snippets/proxy-nobuff.conf;
+
+ proxy_set_header Host $host;
+ include snippets/proxy-forward-headers.conf;
+ proxy_pass_header Server;
+
+ # for websockets
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection $connection_upgrade;
+
+ proxy_pass http://127.0.0.1:{{ item.value.port }};
+ }
+}
diff --git a/roles/apps/etherpad-lite/templates/pod-with-mariadb.yml.j2 b/roles/apps/etherpad-lite/templates/pod-with-mariadb.yml.j2
new file mode 100644
index 00000000..a4acdd21
--- /dev/null
+++ b/roles/apps/etherpad-lite/templates/pod-with-mariadb.yml.j2
@@ -0,0 +1,53 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: "etherpad-lite-{{ item.key }}"
+spec:
+ securityContext:
+ allowPrivilegeEscalation: false
+ containers:
+ - name: etherpad-lite
+ image: spreadspace/etherpad-lite:{{ item.value.version }}
+ # securityContext:
+ # runAsUser: {{ etherpad_lite_app_uid }}
+ # runAsGroup: {{ etherpad_lite_app_gid }}
+ resources:
+ limits:
+ memory: "4Gi"
+ volumeMounts:
+ - name: config
+ mountPath: /opt/etherpad-lite/settings.json
+ subPath: settings.json
+ readOnly: true
+ ports:
+ - containerPort: 9001
+ hostPort: {{ item.value.port }}
+ - name: database
+ image: "mariadb:{{ item.value.database.version }}"
+ securityContext:
+ runAsUser: {{ etherpad_lite_db_uid }}
+ runAsGroup: {{ etherpad_lite_db_gid }}
+ resources:
+ limits:
+ memory: "4Gi"
+ env:
+ - name: MYSQL_RANDOM_ROOT_PASSWORD
+ value: "true"
+ - name: MYSQL_DATABASE
+ value: etherpad-lite
+ - name: MYSQL_USER
+ value: etherpad-lite
+ - name: MYSQL_PASSWORD
+ value: "{{ item.value.database.password }}"
+ volumeMounts:
+ - name: database
+ mountPath: /var/lib/mysql
+ volumes:
+ - name: config
+ hostPath:
+ path: "{{ etherpad_lite_base_path }}/{{ item.key }}/config/"
+ type: Directory
+ - name: database
+ hostPath:
+ path: "{{ etherpad_lite_base_path }}/{{ item.key }}/{{ item.value.database.type }}"
+ type: Directory
diff --git a/roles/apps/nextcloud/defaults/main.yml b/roles/apps/nextcloud/defaults/main.yml
new file mode 100644
index 00000000..16637f44
--- /dev/null
+++ b/roles/apps/nextcloud/defaults/main.yml
@@ -0,0 +1,27 @@
+---
+nextcloud_app_uid: "950"
+nextcloud_app_gid: "950"
+
+nextcloud_db_uid: "951"
+nextcloud_db_gid: "951"
+
+# nextcloud_base_path: /srv/nextcloud
+
+# nextcloud_zfs:
+# pool: storage
+# name: nextcloud
+# size: 500G
+
+# nextcloud_instances:
+# example:
+# new: yes
+# version: 17.0.0
+# port: 8100
+# hostnames:
+# - wolke.example.com
+# - cloud.example.com
+# quota: 100G
+# database:
+# type: mariadb
+# version: 10.4.8
+# password: "{{ vault_nextcloud_database_passwords['example'] }}"
diff --git a/roles/apps/nextcloud/tasks/main.yml b/roles/apps/nextcloud/tasks/main.yml
new file mode 100644
index 00000000..a951867c
--- /dev/null
+++ b/roles/apps/nextcloud/tasks/main.yml
@@ -0,0 +1,170 @@
+---
+- name: create zfs datasets
+ when: nextcloud_zfs is defined
+ block:
+ - name: create zfs base dataset
+ zfs:
+ name: "{{ nextcloud_zfs.pool }}/{{ nextcloud_zfs.name }}"
+ state: present
+ extra_zfs_properties:
+ quota: "{{ nextcloud_zfs.size }}"
+
+ - name: create zfs volumes for instances
+ loop: "{{ nextcloud_instances | dict2items }}"
+ loop_control:
+ label: "{{ item.key }} ({{ item.value.quota }})"
+ zfs:
+ name: "{{ nextcloud_zfs.pool }}/{{ nextcloud_zfs.name }}/{{ item.key }}"
+ state: present
+ extra_zfs_properties:
+ quota: "{{ item.value.quota }}"
+
+ - name: configure nextcloud base bath
+ set_fact:
+ nextcloud_base_path: "{{ zfs_zpools[nextcloud_zfs.pool].mountpoint }}/{{ nextcloud_zfs.name }}"
+
+
+- name: create instance subdirectories
+ when: nextcloud_zfs is not defined
+ loop: "{{ nextcloud_instances | list }}"
+ file:
+ path: "{{ nextcloud_base_path }}/{{ item }}"
+ state: directory
+
+
+
+- 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: create nextcloud app subdirectory
+ loop: "{{ nextcloud_instances | list }}"
+ file:
+ path: "{{ nextcloud_base_path }}/{{ item }}/nextcloud"
+ owner: "{{ nextcloud_app_uid }}"
+ group: "{{ nextcloud_app_gid }}"
+ state: directory
+
+
+- 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: create nextcloud database subdirectory
+ loop: "{{ nextcloud_instances | dict2items}}"
+ loop_control:
+ label: "{{ item.key }} ({{ item.value.database.type }})"
+ file:
+ path: "{{ nextcloud_base_path }}/{{ item.key }}/{{ item.value.database.type }}"
+ owner: "{{ nextcloud_db_uid }}"
+ group: "{{ nextcloud_db_gid }}"
+ state: directory
+
+
+- name: create auxiliary config directory
+ loop: "{{ nextcloud_instances | list }}"
+ file:
+ path: "{{ nextcloud_base_path }}/{{ item }}/config"
+ state: directory
+
+- name: create apache vhost config
+ loop: "{{ nextcloud_instances | list }}"
+ template:
+ src: apache-site.conf.j2
+ dest: "{{ nextcloud_base_path }}/{{ item }}/config/apache-site.conf"
+
+- name: configure apache to run on port 8080 only
+ loop: "{{ nextcloud_instances | list }}"
+ copy:
+ content: |
+ Listen 8080
+ dest: "{{ nextcloud_base_path }}/{{ item }}/config/ports.conf"
+
+
+- name: generate pod manifests
+ loop: "{{ nextcloud_instances | dict2items }}"
+ loop_control:
+ label: "{{ item.key }}"
+ template:
+ src: "pod-with-{{ item.value.database.type }}.yml.j2"
+ dest: "/etc/kubernetes/manifests/nextcloud-{{ item.key }}.yml"
+ mode: 0600
+
+
+- name: install cron trigger script
+ loop: "{{ nextcloud_instances | list }}"
+ template:
+ src: run-cron.sh.j2
+ dest: "{{ nextcloud_base_path }}/{{ item }}/config/run-cron.sh"
+ mode: 0755
+
+- name: install template systemd unit for cron trigger
+ template:
+ src: cron@.service.j2
+ dest: /etc/systemd/system/nextcloud-cron@.service
+
+- name: install systemd timer unit
+ loop: "{{ nextcloud_instances | list }}"
+ template:
+ src: cron-.timer.j2
+ dest: "/etc/systemd/system/nextcloud-cron-{{ item }}.timer"
+
+- name: start/enable cron trigger systemd timer
+ loop: "{{ nextcloud_instances | list }}"
+ systemd:
+ daemon_reload: yes
+ name: "nextcloud-cron-{{ item }}.timer"
+ state: started
+ enabled: yes
+
+
+- name: configure nginx vhost
+ loop: "{{ nextcloud_instances | dict2items }}"
+ include_role:
+ name: nginx/vhost
+ vars:
+ nginx_vhost:
+ name: "nextcloud-{{ item.key }}"
+ template: generic-proxy-no-buffering-with-acme
+ acme: true
+ hostnames: "{{ item.value.hostnames }}"
+ client_max_body_size: "512M"
+ proxy_pass: "http://127.0.0.1:{{ item.value.port }}"
+ proxy_redirect:
+ - redirect: "http://$host/"
+ replacement: "https://$host/"
+ - redirect: "http://$host:8080/"
+ replacement: "https://$host/"
+
+
+- name: install management scripts
+ loop:
+ - nextcloud-upgrade
+ - nextcloud-occ
+ template:
+ src: "{{ item }}.j2"
+ dest: "/usr/local/bin/{{ item }}"
+ mode: 0755
+
+## TODO:
+# run this after installation is complete:
+#
+# nextcloud-occ {{ instance }} db:add-missing-indices
+# nextcloud-occ {{ instance }} db:convert-filecache-bigint
+#
diff --git a/roles/apps/nextcloud/templates/apache-site.conf.j2 b/roles/apps/nextcloud/templates/apache-site.conf.j2
new file mode 100644
index 00000000..a52a7fc5
--- /dev/null
+++ b/roles/apps/nextcloud/templates/apache-site.conf.j2
@@ -0,0 +1,10 @@
+<VirtualHost *:8080>
+ ServerAdmin webmaster@localhost
+ DocumentRoot /var/www/html
+
+ UseCanonicalName Off
+ UseCanonicalPhysicalPort Off
+
+ ErrorLog ${APACHE_LOG_DIR}/error.log
+ CustomLog ${APACHE_LOG_DIR}/access.log combined
+</VirtualHost>
diff --git a/roles/apps/nextcloud/templates/cron-.timer.j2 b/roles/apps/nextcloud/templates/cron-.timer.j2
new file mode 100644
index 00000000..0c3f7cd7
--- /dev/null
+++ b/roles/apps/nextcloud/templates/cron-.timer.j2
@@ -0,0 +1,9 @@
+[Unit]
+Description=Nextcloud cron.php job timer for %i
+
+[Timer]
+OnCalendar=*:{{ 5 | random(seed=item) }}/5
+Unit=nextcloud-cron@{{ item }}.service
+
+[Install]
+WantedBy=timers.target
diff --git a/roles/apps/nextcloud/templates/cron@.service.j2 b/roles/apps/nextcloud/templates/cron@.service.j2
new file mode 100644
index 00000000..822f64b4
--- /dev/null
+++ b/roles/apps/nextcloud/templates/cron@.service.j2
@@ -0,0 +1,15 @@
+[Unit]
+Description=Nextcloud cron.php job for %i
+
+[Service]
+Type=oneshot
+ExecStart={{ 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/apps/nextcloud/templates/nextcloud-occ.j2 b/roles/apps/nextcloud/templates/nextcloud-occ.j2
new file mode 100755
index 00000000..a79c5335
--- /dev/null
+++ b/roles/apps/nextcloud/templates/nextcloud-occ.j2
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+INST_NAME="$1"
+shift
+
+if [ -z "$INST_NAME" ]; then
+ echo "Usage: $0 <instance> [ <arguments for occ.php> ... ]"
+ exit 1
+fi
+
+set -eu
+{% if kubernetes_cri_socket is defined %}
+export CONTAINER_RUNTIME_ENDPOINT="{{ kubernetes_cri_socket }}"
+{% endif %}
+
+pod_id=$(crictl pods -q --state ready --name "$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/apps/nextcloud/templates/nextcloud-upgrade.j2 b/roles/apps/nextcloud/templates/nextcloud-upgrade.j2
new file mode 100755
index 00000000..aac5001f
--- /dev/null
+++ b/roles/apps/nextcloud/templates/nextcloud-upgrade.j2
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+INST_NAME="$1"
+VERSION="$2"
+if [ -z "$INST_NAME" ] || [ -z "$VERSION" ]; then
+ echo "Usage: $0 <instance> <version>"
+ exit 1
+fi
+
+set -eu
+
+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
+
+echo "*** Pre-Pulling the image"
+echo ""
+ctr -n k8s.io image pull "docker.io/library/nextcloud:$VERSION"
+echo ""
+
+echo "*** Patching manifest file"
+echo ""
+sed "s#image: \"nextcloud:.*\"#image: \"nextcloud:$VERSION\"#" "$K8S_MANIFEST_FILE" > "$TMP_D/upgraded.yml"
+set +e
+diff -u "$K8S_MANIFEST_FILE" "$TMP_D/upgraded.yml"
+if [ $? -eq 0 ]; then
+ echo "patching file failed?"
+ exit 2
+fi
+cat "$TMP_D/upgraded.yml" > "$K8S_MANIFEST_FILE"
+echo ""
+
+exit 0
diff --git a/roles/apps/nextcloud/templates/pod-with-mariadb.yml.j2 b/roles/apps/nextcloud/templates/pod-with-mariadb.yml.j2
new file mode 100644
index 00000000..dfef3810
--- /dev/null
+++ b/roles/apps/nextcloud/templates/pod-with-mariadb.yml.j2
@@ -0,0 +1,81 @@
+apiVersion: v1
+kind: Pod
+metadata:
+ name: "nextcloud-{{ item.key }}"
+spec:
+ securityContext:
+ allowPrivilegeEscalation: false
+ containers:
+ - name: nextcloud
+ image: "nextcloud:{{ item.value.version }}"
+ securityContext:
+ runAsUser: {{ nextcloud_app_uid }}
+ runAsGroup: {{ nextcloud_app_gid }}
+ resources:
+ limits:
+ memory: "4Gi"
+{% if 'new' in item.value and item.value.new %}
+ env:
+ - name: NEXTCLOUD_TRUSTED_DOMAINS
+ value: "{{ item.value.hostnames | join(' ') }}"
+ - name: MYSQL_HOST
+ value: 127.0.0.1
+ - name: MYSQL_DATABASE
+ value: nextcloud
+ - name: MYSQL_USER
+ value: nextcloud
+ - name: MYSQL_PASSWORD
+ value: "{{ item.value.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: {{ item.value.port }}
+ - name: database
+ image: "mariadb:{{ item.value.database.version }}"
+ args:
+ - --transaction-isolation=READ-COMMITTED
+ - --binlog-format=ROW
+ securityContext:
+ runAsUser: {{ nextcloud_db_uid }}
+ runAsGroup: {{ nextcloud_db_gid }}
+ resources:
+ limits:
+ memory: "2Gi"
+{% if 'new' in item.value and item.value.new %}
+ env:
+ - name: MYSQL_RANDOM_ROOT_PASSWORD
+ value: "true"
+ - name: MYSQL_DATABASE
+ value: nextcloud
+ - name: MYSQL_USER
+ value: nextcloud
+ - name: MYSQL_PASSWORD
+ value: "{{ item.value.database.password }}"
+{% endif %}
+ volumeMounts:
+ - name: database
+ mountPath: /var/lib/mysql
+ volumes:
+ - name: config
+ hostPath:
+ path: "{{ nextcloud_base_path }}/{{ item.key }}/config/"
+ type: Directory
+ - name: nextcloud
+ hostPath:
+ path: "{{ nextcloud_base_path }}/{{ item.key }}/nextcloud"
+ type: Directory
+ - name: database
+ hostPath:
+ path: "{{ nextcloud_base_path }}/{{ item.key }}/{{ item.value.database.type }}"
+ type: Directory
diff --git a/roles/apps/nextcloud/templates/run-cron.sh.j2 b/roles/apps/nextcloud/templates/run-cron.sh.j2
new file mode 100644
index 00000000..9936bad1
--- /dev/null
+++ b/roles/apps/nextcloud/templates/run-cron.sh.j2
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+{% if kubernetes_cri_socket is defined %}
+export CONTAINER_RUNTIME_ENDPOINT="{{ kubernetes_cri_socket }}"
+{% endif %}
+
+POD_NAME="{{ item }}-$(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