diff options
| author | Grzegorz Koper <grzegorzk@stackhpc.com> | 2025-09-04 16:56:24 +0200 |
|---|---|---|
| committer | Bartosz Bezak <bartosz@stackhpc.com> | 2025-11-06 16:01:20 +0000 |
| commit | 86c732dfabeb8cc9b116da758b3c55eb5d8a2b43 (patch) | |
| tree | 2d995e9e08f312f68981c7bea5dc39de36d8bc45 /ansible | |
| parent | 68852492196e5797deb3077f63777e062bf12d16 (diff) | |
| download | kolla-ansible-86c732dfabeb8cc9b116da758b3c55eb5d8a2b43.tar.gz kolla-ansible-86c732dfabeb8cc9b116da758b3c55eb5d8a2b43.zip | |
Replace Redis with Valkey
This change replaces Redis with Valkey, which is non-existent
on Rocky Linux 10 / CentOS Stream 10 due to licensing issues.
Co-Authored-By: Bartosz Bezak <bartosz@stackhpc.com>
Co-Authored-By: Michal Nasiadka <mnasiadka@gmail.com>
Change-Id: Ifcc6ec6e943c20867d969b0bdb0e4cbac53eea1e
Signed-off-by: Grzegorz Koper <grzegorzk@stackhpc.com>
Signed-off-by: Bartosz Bezak <bartosz@stackhpc.com>
Signed-off-by: Michal Nasiadka <mnasiadka@gmail.com>
Diffstat (limited to 'ansible')
56 files changed, 473 insertions, 303 deletions
diff --git a/ansible/group_vars/all/cinder.yml b/ansible/group_vars/all/cinder.yml index e4659674e..51948a18a 100644 --- a/ansible/group_vars/all/cinder.yml +++ b/ansible/group_vars/all/cinder.yml @@ -19,8 +19,8 @@ cinder_backend_huawei: "no" cinder_backend_huawei_xml_files: [] cinder_volume_group: "cinder-volumes" cinder_target_helper: "{{ 'lioadm' if ansible_facts.os_family == 'RedHat' else 'tgtadm' }}" -# Valid options are [ '', redis, etcd ] -cinder_coordination_backend: "{{ 'redis' if enable_redis | bool else 'etcd' if enable_etcd | bool else '' }}" +# Valid options are [ '', valkey, etcd ] +cinder_coordination_backend: "{{ 'valkey' if enable_valkey | bool else 'etcd' if enable_etcd | bool else '' }}" # Valid options are [ nfs, ceph, s3 ] cinder_backup_driver: "ceph" diff --git a/ansible/group_vars/all/common.yml b/ansible/group_vars/all/common.yml index 4a82c29ea..a32d3154c 100644 --- a/ansible/group_vars/all/common.yml +++ b/ansible/group_vars/all/common.yml @@ -331,7 +331,7 @@ enable_osprofiler: "no" # valid values: ["elasticsearch", "redis"] osprofiler_backend: "elasticsearch" opensearch_connection_string: "elasticsearch://{{ opensearch_address | put_address_in_context('url') }}:{{ opensearch_port }}" -osprofiler_backend_connection_string: "{{ redis_connection_string if osprofiler_backend == 'redis' else opensearch_connection_string }}" +osprofiler_backend_connection_string: "{{ valkey_connection_string if osprofiler_backend in ['redis', 'valkey'] else opensearch_connection_string }}" ###################### # Backend TLS options diff --git a/ansible/group_vars/all/designate.yml b/ansible/group_vars/all/designate.yml index e9916c542..343472a16 100644 --- a/ansible/group_vars/all/designate.yml +++ b/ansible/group_vars/all/designate.yml @@ -12,8 +12,8 @@ designate_ns_record: - "ns1.example.org" designate_backend_external: "no" designate_backend_external_bind9_nameservers: "" -# Valid options are [ '', redis ] -designate_coordination_backend: "{{ 'redis' if enable_redis | bool else '' }}" +# Valid options are [ '', valkey ] +designate_coordination_backend: "{{ 'valkey' if enable_valkey | bool else '' }}" designate_enable_notifications_sink: "no" designate_notifications_topic_name: "notifications_designate" diff --git a/ansible/group_vars/all/gnocchi.yml b/ansible/group_vars/all/gnocchi.yml index f103736b4..3792bf7d0 100644 --- a/ansible/group_vars/all/gnocchi.yml +++ b/ansible/group_vars/all/gnocchi.yml @@ -8,8 +8,8 @@ enable_gnocchi_statsd: "no" # Valid options are [ file, ceph ] gnocchi_backend_storage: "file" -# Valid options are [redis, ''] -gnocchi_incoming_storage: "{{ 'redis' if enable_redis | bool else '' }}" +# Valid options are [valkey, ''] +gnocchi_incoming_storage: "{{ 'valkey' if enable_valkey | bool else '' }}" gnocchi_metric_datadir_volume: "gnocchi" gnocchi_internal_fqdn: "{{ kolla_internal_fqdn }}" diff --git a/ansible/group_vars/all/ironic.yml b/ansible/group_vars/all/ironic.yml index 1acb6e7ab..97df0fe71 100644 --- a/ansible/group_vars/all/ironic.yml +++ b/ansible/group_vars/all/ironic.yml @@ -9,7 +9,7 @@ enable_ironic_pxe_filter: "no" ironic_keystone_user: "ironic" # Coordination backend -ironic_coordination_backend: "{{ 'redis' if enable_redis | bool else 'etcd' if enable_etcd | bool else '' }}" +ironic_coordination_backend: "{{ 'valkey' if enable_valkey | bool else 'etcd' if enable_etcd | bool else '' }}" # Network interfaces ironic_http_interface: "{{ api_interface }}" diff --git a/ansible/group_vars/all/masakari.yml b/ansible/group_vars/all/masakari.yml index bef390e71..1f3d117e1 100644 --- a/ansible/group_vars/all/masakari.yml +++ b/ansible/group_vars/all/masakari.yml @@ -10,4 +10,4 @@ masakari_public_endpoint: "{{ masakari_external_fqdn | kolla_url(public_protocol masakari_api_port: "15868" masakari_api_public_port: "{{ haproxy_single_external_frontend_public_port if haproxy_single_external_frontend | bool else masakari_api_port }}" masakari_api_listen_port: "{{ masakari_api_port }}" -masakari_coordination_backend: "{{ 'redis' if enable_redis | bool else 'etcd' if enable_etcd | bool else '' }}" +masakari_coordination_backend: "{{ 'valkey' if enable_valkey | bool else 'etcd' if enable_etcd | bool else '' }}" diff --git a/ansible/group_vars/all/redis.yml b/ansible/group_vars/all/redis.yml deleted file mode 100644 index bea98be6e..000000000 --- a/ansible/group_vars/all/redis.yml +++ /dev/null @@ -1,11 +0,0 @@ ---- -enable_redis: "no" - -#################### -# Redis options -#################### -redis_connection_string: "redis://{% for host in groups['redis'] %}{% if host == groups['redis'][0] %}default:{{ redis_master_password }}@{{ 'api' | kolla_address(host) | put_address_in_context('url') }}:{{ redis_sentinel_port }}?sentinel=kolla{% else %}&sentinel_fallback={{ 'api' | kolla_address(host) | put_address_in_context('url') }}:{{ redis_sentinel_port }}{% endif %}{% endfor %}{{ redis_connection_string_extras }}" -redis_connection_string_extras: "&db=0&socket_timeout=60&retry_on_timeout=yes" - -redis_port: "6379" -redis_sentinel_port: "26379" diff --git a/ansible/group_vars/all/valkey.yml b/ansible/group_vars/all/valkey.yml new file mode 100644 index 000000000..c970de6ce --- /dev/null +++ b/ansible/group_vars/all/valkey.yml @@ -0,0 +1,30 @@ +--- +enable_valkey: "no" + +valkey_connection_string: >- + redis://{%- + for host in groups['valkey'] -%} + {%- if host == groups['valkey'][0] -%} + default:{{- valkey_master_password -}}@{{- + 'api' | kolla_address(host) | put_address_in_context('url') + -}}:{{- valkey_sentinel_port -}}?sentinel={{- valkey_sentinel_monitor_name -}} + {%- else -%} + &sentinel_fallback={{- + 'api' | kolla_address(host) | put_address_in_context('url') + -}}:{{- valkey_sentinel_port -}} + {%- endif -%} + {%- endfor -%} + {{- valkey_connection_string_extras -}} + +valkey_connection_string_extras: "&db=0&socket_timeout=60&retry_on_timeout=yes" + +# TODO(mnasiadka): Remove in G/2026.1 +# NOTE(mnasiadka): These can't reference valkey_server_port or valkey_sentinel_port since these +# are changed during migration +redis_port: "6379" +redis_sentinel_port: "26379" + +valkey_server_port: "6379" +valkey_sentinel_port: "26379" +valkey_sentinel_monitor_name: "kolla" +valkey_sentinel_quorum: 2 # TODO (gkoper) Discuss and settle on some sane defaults here diff --git a/ansible/inventory/all-in-one b/ansible/inventory/all-in-one index 6ab9227f5..4c6c23670 100644 --- a/ansible/inventory/all-in-one +++ b/ansible/inventory/all-in-one @@ -159,7 +159,7 @@ control [skyline:children] control -[redis:children] +[valkey:children] control [blazar:children] diff --git a/ansible/inventory/multinode b/ansible/inventory/multinode index 972e4059e..a2cba879a 100644 --- a/ansible/inventory/multinode +++ b/ansible/inventory/multinode @@ -177,7 +177,7 @@ control [skyline:children] control -[redis:children] +[valkey:children] control [blazar:children] diff --git a/ansible/roles/cinder/tasks/precheck.yml b/ansible/roles/cinder/tasks/precheck.yml index 21f3d9309..8f4fdff4a 100644 --- a/ansible/roles/cinder/tasks/precheck.yml +++ b/ansible/roles/cinder/tasks/precheck.yml @@ -58,7 +58,7 @@ - name: Checking for coordination backend if Ceph backend is enabled run_once: True fail: - msg: "Please enable redis or etcd when using Cinder Ceph backend" + msg: "Please enable valkey or etcd when using Cinder Ceph backend" when: - not skip_cinder_backend_check | bool - cinder_backend_ceph | bool diff --git a/ansible/roles/cinder/templates/cinder.conf.j2 b/ansible/roles/cinder/templates/cinder.conf.j2 index df6da4851..92cd83a88 100644 --- a/ansible/roles/cinder/templates/cinder.conf.j2 +++ b/ansible/roles/cinder/templates/cinder.conf.j2 @@ -247,8 +247,8 @@ verify_ssl_path = {{ openstack_cacert }} {% endif %} [coordination] -{% if cinder_coordination_backend == 'redis' %} -backend_url = {{ redis_connection_string }} +{% if cinder_coordination_backend == 'valkey' %} +backend_url = {{ valkey_connection_string }} {% elif cinder_coordination_backend == 'etcd' %} # NOTE(yoctozepto): we must use etcd3gw (aka etcd3+http) due to issues with alternative (etcd3) and eventlet (as used by cinder) # see https://bugs.launchpad.net/kolla-ansible/+bug/1854932 diff --git a/ansible/roles/cron/tasks/config.yml b/ansible/roles/cron/tasks/config.yml index e1a5e30e9..caebee58c 100644 --- a/ansible/roles/cron/tasks/config.yml +++ b/ansible/roles/cron/tasks/config.yml @@ -71,7 +71,7 @@ - { name: "prometheus", enabled: "{{ enable_prometheus | bool }}" } - { name: "proxysql", enabled: "{{ enable_proxysql | bool }}" } - { name: "rabbitmq", enabled: "{{ enable_rabbitmq | bool }}" } - - { name: "redis", enabled: "{{ enable_redis | bool }}" } + - { name: "valkey", enabled: "{{ enable_valkey | bool }}" } - { name: "skyline", enabled: "{{ enable_skyline | bool }}" } - { name: "tacker", enabled: "{{ enable_tacker | bool }}" } - { name: "trove", enabled: "{{ enable_trove | bool }}" } diff --git a/ansible/roles/cron/templates/cron-logrotate-redis.conf.j2 b/ansible/roles/cron/templates/cron-logrotate-redis.conf.j2 deleted file mode 100644 index 9fb4c5a50..000000000 --- a/ansible/roles/cron/templates/cron-logrotate-redis.conf.j2 +++ /dev/null @@ -1,3 +0,0 @@ -"/var/log/kolla/redis/*.log" -{ -} diff --git a/ansible/roles/cron/templates/cron-logrotate-valkey.conf.j2 b/ansible/roles/cron/templates/cron-logrotate-valkey.conf.j2 new file mode 100644 index 000000000..f59111e1d --- /dev/null +++ b/ansible/roles/cron/templates/cron-logrotate-valkey.conf.j2 @@ -0,0 +1,3 @@ +"/var/log/kolla/valkey/*.log" +{ +} diff --git a/ansible/roles/designate/templates/designate.conf.j2 b/ansible/roles/designate/templates/designate.conf.j2 index 7f56b7121..2ec55f827 100644 --- a/ansible/roles/designate/templates/designate.conf.j2 +++ b/ansible/roles/designate/templates/designate.conf.j2 @@ -118,8 +118,8 @@ policy_file = {{ designate_policy_file }} {% endif %} [coordination] -{% if designate_coordination_backend == 'redis' %} -backend_url = {{ redis_connection_string }} +{% if designate_coordination_backend == 'valkey' %} +backend_url = {{ valkey_connection_string }} {% endif %} {# NOTE(yoctozepto): etcd is not supported due to lack of group membership diff --git a/ansible/roles/fluentd/tasks/config.yml b/ansible/roles/fluentd/tasks/config.yml index 83a5504f3..d6c8cb649 100644 --- a/ansible/roles/fluentd/tasks/config.yml +++ b/ansible/roles/fluentd/tasks/config.yml @@ -98,6 +98,8 @@ enabled: "{{ enable_fluentd_systemd | bool }}" - name: "conf/input/13-uwsgi.conf.j2" enabled: true + - name: "conf/input/14-valkey.conf.j2" + enabled: "{{ enable_valkey | bool }}" customised_input_files: "{{ find_custom_fluentd_inputs.files | map(attribute='path') | list }}" # Filters fluentd_filter_files: "{{ default_filter_files | customise_fluentd(customised_filter_files) }}" diff --git a/ansible/roles/fluentd/templates/conf/input/14-valkey.conf.j2 b/ansible/roles/fluentd/templates/conf/input/14-valkey.conf.j2 new file mode 100644 index 000000000..113de855c --- /dev/null +++ b/ansible/roles/fluentd/templates/conf/input/14-valkey.conf.j2 @@ -0,0 +1,16 @@ +#jinja2: trim_blocks: False +<source> + @type tail + path /var/log/kolla/valkey/valkey.log,/var/log/kolla/valkey/valkey-sentinel.log + pos_file /var/run/fluentd/kolla-valkey.pos + tag infra.valkey + ignore_repeated_permission_error true + enable_watch_timer {{ fluentd_enable_watch_timer }} + <parse> + @type regexp + expression /^(?<Pid>\d+):(?<Role>[A-Za-z-]+) (?:(?<Timestamp>\d+ \w+ \d+ \d+:\d+:\d+\.\d+) (?<LogLevel>.) )?(?<Payload>.*)$/ + time_key Timestamp + keep_time_key true + time_format %c + </parse> +</source> diff --git a/ansible/roles/gnocchi/templates/gnocchi.conf.j2 b/ansible/roles/gnocchi/templates/gnocchi.conf.j2 index 643f2d35b..56f74d761 100644 --- a/ansible/roles/gnocchi/templates/gnocchi.conf.j2 +++ b/ansible/roles/gnocchi/templates/gnocchi.conf.j2 @@ -3,8 +3,8 @@ debug = {{ gnocchi_logging_debug }} log_dir = /var/log/kolla/gnocchi -{% if enable_redis | bool %} -coordination_url = {{ redis_connection_string }} +{% if enable_valkey | bool %} +coordination_url = {{ valkey_connection_string }} {% endif %} {% if service_name == 'gnocchi-api' %} @@ -66,9 +66,9 @@ policy_file = {{ gnocchi_policy_file }} {% endif %} [incoming] -{% if gnocchi_incoming_storage == 'redis' %} +{% if gnocchi_incoming_storage == 'valkey' %} driver = redis -redis_url = {{ redis_connection_string }} +redis_url = {{ valkey_connection_string }} {% endif %} [storage] diff --git a/ansible/roles/masakari/tasks/precheck.yml b/ansible/roles/masakari/tasks/precheck.yml index e3faf0908..9db46ab9f 100644 --- a/ansible/roles/masakari/tasks/precheck.yml +++ b/ansible/roles/masakari/tasks/precheck.yml @@ -25,3 +25,11 @@ when: - container_facts.containers['masakari_api'] is not defined - inventory_hostname in groups['masakari-api'] + +- name: Checking for coordination backend if running in multinode setup + run_once: True + fail: + msg: "Please enable Valkey or etcd when running in multinode scenario." + when: + - masakari_coordination_backend == '' + - groups['masakari'] | length > 1 diff --git a/ansible/roles/masakari/templates/masakari.conf.j2 b/ansible/roles/masakari/templates/masakari.conf.j2 index b84e0f0eb..d3f6a8721 100644 --- a/ansible/roles/masakari/templates/masakari.conf.j2 +++ b/ansible/roles/masakari/templates/masakari.conf.j2 @@ -84,8 +84,8 @@ connection = mysql+pymysql://{{ masakari_database_user }}:{{ masakari_database_p {% if service_name == 'masakari-api' %} [coordination] -{% if masakari_coordination_backend == 'redis' %} -backend_url = {{ redis_connection_string }} +{% if masakari_coordination_backend == 'valkey' %} +backend_url = {{ valkey_connection_string }} {% elif masakari_coordination_backend == 'etcd' %} # NOTE(jan.gutter): etcd v3.4 removed the default `v3alpha` api_version. Until # tooz defaults to a newer version, we should explicitly specify `v3` diff --git a/ansible/roles/mistral/templates/mistral.conf.j2 b/ansible/roles/mistral/templates/mistral.conf.j2 index 58de8cfc7..548200bb2 100644 --- a/ansible/roles/mistral/templates/mistral.conf.j2 +++ b/ansible/roles/mistral/templates/mistral.conf.j2 @@ -100,7 +100,7 @@ connection_string = {{ osprofiler_backend_connection_string }} {% endif %} [coordination] -backend_url = {{ redis_connection_string }} +backend_url = {{ valkey_connection_string }} [oslo_concurrency] lock_path = /var/lib/mistral/tmp diff --git a/ansible/roles/octavia/tasks/precheck.yml b/ansible/roles/octavia/tasks/precheck.yml index 51b4a0be4..23cf4d431 100644 --- a/ansible/roles/octavia/tasks/precheck.yml +++ b/ansible/roles/octavia/tasks/precheck.yml @@ -65,10 +65,10 @@ - octavia_network_type == "tenant" - neutron_plugin_agent != 'openvswitch' -- name: Checking whether Redis is enabled for octavia jobboard +- name: Checking whether Valkey is enabled for Octavia Jobboard assert: - that: enable_redis | bool - fail_msg: "Redis must be enabled when using octavia jobboard" + that: enable_valkey | bool + fail_msg: "Valkey must be enabled when using Octavia Jobboard" run_once: True when: - enable_octavia_jobboard | bool diff --git a/ansible/roles/octavia/templates/octavia.conf.j2 b/ansible/roles/octavia/templates/octavia.conf.j2 index 586957f30..9f251ffa9 100644 --- a/ansible/roles/octavia/templates/octavia.conf.j2 +++ b/ansible/roles/octavia/templates/octavia.conf.j2 @@ -168,16 +168,15 @@ ca_certificates_file = {{ openstack_cacert }} {% if enable_octavia_jobboard | bool %} [task_flow] -jobboard_backend_hosts = {% for host in groups['redis'] %}{{ 'api' | kolla_address(host) | put_address_in_context('url') }}{% if not loop.last %},{% endif %}{% endfor %} -jobboard_backend_password = {{ redis_master_password }} -jobboard_backend_port = {{ redis_sentinel_port }} +jobboard_backend_hosts = {% for host in groups['valkey'] %}{{ 'api' | kolla_address(host) | put_address_in_context('url') }}{% if not loop.last %},{% endif %}{% endfor %} +jobboard_backend_password = {{ valkey_master_password }} +jobboard_backend_port = {{ valkey_sentinel_port }} jobboard_backend_username = default jobboard_enabled = true jobboard_redis_backend_ssl_options = ssl:False -jobboard_redis_sentinel = kolla +jobboard_redis_sentinel = {{ valkey_sentinel_monitor_name }} jobboard_redis_sentinel_ssl_options = ssl:False persistence_connection = mysql+pymysql://{{ octavia_persistence_database_user }}:{{ octavia_persistence_database_password }}@{{ octavia_persistence_database_address }}/{{ octavia_persistence_database_name }}{{ '?ssl_ca=' ~ openstack_cacert if octavia_database_enable_tls_internal | bool }} -jobboard_enabled = true {% endif %} [oslo_concurrency] diff --git a/ansible/roles/prechecks/tasks/service_checks.yml b/ansible/roles/prechecks/tasks/service_checks.yml index 5f3ceef4b..3f2a711da 100644 --- a/ansible/roles/prechecks/tasks/service_checks.yml +++ b/ansible/roles/prechecks/tasks/service_checks.yml @@ -63,3 +63,10 @@ msg: "We are sorry but enable_ceph is no longer supported. Please use external ceph support." when: - (enable_ceph | default()) | bool + +- name: Validate that enable_redis is disabled + run_once: True + assert: + that: + - not (enable_redis | default(false)) | bool + msg: "Redis support has been replaced with Valkey, please set enable_redis to no and enable_valkey to yes" diff --git a/ansible/roles/prometheus/defaults/main.yml b/ansible/roles/prometheus/defaults/main.yml index 27affe447..147e241a6 100644 --- a/ansible/roles/prometheus/defaults/main.yml +++ b/ansible/roles/prometheus/defaults/main.yml @@ -318,8 +318,8 @@ prometheus_blackbox_exporter_endpoints_default: enabled: "{{ enable_prometheus_alertmanager | bool }}" - endpoints: "{% set rabbitmq_endpoints = [] %}{% for host in groups.get('rabbitmq', []) %}{{ rabbitmq_endpoints.append('rabbitmq_' + host + (':tls_connect:' if rabbitmq_enable_tls | bool else ':tcp_connect:') + ('api' | kolla_address(host) | put_address_in_context('url')) + ':' + hostvars[host]['rabbitmq_port'] ) }}{% endfor %}{{ rabbitmq_endpoints }}" enabled: "{{ enable_rabbitmq | bool }}" - - endpoints: "{% set redis_endpoints = [] %}{% for host in groups.get('redis', []) %}{{ redis_endpoints.append('redis_' + host + ':tcp_connect:' + ('api' | kolla_address(host) | put_address_in_context('url')) + ':' + hostvars[host]['redis_port']) }}{% endfor %}{{ redis_endpoints }}" - enabled: "{{ enable_redis | bool }}" + - endpoints: "{% set valkey_endpoints = [] %}{% for host in groups.get('valkey', []) %}{{ valkey_endpoints.append('valkey_' + host + ':tcp_connect:' + ('api' | kolla_address(host) | put_address_in_context('url')) + ':' + hostvars[host]['valkey_server_port']) }}{% endfor %}{{ valkey_endpoints }}" + enabled: "{{ enable_valkey | bool }}" prometheus_blackbox_exporter_endpoints_custom: [] diff --git a/ansible/roles/redis/defaults/main.yml b/ansible/roles/redis/defaults/main.yml deleted file mode 100644 index 6d3af49f0..000000000 --- a/ansible/roles/redis/defaults/main.yml +++ /dev/null @@ -1,78 +0,0 @@ ---- -redis_services: - redis: - container_name: redis - group: redis - enabled: true - image: "{{ redis_image_full }}" - volumes: "{{ redis_default_volumes + redis_extra_volumes }}" - dimensions: "{{ redis_dimensions }}" - healthcheck: "{{ redis_healthcheck }}" - redis-sentinel: - container_name: redis_sentinel - group: redis - environment: - REDIS_CONF: "{{ redis_conf_path }}" - REDIS_GEN_CONF: "{{ redis_generated_conf_path }}" - enabled: true - image: "{{ redis_sentinel_image_full }}" - volumes: "{{ redis_sentinel_default_volumes + redis_sentinel_extra_volumes }}" - dimensions: "{{ redis_sentinel_dimensions }}" - healthcheck: "{{ redis_sentinel_healthcheck }}" - -#################### -# Docker -#################### -redis_image: "{{ docker_image_url }}redis" -redis_tag: "{{ openstack_tag }}" -redis_image_full: "{{ redis_image }}:{{ redis_tag }}" - -redis_sentinel_image: "{{ docker_image_url }}redis-sentinel" -redis_sentinel_tag: "{{ openstack_tag }}" -redis_sentinel_image_full: "{{ redis_sentinel_image }}:{{ redis_tag }}" -redis_dimensions: "{{ default_container_dimensions }}" -redis_sentinel_dimensions: "{{ default_container_dimensions }}" - -redis_enable_healthchecks: "{{ enable_container_healthchecks }}" -redis_healthcheck_interval: "{{ default_container_healthcheck_interval }}" -redis_healthcheck_retries: "{{ default_container_healthcheck_retries }}" -redis_healthcheck_start_period: "{{ default_container_healthcheck_start_period }}" -redis_healthcheck_test: ["CMD-SHELL", "healthcheck_listen redis-server {{ redis_port }}"] -redis_healthcheck_timeout: "{{ default_container_healthcheck_timeout }}" -redis_healthcheck: - interval: "{{ redis_healthcheck_interval }}" - retries: "{{ redis_healthcheck_retries }}" - start_period: "{{ redis_healthcheck_start_period }}" - test: "{% if redis_enable_healthchecks | bool %}{{ redis_healthcheck_test }}{% else %}NONE{% endif %}" - timeout: "{{ redis_healthcheck_timeout }}" - -redis_sentinel_enable_healthchecks: "{{ enable_container_healthchecks }}" -redis_sentinel_healthcheck_interval: "{{ default_container_healthcheck_interval }}" -redis_sentinel_healthcheck_retries: "{{ default_container_healthcheck_retries }}" -redis_sentinel_healthcheck_start_period: "{{ default_container_healthcheck_start_period }}" -redis_sentinel_healthcheck_test: ["CMD-SHELL", "healthcheck_listen redis-sentinel {{ redis_sentinel_port }}"] -redis_sentinel_healthcheck_timeout: "{{ default_container_healthcheck_timeout }}" -redis_sentinel_healthcheck: - interval: "{{ redis_sentinel_healthcheck_interval }}" - retries: "{{ redis_sentinel_healthcheck_retries }}" - start_period: "{{ redis_sentinel_healthcheck_start_period }}" - test: "{% if redis_sentinel_enable_healthchecks | bool %}{{ redis_sentinel_healthcheck_test }}{% else %}NONE{% endif %}" - timeout: "{{ redis_sentinel_healthcheck_timeout }}" - -redis_default_volumes: - - "{{ node_config_directory }}/redis/:{{ container_config_directory }}/:ro" - - "/etc/localtime:/etc/localtime:ro" - - "{{ '/etc/timezone:/etc/timezone:ro' if ansible_facts.os_family == 'Debian' else '' }}" - - "{{ project_name }}:/var/lib/redis/" - - "kolla_logs:/var/log/kolla/" -redis_sentinel_default_volumes: - - "{{ node_config_directory }}/redis-sentinel/:{{ container_config_directory }}/:ro" - - "/etc/localtime:/etc/localtime:ro" - - "{{ '/etc/timezone:/etc/timezone:ro' if ansible_facts.os_family == 'Debian' else '' }}" - - "kolla_logs:/var/log/kolla/" - -redis_extra_volumes: "{{ default_extra_volumes }}" -redis_sentinel_extra_volumes: "{{ default_extra_volumes }}" - -redis_conf_path: "/etc/redis/redis.conf" -redis_generated_conf_path: "/etc/redis/redis-regenerated-by-config-rewrite.conf" diff --git a/ansible/roles/redis/tasks/check.yml b/ansible/roles/redis/tasks/check.yml deleted file mode 100644 index 0e3c55039..000000000 --- a/ansible/roles/redis/tasks/check.yml +++ /dev/null @@ -1,11 +0,0 @@ ---- -- name: Checking Redis containers - import_role: - role: service-check - -- name: Redis ping pong check - become: true - command: "{{ kolla_container_engine }} exec redis redis-cli -h {{ api_interface_address }} -a {{ redis_master_password }} ping" - register: redis_check - changed_when: "redis_check.stdout != 'PONG'" - failed_when: "redis_check.stdout != 'PONG'" diff --git a/ansible/roles/redis/tasks/precheck.yml b/ansible/roles/redis/tasks/precheck.yml deleted file mode 100644 index 8f6371d0b..000000000 --- a/ansible/roles/redis/tasks/precheck.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -- import_role: - name: service-precheck - vars: - service_precheck_services: "{{ redis_services }}" - service_name: "{{ project_name }}" - -- name: Get container facts - become: true - kolla_container_facts: - action: get_containers - container_engine: "{{ kolla_container_engine }}" - name: - - redis - check_mode: false - register: container_facts - -- name: Checking free port for Redis - vars: - service: "{{ redis_services['redis'] }}" - wait_for: - host: "{{ api_interface_address }}" - port: "{{ redis_port }}" - connect_timeout: 1 - timeout: 1 - state: stopped - when: - - container_facts.containers['redis'] is not defined - - service | service_enabled_and_mapped_to_host diff --git a/ansible/roles/redis/tasks/upgrade.yml b/ansible/roles/redis/tasks/upgrade.yml deleted file mode 100644 index 49edff81e..000000000 --- a/ansible/roles/redis/tasks/upgrade.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -- import_tasks: config.yml - -- import_tasks: check-containers.yml - -- name: Flush handlers - meta: flush_handlers diff --git a/ansible/roles/redis/templates/redis-sentinel.conf.j2 b/ansible/roles/redis/templates/redis-sentinel.conf.j2 deleted file mode 100644 index 34ef13a3d..000000000 --- a/ansible/roles/redis/templates/redis-sentinel.conf.j2 +++ /dev/null @@ -1,12 +0,0 @@ -{% set redis_master_address = 'api' | kolla_address(groups['redis'][0]) %} -daemonize no -pidfile "/var/run/redis/redis-sentinel.pid" -logfile "/var/log/kolla/redis/redis-sentinel.log" -bind {{ api_interface_address }} -port {{ redis_sentinel_port }} -sentinel myid {{ inventory_hostname | hash('sha1') }} -sentinel monitor kolla {{ redis_master_address }} {{ redis_port }} 2 -sentinel auth-pass kolla {{ redis_master_password }} -sentinel down-after-milliseconds kolla 5000 -sentinel failover-timeout kolla 60000 -sentinel parallel-syncs kolla 1 diff --git a/ansible/roles/redis/templates/redis-sentinel.json.j2 b/ansible/roles/redis/templates/redis-sentinel.json.j2 deleted file mode 100644 index d062cefc4..000000000 --- a/ansible/roles/redis/templates/redis-sentinel.json.j2 +++ /dev/null @@ -1,22 +0,0 @@ -{ - "command": "redis-sentinel {{ redis_generated_conf_path }}", - "config_files": [ - { - "source": "{{ container_config_directory }}/redis.conf", - "dest": "{{ redis_conf_path }}", - "owner": "redis", - "perm": "0600" - } - ], - "permissions": [ - { - "path": "/var/log/kolla/redis", - "owner": "redis:redis", - "recurse": true - }, - { - "path": "/etc/redis", - "owner": "redis:redis" - } - ] -} diff --git a/ansible/roles/redis/templates/redis.conf.j2 b/ansible/roles/redis/templates/redis.conf.j2 deleted file mode 100644 index 57a5ddce4..000000000 --- a/ansible/roles/redis/templates/redis.conf.j2 +++ /dev/null @@ -1,55 +0,0 @@ -bind {{ api_interface_address }} -port {{ redis_port }} -tcp-backlog 511 -timeout 0 -tcp-keepalive 300 -daemonize no -pidfile /var/run/redis/redis-server.pid -loglevel notice -logfile /var/log/kolla/redis/redis.log -databases 16 -save 900 1 -save 300 10 -save 60 10000 -stop-writes-on-bgsave-error yes -rdbcompression yes -rdbchecksum yes -dbfilename dump.rdb -dir /var/lib/redis -replica-serve-stale-data yes -replica-read-only yes -repl-diskless-sync no -repl-diskless-sync-delay 5 -repl-disable-tcp-nodelay no -replica-priority 100 -appendonly yes -appendfilename "redis-staging-ao.aof" -appendfsync everysec -no-appendfsync-on-rewrite no -auto-aof-rewrite-percentage 100 -auto-aof-rewrite-min-size 64mb -aof-load-truncated yes -lua-time-limit 5000 -slowlog-log-slower-than 10000 -slowlog-max-len 128 -latency-monitor-threshold 0 -notify-keyspace-events "" -hash-max-ziplist-entries 512 -hash-max-ziplist-value 64 -set-max-intset-entries 512 -zset-max-ziplist-entries 128 -zset-max-ziplist-value 64 -hll-sparse-max-bytes 3000 -activerehashing yes -client-output-buffer-limit normal 0 0 0 -client-output-buffer-limit replica 256mb 64mb 60 -client-output-buffer-limit pubsub 32mb 8mb 60 -hz 10 -aof-rewrite-incremental-fsync yes -requirepass {{ redis_master_password }} -masterauth {{ redis_master_password }} - -{% if inventory_hostname != groups['redis'][0] %} -{% set redis_master_address = 'api' | kolla_address(groups['redis'][0]) %} -replicaof {{ redis_master_address }} 6379 -{% endif %} diff --git a/ansible/roles/redis/templates/redis.json.j2 b/ansible/roles/redis/templates/redis.json.j2 deleted file mode 100644 index 02de435a3..000000000 --- a/ansible/roles/redis/templates/redis.json.j2 +++ /dev/null @@ -1,18 +0,0 @@ -{ - "command": "redis-server {{ redis_conf_path }}", - "config_files": [ - { - "source": "{{ container_config_directory }}/redis.conf", - "dest": "{{ redis_conf_path }}", - "owner": "redis", - "perm": "0600" - } - ], - "permissions": [ - { - "path": "/var/log/kolla/redis", - "owner": "redis:redis", - "recurse": true - } - ] -} diff --git a/ansible/roles/redis/vars/main.yml b/ansible/roles/redis/vars/main.yml deleted file mode 100644 index 1544bfcf9..000000000 --- a/ansible/roles/redis/vars/main.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -project_name: "redis" diff --git a/ansible/roles/telegraf/templates/telegraf.conf.j2 b/ansible/roles/telegraf/templates/telegraf.conf.j2 index a8c88f5e4..a890bf104 100644 --- a/ansible/roles/telegraf/templates/telegraf.conf.j2 +++ b/ansible/roles/telegraf/templates/telegraf.conf.j2 @@ -67,9 +67,9 @@ username = "{{ rabbitmq_user }}" password = "{{ rabbitmq_password }}" {% endif %} -{% if inventory_hostname in groups['redis'] and enable_redis | bool %} +{% if inventory_hostname in groups['valkey'] and enable_valkey | bool %} [[inputs.redis]] - servers = ["tcp://:{{ redis_master_password }}@{{ api_interface_address | put_address_in_context('url') }}:{{ redis_port }}"] + servers = ["tcp://:{{ valkey_master_password }}@{{ api_interface_address | put_address_in_context('url') }}:{{ valkey_server_port }}"] {% endif %} {% if inventory_hostname in groups['mariadb'] and (enable_mariadb or enable_external_mariadb_load_balancer) | bool %} [[inputs.mysql]] diff --git a/ansible/roles/valkey/defaults/main.yml b/ansible/roles/valkey/defaults/main.yml new file mode 100644 index 000000000..46647abd7 --- /dev/null +++ b/ansible/roles/valkey/defaults/main.yml @@ -0,0 +1,78 @@ +--- +valkey_services: + valkey-server: + container_name: valkey_server + group: valkey + enabled: true + image: "{{ valkey_image_full }}" + volumes: "{{ valkey_default_volumes + valkey_extra_volumes }}" + dimensions: "{{ valkey_dimensions }}" + healthcheck: "{{ valkey_healthcheck }}" + valkey-sentinel: + container_name: valkey_sentinel + group: valkey + environment: + VALKEY_CONF: "{{ valkey_conf_path }}" + VALKEY_GEN_CONF: "{{ valkey_generated_conf_path }}" + enabled: true + image: "{{ valkey_sentinel_image_full }}" + volumes: "{{ valkey_sentinel_default_volumes + valkey_sentinel_extra_volumes }}" + dimensions: "{{ valkey_sentinel_dimensions }}" + healthcheck: "{{ valkey_sentinel_healthcheck }}" + +#################### +# Docker +#################### +valkey_image: "{{ docker_image_url }}valkey-server" +valkey_tag: "{{ openstack_tag }}" +valkey_image_full: "{{ valkey_image }}:{{ valkey_tag }}" + +valkey_sentinel_image: "{{ docker_image_url }}valkey-sentinel" +valkey_sentinel_tag: "{{ openstack_tag }}" +valkey_sentinel_image_full: "{{ valkey_sentinel_image }}:{{ valkey_tag }}" +valkey_dimensions: "{{ default_container_dimensions }}" +valkey_sentinel_dimensions: "{{ default_container_dimensions }}" + +valkey_enable_healthchecks: "{{ enable_container_healthchecks }}" +valkey_healthcheck_interval: "{{ default_container_healthcheck_interval }}" +valkey_healthcheck_retries: "{{ default_container_healthcheck_retries }}" +valkey_healthcheck_start_period: "{{ default_container_healthcheck_start_period }}" +valkey_healthcheck_test: ["CMD-SHELL", "healthcheck_listen valkey-server {{ valkey_server_port }}"] +valkey_healthcheck_timeout: "{{ default_container_healthcheck_timeout }}" +valkey_healthcheck: + interval: "{{ valkey_healthcheck_interval }}" + retries: "{{ valkey_healthcheck_retries }}" + start_period: "{{ valkey_healthcheck_start_period }}" + test: "{% if valkey_enable_healthchecks | bool %}{{ valkey_healthcheck_test }}{% else %}NONE{% endif %}" + timeout: "{{ valkey_healthcheck_timeout }}" + +valkey_sentinel_enable_healthchecks: "{{ enable_container_healthchecks }}" +valkey_sentinel_healthcheck_interval: "{{ default_container_healthcheck_interval }}" +valkey_sentinel_healthcheck_retries: "{{ default_container_healthcheck_retries }}" +valkey_sentinel_healthcheck_start_period: "{{ default_container_healthcheck_start_period }}" +valkey_sentinel_healthcheck_test: ["CMD-SHELL", "healthcheck_listen valkey-sentinel {{ valkey_sentinel_port }}"] +valkey_sentinel_healthcheck_timeout: "{{ default_container_healthcheck_timeout }}" +valkey_sentinel_healthcheck: + interval: "{{ valkey_sentinel_healthcheck_interval }}" + retries: "{{ valkey_sentinel_healthcheck_retries }}" + start_period: "{{ valkey_sentinel_healthcheck_start_period }}" + test: "{% if valkey_sentinel_enable_healthchecks | bool %}{{ valkey_sentinel_healthcheck_test }}{% else %}NONE{% endif %}" + timeout: "{{ valkey_sentinel_healthcheck_timeout }}" + +valkey_default_volumes: + - "{{ node_config_directory }}/valkey-server/:{{ container_config_directory }}/:ro" + - "/etc/localtime:/etc/localtime:ro" + - "{{ '/etc/timezone:/etc/timezone:ro' if ansible_facts.os_family == 'Debian' else '' }}" + - "{{ project_name }}:/var/lib/valkey/" + - "kolla_logs:/var/log/kolla/" +valkey_sentinel_default_volumes: + - "{{ node_config_directory }}/valkey-sentinel/:{{ container_config_directory }}/:ro" + - "/etc/localtime:/etc/localtime:ro" + - "{{ '/etc/timezone:/etc/timezone:ro' if ansible_facts.os_family == 'Debian' else '' }}" + - "kolla_logs:/var/log/kolla/" + +valkey_extra_volumes: "{{ default_extra_volumes }}" +valkey_sentinel_extra_volumes: "{{ default_extra_volumes }}" + +valkey_conf_path: "/etc/valkey/valkey.conf" +valkey_generated_conf_path: "/etc/valkey/valkey-regenerated-by-config-rewrite.conf" diff --git a/ansible/roles/redis/handlers/main.yml b/ansible/roles/valkey/handlers/main.yml index d1bd61477..d0c0cfcd6 100644 --- a/ansible/roles/redis/handlers/main.yml +++ b/ansible/roles/valkey/handlers/main.yml @@ -1,8 +1,8 @@ --- -- name: Restart redis container +- name: Restart valkey-server container vars: - service_name: "redis" - service: "{{ redis_services[service_name] }}" + service_name: "valkey-server" + service: "{{ valkey_services[service_name] }}" become: true kolla_container: action: "recreate_or_restart_container" @@ -13,10 +13,10 @@ dimensions: "{{ service.dimensions }}" healthcheck: "{{ service.healthcheck | default(omit) }}" -- name: Restart redis-sentinel container +- name: Restart valkey-sentinel container vars: - service_name: "redis-sentinel" - service: "{{ redis_services[service_name] }}" + service_name: "valkey-sentinel" + service: "{{ valkey_services[service_name] }}" become: true kolla_container: action: "recreate_or_restart_container" diff --git a/ansible/roles/redis/tasks/check-containers.yml b/ansible/roles/valkey/tasks/check-containers.yml index b7e2f7c29..b7e2f7c29 100644 --- a/ansible/roles/redis/tasks/check-containers.yml +++ b/ansible/roles/valkey/tasks/check-containers.yml diff --git a/ansible/roles/valkey/tasks/check.yml b/ansible/roles/valkey/tasks/check.yml new file mode 100644 index 000000000..d7531527a --- /dev/null +++ b/ansible/roles/valkey/tasks/check.yml @@ -0,0 +1,13 @@ +--- +- name: Checking valkey containers + import_role: + role: service-check + +- name: Valkey ping pong check + become: true + shell: >- + {{ kolla_container_engine }} exec valkey_server valkey-cli -h {{ api_interface_address }} + -a {{ valkey_master_password }} ping + register: valkey_check + changed_when: "'PONG' in valkey_check.stdout" + failed_when: "'PONG' not in valkey_check.stdout" diff --git a/ansible/roles/redis/tasks/config.yml b/ansible/roles/valkey/tasks/config.yml index 9f133933d..c04025673 100644 --- a/ansible/roles/redis/tasks/config.yml +++ b/ansible/roles/valkey/tasks/config.yml @@ -7,7 +7,7 @@ group: "{{ config_owner_group }}" mode: "0770" become: true - with_dict: "{{ redis_services | select_services_enabled_and_mapped_to_host }}" + with_dict: "{{ valkey_services | select_services_enabled_and_mapped_to_host }}" - name: Copying over default config.json files template: @@ -15,12 +15,12 @@ dest: "{{ node_config_directory }}/{{ item.key }}/config.json" mode: "0660" become: true - with_dict: "{{ redis_services | select_services_enabled_and_mapped_to_host }}" + with_dict: "{{ valkey_services | select_services_enabled_and_mapped_to_host }}" -- name: Copying over redis config files +- name: Copying over valkey config files template: src: "{{ item.key }}.conf.j2" - dest: "{{ node_config_directory }}/{{ item.key }}/redis.conf" + dest: "{{ node_config_directory }}/{{ item.key }}/valkey.conf" mode: "0660" become: true - with_dict: "{{ redis_services | select_services_enabled_and_mapped_to_host }}" + with_dict: "{{ valkey_services | select_services_enabled_and_mapped_to_host }}" diff --git a/ansible/roles/redis/tasks/config_validate.yml b/ansible/roles/valkey/tasks/config_validate.yml index ed97d539c..ed97d539c 100644 --- a/ansible/roles/redis/tasks/config_validate.yml +++ b/ansible/roles/valkey/tasks/config_validate.yml diff --git a/ansible/roles/redis/tasks/deploy-containers.yml b/ansible/roles/valkey/tasks/deploy-containers.yml index eb24ab5c7..eb24ab5c7 100644 --- a/ansible/roles/redis/tasks/deploy-containers.yml +++ b/ansible/roles/valkey/tasks/deploy-containers.yml diff --git a/ansible/roles/redis/tasks/deploy.yml b/ansible/roles/valkey/tasks/deploy.yml index 49edff81e..49edff81e 100644 --- a/ansible/roles/redis/tasks/deploy.yml +++ b/ansible/roles/valkey/tasks/deploy.yml diff --git a/ansible/roles/redis/tasks/main.yml b/ansible/roles/valkey/tasks/main.yml index bc5d1e625..bc5d1e625 100644 --- a/ansible/roles/redis/tasks/main.yml +++ b/ansible/roles/valkey/tasks/main.yml diff --git a/ansible/roles/valkey/tasks/precheck.yml b/ansible/roles/valkey/tasks/precheck.yml new file mode 100644 index 000000000..689fcfb6f --- /dev/null +++ b/ansible/roles/valkey/tasks/precheck.yml @@ -0,0 +1,45 @@ +--- +# TODO(gkoper) Remove redis checks after G/2026.1 release +- name: Check if Redis is running + become: true + kolla_container_facts: + action: get_containers + container_engine: "{{ kolla_container_engine }}" + name: + - redis + check_mode: false + register: redis_container_facts + +- name: Set migration flag if Redis is present + set_fact: + valkey_is_migrating: "{{ redis_container_facts.containers['redis'] is defined }}" + +- import_role: + name: service-precheck + vars: + service_precheck_services: "{{ valkey_services }}" + service_name: "{{ project_name }}" + +- name: Get container facts + become: true + kolla_container_facts: + action: get_containers + container_engine: "{{ kolla_container_engine }}" + name: + - valkey_server + check_mode: false + register: container_facts + +- name: Checking free port for Valkey + vars: + service: "{{ valkey_services['valkey-server'] }}" + wait_for: + host: "{{ api_interface_address }}" + port: "{{ valkey_server_port }}" + connect_timeout: 1 + timeout: 1 + state: stopped + when: + - container_facts.containers['valkey_server'] is not defined + - service | service_enabled_and_mapped_to_host + - not (valkey_is_migrating | default(false) | bool) diff --git a/ansible/roles/redis/tasks/pull.yml b/ansible/roles/valkey/tasks/pull.yml index 53f9c5fda..53f9c5fda 100644 --- a/ansible/roles/redis/tasks/pull.yml +++ b/ansible/roles/valkey/tasks/pull.yml diff --git a/ansible/roles/redis/tasks/reconfigure.yml b/ansible/roles/valkey/tasks/reconfigure.yml index 5b10a7e11..5b10a7e11 100644 --- a/ansible/roles/redis/tasks/reconfigure.yml +++ b/ansible/roles/valkey/tasks/reconfigure.yml diff --git a/ansible/roles/redis/tasks/stop.yml b/ansible/roles/valkey/tasks/stop.yml index 452b62ffb..a175892b7 100644 --- a/ansible/roles/redis/tasks/stop.yml +++ b/ansible/roles/valkey/tasks/stop.yml @@ -2,5 +2,5 @@ - import_role: name: service-stop vars: - project_services: "{{ redis_services }}" + project_services: "{{ valkey_services }}" service_name: "{{ project_name }}" diff --git a/ansible/roles/valkey/tasks/upgrade.yml b/ansible/roles/valkey/tasks/upgrade.yml new file mode 100644 index 000000000..0cae1ce26 --- /dev/null +++ b/ansible/roles/valkey/tasks/upgrade.yml @@ -0,0 +1,134 @@ +--- +# TODO(bbezak): Remove in G/2026.1 release as Redis migration is no longer required +- name: Check if Redis is running + become: true + kolla_container_facts: + action: get_containers + container_engine: "{{ kolla_container_engine }}" + name: + - redis + check_mode: false + register: redis_container_facts + +- name: Set migration flag if Redis is present + set_fact: + _valkey_migration: "{{ redis_container_facts.containers['redis'] is defined }}" + +- name: Perform Redis to Valkey migration steps + block: + + - name: Set temporary Valkey migration vars + set_fact: + valkey_server_port: "6380" + valkey_sentinel_port: "26380" + valkey_sentinel_monitor_name: "kolla-temp" + + - name: Set valkey master host to valkey[0] + set_fact: + valkey_master_host: "{{ groups['valkey'][0] }}" + redis_slave_hosts: "{{ groups['redis'][1:] }}" + run_once: true + + - name: Start Valkey on temporary ports with temp sentinel monitor name + import_tasks: deploy.yml + + - name: Wait for Valkey replication sync + become: true + delegate_to: "{{ valkey_master_host }}" + run_once: true + shell: >- + {{ kolla_container_engine }} exec valkey_server + valkey-cli -h {{ api_interface_address }} -p {{ valkey_server_port }} info replication + register: valkey_replication + until: "'master_link_status:up' in valkey_replication.stdout" + retries: 30 + delay: 2 + + - name: Set replica-priority=10 on valkey[0] to ensure it becomes master + become: true + delegate_to: "{{ valkey_master_host }}" + run_once: true + command: >- + {{ kolla_container_engine }} exec valkey_server valkey-cli + -h {{ api_interface_address }} -p {{ valkey_server_port }} + CONFIG SET replica-priority 10 + + - name: Set replica-priority=0 on other valkey nodes to prevent promotion + become: true + command: >- + {{ kolla_container_engine }} exec valkey_server valkey-cli + -h {{ api_interface_address }} -p {{ valkey_server_port }} CONFIG SET replica-priority 0 + when: inventory_hostname != valkey_master_host + + - name: Stop redis slaves (so they don't get promoted during failover) + become: true + kolla_container: + name: redis + action: stop_container + when: inventory_hostname in redis_slave_hosts + + - name: Trigger Sentinel failover (using one of redis-sentinels) + become: true + delegate_to: "{{ valkey_master_host }}" + run_once: true + command: >- + {{ kolla_container_engine }} exec redis_sentinel redis-cli + -h {{ api_interface_address }} + -p {{ redis_sentinel_port }} + SENTINEL failover kolla + + - name: Wait until Valkey becomes master + become: true + delegate_to: "{{ valkey_master_host }}" + run_once: true + shell: >- + {{ kolla_container_engine }} exec valkey_server + valkey-cli -h {{ api_interface_address }} -p {{ valkey_server_port }} info replication + register: valkey_role + until: "'role:master' in valkey_role.stdout" + retries: 30 + delay: 2 + + - name: Stop all Redis containers + become: true + kolla_container: + name: redis + action: stop_and_remove_container + when: inventory_hostname in groups['redis'] + + - name: Stop all Sentinel containers + become: true + kolla_container: + name: redis_sentinel + action: stop_and_remove_container + when: inventory_hostname in groups['redis'] + + - name: Remove Redis data volume + become: true + kolla_container: + action: remove_volume + name: redis + when: inventory_hostname in groups['redis'] + + when: redis_container_facts.containers['redis'] is defined + +# These tasks run always, regardless of Redis presence + +- name: Reset Valkey port to default (6379) after migration + set_fact: + valkey_server_port: "6379" + valkey_sentinel_port: "26379" + valkey_sentinel_monitor_name: "kolla" + _valkey_migration: false + + +- name: Reconfigure/Redeploy Valkey on default ports + import_tasks: reconfigure.yml + +- name: Verify Valkey responds on port 6379 + import_tasks: check.yml + +- import_tasks: check-containers.yml + +- name: Flush handlers + meta: flush_handlers diff --git a/ansible/roles/valkey/templates/valkey-sentinel.conf.j2 b/ansible/roles/valkey/templates/valkey-sentinel.conf.j2 new file mode 100644 index 000000000..ee5e4ff2b --- /dev/null +++ b/ansible/roles/valkey/templates/valkey-sentinel.conf.j2 @@ -0,0 +1,12 @@ +{% set valkey_master_address = 'api' | kolla_address(groups['valkey'][0]) %} +daemonize no +pidfile "/var/run/valkey/valkey-sentinel.pid" +logfile "/var/log/kolla/valkey/valkey-sentinel.log" +bind {{ api_interface_address }} +port {{ valkey_sentinel_port }} +sentinel myid {{ inventory_hostname | hash('sha1') }} +sentinel monitor {{ valkey_sentinel_monitor_name }} {{ valkey_master_address }} {{ valkey_server_port }} {{ valkey_sentinel_quorum }} +sentinel auth-pass {{ valkey_sentinel_monitor_name }} {{ valkey_master_password }} +sentinel down-after-milliseconds {{ valkey_sentinel_monitor_name }} 5000 +sentinel failover-timeout {{ valkey_sentinel_monitor_name }} 60000 +sentinel parallel-syncs {{ valkey_sentinel_monitor_name }} 1 diff --git a/ansible/roles/valkey/templates/valkey-sentinel.json.j2 b/ansible/roles/valkey/templates/valkey-sentinel.json.j2 new file mode 100644 index 000000000..7dabf9599 --- /dev/null +++ b/ansible/roles/valkey/templates/valkey-sentinel.json.j2 @@ -0,0 +1,22 @@ +{ + "command": "valkey-sentinel {{ valkey_generated_conf_path }}", + "config_files": [ + { + "source": "{{ container_config_directory }}/valkey.conf", + "dest": "{{ valkey_conf_path }}", + "owner": "valkey", + "perm": "0600" + } + ], + "permissions": [ + { + "path": "/var/log/kolla/valkey", + "owner": "valkey:valkey", + "recurse": true + }, + { + "path": "/etc/valkey", + "owner": "valkey:valkey" + } + ] +} diff --git a/ansible/roles/valkey/templates/valkey-server.conf.j2 b/ansible/roles/valkey/templates/valkey-server.conf.j2 new file mode 100644 index 000000000..b1b94af0d --- /dev/null +++ b/ansible/roles/valkey/templates/valkey-server.conf.j2 @@ -0,0 +1,29 @@ +appendonly yes +bind {{ api_interface_address }} +dir /var/lib/valkey +logfile /var/log/kolla/valkey/valkey.log +pidfile /var/run/valkey/valkey-server.pid +port {{ valkey_server_port }} + +{# TODO(mnasiadka): Remove after Gazpacho/2026.1 #} +{% if _valkey_migration | default(false) | bool %} +protected-mode no +{% if inventory_hostname == groups['valkey'][0] %} +{# Migration mode: valkey[0] replicates from Redis #} +replicaof {{ 'api' | kolla_address(groups['redis'][0]) }} {{ redis_port }} +masterauth {{ redis_master_password }} +{% elif not inventory_hostname == groups['valkey'][0] %} +{# Secondary valkey nodes replicate from valkey[0] #} +replicaof {{ 'api' | kolla_address(groups['valkey'][0]) }} {{ valkey_server_port }} +masterauth {{ valkey_master_password }} +{% endif %} +{% else %} +{# Normal mode: valkey[0] is master #} +{# NOTE: Keep this part after removing the migration block above #} +{% if not inventory_hostname == groups['valkey'][0] %} +{# Secondary valkey nodes replicate from valkey[0] #} +replicaof {{ 'api' | kolla_address(groups['valkey'][0]) }} {{ valkey_server_port }} +{% endif %} +requirepass {{ valkey_master_password }} +masterauth {{ valkey_master_password }} +{% endif %} diff --git a/ansible/roles/valkey/templates/valkey-server.json.j2 b/ansible/roles/valkey/templates/valkey-server.json.j2 new file mode 100644 index 000000000..3a9933ab1 --- /dev/null +++ b/ansible/roles/valkey/templates/valkey-server.json.j2 @@ -0,0 +1,18 @@ +{ + "command": "valkey-server {{ valkey_conf_path }}", + "config_files": [ + { + "source": "{{ container_config_directory }}/valkey.conf", + "dest": "{{ valkey_conf_path }}", + "owner": "valkey", + "perm": "0600" + } + ], + "permissions": [ + { + "path": "/var/log/kolla/valkey", + "owner": "valkey:valkey", + "recurse": true + } + ] +} diff --git a/ansible/roles/valkey/vars/main.yml b/ansible/roles/valkey/vars/main.yml new file mode 100644 index 000000000..209d4d45f --- /dev/null +++ b/ansible/roles/valkey/vars/main.yml @@ -0,0 +1,2 @@ +--- +project_name: "valkey" diff --git a/ansible/site.yml b/ansible/site.yml index 33855f1d6..ae5f281cb 100644 --- a/ansible/site.yml +++ b/ansible/site.yml @@ -63,7 +63,7 @@ - enable_placement_{{ enable_placement | bool }} - enable_prometheus_{{ enable_prometheus | bool }} - enable_rabbitmq_{{ enable_rabbitmq | bool }} - - enable_redis_{{ enable_redis | bool }} + - enable_valkey_{{ enable_valkey | bool }} - enable_skyline_{{ enable_skyline | bool }} - enable_tacker_{{ enable_tacker | bool }} - enable_telegraf_{{ enable_telegraf | bool }} @@ -415,19 +415,19 @@ - { role: telegraf, tags: telegraf } -- name: Apply role redis +- name: Apply role valkey gather_facts: false hosts: - - redis - - '&enable_redis_True' + - valkey + - '&enable_valkey_True' serial: '{{ kolla_serial|default("0") }}' max_fail_percentage: >- - {{ redis_max_fail_percentage | + {{ valkey_max_fail_percentage | default(kolla_max_fail_percentage) | default(100) }} roles: - - { role: redis, - tags: redis } + - { role: valkey, + tags: valkey } # MariaDB deployment is more complicated than other services, so is covered in # its own playbook. |
