From aacc6877cb693def72263ffc5c8402c462e89dc5 Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Wed, 28 May 2025 02:42:39 +0200 Subject: [PATCH] General Optimations --- cli/deploy.py | 12 ++-- group_vars/all/10_users.yml | 59 ++++++++++++++++++- group_vars/all/15_about.yml | 14 ++--- roles/docker-espocrm/meta/main.yml | 3 +- .../templates/docker-compose.yml.j2 | 2 +- roles/docker-espocrm/vars/configuration.yml | 2 +- roles/docker-mailu/meta/main.yml | 3 +- .../tasks/create-mailu-user-and-token.yml | 32 +++++----- roles/docker-mailu/tasks/main.yml | 3 +- roles/docker-mailu/vars/configuration.yml | 7 ++- .../docker-portfolio/templates/config.yaml.j2 | 29 +-------- .../health-nginx/templates/health-nginx.py.j2 | 6 -- 12 files changed, 106 insertions(+), 66 deletions(-) diff --git a/cli/deploy.py b/cli/deploy.py index 877fdca6..3769093b 100644 --- a/cli/deploy.py +++ b/cli/deploy.py @@ -6,8 +6,9 @@ import os import datetime def run_ansible_playbook(inventory, playbook, modes, limit=None, password_file=None, verbose=0, skip_tests=False): - start_time = datetime.datetime.now().isoformat() - print(f"\n▶️ Script started at: {start_time}\n") + start_time = datetime.datetime.now() + print(f"\n▶️ Script started at: {start_time.isoformat()}\n") + print("\n🛠️ Building project (make build)...\n") subprocess.run(["make", "build"], check=True) @@ -35,8 +36,11 @@ def run_ansible_playbook(inventory, playbook, modes, limit=None, password_file=N print("\n🚀 Launching Ansible Playbook...\n") subprocess.run(cmd, check=True) - end_time = datetime.datetime.now().isoformat() - print(f"\n✅ Script ended at: {end_time}\n") + end_time = datetime.datetime.now() + print(f"\n✅ Script ended at: {end_time.isoformat()}\n") + + duration = end_time - start_time + print(f"⏱️ Total execution time: {duration}\n") def main(): script_dir = os.path.dirname(os.path.realpath(__file__)) diff --git a/group_vars/all/10_users.yml b/group_vars/all/10_users.yml index 6c1dcbc1..7b4ef2d9 100644 --- a/group_vars/all/10_users.yml +++ b/group_vars/all/10_users.yml @@ -16,6 +16,25 @@ _users_no_reply_email: "{{ users['no-reply'].email | default(_users_no_ _users_blackhole_username: "{{ users.blackhole.username | default('no-reply') }}" _users_blackhole_email: "{{ users.blackhole.email | default(_users_blackhole_username ~ '@' ~ primary_domain) }}" +# Helper Variables for contact user +_users_contact_username: "{{ users.contact.username | default('contact') }}" +_users_contact_email: "{{ users.contact.email | default(_users_contact_username ~ '@' ~ primary_domain) }}" + +# Helper Variables for support +_users_support_username: "{{ users.support.username | default('support') }}" +_users_support_email: "{{ users.support.email | default(_users_support_username ~ '@' ~ primary_domain) }}" + +# Helper Variables for helpdesk +_users_helpdesk_username: "{{ users.helpdesk.username | default('helpdesk') }}" +_users_helpdesk_email: "{{ users.helpdesk.email | default(_users_helpdesk_username ~ '@' ~ primary_domain) }}" + +# Extract SLD and TLD from primary_domain +_users_sld_username: "{{ primary_domain.split('.')[0] }}" +_users_sld_email: "{{ _users_sld_username ~ '@' ~ primary_domain }}" + +_users_tld_username: "{{ primary_domain.split('.')[-1] }}" +_users_tld_email: "{{ _users_tld_username ~ '@' ~ primary_domain }}" + # Administrator default_users: @@ -50,4 +69,42 @@ default_users: email: "{{ _users_blackhole_email }}" # Email address to which emails can be send which well be forgetten password: "{{ansible_become_password}}" # Example initialisation password needs to be set in inventory file uid: 1004 # Posix User ID for bounce - gid: 1004 # Posix Group ID for bounce \ No newline at end of file + gid: 1004 # Posix Group ID for bounce + + # The contact user account which clients and plattform users can contact + contact: + username: "{{ _users_contact_username }}" # Contact account username + email: "{{ _users_contact_email }}" # Email address to which initial contacct emails can be send + password: "{{ansible_become_password}}" # Example initialisation password needs to be set in inventory file + uid: 1005 # Posix User ID for bounce + gid: 1005 # Posix Group ID for bounce + + # Support and Helpdesk accounts + support: + username: "{{ _users_support_username }}" # Support account username + email: "{{ _users_support_email }}" # Email for customer and platform support communication + password: "{{ ansible_become_password }}" # Example initialisation password needs to be set in inventory file + uid: 1006 # Posix User ID for support + gid: 1006 # Posix Group ID for support + + helpdesk: + username: "{{ _users_helpdesk_username }}" # Helpdesk account username + email: "{{ _users_helpdesk_email }}" # Email for internal technical helpdesk communication + password: "{{ ansible_become_password }}" # Example initialisation password needs to be set in inventory file + uid: 1007 # Posix User ID for helpdesk + gid: 1007 # Posix Group ID for helpdesk + + sld_user: + username: "{{ _users_sld_username }}" # Username based on SLD of the primary domain + email: "{{ _users_sld_email }}" # Email address with SLD username + password: "{{ ansible_become_password }}" # Init password from inventory + uid: 1008 + gid: 1008 + + tld_user: + username: "{{ _users_tld_username }}" # Username based on TLD of the primary domain + email: "{{ _users_tld_email }}" # Email address with TLD username + password: "{{ ansible_become_password }}" # Init password from inventory + uid: 1009 + gid: 1009 + diff --git a/group_vars/all/15_about.yml b/group_vars/all/15_about.yml index 59c8c435..8db9d301 100644 --- a/group_vars/all/15_about.yml +++ b/group_vars/all/15_about.yml @@ -17,15 +17,15 @@ defaults_service_provider: favicon: "{{ applications['assets-server'].url ~ '/img/favicon.ico' }}" contact: bluesky: >- - {{ ('@' ~ users.administrator.username ~ '.' ~ domains.bluesky.api) + {{ ('@' ~ users.contact.username ~ '.' ~ domains.bluesky.api) if 'bluesky' in group_names else '' }} - email: "contact@{{ primary_domain }}" - mastodon: "{{ '@' ~ users.administrator.username ~ '@' ~ domains | get_domain('mastodon') if 'mastodon' in group_names else '' }}" - matrix: "{{ '@' ~ users.administrator.username ~ ':' ~ domains.matrix.synapse if 'matrix' in group_names else '' }}" - peertube: "{{ '@' ~ users.administrator.username ~ '@' ~ domains | get_domain('peertube') if 'peertube' in group_names else '' }}" - pixelfed: "{{ '@' ~ users.administrator.username ~ '@' ~ domains | get_domain('pixelfed') if 'pixelfed' in group_names else '' }}" + email: "{{ users.contact.username ~ '@' ~ domains | get_domain('mailu') if 'mailu' in group_names else '' }}" + mastodon: "{{ '@' ~ users.contact.username ~ '@' ~ domains | get_domain('mastodon') if 'mastodon' in group_names else '' }}" + matrix: "{{ '@' ~ users.contact.username ~ ':' ~ domains.matrix.synapse if 'matrix' in group_names else '' }}" + peertube: "{{ '@' ~ users.contact.username ~ '@' ~ domains | get_domain('peertube') if 'peertube' in group_names else '' }}" + pixelfed: "{{ '@' ~ users.contact.username ~ '@' ~ domains | get_domain('pixelfed') if 'pixelfed' in group_names else '' }}" phone: "+0 000 000 404" - wordpress: "{{ '@' ~ users.administrator.username ~ '@' ~ domains | get_domain('wordpress') if 'wordpress' in group_names else '' }}" + wordpress: "{{ '@' ~ users.contact.username ~ '@' ~ domains | get_domain('wordpress') if 'wordpress' in group_names else '' }}" legal: editorial_responsible: "Johannes Gutenberg" diff --git a/roles/docker-espocrm/meta/main.yml b/roles/docker-espocrm/meta/main.yml index b84a76e9..71515b5f 100644 --- a/roles/docker-espocrm/meta/main.yml +++ b/roles/docker-espocrm/meta/main.yml @@ -19,4 +19,5 @@ galaxy_info: documentation: "https://s.veen.world/cymais" logo: class: "fa-solid fa-phone" -dependencies: [] \ No newline at end of file + run_after: + - docker-keycloak \ No newline at end of file diff --git a/roles/docker-espocrm/templates/docker-compose.yml.j2 b/roles/docker-espocrm/templates/docker-compose.yml.j2 index 4a91383f..a8429ec6 100644 --- a/roles/docker-espocrm/templates/docker-compose.yml.j2 +++ b/roles/docker-espocrm/templates/docker-compose.yml.j2 @@ -31,7 +31,7 @@ services: driver: journald environment: - ESPOCRM_CONFIG_USE_WEB_SOCKET=true - - ESPOCRM_CONFIG_WEB_SOCKET_URL=ws://{{ domains | get_domain(application_id) }}/ws + - ESPOCRM_CONFIG_WEB_SOCKET_URL=wss://{{ domains | get_domain(application_id) }}/ws - ESPOCRM_CONFIG_WEB_SOCKET_ZERO_M_Q_SUBSCRIBER_DSN=tcp://*:7777 - ESPOCRM_CONFIG_WEB_SOCKET_ZERO_M_Q_SUBMISSION_DSN=tcp://websocket:7777 entrypoint: docker-websocket.sh diff --git a/roles/docker-espocrm/vars/configuration.yml b/roles/docker-espocrm/vars/configuration.yml index cf7d3fed..6c1eca56 100644 --- a/roles/docker-espocrm/vars/configuration.yml +++ b/roles/docker-espocrm/vars/configuration.yml @@ -22,7 +22,7 @@ csp: unsafe-inline: true whitelist: connect-src: - - ws://espocrm.{{ primary_domain }} + - wss://espocrm.{{ primary_domain }} domains: aliases: - "crm.{{ primary_domain }}" \ No newline at end of file diff --git a/roles/docker-mailu/meta/main.yml b/roles/docker-mailu/meta/main.yml index 324b061c..8acdf873 100644 --- a/roles/docker-mailu/meta/main.yml +++ b/roles/docker-mailu/meta/main.yml @@ -19,4 +19,5 @@ galaxy_info: documentation: "https://s.veen.world/cymais" logo: class: "fa-solid fa-envelope" -dependencies: [] + run_after: + - docker-keycloak diff --git a/roles/docker-mailu/tasks/create-mailu-user-and-token.yml b/roles/docker-mailu/tasks/create-mailu-user-and-token.yml index 9a6ad250..2a562be6 100644 --- a/roles/docker-mailu/tasks/create-mailu-user-and-token.yml +++ b/roles/docker-mailu/tasks/create-mailu-user-and-token.yml @@ -1,7 +1,7 @@ -- name: "Ensure Mailu user {{ mailu_user }}@{{ mailu_domain }} exists" +- name: "Ensure Mailu user '{{ mailu_user_key }};{{ mailu_user_name }}@{{ mailu_domain }}'' exists" command: > docker compose exec admin flask mailu {{ mailu_action }} - {{ mailu_user }} {{ mailu_domain }} '{{ mailu_password }}' + {{ mailu_user_name }} {{ mailu_domain }} '{{ mailu_password }}' args: chdir: "{{ mailu_compose_dir }}" register: mailu_user_result @@ -13,10 +13,10 @@ ) changed_when: mailu_user_result.rc == 0 -- name: "Change password for user {{ mailu_user }}@{{ mailu_domain }}" +- name: "Change password for user '{{ mailu_user_key }};{{ mailu_user_name }}@{{ mailu_domain }}'" command: > docker compose exec admin flask mailu password - {{ mailu_user }} {{ mailu_domain }} '{{ mailu_password }}' + {{ mailu_user_name }} {{ mailu_domain }} '{{ mailu_password }}' args: chdir: "{{ mailu_compose_dir }}" @@ -30,18 +30,18 @@ register: mailu_tokens_cli changed_when: false -- name: "Extract existing token info for {{ mailu_user }}" +- name: "Extract existing token info for '{{ mailu_user_key }};{{ mailu_user_name }}'" set_fact: mailu_user_existing_token: >- {{ ( mailu_tokens_cli.stdout | default('[]') | from_json - | selectattr('comment','equalto', mailu_user ~ " - ansible.cymais") + | selectattr('comment','equalto', mailu_user_key ~ " - ansible.cymais") | list ).0 | default(None) }} -- name: "Delete existing API token for {{ mailu_user }} if local token missing but remote exists" +- name: "Delete existing API token for '{{ mailu_user_key }};{{ mailu_user_name }}' if local token missing but remote exists" command: >- docker compose exec -T admin \ curl -s -X DELETE {{ mailu_api_base_url }}/token/{{ mailu_user_existing_token.id }} \ @@ -49,40 +49,40 @@ args: chdir: "{{ mailu_compose_dir }}" when: - - users[mailu_user].mailu_token is not defined + - users[mailu_user_key].mailu_token is not defined - mailu_user_existing_token is not none - mailu_user_existing_token.id is defined register: mailu_token_delete changed_when: mailu_token_delete.rc == 0 -- name: "Create API token for {{ mailu_user }} if no local token defined" +- name: "Create API token for '{{ mailu_user_key }};{{ mailu_user_name }}' if no local token defined" command: >- docker compose exec -T admin \ curl -s -X POST {{ mailu_api_base_url }}/token \ -H "Authorization: Bearer {{ mailu_global_api_token }}" \ -H "Content-Type: application/json" \ -d '{{ { - "comment": mailu_user ~ " - ansible.cymais", - "email": users[mailu_user].email, + "comment": mailu_user_key ~ " - ansible.cymais", + "email": users[mailu_user_key].email, "ip": mailu_token_ip } | to_json }}' args: chdir: "{{ mailu_compose_dir }}" - when: users[mailu_user].mailu_token is not defined + when: users[mailu_user_key].mailu_token is not defined register: mailu_token_creation changed_when: mailu_token_creation.rc == 0 -- name: "Set mailu_token for {{ mailu_user }} in users dict if newly created" +- name: "Set mailu_token for '{{ mailu_user_key }};{{ mailu_user_name }}' in users dict if newly created" set_fact: users: >- {{ users | combine({ - mailu_user: ( - users[mailu_user] + mailu_user_key: ( + users[mailu_user_key] | combine({ 'mailu_token': (mailu_token_creation.stdout | from_json).token }) ) }, recursive=True) }} - when: users[mailu_user].mailu_token is not defined + when: users[mailu_user_key].mailu_token is not defined diff --git a/roles/docker-mailu/tasks/main.yml b/roles/docker-mailu/tasks/main.yml index 75269aab..46aada69 100644 --- a/roles/docker-mailu/tasks/main.yml +++ b/roles/docker-mailu/tasks/main.yml @@ -33,7 +33,8 @@ mailu_api_base_url: "http://127.0.0.1:8080/api/v1" mailu_global_api_token: "{{ applications.mailu.credentials.api_token }}" mailu_action: "{{ item.value.is_admin | default(false) | ternary('admin','user') }}" - mailu_user: "{{ item.key }}" + mailu_user_key: "{{ item.key }}" + mailu_user_name: "{{ item.value.username }}" mailu_password: "{{ item.value.password }}" mailu_token_ip: "{{ item.value.ip | default('') }}" loop: "{{ users | dict2items }}" diff --git a/roles/docker-mailu/vars/configuration.yml b/roles/docker-mailu/vars/configuration.yml index bdb5fbcd..8f102b4d 100644 --- a/roles/docker-mailu/vars/configuration.yml +++ b/roles/docker-mailu/vars/configuration.yml @@ -15,4 +15,9 @@ features: central_database: false # Deactivate central database for mailu, I don't know why the database deactivation is necessary domains: canonical: - - "mail.{{ primary_domain }}" \ No newline at end of file + - "mail.{{ primary_domain }}" +flags: + style-src: + unsafe-inline: true + script-src: + unsafe-inline: true \ No newline at end of file diff --git a/roles/docker-portfolio/templates/config.yaml.j2 b/roles/docker-portfolio/templates/config.yaml.j2 index 87613e55..b57d2681 100644 --- a/roles/docker-portfolio/templates/config.yaml.j2 +++ b/roles/docker-portfolio/templates/config.yaml.j2 @@ -10,9 +10,7 @@ accounts: description: Platforms where I share content. icon: class: fas fa-newspaper - -{% if ["mastodon", "bluesky"] | any_in(group_names) %} - +{% if ["mastodon", "bluesky"] | any_in(group_names) %} children: - name: Microblogs description: Stay updated with {{ 'our' if service_provider.type == 'legal' else 'my' }} microblogs. @@ -20,8 +18,6 @@ accounts: class: fa-solid fa-pen-nib children: {% if service_provider.contact.mastodon is defined and service_provider.contact.mastodon != "" %} - - - name: Mastodon description: Follow {{ 'our' if service_provider.type == 'legal' else 'my' }} updates on Mastodon. icon: @@ -29,11 +25,8 @@ accounts: url: "{{ web_protocol }}://{{ service_provider.contact.mastodon.split('@')[2] }}/@{{ service_provider.contact.mastodon.split('@')[1] }}" identifier: "{{service_provider.contact.mastodon}}" iframe: {{ applications | is_feature_enabled('portfolio_iframe','mastodon') }} - {% endif %} {% if service_provider.contact.bluesky is defined and service_provider.contact.bluesky != "" %} - - - name: Bluesky description: Follow {{ 'our' if service_provider.type == 'legal' else 'my' }} on Bluesky. icon: @@ -41,11 +34,9 @@ accounts: alternatives: - link: accounts.publishingchannels.microblogs.mastodon identifier: "{{service_provider.contact.bluesky}}" - {% endif %} {% endif %} {% if service_provider.contact.pixelfed is defined and service_provider.contact.pixelfed != "" %} - - name: Pictures description: Explore {{ 'our' if service_provider.type == 'legal' else 'my' }} photo gallery on Pixelfed. icon: @@ -53,11 +44,8 @@ accounts: identifier: "{{service_provider.contact.pixelfed}}" url: "{{ web_protocol }}://{{ service_provider.contact.pixelfed.split('@')[2] }}/@{{ service_provider.contact.pixelfed.split('@')[1] }}" iframe: {{ applications | is_feature_enabled('portfolio_iframe','pixelfed') }} - {% endif %} {% if service_provider.contact.peertube is defined and service_provider.contact.peertube != "" %} - - - name: Peertube description: Discover {{ 'our' if service_provider.type == 'legal' else 'my' }} videos on Peertube. icon: @@ -65,11 +53,8 @@ accounts: identifier: "{{service_provider.contact.peertube}}" url: "{{ web_protocol }}://{{ service_provider.contact.peertube.split('@')[2] }}/@{{ service_provider.contact.peertube.split('@')[1] }}" iframe: {{ applications | is_feature_enabled('portfolio_iframe','peertube') }} - {% endif %} {% if service_provider.contact.wordpress is defined and service_provider.contact.wordpress != "" %} - - - name: Blog description: Read {{ 'our' if service_provider.type == 'legal' else 'my' }} articles and stories. icon: @@ -77,21 +62,15 @@ accounts: identifier: "{{service_provider.contact.wordpress}}" url: "{{ web_protocol }}://{{ service_provider.contact.wordpress.split('@')[2] }}/@{{ service_provider.contact.wordpress.split('@')[1] }}" iframe: {{ applications | is_feature_enabled('portfolio_iframe','wordpress') }} - {% endif %} -{% if service_provider.contact.source_code is defined and service_provider.contact.source_code != "" %} - - - - name: Our Code +{% if service_provider.legal.source_code is defined and service_provider.legal.source_code != "" %} + - name: Source Code description: Explore {{ 'our' if service_provider.type == 'legal' else 'my' }} code. icon: class: fa-solid fa-code url: "{{service_provider.legal.source_code}}" - {% endif %} {% if service_provider.contact.friendica is defined and service_provider.contact.friendica != "" %} - - - name: Social Network description: Visit {{ 'our' if service_provider.type == 'legal' else 'my' }} friendica profile icon: @@ -99,9 +78,7 @@ accounts: identifier: "{{service_provider.contact.friendica}}" url: "{{ web_protocol }}://{{ service_provider.contact.friendica.split('@')[2] }}/@{{ service_provider.contact.friendica.split('@')[1] }}" iframe: {{ applications | is_feature_enabled('portfolio_iframe','friendica') }} - {% endif %} - - link: navigation.header.contact cards: diff --git a/roles/health-nginx/templates/health-nginx.py.j2 b/roles/health-nginx/templates/health-nginx.py.j2 index 3ce85300..f39f8837 100644 --- a/roles/health-nginx/templates/health-nginx.py.j2 +++ b/roles/health-nginx/templates/health-nginx.py.j2 @@ -15,16 +15,12 @@ def get_expected_statuses(domain: str, parts: list[str], redirected_domains: set Returns: A list of expected HTTP status codes. """ - {%- if domains.listmonk | safe_var | bool %} if domain == '{{domains | get_domain('listmonk')}}': return [404] - {%- endif %} if (parts and parts[0] == 'www') or (domain in redirected_domains): return [301] - {%- if domains.yourls | safe_var | bool %} if domain == '{{domains | get_domain('yourls')}}': return [403] - {%- endif %} # Default: Expect status code 200 or 302 for a domain return [200,302] @@ -48,9 +44,7 @@ for filename in os.listdir(config_path): url = f"{{ web_protocol }}://{domain}" redirected_domains = [domain['source'] for domain in {{ current_play_domain_mappings_redirect}}] - {%- if domains.mailu | safe_var | bool %} redirected_domains.append("{{domains | get_domain('mailu')}}") - {%- endif %} expected_statuses = get_expected_statuses(domain, parts, redirected_domains)