Compare commits

...

16 Commits

Author SHA1 Message Date
9469452275 Finalized matomo integration into new architecture 2025-07-17 12:09:20 +02:00
fd8ef26b53 Solved streaming bugs 2025-07-17 09:47:08 +02:00
8cda54c46e Finished moodle adaptation to new structure 2025-07-17 09:18:24 +02:00
90bc52632e Moved web-app-phpmyadmin to new structure 2025-07-17 08:24:07 +02:00
0b8d2e0b40 Solved variable bug 2025-07-17 08:22:59 +02:00
40491dbc2e Solved typos in port-ui 2025-07-17 07:54:19 +02:00
fac8971982 Solved typo 2025-07-17 07:49:05 +02:00
c791e86b8b Solved discourse variable bug 2025-07-17 07:46:39 +02:00
d222b55f30 Changed espocrm application id to new forma 2025-07-17 07:43:50 +02:00
a04a1710d3 Changed keycloak application id 2025-07-17 07:16:38 +02:00
4f06f94023 Added credentials replacement draft for matomo 2025-07-17 06:57:35 +02:00
2529c7cdb3 Optimized moodle variables 2025-07-17 06:56:54 +02:00
ab12a933f6 Optimized keycloak variables 2025-07-17 06:56:26 +02:00
529efc0bd7 Optimized moodle variable names 2025-07-17 06:38:51 +02:00
725fea1169 Solved database credentials bug 2025-07-17 06:32:53 +02:00
84322f81ef Implemented draft for auto database credentials change moodle 2025-07-17 06:31:55 +02:00
40 changed files with 235 additions and 166 deletions

View File

@@ -1,50 +0,0 @@
# filter_plugins/get_cymais_path.py
"""
This plugin provides filters to extract the CyMaIS directory and file identifiers
from a given role name. It assumes the role name is structured as 'dir_file'.
If the structure is invalid (e.g., missing or too many underscores), it raises an error.
These filters are used to support internal processing within CyMaIS.
"""
from ansible.errors import AnsibleFilterError
class CymaisPathExtractor:
"""Extracts directory and file parts from role names in the format 'dir_file'."""
def __init__(self, value):
self.value = value
self._parts = self._split_value()
def _split_value(self):
parts = self.value.split("_")
if len(parts) != 2:
raise AnsibleFilterError(
f"Invalid format: '{self.value}' must contain exactly one underscore (_)"
)
return parts
def get_dir(self):
return self._parts[0]
def get_file(self):
return self._parts[1]
def get_cymais_dir(value):
return CymaisPathExtractor(value).get_dir()
def get_cymais_file(value):
return CymaisPathExtractor(value).get_file()
class FilterModule(object):
"""Ansible filter plugin for CyMaIS path parsing."""
def filters(self):
return {
"get_cymais_dir": get_cymais_dir,
"get_cymais_file": get_cymais_file,
}

View File

@@ -0,0 +1,17 @@
class FilterModule(object):
def filters(self):
return {
'get_public_id': self.get_public_id
}
def get_public_id(self, value):
"""
Extract the substring after the last hyphen in the input string.
Example:
'service-user-abc123' => 'abc123'
"""
if not isinstance(value, str):
raise ValueError("Expected a string")
if '-' not in value:
raise ValueError("No hyphen found in input string")
return value.rsplit('-', 1)[-1]

View File

@@ -7,9 +7,9 @@ ports:
# https://developer.mozilla.org/de/docs/Web/API/WebSockets_API
websocket:
web-app-mastodon: 4001
espocrm: 4002
web-app-espocrm: 4002
oauth2_proxy:
phpmyadmin: 4181
web-app-phpmyadmin: 4181
lam: 4182
web-app-openproject: 4183
yourls: 4184
@@ -46,21 +46,21 @@ ports:
web-app-openproject: 8023
gitlab: 8024
web-app-akaunting: 8025
moodle: 8026
web-app-moodle: 8026
taiga: 8027
friendica: 8028
web-app-port-ui: 8029
bluesky_api: 8030
bluesky_web: 8031
keycloak: 8032
web-app-keycloak: 8032
lam: 8033
phpmyadmin: 8034
web-app-phpmyadmin: 8034
snipe-it: 8035
sphinx: 8036
phpldapadmin: 8037
fusiondirectory: 8038
presentation: 8039
espocrm: 8040
web-app-espocrm: 8040
syncope: 8041
collabora: 8042
mobilizon: 8043

View File

