From cc4895391413d0323003ffbd8fd9ff79d82c019b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Xavi=20Lle=C3=B3=20Tom=C3=A1s?= <xavi@verdnatura.es>
Date: Thu, 10 Apr 2025 15:50:23 +0200
Subject: [PATCH 1/2] maxscale: refs #8822 - Final approach

---
 playbooks/maxscale.yml                      |  6 ++
 roles/maxscale/defaults/main.yaml           | 15 ++++
 roles/maxscale/handlers/main.yml            | 16 ++++
 roles/maxscale/tasks/main.yml               |  3 +
 roles/maxscale/tasks/maxscale.yml           | 68 ++++++++++++++++
 roles/maxscale/templates/.secrets           |  6 ++
 roles/maxscale/templates/keepalived.conf.j2 | 40 +++++++++
 roles/maxscale/templates/maxscale.cnf.j2    | 90 +++++++++++++++++++++
 roles/maxscale/templates/override.conf.j2   |  4 +
 9 files changed, 248 insertions(+)
 create mode 100644 playbooks/maxscale.yml
 create mode 100644 roles/maxscale/defaults/main.yaml
 create mode 100644 roles/maxscale/handlers/main.yml
 create mode 100644 roles/maxscale/tasks/main.yml
 create mode 100644 roles/maxscale/tasks/maxscale.yml
 create mode 100644 roles/maxscale/templates/.secrets
 create mode 100644 roles/maxscale/templates/keepalived.conf.j2
 create mode 100644 roles/maxscale/templates/maxscale.cnf.j2
 create mode 100644 roles/maxscale/templates/override.conf.j2

