diff options
98 files changed, 962 insertions, 420 deletions
diff --git a/.ansible-lint b/.ansible-lint index 48663ad43..2f500a5c1 100644 --- a/.ansible-lint +++ b/.ansible-lint @@ -1,4 +1,9 @@ --- +exclude_paths: + - etc + - roles + - tests + - zuul.d strict: true use_default_rules: true skip_list: diff --git a/README.rst b/README.rst index 4ee2c7dd0..78058b5d2 100644 --- a/README.rst +++ b/README.rst @@ -93,7 +93,7 @@ Kolla Ansible deploys containers for the following infrastructure components: - `Open vSwitch <https://www.openvswitch.org/>`__ for use with Neutron. - `RabbitMQ <https://www.rabbitmq.com/>`__ as a messaging backend for communication between services. -- `Redis <https://redis.io/>`__ an in-memory data structure store. +- `Valkey <https://valkey.io/>`__ an in-memory data structure store. Directories =========== 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/keystone/defaults/main.yml b/ansible/roles/keystone/defaults/main.yml index 3d236dfef..0b98275f8 100644 --- a/ansible/roles/keystone/defaults/main.yml +++ b/ansible/roles/keystone/defaults/main.yml @@ -31,32 +31,40 @@ keystone_services: backend_http_extra: - "balance {{ 'source' if enable_keystone_federation | bool else 'roundrobin' }}" - "option httpchk" - keystone-ssh: - container_name: "keystone_ssh" + keystone-fernet: + container_name: "keystone_fernet" group: "keystone" enabled: true - image: "{{ keystone_ssh_image_full }}" + image: "{{ keystone_fernet_image_full }}" volumes: - - "{{ node_config_directory }}/keystone-ssh/:{{ container_config_directory }}/:ro" + - "{{ node_config_directory }}/keystone-fernet/:{{ 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/" - "keystone_fernet_tokens:/etc/keystone/fernet-keys" - dimensions: "{{ keystone_ssh_dimensions }}" - healthcheck: "{{ keystone_ssh_healthcheck }}" - keystone-fernet: - container_name: "keystone_fernet" + dimensions: "{{ keystone_fernet_dimensions }}" + healthcheck: "{{ keystone_fernet_healthcheck }}" + keystone-httpd: + container_name: "keystone_httpd" + group: "keystone" + enabled: "{{ enable_keystone_federation | bool }}" + image: "{{ keystone_httpd_image_full }}" + volumes: "{{ keystone_httpd_default_volumes + keystone_httpd_extra_volumes }}" + dimensions: "{{ keystone_httpd_dimensions }}" + healthcheck: "{{ keystone_httpd_healthcheck }}" + keystone-ssh: + container_name: "keystone_ssh" group: "keystone" enabled: true - image: "{{ keystone_fernet_image_full }}" + image: "{{ keystone_ssh_image_full }}" volumes: - - "{{ node_config_directory }}/keystone-fernet/:{{ container_config_directory }}/:ro" + - "{{ node_config_directory }}/keystone-ssh/:{{ 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/" - "keystone_fernet_tokens:/etc/keystone/fernet-keys" - dimensions: "{{ keystone_fernet_dimensions }}" - healthcheck: "{{ keystone_fernet_healthcheck }}" + dimensions: "{{ keystone_ssh_dimensions }}" + healthcheck: "{{ keystone_ssh_healthcheck }}" #################### # Config Validate @@ -105,6 +113,10 @@ keystone_image: "{{ docker_image_url }}keystone" keystone_service_tag: "{{ keystone_tag }}" keystone_image_full: "{{ keystone_image }}:{{ keystone_service_tag }}" +keystone_httpd_image: "{{ docker_image_url }}httpd" +keystone_httpd_tag: "{{ keystone_tag }}" +keystone_httpd_image_full: "{{ keystone_httpd_image }}:{{ keystone_httpd_tag }}" + keystone_fernet_image: "{{ docker_image_url }}keystone-fernet" keystone_fernet_tag: "{{ keystone_tag }}" keystone_fernet_image_full: "{{ keystone_fernet_image }}:{{ keystone_fernet_tag }}" @@ -114,6 +126,7 @@ keystone_ssh_tag: "{{ keystone_tag }}" keystone_ssh_image_full: "{{ keystone_ssh_image }}:{{ keystone_ssh_tag }}" keystone_dimensions: "{{ default_container_dimensions }}" +keystone_httpd_dimensions: "{{ default_container_dimensions }}" keystone_fernet_dimensions: "{{ default_container_dimensions }}" keystone_ssh_dimensions: "{{ default_container_dimensions }}" @@ -130,18 +143,18 @@ keystone_healthcheck: test: "{% if keystone_enable_healthchecks | bool %}{{ keystone_healthcheck_test }}{% else %}NONE{% endif %}" timeout: "{{ keystone_healthcheck_timeout }}" -keystone_ssh_enable_healthchecks: "{{ enable_container_healthchecks }}" -keystone_ssh_healthcheck_interval: "{{ default_container_healthcheck_interval }}" -keystone_ssh_healthcheck_retries: "{{ default_container_healthcheck_retries }}" -keystone_ssh_healthcheck_start_period: "{{ default_container_healthcheck_start_period }}" -keystone_ssh_healthcheck_test: ["CMD-SHELL", "healthcheck_listen sshd {{ keystone_ssh_port }}"] -keystone_ssh_healthcheck_timeout: "{{ default_container_healthcheck_timeout }}" -keystone_ssh_healthcheck: - interval: "{{ keystone_ssh_healthcheck_interval }}" - retries: "{{ keystone_ssh_healthcheck_retries }}" - start_period: "{{ keystone_ssh_healthcheck_start_period }}" - test: "{% if keystone_ssh_enable_healthchecks | bool %}{{ keystone_ssh_healthcheck_test }}{% else %}NONE{% endif %}" - timeout: "{{ keystone_ssh_healthcheck_timeout }}" +keystone_httpd_enable_healthchecks: "{{ enable_container_healthchecks }}" +keystone_httpd_healthcheck_interval: "{{ default_container_healthcheck_interval }}" +keystone_httpd_healthcheck_retries: "{{ default_container_healthcheck_retries }}" +keystone_httpd_healthcheck_start_period: "{{ default_container_healthcheck_start_period }}" +keystone_httpd_healthcheck_test: ["CMD-SHELL", "healthcheck_curl {{ 'https' if keystone_enable_tls_backend | bool else 'http' }}://{{ api_interface_address | put_address_in_context('url') }}:{{ keystone_public_listen_port }}"] +keystone_httpd_healthcheck_timeout: "{{ default_container_healthcheck_timeout }}" +keystone_httpd_healthcheck: + interval: "{{ keystone_httpd_healthcheck_interval }}" + retries: "{{ keystone_httpd_healthcheck_retries }}" + start_period: "{{ keystone_httpd_healthcheck_start_period }}" + test: "{% if keystone_httpd_enable_healthchecks | bool %}{{ keystone_httpd_healthcheck_test }}{% else %}NONE{% endif %}" + timeout: "{{ keystone_httpd_healthcheck_timeout }}" keystone_fernet_enable_healthchecks: "{{ enable_container_healthchecks }}" keystone_fernet_healthcheck_interval: "{{ default_container_healthcheck_interval }}" @@ -156,6 +169,19 @@ keystone_fernet_healthcheck: test: "{% if keystone_fernet_enable_healthchecks | bool %}{{ keystone_fernet_healthcheck_test }}{% else %}NONE{% endif %}" timeout: "{{ keystone_fernet_healthcheck_timeout }}" +keystone_ssh_enable_healthchecks: "{{ enable_container_healthchecks }}" +keystone_ssh_healthcheck_interval: "{{ default_container_healthcheck_interval }}" +keystone_ssh_healthcheck_retries: "{{ default_container_healthcheck_retries }}" +keystone_ssh_healthcheck_start_period: "{{ default_container_healthcheck_start_period }}" +keystone_ssh_healthcheck_test: ["CMD-SHELL", "healthcheck_listen sshd {{ keystone_ssh_port }}"] +keystone_ssh_healthcheck_timeout: "{{ default_container_healthcheck_timeout }}" +keystone_ssh_healthcheck: + interval: "{{ keystone_ssh_healthcheck_interval }}" + retries: "{{ keystone_ssh_healthcheck_retries }}" + start_period: "{{ keystone_ssh_healthcheck_start_period }}" + test: "{% if keystone_ssh_enable_healthchecks | bool %}{{ keystone_ssh_healthcheck_test }}{% else %}NONE{% endif %}" + timeout: "{{ keystone_ssh_healthcheck_timeout }}" + keystone_default_volumes: - "{{ node_config_directory }}/keystone/:{{ container_config_directory }}/:ro" - "/etc/localtime:/etc/localtime:ro" @@ -165,7 +191,14 @@ keystone_default_volumes: - "{{ '/dev/shm:/dev/shm' }}" - "keystone_fernet_tokens:/etc/keystone/fernet-keys" +keystone_httpd_default_volumes: + - "{{ node_config_directory }}/keystone-httpd/:{{ 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/" + keystone_extra_volumes: "{{ default_extra_volumes }}" +keystone_httpd_extra_volumes: "{{ keystone_extra_volumes }}" #################### # OpenStack @@ -266,3 +299,4 @@ keystone_copy_certs: "{{ kolla_copy_ca_into_containers | bool or keystone_enable # WSGI ############ keystone_wsgi_provider: "uwsgi" +keystone_wsgi_socket_port: "5001" diff --git a/ansible/roles/keystone/handlers/main.yml b/ansible/roles/keystone/handlers/main.yml index c14987791..8d5f1fd04 100644 --- a/ansible/roles/keystone/handlers/main.yml +++ b/ansible/roles/keystone/handlers/main.yml @@ -68,6 +68,20 @@ dimensions: "{{ service.dimensions }}" healthcheck: "{{ service.healthcheck | default(omit) }}" +- name: Restart keystone-httpd container + vars: + service_name: "keystone-httpd" + service: "{{ keystone_services[service_name] }}" + become: true + kolla_container: + action: "recreate_or_restart_container" + common_options: "{{ docker_common_options }}" + name: "{{ service.container_name }}" + image: "{{ service.image }}" + volumes: "{{ service.volumes | reject('equalto', '') | list }}" + dimensions: "{{ service.dimensions }}" + healthcheck: "{{ service.healthcheck | default(omit) }}" + - name: Finish keystone database upgrade vars: service_name: "keystone" diff --git a/ansible/roles/keystone/tasks/config.yml b/ansible/roles/keystone/tasks/config.yml index df6617dd4..3ad247281 100644 --- a/ansible/roles/keystone/tasks/config.yml +++ b/ansible/roles/keystone/tasks/config.yml @@ -147,9 +147,14 @@ project_services: "{{ keystone_services }}" service: "{{ keystone_services['keystone'] }}" service_name: "keystone" + service_uwsgi_config_host: >- + {{ '127.0.0.1' if enable_keystone_federation | bool + else api_interface_address | put_address_in_context('url') }} service_uwsgi_config_http_port: "{{ keystone_listen_port }}" service_uwsgi_config_module: "{{ service.wsgi }}" - service_uwsgi_config_tls_backend: "{{ keystone_enable_tls_backend | bool }}" + service_uwsgi_config_socket_port: "{{ keystone_wsgi_socket_port if enable_keystone_federation | bool else '' }}" + service_uwsgi_config_tls_backend: >- + {{ keystone_enable_tls_backend | bool and (not enable_keystone_federation | bool) }} service_uwsgi_config_tls_cert: "/etc/keystone/certs/keystone-cert.pem" service_uwsgi_config_tls_key: "/etc/keystone/certs/keystone-key.pem" service_uwsgi_config_uid: "keystone" @@ -157,6 +162,22 @@ - service | service_enabled_and_mapped_to_host - keystone_wsgi_provider == "uwsgi" +- name: Copying over httpd-keystone.conf + vars: + service: "{{ keystone_services['keystone-httpd'] }}" + template: + src: "{{ item }}" + dest: "{{ node_config_directory }}/keystone-httpd/httpd-keystone.conf" + mode: "0660" + become: true + when: + - service | service_enabled_and_mapped_to_host + - keystone_wsgi_provider == "uwsgi" + with_first_found: + - "{{ node_custom_config }}/keystone/{{ inventory_hostname }}/httpd-keystone.conf" + - "{{ node_custom_config }}/keystone/httpd-keystone.conf" + - "httpd-keystone.conf.j2" + - name: Checking whether keystone-paste.ini file exists vars: service: "{{ keystone_services['keystone'] }}" diff --git a/ansible/roles/keystone/templates/httpd-keystone.conf.j2 b/ansible/roles/keystone/templates/httpd-keystone.conf.j2 new file mode 100644 index 000000000..435fe7cdd --- /dev/null +++ b/ansible/roles/keystone/templates/httpd-keystone.conf.j2 @@ -0,0 +1,113 @@ +{% set keystone_log_dir = '/var/log/kolla/keystone' %} +{% set binary_path = '/var/lib/kolla/venv/bin' %} +{% if keystone_enable_tls_backend | bool %} +{% if kolla_base_distro in ['centos', 'rocky'] %} +LoadModule ssl_module /usr/lib64/httpd/modules/mod_ssl.so +{% else %} +LoadModule ssl_module /usr/lib/apache2/modules/mod_ssl.so +{% endif %} +{% endif %} + +{% if kolla_base_distro in ['centos', 'rocky'] %} +LoadModule proxy_module /usr/lib64/httpd/modules/mod_proxy.so +LoadModule proxy_uwsgi_module /usr/lib64/httpd/modules/mod_proxy_uwsgi.so +{% else %} +LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so +LoadModule proxy_uwsgi_module /usr/lib/apache2/modules/mod_proxy_uwsgi.so +{% endif %} + +Listen {{ api_interface_address | put_address_in_context('url') }}:{{ keystone_public_listen_port }} + +ServerSignature Off +ServerTokens Prod +TraceEnable off +TimeOut {{ kolla_httpd_timeout }} +KeepAliveTimeout {{ kolla_httpd_keep_alive }} + +ErrorLog "{{ keystone_log_dir }}/apache-error.log" +<IfModule log_config_module> + CustomLog "{{ keystone_log_dir }}/apache-access.log" common +</IfModule> + +{% if keystone_logging_debug | bool %} +LogLevel info +{% endif %} + +<VirtualHost *:{{ keystone_public_listen_port }}> +{# NOTE(darmach): with external tls enabled OIDC redirection fails, as TLS terminated on haproxy keystone is not aware that redirection should use https. -#} +{# With missing ServerName Keystone Apache uses fqdn, with http. Adding ServerName pointing to keystone_public_url corrects this. -#} +{% if kolla_enable_tls_external | bool %} + ServerName {{ keystone_public_url }} +{% endif %} + ErrorLogFormat "%{cu}t %M" + ErrorLog "{{ keystone_log_dir }}/keystone-apache-public-error.log" + LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b %D \"%{Referer}i\" \"%{User-Agent}i\"" logformat + CustomLog "{{ keystone_log_dir }}/keystone-apache-public-access.log" logformat + ProxyPass / "uwsgi://localhost:{{ keystone_wsgi_socket_port }}/" + +{% if keystone_enable_tls_backend | bool %} + SSLEngine on + SSLCertificateFile /etc/keystone/certs/keystone-cert.pem + SSLCertificateKeyFile /etc/keystone/certs/keystone-key.pem +{% endif -%} + +{% if keystone_enable_federation_openid | bool %} +{% if keystone_federation_oidc_forwarded_headers | length > 0 %} + OIDCXForwardedHeaders "{{ keystone_federation_oidc_forwarded_headers }}" +{% endif %} + OIDCClaimPrefix "OIDC-" + OIDCClaimDelimiter "{{ keystone_federation_oidc_claim_delimiter }}" + OIDCResponseType "{{ keystone_federation_oidc_response_type }}" + OIDCScope "{{ keystone_federation_oidc_scopes }}" + OIDCMetadataDir {{ keystone_container_federation_oidc_metadata_folder }} +{% if keystone_federation_oidc_jwks_uri | length > 0 %} + OIDCOAuthVerifyJwksUri {{ keystone_federation_oidc_jwks_uri }} +{% endif %} +{% if keystone_federation_openid_certificate_key_ids | length > 0 %} + OIDCOAuthVerifyCertFiles {{ keystone_federation_openid_certificate_key_ids | join(" ") }} +{% endif %} + OIDCCryptoPassphrase {{ keystone_federation_openid_crypto_password }} + OIDCRedirectURI {{ keystone_public_url }}/redirect_uri +{% if enable_memcached | bool and keystone_oidc_enable_memcached | bool %} + OIDCCacheType memcache + OIDCMemCacheServers "{% for host in groups['memcached'] %}{{ 'api' | kolla_address(host) | put_address_in_context('memcache') }}:{{ memcached_port }}{% if not loop.last %} {% endif %}{% endfor %}" +{% endif %} +{% for key, value in keystone_federation_oidc_additional_options.items() %} + {{ key }} {{ value }} +{% endfor %} + + <Location ~ "/redirect_uri"> + Require valid-user + AuthType openid-connect + </Location> + + {# WebSSO authentication endpoint -#} + <Location /v3/auth/OS-FEDERATION/websso/openid> + Require valid-user + AuthType openid-connect + </Location> + +{% for idp in keystone_identity_providers %} +{% if idp.protocol == 'openid' %} + <LocationMatch /v3/auth/OS-FEDERATION/identity_providers/{{ idp.name }}/protocols/{{ idp.protocol }}/websso> + OIDCDiscoverURL {{ keystone_public_url }}/redirect_uri?iss={{ idp.identifier | urlencode }} + Require valid-user + AuthType openid-connect + </LocationMatch> +{% endif %} +{% endfor %} + + {# CLI / API authentication endpoint -#} +{% for idp in keystone_identity_providers %} +{% if idp.protocol == 'openid' -%} + <LocationMatch /v3/OS-FEDERATION/identity_providers/{{ idp.name }}/protocols/{{ idp.protocol }}/auth> + Require valid-user + {# Note(jasonanderson): `auth-openidc` is a special auth type that can -#} + {# additionally handle verifying bearer tokens -#} + AuthType auth-openidc + </LocationMatch> +{% endif %} +{% endfor %} +{% endif %} +</VirtualHost> + diff --git a/ansible/roles/keystone/templates/keystone-httpd.json.j2 b/ansible/roles/keystone/templates/keystone-httpd.json.j2 new file mode 100644 index 000000000..b82376afc --- /dev/null +++ b/ansible/roles/keystone/templates/keystone-httpd.json.j2 @@ -0,0 +1,63 @@ +{% set apache_cmd = '/usr/sbin/apache2' if kolla_base_distro in ['ubuntu', 'debian'] else '/usr/sbin/httpd' %} +{% set apache_dir = 'apache2/conf-enabled' if kolla_base_distro in ['ubuntu', 'debian'] else 'httpd/conf.d' %} +{% set apache_user = 'www-data' if kolla_base_distro in ['ubuntu', 'debian'] else 'apache' %} + +{ + "command": "{{ apache_cmd }} -DFOREGROUND", + "config_files": [ + { + "source": "{{ container_config_directory }}/httpd-keystone.conf", + "dest": "/etc/{{ apache_dir }}/httpd-keystone.conf", + "owner": "root", + "perm": "0600" + }{% if keystone_enable_tls_backend | bool %}, + { + "source": "{{ container_config_directory }}/keystone-cert.pem", + "dest": "/etc/keystone/certs/keystone-cert.pem", + "owner": "keystone", + "perm": "0600" + }, + { + "source": "{{ container_config_directory }}/keystone-key.pem", + "dest": "/etc/keystone/certs/keystone-key.pem", + "owner": "keystone", + "perm": "0600" + }{% endif %}{% if keystone_enable_federation_openid | bool %}, + { + "source": "{{ container_config_directory }}/federation/oidc/metadata", + "dest": "{{ keystone_container_federation_oidc_metadata_folder }}", + "owner": "{{ apache_user }}:{{ apache_user }}", + "perm": "0600", + "merge": true + }, + { + "source": "{{ container_config_directory }}/federation/oidc/cert", + "dest": "{{ keystone_container_federation_oidc_idp_certificate_folder }}", + "owner": "{{ apache_user }}:{{ apache_user }}", + "perm": "0600", + "merge": true + }{% endif %}{% if kolla_copy_ca_into_containers | bool %}, + { + "source": "{{ container_config_directory }}/ca-certificates", + "dest": "/var/lib/kolla/share/ca-certificates", + "owner": "root", + "perm": "0600" + }{% endif %} + ], + "permissions": [ + { + "path": "/var/log/kolla/keystone", + "owner": "keystone:kolla" + }{% if keystone_enable_federation_openid | bool %}, + { + "path": "{{ keystone_container_federation_oidc_metadata_folder }}", + "owner": "{{ apache_user }}:{{ apache_user }}", + "perm": "0700" + }, + { + "path": "{{ keystone_container_federation_oidc_idp_certificate_folder }}", + "owner": "{{ apache_user }}:{{ apache_user }}", + "perm": "0700" + }{% endif %} + ] +} 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/service-uwsgi-config/defaults/main.yml b/ansible/roles/service-uwsgi-config/defaults/main.yml index 6e5225c92..9c5e13ed3 100644 --- a/ansible/roles/service-uwsgi-config/defaults/main.yml +++ b/ansible/roles/service-uwsgi-config/defaults/main.yml @@ -3,6 +3,7 @@ service_uwsgi_config_host: "{{ api_interface_address | put_address_in_context('u service_uwsgi_config_file: "{{ node_config_directory }}/{{ service_name }}/{{ service_name }}-uwsgi.ini" service_uwsgi_config_log_dir: "{{ ansible_parent_role_names | first }}" service_uwsgi_config_log_file: "{{ service_name }}-uwsgi.log" +service_uwsgi_config_socket_port: "" service_uwsgi_config_tls_backend: false service_uwsgi_config_worker_timeout: 80 service_uwsgi_config_workers: "{{ openstack_service_workers }}" diff --git a/ansible/roles/service-uwsgi-config/templates/uwsgi.ini.j2 b/ansible/roles/service-uwsgi-config/templates/uwsgi.ini.j2 index a7495b439..2c93d4e1b 100644 --- a/ansible/roles/service-uwsgi-config/templates/uwsgi.ini.j2 +++ b/ansible/roles/service-uwsgi-config/templates/uwsgi.ini.j2 @@ -10,6 +10,9 @@ https = {{ service_uwsgi_config_host }}:{{ service_uwsgi_config_http_port }},{{ {% else %} http = {{ service_uwsgi_config_host }}:{{ service_uwsgi_config_http_port }} {% endif %} +http-auto-chunked = true +http-chunked-input = true +http-raw-body = true lazy-apps = true logto2 = /var/log/kolla/{{ service_uwsgi_config_log_dir }}/{{ service_uwsgi_config_log_file }} {% if service_uwsgi_config_log_file_chmod is defined %} @@ -27,6 +30,9 @@ wsgi-file = {{ service_uwsgi_config_wsgi_file }} plugins-dir = {{ '/usr/lib/uwsgi/plugins' if kolla_base_distro in ['ubuntu', 'debian'] else '/usr/lib64/uwsgi' }} plugins = python3 processes = {{ service_uwsgi_config_workers }} +{% if service_uwsgi_config_socket_port | length > 0 %} +socket = {{ service_uwsgi_config_host }}:{{ service_uwsgi_config_socket_port }} +{% endif %} socket-timeout = 30 thunder-lock = true {% if service_uwsgi_config_uid is defined %} 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. diff --git a/doc/source/admin/password-rotation.rst b/doc/source/admin/password-rotation.rst index 506709975..fe5b5bdb0 100644 --- a/doc/source/admin/password-rotation.rst +++ b/doc/source/admin/password-rotation.rst @@ -58,7 +58,7 @@ applied this way. * ``osprofiler_secret`` * ``prometheus_alertmanager_password`` * ``qdrouterd_password`` -* ``redis_master_password`` +* ``valkey_master_password`` It is possible to change more secrets however some require manual steps. The manual steps vary depending on the secret. They are listed below in the order diff --git a/doc/source/reference/networking/designate-guide.rst b/doc/source/reference/networking/designate-guide.rst index 9a629ebb4..aa0932b87 100644 --- a/doc/source/reference/networking/designate-guide.rst +++ b/doc/source/reference/networking/designate-guide.rst @@ -51,10 +51,10 @@ Configure Designate options in ``/etc/kolla/globals.yml`` .. important:: If multiple nodes are assigned to be Designate workers, then you must - enable a supported coordination backend, currently only ``redis`` + enable a supported coordination backend, currently only ``valkey`` is supported. The backend choice can be overridden via the - ``designate_coordination_backend`` variable. It defaults to ``redis`` - when ``redis`` is enabled (``enable_redis`` is set to ``yes``). + ``designate_coordination_backend`` variable. It defaults to ``valkey`` + when ``valkey`` is enabled (``enable_valkey`` is set to ``yes``). The following additional variables are required depending on which backend you intend to use: diff --git a/etc/kolla/globals.yml b/etc/kolla/globals.yml index 8f0973f5a..36f5b4806 100644 --- a/etc/kolla/globals.yml +++ b/etc/kolla/globals.yml @@ -429,7 +429,7 @@ workaround_ansible_issue_8743: yes #enable_placement: "{{ enable_nova | bool or enable_zun | bool }}" #enable_prometheus: "no" #enable_proxysql: "yes" -#enable_redis: "no" +#enable_valkey: "no" #enable_skyline: "no" #enable_tacker: "no" #enable_telegraf: "no" @@ -540,7 +540,7 @@ workaround_ansible_issue_8743: yes #################### # Osprofiler options #################### -# valid values: ["elasticsearch", "redis"] +# valid values: ["elasticsearch", "valkey"] #osprofiler_backend: "elasticsearch" ################## @@ -556,8 +556,8 @@ workaround_ansible_issue_8743: yes # 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 '' }}" ################################ # Cinder - Block Storage Options @@ -565,8 +565,8 @@ workaround_ansible_issue_8743: yes # Enable / disable Cinder backends #cinder_backend_ceph: "no" #cinder_volume_group: "cinder-volumes" -# 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" @@ -598,8 +598,8 @@ workaround_ansible_issue_8743: yes #designate_backend: "bind9" #designate_ns_record: # - "ns1.example.org" -# 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 '' }}" ######################## # Nova - Compute Options @@ -659,8 +659,8 @@ workaround_ansible_issue_8743: yes # List of extra kernel parameters passed to the kernel used during inspection #ironic_kernel_cmdline_extras: [] -# Valid options are [ '', redis, etcd ] -#ironic_coordination_backend: "{{ 'redis' if enable_redis|bool else 'etcd' if enable_etcd|bool else '' }}" +# Valid options are [ '', valkey, etcd ] +#ironic_coordination_backend: "{{ 'valkey' if enable_valkey | bool else 'etcd' if enable_etcd | bool else '' }}" ###################################### # Manila - Shared File Systems Options diff --git a/etc/kolla/passwords.yml b/etc/kolla/passwords.yml index 5705873d6..1120754a8 100644 --- a/etc/kolla/passwords.yml +++ b/etc/kolla/passwords.yml @@ -197,8 +197,10 @@ keepalived_password: etcd_cluster_token: #################### -# redis options +# valkey options #################### +valkey_master_password: +# TODO(gkoper): Remove after G/2026.1 release redis_master_password: #################### diff --git a/releasenotes/notes/bug-2097452-6b635e49606ebe26.yaml b/releasenotes/notes/bug-2097452-6b635e49606ebe26.yaml index 1fa4888bb..1731789bd 100644 --- a/releasenotes/notes/bug-2097452-6b635e49606ebe26.yaml +++ b/releasenotes/notes/bug-2097452-6b635e49606ebe26.yaml @@ -1,7 +1,7 @@ --- fixes: - | - Configuration with letsencrypt disabled generates - in haproxy unnecessary backend 'acme_client_back' - and 'path_reg ^/.well-known/acme-challenge/.+'. + Fixes haproxy configurations that kept rendering the ``acme_client_back`` + backend and the ``path_reg ^/.well-known/acme-challenge/.+`` ACL even when + Let's Encrypt support was disabled. `LP#2097452 <https://launchpad.net/bugs/2097452>`__ diff --git a/releasenotes/notes/bug-2111916-6b2ca611df41dceb.yaml b/releasenotes/notes/bug-2111916-6b2ca611df41dceb.yaml index 78b22c633..c971365cd 100644 --- a/releasenotes/notes/bug-2111916-6b2ca611df41dceb.yaml +++ b/releasenotes/notes/bug-2111916-6b2ca611df41dceb.yaml @@ -1,6 +1,6 @@ --- fixes: - | - Fixes invalid use of ``drain`` on single-node RabbitMQ setups - by using ``stop_app`` instead. + Single-node RabbitMQ upgrades no longer fail on the unsupported ``drain`` + command; the playbooks now call ``stop_app`` in that scenario. `LP#2111916 <https://launchpad.net/bugs/2111916>`__ diff --git a/releasenotes/notes/bug-2112339-3f67eefc7f0062cc.yaml b/releasenotes/notes/bug-2112339-3f67eefc7f0062cc.yaml index d01515854..062acd162 100644 --- a/releasenotes/notes/bug-2112339-3f67eefc7f0062cc.yaml +++ b/releasenotes/notes/bug-2112339-3f67eefc7f0062cc.yaml @@ -1,10 +1,9 @@ --- fixes: - | - Improves query routing in ProxySQL by setting ``default_hostgroup`` - for all database users and by adding user-based routing rules in - addition to schema-based rules. This enhancement also fixes incorrect - routing of queries that are executed before a schema is selected, - such as ``SET AUTOCOMMIT`` or ``ROLLBACK``, which could otherwise be sent - to a non-existent hostgroup. + Improves ProxySQL routing by setting ``default_hostgroup`` for every + MariaDB user and by adding user-based rules alongside the schema-based + rules. Statements that run before a schema is selected (for example + ``SET AUTOCOMMIT`` or ``ROLLBACK``) now land in a valid hostgroup instead + of failing against ``NULL`` backends. `LP#2112339 <https://launchpad.net/bugs/2112339>`__ diff --git a/releasenotes/notes/cron-break-out-role-fa72289cc100ef53.yaml b/releasenotes/notes/cron-break-out-role-fa72289cc100ef53.yaml index 7bbb085e5..bdcdc94bd 100644 --- a/releasenotes/notes/cron-break-out-role-fa72289cc100ef53.yaml +++ b/releasenotes/notes/cron-break-out-role-fa72289cc100ef53.yaml @@ -1,5 +1,5 @@ --- upgrade: - | - A ``cron`` Ansible role has been created and its deployment is not part - of the ``common`` role anymore. + The ``cron`` tasks now live in their own Ansible role instead of being + shipped inside ``common``. diff --git a/releasenotes/notes/custom_modOIDC_error_page-0fe3dd7414310536.yaml b/releasenotes/notes/custom_modOIDC_error_page-0fe3dd7414310536.yaml index e50b46911..1fbcb35f8 100644 --- a/releasenotes/notes/custom_modOIDC_error_page-0fe3dd7414310536.yaml +++ b/releasenotes/notes/custom_modOIDC_error_page-0fe3dd7414310536.yaml @@ -1,19 +1,15 @@ --- features: - | - Enable the configuration of the timeout manager by - ``OIDCStateTimeout`` variable. We also provide means to - override the error page for the modOIDC plugin via - ``{{ node_custom_config }}/keystone/federation/modoidc-error-page.html`` - file. + Adds knobs for the Keystone mod_auth_openidc integration: tune the timeout + manager via ``OIDCStateTimeout`` and provide a custom error page at + ``{{ node_custom_config }}/keystone/federation/modoidc-error-page.html``. upgrade: - | - It was added a default template for the modOIDC plugin, - which will handle authentication errors for federated users. - The default template is found at - "ansible/roles/keystone/templates/modoidc-error-page.html.j2"; - it can also be replaced/overwritten. One can also overwrite, - the timeout, instead of the whole page via the following variable: + Deployments now ship a default template at + ``ansible/roles/keystone/templates/modoidc-error-page.html.j2`` to handle + federated authentication errors. Operators can override the full template + or just adjust the redirect delay via ``keystone_federation_oidc_error_page_retry_login_delay_milliseconds``. - The default timeout for the page redirection is 5 seconds. + The default redirect delay is 5 seconds. diff --git a/releasenotes/notes/drop-clustercheck-and-haproxy-support-for-mariadb-4cbd7c8590a34981.yaml b/releasenotes/notes/drop-clustercheck-and-haproxy-support-for-mariadb-4cbd7c8590a34981.yaml index ab486ca79..095760b47 100644 --- a/releasenotes/notes/drop-clustercheck-and-haproxy-support-for-mariadb-4cbd7c8590a34981.yaml +++ b/releasenotes/notes/drop-clustercheck-and-haproxy-support-for-mariadb-4cbd7c8590a34981.yaml @@ -1,13 +1,12 @@ --- features: - | - ProxySQL is now automatically enabled when MariaDB is enabled. - MariaDB container healthcheck method was updated as healthcheck script was - replaced from Clustercheck to official MariaDB docker image's + ProxySQL is now enabled automatically whenever MariaDB is enabled, and the + container health check now uses the upstream `healthcheck.sh <https://mariadb.com/docs/server/server-management/install-and-upgrade-mariadb/installing-mariadb/binary-packages/automated-mariadb-deployment-and-administration/docker-and-mariadb/using-healthcheck-sh>`__ + script instead of ``clustercheck``. upgrade: - | - Database loadbalancing with HAProxy and MariaDB Clustercheck is no longer - supported. For the system that uses HAProxy and Clustercheck, upgrading - MariaDB with ``kolla-ansible upgrade`` will deploy ProxySQL containers and - remove MariaDB Clustercheck containers. + The HAProxy + ``clustercheck`` backend for MariaDB is no longer supported. + Running ``kolla-ansible upgrade`` now deploys ProxySQL and removes the old + ``clustercheck`` containers automatically. diff --git a/releasenotes/notes/drop-ironic-inspector-38fc91c64517ffc1.yaml b/releasenotes/notes/drop-ironic-inspector-38fc91c64517ffc1.yaml index a912433e9..5d379df6b 100644 --- a/releasenotes/notes/drop-ironic-inspector-38fc91c64517ffc1.yaml +++ b/releasenotes/notes/drop-ironic-inspector-38fc91c64517ffc1.yaml @@ -1,12 +1,11 @@ --- upgrade: - | - The ``ironic-inspector`` deployment support has been dropped following - retirement of that service in ``Ironic`` project. - ``ironic_inspector_kernel_cmdline_extras`` has been renamed to - ``ironic_kernel_cmdline_extras`` and ``ironic_inspector_pxe_filter`` - has been renamed to ``ironic_pxe_filter``. - Also the ``inspector.ipxe`` file has been renamed to ``ipa.ipxe``. + Support for deploying ``ironic-inspector`` has been dropped following the + service's retirement upstream. The remaining variables and artifacts were + renamed for consistency: ``ironic_inspector_kernel_cmdline_extras`` becomes + ``ironic_kernel_cmdline_extras``, ``ironic_inspector_pxe_filter`` becomes + ``ironic_pxe_filter``, and ``inspector.ipxe`` becomes ``ipa.ipxe``. - | - ``bifrost`` support for deploying legacy ironic inspector has been - dropped together with ``bifrost_enable_ironic_inspector`` variable. + ``bifrost`` also removed its legacy inspector integration, so the + ``bifrost_enable_ironic_inspector`` option has been deleted. diff --git a/releasenotes/notes/drop-vmware-support-6303715d3fb80946.yaml b/releasenotes/notes/drop-vmware-support-6303715d3fb80946.yaml index 0a7b28a7d..d672d90b3 100644 --- a/releasenotes/notes/drop-vmware-support-6303715d3fb80946.yaml +++ b/releasenotes/notes/drop-vmware-support-6303715d3fb80946.yaml @@ -1,6 +1,6 @@ --- upgrade: - | - ``VMWare`` support for various OpenStack services (e.g. Nova, Cinder, - Neutron) has been dropped due to removal in respective services - and no development or new versions of third party libraries. + ``VMware`` drivers across Nova, Cinder, and Neutron are no longer deployed. + Upstream projects removed the integration and the third-party libraries are + unmaintained. diff --git a/releasenotes/notes/flamingo-prelude-57a2c0e9d578fd57.yaml b/releasenotes/notes/flamingo-prelude-57a2c0e9d578fd57.yaml new file mode 100644 index 000000000..f7bddc179 --- /dev/null +++ b/releasenotes/notes/flamingo-prelude-57a2c0e9d578fd57.yaml @@ -0,0 +1,29 @@ +--- +prelude: | + The Kolla Ansible ``21.0.0`` (Flamingo) release focuses on tightening + operations for the control plane, database layer, and observability stack + while following upstream service retirements. Highlights include: + + * Database services now use ``ProxySQL`` by default with ``MariaDB`` adopting + the upstream ``healthcheck.sh`` script, TLS enabled for all ``MariaDB`` + connections through ``ProxySQL``, and ``Valkey`` replacing ``Redis``. The + legacy ``HAProxy``/``clustercheck`` path and containers have been removed. + * Logging and monitoring were overhauled: ``Fluentd`` moved into its own role + and sends logs directly to ``OpenSearch`` nodes, ``Prometheus`` + node-exporters run from a dedicated role, and ``OpenSearch Dashboards`` + connects to the data nodes without an intermediate ``HAProxy`` hop. + * Control-plane services gained multiple lifecycle improvements. ``Neutron`` + now mirrors the upstream layout with new maintenance/RPC workers, wrapper + containers manage the OVN metadata-agent HAProxy processes, + ``nova-metadata`` runs in its own container, ``Horizon`` uses port ``8080`` + when fronted by ``HAProxy``, and the default ``uWSGI`` provider now covers + more services. + * Tooling and reliability improvements: the supported ``ansible`` window is + 11–12, host bootstrap tasks moved into ``ansible-collection-kolla``, CA + bundle trust paths were aligned on Enterprise Linux hosts, ``mod_oidc`` + gained templated error pages, and several HA fixes landed (Let’s Encrypt + ACME cleanup, Horizon memcached resilience, RabbitMQ single-node upgrades, + and ``ProxySQL`` routing improvements). + * With ``ironic-inspector`` retired upstream, Kolla Ansible now provides the + ``ironic-pxe-filter`` service to cover bare-metal PXE filtering and removes + other unused integrations such as ``Venus`` and ``VMware`` drivers. diff --git a/releasenotes/notes/fluentd-break-out-role-1e5306dac1c41583.yaml b/releasenotes/notes/fluentd-break-out-role-1e5306dac1c41583.yaml index 60d97f922..f0110ee82 100644 --- a/releasenotes/notes/fluentd-break-out-role-1e5306dac1c41583.yaml +++ b/releasenotes/notes/fluentd-break-out-role-1e5306dac1c41583.yaml @@ -1,5 +1,5 @@ --- upgrade: - | - A ``fluentd`` Ansible role has been created and its deployment is not part - of the ``common`` role anymore. + ``fluentd`` now has its own Ansible role instead of being deployed from the + ``common`` role. diff --git a/releasenotes/notes/neutron-uwsgi-5ac29b1403c02554.yaml b/releasenotes/notes/neutron-uwsgi-5ac29b1403c02554.yaml index 9cabd83a8..7349c1b0c 100644 --- a/releasenotes/notes/neutron-uwsgi-5ac29b1403c02554.yaml +++ b/releasenotes/notes/neutron-uwsgi-5ac29b1403c02554.yaml @@ -1,13 +1,11 @@ --- upgrade: - | - ``Neutron`` deployment has been reworked to use uWSGI for API workers - and to run additional processes in separate containers (following changes - in Neutron project). - Therefore ``neutron-tls-proxy`` service has been dropped and currently - TLS is terminated on the uWSGI server. - In addition to this there are new containers/services: + ``Neutron`` now runs its API workers under uWSGI and moves auxiliary + processes into dedicated containers, matching the upstream deployment + model. TLS is terminated directly on uWSGI, so the ``neutron-tls-proxy`` + service was removed. New containers introduced with this change include: - * neutron-ovn-maintenance-worker - * neutron-rpc-server - * neutron-periodic-workers + * ``neutron-ovn-maintenance-worker`` + * ``neutron-rpc-server`` + * ``neutron-periodic-workers`` diff --git a/releasenotes/notes/nova-metadata-split-d1c9ff2010390352.yaml b/releasenotes/notes/nova-metadata-split-d1c9ff2010390352.yaml index 2cf1ffb5f..dd9085aa3 100644 --- a/releasenotes/notes/nova-metadata-split-d1c9ff2010390352.yaml +++ b/releasenotes/notes/nova-metadata-split-d1c9ff2010390352.yaml @@ -1,5 +1,5 @@ --- features: - | - ``nova-metadata`` service has been split into it's own container in - preparation for uWSGI support. + The ``nova-metadata`` service now runs in its own container in preparation + for the uWSGI migration. diff --git a/releasenotes/notes/replace-redis-with-valkey-8f60e01c2460a301.yaml b/releasenotes/notes/replace-redis-with-valkey-8f60e01c2460a301.yaml new file mode 100644 index 000000000..4a7b27998 --- /dev/null +++ b/releasenotes/notes/replace-redis-with-valkey-8f60e01c2460a301.yaml @@ -0,0 +1,12 @@ +--- +features: + - | + Added a Valkey role with Sentinel so deployments use Valkey instead of + Redis without changing coordination endpoints. +upgrade: + - | + Redis has been replaced with Valkey. Before running ``kolla-ansible + upgrade``, set ``enable_redis: "no"`` and ``enable_valkey: "yes"`` + in ``globals.yml``. The upgrade playbooks automatically migrate Redis + data into Valkey using temporary ports and then switch back to the + defaults. diff --git a/releasenotes/notes/uwsgi-chunked-input-8b15b1c77f093332.yaml b/releasenotes/notes/uwsgi-chunked-input-8b15b1c77f093332.yaml new file mode 100644 index 000000000..a7007fe88 --- /dev/null +++ b/releasenotes/notes/uwsgi-chunked-input-8b15b1c77f093332.yaml @@ -0,0 +1,4 @@ +--- +features: + - | + HTTP chunked input is now enabled by default for all ``uWSGI`` services. diff --git a/roles/kolla-ansible-test-dashboard/tasks/main.yml b/roles/kolla-ansible-test-dashboard/tasks/main.yml index 8455b3154..534769182 100644 --- a/roles/kolla-ansible-test-dashboard/tasks/main.yml +++ b/roles/kolla-ansible-test-dashboard/tasks/main.yml @@ -55,6 +55,10 @@ detach: true image: "quay.io/opendevmirror/selenium-standalone-firefox:latest" network_mode: host + register: docker_result + retries: 5 + delay: 3 + until: docker_result is succeeded - name: Run Selenium Firefox container (Podman) become: true @@ -64,6 +68,10 @@ detach: true image: "quay.io/opendevmirror/selenium-standalone-firefox:latest" network_mode: host + register: podman_result + retries: 5 + delay: 3 + until: podman_result is succeeded - name: Wait for port 444 to be up ansible.builtin.wait_for: diff --git a/tests/check-logs.sh b/tests/check-logs.sh index dac11ccb9..c9953982c 100755 --- a/tests/check-logs.sh +++ b/tests/check-logs.sh @@ -88,6 +88,7 @@ function check_fluentd_missing_logs { /var/log/kolla/rabbitmq/*upgrade.log) continue ;; + # TODO(gkoper) Remove after G/2026.1 release /var/log/kolla/redis/*) continue ;; diff --git a/tests/pre.yml b/tests/pre.yml index 1a666e97d..1480609b3 100644 --- a/tests/pre.yml +++ b/tests/pre.yml @@ -52,6 +52,12 @@ - "veth-{{ neutron_external_bridge_name }}-ext" bridge_name: "{{ neutron_external_bridge_name }}" tasks: + - name: Set Rockylinux mirror to download.rockylinux.org + become: true + ansible.builtin.shell: + cmd: sed -i 's/mirrorlist/#mirrorlist/g; s/#baseurl/baseurl/g' /etc/yum.repos.d/rocky.repo + when: ansible_facts.distribution == "Rocky" + # NOTE(yoctozepto): we use gawk to add time to each logged line # outside of Ansible (e.g. for init-runonce) - name: Install gawk and required Python modules diff --git a/tests/templates/globals-default.j2 b/tests/templates/globals-default.j2 index ddcc631dd..af04859ff 100644 --- a/tests/templates/globals-default.j2 +++ b/tests/templates/globals-default.j2 @@ -118,11 +118,15 @@ enable_prometheus_openstack_exporter: "no" enable_tacker: "yes" enable_neutron_sfc: "yes" enable_mistral: "yes" -enable_redis: "yes" +enable_valkey: "yes" enable_barbican: "yes" enable_heat: "yes" # NOTE(yoctozepto): see https://bugs.launchpad.net/kolla-ansible/+bug/1906299 enable_aodh: "yes" +# TODO(gkoper): Remove after G/2026.1 release +{% if is_previous_release %} +enable_redis: "yes" +{% endif %} {% endif %} {% if scenario == "ironic" %} @@ -136,6 +140,7 @@ ironic_dnsmasq_dhcp_ranges: {% if scenario == "masakari" %} enable_masakari: "yes" +enable_valkey: "yes" {% endif %} {% if scenario == "cells" %} @@ -156,7 +161,7 @@ enable_mariabackup: "yes" # kolla-ansible vars enable_cinder: "yes" enable_neutron_agent_ha: "yes" -enable_redis: "yes" +enable_valkey: "yes" cinder_cluster_name: "kolla_ceph" # External Ceph glance_backend_ceph: "yes" @@ -166,8 +171,10 @@ nova_backend_ceph: "yes" rabbitmq_cluster_partition_handling: "autoheal" rabbitmq_extra_config: cluster_keepalive_interval: 50000 -# Redis for coordination +# TODO(gkoper): Remove after G/2026.1 release +{% if is_previous_release %} enable_redis: "yes" +{% endif %} enable_ceph_rgw: "yes" ceph_rgw_hosts: @@ -201,8 +208,11 @@ neutron_enable_ovn_agent: "yes" enable_octavia: "yes" octavia_provider_drivers: "ovn:OVN provider" octavia_provider_agents: "ovn" -enable_redis: "yes" neutron_dns_domain: "example.org." +# TODO(gkoper): Remove after G/2026.1 release +{% if is_previous_release %} +enable_redis: "yes" +{% endif %} {% endif %} {% if scenario == "prometheus-opensearch" %} @@ -234,8 +244,12 @@ octavia_amp_flavor: ram: 1024 disk: 5 octavia_network_type: "tenant" +enable_valkey: "yes" +# TODO(gkoper): Remove after G/2026.1 release +{% if is_previous_release %} enable_redis: "yes" {% endif %} +{% endif %} {% if groups['all'] | length == 1 %} keepalived_track_script_enabled: "no" @@ -281,6 +295,11 @@ skyline_enable_sso: "yes" enable_aodh: "yes" enable_ceilometer: "yes" enable_gnocchi: "yes" +enable_valkey: "yes" +{% endif %} + +{% if scenario == "federation" %} +enable_keystone_federation: true {% endif %} mariadb_monitor_read_only_interval: "30000" diff --git a/tests/templates/inventory.j2 b/tests/templates/inventory.j2 index d0711e93e..8441d825e 100644 --- a/tests/templates/inventory.j2 +++ b/tests/templates/inventory.j2 @@ -225,9 +225,13 @@ deployment [zun:children] control +# TODO(gkoper): Remove redis group after G/2026.1 release [redis:children] control +[valkey:children] +control + [blazar:children] control @@ -158,4 +158,4 @@ setenv = {[testenv:linters]setenv} deps = {[testenv:linters]deps} commands = python {toxinidir}/tools/validate-all-file.py - ansible-lint -p --exclude tests --exclude roles --exclude etc --exclude zuul.d + ansible-lint -p diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml index dffc20c4e..098624130 100644 --- a/zuul.d/project.yaml +++ b/zuul.d/project.yaml @@ -11,6 +11,7 @@ # NOTE(mnasiadka): Failing since # https://review.opendev.org/c/openstack/kolla-ansible/+/864780 # - kolla-ansible-scenario-container-engine-migration + - kolla-ansible-scenario-federation - kolla-ansible-scenario-haproxy-fqdn - kolla-ansible-scenario-kayobe - kolla-ansible-scenario-openbao diff --git a/zuul.d/scenarios/aio.yaml b/zuul.d/scenarios/aio.yaml index f8e9b06e3..384a06b27 100644 --- a/zuul.d/scenarios/aio.yaml +++ b/zuul.d/scenarios/aio.yaml @@ -6,7 +6,7 @@ - ^ansible/group_vars/all/(common|fluentd|glance|haproxy|heat|horizon|keepalived|keystone|loadbalancer|neutron|nova|openvswitch|placement|proxysql|rabbitmq).yml - ^ansible/group_vars/baremetal/ansible-python-interpreter.yml - ^ansible/(action_plugins|filter_plugins|library|module_utils)/ - - ^ansible/roles/(common|fluentd|glance|haproxy-config|heat|horizon|keystone|loadbalancer|loadbalancer-config|neutron|nova|nova-cell|openvswitch|placement|proxysql|rabbitmq|service-.*)/ + - ^ansible/roles/(common|fluentd|glance|haproxy-config|heat|horizon|keystone|loadbalancer|loadbalancer-config|neutron|nova|nova-cell|openvswitch|placement|proxysql|rabbitmq|service.*)/ - ^kolla_ansible/ - ^roles/kolla-ansible-(deploy|tempest|test-dashboard)/ - ^tests/testinfra/test_horizon.py diff --git a/zuul.d/scenarios/cephadm.yaml b/zuul.d/scenarios/cephadm.yaml index 28ac2128b..2120af30e 100644 --- a/zuul.d/scenarios/cephadm.yaml +++ b/zuul.d/scenarios/cephadm.yaml @@ -4,9 +4,9 @@ parent: kolla-ansible-base voting: false files: - - ^ansible/group_vars/all/(ceph|ceph-rgw|common|fluentd|glance|heat|horizon|keepalived|keystone|loadbalancer|neutron|nova|openvswitch|placement|proxysql|rabbitmq).yml + - ^ansible/group_vars/all/(ceph|ceph-rgw|common|fluentd|glance|heat|horizon|keepalived|keystone|loadbalancer|neutron|nova|openvswitch|placement|proxysql|rabbitmq|valkey).yml - ^ansible/group_vars/baremetal/ansible-python-interpreter.yml - - ^ansible/roles/(ceph-rgw|common|fluentd|glance|haproxy-config|heat|horizon|keystone|loadbalancer|loadbalancer-config|neutron|nova|openvswitch|placement|proxysql|rabbitmq)/ + - ^ansible/roles/(ceph-rgw|common|fluentd|glance|haproxy-config|heat|horizon|keystone|loadbalancer|loadbalancer-config|neutron|nova|openvswitch|placement|proxysql|rabbitmq|valkey)/ - ^roles/cephadm/ vars: kolla_ansible_setup_disks_file_path: "/var/lib/ceph-osd.img" @@ -16,7 +16,7 @@ scenario: cephadm scenario_images_extra: - ^cinder - - ^redis + - ^valkey - job: name: kolla-ansible-debian-bookworm-cephadm diff --git a/zuul.d/scenarios/keystone-federation.yaml b/zuul.d/scenarios/keystone-federation.yaml new file mode 100644 index 000000000..47e3f3ff8 --- /dev/null +++ b/zuul.d/scenarios/keystone-federation.yaml @@ -0,0 +1,37 @@ +--- +- job: + name: kolla-ansible-federation-base + parent: kolla-ansible-base + voting: false + files: !inherit + - ^ansible/group_vars/all/keystone.yml + - ^ansible/roles/keystone/ + vars: + scenario: federation + scenario_images_extra: + - ^httpd + +- job: + name: kolla-ansible-debian-bookworm-federation + parent: kolla-ansible-federation-base + nodeset: kolla-ansible-debian-bookworm-multi-8GB + +- job: + name: kolla-ansible-rocky-10-federation + parent: kolla-ansible-federation-base + nodeset: kolla-ansible-rocky-10-multi-8GB + +- job: + name: kolla-ansible-ubuntu-noble-federation + parent: kolla-ansible-federation-base + nodeset: kolla-ansible-ubuntu-noble-multi-8GB + +- project-template: + name: kolla-ansible-scenario-federation + description: | + Runs Kolla-Ansible Keystone federation scenario jobs. + check: + jobs: + - kolla-ansible-debian-bookworm-federation + - kolla-ansible-rocky-10-federation + - kolla-ansible-ubuntu-noble-federation diff --git a/zuul.d/scenarios/masakari.yaml b/zuul.d/scenarios/masakari.yaml index 4593f0a67..02eb2a98e 100644 --- a/zuul.d/scenarios/masakari.yaml +++ b/zuul.d/scenarios/masakari.yaml @@ -4,14 +4,15 @@ parent: kolla-ansible-base voting: false files: !inherit - - ^ansible/group_vars/all/(hacluster|masakari).yml - - ^ansible/roles/(hacluster|masakari)/ + - ^ansible/group_vars/all/(hacluster|masakari|valkey).yml + - ^ansible/roles/(hacluster|masakari|valkey)/ - ^tests/test-masakari.sh vars: scenario: masakari scenario_images_extra: - ^masakari - ^hacluster + - ^valkey # TODO: Remove once Masakari has TLS support tls_enabled: false diff --git a/zuul.d/scenarios/nfv.yaml b/zuul.d/scenarios/nfv.yaml index 60e44f7ee..03df813c0 100644 --- a/zuul.d/scenarios/nfv.yaml +++ b/zuul.d/scenarios/nfv.yaml @@ -4,8 +4,8 @@ parent: kolla-ansible-base voting: false files: !inherit - - ^ansible/group_vars/all/(aodh|barbican|heat|mistral|redis|tacker).yml - - ^ansible/roles/(aodh|barbican|heat|mistral|redis|tacker)/ + - ^ansible/group_vars/all/(aodh|barbican|heat|mistral|valkey|tacker).yml + - ^ansible/roles/(aodh|barbican|heat|mistral|valkey|tacker)/ - ^tests/test-scenario-nfv.sh vars: scenario: nfv @@ -13,7 +13,7 @@ - ^aodh - ^tacker - ^mistral - - ^redis + - ^valkey - ^barbican tls_enabled: false diff --git a/zuul.d/scenarios/octavia.yaml b/zuul.d/scenarios/octavia.yaml index d7fdcb208..520969f65 100644 --- a/zuul.d/scenarios/octavia.yaml +++ b/zuul.d/scenarios/octavia.yaml @@ -4,13 +4,13 @@ parent: kolla-ansible-base voting: false files: !inherit - - ^ansible/group_vars/all/octavia.yml - - ^ansible/roles/(octavia|octavia-certificates)/ + - ^ansible/group_vars/all/(octavia|valkey).yml + - ^ansible/roles/(octavia|octavia-certificates|valkey)/ - ^tests/test-octavia.sh vars: scenario: octavia scenario_images_extra: - - ^redis + - ^valkey - ^octavia tls_enabled: false diff --git a/zuul.d/scenarios/ovn.yaml b/zuul.d/scenarios/ovn.yaml index 6e9472845..cfc4b2926 100644 --- a/zuul.d/scenarios/ovn.yaml +++ b/zuul.d/scenarios/ovn.yaml @@ -9,7 +9,6 @@ vars: scenario: ovn scenario_images_extra: - - ^redis - ^octavia - ^ovn diff --git a/zuul.d/scenarios/telemetry.yaml b/zuul.d/scenarios/telemetry.yaml index 08d01d890..bd762ea4c 100644 --- a/zuul.d/scenarios/telemetry.yaml +++ b/zuul.d/scenarios/telemetry.yaml @@ -4,8 +4,8 @@ parent: kolla-ansible-base voting: false files: - - ^ansible/group_vars/all/(aodh|ceilometer|gnocchi).yml - - ^ansible/roles/(aodh|ceilometer|gnocchi)/ + - ^ansible/group_vars/all/(aodh|ceilometer|gnocchi|valkey).yml + - ^ansible/roles/(aodh|ceilometer|gnocchi|valkey)/ - ^tests/test-telemetry.sh vars: scenario: telemetry @@ -13,6 +13,7 @@ - ^aodh - ^ceilometer - ^gnocchi + - ^valkey - job: name: kolla-ansible-debian-bookworm-telemetry |