@@ -28,7 +28,7 @@ defaults_networks:
subnet: 192.168.101.128/28
web-app-joomla:
subnet: 192.168.101.144/28
keycloak:
web-app-keycloak:
subnet: 192.168.101.160/28
web-app-wordpress:
subnet: 192.168.101.176/28
@@ -46,7 +46,7 @@ defaults_networks:
# Use one of the last container ips for dns resolving so that it isn't used
dns: 192.168.102.29
subnet: 192.168.102.16/28
moodle:
web-app-moodle:
subnet: 192.168.102.32/28
web-app-mybb:
subnet: 192.168.102.48/28
@@ -56,7 +56,7 @@ defaults_networks:
subnet: 192.168.102.80/28
web-app-peertube:
subnet: 192.168.102.96/28
phpmyadmin:
web-app-phpmyadmin:
subnet: 192.168.102.112/28
web-app-pixelfed:
subnet: 192.168.102.128/28
@@ -80,7 +80,7 @@ defaults_networks:
subnet: 192.168.103.32/28
presentation:
subnet: 192.168.103.48/28
espocrm:
web-app-espocrm:
subnet: 192.168.103.64/28
syncope:
subnet: 192.168.103.80/28

View File

@@ -12,7 +12,7 @@ _oidc_client_realm: "{{ oidc.client.realm if oidc.client is defined and
_oidc_url: "{{
(oidc.url
if (oidc is defined and oidc.url is defined)
else web_protocol ~ '://' ~ (domains | get_domain('keycloak'))
else web_protocol ~ '://' ~ (domains | get_domain('web-app-keycloak'))
)
}}"
_oidc_client_issuer_url: "{{ _oidc_url }}/realms/{{_oidc_client_realm}}"

View File

@@ -1,13 +1,12 @@
# Helper variables
_database_id: "svc-db-{{ database_type }}"
_database_central_name: "{{ applications | get_app_conf( _database_id, 'docker.services.' ~ database_type ~ '.name') }}"
_database_central_user: "{{ database_type }}"
# Definition
database_name: "{{ applications | get_app_conf( database_application_id, 'database.name', false, _database_central_name ) }}" # The overwritte configuration is needed by bigbluebutton
database_name: "{{ applications | get_app_conf( database_application_id, 'database.name', false, database_application_id | get_public_id ) }}" # The overwritte configuration is needed by bigbluebutton
database_instance: "{{ _database_central_name if applications | get_app_conf(database_application_id, 'features.central_database', False) else database_name }}" # This could lead to bugs at dedicated database @todo cleanup
database_host: "{{ _database_central_name if applications | get_app_conf(database_application_id, 'features.central_database', False) else 'database' }}" # This could lead to bugs at dedicated database @todo cleanup
database_username: "{{ applications | get_app_conf(database_application_id, 'database.username', false, _database_central_user )}}" # The overwritte configuration is needed by bigbluebutton
database_username: "{{ applications | get_app_conf(database_application_id, 'database.username', false, database_application_id | get_public_id)}}" # The overwritte configuration is needed by bigbluebutton
database_password: "{{ applications | get_app_conf(database_application_id, 'credentials.database_password', true) }}"
database_port: "{{ ports.localhost.database[ _database_id ] }}"
database_env: "{{docker_compose.directories.env}}{{database_type}}.env"

View File

@@ -6,7 +6,7 @@ docker:
services:
openldap:
image: "bitnami/openldap"
name: "optenldap"
name: "openldap"
version: "latest"
network: "openldap"
volumes:

View File

@@ -1,5 +1,3 @@
images:
espocrm: "espocrm/espocrm:latest"
features:
matomo: true
css: false
@@ -31,3 +29,9 @@ docker:
services:
database:
enabled: true
espocrm:
image: "espocrm/espocrm"
version: "latest"
name: "espocrm"
volumes:
data: espocrm_data

View File