diff --git a/playbooks/maxscale.yml b/playbooks/maxscale.yml
new file mode 100644
index 0000000..7852259
--- /dev/null
+++ b/playbooks/maxscale.yml
@@ -0,0 +1,6 @@
+- name: Configure MaxScale
+  hosts: all
+  tasks:
+  - name: Configure MaxScale to install in the server
+    import_role:
+      name: maxscale
\ No newline at end of file
diff --git a/roles/maxscale/defaults/main.yaml b/roles/maxscale/defaults/main.yaml
new file mode 100644
index 0000000..dd63441
--- /dev/null
+++ b/roles/maxscale/defaults/main.yaml
@@ -0,0 +1,15 @@
+downloads:
+  - url: https://r.mariadb.com/downloads/mariadb_repo_setup
+    dest: /tmp/mariadb_repo_setup
+    mode: u=rwx,g=rx,o=rx
+certificates:
+  - { content: '{{ maxscale_config.admin_cert }}', dest: '/etc/ssl/private/cert.pem', owner: 'root', group: 'maxscale', mode: 'u=rw,g=r,o=r' }
+  - { content: '{{ maxscale_config.admin_key }}', dest: '/etc/ssl/private/key.pem', owner: 'root', group: 'maxscale', mode: 'u=rw,g=r,o=' }
+  - { content: '{{ maxscale_config.db_cert_pem }}', dest: '/etc/ssl/private/db-cert.pem', owner: 'root', group: 'maxscale', mode: 'u=rw,g=r,o=' }
+  - { content: '{{ maxscale_config.db_ca_pem }}', dest: '/etc/ssl/private/db-ca.pem', owner: 'root', group: 'maxscale', mode: 'u=rw,g=r,o=' }
+  - { content: '{{ maxscale_config.db_key }}', dest: '/etc/ssl/private/db-key.pem', owner: 'root', group: 'maxscale', mode: 'u=rw,g=r,o=' }
+maxscale_templates:
+  - { src: 'maxscale.cnf.j2', dest: '/etc/maxscale.cnf' }  
+  - { src: 'keepalived.conf.j2', dest: '/etc/keepalived/keepalived.conf' }
+  - { src: 'override.conf.j2', dest: '/etc/systemd/system/maxscale.service.d/override.conf' }
+  - { src: '.secrets', dest: '/var/lib/maxscale/.secrets', owner: 'maxscale', group: 'maxscale', mode: 'u=r,g=,o=' }
\ No newline at end of file
diff --git a/roles/maxscale/handlers/main.yml b/roles/maxscale/handlers/main.yml
new file mode 100644
index 0000000..465e069
--- /dev/null
+++ b/roles/maxscale/handlers/main.yml
@@ -0,0 +1,16 @@
+- name: reload-systemd
+  command:
+    cmd: systemctl daemon-reload
+- name: restart-maxscale
+  systemd:
+    name: maxscale
+    state: restarted
+    enabled: yes
+- name: restart-keepalived
+  systemd:
+    name: keepalived
+    state: restarted
+    enabled: yes
+- name: reload-systemd
+  command:
+    cmd: systemctl daemon-reload
diff --git a/roles/maxscale/tasks/main.yml b/roles/maxscale/tasks/main.yml
new file mode 100644
index 0000000..52f03c8
--- /dev/null
+++ b/roles/maxscale/tasks/main.yml
@@ -0,0 +1,3 @@
+- import_tasks: maxscale.yml
+  tags: maxscale
+
diff --git a/roles/maxscale/tasks/maxscale.yml b/roles/maxscale/tasks/maxscale.yml
new file mode 100644
index 0000000..7104dc0
--- /dev/null
+++ b/roles/maxscale/tasks/maxscale.yml
@@ -0,0 +1,68 @@
+- name: Ensure required packages for MaxScale are installed
+  apt:
+    name: keepalived
+    state: present
+    install_recommends: no
+    update_cache: true
+- name: Download required setup files
+  get_url:
+    url: "{{ item.url }}"
+    dest: "{{ item.dest }}"
+    mode: "{{ item.mode }}"
+  register: mariadb_repo_script
+  loop: "{{ downloads }}"
+- name: Run MariaDB repository setup script
+  command:
+    cmd: "/bin/bash /tmp/mariadb_repo_setup --mariadb-server-version={{ db.version | default('10.11.10') }} --mariadb-maxscale-version={{ db.maxscale | default('23.08.9') }}"
+    creates: "/etc/apt/sources.list.d/mariadb.list"
+  when: mariadb_repo_script.changed
+- name: Ensure systemd override directory exists
+  file:
+    path: /etc/systemd/system/maxscale.service.d
+    state: directory
+    owner: root
+    group: root
+    mode: 'u=rwx,g=rx,o=rx'
+- name: Install maxscale
+  apt:
+    name: maxscale
+    state: present
+    install_recommends: no
+    update_cache: true
+- name: Ensure /etc/ssl/private has correct permissions and ownership
+  file:
+    path: /etc/ssl/private
+    state: directory
+    owner: root
+    group: maxscale
+    mode: "u=rwx,g=rx,o="
+- name: Deploy templated configuration files
+  ansible.builtin.template:
+    src: "{{ item.src }}"
+    dest: "{{ item.dest }}"
+    owner: "{{ item.owner | default('root') }}"
+    group: "{{ item.group | default('root') }}"
+    mode: "{{ item.mode | default('u=rw,g=r,o=r') }}"
+  loop: "{{ maxscale_templates }}"
+  notify:
+    - restart-keepalived
+    - restart-maxscale
+    - reload-systemd
+- name: Insert certificates
+  no_log: true
+  copy:
+    content: "{{ item.content }}"
+    dest: "{{ item.dest }}"
+    owner: "{{ item.owner }}"
+    group: "{{ item.group }}"
+    mode: "{{ item.mode }}"
+  loop: "{{ certificates }}"
+  notify:
+    - restart-maxscale
+    - reload-systemd
+
+
+
+
+
+
diff --git a/roles/maxscale/templates/.secrets b/roles/maxscale/templates/.secrets
new file mode 100644
index 0000000..a0d02d5
--- /dev/null
+++ b/roles/maxscale/templates/.secrets
@@ -0,0 +1,6 @@
+{
+    "description": "MaxScale encryption/decryption key",
+    "maxscale_version": "6.2.4",
+    "encryption_cipher": "EVP_aes_256_cbc",
+    "encryption_key": "{{ lookup(passbolt, 'maxscale_encryption_key', folder_parent_id=passbolt_folder).password }}"
+}
\ No newline at end of file
diff --git a/roles/maxscale/templates/keepalived.conf.j2 b/roles/maxscale/templates/keepalived.conf.j2
new file mode 100644
index 0000000..ed9a5e9
--- /dev/null
+++ b/roles/maxscale/templates/keepalived.conf.j2
@@ -0,0 +1,40 @@
+{% set k = keepalive %}
+global_defs {
+    script_user root
+    enable_script_security
+}
+
+vrrp_script check_maxscale {
+    script "/usr/bin/pgrep maxscale"
+    interval 4
+    timeout 4
+    rise 3
+    fall 3
+}
+
+{% for vip in k.vips %}
+vrrp_instance {{ vip.name }} {
+    interface         {{ k.interface }}
+    state             BACKUP
+    priority {{ k.priorities.master if vip.host == inventory_hostname_short else k.priorities.backup }}
+    virtual_router_id {{ vip.vrid }}
+    advert_int        1
+    accept
+    unicast_src_ip    {{ ansible_host }}
+
+    unicast_peer {
+{% for peer in k.peers if peer.host != inventory_hostname %}
+        {{ peer.ip }}
+{% endfor %}
+    }
+
+
+    virtual_ipaddress {
+        {{ vip.vip }}
+    }
+
+    track_script {
+        check_maxscale
+    }
+}
+{% endfor %}
diff --git a/roles/maxscale/templates/maxscale.cnf.j2 b/roles/maxscale/templates/maxscale.cnf.j2
new file mode 100644
index 0000000..4f641b2
--- /dev/null
+++ b/roles/maxscale/templates/maxscale.cnf.j2
@@ -0,0 +1,90 @@
+# MaxScale documentation:
+# https://mariadb.com/kb/en/mariadb-maxscale-2208/
+# https://mariadb.com/kb/en/mariadb-maxscale-2208-mariadb-maxscale-configuration-guide/
+
+[maxscale]
+threads=auto
+admin_host=0.0.0.0
+admin_port=443
+admin_ssl_cert={{ maxscale_config.admin_cert_path }}
+admin_ssl_key={{ maxscale_config.admin_key_path }}
+syslog=false
+log_warning=false
+logdir=/var/log/maxscale/
+query_classifier_cache_size=250M
+config_sync_cluster={{ maxscale_config.config_sync_cluster }}
+config_sync_user={{ maxscale_config.config_sync_user }}
+config_sync_password={{ lookup(passbolt, 'maxscale_config.config_sync_password', folder_parent_id=passbolt_folder).password }}
+
+{% for server in maxscale_config.db_servers %}
+[{{ server.name }}]
+type=server
+address={{ server.address }}
+port=3306
+protocol=MariaDBBackend
+{% endfor %}
+
+[MariaDB-Monitor]
+type=monitor
+module=mariadbmon
+servers={{ maxscale_config.db_servers | map(attribute='name') | join(',') }}
+user={{ maxscale_config.monitor_user }}
+password={{ lookup(passbolt, 'maxscale_config.monitor_password', folder_parent_id=passbolt_folder).password }}
+monitor_interval=2s
+replication_user={{ maxscale_config.repl_user }}
+replication_password={{ lookup(passbolt, 'maxscale_config.repl_password', folder_parent_id=passbolt_folder).password }}
+switchover_timeout=1m
+cooperative_monitoring_locks=majority_of_running
+
+[Read-Write-Service]
+type=service
+router=readwritesplit
+servers=db1,db2
+user={{ maxscale_config.rw_user }}
+password={{ lookup(passbolt, 'maxscale_config.rw_password', folder_parent_id=passbolt_folder).password }}
+master_accept_reads=true
+strict_multi_stmt=true
+strict_sp_calls=true
+slave_connections=0
+max_slave_connections=0
+use_sql_variables_in=master
+
+[Read-Only-Service]
+type=service
+router=readconnroute
+servers=db1,db2
+user={{ maxscale_config.ro_user }}
+password={{ lookup(passbolt, 'maxscale_config.ro_password', folder_parent_id=passbolt_folder).password }}
+router_options=slave
+
+[Read-Write-Listener-SSL]
+type=listener
+service=Read-Write-Service
+protocol=MariaDBClient
+port=3306
+ssl=true
+ssl_cert={{ maxscale_config.db_cert_path }}
+ssl_key={{ maxscale_config.db_key_path }}
+ssl_ca_cert={{ maxscale_config.db_ca_path }}
+
+[Read-Only-Listener-SSL]
+type=listener
+service=Read-Only-Service
+protocol=MariaDBClient
+port=3307
+ssl=true
+ssl_cert={{ maxscale_config.db_cert_path }}
+ssl_key={{ maxscale_config.db_key_path }}
+ssl_ca_cert={{ maxscale_config.db_ca_path }}
+
+[Read-Write-Listener]
+type=listener
+service=Read-Write-Service
+protocol=MariaDBClient
+port=3308
+
+[Read-Only-Listener]
+type=listener
+service=Read-Only-Service
+protocol=MariaDBClient
+port=3309
diff --git a/roles/maxscale/templates/override.conf.j2 b/roles/maxscale/templates/override.conf.j2
new file mode 100644
index 0000000..7ff5b18
--- /dev/null
+++ b/roles/maxscale/templates/override.conf.j2
@@ -0,0 +1,4 @@
+[Service]
+ExecStartPre=+setcap CAP_NET_BIND_SERVICE=+eip /bin/maxscale
+WatchdogSec=10m
+Restart=on-abnormal

From a6b0ea158492f5bb140c1c54acfb8452cf957b37 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Xavi=20Lle=C3=B3=20Tom=C3=A1s?= <xavi@verdnatura.es>
Date: Fri, 11 Apr 2025 08:30:53 +0200
Subject: [PATCH 2/2] maxscale: refs #8822 - delete last notify

---
 roles/maxscale/tasks/maxscale.yml | 1 -
 1 file changed, 1 deletion(-)

diff --git a/roles/maxscale/tasks/maxscale.yml b/roles/maxscale/tasks/maxscale.yml
index 7104dc0..01f044b 100644
--- a/roles/maxscale/tasks/maxscale.yml
+++ b/roles/maxscale/tasks/maxscale.yml
@@ -59,7 +59,6 @@
   loop: "{{ certificates }}"
   notify:
     - restart-maxscale
-    - reload-systemd