diff --git a/pmm_qa/mysql/__init__.py b/pmm_qa/mysql/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pmm_qa/mysql/data/group_replication/init.sql.j2 b/pmm_qa/mysql/data/group_replication/init.sql.j2 new file mode 100644 index 0000000..0f90f4d --- /dev/null +++ b/pmm_qa/mysql/data/group_replication/init.sql.j2 @@ -0,0 +1,14 @@ +-- 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/mysql/data/group_replication/my.cnf.j2 b/pmm_qa/mysql/data/group_replication/my.cnf.j2 new file mode 100644 index 0000000..a2ec202 --- /dev/null +++ b/pmm_qa/mysql/data/group_replication/my.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=mysql_pmm_{{ms_version}}_{{ 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='mysql_pmm_{{ms_version}}_{{ item }}:{{ group_seeds_port }}' +loose-group_replication_group_seeds='{% for i in range(1, nodes_count | int + 1) %}mysql_pmm_{{ms_version}}_{{ 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=mysql_pmm_{{ms_version}}_{{ 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/init-async-replication.sql.j2 b/pmm_qa/mysql/data/init-async-replication.sql.j2 new file mode 100644 index 0000000..7fd1a45 --- /dev/null +++ b/pmm_qa/mysql/data/init-async-replication.sql.j2 @@ -0,0 +1,13 @@ +-- 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 %} \ No newline at end of file diff --git a/pmm_qa/mysql/data/my-async-replication.cnf.j2 b/pmm_qa/mysql/data/my-async-replication.cnf.j2 new file mode 100644 index 0000000..091b7f7 --- /dev/null +++ b/pmm_qa/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=mysql_pmm_{{ ms_version }}_{{ 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=mysql_pmm_{{ ms_version }}_{{ 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 0000000..e69de29 diff --git a/pmm_qa/mysql/mysql_setup.yml b/pmm_qa/mysql/mysql_setup.yml new file mode 100644 index 0000000..ed25aa6 --- /dev/null +++ b/pmm_qa/mysql/mysql_setup.yml @@ -0,0 +1,236 @@ +--- +# MySQL 8.4 and higher single instance and also Cluster with Group Replication +- name: Setup MySQL 8.4 and higher. Cluster with Group Replication in Docker + hosts: localhost + connection: local + gather_facts: yes + vars: + ms_version: "{{ lookup('env', 'MS_VERSION') | default('8.4', true) }}" + cluster_name: "mysql_cluster" + replication_user: "repl_user" + replication_password: "GRgrO9301RuF" + root_password: "GRgrO9301RuF" + mysql_port: 4306 + mysql_listen_port: 3306 + group_seeds_port: 44061 + 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: "" + + 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 MySQL containers + community.docker.docker_container: + name: "mysql_pmm_{{ ms_version }}_{{ item }}" + image: "mysql:{{ ms_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 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-setup-single.yml + when: setup_type != "gr" and setup_type != "replication" + + - name: Create slowlog configuration for mysql nodes + community.docker.docker_container_exec: + container: "mysql_pmm_{{ ms_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_docker_container.yml + vars: + container_name: "mysql_pmm_{{ ms_version }}_{{ item }}" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + + - name: Get already connected services to pmm server + community.docker.docker_container_exec: + container: "mysql_pmm_{{ ms_version }}_1" + command: > + sh -c 'curl --location --insecure -u"admin:{{ admin_password }}" -s --request GET "http://{{ pmm_server_ip }}:{{ '80' if pmm_server_ip is ansible.utils.ipv4 else '8080' }}/v1/management/services" | jq -r ".services[].service_name"' + register: pmm_server_services + + - name: Display already connected services to pmm server + debug: + msg: "{{ pmm_server_services.stdout | split('\n') }}" + + - name: Find out if service is already connected to pmm server + block: + - name: Loop through MySQL databases + set_fact: + random_service_name_value: "_{{ 9999 | random + 1 }}" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + when: "('mysql_pmm_' ~ ms_version ~ '_' ~ item) in pmm_server_services.stdout" + + - name: Add service to pmm server + community.docker.docker_container_exec: + container: "mysql_pmm_{{ ms_version }}_{{ item }}" + command: pmm-admin add mysql --query-source={{ query_source }} --username=root --password={{ root_password }} --environment=ms-gr-dev --cluster=ms-gr-dev-cluster --replication-set=ms-gr-replication mysql_pmm_{{ ms_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: "mysql_pmm_{{ ms_version }}_{{ item }}" + command: pmm-admin add mysql --query-source={{ query_source }} --username=root --password={{ root_password }} --environment=ms-replication-dev --cluster=ms-replication-dev-cluster --replication-set=ms-async-replication mysql_pmm_{{ ms_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: "mysql_pmm_{{ ms_version }}_{{ item }}" + command: pmm-admin add mysql --query-source={{ query_source }} --username=root --password={{ root_password }} --environment=ms-dev mysql_pmm_{{ ms_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 MySQL nodes + community.docker.docker_container_exec: + container: "mysql_pmm_{{ ms_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 MySQL nodes + community.docker.docker_container_exec: + container: "mysql_pmm_{{ ms_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 MySQL nodes + community.docker.docker_container_exec: + container: "mysql_pmm_{{ ms_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 MySQL nodes + community.docker.docker_container_exec: + container: "mysql_pmm_{{ ms_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 MySQL nodes + community.docker.docker_container_exec: + container: "mysql_pmm_{{ ms_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 MySQL nodes + community.docker.docker_container_exec: + container: "mysql_pmm_{{ ms_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 MySQL nodes + community.docker.docker_container_exec: + container: "mysql_pmm_{{ ms_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 }}" diff --git a/pmm_qa/mysql/setup_mysql.py b/pmm_qa/mysql/setup_mysql.py new file mode 100644 index 0000000..aaa9ab7 --- /dev/null +++ b/pmm_qa/mysql/setup_mysql.py @@ -0,0 +1,16 @@ +import os +from scripts.get_env_value import get_value +from scripts.run_ansible_playbook import run_ansible_playbook + +def setup_mysql_docker(db_type, container_name, db_config=None, args=None): + env_vars = { + 'SETUP_TYPE': get_value('SETUP_TYPE', db_type, args, db_config).lower(), + 'MS_VERSION': get_value('MS_VERSION', db_type, args, db_config), + 'PMM_SERVER_IP': args.pmm_server_ip or container_name or '127.0.0.1', + 'CLIENT_VERSION': get_value('CLIENT_VERSION', db_type, args, db_config), + 'QUERY_SOURCE': get_value('QUERY_SOURCE', db_type, args, db_config), + 'ADMIN_PASSWORD': os.getenv('ADMIN_PASSWORD') or args.pmm_server_password or 'admin', + 'NODES_COUNT': get_value('NODES_COUNT', db_type, args, db_config), + } + + run_ansible_playbook('mysql/mysql_setup.yml', env_vars, args) 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 0000000..8d46701 --- /dev/null +++ b/pmm_qa/mysql/tasks/mysql-async-replication-setup.yml @@ -0,0 +1,126 @@ +- 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: "mysql_pmm_{{ ms_version }}_{{ item }}" + image: "mysql:{{ ms_version }}" + restart_policy: always + state: started + cgroupns_mode: host + 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" + - "/sys/fs/cgroup:/sys/fs/cgroup:rw" + 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: "mysql_pmm_{{ ms_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 mysql_pmm_{{ ms_version }}_1 binary log status + community.docker.docker_container_exec: + container: "mysql_pmm_{{ ms_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: "mysql_pmm_{{ ms_version }}_{{ item }}" + command: > + mysql -uroot -p{{ root_password }} -e " + CHANGE REPLICATION SOURCE TO + SOURCE_HOST='mysql_pmm_{{ ms_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: "mysql_pmm_{{ ms_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: "mysql_pmm_{{ ms_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 (mysql_pmm_{{ ms_version }}_1): + docker exec -it mysql_pmm_{{ ms_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 mysql_pmm_{{ ms_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/mysql/tasks/mysql-group-replication-setup.yml b/pmm_qa/mysql/tasks/mysql-group-replication-setup.yml new file mode 100644 index 0000000..4ae64e8 --- /dev/null +++ b/pmm_qa/mysql/tasks/mysql-group-replication-setup.yml @@ -0,0 +1,124 @@ +- name: Generate my.cnf for each node + template: + src: ./data/group_replication/my.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/group_replication/init.sql.j2 + dest: "{{ data_dir }}/node{{ item }}/init.sql" + loop: "{{ range(1, nodes_count | int + 1) | list }}" + +- name: Start MySQL containers with group replication + community.docker.docker_container: + name: "mysql_pmm_{{ ms_version }}_{{ item }}" + image: "mysql:{{ ms_version }}" + restart_policy: always + state: started + cgroupns_mode: host + 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" + - "/sys/fs/cgroup:/sys/fs/cgroup:rw" + 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: "mysql_pmm_{{ ms_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: "mysql_pmm_{{ ms_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: "mysql_pmm_{{ ms_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: "mysql_pmm_{{ ms_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: "mysql_pmm_{{ ms_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: "mysql_pmm_{{ ms_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 mysql_pmm_{{ ms_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 mysql_pmm_{{ ms_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/mysql/tasks/mysql-setup-single.yml b/pmm_qa/mysql/tasks/mysql-setup-single.yml new file mode 100644 index 0000000..3053b49 --- /dev/null +++ b/pmm_qa/mysql/tasks/mysql-setup-single.yml @@ -0,0 +1,33 @@ +- 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 MySQL containers + community.docker.docker_container: + name: "mysql_pmm_{{ ms_version }}_{{ item }}" + image: "mysql:{{ ms_version }}" + restart_policy: always + state: started + cgroupns_mode: host + 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" + - "/sys/fs/cgroup:/sys/fs/cgroup:rw" + 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/percona-server-setup.yml b/pmm_qa/percona_server/percona-server-setup.yml index 4af81dc..b12db72 100644 --- a/pmm_qa/percona_server/percona-server-setup.yml +++ b/pmm_qa/percona_server/percona-server-setup.yml @@ -21,6 +21,7 @@ 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: "" @@ -90,7 +91,7 @@ when: query_source == "slowlog" - name: Install and add pmm client. - include_tasks: ../tasks/install_pmm_client_centos.yml + include_tasks: ../tasks/install_pmm_client_docker_container.yml vars: container_name: "ps_pmm_{{ ps_version }}_{{ item }}" loop: "{{ range(1, nodes_count | int + 1) | list }}" 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 index 67cebb4..452e6ae 100644 --- a/pmm_qa/percona_server/tasks/percona-server-async-replication-setup.yml +++ b/pmm_qa/percona_server/tasks/percona-server-async-replication-setup.yml @@ -16,6 +16,7 @@ image: "percona/percona-server:{{ ps_version }}" restart_policy: always state: started + cgroupns_mode: host networks: - name: "{{ network_name }}" env: @@ -26,6 +27,7 @@ - "{{ 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" + - "/sys/fs/cgroup:/sys/fs/cgroup:rw" loop: "{{ range(1, nodes_count | int + 1) | list }}" - name: Wait for MySQL to be available 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 index 0f6d72f..aaa0317 100644 --- a/pmm_qa/percona_server/tasks/percona-server-group-replication-setup.yml +++ b/pmm_qa/percona_server/tasks/percona-server-group-replication-setup.yml @@ -16,6 +16,7 @@ image: "percona/percona-server:{{ ps_version }}" restart_policy: always state: started + cgroupns_mode: host networks: - name: "{{ network_name }}" env: @@ -27,6 +28,7 @@ - "{{ 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" + - "/sys/fs/cgroup:/sys/fs/cgroup:rw" loop: "{{ range(1, nodes_count | int + 1) | list }}" - name: Wait for MySQL to be available diff --git a/pmm_qa/percona_server/tasks/percona-server-setup.yml b/pmm_qa/percona_server/tasks/percona-server-setup.yml index 9fbad84..a38a714 100644 --- a/pmm_qa/percona_server/tasks/percona-server-setup.yml +++ b/pmm_qa/percona_server/tasks/percona-server-setup.yml @@ -12,6 +12,7 @@ state: started networks: - name: "{{ network_name }}" + cgroupns_mode: host env: MYSQL_ROOT_PASSWORD: "{{ root_password }}" ports: @@ -20,6 +21,7 @@ volumes: - "{{ data_dir }}/node{{ item }}/my.cnf:/etc/mysql/my.cnf" - "{{ data_dir }}/node{{ item }}/data:/var/lib/mysql" + - "/sys/fs/cgroup:/sys/fs/cgroup:rw" loop: "{{ range(1, nodes_count | int + 1) | list }}" - name: Wait for MySQL to be available diff --git a/pmm_qa/pmm-framework.py b/pmm_qa/pmm-framework.py index 5538e53..8b7145f 100755 --- a/pmm_qa/pmm-framework.py +++ b/pmm_qa/pmm-framework.py @@ -2,119 +2,12 @@ import argparse import os import sys -import ansible_runner import requests import re - -# Database configurations -database_configs = { - "PSMDB": { - "versions": ["4.4", "5.0", "6.0", "7.0", "8.0", "latest"], - "configurations": {"CLIENT_VERSION": "3-dev-latest", "SETUP_TYPE": "pss", "COMPOSE_PROFILES": "classic", - "TARBALL": ""} - }, - "MLAUNCH_PSMDB": { - "versions": ["4.4", "5.0", "6.0", "7.0", "8.0"], - "configurations": {"CLIENT_VERSION": "3-dev-latest", "SETUP_TYPE": "pss", "TARBALL": ""} - }, - "MLAUNCH_MODB": { - "versions": ["4.4", "5.0", "6.0", "7.0", "8.0"], - "configurations": {"CLIENT_VERSION": "3-dev-latest", "SETUP_TYPE": "pss", "TARBALL": ""} - }, - "SSL_MLAUNCH": { - "versions": ["4.4", "5.0", "6.0", "7.0", "8.0"], - "configurations": {"CLIENT_VERSION": "3-dev-latest", "SETUP_TYPE": "pss", "COMPOSE_PROFILES": "classic", - "TARBALL": ""} - }, - "SSL_PSMDB": { - "versions": ["4.4", "5.0", "6.0", "7.0", "8.0", "latest"], - "configurations": {"CLIENT_VERSION": "3-dev-latest", "SETUP_TYPE": "pss", "COMPOSE_PROFILES": "classic", - "TARBALL": ""} - }, - "MYSQL": { - "versions": ["8.4", "8.0"], - "configurations": {"QUERY_SOURCE": "perfschema", "SETUP_TYPE": "", "CLIENT_VERSION": "3-dev-latest", - "TARBALL": ""} - }, - "PS": { - "versions": ["5.7", "8.4", "8.0"], - "configurations": {"QUERY_SOURCE": "perfschema", "SETUP_TYPE": "", "CLIENT_VERSION": "3-dev-latest", - "TARBALL": "", "NODES_COUNT": 1} - }, - "SSL_MYSQL": { - "versions": ["5.7", "8.4", "8.0"], - "configurations": {"QUERY_SOURCE": "perfschema", "SETUP_TYPE": "", "CLIENT_VERSION": "3-dev-latest", - "TARBALL": ""} - }, - "PGSQL": { - "versions": ["11", "12", "13", "14", "15", "16", "17"], - "configurations": {"QUERY_SOURCE": "pgstatements", "CLIENT_VERSION": "3-dev-latest", "USE_SOCKET": ""} - }, - "PDPGSQL": { - "versions": ["11", "12", "13", "14", "15", "16", "17"], - "configurations": {"CLIENT_VERSION": "3-dev-latest", "USE_SOCKET": ""} - }, - "SSL_PDPGSQL": { - "versions": ["11", "12", "13", "14", "15", "16", "17"], - "configurations": {"CLIENT_VERSION": "3-dev-latest", "USE_SOCKET": ""} - }, - "PXC": { - "versions": ["5.7", "8.0"], - "configurations": {"CLIENT_VERSION": "3-dev-latest", "QUERY_SOURCE": "perfschema", "TARBALL": ""} - }, - "PROXYSQL": { - "versions": ["2"], - "configurations": {"PACKAGE": ""} - }, - "HAPROXY": { - "versions": [""], - "configurations": {"CLIENT_VERSION": "3-dev-latest"} - }, - "EXTERNAL": { - "REDIS": { - "versions": ["1.14.0", "1.58.0"], - }, - "NODEPROCESS": { - "versions": ["0.7.5", "0.7.10"], - }, - "configurations": {"CLIENT_VERSION": "3-dev-latest"} - }, - "DOCKERCLIENTS": { - "configurations": {} # Empty dictionary for consistency - }, -} - - -def run_ansible_playbook(playbook_filename, env_vars, args): - # Get Script Dir - script_path = os.path.abspath(sys.argv[0]) - script_dir = os.path.dirname(script_path) - playbook_path = script_dir + "/" + playbook_filename - verbosity_level = 1 - - - - if args.verbosity_level is not None: - verbosity_level = int(args.verbosity_level) - - if args.verbose: - print(f'Options set after considering Defaults: {env_vars}') - - r = ansible_runner.run( - private_data_dir=script_dir, - playbook=playbook_path, - inventory='127.0.0.1', - cmdline='-l localhost, --connection=local', - envvars=env_vars, - suppress_env_files=True, - verbosity=verbosity_level, - ) - - print(f'{playbook_filename} playbook execution {r.status}') - - if r.rc != 0: - exit(1) - +from mysql.setup_mysql import setup_mysql_docker +from scripts.get_env_value import get_value +from scripts.database_options import database_options as database_configs +from scripts.run_ansible_playbook import run_ansible_playbook def get_running_container_name(): container_image_name = "pmm-server" @@ -151,26 +44,6 @@ def get_running_container_name(): return None - -def get_value(key, db_type, args, db_config): - # Check if the variable exists in the environment - env_value = os.environ.get(key) - if env_value is not None: - return env_value - - # Only for client_version we accept global command line argument - if key == "CLIENT_VERSION" and args.client_version is not None: - return args.client_version - - # Check if the variable exists in the args config - config_value = db_config.get(key) - if config_value is not None: - return config_value - - # Fall back to default configs value or empty '' - return database_configs[db_type]["configurations"].get(key, '') - - def setup_ps(db_type, db_version=None, db_config=None, args=None): # Check if PMM server is running container_name = get_running_container_name() @@ -236,6 +109,7 @@ 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 = '' @@ -248,26 +122,28 @@ def setup_mysql(db_type, db_version=None, db_config=None, args=None): setup_type = '' no_of_nodes = 2 - # Define environment variables for playbook - env_vars = { - 'GROUP_REPLICATION': setup_type, - 'MS_NODES': no_of_nodes, - 'MS_VERSION': ms_version, - '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), - 'QUERY_SOURCE': get_value('QUERY_SOURCE', db_type, args, db_config), - 'MS_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 = 'ms_pmm_setup.yml' + if ms_version_int >= 84: + setup_mysql_docker(db_type, container_name, db_config, args) + else: + # Define environment variables for playbook + env_vars = { + 'GROUP_REPLICATION': setup_type, + 'MS_NODES': no_of_nodes, + 'MS_VERSION': ms_version, + '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), + 'QUERY_SOURCE': get_value('QUERY_SOURCE', db_type, args, db_config), + 'MS_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' + } - # Call the function to run the Ansible playbook - run_ansible_playbook(playbook_filename, env_vars, args) + # 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) 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/__init__.py b/pmm_qa/scripts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pmm_qa/scripts/database_options.py b/pmm_qa/scripts/database_options.py new file mode 100644 index 0000000..70c57b9 --- /dev/null +++ b/pmm_qa/scripts/database_options.py @@ -0,0 +1,77 @@ +database_options = { + "PSMDB": { + "versions": ["4.4", "5.0", "6.0", "7.0", "8.0", "latest"], + "configurations": {"CLIENT_VERSION": "3-dev-latest", "SETUP_TYPE": "pss", "COMPOSE_PROFILES": "classic", + "TARBALL": ""} + }, + "MLAUNCH_PSMDB": { + "versions": ["4.4", "5.0", "6.0", "7.0", "8.0"], + "configurations": {"CLIENT_VERSION": "3-dev-latest", "SETUP_TYPE": "pss", "TARBALL": ""} + }, + "MLAUNCH_MODB": { + "versions": ["4.4", "5.0", "6.0", "7.0", "8.0"], + "configurations": {"CLIENT_VERSION": "3-dev-latest", "SETUP_TYPE": "pss", "TARBALL": ""} + }, + "SSL_MLAUNCH": { + "versions": ["4.4", "5.0", "6.0", "7.0", "8.0"], + "configurations": {"CLIENT_VERSION": "3-dev-latest", "SETUP_TYPE": "pss", "COMPOSE_PROFILES": "classic", + "TARBALL": ""} + }, + "SSL_PSMDB": { + "versions": ["4.4", "5.0", "6.0", "7.0", "8.0", "latest"], + "configurations": {"CLIENT_VERSION": "3-dev-latest", "SETUP_TYPE": "pss", "COMPOSE_PROFILES": "classic", + "TARBALL": ""} + }, + "MYSQL": { + "versions": ["8.0", "8.4"], + "configurations": {"QUERY_SOURCE": "perfschema", "SETUP_TYPE": "", "CLIENT_VERSION": "3-dev-latest", + "TARBALL": ""} + }, + "PS": { + "versions": ["5.7", "8.4", "8.0"], + "configurations": {"QUERY_SOURCE": "perfschema", "SETUP_TYPE": "", "CLIENT_VERSION": "3-dev-latest", + "TARBALL": "", "NODES_COUNT": 1} + }, + "SSL_MYSQL": { + "versions": ["5.7", "8.4", "8.0"], + "configurations": {"QUERY_SOURCE": "perfschema", "SETUP_TYPE": "", "CLIENT_VERSION": "3-dev-latest", + "TARBALL": ""} + }, + "PGSQL": { + "versions": ["11", "12", "13", "14", "15", "16", "17"], + "configurations": {"QUERY_SOURCE": "pgstatements", "CLIENT_VERSION": "3-dev-latest", "USE_SOCKET": "", + "SETUP_TYPE": ""} + }, + "PDPGSQL": { + "versions": ["11", "12", "13", "14", "15", "16", "17"], + "configurations": {"CLIENT_VERSION": "3-dev-latest", "USE_SOCKET": "", "SETUP_TYPE": ""} + }, + "SSL_PDPGSQL": { + "versions": ["11", "12", "13", "14", "15", "16", "17"], + "configurations": {"CLIENT_VERSION": "3-dev-latest", "USE_SOCKET": ""} + }, + "PXC": { + "versions": ["5.7", "8.0"], + "configurations": {"CLIENT_VERSION": "3-dev-latest", "QUERY_SOURCE": "perfschema", "TARBALL": ""} + }, + "PROXYSQL": { + "versions": ["2"], + "configurations": {"PACKAGE": ""} + }, + "HAPROXY": { + "versions": [""], + "configurations": {"CLIENT_VERSION": "3-dev-latest"} + }, + "EXTERNAL": { + "REDIS": { + "versions": ["1.14.0", "1.58.0"], + }, + "NODEPROCESS": { + "versions": ["0.7.5", "0.7.10"], + }, + "configurations": {"CLIENT_VERSION": "3-dev-latest"} + }, + "DOCKERCLIENTS": { + "configurations": {} # Empty dictionary for consistency + }, +} diff --git a/pmm_qa/scripts/get_env_value.py b/pmm_qa/scripts/get_env_value.py new file mode 100644 index 0000000..74d6514 --- /dev/null +++ b/pmm_qa/scripts/get_env_value.py @@ -0,0 +1,20 @@ +import os +from .database_options import database_options + +def get_value(key, db_type, args, db_config): + # Check if the variable exists in the environment + env_value = os.environ.get(key) + if env_value is not None: + return env_value + + # Only for client_version we accept global command line argument + if key == "CLIENT_VERSION" and args.client_version is not None: + return args.client_version + + # Check if the variable exists in the args config + config_value = db_config.get(key) + if config_value is not None: + return config_value + + # Fall back to default configs value or empty '' + return database_options[db_type]["configurations"].get(key, '') diff --git a/pmm_qa/scripts/run_ansible_playbook.py b/pmm_qa/scripts/run_ansible_playbook.py new file mode 100644 index 0000000..cda9538 --- /dev/null +++ b/pmm_qa/scripts/run_ansible_playbook.py @@ -0,0 +1,31 @@ +import os +import ansible_runner +import sys + +def run_ansible_playbook(playbook_filename, env_vars, args): + # Get Script Dir + script_path = os.path.abspath(sys.argv[0]) + script_dir = os.path.dirname(script_path) + playbook_path = script_dir + "/" + playbook_filename + verbosity_level = 1 + + if args.verbosity_level is not None: + verbosity_level = int(args.verbosity_level) + + if args.verbose: + print(f'Options set after considering Defaults: {env_vars}') + + r = ansible_runner.run( + private_data_dir=script_dir, + playbook=playbook_path, + inventory='127.0.0.1', + cmdline='-l localhost, --connection=local', + envvars=env_vars, + suppress_env_files=True, + verbosity=verbosity_level, + ) + + print(f'{playbook_filename} playbook execution {r.status}') + + if r.rc != 0: + exit(1) diff --git a/pmm_qa/tasks/add_mysql_to_pmm_server.yml b/pmm_qa/tasks/add_mysql_to_pmm_server.yml index 1dd6b42..7114d97 100644 --- a/pmm_qa/tasks/add_mysql_to_pmm_server.yml +++ b/pmm_qa/tasks/add_mysql_to_pmm_server.yml @@ -1,5 +1,5 @@ - name: Install and add pmm client - include_tasks: ./install_pmm_client_centos.yml + include_tasks: install_pmm_client_docker_container.yml - name: Set unique service name include_tasks: ./set_unique_service_name.yml diff --git a/pmm_qa/tasks/install_pmm_client_centos.yml b/pmm_qa/tasks/install_pmm_client_centos.yml deleted file mode 100644 index ea8f9f3..0000000 --- a/pmm_qa/tasks/install_pmm_client_centos.yml +++ /dev/null @@ -1,29 +0,0 @@ -- name: Get PMM server address - shell: 'docker ps -f name=-server --format "{{ "{{" }}.Names{{ "}}" }}"' - register: pmm_server_ip_output - when: pmm_server_ip == "127.0.0.1" - -- name: Set correct pmm server address - set_fact: - pmm_server_ip: "{{ pmm_server_ip_output.stdout }}" - when: pmm_server_ip == "127.0.0.1" - -- name: Print pmm server address - debug: - var: pmm_server_ip - -- name: Copy a file into the container - community.docker.docker_container_copy_into: - container: "{{ container_name }}" - path: ../pmm3-client-setup-centos.sh - container_path: /pmm3-client-setup.sh - -- name: "PMM Server IP is" - debug: - msg: "{{ pmm_server_ip }} is pmm server IP" - -- name: Install pmm-client - community.docker.docker_container_exec: - container: "{{ container_name }}" - user: "root" - command: bash -x /pmm3-client-setup.sh --pmm_server_ip {{ pmm_server_ip }} --client_version {{ client_version }} --admin_password {{ admin_password }} --use_metrics_mode no diff --git a/pmm_qa/tasks/install_pmm_client_docker_container.yml b/pmm_qa/tasks/install_pmm_client_docker_container.yml new file mode 100644 index 0000000..651e89a --- /dev/null +++ b/pmm_qa/tasks/install_pmm_client_docker_container.yml @@ -0,0 +1,261 @@ +- name: Get PMM server address + shell: 'docker ps -f name=-server --format "{{ "{{" }}.Names{{ "}}" }}"' + register: pmm_server_ip_output + when: pmm_server_ip == "127.0.0.1" + +- name: Set correct pmm server address + set_fact: + pmm_server_ip: "{{ pmm_server_ip_output.stdout }}" + when: pmm_server_ip == "127.0.0.1" + +- name: Print pmm server address + debug: + var: pmm_server_ip + +- name: Copy a file into the container + community.docker.docker_container_copy_into: + container: "{{ container_name }}" + path: ../pmm3-client-setup-centos.sh + container_path: /pmm3-client-setup.sh + +- name: "PMM Server IP is" + debug: + msg: "{{ pmm_server_ip }} is pmm server IP" + +- name: Set correct pmm server port + set_fact: + pmm_server_port: 443 + when: pmm_server_ip is ansible.utils.ipv4 + +- name: Set correct pmm server port + set_fact: + pmm_server_port: 8443 + when: pmm_server_ip is not ansible.utils.ipv4 + +- name: Detect OS inside the container + community.docker.docker_container_exec: + container: "{{ container_name }}" + command: cat /etc/os-release + register: container_os_info + +- name: Set distro family (debian/rhel) + set_fact: + distro_family: >- + {{ + ( + 'debian' if 'debian' in container_os_info.stdout | lower else + 'rhel' if 'rhel' in container_os_info.stdout | lower or 'centos' in container_os_info.stdout | lower or 'fedora' in container_os_info.stdout | lower + else 'unknown' + ) | trim + }} +- name: Install dependencies inside Debian-family container + community.docker.docker_container_exec: + container: "{{ container_name }}" + command: > + sh -c ' + apt-get update && + apt-get install -y wget gnupg2 jq lsb-base lsb-release curl iproute2 + ' + user: "root" + when: distro_family == "debian" + +- name: Install dependencies on RHEL-family containers + community.docker.docker_container_exec: + container: "{{ container_name }}" + command: microdnf install -y wget gnupg2 jq iproute + user: "root" + when: distro_family == "rhel" + +- name: Install curl on RHEL-family containers + community.docker.docker_container_exec: + container: "{{ container_name }}" + command: microdnf install -y curl-minimal + user: "root" + when: distro_family == "rhel" + ignore_errors: true + +- name: Get lsb_release + community.docker.docker_container_exec: + container: "{{ container_name }}" + command: > + bash -c "grep '^VERSION_CODENAME=' /etc/os-release | cut -d '=' -f2 | tr -d '\"'" + user: "root" + register: lsb_release + +- name: Set lsb_release + set_fact: + lsb_release: "{{ lsb_release.stdout }}" + +- name: Print expected client version + debug: + msg: "{{ metrics_mode }}" + +- name: Install percona release on Debian-family containers + community.docker.docker_container_exec: + container: "{{ container_name }}" + user: "root" + command: > + sh -c ' + wget -O /percona-release_latest.{{ lsb_release }}_all.deb https://repo.percona.com/apt/percona-release_latest.{{ lsb_release }}_all.deb && + dpkg -i /percona-release_latest.{{ lsb_release }}_all.deb + ' + when: + - distro_family == 'debian' + +- name: Install specific PMM client version on RHEL-family containers + community.docker.docker_container_exec: + container: "{{ container_name }}" + user: "root" + command: > + sh -c ' + wget -O /percona-release-latest.noarch.rpm https://repo.percona.com/yum/percona-release-latest.noarch.rpm && + rpm -i /percona-release-latest.noarch.rpm + ' + when: + - distro_family == 'rhel' + ignore_errors: true + +- name: Install pmm client experimental on Debian-family containers + community.docker.docker_container_exec: + container: "{{ container_name }}" + user: "root" + command: > + sh -c ' + percona-release enable-only pmm3-client experimental && + apt-get update && + apt-get -y install pmm-client + ' + when: distro_family == "debian" and client_version == "3-dev-latest" + +- name: Install pmm client experimental on RHEL-family containers + community.docker.docker_container_exec: + container: "{{ container_name }}" + user: "root" + command: > + sh -c ' + percona-release enable-only pmm3-client experimental && + microdnf install -y pmm-client + ' + when: distro_family == "rhel" and client_version == "3-dev-latest" + +- name: Install pmm client testing on Debian-family containers + community.docker.docker_container_exec: + container: "{{ container_name }}" + user: "root" + command: > + sh -c ' + percona-release enable-only pmm3-client testing && + apt-get update && + apt-get -y install pmm-client + ' + when: distro_family == "debian" and client_version == "pmm3-rc" + +- name: Install pmm client testing on RHEL-family containers + community.docker.docker_container_exec: + container: "{{ container_name }}" + user: "root" + command: > + sh -c ' + percona-release enable-only pmm3-client testing && + microdnf install -y pmm-client + ' + when: distro_family == "rhel" and client_version == "pmm3-rc" + +- name: Install pmm client release on Debian-family containers + community.docker.docker_container_exec: + container: "{{ container_name }}" + user: "root" + command: > + sh -c ' + percona-release enable-only pmm3-client release && + apt-get update && + apt-get -y install pmm-client + ' + when: distro_family == "debian" and client_version == "pmm3-latest" + +- name: Install pmm client release on RHEL-family containers + community.docker.docker_container_exec: + container: "{{ container_name }}" + user: "root" + command: > + sh -c ' + percona-release enable-only pmm3-client release && + microdnf install -y pmm-client + ' + when: distro_family == "rhel" and client_version == "pmm3-latest" + +- name: Install specific PMM client version on Debian-family containers + community.docker.docker_container_exec: + container: "{{ container_name }}" + user: "root" + command: > + sh -c ' + wget -O /pmm-client.deb https://repo.percona.com/pmm3-client/apt/pool/main/p/pmm-client/pmm-client_{{ client_version }}-7.$(lsb_release -sc)_amd64.deb && + dpkg -i /pmm-client.deb + ' + when: + - distro_family == 'debian' + - client_version is match('^3\\.[0-9]+\\.[0-9]+$') + +- name: Install specific PMM client version on RHEL-family containers + community.docker.docker_container_exec: + container: "{{ container_name }}" + user: "root" + command: > + sh -c ' + wget -O /pmm-client.rpm https://repo.percona.com/pmm3-client/yum/release/9/RPMS/x86_64/pmm-client-{{ client_version }}-7.el9.x86_64.rpm && + rpm -i /pmm-client.rpm + ' + when: + - distro_family == 'rhel' + - client_version is match('^3\\.[0-9]+\\.[0-9]+$') + +- name: Install tarball PMM client version + community.docker.docker_container_exec: + container: "{{ container_name }}" + user: "root" + command: > + sh -c ' + wget -O /pmm-client.tar.gz "{{ client_version }}" && + tar -zxpf /pmm-client.tar.gz && + PMM_CLIENT=`ls -1td pmm-client* 2>/dev/null | grep -v ".tar" | grep -v ".sh" | head -n1` && + echo ${PMM_CLIENT} && + rm -rf pmm-client && + mv ${PMM_CLIENT} pmm-client && + rm -rf /usr/local/bin/pmm-client && + mv -f pmm-client /usr/local/bin && + bash -x /usr/local/bin/pmm-client/install_tarball && + ln -sf /usr/local/percona/pmm/bin/pmm-admin /usr/local/bin/pmm-admin && + ln -sf /usr/local/percona/pmm/bin/pmm-agent /usr/local/bin/pmm-agent && + pmm-admin --version + ' + when: + - client_version | regex_search('^https?://.*\\.tar\\.gz$') is not none + +- name: Connect pmm client to pmm server using metrics mode + community.docker.docker_container_exec: + container: "{{ container_name }}" + user: "root" + command: pmm-agent setup --config-file=/usr/local/percona/pmm/config/pmm-agent.yaml --server-address={{ pmm_server_ip }}:{{ pmm_server_port }} --server-insecure-tls --metrics-mode={{ metrics_mode }} --server-username=admin --server-password={{ admin_password }} {{ container_name }} + when: metrics_mode | length > 0 + +- name: Connect pmm client to pmm server using metrics mode + community.docker.docker_container_exec: + container: "{{ container_name }}" + user: "root" + command: pmm-agent setup --config-file=/usr/local/percona/pmm/config/pmm-agent.yaml --server-address={{ pmm_server_ip }}:{{ pmm_server_port }} --server-insecure-tls --server-username=admin --server-password={{ admin_password }} {{ container_name }} + when: metrics_mode | length == 0 + +- name: Wait 5 seconds for connection to complete + pause: + seconds: 5 + +- name: Start pmm client + community.docker.docker_container_exec: + container: "{{ container_name }}" + user: "root" + command: > + sh -c 'nohup pmm-agent --config-file=/usr/local/percona/pmm/config/pmm-agent.yaml > /var/log/pmm-agent.log 2>&1 &' +- name: Wait 5 seconds for start to complete + pause: + seconds: 5