@@ -1,6 +1,7 @@
{% include 'roles/docker-compose/templates/base.yml.j2' %}
web:
image: "{{ applications | get_app_conf(application_id, 'images.espocrm', True) }}"
container_name: {{ espocrm_name }}
image: "{{ espocrm_image }}:{{ espocrm_version }}"
{% include 'roles/docker-container/templates/base.yml.j2' %}
{% include 'roles/docker-container/templates/healthcheck/curl.yml.j2' %}
ports:
@@ -11,7 +12,7 @@
- data:/var/www/html
daemon:
image: "{{ applications | get_app_conf(application_id, 'images.espocrm', True) }}"
image: "{{ espocrm_image }}:{{ espocrm_version }}"
restart: {{docker_restart_policy}}
logging:
driver: journald
@@ -21,7 +22,7 @@
- data:/var/www/html
websocket:
image: "{{ applications | get_app_conf(application_id, 'images.espocrm', True) }}"
image: "{{ espocrm_image }}:{{ espocrm_version }}"
restart: {{docker_restart_policy}}
logging:
driver: journald
@@ -40,5 +41,6 @@
{% include 'roles/docker-compose/templates/volumes.yml.j2' %}
data:
name: {{ espocrm_volume }}
{% include 'roles/docker-compose/templates/networks.yml.j2' %}

View File

@@ -1,7 +1,11 @@
application_id: "espocrm"
application_id: "web-app-espocrm"
database_type: "mariadb"
ws_path: "/ws"
ws_port: "{{ ports.localhost.websocket[application_id] }}"
client_max_body_size: "100m"
vhost_flavour: "ws_generic"
docker_compose_flush_handlers: true
espocrm_version: "{{ applications | get_app_conf(application_id, 'docker.services.espocrm.version', True) }}"
espocrm_image: "{{ applications | get_app_conf(application_id, 'docker.services.espocrm.image', True) }}"
espocrm_name: "{{ applications | get_app_conf(application_id, 'docker.services.espocrm.name', True) }}"
espocrm_volume: "{{ applications | get_app_conf(application_id, 'docker.volumes.data', True) }}"

View File

@@ -27,6 +27,7 @@ docker:
keycloak:
image: "quay.io/keycloak/keycloak"
version: "latest"
name: "keycloak"
database:
enabled: true

View File

@@ -78,5 +78,5 @@
- name: Apply SSH Public Key to user-profile via kcadm
shell: |
docker exec -i {{ container_name }} \
docker exec -i {{ keycloak_container }} \
/opt/keycloak/bin/kcadm.sh update realms/{{ keycloak_realm }} -f {{ keycloak_docker_import_directory }}user-profile.json

View File

@@ -517,7 +517,7 @@
"/realms/{{ keycloak_realm }}/account/*"
],
"webOrigins": [
"{{ domains | get_url('keycloak', web_protocol) }}"
"{{ domains | get_url('web-app-keycloak', web_protocol) }}"
],
"notBefore": 0,
"bearerOnly": false,
@@ -1697,7 +1697,7 @@
"replyTo": "",
"host": "{{system_email.host}}",
"from": "{{ users['no-reply'].email }}",
"fromDisplayName": "Keycloak Authentification System - {{domains | get_domain('keycloak')}}",
"fromDisplayName": "Keycloak Authentification System - {{domains | get_domain('web-app-keycloak')}}",
"envelopeFrom": "",
"ssl": "true",
"user": "{{ users['no-reply'].email }}"

View File

@@ -1,6 +1,6 @@
application_id: "keycloak" # Internal CyMaIS application id
application_id: "web-app-keycloak" # Internal CyMaIS application id
database_type: "postgres" # Database which will be used
keycloak_container: "{{ application_id }}_application" # Name of the keycloack docker container
keycloak_container: "{{ applications | get_app_conf(application_id, 'docker.services.keycloak.name', True) }}" # Name of the keycloack docker container
keycloak_host_import_directory: "{{ docker_compose.directories.volumes }}import/" # Directory in which keycloack import files are placed on the host
keycloak_docker_import_directory: "/opt/keycloak/data/import/" # Directory in which keycloack import files are placed in the running docker container
keycloak_realm: "{{ primary_domain}}" # This is the name of the default realm which is used by the applications

View File

@@ -28,5 +28,6 @@ docker:
streaming:
image: "ghcr.io/mastodon/mastodon-streaming"
version: latest
name: "mastodon-streaming"
volumes:
data: "mastodon_data"

View File

@@ -6,7 +6,7 @@
- name: "Include setup for domain '{{ domain }}'"
include_role:
name: srv-proxy-6-6-domain
loop: "{{ domains.mastodon }}"
loop: "{{ domains['web-app-mastodon'] }}"
loop_control:
loop_var: domain
vars:

View File

