From 904a107ae1632a5a68a8b561e7981e2e17e6cd49 Mon Sep 17 00:00:00 2001 From: Faustin Lammler Date: Wed, 12 Oct 2022 14:01:19 +0200 Subject: [PATCH] Add cluster testing in CI (close #26) --- .github/workflows/test_cluster.yml | 69 +++++++++++++++++ .github/workflows/test_default.yml | 4 +- .github/workflows/test_mdbf.yml | 4 +- molecule/cluster/converge.yml | 7 ++ molecule/cluster/molecule.yml | 71 ++++++++++++++++++ molecule/cluster/verify.yml | 34 +++++++++ molecule/vagrant/converge.yml | 9 +++ molecule/vagrant/molecule.yml | 38 ++++++++++ molecule/vagrant/vars/Debian.yml | 1 + molecule/vagrant/vars/RedHat.yml | 1 + molecule/vagrant/vars/testvars.yml | 47 ++++++++++++ molecule/vagrant/verify.yml | 116 +++++++++++++++++++++++++++++ tasks/replication_replica.yml | 38 +++++----- 13 files changed, 415 insertions(+), 24 deletions(-) create mode 100644 .github/workflows/test_cluster.yml create mode 100644 molecule/cluster/converge.yml create mode 100644 molecule/cluster/molecule.yml create mode 100644 molecule/cluster/verify.yml create mode 100644 molecule/vagrant/converge.yml create mode 100644 molecule/vagrant/molecule.yml create mode 120000 molecule/vagrant/vars/Debian.yml create mode 120000 molecule/vagrant/vars/RedHat.yml create mode 100644 molecule/vagrant/vars/testvars.yml create mode 100644 molecule/vagrant/verify.yml diff --git a/.github/workflows/test_cluster.yml b/.github/workflows/test_cluster.yml new file mode 100644 index 0000000..c0eee0f --- /dev/null +++ b/.github/workflows/test_cluster.yml @@ -0,0 +1,69 @@ +--- +name: Cluster deployment + +on: + push: + paths: + - .github/workflows/test_cluster.yml + - requirements.txt + - "files/**" + - "handlers/**" + - "molecule/cluster/**" + - "tasks/**" + - "templates/**" + - "vars/**" + pull_request: + paths: + - .github/workflows/test_cluster.yml + - requirements.txt + - "files/**" + - "handlers/**" + - "molecule/cluster/**" + - "tasks/**" + - "templates/**" + - "vars/**" + schedule: + - cron: "30 5 * * 2" + +jobs: + molecule-distrib-pkg: + name: Cluster + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + distro: + # - ubuntu-18.04 + # - ubuntu-20.04 + - ubuntu-22.04 + # - debian-10 + - debian-11 + # - debian-sid + # - fedora-36 + - fedora-37 + # - almalinux-8 + - almalinux-9 + - rockylinux-8 + # - rockylinux-9 + playbook: + - converge.yml + steps: + - uses: actions/checkout@v3 + - name: Install requirements + run: | + python3 -m pip install --upgrade pip + python3 -m pip install -r requirements.txt + # This is necessary on GH Actions to allow running systemd in rootless containers + # see: https://github.com/actions/virtual-environments/issues/3536 + # see: https://github.com/ansible-community/molecule/discussions/3155 + - name: Start systemd user service + run: | + loginctl enable-linger $(whoami) + sleep 1 + - name: Run molecule + run: molecule test -s cluster + env: + PY_COLORS: "1" + ANSIBLE_FORCE_COLOR: "1" + MOLECULE_DISTRO: ${{ matrix.distro }} + MOLECULE_PLAYBOOK: ${{ matrix.playbook }} diff --git a/.github/workflows/test_default.yml b/.github/workflows/test_default.yml index 6bd2778..99989f8 100644 --- a/.github/workflows/test_default.yml +++ b/.github/workflows/test_default.yml @@ -8,7 +8,7 @@ on: - requirements.txt - "files/**" - "handlers/**" - - "molecule/**" + - "molecule/default/**" - "tasks/**" - "templates/**" - "vars/**" @@ -18,7 +18,7 @@ on: - requirements.txt - "files/**" - "handlers/**" - - "molecule/**" + - "molecule/default/**" - "tasks/**" - "templates/**" - "vars/**" diff --git a/.github/workflows/test_mdbf.yml b/.github/workflows/test_mdbf.yml index 7f0bbeb..20608a4 100644 --- a/.github/workflows/test_mdbf.yml +++ b/.github/workflows/test_mdbf.yml @@ -8,7 +8,7 @@ on: - requirements.txt - "files/**" - "handlers/**" - - "molecule/**" + - "molecule/default/**" - "tasks/**" - "templates/**" - "vars/**" @@ -18,7 +18,7 @@ on: - requirements.txt - "files/**" - "handlers/**" - - "molecule/**" + - "molecule/default/**" - "tasks/**" - "templates/**" - "vars/**" diff --git a/molecule/cluster/converge.yml b/molecule/cluster/converge.yml new file mode 100644 index 0000000..6491b2c --- /dev/null +++ b/molecule/cluster/converge.yml @@ -0,0 +1,7 @@ +--- +- name: Converge + hosts: all + gather_facts: true + + roles: + - role: ansible-role-mariadb diff --git a/molecule/cluster/molecule.yml b/molecule/cluster/molecule.yml new file mode 100644 index 0000000..a69ca07 --- /dev/null +++ b/molecule/cluster/molecule.yml @@ -0,0 +1,71 @@ +--- +driver: + name: podman +platforms: + - name: node1 + image: "fauust/docker-ansible:${MOLECULE_DISTRO:-debian-11}" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + override_command: false + pre_build_image: true + network: local + - name: node2 + image: "fauust/docker-ansible:${MOLECULE_DISTRO:-debian-11}" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + override_command: false + pre_build_image: true + groups: + - replica + network: local + - name: node3 + image: "fauust/docker-ansible:${MOLECULE_DISTRO:-debian-11}" + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:ro + override_command: false + pre_build_image: true + groups: + - replica + network: local +provisioner: + name: ansible + inventory: + group_vars: + all: + mariadb_replication_user: + - name: ReplicationUser + password: ReplicationPassword + state: present + replica: + mariadb_replication_role: replica + mariadb_replication_master_ip: node1 + host_vars: + node1: + mariadb_server_id: 1 + mariadb_bind_address: 0.0.0.0 + mariadb_replication_role: master + mariadb_max_binlog_size: 100M + mariadb_binlog_format: MIXED + mariadb_expire_logs_days: 10 + mariadb_databases: + - name: db + state: present + replicate: true + node2: + mariadb_server_id: 2 + node3: + mariadb_server_id: 3 + env: + ANSIBLE_GATHERING: explicit + ANSIBLE_FORCE_COLOR: true + playbooks: + converge: ${MOLECULE_PLAYBOOK:-converge.yml} +verifier: + name: ansible +scenario: + name: cluster + test_sequence: + - create + - converge + - idempotence + - verify diff --git a/molecule/cluster/verify.yml b/molecule/cluster/verify.yml new file mode 100644 index 0000000..140e116 --- /dev/null +++ b/molecule/cluster/verify.yml @@ -0,0 +1,34 @@ +--- +- name: Verify setup + hosts: all + + tasks: + - name: Get mariadb service status + ansible.builtin.systemd: + name: "mariadb" + register: mariadb_service + + - name: Check that mariadb service is active + ansible.builtin.assert: + that: + - mariadb_service.status.ActiveState == 'active' + +- name: Verify replication + hosts: replica + tasks: + - name: Check that test db exist (created only on master) + ansible.builtin.shell: | + mariadb -Bse 'SHOW DATABASES' | grep -q '^{{ item }}$' + loop: + - db + + - name: Get replica status + ansible.builtin.shell: | + mariadb -Bse 'SHOW SLAVE STATUS\G' + register: replica_status + + - name: Check that replication is working + ansible.builtin.assert: + that: + - "'Waiting for master to send event' in replica_status.stdout" + msg: "{{ replica_status.stdout }}" diff --git a/molecule/vagrant/converge.yml b/molecule/vagrant/converge.yml new file mode 100644 index 0000000..887b93c --- /dev/null +++ b/molecule/vagrant/converge.yml @@ -0,0 +1,9 @@ +--- +- name: Converge + hosts: all + gather_facts: true + vars_files: vars/testvars.yml + become: true + + roles: + - role: ansible-role-mariadb diff --git a/molecule/vagrant/molecule.yml b/molecule/vagrant/molecule.yml new file mode 100644 index 0000000..813d62d --- /dev/null +++ b/molecule/vagrant/molecule.yml @@ -0,0 +1,38 @@ +--- +dependency: + name: galaxy +driver: + name: vagrant + provider: + name: libvirt +platforms: + - name: node1 + box: ${TESTBOX:-debian/buster64} + interfaces: + - network_name: private_network + ip: 192.168.56.11 + memory: 1024 + cpus: 2 + provider_options: + # using session with network leads to troubles + qemu_use_session: false + config_options: + synced_folder: true + instance_raw_config_args: + - 'vm.synced_folder ".", "/vagrant", type: "rsync"' + - name: node2 + box: ${TESTBOX:-debian/bullseye64} + interfaces: + - network_name: private_network + ip: 192.168.56.12 + memory: 1024 + cpus: 2 + provider_options: + # using session with network leads to troubles + qemu_use_session: false + instance_raw_config_args: + - 'vm.synced_folder ".", "/vagrant", type: "rsync"' +provisioner: + name: ansible +scenario: + name: vagrant diff --git a/molecule/vagrant/vars/Debian.yml b/molecule/vagrant/vars/Debian.yml new file mode 120000 index 0000000..c6ef0b7 --- /dev/null +++ b/molecule/vagrant/vars/Debian.yml @@ -0,0 +1 @@ +../../../vars/Debian.yml \ No newline at end of file diff --git a/molecule/vagrant/vars/RedHat.yml b/molecule/vagrant/vars/RedHat.yml new file mode 120000 index 0000000..98913c1 --- /dev/null +++ b/molecule/vagrant/vars/RedHat.yml @@ -0,0 +1 @@ +../../../vars/RedHat.yml \ No newline at end of file diff --git a/molecule/vagrant/vars/testvars.yml b/molecule/vagrant/vars/testvars.yml new file mode 100644 index 0000000..4b64303 --- /dev/null +++ b/molecule/vagrant/vars/testvars.yml @@ -0,0 +1,47 @@ +--- +mariadb_server_id: 1 +mariadb_bind_address: 0.0.0.0 +mariadb_replication_role: master + +mariadb_innodb_raw: | + innodb_buffer_pool_size = 512M + innodb_log_file_size = 64M + innodb_file_per_table = 1 + +mariadb_databases: + - name: db1 + collation: latin1_swedish_ci + encoding: latin1 + state: present + - name: db2 + state: present + replicate: true + +mariadb_users: + - name: user1 + host: "%" + password: user1passwd + priv: "db2.*:SELECT" + state: present + - name: user2 + host: 100.64.10.3 + password: user2passwd + priv: "db2.*:ALL" + state: present + +mariadb_replication_user: + - name: ReplicationUser + host: 100.64.10.33 + password: ReplicationPassword + state: present + +# backup +mariadb_backup_db: true +mariadb_backup_db_cron_min: "50" +mariadb_backup_db_cron_hour: "00" +mariadb_backup_db_dir: "/mnt/backup" +mariadb_backup_db_rotation: "15" + +mariadb_backup_db_name: + - db1 + - db2 diff --git a/molecule/vagrant/verify.yml b/molecule/vagrant/verify.yml new file mode 100644 index 0000000..cb7ac93 --- /dev/null +++ b/molecule/vagrant/verify.yml @@ -0,0 +1,116 @@ +--- +- name: Verify + hosts: all + gather_facts: true + + tasks: + - name: Load OS-specific vars + ansible.builtin.include_vars: "{{ lookup('first_found', params) }}" + vars: + params: + files: + - "{{ ansible_distribution }}.yml" + - "{{ ansible_os_family }}.yml" + paths: + - "vars" + + - name: Gather package facts + ansible.builtin.package_facts: + manager: auto + + - name: Verify Packages + ansible.builtin.assert: + that: "'mariadb-server' in ansible_facts.packages|lower" + + - name: Register {{ mariadb_config_file }} + ansible.builtin.stat: + path: "{{ mariadb_config_file }}" + register: conf + + - name: Check {{ mariadb_config_file }} + ansible.builtin.assert: + that: + - conf.stat.exists is true + - conf.stat.pw_name == 'root' + - conf.stat.gr_name == 'root' + + - name: Register {{ mariadb_data_dir }} + ansible.builtin.stat: + path: "{{ mariadb_data_dir }}" + register: datadir + + - name: Check {{ mariadb_data_dir }} + ansible.builtin.assert: + that: + - datadir.stat.isdir is true + - datadir.stat.pw_name == "{{ mariadb_user }}" + - datadir.stat.gr_name == "{{ mariadb_user }}" + + - name: Register {{ mariadb_log_dir }} + ansible.builtin.stat: + path: "{{ mariadb_log_dir }}" + register: logdir + + - name: Check {{ mariadb_log_dir }} + ansible.builtin.assert: + that: + - logdir.stat.isdir is true + - logdir.stat.pw_name == "{{ mariadb_user }}" + - logdir.stat.gr_name == "{{ mariadb_user }}" + + - name: Get mariadb service status + ansible.builtin.systemd: + name: "mariadb" + register: mariadb_service + + - name: Check that mariadb service is active + ansible.builtin.assert: + that: + - mariadb_service.status.ActiveState == 'active' + + - name: Check that 127.0.0.1:3306 is listening + ansible.builtin.wait_for: + port: 3306 + timeout: 2 + + - name: Get MariaDB version + ansible.builtin.shell: | + sudo mariadb -Bse 'STATUS' | grep "^Server version:" + register: version + when: "{{ lookup('env', 'MARIADB_VERSION') }}" + + - name: Check MariaDB version + ansible.builtin.assert: + that: + - "'{{ lookup('env', 'MARIADB_VERSION') }}' in version.stdout" + msg: "{{ version.stdout }}" + when: "{{ lookup('env', 'MARIADB_VERSION') }}" + + - name: Check that Innodb engine is enabled (and default) + ansible.builtin.shell: | + sudo mariadb -Bse 'SHOW ENGINES' | grep -qE '^InnoDB.DEFAULT.*YES.YES.YES$' + + - name: Check that default db exist + ansible.builtin.shell: | + sudo mariadb -Bse 'SHOW DATABASES' | grep -q '^{{ item }}$' + loop: + - mysql + - information_schema + - performance_schema + + - name: Check that test db exist + ansible.builtin.shell: | + sudo mariadb -Bse 'SHOW DATABASES' | grep -q '^{{ item }}$' + loop: + - db1 + - db2 + + - name: Do some SQL queries + ansible.builtin.shell: | + sudo mariadb -Bse 'DROP DATABASE IF EXIST db' + sudo mariadb -Bse 'CREATE DATABASE db' + sudo mariadb -e 'CREATE TABLE db.t_innodb(a1 SERIAL, c1 CHAR(8)) ENGINE=InnoDB; INSERT INTO db.t_innodb VALUES (1,"foo"),(2,"bar")' + sudo mariadb -e 'CREATE FUNCTION db.f() RETURNS INT DETERMINISTIC RETURN 1' + sudo mariadb -e 'SHOW TABLES IN db' + sudo mariadb -e 'SELECT * FROM db.t_innodb; INSERT INTO db.t_innodb VALUES (3,"foo"),(4,"bar")' + sudo mariadb -e 'SELECT db.f()' diff --git a/tasks/replication_replica.yml b/tasks/replication_replica.yml index b0a16e5..9dd2804 100644 --- a/tasks/replication_replica.yml +++ b/tasks/replication_replica.yml @@ -6,32 +6,30 @@ register: replica no_log: true -# For the moment, we have to use a sql command. -# In ansible 2.10, we should be able to use mysql_replication module. -# See https://github.com/ansible/ansible/pull/62648 (and below) +# # Keeping this for the record +# # See https://github.com/ansible/ansible/pull/62648 +# - name: Configure replication on the replica +# ansible.builtin.command: | +# /usr/bin/mariadb -e "CHANGE MASTER TO master_host='{{ mariadb_replication_master_ip }}', +# master_user='{{ item.name }}', master_password='{{ item.password }}', master_use_gtid=slave_pos" +# loop: "{{ mariadb_replication_user }}" +# when: +# - not replica.Is_Replica +# no_log: true + - name: Configure replication on the replica - ansible.builtin.command: | - /usr/bin/mariadb -e "CHANGE MASTER TO master_host='{{ mariadb_replication_master_ip }}', - master_user='{{ item.name }}', master_password='{{ item.password }}', master_use_gtid=slave_pos" + community.mysql.mysql_replication: + mode: changeprimary + master_host: "{{ mariadb_replication_master_ip }}" + master_user: "{{ item.name }}" + master_password: "{{ item.password }}" + master_use_gtid: "{{ mariadb_replication_gtid | default('replica_pos') }}" + login_unix_socket: "{{ mariadb_unix_socket }}" loop: "{{ mariadb_replication_user }}" when: - not replica.Is_Replica no_log: true -# # Following (not tested) should work on ansible 2.10 -# - name: Configure replication on the replica -# mysql_replication: -# mode: changemaster -# master_host: "{{ mariadb_replication_master_ip }}" -# master_user: "{{ item.name }}" -# master_password: "{{ item.password }}" -# master_use_gtid: "{{ mariadb_replication_gtid | default('slave_pos') }} -# login_unix_socket: "{{ mariadb_unix_socket }}" -# loop: "{{ mariadb_replication_user }}" -# when: -# - not replica.Is_Slave -# no_log: true - - name: Reset replica replication community.mysql.mysql_replication: mode: resetreplica