From f723f282466fea3bbf4083ab340544f720976f55 Mon Sep 17 00:00:00 2001 From: travagliad <215686151+travagliad@users.noreply.github.com> Date: Mon, 28 Jul 2025 09:48:38 +0100 Subject: [PATCH] PMM-14170: Add Valkey setup and configuration scripts --- pmm_qa/pmm-framework.py | 27 ++++ pmm_qa/scripts/database_options.py | 4 + pmm_qa/valkey/cleanup.sh | 15 ++ pmm_qa/valkey/sentinel.conf.j2 | 22 +++ pmm_qa/valkey/valkey-primary.conf.j2 | 27 ++++ pmm_qa/valkey/valkey-replica.conf.j2 | 28 ++++ pmm_qa/valkey/valkey.yml | 209 +++++++++++++++++++++++++++ 7 files changed, 332 insertions(+) create mode 100644 pmm_qa/valkey/cleanup.sh create mode 100644 pmm_qa/valkey/sentinel.conf.j2 create mode 100644 pmm_qa/valkey/valkey-primary.conf.j2 create mode 100644 pmm_qa/valkey/valkey-replica.conf.j2 create mode 100644 pmm_qa/valkey/valkey.yml diff --git a/pmm_qa/pmm-framework.py b/pmm_qa/pmm-framework.py index 84d02e1..e662571 100755 --- a/pmm_qa/pmm-framework.py +++ b/pmm_qa/pmm-framework.py @@ -788,6 +788,31 @@ def setup_dockerclients(db_type, db_version=None, db_config=None, args=None): # Call the function to run the setup_docker_client_images script execute_shell_scripts(shell_scripts, shell_scripts_path, env_vars, args) +def setup_valkey(db_type, db_version=None, db_config=None, args=None): + + # Check if PMM server is running + container_name = get_running_container_name() + if container_name is None and args.pmm_server_ip is None: + print(f"Check if PMM Server is Up and Running..Exiting") + exit() + + # Gather Version details + valkey_version = os.getenv('VALKEY_VERSION') or db_version or database_configs[db_type]["versions"][-1] + + # Define environment variables for playbook + env_vars = { + 'PMM_SERVER_IP': args.pmm_server_ip or container_name or '127.0.0.1', + 'VALKEY_VERSION': valkey_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', + 'PMM_QA_GIT_BRANCH': os.getenv('PMM_QA_GIT_BRANCH') or 'v3' + } + + # Ansible playbook filename + playbook_filename = 'valkey/valkey.yml' + + # Call the function to run the Ansible playbook + run_ansible_playbook(playbook_filename, env_vars, args) # Set up databases based on arguments received def setup_database(db_type, db_version=None, db_config=None, args=None): @@ -834,6 +859,8 @@ def setup_database(db_type, db_version=None, db_config=None, args=None): setup_ssl_mlaunch(db_type, db_version, db_config, args) elif db_type == 'BUCKET': setup_bucket(db_type, db_version, db_config, args) + elif db_type == 'VALKEY': + setup_valkey(db_type, db_version, db_config, args) else: print(f"Database type {db_type} is not recognised, Exiting...") exit(1) diff --git a/pmm_qa/scripts/database_options.py b/pmm_qa/scripts/database_options.py index 444fed5..46028d6 100644 --- a/pmm_qa/scripts/database_options.py +++ b/pmm_qa/scripts/database_options.py @@ -76,5 +76,9 @@ }, "BUCKET": { "configurations": {"BUCKET_NAMES": 'bcp'} + }, + "VALKEY": { + "versions": ["7-alpine", "8-bookworm"], + "configurations": {"CLIENT_VERSION": "3-dev-latest", "SETUP_TYPE": "", "TARBALL": ""} } } diff --git a/pmm_qa/valkey/cleanup.sh b/pmm_qa/valkey/cleanup.sh new file mode 100644 index 0000000..9f11258 --- /dev/null +++ b/pmm_qa/valkey/cleanup.sh @@ -0,0 +1,15 @@ +#!/bin/bash -e + +docker exec -it pmm-server pmm-admin remove valkey valkey-primary-svc || : +docker exec -it pmm-server pmm-admin remove valkey valkey-replica1-svc || : +docker exec -it pmm-server pmm-admin remove valkey valkey-replica2-svc || : +docker exec -it pmm-server pmm-admin remove valkey sentinel1-svc || : +docker exec -it pmm-server pmm-admin remove valkey sentinel2-svc || : +docker exec -it pmm-server pmm-admin remove valkey sentinel3-svc || : + +docker rm -vf valkey-primary valkey-replica-1 valkey-replica-2 || : +docker rm -vf sentinel-1 sentinel-2 sentinel-3 || : + +docker volume rm -f valkey-primary-data valkey-replica-1-data valkey-replica-2-data || : + +rm -rf "$HOME/valkey" \ No newline at end of file diff --git a/pmm_qa/valkey/sentinel.conf.j2 b/pmm_qa/valkey/sentinel.conf.j2 new file mode 100644 index 0000000..9137777 --- /dev/null +++ b/pmm_qa/valkey/sentinel.conf.j2 @@ -0,0 +1,22 @@ +# sentinel.conf +bind 0.0.0.0 + +port 26379 + +# Monitor the master +sentinel monitor valkey-primary valkey-primary 6379 {{ sentinel_quorum }} +sentinel auth-user valkey-primary default +sentinel auth-pass valkey-primary "{{ valkey_password }}" +sentinel resolve-hostnames yes + +# Failover timeouts +sentinel down-after-milliseconds valkey-primary 5000 +sentinel failover-timeout valkey-primary 10000 +sentinel parallel-syncs valkey-primary 1 + +# Security +protected-mode no + +# Logging +loglevel notice +logfile "" \ No newline at end of file diff --git a/pmm_qa/valkey/valkey-primary.conf.j2 b/pmm_qa/valkey/valkey-primary.conf.j2 new file mode 100644 index 0000000..40fcff2 --- /dev/null +++ b/pmm_qa/valkey/valkey-primary.conf.j2 @@ -0,0 +1,27 @@ +# Basic Valkey configuration for primary +bind 0.0.0.0 +port 6379 + +requirepass "{{ valkey_password }}" +masterauth "{{ valkey_password }}" + +# Persistence +save 900 1 +save 300 10 +save 60 10000 + +# Replication +replica-serve-stale-data yes +replica-read-only yes +repl-diskless-sync no +repl-diskless-sync-delay 5 + +# Security +protected-mode no + +# Logging +loglevel notice +logfile "" + +# Memory management +maxmemory-policy allkeys-lru \ No newline at end of file diff --git a/pmm_qa/valkey/valkey-replica.conf.j2 b/pmm_qa/valkey/valkey-replica.conf.j2 new file mode 100644 index 0000000..d794973 --- /dev/null +++ b/pmm_qa/valkey/valkey-replica.conf.j2 @@ -0,0 +1,28 @@ +# Basic Valkey configuration for replica +bind 0.0.0.0 +port 6379 + +requirepass "{{ valkey_password }}" +masterauth "{{ valkey_password }}" + +# Replication +replicaof valkey-primary 6379 +replica-serve-stale-data yes +replica-read-only yes +repl-diskless-sync no +repl-diskless-sync-delay 5 + +# Persistence +save 900 1 +save 300 10 +save 60 10000 + +# Security +protected-mode no + +# Logging +loglevel notice +logfile "" + +# Memory management +maxmemory-policy allkeys-lru \ No newline at end of file diff --git a/pmm_qa/valkey/valkey.yml b/pmm_qa/valkey/valkey.yml new file mode 100644 index 0000000..423df45 --- /dev/null +++ b/pmm_qa/valkey/valkey.yml @@ -0,0 +1,209 @@ +--- +- name: Deploy Valkey Cluster with Sentinel + hosts: localhost + gather_facts: false + vars: + valkey_version: "{{ lookup('env', 'VALKEY_VERSION') | default('7-alpine', true) }}" + valkey_image: "valkey/valkey:{{ valkey_version }}" + valkey_network_name: "pmm-qa" + valkey_password: "" + valkey_data_dir: "{{ lookup('env', 'HOME') }}/valkey/data" + valkey_config_dir: "{{ lookup('env', 'HOME') }}/valkey/config" + valkey_primary_port: 6379 + valkey_replica_count: 2 + valkey_replica_start_port: 6380 + sentinel_count: 3 + sentinel_start_port: 26379 + sentinel_quorum: 2 + + pmm_server_name: "pmm-server" + + tasks: + - name: Create Docker network + community.docker.docker_network: + name: "{{ valkey_network_name }}" + driver: bridge + state: present + + - name: Create config directory + file: + path: "{{ valkey_config_dir }}" + state: directory + mode: '0755' + + - name: Create a config directory per Sentinel + file: + path: "{{ valkey_config_dir }}/sentinel-{{ item }}" + state: directory + mode: '0755' + loop: "{{ range(1, sentinel_count + 1) | list }}" + + - name: Create data directory + file: + path: "{{ valkey_data_dir }}" + state: directory + mode: '0755' + + - name: Generate Valkey primary configuration + template: + src: valkey-primary.conf.j2 + dest: "{{ valkey_config_dir }}/valkey-primary.conf" + mode: '0644' + + - name: Generate Valkey replica configurations + template: + src: valkey-replica.conf.j2 + dest: "{{ valkey_config_dir }}/valkey-replica-{{ item }}.conf" + mode: '0644' + loop: "{{ range(1, valkey_replica_count + 1) | list }}" + + - name: Generate Sentinel configurations + template: + src: sentinel.conf.j2 + dest: "{{ valkey_config_dir }}/sentinel-{{ item }}/sentinel.conf" + mode: '0664' + loop: "{{ range(1, sentinel_count + 1) | list }}" + + - name: Generate a password if not provided + when: valkey_password == "" + set_fact: + valkey_password: "{{ lookup('community.general.random_string', length=20, min_special=5, min_upper=2, override_special='!?()[]{}:;/|@#$%&^*<>=_+-') }}" + + - name: Display generated Valkey password + debug: + msg: "Generated Valkey password: {{ valkey_password }}" + + - name: Create Docker volume for primary data + community.docker.docker_volume: + name: "valkey-primary-data" + state: present + + - name: Create Docker volumes for replica data + community.docker.docker_volume: + name: "valkey-replica-{{ item }}-data" + state: present + loop: "{{ range(1, valkey_replica_count + 1) | list }}" + + - name: Start Valkey primary container + community.docker.docker_container: + name: "valkey-primary" + image: "{{ valkey_image }}" + state: started + restart_policy: unless-stopped + networks: + - name: "{{ valkey_network_name }}" + ports: + - "{{ valkey_primary_port }}:6379" + volumes: + - "valkey-primary-data:/data" + - "{{ valkey_config_dir }}/valkey-primary.conf:/usr/local/etc/valkey/valkey.conf:ro" + command: ["valkey-server", "/usr/local/etc/valkey/valkey.conf"] + healthcheck: + test: ["CMD", "valkey-cli", "-a", "{{ valkey_password }}", "ping"] + interval: 10s + timeout: 5s + retries: 5 + + - name: Wait for the primary to be ready + wait_for: + host: localhost + port: "{{ valkey_primary_port }}" + timeout: 30 + delay: 1 + + - name: Start Valkey replica containers + community.docker.docker_container: + name: "valkey-replica-{{ item }}" + image: "{{ valkey_image }}" + state: started + restart_policy: unless-stopped + networks: + - name: "{{ valkey_network_name }}" + ports: + - "{{ valkey_replica_start_port + item - 1 }}:6379" + volumes: + - "valkey-replica-{{ item }}-data:/data" + - "{{ valkey_config_dir }}/valkey-replica-{{ item }}.conf:/usr/local/etc/valkey/valkey.conf:ro" + command: ["valkey-server", "/usr/local/etc/valkey/valkey.conf"] + healthcheck: + test: ["CMD", "valkey-cli", "-a", "{{ valkey_password }}", "ping"] + interval: 10s + timeout: 5s + retries: 5 + loop: "{{ range(1, valkey_replica_count + 1) | list }}" + + - name: Wait for replicas to be ready + wait_for: + host: localhost + port: "{{ valkey_replica_start_port + item - 1 }}" + timeout: 30 + delay: 1 + loop: "{{ range(1, valkey_replica_count + 1) | list }}" + + - name: Start Sentinel containers + community.docker.docker_container: + name: "sentinel-{{ item }}" + image: "{{ valkey_image }}" + state: started + restart_policy: unless-stopped + networks: + - name: "{{ valkey_network_name }}" + ports: + - "{{ sentinel_start_port + item - 1 }}:26379" + volumes: + - "{{ valkey_config_dir }}/sentinel-{{ item }}:/usr/local/etc/valkey" + command: ["valkey-sentinel", "/usr/local/etc/valkey/sentinel.conf"] + healthcheck: + test: ["CMD", "valkey-cli", "-p", "{{ sentinel_start_port }}", "ping"] + interval: 10s + timeout: 5s + retries: 5 + loop: "{{ range(1, sentinel_count + 1) | list }}" + + - name: Wait for Sentinels to be ready + wait_for: + host: localhost + port: "{{ sentinel_start_port + item - 1 }}" + timeout: 30 + delay: 1 + loop: "{{ range(1, sentinel_count + 1) | list }}" + + - name: Verify cluster status + community.docker.docker_container_exec: + container: "valkey-primary" + command: valkey-cli -a "{{ valkey_password }}" info replication + register: cluster_status + + - name: Display cluster status + debug: + msg: "{{ cluster_status.stdout_lines }}" + + - name: Run Sentinel status command + community.docker.docker_container_exec: + container: "sentinel-1" + command: valkey-cli -p {{ sentinel_start_port }} sentinel masters + register: sentinel_status + + - name: Display Sentinel status + debug: + msg: "{{ sentinel_status.stdout_lines }}" + + - name: Add the primary to monitoring + community.docker.docker_container_exec: + container: "{{ pmm_server_name }}" + command: pmm-admin add valkey --cluster=valkey-cluster --replication-set=valkey-repl --environment=valkey-test --username=default --password="{{ valkey_password }}" --service-name=valkey-primary-svc --host=valkey-primary --port=6379 --custom-labels='role=primary' + ignore_errors: yes + + - name: Add the replicas to monitoring + community.docker.docker_container_exec: + container: "{{ pmm_server_name }}" + command: pmm-admin add valkey --cluster=valkey-cluster --replication-set=valkey-repl --environment=valkey-test --username=default --password="{{ valkey_password }}" --service-name=valkey-replica{{ item }}-svc --host=valkey-replica-{{ item }} --port=6379 --custom-labels='role=replica' + loop: "{{ range(1, valkey_replica_count + 1) | list }}" + ignore_errors: yes + + - name: Add Sentinels to monitoring + community.docker.docker_container_exec: + container: "{{ pmm_server_name }}" + command: pmm-admin add valkey --cluster=valkey-cluster --environment=valkey-test --username=default --password="{{ valkey_password }}" --service-name=sentinel{{ item }}-svc --host=sentinel-{{ item }} --port={{ sentinel_start_port }} --custom-labels='role=sentinel' + loop: "{{ range(1, sentinel_count + 1) | list }}" + ignore_errors: yes \ No newline at end of file