@@ -24,7 +24,7 @@
command: node ./streaming
{% include 'roles/docker-container/templates/healthcheck/wget.yml.j2' %}
ports:
- "127.0.0.1:{{ports.localhost.websocket[application_id]}}:{{ container_port }}"
- "127.0.0.1:{{ ports.localhost.websocket[application_id] }}:{{ container_port }}"
{% include 'roles/docker-container/templates/depends_on/dmbs_excl.yml.j2' %}
{% include 'roles/docker-container/templates/networks.yml.j2' %}
@@ -37,7 +37,10 @@
volumes:
- data:/mastodon/public/system
healthcheck:
test: ['CMD-SHELL', "ps aux | grep '[s]idekiq\ 6' || false"]
test: ["CMD-SHELL", "pgrep -f sidekiq || exit 1"]
interval: 1m
timeout: 10s
retries: 3
{% include 'roles/docker-container/templates/networks.yml.j2' %}
{% include 'roles/docker-compose/templates/volumes.yml.j2' %}

View File

@@ -4,7 +4,7 @@
LOCAL_DOMAIN={{domains | get_domain(application_id)}}
ALTERNATE_DOMAINS="{{ domains.mastodon[1:] | join(',') }}"
ALTERNATE_DOMAINS="{{ domains['web-app-mastodon'][1:] | join(',') }}"
SINGLE_USER_MODE={{ applications | get_app_conf(application_id, 'single_user_mode', True) }}
# Credentials

View File

@@ -4,8 +4,8 @@ mastodon_version: "{{ applications | get_app_conf(application_id, 'd
mastodon_image: "{{ applications | get_app_conf(application_id, 'docker.services.mastodon.image', True) }}"
mastodon_name: "{{ applications | get_app_conf(application_id, 'docker.services.mastodon.name', True) }}"
mastodon_volume: "{{ applications | get_app_conf(application_id, 'docker.volumes.data', True) }}"
mastodon_streaming_version: "{{ applications | get_app_conf(application_id, 'docker.services.mastodon.version', True) }}"
mastodon_streaming_image: "{{ applications | get_app_conf(application_id, 'docker.services.mastodon.image', True) }}"
mastodon_streaming_name: "{{ applications | get_app_conf(application_id, 'docker.services.mastodon.name', True) }}_streaming"
mastodon_streaming_version: "{{ applications | get_app_conf(application_id, 'docker.services.streaming.version', True) }}"
mastodon_streaming_image: "{{ applications | get_app_conf(application_id, 'docker.services.streaming.image', True) }}"
mastodon_streaming_name: "{{ applications | get_app_conf(application_id, 'docker.services.streaming.name', True) }}"
mastodon_sidekiq_name: "{{ applications | get_app_conf(application_id, 'docker.services.mastodon.name', True) }}_sidekiq"
mastodon_setup: "{{ applications | get_app_conf(application_id, 'setup', True) }}"

View File

@@ -2,6 +2,9 @@
include_role:
name: cmp-db-docker-proxy
- name: "Update database credentials"
include_tasks: database.yml
- name: flush docker service
meta: flush_handlers

View File

@@ -0,0 +1,25 @@
- name: Backup config.ini.php before patching
command: >
docker cp {{ matomo_name }}:{{ matomo_config }} {{ matomo_backup_file }}
- name: Patch Matomo config.ini.php with updated DB credentials
block:
- name: Update DB host
command: >
docker exec --user root {{ matomo_name }}
sed -i "s/^host *=.*/host = {{ database_host }}/" {{ matomo_config }}
- name: Update DB name
command: >
docker exec --user root {{ matomo_name }}
sed -i "s/^dbname *=.*/dbname = {{ database_name }}/" {{ matomo_config }}
- name: Update DB user
command: >
docker exec --user root {{ matomo_name }}
sed -i "s/^username *=.*/username = {{ database_username }}/" {{ matomo_config }}
- name: Update DB password
command: >
docker exec --user root {{ matomo_name }}
sed -i "s/^password *=.*/password = {{ database_password }}/" {{ matomo_config }}

View File

@@ -1,5 +1,6 @@
{% include 'roles/docker-compose/templates/base.yml.j2' %}
application:
container_name: {{ matomo_name }}
{% set container_port = 80 %}
{% include 'roles/docker-container/templates/base.yml.j2' %}
image: "{{ matomo_image }}:{{ matomo_version }}"

View File

