diff --git a/pmm_qa/percona_server/data/ps_load.sql b/pmm_qa/data/mysql_load.sql similarity index 91% rename from pmm_qa/percona_server/data/ps_load.sql rename to pmm_qa/data/mysql_load.sql index 6df95275..a98191a0 100644 --- a/pmm_qa/percona_server/data/ps_load.sql +++ b/pmm_qa/data/mysql_load.sql @@ -7,13 +7,13 @@ CREATE TABLE students ( first_name VARCHAR(50), last_name VARCHAR(50), birth_date DATE -); +) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8; CREATE TABLE classes ( class_id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), teacher VARCHAR(100) -); +) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8; CREATE TABLE enrollments ( enrollment_id INT AUTO_INCREMENT PRIMARY KEY, @@ -22,7 +22,7 @@ CREATE TABLE enrollments ( enrollment_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (student_id) REFERENCES students(student_id), FOREIGN KEY (class_id) REFERENCES classes(class_id) -); +) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8; -- ======================================== -- INSERT INITIAL DATA @@ -91,4 +91,4 @@ DELETE FROM enrollments WHERE student_id = (SELECT student_id FROM students WHERE first_name = 'Alice' AND last_name = 'Smith'); DELETE FROM students -WHERE first_name = 'Alice' AND last_name = 'Smith'; \ No newline at end of file +WHERE first_name = 'Alice' AND last_name = 'Smith'; diff --git a/pmm_qa/mysql/data/my-async-replication-57.cnf.j2 b/pmm_qa/mysql/data/my-async-replication-57.cnf.j2 new file mode 100644 index 00000000..a7e3e1d8 --- /dev/null +++ b/pmm_qa/mysql/data/my-async-replication-57.cnf.j2 @@ -0,0 +1,37 @@ +[mysqld] +# General server configuration +server_id={{ item }} +bind-address=0.0.0.0 +port={{ mysql_listen_port }} + +# Replication settings +gtid_mode=ON +enforce_gtid_consistency=ON +log_bin=binlog +log_slave_updates=ON +sync_binlog=1 +binlog_checksum=NONE +# Only disable engines supported in 5.7 and safe for GTID +disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE" +# MacOS-specific, where table names are case-sensitive +lower_case_table_names=2 + +# Optional: report_host is valid in 5.7 +report_host={{ container_prefix }}{{ item }} + +# Replica configuration - applies to all nodes except primary (they'll be able to become replicas) +{% if item != 1 %} +# Replica specific settings (use slave_parallel_* in 5.7) +slave_parallel_workers=4 +slave_parallel_type=LOGICAL_CLOCK +slave_preserve_commit_order=1 +{% endif %} + +# Crash-safe replication settings +relay-log={{ container_prefix }}{{ item }}-relay-bin +relay_log_recovery=ON +relay_log_purge=ON + +# Performance and connection settings +max_connections=1000 +innodb_buffer_pool_size=256M diff --git a/pmm_qa/percona_server/data/my-async-replication.cnf.j2 b/pmm_qa/mysql/data/my-async-replication.cnf.j2 similarity index 90% rename from pmm_qa/percona_server/data/my-async-replication.cnf.j2 rename to pmm_qa/mysql/data/my-async-replication.cnf.j2 index 014d37f7..efce584c 100644 --- a/pmm_qa/percona_server/data/my-async-replication.cnf.j2 +++ b/pmm_qa/mysql/data/my-async-replication.cnf.j2 @@ -3,7 +3,6 @@ server_id={{ item }} bind-address=0.0.0.0 port={{ mysql_listen_port }} -userstat=1 # Authentication settings for caching_sha2_password caching_sha2_password_auto_generate_rsa_keys=ON @@ -23,7 +22,7 @@ disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY" lower_case_table_names=2 # MySQL 8.4 compatibility settings -report_host=ps_pmm_{{ ps_version }}_{{ item }} +report_host={{ container_prefix }}{{ item }} # Replica configuration - applies to all nodes except primary (they'll be able to become replicas) {% if item != 1 %} @@ -34,7 +33,7 @@ replica_preserve_commit_order=1 {% endif %} # Crash-safe replication settings -relay-log=ps_pmm_{{ ps_version }}_{{ item }}-relay-bin +relay-log={{ container_prefix }}{{ item }}-relay-bin relay_log_recovery=ON relay_log_purge=ON diff --git a/pmm_qa/mysql/data/my-group-replication-57.cnf.j2 b/pmm_qa/mysql/data/my-group-replication-57.cnf.j2 new file mode 100644 index 00000000..84c98784 --- /dev/null +++ b/pmm_qa/mysql/data/my-group-replication-57.cnf.j2 @@ -0,0 +1,48 @@ +[mysqld] +# General server configuration +server_id={{ server_id_start + item - 1 }} +binlog_format=ROW +bind-address=0.0.0.0 +port={{ mysql_listen_port }} + +# 5.7 General replication settings +gtid_mode=ON +enforce_gtid_consistency=ON +master_info_repository=TABLE +relay_log_info_repository=TABLE +transaction_write_set_extraction=XXHASH64 +binlog_checksum=NONE +log_bin=binlog +log_slave_updates=ON +# NO: disabled_storage_engines in 5.7 +lower_case_table_names=2 + +# Report host for replication/monitoring +report_host={{ container_prefix }}{{ item }} + +# Group Replication Settings +# (Available in MySQL 5.7.17+ and must be installed as plugin) +plugin_load_add='group_replication.so' +loose-group_replication_group_name='aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' +loose-group_replication_local_address='{{ container_prefix }}{{ item }}:{{ group_seeds_port }}' +loose-group_replication_group_seeds={% for i in range(1, nodes_count | int + 1) %}{{ container_prefix }}{{ i }}:{{ group_seeds_port }}{% if not loop.last %},{% endif %}{% endfor %} +loose-group_replication_communication_stack=XCOM + +# Group replication behavior +loose-group_replication_start_on_boot=OFF +loose-group_replication_bootstrap_group=OFF +loose-group_replication_single_primary_mode=ON +loose-group_replication_enforce_update_everywhere_checks=OFF + +# Recovery settings +loose-group_replication_recovery_retry_count=10 +loose-group_replication_recovery_reconnect_interval=60 + +# Crash-safe replication settings +relay-log={{ container_prefix }}{{ item }}-relay-bin +relay_log_recovery=ON +relay_log_purge=ON + +# Performance and connection settings +max_connections=1000 +innodb_buffer_pool_size=256M diff --git a/pmm_qa/mysql/data/my-group-replication.cnf.j2 b/pmm_qa/mysql/data/my-group-replication.cnf.j2 new file mode 100644 index 00000000..9c0f4076 --- /dev/null +++ b/pmm_qa/mysql/data/my-group-replication.cnf.j2 @@ -0,0 +1,44 @@ +[mysqld] +# General server configuration +server_id={{ server_id_start + item - 1 }} +bind-address=0.0.0.0 +port={{ mysql_listen_port }} + +# General replication settings +gtid_mode=ON +enforce_gtid_consistency=ON +binlog_checksum=NONE +log_bin=binlog +log_replica_updates=ON +disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY" +lower_case_table_names=2 # MacOS-specific, but also good generally + +# MySQL 8.4 compatibility settings +report_host={{ container_prefix }}{{ item }} + +# Group Replication Settings +plugin_load_add='group_replication.so' +loose-group_replication_group_name='aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' +loose-group_replication_local_address='{{ container_prefix }}{{ item }}:{{ group_seeds_port }}' +loose-group_replication_group_seeds='{% for i in range(1, nodes_count | int + 1) %}{{ container_prefix }}{{ i }}:{{ group_seeds_port }}{% if not loop.last %},{% endif %}{% endfor %}' +loose-group_replication_communication_stack=XCOM + +# Group replication behavior +loose-group_replication_start_on_boot=OFF +loose-group_replication_bootstrap_group=OFF +loose-group_replication_single_primary_mode=ON +loose-group_replication_enforce_update_everywhere_checks=OFF + +# Recovery settings +loose-group_replication_recovery_get_public_key=ON +loose-group_replication_recovery_retry_count=10 +loose-group_replication_recovery_reconnect_interval=60 + +# Crash-safe replication settings +relay-log={{ container_prefix }}{{ item }}-relay-bin +relay_log_recovery=ON +relay_log_purge=ON + +# Performance and connection settings +max_connections=1000 +innodb_buffer_pool_size=256M diff --git a/pmm_qa/mysql/data/my.cnf.j2 b/pmm_qa/mysql/data/my.cnf.j2 new file mode 100644 index 00000000..6aa308b3 --- /dev/null +++ b/pmm_qa/mysql/data/my.cnf.j2 @@ -0,0 +1,2 @@ +[mysqld] +plugin-load-add=auth_native_password.so diff --git a/pmm_qa/mysql/mysql-setup.yml b/pmm_qa/mysql/mysql-setup.yml new file mode 100644 index 00000000..c9a51069 --- /dev/null +++ b/pmm_qa/mysql/mysql-setup.yml @@ -0,0 +1,173 @@ +--- + +- name: MySQL single, cluster with group Replication in Docker + hosts: localhost + connection: local + gather_facts: yes + vars: + mysql_version: "{{ (lookup('env', 'MS_VERSION') | default('8.0', true)) | replace('.', '_') }}" + replication_user: "repl_user" + replication_password: "GRgrO9301RuF" + root_password: "GRgrO9301RuF" + mysql_port: 33066 + mysql_listen_port: 3306 + group_seeds_port: 34061 + nodes_count: "{{ (lookup('env', 'NODES_COUNT') | default('1', true)) | int }}" + network_name: "pmm-qa" + data_dir: "{{ lookup('env', 'HOME') }}/mysql_cluster_data" + server_id_start: 1 + pmm_server_ip: "{{ lookup('vars', 'extra_pmm_server_ip', default=lookup('env','PMM_SERVER_IP') | default('127.0.0.1', true) ) }}" + client_version: "{{ lookup('vars', 'extra_client_version', default=lookup('env','CLIENT_VERSION') | default('3-dev-latest', true) ) }}" + admin_password: "{{ lookup('vars', 'extra_admin_password', default=lookup('env','ADMIN_PASSWORD') | default('admin', true) ) }}" + query_source: "{{ lookup('env', 'QUERY_SOURCE') | default('perfschema', true) }}" + metrics_mode: "{{ lookup('env', 'metrics_mode') }}" + setup_type: "{{ lookup('env', 'SETUP_TYPE') }}" + random_service_name_value: "" + my_rocks: "{{ lookup('env', 'MY_ROCKS') | default(false, true) }}" + container_prefix: "mysql_pmm{{ (setup_type|default('')) and '_' ~ setup_type }}_{{ mysql_version }}_" + + tasks: +# - name: Fail if setup_type is gr or replication and version is less than 80 +# fail: +# msg: "This setup_type ({{ setup_type }}) with version {{ mysql_version | replace('_', '.') }} is not supported!" +# when: (setup_type == 'gr' or setup_type == 'replication') and (mysql_version | replace('_', '') | int < 80) + + - name: Modify the node count for group replication + set_fact: + nodes_count: 3 + when: nodes_count | int < 3 and setup_type == "gr" + + - name: Chance to correct nodes count for async replication + set_fact: + nodes_count: 2 + when: nodes_count | int < 2 and setup_type == "replication" + + - name: Create Docker network + shell: docker network create {{ network_name }} + ignore_errors: true + + - name: Remove old data folders + shell: 'rm -fr {{ data_dir }}' + loop: "{{ range(1, nodes_count | int + 1) | list }}" + + - name: Create data directories + file: + path: "{{ data_dir }}/node{{ item }}/data" + state: directory + mode: '0755' + loop: "{{ range(1, nodes_count | int + 1) | list }}" + + - name: Recursively change ownership of a directory + shell: "sudo chown -R 1001:1001 {{ data_dir }}/node{{ item }}/data" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + + - name: Setup MySQL group replication + include_tasks: ./tasks/mysql-group-replication-setup.yml + when: setup_type == "gr" + + - name: Setup MySQL with async replication + include_tasks: ./tasks/mysql-async-replication-setup.yml + when: setup_type == "replication" + + - name: Setup MySQL + include_tasks: tasks/mysql-single.yml + when: setup_type != "gr" and setup_type != "replication" + + - name: Wait 10 seconds for setup to finish + pause: + seconds: 10 + + - name: Create slowlog configuration for mysql nodes + shell: | + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "SET GLOBAL slow_query_log='ON'; SET GLOBAL long_query_time=0;" + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "SET GLOBAL log_slow_admin_statements=ON; SET GLOBAL log_slow_slave_statements=ON;" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: query_source == "slowlog" + + - name: Install and add pmm client. + include_tasks: ../tasks/install_pmm_client.yml + vars: + container_name: "{{ container_prefix }}{{ item }}" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + + - name: Generate random service name suffix + set_fact: + random_service_name_value: "_{{ 99999 | random + 1 }}" + + - name: Add service to pmm server + shell: docker exec {{ container_prefix }}{{ item }} pmm-admin add mysql --query-source={{ query_source }} --username=root --password={{ root_password }} --environment=mysql-gr-dev --cluster=mysql-gr-dev-cluster --replication-set=mysql-gr-replication {{ container_prefix }}{{ item }}{{ random_service_name_value }} --debug 127.0.0.1:3306 + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: setup_type == "gr" + + - name: Add service to pmm server + shell: docker exec {{ container_prefix }}{{ item }} pmm-admin add mysql --query-source={{ query_source }} --username=root --password={{ root_password }} --environment=mysql-replication-dev --cluster=mysql-replication-dev-cluster --replication-set=mysql-async-replication {{ container_prefix }}{{ item }}{{ random_service_name_value }} --debug 127.0.0.1:3306 + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: setup_type == "replication" + + - name: Add service to pmm server + shell: docker exec {{ container_prefix }}{{ item }} pmm-admin add mysql --query-source={{ query_source }} --username=root --password={{ root_password }} --cluster=mysql-single-dev-cluster --environment=mysql-dev {{ container_prefix }}{{ item }}{{ random_service_name_value }} --debug 127.0.0.1:3306 + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: setup_type != "gr" and setup_type != "replication" + + - name: Install sysbench inside of all mysql nodes + shell: docker exec {{ container_prefix }}{{ item }} apt-get install -y sysbench + loop: "{{ range(1, nodes_count | int + 1) | list }}" + + - name: Prepare sysbench inside of all mysql nodes + shell: docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "SET GLOBAL super_read_only = OFF; SET GLOBAL read_only = OFF;" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + + - name: Prepare sysbench inside of all mysql nodes + shell: | + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "CREATE DATABASE sbtest; CREATE USER 'sbtest'@'localhost' IDENTIFIED BY 'password';" + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "GRANT ALL PRIVILEGES ON *.* TO 'sbtest'@'localhost'; CREATE USER 'sbtest'@'127.0.0.1' IDENTIFIED BY 'password';" + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "GRANT ALL PRIVILEGES ON *.* TO 'sbtest'@'127.0.0.1'; FLUSH PRIVILEGES;" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: setup_type != "gr" and setup_type != "replication" #and mysql_version | replace('_', '') | int >= 84 + + - name: Prepare sysbench inside of primary mysql node + shell: | + docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e "CREATE DATABASE sbtest; CREATE USER 'sbtest'@'localhost' IDENTIFIED BY 'password';" + docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e "GRANT ALL PRIVILEGES ON *.* TO 'sbtest'@'localhost'; CREATE USER 'sbtest'@'127.0.0.1' IDENTIFIED BY 'password';" + docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e "GRANT ALL PRIVILEGES ON *.* TO 'sbtest'@'127.0.0.1'; FLUSH PRIVILEGES;" + when: setup_type == "gr" or setup_type == "replication" # and mysql_version | replace('_', '') | int >= 84 + + - name: Prepare data for sysbench inside of all mysql nodes + shell: | + docker exec {{ container_prefix }}{{ item }} sysbench /usr/share/sysbench/oltp_read_write.lua --mysql-host=127.0.0.1 --mysql-port=3306 --mysql-user=sbtest --mysql-password=password --mysql-db=sbtest --tables=10 --table-size=100000 prepare + when: setup_type != "gr" and setup_type != "replication" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + + - name: Prepare data for sysbench inside of first mysql nodes + shell: docker exec {{ container_prefix }}1 sysbench /usr/share/sysbench/oltp_read_write.lua --mysql-host=127.0.0.1 --mysql-port=3306 --mysql-user=sbtest --mysql-password=password --mysql-db=sbtest --tables=10 --table-size=100000 prepare + when: setup_type == "gr" or setup_type == "replication" + + - name: Run load for sysbench inside of all mysql nodes + shell: docker exec {{ container_prefix }}{{ item }} sysbench /usr/share/sysbench/oltp_read_write.lua --mysql-host=127.0.0.1 --mysql-port=3306 --mysql-user=sbtest --mysql-password=password --mysql-db=sbtest --tables=10 --table-size=100000 --threads=16 --time=60 run + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: setup_type != "gr" and setup_type != "replication" + + - name: Run load for sysbench inside of primary mysql node + shell: docker exec {{ container_prefix }}1 sysbench /usr/share/sysbench/oltp_read_write.lua --mysql-host=127.0.0.1 --mysql-port=3306 --mysql-user=sbtest --mysql-password=password --mysql-db=sbtest --tables=10 --table-size=100000 --threads=16 --time=60 run + when: setup_type == "gr" and setup_type == "replication" + + - name: Copy a load file into the container + shell: docker cp ../data/mysql_load.sql {{ container_prefix }}{{ item }}:/mysql_load.sql + loop: "{{ range(1, nodes_count | int + 1) | list }}" + + - name: Wait 10 seconds for node to be connected + pause: + seconds: 10 + + - name: Run load inside of first mysql node + shell: | + docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e "CREATE DATABASE school;" + docker exec {{ container_prefix }}1 sh -c "mysql -uroot -p{{ root_password }} school < /mysql_load.sql" + when: setup_type in ['gr', 'replication'] and (mysql_version | replace('_','') | int) >= 80 + + - name: Run load inside of all mysql nodes + shell: | + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "CREATE DATABASE school;" + docker exec {{ container_prefix }}{{ item }} sh -c "mysql -uroot -p{{ root_password }} school < /mysql_load.sql" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: setup_type not in ['gr', 'replication'] and (mysql_version | replace('_','') | int) >= 80 \ No newline at end of file diff --git a/pmm_qa/mysql/tasks/mysql-async-replication-setup.yml b/pmm_qa/mysql/tasks/mysql-async-replication-setup.yml new file mode 100644 index 00000000..908bb68a --- /dev/null +++ b/pmm_qa/mysql/tasks/mysql-async-replication-setup.yml @@ -0,0 +1,86 @@ +- name: Generate my.cnf for each node + template: + src: ./data/my-async-replication{{ '-57' if mysql_version | replace('_', '') == '57' else '' }}.cnf.j2 + dest: "{{ data_dir }}/node{{ item }}/my.cnf" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + +- name: Prepare docker container and install MySQL + include_tasks: ./tasks/prepare_install_mysql.yml + vars: + index: "{{ item }}" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + +- name: Reset configuration for all nodes + shell: docker exec {{ container_prefix}}{{ item }} mysql -uroot -p{{ root_password }} -e "RESET BINARY LOGS AND GTIDS; RESET REPLICA ALL;" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + ignore_errors: yes + +- name: Configure replica servers (container2-containerN) for MySQL 8.0 and above + shell: > + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e " + CHANGE REPLICATION SOURCE TO + SOURCE_HOST='{{ container_prefix }}1', + SOURCE_PORT={{ mysql_listen_port }}, + SOURCE_USER='{{ replication_user }}', + SOURCE_PASSWORD='{{ replication_password }}', + SOURCE_AUTO_POSITION=1, + SOURCE_PUBLIC_KEY_PATH='', + GET_SOURCE_PUBLIC_KEY=1; + START REPLICA; + " + loop: "{{ range(2, nodes_count | int + 1) | list }}" + when: mysql_version | replace('_', '') | int >= 80 + +- name: Configure replica servers (container2-containerN) for Mysql 5.7 + shell: > + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e " + CHANGE MASTER TO + MASTER_HOST='{{ container_prefix }}1', + MASTER_PORT={{ mysql_listen_port }}, + MASTER_USER='{{ replication_user }}', + MASTER_PASSWORD='{{ replication_password }}', + MASTER_AUTO_POSITION=1; + START SLAVE; + " + loop: "{{ range(2, nodes_count | int + 1) | list }}" + when: mysql_version | replace('_', '') | int < 80 + +- name: Create and seed a test database on primary + shell: > + docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e " + CREATE DATABASE testdb; + USE testdb; + CREATE TABLE testdb (id INT PRIMARY KEY, data VARCHAR(100)); + INSERT INTO testdb VALUES (1, 'Initial data from node mysql1'); + " +- name: Check replication status on replica nodes + shell: docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "SHOW REPLICA STATUS\G" + register: replication_status + loop: "{{ range(2, nodes_count | int + 1) | list }}" + changed_when: false + when: mysql_version | replace('_', '') | int >= 80 + +- name: Check replication status on replica nodes + shell: docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "SHOW SLAVE STATUS\G" + register: replication_status + loop: "{{ range(2, nodes_count | int + 1) | list }}" + changed_when: false + when: mysql_version | replace('_', '') | int < 80 + +- name: Set verification instructions + set_fact: + verification_msg: | + MySQL Cluster setup complete with asynchronous replication! + To verify replication is working: + 1. Connect to the primary ({{ container_prefix }}1): + docker exec -it {{ container_prefix }}1 mysql -uroot -p{{ root_password }} + 2. Insert data in the test database: + USE testdb; + INSERT INTO testdb VALUES (100, 'Test replication'); + 3. Connect to replicas and verify data is replicated: + docker exec -it {{ container_prefix }}2 mysql -uroot -p{{ root_password }} + USE testdb; + SELECT * FROM testdb; +- name: Display verification instructions + debug: + msg: "{{ verification_msg | split('\n') }}" diff --git a/pmm_qa/mysql/tasks/mysql-group-replication-setup.yml b/pmm_qa/mysql/tasks/mysql-group-replication-setup.yml new file mode 100644 index 00000000..6c92966e --- /dev/null +++ b/pmm_qa/mysql/tasks/mysql-group-replication-setup.yml @@ -0,0 +1,123 @@ +- name: Generate my.cnf for each node + template: + src: ./data/my-group-replication{{ '-57' if mysql_version | replace('_', '') == '57' else '' }}.cnf.j2 + dest: "{{ data_dir }}/node{{ item }}/my.cnf" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + +- name: Prepare docker container and install Percona Server for MySQL + include_tasks: ./tasks/prepare_install_mysql.yml + vars: + index: "{{ item }}" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + +- name: Reset configuration for all nodes for MySQL 8.4 + shell: > + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e"RESET BINARY LOGS AND GTIDS; RESET REPLICA ALL; SET GLOBAL gtid_purged='';" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: mysql_version | replace('_', '') | int >= 84 + +- name: Reset configuration for all nodes for MySQL 8.0 + shell: > + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "RESET MASTER; RESET SLAVE ALL;" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: mysql_version | replace('_', '') | int < 84 + +- name: Init configuration for group replication (single exec per node, no binlog) for MySQL 8.0+ + shell: | + docker exec -i {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} <<'EOSQL' + SET SQL_LOG_BIN=0; + CREATE USER IF NOT EXISTS '{{ replication_user }}'@'%' IDENTIFIED BY '{{ replication_password }}'; + GRANT REPLICATION SLAVE ON *.* TO '{{ replication_user }}'@'%'; + GRANT CONNECTION_ADMIN ON *.* TO '{{ replication_user }}'@'%'; + GRANT BACKUP_ADMIN ON *.* TO '{{ replication_user }}'@'%'; + GRANT GROUP_REPLICATION_STREAM ON *.* TO '{{ replication_user }}'@'%'; + GRANT SERVICE_CONNECTION_ADMIN ON *.* TO '{{ replication_user }}'@'%'; + GRANT SYSTEM_VARIABLES_ADMIN ON *.* TO '{{ replication_user }}'@'%'; + FLUSH PRIVILEGES; + -- Configure recovery channel credentials (explicit host/port to primary node) + CHANGE REPLICATION SOURCE TO + SOURCE_USER='{{ replication_user }}', + SOURCE_PASSWORD='{{ replication_password }}' + FOR CHANNEL 'group_replication_recovery'; + SET SQL_LOG_BIN=1; + EOSQL + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: mysql_version | replace('_', '') | int >= 80 + +- name: Init configuration for group replication (single exec per node, no binlog) for MySQL 5.7 + shell: | + docker exec -i {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} <<'EOSQL' + SET SQL_LOG_BIN=0; + CREATE USER IF NOT EXISTS 'repl_user'@'%' IDENTIFIED BY 'GRgrO9301RuF'; + GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%'; + FLUSH PRIVILEGES; + -- Configure recovery channel credentials (explicit host/port to primary node) + CHANGE MASTER TO + MASTER_USER='{{ replication_user }}', + MASTER_PASSWORD='{{ replication_password }}' + FOR CHANNEL 'group_replication_recovery'; + SET SQL_LOG_BIN=1; + EOSQL + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: mysql_version | replace('_', '') | int < 80 + +- name: Bootstrap first node (primary) for MySQL 8.4/8.0 + shell: | + docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e "SET GLOBAL group_replication_bootstrap_group=ON;" + docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e "START GROUP_REPLICATION;" + docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e "SET GLOBAL group_replication_bootstrap_group=OFF;" +- name: Wait for bootstrap to complete + pause: + seconds: 10 + +- name: Start group replication on other nodes + shell: | + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "START GROUP_REPLICATION;" + loop: "{{ range(2, nodes_count | int + 1) | list }}" + +- name: Wait 10 seconds for the other nodes to join + pause: + seconds: 10 + +- name: Create and seed a test database on primary + shell: > + docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e " + CREATE DATABASE testdb; + USE testdb; + CREATE TABLE testdb (id INT PRIMARY KEY, data VARCHAR(100)); + INSERT INTO testdb VALUES (1, 'Initial data from node mysql1'); + " +- name: Check replication status on first node + shell: docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e "SELECT * FROM performance_schema.replication_group_members;" + register: replication_status + +- name: Display replication status + debug: + var: replication_status.stdout + +- name: Check replication group members count + shell: docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e "SELECT COUNT(*) AS count FROM performance_schema.replication_group_members;" + register: member_count + +- name: Display member count + debug: + var: member_count.stdout + +- name: Set verification instructions + set_fact: + verification_msg: | + MySQL Cluster setup complete! + To verify replication is working: + 1. Connect to the first node: + docker exec -it {{ container_prefix }}1 mysql -uroot -p{{ root_password }} + 2. Insert data in the test database: + USE testdb; + INSERT INTO testdb VALUES (100, 'Test replication'); + 3. Connect to other nodes and verify data is replicated: + docker exec -it {{ container_prefix }}2 mysql -uroot -p{{ root_password }} + USE testdb; + SELECT * FROM testdb; + +- name: Display verification instructions + debug: + msg: "{{ verification_msg | split('\n') }}" diff --git a/pmm_qa/mysql/tasks/mysql-single.yml b/pmm_qa/mysql/tasks/mysql-single.yml new file mode 100644 index 00000000..7040cf3f --- /dev/null +++ b/pmm_qa/mysql/tasks/mysql-single.yml @@ -0,0 +1,11 @@ +- name: Generate my.cnf for each node + template: + src: ./data/my.cnf.j2 + dest: "{{ data_dir }}/node{{ item }}/my.cnf" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + +- name: Prepare docker container and install Percona Server for MySQL + include_tasks: ./tasks/prepare_install_mysql.yml + vars: + index: "{{ item }}" + loop: "{{ range(1, nodes_count | int + 1) | list }}" diff --git a/pmm_qa/mysql/tasks/prepare_install_mysql.yml b/pmm_qa/mysql/tasks/prepare_install_mysql.yml new file mode 100644 index 00000000..7867f965 --- /dev/null +++ b/pmm_qa/mysql/tasks/prepare_install_mysql.yml @@ -0,0 +1,125 @@ +- name: Prepare Container for MySQL 8.0+ + shell: | + docker run --rm -d --name="{{ container_prefix }}{{ item }}" \ + --network="pmm-qa" \ + --privileged --cgroupns=host -v /sys/fs/cgroup:/sys/fs/cgroup:rw \ + -v /var/lib/containerd \ + -v ./ssl:/ssl \ + antmelekhin/docker-systemd:ubuntu-24.04 + when: mysql_version | replace('_', '') | int >= 80 + +- name: Prepare Container for MySQL 5.7 + shell: | + docker run --rm -d --name="{{ container_prefix }}{{ item }}" \ + --network="pmm-qa" \ + --privileged --cgroupns=host -v /sys/fs/cgroup:/sys/fs/cgroup:rw \ + -v /var/lib/containerd \ + -v ./ssl:/ssl \ + antmelekhin/docker-systemd:ubuntu-22.04 + when: mysql_version | replace('_', '') | int < 80 + +- name: Install dependencies + shell: | + docker exec {{ container_prefix }}{{ index }} apt-get update + docker exec {{ container_prefix }}{{ index }} apt-get -y install wget gnupg2 lsb-release curl xz-utils libnuma1 +- name: Install MySQL 8.0+ dependencies + shell: | + docker exec {{ container_prefix }}{{ index }} apt-get update + docker exec {{ container_prefix }}{{ index }} apt-get install -y libncurses6 libaio1t64 + docker exec {{ container_prefix }}{{ index }} ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1 + when: mysql_version | replace('_', '') | int >= 80 + +- name: Install MySQL 5.7 dependencies + shell: | + docker exec {{ container_prefix }}{{ index }} apt-get update + docker exec {{ container_prefix }}{{ index }} apt-get install -y libaio1 libncurses5 + when: mysql_version | replace('_', '') | int == 57 + +- name: Query Docker Hub for MySQL tags + uri: + url: "https://hub.docker.com/v2/repositories/library/mysql/tags?page_size=100&name={{ mysql_version | replace('_', '.') }}" + method: GET + return_content: yes + register: mysql_tags_response + +- name: Extract tag names (only versions) + set_fact: + mysql_exact_version: "{{ mysql_tags_response.json.results | map(attribute='name') | list | select('match', '^[0-9]+\\.[0-9]+\\.[0-9]+$') | first }}" + +- name: Install MySQL 8.0+ + shell: | + docker exec {{ container_prefix }}{{ index }} wget -q -O mysql.tar.xz https://dev.mysql.com/get/Downloads/MySQL-{{ mysql_version | replace('_', '.') }}/mysql-{{ mysql_exact_version }}-linux-glibc2.28-x86_64.tar.xz + docker exec {{ container_prefix }}{{ index }} tar -xf mysql.tar.xz + docker exec {{ container_prefix }}{{ index }} groupadd mysql + docker exec {{ container_prefix }}{{ index }} useradd -r -g mysql -s /bin/false mysql + docker exec {{ container_prefix }}{{ index }} mv mysql-{{ mysql_exact_version }}-linux-glibc2.28-x86_64 /usr/local/mysql + docker exec {{ container_prefix }}{{ index }} ln -s /usr/local/mysql-{{ mysql_exact_version }}-linux-glibc2.28-x86_64 mysql + docker exec {{ container_prefix }}{{ index }} chown -R mysql:mysql /usr/local/mysql + docker exec {{ container_prefix }}{{ index }} mkdir /usr/local/mysql/data + docker exec {{ container_prefix }}{{ index }} chown mysql:mysql /usr/local/mysql/data + docker exec {{ container_prefix }}{{ index }} /usr/local/mysql/bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data + docker exec {{ container_prefix }}{{ index }} cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysql + docker exec {{ container_prefix }}{{ index }} chmod +x /etc/init.d/mysql + docker exec {{ container_prefix }}{{ index }} sh -c "echo 'export PATH=/usr/local/mysql/bin:\$PATH' >> /etc/profile" + docker exec {{ container_prefix }}{{ index }} ln -s /usr/local/mysql/bin/mysql /usr/bin/mysql + docker exec {{ container_prefix }}{{ index }} bash -c 'source ~/.bashrc' + register: mysql_80_root_password + when: mysql_version | replace('_', '') | int >= 80 + +- name: Install MySQL 5.7 + shell: | + docker exec {{ container_prefix }}{{ index }} wget -q -O mysql.tar.gz https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz + docker exec {{ container_prefix }}{{ index }} tar zxf mysql.tar.gz + docker exec {{ container_prefix }}{{ index }} groupadd mysql + docker exec {{ container_prefix }}{{ index }} useradd -r -g mysql -s /bin/false mysql + docker exec {{ container_prefix }}{{ index }} mv mysql-5.7.44-linux-glibc2.12-x86_64 /usr/local/mysql + docker exec {{ container_prefix }}{{ index }} ln -s /usr/local/mysql-5.7.44-linux-glibc2.12-x86_64 mysql + docker exec {{ container_prefix }}{{ index }} chown -R mysql:mysql /usr/local/mysql + docker exec {{ container_prefix }}{{ index }} mkdir /usr/local/mysql/data + docker exec {{ container_prefix }}{{ index }} chown mysql:mysql /usr/local/mysql/data + docker exec {{ container_prefix }}{{ index }} /usr/local/mysql/bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data + docker exec {{ container_prefix }}{{ index }} cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysql + docker exec {{ container_prefix }}{{ index }} chmod +x /etc/init.d/mysql + docker exec {{ container_prefix }}{{ index }} sh -c "echo 'export PATH=/usr/local/mysql/bin:\$PATH' >> /etc/profile" + docker exec {{ container_prefix }}{{ index }} ln -s /usr/local/mysql/bin/mysql /usr/bin/mysql + docker exec {{ container_prefix }}{{ index }} ln -s /usr/local/mysql/bin/mysqldump /usr/bin/mysqldump + docker exec {{ container_prefix }}{{ index }} bash -c 'source ~/.bashrc' + register: mysql_57_root_password + when: mysql_version | replace('_', '') | int == 57 + +- debug: var=mysql_80_root_password + when: mysql_version | replace('_', '') | int >= 80 + +- name: Store Mysql root password for MySQL 8.0+ + set_fact: + mysql_root_password: "{{ mysql_80_root_password.stderr | regex_search('root@localhost: (.+)', '\\1') | first }}" + when: mysql_version | replace('_', '') | int >= 80 + +- name: Store Mysql root password for MySQL 5.7 + set_fact: + mysql_root_password: "{{ mysql_57_root_password.stderr | regex_search('root@localhost: (.+)', '\\1') | first }}" + when: mysql_version | replace('_', '') | int == 57 + +- name: Start MySQL + shell: | + docker exec {{ container_prefix }}{{ index }} systemctl enable mysql + docker exec {{ container_prefix }}{{ index }} systemctl start mysql +- name: Copy config file to docker container + shell: | + docker exec {{ container_prefix }}{{ item }} mkdir -p /etc/mysql + docker cp {{ data_dir }}/node{{ index }}/my.cnf {{ container_prefix }}{{ item }}:/etc/mysql/my.cnf + +- name: Restart MySQL + shell: docker exec {{ container_prefix }}{{ index }} systemctl restart mysql + +- name: Wait 5 seconds for MySQL to start + pause: + seconds: 5 + +- name: Chance root password Percona Server for MySQL 5.7 + shell: "docker exec {{ container_prefix }}{{ index }} mysql --connect-expired-password -uroot -p'{{ mysql_root_password }}' -e \"ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '{{ root_password }}';\"" + when: mysql_version|replace('_', '')|int < 80 + +- name: Chance root password Percona Server for MySQL 8.0+ + shell: "docker exec {{ container_prefix }}{{ index }} mysql --connect-expired-password -uroot -p'{{ mysql_root_password }}' -e \"ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY '{{ root_password }}';\"" + when: mysql_version|replace('_', '')|int >= 80 diff --git a/pmm_qa/percona_server/data/init-async-replication.sql.j2 b/pmm_qa/percona_server/data/init-async-replication.sql.j2 deleted file mode 100644 index a96ef137..00000000 --- a/pmm_qa/percona_server/data/init-async-replication.sql.j2 +++ /dev/null @@ -1,13 +0,0 @@ --- Create replication user and grant necessary privileges -SET SQL_LOG_BIN=0; -CREATE USER '{{ replication_user }}'@'%' IDENTIFIED WITH 'caching_sha2_password' BY '{{ replication_password }}' REQUIRE NONE; -GRANT REPLICATION SLAVE ON *.* TO '{{ replication_user }}'@'%'; -GRANT CONNECTION_ADMIN ON *.* TO '{{ replication_user }}'@'%'; -GRANT BACKUP_ADMIN ON *.* TO '{{ replication_user }}'@'%'; -FLUSH PRIVILEGES; -SET SQL_LOG_BIN=1; - -{% if item == 1 %} --- Primary server: enable binary logging for replication -FLUSH BINARY LOGS; -{% endif %} diff --git a/pmm_qa/percona_server/data/init-group-replication.sql.j2 b/pmm_qa/percona_server/data/init-group-replication.sql.j2 deleted file mode 100644 index 19185831..00000000 --- a/pmm_qa/percona_server/data/init-group-replication.sql.j2 +++ /dev/null @@ -1,15 +0,0 @@ --- Create replication user and grant necessary privileges -SET SQL_LOG_BIN=0; -CREATE USER '{{ replication_user }}'@'%' IDENTIFIED BY '{{ replication_password }}'; -GRANT REPLICATION SLAVE ON *.* TO '{{ replication_user }}'@'%'; -GRANT CONNECTION_ADMIN ON *.* TO '{{ replication_user }}'@'%'; -GRANT BACKUP_ADMIN ON *.* TO '{{ replication_user }}'@'%'; -GRANT GROUP_REPLICATION_STREAM ON *.* TO '{{ replication_user }}'@'%'; --- GRANT SERVICE_CONNECTION_ADMIN ON *.* TO '{{ replication_user }}'@'%'; --- GRANT SYSTEM_VARIABLES_ADMIN ON *.* TO '{{ replication_user }}'@'%'; -FLUSH PRIVILEGES; -SET SQL_LOG_BIN=1; - --- Configure group replication recovery credentials -CHANGE REPLICATION SOURCE TO SOURCE_USER='{{ replication_user }}', SOURCE_PASSWORD='{{ replication_password }}' FOR CHANNEL 'group_replication_recovery'; - diff --git a/pmm_qa/percona_server/data/my.cnf.j2 b/pmm_qa/percona_server/data/my.cnf.j2 deleted file mode 100644 index fd4b27f2..00000000 --- a/pmm_qa/percona_server/data/my.cnf.j2 +++ /dev/null @@ -1,2 +0,0 @@ -[mysqld] -userstat=1 \ No newline at end of file diff --git a/pmm_qa/percona_server/percona-server-setup.yml b/pmm_qa/percona_server/percona-server-setup.yml deleted file mode 100644 index 34bd2658..00000000 --- a/pmm_qa/percona_server/percona-server-setup.yml +++ /dev/null @@ -1,269 +0,0 @@ ---- -# Percona Server 8.4 and higher single instance and also Cluster with Group Replication -- name: Setup Percona Server 8.4 and higher. Cluster with Group Replication in Docker - hosts: localhost - connection: local - gather_facts: yes - vars: - ps_version: "{{ lookup('env', 'PS_VERSION') | default('8.4', true) }}" - cluster_name: "mysql_cluster" - replication_user: "repl_user" - replication_password: "GRgrO9301RuF" - root_password: "GRgrO9301RuF" - mysql_port: 33066 - mysql_listen_port: 3306 - group_seeds_port: 34061 - nodes_count: "{{ (lookup('env', 'NODES_COUNT') | default('3', true)) | int }}" - network_name: "pmm-qa" - data_dir: "{{ lookup('env', 'HOME') }}/mysql_cluster_data" - server_id_start: 1 - pmm_server_ip: "{{ lookup('vars', 'extra_pmm_server_ip', default=lookup('env','PMM_SERVER_IP') | default('127.0.0.1', true) ) }}" - client_version: "{{ lookup('vars', 'extra_client_version', default=lookup('env','CLIENT_VERSION') | default('3-dev-latest', true) ) }}" - admin_password: "{{ lookup('vars', 'extra_admin_password', default=lookup('env','ADMIN_PASSWORD') | default('admin', true) ) }}" - query_source: "{{ lookup('env', 'QUERY_SOURCE') | default('perfschema', true) }}" - metrics_mode: "{{ lookup('env', 'metrics_mode') }}" - setup_type: "{{ lookup('env', 'SETUP_TYPE') }}" - random_service_name_value: "" - my_rocks: "{{ lookup('env', 'MY_ROCKS') | default(false, true) }}" - - - tasks: - - name: Mofidy the node count for group replication - set_fact: - nodes_count: 3 - when: nodes_count | int < 3 and setup_type == "gr" - - - name: Chance to correct nodes count for async replication - set_fact: - nodes_count: 2 - when: nodes_count | int < 2 and setup_type == "replication" - - - name: Create Docker network - community.docker.docker_network: - name: "{{ network_name }}" - state: present - - - name: Remove old data folders - shell: 'rm -fr {{ data_dir }}' - loop: "{{ range(1, nodes_count | int + 1) | list }}" - - - name: Create data directories - file: - path: "{{ data_dir }}/node{{ item }}/data" - state: directory - mode: '0755' - loop: "{{ range(1, nodes_count | int + 1) | list }}" - - - name: Remove old percona server containers - community.docker.docker_container: - name: "ps_pmm_{{ ps_version }}_{{ item }}" - image: "percona/percona-server:{{ ps_version }}" - restart_policy: always - state: absent - loop: "{{ range(1, nodes_count | int + 1) | list }}" - ignore_errors: yes - - - name: Recursively change ownership of a directory - shell: "sudo chown -R 1001:1001 {{ data_dir }}/node{{ item }}/data" - loop: "{{ range(1, nodes_count | int + 1) | list }}" - - - name: Setup Percona Server group replication - include_tasks: ./tasks/percona-server-group-replication-setup.yml - when: setup_type == "gr" - - - name: Setup Percona Server with async replication - include_tasks: ./tasks/percona-server-async-replication-setup.yml - when: setup_type == "replication" - - - name: Setup Percona Server - include_tasks: tasks/percona-server-setup-single.yml - when: setup_type != "gr" and setup_type != "replication" - - - name: Wait 10 seconds for setup to finish - pause: - seconds: 10 - - - name: Create slowlog configuration for mysql nodes - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_{{ item }}" - command: > - mysql -uroot -p{{ root_password }} -e " - SET GLOBAL slow_query_log='ON'; - SET GLOBAL long_query_time=0; - SET GLOBAL log_slow_admin_statements=ON; - SET GLOBAL log_slow_slave_statements=ON; - " - loop: "{{ range(1, nodes_count | int + 1) | list }}" - when: query_source == "slowlog" - - - name: Install and add pmm client. - include_tasks: ../tasks/install_pmm_client.yml - vars: - container_name: "ps_pmm_{{ ps_version }}_{{ item }}" - loop: "{{ range(1, nodes_count | int + 1) | list }}" - - - name: Generate random service name suffix - set_fact: - random_service_name_value: "_{{ 99999 | random + 1 }}" - - - name: Add service to pmm server - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_{{ item }}" - command: pmm-admin add mysql --query-source={{ query_source }} --username=root --password={{ root_password }} --environment=ps-gr-dev --cluster=ps-gr-dev-cluster --replication-set=ps-gr-replication ps_pmm_{{ ps_version }}_{{ item }}{{ random_service_name_value }} --debug 127.0.0.1:3306 - loop: "{{ range(1, nodes_count | int + 1) | list }}" - when: setup_type == "gr" - - - name: Add service to pmm server - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_{{ item }}" - command: pmm-admin add mysql --query-source={{ query_source }} --username=root --password={{ root_password }} --environment=ps-replication-dev --cluster=ps-replication-dev-cluster --replication-set=ps-async-replication ps_pmm_{{ ps_version }}_{{ item }}{{ random_service_name_value }} --debug 127.0.0.1:3306 - loop: "{{ range(1, nodes_count | int + 1) | list }}" - when: setup_type == "replication" - - - name: Add service to pmm server - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_{{ item }}" - command: pmm-admin add mysql --query-source={{ query_source }} --username=root --password={{ root_password }} --cluster=ps-single-dev-cluster --environment=ps-dev ps_pmm_{{ ps_version }}_{{ item }}{{ random_service_name_value }} --debug 127.0.0.1:3306 - loop: "{{ range(1, nodes_count | int + 1) | list }}" - when: setup_type != "gr" and setup_type != "replication" - - - name: Install sysbench inside of all percona server nodes - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_{{ item }}" - user: "root" - command: > - /bin/sh -c " - wget -O epel-release.rpm --progress=dot:giga https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm && - rpm -i epel-release.rpm && - microdnf install -y sysbench - " - loop: "{{ range(1, nodes_count | int + 1) | list }}" - - - name: Prepare sysbench inside of all percona server nodes - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_{{ item }}" - command: > - mysql -uroot -p{{ root_password }} -e " - SET GLOBAL super_read_only = OFF; - SET GLOBAL read_only = OFF; - " - loop: "{{ range(1, nodes_count | int + 1) | list }}" - - - name: Prepare sysbench inside of all percona server nodes - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_{{ item }}" - command: > - mysql -uroot -p{{ root_password }} -e " - CREATE DATABASE sbtest; - CREATE USER 'sbtest'@'localhost' IDENTIFIED BY 'password'; - GRANT ALL PRIVILEGES ON *.* TO 'sbtest'@'localhost'; - CREATE USER 'sbtest'@'127.0.0.1' IDENTIFIED BY 'password'; - GRANT ALL PRIVILEGES ON *.* TO 'sbtest'@'127.0.0.1'; - FLUSH PRIVILEGES; - " - loop: "{{ range(1, nodes_count | int + 1) | list }}" - when: setup_type != "gr" and setup_type != "replication" - - - name: Prepare sysbench inside of all percona server nodes - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_1" - command: > - mysql -uroot -p{{ root_password }} -e " - CREATE DATABASE sbtest; - CREATE USER 'sbtest'@'localhost' IDENTIFIED BY 'password'; - GRANT ALL PRIVILEGES ON *.* TO 'sbtest'@'localhost'; - CREATE USER 'sbtest'@'127.0.0.1' IDENTIFIED BY 'password'; - GRANT ALL PRIVILEGES ON *.* TO 'sbtest'@'127.0.0.1'; - FLUSH PRIVILEGES; - " - when: setup_type == "gr" or setup_type == "replication" - - - name: Prepare data for sysbench inside of all percona server nodes - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_{{ item }}" - command: > - sysbench /usr/share/sysbench/oltp_read_write.lua - --mysql-host=127.0.0.1 - --mysql-port=3306 - --mysql-user=sbtest - --mysql-password=password - --mysql-db=sbtest - --tables=10 - --table-size=100000 - prepare - when: setup_type != "gr" and setup_type != "replication" - loop: "{{ range(1, nodes_count | int + 1) | list }}" - - - name: Prepare data for sysbench inside of first percona server nodes - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_1" - command: > - sysbench /usr/share/sysbench/oltp_read_write.lua - --mysql-host=127.0.0.1 - --mysql-port=3306 - --mysql-user=sbtest - --mysql-password=password - --mysql-db=sbtest - --tables=10 - --table-size=100000 - prepare - when: setup_type == "gr" or setup_type == "replication" - - - name: Run load for sysbench inside of all percona server nodes - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_{{ item }}" - command: > - sysbench /usr/share/sysbench/oltp_read_write.lua - --mysql-host=127.0.0.1 - --mysql-port=3306 - --mysql-user=sbtest - --mysql-password=password - --mysql-db=sbtest - --tables=10 - --table-size=100000 - --threads=16 - --time=60 - run - loop: "{{ range(1, nodes_count | int + 1) | list }}" - - - name: Copy a load file into the container - community.docker.docker_container_copy_into: - container: "ps_pmm_{{ ps_version }}_{{ item }}" - path: ./data/ps_load.sql - container_path: /ps_load.sql - loop: "{{ range(1, nodes_count | int + 1) | list }}" - - - name: Wait 10 seconds for node to be connected - pause: - seconds: 10 - - - name: Run load inside of first percona server node - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_1" - command: > - /bin/sh -c ' - mysql -uroot -p{{ root_password }} -e "CREATE DATABASE school;" - mysql -uroot -p{{ root_password }} school < /ps_load.sql - ' - when: setup_type == "gr" or setup_type == "replication" - - - name: Run load inside of all percona server nodes - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_{{ item }}" - command: > - /bin/sh -c ' - mysql -uroot -p{{ root_password }} -e "CREATE DATABASE school;" - mysql -uroot -p{{ root_password }} school < /ps_load.sql - ' - loop: "{{ range(1, nodes_count | int + 1) | list }}" - when: setup_type != "gr" and setup_type != "replication" - - - name: Enable MySQL MyRocks - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_{{ item }}" - command: > - /bin/sh -c ' - ps-admin --enable-rocksdb -u root -p{{ root_password }} - ' - loop: "{{ range(1, nodes_count | int + 1) | list }}" - when: my_rocks | bool diff --git a/pmm_qa/percona_server/tasks/percona-server-async-replication-setup.yml b/pmm_qa/percona_server/tasks/percona-server-async-replication-setup.yml deleted file mode 100644 index 67cebb47..00000000 --- a/pmm_qa/percona_server/tasks/percona-server-async-replication-setup.yml +++ /dev/null @@ -1,129 +0,0 @@ -- name: Generate my.cnf for each node - template: - src: ./data/my-async-replication.cnf.j2 - dest: "{{ data_dir }}/node{{ item }}/my.cnf" - loop: "{{ range(1, nodes_count | int + 1) | list }}" - -- name: Create initialization script for each node - template: - src: ./data/init-async-replication.sql.j2 - dest: "{{ data_dir }}/node{{ item }}/init.sql" - loop: "{{ range(1, nodes_count | int + 1) | list }}" - -- name: Start Percona Server containers with async replication - community.docker.docker_container: - name: "ps_pmm_{{ ps_version }}_{{ item }}" - image: "percona/percona-server:{{ ps_version }}" - restart_policy: always - state: started - networks: - - name: "{{ network_name }}" - env: - MYSQL_ROOT_PASSWORD: "{{ root_password }}" - ports: - - "{{ mysql_port + item - 1 }}:{{ mysql_listen_port }}" - volumes: - - "{{ data_dir }}/node{{ item }}/data:/var/lib/mysql" - - "{{ data_dir }}/node{{ item }}/my.cnf:/etc/mysql/my.cnf" - - "{{ data_dir }}/node{{ item }}/init.sql:/docker-entrypoint-initdb.d/init.sql" - loop: "{{ range(1, nodes_count | int + 1) | list }}" - -- name: Wait for MySQL to be available - wait_for: - host: localhost - port: "{{ mysql_port + item - 1 }}" - delay: 10 - timeout: 300 - loop: "{{ range(1, nodes_count | int + 1) | list }}" - -- name: Wait 5 seconds for percona server start to complete - pause: - seconds: 5 - -- name: Reset configuration for all nodes - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_{{ item }}" - command: > - mysql -uroot -p{{ root_password }} -e " - RESET BINARY LOGS AND GTIDS; - RESET REPLICA ALL; - " - loop: "{{ range(1, nodes_count | int + 1) | list }}" - ignore_errors: yes - -- name: Get primary ps_pmm_{{ ps_version }}_1 binary log status - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_1" - command: > - mysql -uroot -p{{ root_password }} -e " - SHOW BINARY LOG STATUS\G - " - register: primary_status - changed_when: false - - -- name: Display binary log status for primary - debug: - msg: "{{ primary_status.stdout | split('\n') }}" - -- name: Configure replica servers (container2-containerN) - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_{{ item }}" - command: > - mysql -uroot -p{{ root_password }} -e " - CHANGE REPLICATION SOURCE TO - SOURCE_HOST='ps_pmm_{{ ps_version }}_1', - SOURCE_PORT={{ mysql_listen_port }}, - SOURCE_USER='{{ replication_user }}', - SOURCE_PASSWORD='{{ replication_password }}', - SOURCE_AUTO_POSITION=1, - SOURCE_PUBLIC_KEY_PATH='', - GET_SOURCE_PUBLIC_KEY=1; - START REPLICA; - " - loop: "{{ range(2, nodes_count | int + 1) | list }}" - -- name: Create and seed a test database on primary - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_1" - command: > - mysql -uroot -p{{ root_password}} -e " - CREATE DATABASE testdb; - USE testdb; - CREATE TABLE testdb (id INT PRIMARY KEY, data VARCHAR(100)); - INSERT INTO testdb VALUES (1, 'Initial data from node mysql1');" - -- name: Check replication status on replica nodes - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_{{ item }}" - command: mysql -uroot -p{{ root_password }} -e "SHOW REPLICA STATUS\G" - register: replication_status - loop: "{{ range(2, nodes_count | int + 1) | list }}" - changed_when: false - -- name: Display replication status for each replica - debug: - msg: "{{ replication_status.results[item - 2].stdout_lines }}" - loop: "{{ range(2, nodes_count | int + 1) | list }}" - -- name: Set verification instructions - set_fact: - verification_msg: | - MySQL Cluster setup complete with asynchronous replication! - - To verify replication is working: - 1. Connect to the primary (ps_pmm_{{ ps_version }}_1): - docker exec -it ps_pmm_{{ ps_version }}_1 mysql -uroot -p{{ root_password }} - - 2. Insert data in the test database: - USE testdb; - INSERT INTO testdb VALUES (100, 'Test replication'); - - 3. Connect to replicas and verify data is replicated: - docker exec -it ps_pmm_{{ ps_version }}_2 mysql -uroot -p{{ root_password }} - USE testdb; - SELECT * FROM testdb; - -- name: Display verification instructions - debug: - msg: "{{ verification_msg | split('\n') }}" diff --git a/pmm_qa/percona_server/tasks/percona-server-group-replication-setup.yml b/pmm_qa/percona_server/tasks/percona-server-group-replication-setup.yml deleted file mode 100644 index cd179239..00000000 --- a/pmm_qa/percona_server/tasks/percona-server-group-replication-setup.yml +++ /dev/null @@ -1,127 +0,0 @@ -- name: Generate my.cnf for each node - template: - src: ./data/my-group-replication.cnf.j2 - dest: "{{ data_dir }}/node{{ item }}/my.cnf" - loop: "{{ range(1, nodes_count | int + 1) | list }}" - -- name: Create initialization script for each node - template: - src: ./data/init-group-replication.sql.j2 - dest: "{{ data_dir }}/node{{ item }}/init.sql" - loop: "{{ range(1, nodes_count | int + 1) | list }}" - -- name: Start Percona Server containers with group replication - community.docker.docker_container: - name: "ps_pmm_{{ ps_version }}_{{ item }}" - image: "percona/percona-server:{{ ps_version }}" - restart_policy: always - state: started - networks: - - name: "{{ network_name }}" - env: - MYSQL_ROOT_PASSWORD: "{{ root_password }}" - ports: - - "{{ mysql_port + item - 1 }}:{{ mysql_listen_port }}" - - "{{ group_seeds_port + item - 1 }}:{{ group_seeds_port }}" - volumes: - - "{{ data_dir }}/node{{ item }}/data:/var/lib/mysql" - - "{{ data_dir }}/node{{ item }}/my.cnf:/etc/mysql/my.cnf" - - "{{ data_dir }}/node{{ item }}/init.sql:/docker-entrypoint-initdb.d/init.sql" - loop: "{{ range(1, nodes_count | int + 1) | list }}" - -- name: Wait for MySQL to be available - wait_for: - host: localhost - port: "{{ mysql_port + item - 1 }}" - delay: 10 - timeout: 300 - loop: "{{ range(1, nodes_count | int + 1) | list }}" - -- name: Reset configuration for all nodes - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_{{ item }}" - command: > - mysql -uroot -p{{ root_password }} -e " - RESET BINARY LOGS AND GTIDS; - RESET REPLICA ALL; - SET GLOBAL gtid_purged=''; - " - loop: "{{ range(1, nodes_count | int + 1) | list }}" - -- name: Bootstrap first node in the cluster - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_1" - command: > - mysql -uroot -p{{ root_password }} -e " - SET GLOBAL group_replication_bootstrap_group=ON; - START GROUP_REPLICATION; - SET GLOBAL group_replication_bootstrap_group=OFF;" - retries: 5 - delay: 10 - -- name: Wait 5 seconds for bootstrap to complete - pause: - seconds: 5 - -- name: Start group replication on other nodes - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_{{ item }}" - command: mysql -uroot -p{{ root_password }} -e "START GROUP_REPLICATION;" - loop: "{{ range(2, nodes_count | int + 1) | list }}" - ignore_errors: yes - -- name: Wait 10 seconds for the other nodes to join - pause: - seconds: 10 - -- name: Create and seed a test database on primary - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_1" - command: > - mysql -uroot -p{{ root_password}} -e " - CREATE DATABASE testdb; - USE testdb; - CREATE TABLE testdb (id INT PRIMARY KEY, data VARCHAR(100)); - INSERT INTO testdb VALUES (1, 'Initial data from node mysql1');" - -- name: Check replication status on first node - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_1" - command: mysql -uroot -p{{ root_password }} -e "SELECT * FROM performance_schema.replication_group_members;" - register: replication_status - -- name: Display replication status - debug: - var: replication_status.stdout - -- name: Check replication group members count - community.docker.docker_container_exec: - container: "ps_pmm_{{ ps_version }}_1" - command: mysql -uroot -p{{ root_password }} -e "SELECT COUNT(*) AS count FROM performance_schema.replication_group_members;" - register: member_count - -- name: Display member count - debug: - var: member_count.stdout - -- name: Set verification instructions - set_fact: - verification_msg: | - MySQL Cluster setup complete! - - To verify replication is working: - 1. Connect to the first node: - docker exec -it ps_pmm_{{ ps_version }}_1 mysql -uroot -p{{ root_password }} - - 2. Insert data in the test database: - USE testdb; - INSERT INTO testdb VALUES (100, 'Test replication'); - - 3. Connect to other nodes and verify data is replicated: - docker exec -it ps_pmm_{{ ps_version }}_2 mysql -uroot -p{{ root_password }} - USE testdb; - SELECT * FROM testdb; - -- name: Display verification instructions - debug: - msg: "{{ verification_msg | split('\n') }}" diff --git a/pmm_qa/percona_server/tasks/percona-server-setup-single.yml b/pmm_qa/percona_server/tasks/percona-server-setup-single.yml deleted file mode 100644 index 9fbad84c..00000000 --- a/pmm_qa/percona_server/tasks/percona-server-setup-single.yml +++ /dev/null @@ -1,31 +0,0 @@ -- name: Generate my.cnf for each node - template: - src: ./data/my.cnf.j2 - dest: "{{ data_dir }}/node{{ item }}/my.cnf" - loop: "{{ range(1, nodes_count | int + 1) | list }}" - -- name: Start Percona Server containers - community.docker.docker_container: - name: "ps_pmm_{{ ps_version }}_{{ item }}" - image: "percona/percona-server:{{ ps_version }}" - restart_policy: always - state: started - networks: - - name: "{{ network_name }}" - env: - MYSQL_ROOT_PASSWORD: "{{ root_password }}" - ports: - - "{{ mysql_port + item - 1 }}:{{ mysql_listen_port }}" - - "{{ group_seeds_port + item - 1 }}:{{ group_seeds_port }}" - volumes: - - "{{ data_dir }}/node{{ item }}/my.cnf:/etc/mysql/my.cnf" - - "{{ data_dir }}/node{{ item }}/data:/var/lib/mysql" - loop: "{{ range(1, nodes_count | int + 1) | list }}" - -- name: Wait for MySQL to be available - wait_for: - host: localhost - port: "{{ mysql_port + item - 1 }}" - delay: 10 - timeout: 300 - loop: "{{ range(1, nodes_count | int + 1) | list }}" diff --git a/pmm_qa/percona_server_for_mysql/data/my-async-replication-57.cnf.j2 b/pmm_qa/percona_server_for_mysql/data/my-async-replication-57.cnf.j2 new file mode 100644 index 00000000..b2f96dc5 --- /dev/null +++ b/pmm_qa/percona_server_for_mysql/data/my-async-replication-57.cnf.j2 @@ -0,0 +1,38 @@ +[mysqld] +# General server configuration +server_id={{ item }} +bind-address=0.0.0.0 +port={{ mysql_listen_port }} +userstat=1 + +# Replication settings +gtid_mode=ON +enforce_gtid_consistency=ON +log_bin=binlog +log_slave_updates=ON +sync_binlog=1 +binlog_checksum=NONE +# Only disable engines supported in 5.7 and safe for GTID +disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE" +# MacOS-specific, where table names are case-sensitive +lower_case_table_names=2 + +# Optional: report_host is valid in 5.7 +report_host={{ container_prefix }}{{ item }} + +# Replica configuration - applies to all nodes except primary (they'll be able to become replicas) +{% if item != 1 %} +# Replica specific settings (use slave_parallel_* in 5.7) +slave_parallel_workers=4 +slave_parallel_type=LOGICAL_CLOCK +slave_preserve_commit_order=1 +{% endif %} + +# Crash-safe replication settings +relay-log={{ container_prefix }}{{ item }}-relay-bin +relay_log_recovery=ON +relay_log_purge=ON + +# Performance and connection settings +max_connections=1000 +innodb_buffer_pool_size=256M diff --git a/pmm_qa/percona_server_for_mysql/data/my-async-replication.cnf.j2 b/pmm_qa/percona_server_for_mysql/data/my-async-replication.cnf.j2 new file mode 100644 index 00000000..efce584c --- /dev/null +++ b/pmm_qa/percona_server_for_mysql/data/my-async-replication.cnf.j2 @@ -0,0 +1,42 @@ +[mysqld] +# General server configuration +server_id={{ item }} +bind-address=0.0.0.0 +port={{ mysql_listen_port }} + +# Authentication settings for caching_sha2_password +caching_sha2_password_auto_generate_rsa_keys=ON +# The following two parameters tell MySQL where to store the RSA key pair +caching_sha2_password_private_key_path=private_key.pem +caching_sha2_password_public_key_path=public_key.pem + +# Replication settings +gtid_mode=ON +enforce_gtid_consistency=ON +log_bin=binlog +log_replica_updates=ON +sync_binlog=1 +binlog_checksum=NONE +disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY" +# MacOS-specific, where table names are case-sensitive +lower_case_table_names=2 + +# MySQL 8.4 compatibility settings +report_host={{ container_prefix }}{{ item }} + +# Replica configuration - applies to all nodes except primary (they'll be able to become replicas) +{% if item != 1 %} +# Replica specific settings +replica_parallel_workers=4 +replica_parallel_type=LOGICAL_CLOCK +replica_preserve_commit_order=1 +{% endif %} + +# Crash-safe replication settings +relay-log={{ container_prefix }}{{ item }}-relay-bin +relay_log_recovery=ON +relay_log_purge=ON + +# Performance and connection settings +max_connections=1000 +innodb_buffer_pool_size=256M diff --git a/pmm_qa/percona_server_for_mysql/data/my-group-replication-57.cnf.j2 b/pmm_qa/percona_server_for_mysql/data/my-group-replication-57.cnf.j2 new file mode 100644 index 00000000..74383253 --- /dev/null +++ b/pmm_qa/percona_server_for_mysql/data/my-group-replication-57.cnf.j2 @@ -0,0 +1,49 @@ +[mysqld] +# General server configuration +server_id={{ server_id_start + item - 1 }} +binlog_format=ROW +bind-address=0.0.0.0 +port={{ mysql_listen_port }} +userstat=1 + +# 5.7 General replication settings +gtid_mode=ON +enforce_gtid_consistency=ON +master_info_repository=TABLE +relay_log_info_repository=TABLE +transaction_write_set_extraction=XXHASH64 +binlog_checksum=NONE +log_bin=binlog +log_slave_updates=ON +# NO: disabled_storage_engines in 5.7 +lower_case_table_names=2 + +# Report host for replication/monitoring +report_host={{ container_prefix }}{{ item }} + +# Group Replication Settings +# (Available in MySQL 5.7.17+ and must be installed as plugin) +plugin_load_add='group_replication.so' +loose-group_replication_group_name='aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' +loose-group_replication_local_address='{{ container_prefix }}{{ item }}:{{ group_seeds_port }}' +loose-group_replication_group_seeds={% for i in range(1, nodes_count | int + 1) %}{{ container_prefix }}{{ i }}:{{ group_seeds_port }}{% if not loop.last %},{% endif %}{% endfor %} +loose-group_replication_communication_stack=XCOM + +# Group replication behavior +loose-group_replication_start_on_boot=OFF +loose-group_replication_bootstrap_group=OFF +loose-group_replication_single_primary_mode=ON +loose-group_replication_enforce_update_everywhere_checks=OFF + +# Recovery settings +loose-group_replication_recovery_retry_count=10 +loose-group_replication_recovery_reconnect_interval=60 + +# Crash-safe replication settings +relay-log={{ container_prefix }}{{ item }}-relay-bin +relay_log_recovery=ON +relay_log_purge=ON + +# Performance and connection settings +max_connections=1000 +innodb_buffer_pool_size=256M diff --git a/pmm_qa/percona_server/data/my-group-replication.cnf.j2 b/pmm_qa/percona_server_for_mysql/data/my-group-replication.cnf.j2 similarity index 85% rename from pmm_qa/percona_server/data/my-group-replication.cnf.j2 rename to pmm_qa/percona_server_for_mysql/data/my-group-replication.cnf.j2 index 8fcdbbf6..df2434f9 100644 --- a/pmm_qa/percona_server/data/my-group-replication.cnf.j2 +++ b/pmm_qa/percona_server_for_mysql/data/my-group-replication.cnf.j2 @@ -15,13 +15,13 @@ disabled_storage_engines="MyISAM,BLACKHOLE,FEDERATED,ARCHIVE,MEMORY" lower_case_table_names=2 # MacOS-specific, but also good generally # MySQL 8.4 compatibility settings -report_host=ps_pmm_{{ps_version}}_{{ item }} +report_host={{ container_prefix }}{{ item }} # Group Replication Settings plugin_load_add='group_replication.so' loose-group_replication_group_name='aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' -loose-group_replication_local_address='ps_pmm_{{ps_version}}_{{ item }}:{{ group_seeds_port }}' -loose-group_replication_group_seeds='{% for i in range(1, nodes_count | int + 1) %}ps_pmm_{{ps_version}}_{{ i }}:{{ group_seeds_port }}{% if not loop.last %},{% endif %}{% endfor %}' +loose-group_replication_local_address='{{ container_prefix }}{{ item }}:{{ group_seeds_port }}' +loose-group_replication_group_seeds='{% for i in range(1, nodes_count | int + 1) %}{{ container_prefix }}{{ i }}:{{ group_seeds_port }}{% if not loop.last %},{% endif %}{% endfor %}' loose-group_replication_communication_stack=XCOM # Group replication behavior @@ -36,7 +36,7 @@ loose-group_replication_recovery_retry_count=10 loose-group_replication_recovery_reconnect_interval=60 # Crash-safe replication settings -relay-log=ps_pmm_{{ps_version}}_{{ item }}-relay-bin +relay-log={{ container_prefix }}{{ item }}-relay-bin relay_log_recovery=ON relay_log_purge=ON diff --git a/pmm_qa/percona_server_for_mysql/data/my.cnf.j2 b/pmm_qa/percona_server_for_mysql/data/my.cnf.j2 new file mode 100644 index 00000000..d1f8bde9 --- /dev/null +++ b/pmm_qa/percona_server_for_mysql/data/my.cnf.j2 @@ -0,0 +1,3 @@ +[mysqld] +plugin-load-add=auth_native_password.so +userstat=1 \ No newline at end of file diff --git a/pmm_qa/percona_server_for_mysql/percona-server-setup.yml b/pmm_qa/percona_server_for_mysql/percona-server-setup.yml new file mode 100644 index 00000000..cec920c8 --- /dev/null +++ b/pmm_qa/percona_server_for_mysql/percona-server-setup.yml @@ -0,0 +1,173 @@ +--- + +- name: Setup Percona Server for MySQL single, cluster with group Replication in Docker + hosts: localhost + connection: local + gather_facts: yes + vars: + ps_version: "{{ (lookup('env', 'PS_VERSION') | default('8.0', true)) | replace('.', '_') }}" + replication_user: "repl_user" + replication_password: "GRgrO9301RuF" + root_password: "GRgrO9301RuF" + mysql_port: 33066 + mysql_listen_port: 3306 + group_seeds_port: 34061 + nodes_count: "{{ (lookup('env', 'NODES_COUNT') | default('1', true)) | int }}" + network_name: "pmm-qa" + data_dir: "{{ lookup('env', 'HOME') }}/mysql_cluster_data" + server_id_start: 1 + pmm_server_ip: "{{ lookup('vars', 'extra_pmm_server_ip', default=lookup('env','PMM_SERVER_IP') | default('127.0.0.1', true) ) }}" + client_version: "{{ lookup('vars', 'extra_client_version', default=lookup('env','CLIENT_VERSION') | default('3-dev-latest', true) ) }}" + admin_password: "{{ lookup('vars', 'extra_admin_password', default=lookup('env','ADMIN_PASSWORD') | default('admin', true) ) }}" + query_source: "{{ lookup('env', 'QUERY_SOURCE') | default('perfschema', true) }}" + metrics_mode: "{{ lookup('env', 'metrics_mode') }}" + setup_type: "{{ lookup('env', 'SETUP_TYPE') }}" + random_service_name_value: "" + my_rocks: "{{ lookup('env', 'MY_ROCKS') | default(false, true) }}" + container_prefix: "ps_pmm{{ (setup_type|default('')) and '_' ~ setup_type }}_{{ ps_version }}_" + + tasks: + - name: Modify the node count for group replication + set_fact: + nodes_count: 3 + when: nodes_count | int < 3 and setup_type == "gr" + + - name: Chance to correct nodes count for async replication + set_fact: + nodes_count: 2 + when: nodes_count | int < 2 and setup_type == "replication" + + - name: Create Docker network + shell: docker network create {{ network_name }} + ignore_errors: true + + - name: Remove old data folders + shell: 'rm -fr {{ data_dir }}' + loop: "{{ range(1, nodes_count | int + 1) | list }}" + + - name: Create data directories + file: + path: "{{ data_dir }}/node{{ item }}/data" + state: directory + mode: '0755' + loop: "{{ range(1, nodes_count | int + 1) | list }}" + + - name: Recursively change ownership of a directory + shell: "sudo chown -R 1001:1001 {{ data_dir }}/node{{ item }}/data" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + + - name: Setup Percona Server group replication + include_tasks: ./tasks/percona-server-group-replication-setup.yml + when: setup_type == "gr" + + - name: Setup Percona Server with async replication + include_tasks: ./tasks/percona-server-async-replication-setup.yml + when: setup_type == "replication" + + - name: Setup Percona Server + include_tasks: tasks/percona-server-setup-single.yml + when: setup_type != "gr" and setup_type != "replication" + + - name: Wait 10 seconds for setup to finish + pause: + seconds: 10 + + - name: Create slowlog configuration for mysql nodes + shell: | + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "SET GLOBAL slow_query_log='ON'; SET GLOBAL long_query_time=0;" + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "SET GLOBAL log_slow_admin_statements=ON; SET GLOBAL log_slow_slave_statements=ON;" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: query_source == "slowlog" + + - name: Install and add pmm client. + include_tasks: ../tasks/install_pmm_client.yml + vars: + container_name: "{{ container_prefix }}{{ item }}" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + + - name: Generate random service name suffix + set_fact: + random_service_name_value: "_{{ 99999 | random + 1 }}" + + - name: Add service to pmm server + shell: docker exec {{ container_prefix }}{{ item }} pmm-admin add mysql --query-source={{ query_source }} --username=root --password={{ root_password }} --environment=ps-gr-dev --cluster=ps-gr-dev-cluster --replication-set=ps-gr-replication {{ container_prefix }}{{ item }}{{ random_service_name_value }} --debug 127.0.0.1:3306 + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: setup_type == "gr" + + - name: Add service to pmm server + shell: docker exec {{ container_prefix }}{{ item }} pmm-admin add mysql --query-source={{ query_source }} --username=root --password={{ root_password }} --environment=ps-replication-dev --cluster=ps-replication-dev-cluster --replication-set=ps-async-replication {{ container_prefix }}{{ item }}{{ random_service_name_value }} --debug 127.0.0.1:3306 + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: setup_type == "replication" + + - name: Add service to pmm server + shell: docker exec {{ container_prefix }}{{ item }} pmm-admin add mysql --query-source={{ query_source }} --username=root --password={{ root_password }} --cluster=ps-single-dev-cluster --environment=ps-dev {{ container_prefix }}{{ item }}{{ random_service_name_value }} --debug 127.0.0.1:3306 + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: setup_type != "gr" and setup_type != "replication" + + - name: Install sysbench inside of all percona server nodes + shell: docker exec {{ container_prefix }}{{ item }} apt-get install -y sysbench + loop: "{{ range(1, nodes_count | int + 1) | list }}" + + - name: Prepare sysbench inside of all percona server nodes + shell: docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "SET GLOBAL super_read_only = OFF; SET GLOBAL read_only = OFF;" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + + - name: Prepare sysbench inside of all percona server nodes + shell: | + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "CREATE DATABASE sbtest; CREATE USER 'sbtest'@'localhost' IDENTIFIED BY 'password';" + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "GRANT ALL PRIVILEGES ON *.* TO 'sbtest'@'localhost'; CREATE USER 'sbtest'@'127.0.0.1' IDENTIFIED BY 'password';" + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "GRANT ALL PRIVILEGES ON *.* TO 'sbtest'@'127.0.0.1'; FLUSH PRIVILEGES;" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: setup_type != "gr" and setup_type != "replication" #and ps_version | replace('_', '') | int >= 84 + + - name: Prepare sysbench inside of primary percona server node + shell: | + docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e "CREATE DATABASE sbtest; CREATE USER 'sbtest'@'localhost' IDENTIFIED BY 'password';" + docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e "GRANT ALL PRIVILEGES ON *.* TO 'sbtest'@'localhost'; CREATE USER 'sbtest'@'127.0.0.1' IDENTIFIED BY 'password';" + docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e "GRANT ALL PRIVILEGES ON *.* TO 'sbtest'@'127.0.0.1'; FLUSH PRIVILEGES;" + when: setup_type == "gr" or setup_type == "replication" # and ps_version | replace('_', '') | int >= 84 + + - name: Prepare data for sysbench inside of all percona server nodes + shell: | + docker exec {{ container_prefix }}{{ item }} sysbench /usr/share/sysbench/oltp_read_write.lua --mysql-host=127.0.0.1 --mysql-port=3306 --mysql-user=sbtest --mysql-password=password --mysql-db=sbtest --tables=10 --table-size=100000 prepare + when: setup_type != "gr" and setup_type != "replication" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + + - name: Prepare data for sysbench inside of first percona server nodes + shell: docker exec {{ container_prefix }}1 sysbench /usr/share/sysbench/oltp_read_write.lua --mysql-host=127.0.0.1 --mysql-port=3306 --mysql-user=sbtest --mysql-password=password --mysql-db=sbtest --tables=10 --table-size=100000 prepare + when: setup_type == "gr" or setup_type == "replication" + + - name: Run load for sysbench inside of all percona server nodes + shell: docker exec {{ container_prefix }}{{ item }} sysbench /usr/share/sysbench/oltp_read_write.lua --mysql-host=127.0.0.1 --mysql-port=3306 --mysql-user=sbtest --mysql-password=password --mysql-db=sbtest --tables=10 --table-size=100000 --threads=16 --time=60 run + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: setup_type != "gr" and setup_type != "replication" + + - name: Run load for sysbench inside of primary percona server node + shell: docker exec {{ container_prefix }}1 sysbench /usr/share/sysbench/oltp_read_write.lua --mysql-host=127.0.0.1 --mysql-port=3306 --mysql-user=sbtest --mysql-password=password --mysql-db=sbtest --tables=10 --table-size=100000 --threads=16 --time=60 run + when: setup_type == "gr" and setup_type == "replication" + + - name: Copy a load file into the container + shell: docker cp ../data/mysql_load.sql {{ container_prefix }}{{ item }}:/ps_load.sql + loop: "{{ range(1, nodes_count | int + 1) | list }}" + + - name: Wait 10 seconds for node to be connected + pause: + seconds: 10 + + - name: Run load inside of first percona server node + shell: | + docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e "CREATE DATABASE school;" + docker exec {{ container_prefix }}1 sh -c "mysql -uroot -p{{ root_password }} school < /ps_load.sql" + when: setup_type in ['gr', 'replication'] and (ps_version | replace('_','') | int) >= 80 + + - name: Run load inside of all percona server nodes + shell: | + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "CREATE DATABASE school;" + docker exec {{ container_prefix }}{{ item }} sh -c "mysql -uroot -p{{ root_password }} school < /ps_load.sql" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: setup_type not in ['gr', 'replication'] and (ps_version | replace('_','') | int) >= 80 + + - name: Enable MySQL MyRocks + shell: docker exec {{ container_prefix }}{{ item }} ps-admin --enable-rocksdb -u root -p{{ root_password }} + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: my_rocks | bool \ No newline at end of file diff --git a/pmm_qa/percona_server_for_mysql/tasks/percona-server-async-replication-setup.yml b/pmm_qa/percona_server_for_mysql/tasks/percona-server-async-replication-setup.yml new file mode 100644 index 00000000..e07d3215 --- /dev/null +++ b/pmm_qa/percona_server_for_mysql/tasks/percona-server-async-replication-setup.yml @@ -0,0 +1,81 @@ +- name: Generate my.cnf for each node + template: + src: ./data/my-async-replication{{ '-57' if ps_version | replace('_', '') == '57' else '' }}.cnf.j2 + dest: "{{ data_dir }}/node{{ item }}/my.cnf" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + +- name: Prepare docker container and install Percona Server for MySQL + include_tasks: ./tasks/prepare_install_ps.yml + +- name: Reset configuration for all nodes + shell: docker exec {{ container_prefix}}{{ item }} mysql -uroot -p{{ root_password }} -e "RESET BINARY LOGS AND GTIDS; RESET REPLICA ALL;" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + ignore_errors: yes + +- name: Configure replica servers (container2-containerN) for MySQL 8.0 and above + shell: > + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e " + CHANGE REPLICATION SOURCE TO + SOURCE_HOST='{{ container_prefix }}1', + SOURCE_PORT={{ mysql_listen_port }}, + SOURCE_USER='{{ replication_user }}', + SOURCE_PASSWORD='{{ replication_password }}', + SOURCE_AUTO_POSITION=1, + SOURCE_PUBLIC_KEY_PATH='', + GET_SOURCE_PUBLIC_KEY=1; + START REPLICA; + " + loop: "{{ range(2, nodes_count | int + 1) | list }}" + when: ps_version | replace('_', '') | int >= 80 + +- name: Configure replica servers (container2-containerN) for Mysql 5.7 + shell: > + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e " + CHANGE MASTER TO + MASTER_HOST='{{ container_prefix }}1', + MASTER_PORT={{ mysql_listen_port }}, + MASTER_USER='{{ replication_user }}', + MASTER_PASSWORD='{{ replication_password }}', + MASTER_AUTO_POSITION=1; + START SLAVE; + " + loop: "{{ range(2, nodes_count | int + 1) | list }}" + when: ps_version | replace('_', '') | int < 80 + +- name: Create and seed a test database on primary + shell: > + docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e " + CREATE DATABASE testdb; + USE testdb; + CREATE TABLE testdb (id INT PRIMARY KEY, data VARCHAR(100)); + INSERT INTO testdb VALUES (1, 'Initial data from node mysql1'); + " +- name: Check replication status on replica nodes + shell: docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "SHOW REPLICA STATUS\G" + loop: "{{ range(2, nodes_count | int + 1) | list }}" + changed_when: false + when: ps_version | replace('_', '') | int >= 80 + +- name: Check replication status on replica nodes + shell: docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "SHOW SLAVE STATUS\G" + loop: "{{ range(2, nodes_count | int + 1) | list }}" + changed_when: false + when: ps_version | replace('_', '') | int < 80 + +- name: Set verification instructions + set_fact: + verification_msg: | + MySQL Cluster setup complete with asynchronous replication! + To verify replication is working: + 1. Connect to the primary ({{ container_prefix }}1): + docker exec -it {{ container_prefix }}1 mysql -uroot -p{{ root_password }} + 2. Insert data in the test database: + USE testdb; + INSERT INTO testdb VALUES (100, 'Test replication'); + 3. Connect to replicas and verify data is replicated: + docker exec -it {{ container_prefix }}2 mysql -uroot -p{{ root_password }} + USE testdb; + SELECT * FROM testdb; +- name: Display verification instructions + debug: + msg: "{{ verification_msg | split('\n') }}" \ No newline at end of file diff --git a/pmm_qa/percona_server_for_mysql/tasks/percona-server-group-replication-setup.yml b/pmm_qa/percona_server_for_mysql/tasks/percona-server-group-replication-setup.yml new file mode 100644 index 00000000..f229f97e --- /dev/null +++ b/pmm_qa/percona_server_for_mysql/tasks/percona-server-group-replication-setup.yml @@ -0,0 +1,120 @@ +- name: Generate my.cnf for each node + template: + src: ./data/my-group-replication{{ '-57' if ps_version | replace('_', '') == '57' else '' }}.cnf.j2 + dest: "{{ data_dir }}/node{{ item }}/my.cnf" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + +- name: Prepare docker container and install Percona Server for MySQL + include_tasks: ./tasks/prepare_install_ps.yml + +- name: Reset configuration for all nodes for MySQL 8.4 + shell: > + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e"RESET BINARY LOGS AND GTIDS; RESET REPLICA ALL; SET GLOBAL gtid_purged='';" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: ps_version | replace('_', '') | int >= 84 + +- name: Reset configuration for all nodes for MySQL 8.0 and bellow + shell: > + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "RESET MASTER; RESET SLAVE ALL;" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: ps_version | replace('_', '') | int < 84 + +- name: Init configuration for group replication (single exec per node, no binlog) for MySQL 8.0+ + shell: | + docker exec -i {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} <<'EOSQL' + SET SQL_LOG_BIN=0; + CREATE USER IF NOT EXISTS '{{ replication_user }}'@'%' IDENTIFIED BY '{{ replication_password }}'; + GRANT REPLICATION SLAVE ON *.* TO '{{ replication_user }}'@'%'; + GRANT CONNECTION_ADMIN ON *.* TO '{{ replication_user }}'@'%'; + GRANT BACKUP_ADMIN ON *.* TO '{{ replication_user }}'@'%'; + GRANT GROUP_REPLICATION_STREAM ON *.* TO '{{ replication_user }}'@'%'; + GRANT SERVICE_CONNECTION_ADMIN ON *.* TO '{{ replication_user }}'@'%'; + GRANT SYSTEM_VARIABLES_ADMIN ON *.* TO '{{ replication_user }}'@'%'; + FLUSH PRIVILEGES; + -- Configure recovery channel credentials (explicit host/port to primary node) + CHANGE REPLICATION SOURCE TO + SOURCE_USER='{{ replication_user }}', + SOURCE_PASSWORD='{{ replication_password }}' + FOR CHANNEL 'group_replication_recovery'; + SET SQL_LOG_BIN=1; + EOSQL + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: ps_version | replace('_', '') | int >= 80 + +- name: Init configuration for group replication (single exec per node, no binlog) for MySQL 5.7 + shell: | + docker exec -i {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} <<'EOSQL' + SET SQL_LOG_BIN=0; + CREATE USER IF NOT EXISTS 'repl_user'@'%' IDENTIFIED BY 'GRgrO9301RuF'; + GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%'; + FLUSH PRIVILEGES; + -- Configure recovery channel credentials (explicit host/port to primary node) + CHANGE MASTER TO + MASTER_USER='{{ replication_user }}', + MASTER_PASSWORD='{{ replication_password }}' + FOR CHANNEL 'group_replication_recovery'; + SET SQL_LOG_BIN=1; + EOSQL + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: ps_version | replace('_', '') | int < 80 + +- name: Bootstrap first node (primary) for MySQL 8.4/8.0 + shell: | + docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e "SET GLOBAL group_replication_bootstrap_group=ON;" + docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e "START GROUP_REPLICATION;" + docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e "SET GLOBAL group_replication_bootstrap_group=OFF;" +- name: Wait for bootstrap to complete + pause: + seconds: 10 + +- name: Start group replication on other nodes + shell: | + docker exec {{ container_prefix }}{{ item }} mysql -uroot -p{{ root_password }} -e "START GROUP_REPLICATION;" + loop: "{{ range(2, nodes_count | int + 1) | list }}" + +- name: Wait 10 seconds for the other nodes to join + pause: + seconds: 10 + +- name: Create and seed a test database on primary + shell: > + docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e " + CREATE DATABASE testdb; + USE testdb; + CREATE TABLE testdb (id INT PRIMARY KEY, data VARCHAR(100)); + INSERT INTO testdb VALUES (1, 'Initial data from node mysql1'); + " +- name: Check replication status on first node + shell: docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e "SELECT * FROM performance_schema.replication_group_members;" + register: replication_status + +- name: Display replication status + debug: + var: replication_status.stdout + +- name: Check replication group members count + shell: docker exec {{ container_prefix }}1 mysql -uroot -p{{ root_password }} -e "SELECT COUNT(*) AS count FROM performance_schema.replication_group_members;" + register: member_count + +- name: Display member count + debug: + var: member_count.stdout + +- name: Set verification instructions + set_fact: + verification_msg: | + MySQL Cluster setup complete! + To verify replication is working: + 1. Connect to the first node: + docker exec -it {{ container_prefix }}1 mysql -uroot -p{{ root_password }} + 2. Insert data in the test database: + USE testdb; + INSERT INTO testdb VALUES (100, 'Test replication'); + 3. Connect to other nodes and verify data is replicated: + docker exec -it {{ container_prefix }}2 mysql -uroot -p{{ root_password }} + USE testdb; + SELECT * FROM testdb; + +- name: Display verification instructions + debug: + msg: "{{ verification_msg | split('\n') }}" diff --git a/pmm_qa/percona_server_for_mysql/tasks/percona-server-setup-single.yml b/pmm_qa/percona_server_for_mysql/tasks/percona-server-setup-single.yml new file mode 100644 index 00000000..75d4ea58 --- /dev/null +++ b/pmm_qa/percona_server_for_mysql/tasks/percona-server-setup-single.yml @@ -0,0 +1,8 @@ +- name: Generate my.cnf for each node + template: + src: ./data/my.cnf.j2 + dest: "{{ data_dir }}/node{{ item }}/my.cnf" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + +- name: Prepare docker container and install Percona Server for MySQL + include_tasks: ./tasks/prepare_install_ps.yml diff --git a/pmm_qa/percona_server_for_mysql/tasks/prepare_install_ps.yml b/pmm_qa/percona_server_for_mysql/tasks/prepare_install_ps.yml new file mode 100644 index 00000000..dce072be --- /dev/null +++ b/pmm_qa/percona_server_for_mysql/tasks/prepare_install_ps.yml @@ -0,0 +1,72 @@ +- name: Prepare Container for Percona Server for MySQL 8.0+ + shell: | + docker run --rm -d --name="{{ container_prefix }}{{ item }}" \ + --network="pmm-qa" \ + --privileged --cgroupns=host -v /sys/fs/cgroup:/sys/fs/cgroup:rw \ + -v /var/lib/containerd \ + -v ./ssl:/ssl \ + antmelekhin/docker-systemd:ubuntu-24.04 + when: ps_version | replace('_', '') | int >= 80 + loop: "{{ range(1, nodes_count | int + 1) | list }}" + +- name: Prepare Container for Percona Server for MySQL 5.7 + shell: | + docker run --rm -d --name="{{ container_prefix }}{{ item }}" \ + --network="pmm-qa" \ + --privileged --cgroupns=host -v /sys/fs/cgroup:/sys/fs/cgroup:rw \ + -v /var/lib/containerd \ + -v ./ssl:/ssl \ + antmelekhin/docker-systemd:ubuntu-22.04 + when: ps_version | replace('_', '') | int < 80 + loop: "{{ range(1, nodes_count | int + 1) | list }}" + +- name: Install dependencies + shell: | + docker exec {{ container_prefix }}{{ item }} apt-get update + docker exec {{ container_prefix }}{{ item }} apt-get -y install wget gnupg2 lsb-release curl + loop: "{{ range(1, nodes_count | int + 1) | list }}" + +- name: Install Percona Release + shell: | + docker exec {{ container_prefix }}{{ item }} wget https://repo.percona.com/apt/percona-release_latest.generic_all.deb + docker exec {{ container_prefix }}{{ item }} dpkg -i ./percona-release_latest.generic_all.deb + loop: "{{ range(1, nodes_count | int + 1) | list }}" + +- name: Enable Percona Server for MySQL repository + shell: docker exec {{ container_prefix }}{{ item }} percona-release enable {{ 'ps-84-lts' if ps_version == '8_4' else 'ps-' + ps_version | replace('_', '') }} release + loop: "{{ range(1, nodes_count | int + 1) | list }}" + +- name: Install Percona Server for MySQL + shell: | + docker exec {{ container_prefix }}{{ item }} apt install -y \ + percona-server-server{{ '-5.7' if ps_version | replace('_', '') == '57' else '' }} \ + percona-server-rocksdb{{ '-5.7' if ps_version | replace('_', '') == '57' else '' }} \ + loop: "{{ range(1, nodes_count | int + 1) | list }}" + +- name: Start Percona Server for MySQL + shell: | + docker exec {{ container_prefix }}{{ item }} systemctl enable mysql + docker exec {{ container_prefix }}{{ item }} systemctl start mysql + loop: "{{ range(1, nodes_count | int + 1) | list }}" + +- name: Copy config file to docker container + shell: docker cp {{ data_dir }}/node{{ item }}/my.cnf {{ container_prefix }}{{ item }}:/etc/mysql/my.cnf + loop: "{{ range(1, nodes_count | int + 1) | list }}" + +- name: Restart Percona Server for MySQL + shell: docker exec {{ container_prefix }}{{ item }} systemctl restart mysql + loop: "{{ range(1, nodes_count | int + 1) | list }}" + +- name: Wait 5 seconds for MySQL to start + pause: + seconds: 5 + +- name: Chance root password Percona Server for MySQL 5.7 + shell: "docker exec {{ container_prefix }}{{ item }} mysql -e \"ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '{{ root_password }}';\"" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: ps_version|replace('_', '')|int < 80 + +- name: Chance root password Percona Server for MySQL 8.0+ + shell: "docker exec {{ container_prefix }}{{ item }} mysql -e \"ALTER USER 'root'@'localhost' IDENTIFIED WITH caching_sha2_password BY '{{ root_password }}';\"" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: ps_version|replace('_', '')|int >= 80 diff --git a/pmm_qa/pmm-framework.py b/pmm_qa/pmm-framework.py index 7b477332..641d7a1b 100755 --- a/pmm_qa/pmm-framework.py +++ b/pmm_qa/pmm-framework.py @@ -66,43 +66,19 @@ def setup_ps(db_type, db_version=None, db_config=None, args=None): # Gather Version details ps_version = os.getenv('PS_VERSION') or db_version or database_configs[db_type]["versions"][-1] ps_version_int = int(ps_version.replace(".", "")) - if ps_version_int >= 84: - # Define environment variables for playbook - env_vars = { - 'PMM_SERVER_IP': args.pmm_server_ip or container_name or '127.0.0.1', - 'SETUP_TYPE': setup_type_value, - 'NODES_COUNT': get_value('NODES_COUNT', db_type, args, db_config), - 'QUERY_SOURCE': get_value('QUERY_SOURCE', db_type, args, db_config), - 'PS_VERSION': ps_version, - 'CLIENT_VERSION': get_value('CLIENT_VERSION', db_type, args, db_config), - 'ADMIN_PASSWORD': os.getenv('ADMIN_PASSWORD') or args.pmm_server_password or 'admin', - 'MY_ROCKS': get_value('MY_ROCKS', db_type, args, db_config), - } - - run_ansible_playbook('percona_server/percona-server-setup.yml', env_vars, args) - else: - # Define environment variables for playbook - env_vars = { - 'GROUP_REPLICATION': setup_type, - 'PS_NODES': no_of_nodes, - 'PS_VERSION': ps_version, - 'PMM_SERVER_IP': args.pmm_server_ip or container_name or '127.0.0.1', - 'PS_CONTAINER': 'ps_pmm_' + str(ps_version) + ( - '_replica' if setup_type_value in ("replication", "replica") else ''), - 'PS_PORT': 3318 if setup_type_value in ("replication", "replica") else 3317, - 'CLIENT_VERSION': get_value('CLIENT_VERSION', db_type, args, db_config), - 'QUERY_SOURCE': get_value('QUERY_SOURCE', db_type, args, db_config), - 'PS_TARBALL': get_value('TARBALL', db_type, args, db_config), - 'ADMIN_PASSWORD': os.getenv('ADMIN_PASSWORD') or args.pmm_server_password or 'admin', - 'PMM_QA_GIT_BRANCH': os.getenv('PMM_QA_GIT_BRANCH') or 'v3' - } - - # Ansible playbook filename - playbook_filename = 'ps_pmm_setup.yml' - - # Call the function to run the Ansible playbook - run_ansible_playbook(playbook_filename, env_vars, args) + # Define environment variables for playbook + env_vars = { + 'PMM_SERVER_IP': args.pmm_server_ip or container_name or '127.0.0.1', + 'SETUP_TYPE': setup_type_value, + 'NODES_COUNT': get_value('NODES_COUNT', db_type, args, db_config), + 'QUERY_SOURCE': get_value('QUERY_SOURCE', db_type, args, db_config), + 'PS_VERSION': ps_version, + 'CLIENT_VERSION': get_value('CLIENT_VERSION', db_type, args, db_config), + 'ADMIN_PASSWORD': os.getenv('ADMIN_PASSWORD') or args.pmm_server_password or 'admin', + 'MY_ROCKS': get_value('MY_ROCKS', db_type, args, db_config), + } + run_ansible_playbook('percona_server_for_mysql/percona-server-setup.yml', env_vars, args) def setup_mysql(db_type, db_version=None, db_config=None, args=None): # Check if PMM server is running @@ -113,7 +89,6 @@ def setup_mysql(db_type, db_version=None, db_config=None, args=None): # Gather Version details ms_version = os.getenv('MS_VERSION') or db_version or database_configs[db_type]["versions"][-1] - ms_version_int = int(ms_version.replace(".", "")) # Check Setup Types setup_type = '' @@ -131,6 +106,7 @@ def setup_mysql(db_type, db_version=None, db_config=None, args=None): 'GROUP_REPLICATION': setup_type, 'MS_NODES': no_of_nodes, 'MS_VERSION': ms_version, + 'SETUP_TYPE': setup_type_value, 'PMM_SERVER_IP': args.pmm_server_ip or container_name or '127.0.0.1', 'MS_CONTAINER': 'mysql_pmm_' + str(ms_version), 'CLIENT_VERSION': get_value('CLIENT_VERSION', db_type, args, db_config), @@ -140,11 +116,7 @@ def setup_mysql(db_type, db_version=None, db_config=None, args=None): 'PMM_QA_GIT_BRANCH': os.getenv('PMM_QA_GIT_BRANCH') or 'v3' } - # Ansible playbook filename - playbook_filename = 'ms_pmm_setup.yml' - - # Call the function to run the Ansible playbook - run_ansible_playbook(playbook_filename, env_vars, args) + run_ansible_playbook('mysql/mysql-setup.yml', env_vars, args) def setup_ssl_mysql(db_type, db_version=None, db_config=None, args=None): # Check if PMM server is running diff --git a/pmm_qa/scripts/database_options.py b/pmm_qa/scripts/database_options.py index b58373fd..1024ea6c 100644 --- a/pmm_qa/scripts/database_options.py +++ b/pmm_qa/scripts/database_options.py @@ -23,7 +23,7 @@ "TARBALL": ""} }, "MYSQL": { - "versions": ["8.0", "8.4"], + "versions": ["5.7", "8.0", "8.4"], "configurations": {"QUERY_SOURCE": "perfschema", "SETUP_TYPE": "", "CLIENT_VERSION": "3-dev-latest", "TARBALL": ""} },