@@ -6,7 +6,10 @@ matomo_index_php_url: "{{ domains | get_url(application_id, web_protocol) }}/ind
matomo_auth_token: "{{ applications | get_app_conf(application_id, 'credentials.auth_token', True) }}"
matomo_version: "{{ applications | get_app_conf(application_id, 'docker.services.matomo.version', True) }}"
matomo_image: "{{ applications | get_app_conf(application_id, 'docker.services.matomo.image', True) }}"
matomo_name: "{{ applications | get_app_conf(application_id, 'docker.services.matomo.name', True) }}"
matomo_data: "{{ applications | get_app_conf(application_id, 'docker.volumes.data', True) }}"
matomo_backup_file: "{{ docker_compose.directories.instance }}/config.ini.php.bak"
matomo_config: "/var/www/html/config/config.ini.php"
# I don't know if this is still necessary
domain: "{{ domains | get_domain(application_id) }}"

View File

@@ -1,9 +1,8 @@
site_titel: "Academy on {{primary_domain}}"
version: "4.5" # Latest LTS - Necessary for OIDC
features:
matomo: true
css: false
port-ui-desktop: true
port-ui-desktop: true
central_database: true
oidc: true
csp:
@@ -28,4 +27,12 @@ domains:
docker:
services:
database:
enabled: true
enabled: true
moodle:
version: "4.5" # Latest LTS - Necessary for OIDC
image: bitnami/moodle
name: moodle
volumes:
data: moodle_data
code: moodle_code

View File

@@ -0,0 +1,47 @@
- name: Check if config.php exists
command: docker exec --user root {{ moodle_container }} test -f {{ moodle_config }}
register: config_file_exists
changed_when: false
failed_when: false
- name: Backup config.php to host
when: config_file_exists.rc == 0
block:
- name: Create backup directory on host
ansible.builtin.file:
path: "/opt/docker/moodle/_backup"
state: directory
mode: "0755"
- name: Copy config.php from container to host
command: >
docker cp {{ moodle_container }}:{{ moodle_config }} {{ moodle_backup_file }}
- name: Check if config.php exists
command: docker exec --user root {{ moodle_container }} test -f {{ moodle_config }}
register: config_file_exists
changed_when: false
failed_when: false
- name: Patch Moodle config.php with updated DB credentials
when: config_file_exists.rc == 0
block:
- name: Update DB host
command: >
docker exec --user root {{ moodle_container }}
sed -i "s/^\$CFG->dbhost *= *.*/\$CFG->dbhost = '{{ database_host }}';/" {{ moodle_config }}
- name: Update DB name
command: >
docker exec --user root {{ moodle_container }}
sed -i "s/^\$CFG->dbname *= *.*/\$CFG->dbname = '{{ database_name }}';/" {{ moodle_config }}
- name: Update DB user
command: >
docker exec --user root {{ moodle_container }}
sed -i "s/^\$CFG->dbuser *= *.*/\$CFG->dbuser = '{{ database_username }}';/" {{ moodle_config }}
- name: Update DB password
command: >
docker exec --user root {{ moodle_container }}
sed -i "s/^\$CFG->dbpass *= *.*/\$CFG->dbpass = '{{ database_password }}';/" {{ moodle_config }}

View File

@@ -3,8 +3,14 @@
include_role:
name: cmp-db-docker-proxy
- name: "Update database credentials"
include_tasks: database.yml
- name: flush docker service
meta: flush_handlers
- name: Wait until the Moodle container is healthy
shell: docker inspect --format '{% raw %}{{.State.Health.Status}}{% endraw %}' {{ container_name }}
shell: docker inspect --format '{% raw %}{{.State.Health.Status}}{% endraw %}' {{ moodle_container }}
register: health_check
until: health_check.stdout.strip() == "healthy"
retries: 120
@@ -19,7 +25,7 @@
- name: Run Moodle system check
command: >
docker exec --user {{ bitnami_user }} {{ container_name }}
docker exec --user {{ bitnami_user }} {{ moodle_container }}
php /opt/bitnami/moodle/admin/cli/checks.php
register: moodle_checks
changed_when: false

View File

@@ -2,7 +2,7 @@
- name: Check if OIDC plugin is present in container
command: >
docker exec --user root {{ container_name }} test -d {{ bitnami_oidc_plugin_dir }}
docker exec --user root {{ moodle_container }} test -d {{ bitnami_oidc_plugin_dir }}
register: oidc_plugin_check
ignore_errors: true
changed_when: false
@@ -13,11 +13,11 @@
when: oidc_plugin_check.rc != 0
#- name: "Upgrade Moodle to apply OIDC plugin"
# command: "docker exec --user {{ bitnami_user }} {{ container_name }} php /opt/bitnami/moodle/admin/cli/upgrade.php --non-interactive"
# command: "docker exec --user {{ bitnami_user }} {{ moodle_container }} php /opt/bitnami/moodle/admin/cli/upgrade.php --non-interactive"
#
#- name: Clear Moodle cache
# command: >
# docker exec --user {{ bitnami_user }} {{ container_name }} php /opt/bitnami/moodle/admin/cli/purge_caches.php
# docker exec --user {{ bitnami_user }} {{ moodle_container }} php /opt/bitnami/moodle/admin/cli/purge_caches.php
- name: "Set Moodle OIDC configuration via CLI"
loop:
@@ -43,11 +43,11 @@
loop_control:
label: "{{ item.name }}"
command: >
docker exec --user {{ bitnami_user }} {{ container_name }} php /opt/bitnami/moodle/admin/cli/cfg.php --component=auth_oidc
docker exec --user {{ bitnami_user }} {{ moodle_container }} php /opt/bitnami/moodle/admin/cli/cfg.php --component=auth_oidc
--name={{ item.name }} --set="{{ item.value }}"
- name: "Enable OIDC login"
command: "docker exec --user {{ bitnami_user }} {{ container_name }} php /opt/bitnami/moodle/admin/cli/cfg.php --name=auth --set=oidc"
command: "docker exec --user {{ bitnami_user }} {{ moodle_container }} php /opt/bitnami/moodle/admin/cli/cfg.php --name=auth --set=oidc"
- name: Set auth = 'oidc' for all users except guest
shell: >
@@ -57,4 +57,4 @@
executable: /bin/bash
#- name: Prevent Account Creation
# command: docker exec --user {{ bitnami_user }} {{ container_name }} php /opt/bitnami/moodle/admin/cli/cfg.php --name=authpreventaccountcreation --set=1
# command: docker exec --user {{ bitnami_user }} {{ moodle_container }} php /opt/bitnami/moodle/admin/cli/cfg.php --name=authpreventaccountcreation --set=1

View File

@@ -7,13 +7,13 @@
- "{{ bitnami_data_dir }}"
block:
- name: Ensure ownership is correct
command: "docker exec --user root {{ container_name }} chown -R {{ bitnami_user_group }} {{ item }}"
command: "docker exec --user root {{ moodle_container }} chown -R {{ bitnami_user_group }} {{ item }}"
loop: "{{ moodle_dirs }}"
- name: Set directory permissions (770)
command: "docker exec --user root {{ container_name }} find {{ item }} -type d -exec chmod 770 {} \\;"
command: "docker exec --user root {{ moodle_container }} find {{ item }} -type d -exec chmod 770 {} \\;"
loop: "{{ moodle_dirs }}"
- name: Set file permissions (660)
command: "docker exec --user root {{ container_name }} find {{ item }} -type f -exec chmod 660 {} \\;"
command: "docker exec --user root {{ moodle_container }} find {{ item }} -type f -exec chmod 660 {} \\;"
loop: "{{ moodle_dirs }}"

View File

@@ -1,10 +1,10 @@
FROM bitnami/moodle:{{ applications | get_app_conf(application_id, 'version', True) }}
FROM {{ moodle_image }}:{{ moodle_version }}
{% if applications | get_app_conf(application_id, 'features.oidc', False) %}
RUN install_packages unzip curl jq \
&& VERSION=$(curl -s https://api.github.com/repos/microsoft/moodle-auth_oidc/tags \
| jq -r '.[].name' \
| grep v{{ applications | get_app_conf(application_id, 'version', True) }} \
| grep v{{ moodle_version }} \
| sort -Vr \
| head -n1) \
&& echo "Using version $VERSION" \

View File

@@ -2,7 +2,7 @@
moodle:
{% set container_port = 8080 %}
container_name: {{ container_name }}
container_name: {{ moodle_container }}
build:
context: .
dockerfile: Dockerfile
@@ -19,7 +19,9 @@
{% include 'roles/docker-compose/templates/volumes.yml.j2' %}
code:
name: {{ moodle_volume_code }}
data:
name: {{ moodle_volume_data }}
{% include 'roles/docker-compose/templates/networks.yml.j2' %}

View File

@@ -1,11 +1,19 @@
---
application_id: "moodle"
application_id: "web-app-moodle"
database_type: "mariadb"
container_name: "{{ application_id }}"
bitnami_code_link: "/bitnami/moodle"
bitnami_code_dir: "/opt{{bitnami_code_link}}"
bitnami_data_dir: "/bitnami/moodledata"
bitnami_oidc_plugin_dir: "{{ bitnami_code_dir }}/auth/oidc"
bitnami_user: "daemon"
bitnami_user_group: "{{ bitnami_user }}:{{ bitnami_user }}"
docker_compose_flush_handlers: true
docker_compose_flush_handlers: false # Wait for env update
moodle_backup_file: "{{ docker_compose.directories.instance }}/config.ini.php.bak"
moodle_config: "/bitnami/moodle/config.php"
moodle_version: "{{ applications | get_app_conf(application_id, 'docker.services.moodle.version', True) }}"
moodle_image: "{{ applications | get_app_conf(application_id, 'docker.services.moodle.image', True) }}"
moodle_container: "{{ applications | get_app_conf(application_id, 'docker.services.moodle.name', True) }}"
moodle_volume_data: "{{ applications | get_app_conf(application_id, 'docker.volumes.data', True) }}"
moodle_volume_code: "{{ applications | get_app_conf(application_id, 'docker.volumes.code', True) }}"

View File

@@ -25,7 +25,7 @@ plugin_configuration:
configkey: "custom_providers"
configvalue:
custom_oidc:
- name: "{{ domains | get_domain('keycloak') }}"
- name: "{{ domains | get_domain('web-app-keycloak') }}"
title: "keycloak"
style: "keycloak"
authorizeUrl: "{{ oidc.client.authorize_url }}"

View File

@@ -2,7 +2,7 @@ http_address = "0.0.0.0:4180"
cookie_secret = "{{ applications | get_app_conf(oauth2_proxy_application_id, 'credentials.oauth2_proxy_cookie_secret', True) }}"
cookie_secure = "true" # True is necessary to force the cookie set via https
upstreams = "http://{{ applications | get_app_conf(oauth2_proxy_application_id, 'oauth2_proxy.application', True) }}:{{ applications | get_app_conf(oauth2_proxy_application_id, 'oauth2_proxy.port', True) }}"
cookie_domains = ["{{ domains | get_domain(oauth2_proxy_application_id) }}", "{{ domains | get_domain('keycloak') }}"] # Required so cookie can be read on all subdomains.
cookie_domains = ["{{ domains | get_domain(oauth2_proxy_application_id) }}", "{{ domains | get_domain('web-app-keycloak') }}"] # Required so cookie can be read on all subdomains.
whitelist_domains = [".{{ primary_domain }}"] # Required to allow redirection back to original requested target.
# keycloak provider

View File

@@ -1,4 +1,3 @@
version: "latest" # Use the latest phpmyadmin version
autologin: false # This is a high security risk. Just activate this option if you know what you're doing
oauth2_proxy:
port: "80"
@@ -6,7 +5,7 @@ oauth2_proxy:
features:
matomo: true
css: false
port-ui-desktop: false # Opens itself in a new window, when it's loaded in an iframe.
port-ui-desktop: false # Opens itself in a new window, when it's loaded in an iframe.
# it's anyhow not so enduser relevant, so it can be kept like this
central_database: true
oauth2: true
@@ -24,3 +23,7 @@ docker:
services:
database:
enabled: true
phpmyadmin:
version: "latest" # Use the latest phpmyadmin version
name: "phpmyadmin"
image: phpmyadmin/phpmyadmin

View File

@@ -2,8 +2,8 @@
application:
{% set container_port = 80 %}
image: phpmyadmin/phpmyadmin:{{applications.phpmyadmin.version}}
container_name: phpmyadmin
image: "{{ phpmyadmin_image }}:{{ phpmyadmin_version }}"
container_name: "{{ phpmyadmin_name }}"
{% include 'roles/docker-container/templates/base.yml.j2' %}
ports:
- "127.0.0.1:{{ports.localhost.http[application_id]}}:{{ container_port }}"

View File

@@ -1,3 +1,6 @@
application_id: "phpmyadmin"
application_id: "web-app-phpmyadmin"
database_type: "mariadb"
database_host: "{{ applications | get_app_conf('svc-db-mariadb', 'docker.services.mariadb.name', True) if applications | get_app_conf(application_id, 'features.central_database', False)}}"
phpmyadmin_version: "{{ applications | get_app_conf(application_id, 'docker.services.phpmyadmin.version', True) }}"
phpmyadmin_image: "{{ applications | get_app_conf(application_id, 'docker.services.phpmyadmin.image', True) }}"
phpmyadmin_name: "{{ applications | get_app_conf(application_id, 'docker.services.phpmyadmin.name', True) }}"

View File

@@ -32,19 +32,19 @@ applications:
description: Access the central admin console
icon:
class: fa-solid fa-shield-halved
url: https://{{domains | get_domain('keycloak')}}/admin
iframe: {{ applications | get_app_conf( 'keycloak', 'features.port-ui-desktop', False) }}
url: https://{{domains | get_domain('web-app-keycloak')}}/admin
iframe: {{ applications | get_app_conf( 'web-app-keycloak', 'features.port-ui-desktop', False) }}
- name: Profile
description: Update your personal admin settings
icon:
class: fa-solid fa-user-gear
url: https://{{ domains | get_domain('keycloak') }}/realms/{{oidc.client.id}}/account
iframe: {{ applications | get_app_conf( 'keycloak', 'features.port-ui-desktop', False) }}
url: https://{{ domains | get_domain('web-app-keycloak') }}/realms/{{oidc.client.id}}/account
iframe: {{ applications | get_app_conf( 'web-app-keycloak', 'features.port-ui-desktop', False) }}
- name: Logout
description: End your admin session securely
icon:
class: fa-solid fa-right-from-bracket
url: https://{{ domains | get_domain('keycloak') }}/realms/{{oidc.client.id}}/protocol/openid-connect/logout
url: https://{{ domains | get_domain('web-app-keycloak') }}/realms/{{oidc.client.id}}/protocol/openid-connect/logout
iframe: false
{% endif %}

View File

@@ -31,7 +31,7 @@ followus:
class: fa-solid fa-camera
identifier: "{{service_provider.contact.pixelfed}}"
url: "{{ web_protocol }}://{{ service_provider.contact.pixelfed.split('@')[2] }}/@{{ service_provider.contact.pixelfed.split('@')[1] }}"
iframe: {{ applications | get_app_conf(web-app-pixelfed,'features.port-ui-desktop',True) }}
iframe: {{ applications | get_app_conf('web-app-pixelfed','features.port-ui-desktop',True) }}
{% endif %}
{% if service_provider.contact.peertube is defined and service_provider.contact.peertube != "" %}
- name: Peertube

View File

@@ -1,46 +0,0 @@
# tests/unit/filter_plugins/test_get_cymais_path.py
import unittest
import sys
import os
# Ensure the filter_plugins directory is in the import path
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../filter_plugins')))
from get_cymais_path import get_cymais_dir, get_cymais_file
from ansible.errors import AnsibleFilterError
class TestGetCymaisPath(unittest.TestCase):
def test_valid_input(self):
"""Test valid input with exactly one underscore"""
self.assertEqual(get_cymais_dir("web_app"), "web")
self.assertEqual(get_cymais_file("web_app"), "app")
self.assertEqual(get_cymais_dir("sys_timer"), "sys")
self.assertEqual(get_cymais_file("sys_timer"), "timer")
def test_invalid_no_underscore(self):
"""Test input with no underscore raises error"""
with self.assertRaises(AnsibleFilterError):
get_cymais_dir("invalid")
with self.assertRaises(AnsibleFilterError):
get_cymais_file("invalid")
def test_invalid_multiple_underscores(self):
"""Test input with more than one underscore raises error"""
with self.assertRaises(AnsibleFilterError):
get_cymais_dir("too_many_parts_here")
with self.assertRaises(AnsibleFilterError):
get_cymais_file("too_many_parts_here")
def test_empty_string(self):
"""Test empty string input raises error"""
with self.assertRaises(AnsibleFilterError):
get_cymais_dir("")
with self.assertRaises(AnsibleFilterError):
get_cymais_file("")
if __name__ == '__main__':
unittest.main()

View File

@@ -0,0 +1,26 @@
import unittest
from filter_plugins.get_public_id import FilterModule
class TestGetPublicId(unittest.TestCase):
def setUp(self):
self.filter = FilterModule().filters()['get_public_id']
def test_extract_public_id(self):
self.assertEqual(self.filter("svc-user-abc123"), "abc123")
self.assertEqual(self.filter("something-simple-xyz"), "xyz")
self.assertEqual(self.filter("a-b-c-d-e"), "e")
def test_no_hyphen(self):
with self.assertRaises(ValueError):
self.filter("nohyphenhere")
def test_non_string_input(self):
with self.assertRaises(ValueError):
self.filter(12345)
def test_empty_string(self):
with self.assertRaises(ValueError):
self.filter("")
if __name__ == '__main__':
unittest.main()