diff --git a/ansible/group_vars/all/common.yml b/ansible/group_vars/all/common.yml index 1aeae7f448..d007b9b1ad 100644 --- a/ansible/group_vars/all/common.yml +++ b/ansible/group_vars/all/common.yml @@ -298,15 +298,11 @@ om_rabbitmq_qos_prefetch_count: "1" om_enable_rabbitmq_stream_fanout: true -# OpenStack authentication string. You should only need to override these if you -# are changing the admin tenant/project or user. openstack_auth: - auth_url: "{{ keystone_internal_url }}" - username: "{{ keystone_admin_user }}" password: "{{ keystone_admin_password }}" - project_name: "{{ keystone_admin_project }}" - domain_name: "default" - user_domain_name: "default" + +openstack_auth_cloud: "kolla-admin-internal" +openstack_auth_cloud_system: "kolla-admin-system-internal" #################### # OpenStack options diff --git a/ansible/group_vars/all/horizon.yml b/ansible/group_vars/all/horizon.yml index 8e477ad9c1..d906f04085 100644 --- a/ansible/group_vars/all/horizon.yml +++ b/ansible/group_vars/all/horizon.yml @@ -38,6 +38,12 @@ enable_nova_horizon_policy_file: "{{ enable_nova }}" # TLS horizon_enable_tls_backend: "{{ kolla_enable_tls_backend }}" +# Cache +horizon_session_cache_backend: >- + {{ 'valkey' if enable_valkey | bool + else 'memcached' if enable_memcached | bool + else 'disabled' }} + # Ports horizon_internal_fqdn: "{{ kolla_internal_fqdn }}" horizon_external_fqdn: "{{ kolla_external_fqdn }}" diff --git a/ansible/group_vars/all/octavia.yml b/ansible/group_vars/all/octavia.yml index eaff670bc8..f95a497226 100644 --- a/ansible/group_vars/all/octavia.yml +++ b/ansible/group_vars/all/octavia.yml @@ -31,3 +31,6 @@ octavia_api_port: "9876" octavia_api_listen_port: "{{ octavia_api_port }}" octavia_api_public_port: "{{ haproxy_single_external_frontend_public_port if haproxy_single_external_frontend | bool else octavia_api_port }}" octavia_health_manager_port: "5555" +# Project that Octavia will use to interact with other services. Note that in +# Train and earlier releases this was "admin". +octavia_service_auth_project: "service" diff --git a/ansible/group_vars/all/prometheus.yml b/ansible/group_vars/all/prometheus.yml index 0eeca4e7c0..b6c7465879 100644 --- a/ansible/group_vars/all/prometheus.yml +++ b/ansible/group_vars/all/prometheus.yml @@ -23,6 +23,7 @@ enable_prometheus_libvirt_exporter: "{{ enable_prometheus | bool and enable_nova enable_prometheus_etcd_integration: "{{ enable_prometheus | bool and enable_etcd | bool }}" enable_prometheus_proxysql_exporter: "{{ enable_prometheus | bool and enable_proxysql | bool }}" enable_prometheus_valkey_exporter: "{{ enable_prometheus | bool and enable_valkey | bool }}" +enable_prometheus_openstack_network_exporter: "{{ enable_prometheus | bool }}" prometheus_alertmanager_user: "admin" prometheus_ceph_exporter_interval: "{{ prometheus_scrape_interval }}" @@ -81,5 +82,8 @@ prometheus_elasticsearch_exporter_port: "9108" # Prometheus blackbox-exporter ports prometheus_blackbox_exporter_port: "9115" +# Prometheus network exporter ports +prometheus_openstack_network_exporter_port: "1981" + # Prometheus instance label to use for metrics prometheus_instance_label: diff --git a/ansible/inventory/all-in-one b/ansible/inventory/all-in-one index 1eccb53107..3eed0195e4 100644 --- a/ansible/inventory/all-in-one +++ b/ansible/inventory/all-in-one @@ -175,10 +175,10 @@ common [fluentd:children] common -[kolla-toolbox:children] +[kolla_logs:children] common -[kolla_logs:children] +[kolla_toolbox:children] common [opensearch:children] @@ -239,6 +239,9 @@ neutron [neutron-metadata-agent:children] neutron +[neutron-ovn-vpn-agent:children] +neutron + [neutron-metering-agent:children] neutron @@ -543,6 +546,10 @@ monitoring [prometheus-libvirt-exporter:children] compute +[prometheus-openstack-network-exporter:children] +compute +network + [prometheus-valkey-exporter:children] valkey diff --git a/ansible/inventory/multinode b/ansible/inventory/multinode index 9c87a2015b..eb533b8f5f 100644 --- a/ansible/inventory/multinode +++ b/ansible/inventory/multinode @@ -193,15 +193,11 @@ common [fluentd:children] common -[kolla-toolbox:children] +[kolla_logs:children] common -[kolla_logs:children] -control -network -compute -storage -monitoring +[kolla_toolbox:children] +common [opensearch:children] control @@ -284,6 +280,9 @@ control compute network +[neutron-ovn-vpn-agent:children] +neutron + # Cinder [cinder-api:children] cinder @@ -565,6 +564,10 @@ monitoring [prometheus-libvirt-exporter:children] compute +[prometheus-openstack-network-exporter:children] +compute +network + [prometheus-valkey-exporter:children] valkey diff --git a/ansible/post-deploy.yml b/ansible/post-deploy.yml index 6cd0798147..af565e544d 100644 --- a/ansible/post-deploy.yml +++ b/ansible/post-deploy.yml @@ -18,7 +18,7 @@ - name: Template out clouds.yaml become: "{{ needs_root }}" ansible.builtin.template: - src: "roles/common/templates/clouds.yaml.j2" + src: "templates/clouds.yaml.j2" dest: "{{ node_config }}/clouds.yaml" owner: "{{ ansible_facts.user_uid }}" group: "{{ ansible_facts.user_gid }}" @@ -30,7 +30,7 @@ - name: Template out admin-openrc.sh become: "{{ needs_root }}" ansible.builtin.template: - src: "roles/common/templates/admin-openrc.sh.j2" + src: "templates/admin-openrc.sh.j2" dest: "{{ node_config }}/admin-openrc.sh" owner: "{{ ansible_facts.user_uid }}" group: "{{ ansible_facts.user_gid }}" @@ -39,7 +39,7 @@ - name: Template out admin-openrc-system.sh become: "{{ needs_root }}" ansible.builtin.template: - src: "roles/common/templates/admin-openrc-system.sh.j2" + src: "templates/admin-openrc-system.sh.j2" dest: "{{ node_config }}/admin-openrc-system.sh" owner: "{{ ansible_facts.user_uid }}" group: "{{ ansible_facts.user_gid }}" @@ -48,7 +48,7 @@ - name: Template out public-openrc.sh become: "{{ needs_root }}" ansible.builtin.template: - src: "roles/common/templates/public-openrc.sh.j2" + src: "templates/public-openrc.sh.j2" dest: "{{ node_config }}/public-openrc.sh" owner: "{{ ansible_facts.user_uid }}" group: "{{ ansible_facts.user_gid }}" @@ -57,7 +57,7 @@ - name: Template out public-openrc-system.sh become: "{{ needs_root }}" ansible.builtin.template: - src: "roles/common/templates/public-openrc-system.sh.j2" + src: "templates/public-openrc-system.sh.j2" dest: "{{ node_config }}/public-openrc-system.sh" owner: "{{ ansible_facts.user_uid }}" group: "{{ ansible_facts.user_gid }}" diff --git a/ansible/roles/blazar/tasks/bootstrap.yml b/ansible/roles/blazar/tasks/bootstrap.yml index d84eb6eacc..88cbbf2017 100644 --- a/ansible/roles/blazar/tasks/bootstrap.yml +++ b/ansible/roles/blazar/tasks/bootstrap.yml @@ -43,7 +43,8 @@ container_engine: "{{ kolla_container_engine }}" module_name: os_nova_host_aggregate module_args: - auth: "{{ openstack_auth }}" + auth: "{{ openstack_blazar_auth }}" + cloud: "{{ openstack_auth_cloud }}" cacert: "{{ openstack_cacert }}" endpoint_type: "{{ openstack_interface }}" region_name: "{{ openstack_region_name }}" diff --git a/ansible/roles/common/templates/kolla-toolbox.json.j2 b/ansible/roles/common/templates/kolla-toolbox.json.j2 index 03c79a5cd3..bc766febea 100644 --- a/ansible/roles/common/templates/kolla-toolbox.json.j2 +++ b/ansible/roles/common/templates/kolla-toolbox.json.j2 @@ -1,7 +1,13 @@ { "command": "kolla_toolbox", "config_files": [ - {% if enable_rabbitmq | bool %}{ + { + "source": "{{ container_config_directory }}/clouds.yaml", + "dest": "/var/lib/ansible/.config/openstack/clouds.yaml", + "owner": "ansible", + "perm": "0600" + }{% if enable_rabbitmq | bool %}, + { "source": "{{ container_config_directory }}/rabbitmq-erlang.cookie", "dest": "/var/lib/rabbitmq/.erlang.cookie", "owner": "rabbitmq", @@ -18,7 +24,7 @@ "dest": "/etc/rabbitmq/erl_inetrc", "owner": "rabbitmq", "perm": "0600" - }{% endif %}{% if kolla_copy_ca_into_containers | bool %}{% if enable_rabbitmq | bool %},{% endif %} + }{% endif %}{% if kolla_copy_ca_into_containers | bool %}, { "source": "{{ container_config_directory }}/ca-certificates", "dest": "/var/lib/kolla/share/ca-certificates", diff --git a/ansible/roles/common/vars/main.yml b/ansible/roles/common/vars/main.yml deleted file mode 100644 index df0a76fc2b..0000000000 --- a/ansible/roles/common/vars/main.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -project_name: "common" diff --git a/ansible/roles/heat/defaults/main.yml b/ansible/roles/heat/defaults/main.yml index ec82d57c0b..bc22c1a352 100644 --- a/ansible/roles/heat/defaults/main.yml +++ b/ansible/roles/heat/defaults/main.yml @@ -260,8 +260,8 @@ heat_ks_roles: - "{{ heat_stack_user_role }}" heat_ks_user_roles: - - project: "{{ openstack_auth.project_name }}" - user: "{{ openstack_auth.username }}" + - project: "{{ keystone_admin_project }}" + user: "{{ keystone_admin_user }}" role: "{{ heat_stack_owner_role }}" #################### diff --git a/ansible/roles/heat/tasks/bootstrap_service.yml b/ansible/roles/heat/tasks/bootstrap_service.yml index 38fd5d777d..70a3ac4026 100644 --- a/ansible/roles/heat/tasks/bootstrap_service.yml +++ b/ansible/roles/heat/tasks/bootstrap_service.yml @@ -10,13 +10,13 @@ environment: KOLLA_BOOTSTRAP: KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}" - OS_AUTH_URL: "{{ openstack_auth.auth_url }}" + OS_AUTH_URL: "{{ keystone_internal_url }}" OS_IDENTITY_API_VERSION: "3" OS_INTERFACE: "internal" - OS_USERNAME: "{{ openstack_auth.username }}" - OS_PASSWORD: "{{ openstack_auth.password }}" - OS_PROJECT_NAME: "{{ openstack_auth.project_name }}" - OS_USER_DOMAIN_NAME: "{{ openstack_auth.user_domain_name }}" + OS_USERNAME: "{{ keystone_admin_user }}" + OS_PASSWORD: "{{ keystone_admin_password }}" + OS_PROJECT_NAME: "{{ keystone_admin_project }}" + OS_USER_DOMAIN_NAME: "{{ default_user_domain_name }}" OS_REGION_NAME: "{{ openstack_region_name }}" OS_CACERT: "{{ openstack_cacert | default(omit) }}" HEAT_DOMAIN_ADMIN_PASSWORD: "{{ heat_domain_admin_password }}" diff --git a/ansible/roles/horizon/templates/_9998-kolla-settings.py.j2 b/ansible/roles/horizon/templates/_9998-kolla-settings.py.j2 index 5c4fbd1ab9..e88afbdc3b 100644 --- a/ansible/roles/horizon/templates/_9998-kolla-settings.py.j2 +++ b/ansible/roles/horizon/templates/_9998-kolla-settings.py.j2 @@ -8,18 +8,51 @@ ALLOWED_HOSTS = ['*'] SESSION_ENGINE = 'django.contrib.sessions.backends.db' DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': '{{ horizon_database_name }}', - 'USER': '{{ horizon_database_user }}', - 'PASSWORD': '{{ horizon_database_password }}', - 'HOST': '{{ database_address }}', - 'PORT': '{{ database_port }}' + 'ENGINE': 'django.db.backends.mysql', + 'NAME': '{{ horizon_database_name }}', + 'USER': '{{ horizon_database_user }}', + 'PASSWORD': '{{ horizon_database_password }}', + 'HOST': '{{ database_address }}', + 'PORT': '{{ database_port }}' } } -{% elif groups['memcached'] | length > 0 and not horizon_backend_database | bool %} +{% elif horizon_session_cache_backend == 'valkey' %} SESSION_ENGINE = 'django.contrib.sessions.backends.cache' -CACHES['default']['LOCATION'] = [{% for host in groups['memcached'] %}'{{ 'api' | kolla_address(host) | put_address_in_context('url') }}:{{ memcached_port }}'{% if not loop.last %},{% endif %}{% endfor %}] -CACHES['default']['OPTIONS'] = {'ignore_exc': True} +CACHES = { + 'default': { + 'BACKEND': 'django_redis.cache.RedisCache', + 'LOCATION': 'redis://{{ valkey_sentinel_monitor_name }}/0', + 'OPTIONS': { + 'CLIENT_CLASS': 'django_redis.client.SentinelClient', + 'CONNECTION_FACTORY': 'django_redis.pool.SentinelConnectionFactory', + 'SENTINELS': [ +{% for host in groups['valkey'] %} + ('{{ 'api' | kolla_address(host) | put_address_in_context('url') }}', {{ valkey_sentinel_port }}), +{% endfor %} + ], + 'PASSWORD': '{{ valkey_master_password }}', + 'CONNECTION_POOL_KWARGS': { + 'retry_on_timeout': True, + }, + 'IGNORE_EXCEPTIONS': False, + } + } +} +{% elif horizon_session_cache_backend == 'memcached' %} +SESSION_ENGINE = 'django.contrib.sessions.backends.cache' +CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache', + 'LOCATION': [ +{% for host in groups['memcached'] %} + '{{ 'api' | kolla_address(host) | put_address_in_context('url') }}:{{ memcached_port }}'{% if not loop.last %},{% endif %} +{% endfor %} + ], + 'OPTIONS': { + 'ignore_exc': True, + } + } +} {% endif %} {% if kolla_enable_tls_external | bool or kolla_enable_tls_internal | bool %} @@ -35,9 +68,9 @@ OPENSTACK_API_VERSIONS = { OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = {{ horizon_keystone_multidomain | bool }} OPENSTACK_KEYSTONE_DOMAIN_DROPDOWN = {{ 'True' if horizon_keystone_domain_choices | length > 1 else 'False' }} OPENSTACK_KEYSTONE_DOMAIN_CHOICES = ( -{% for key, value in horizon_keystone_domain_choices.items() %} + {% for key, value in horizon_keystone_domain_choices.items() %} ('{{ key }}', '{{ value }}'), -{% endfor %} + {% endfor %} ) LOCAL_PATH = '/tmp' @@ -373,4 +406,3 @@ REST_API_REQUIRED_SETTINGS = [ 'OPENSTACK_KEYSTONE_BACKEND', 'OPENSTACK_KEYSTONE_DEFAULT_DOMAIN', ] - diff --git a/ansible/roles/ironic/tasks/upgrade.yml b/ansible/roles/ironic/tasks/upgrade.yml index 7303686ad8..8af59c2ee3 100644 --- a/ansible/roles/ironic/tasks/upgrade.yml +++ b/ansible/roles/ironic/tasks/upgrade.yml @@ -52,19 +52,13 @@ - name: Wait for Ironic nodes not to wait become: true - vars: - ironic_auth: - auth_url: "{{ openstack_auth.auth_url }}" - username: "{{ openstack_auth.username }}" - password: "{{ openstack_auth.password }}" - user_domain_name: "{{ openstack_auth.user_domain_name }}" - system_scope: "all" kolla_toolbox: container_engine: "{{ kolla_container_engine }}" module_name: "openstack.cloud.baremetal_node_info" module_args: region_name: "{{ openstack_region_name }}" - auth: "{{ ironic_auth }}" + auth: "{{ openstack_auth }}" + cloud: "{{ openstack_auth_cloud_system }}" interface: "{{ openstack_interface }}" cacert: "{{ openstack_cacert }}" register: ironic_nodes diff --git a/ansible/roles/keystone/defaults/main.yml b/ansible/roles/keystone/defaults/main.yml index 3727fdd3f7..bb3b352866 100644 --- a/ansible/roles/keystone/defaults/main.yml +++ b/ansible/roles/keystone/defaults/main.yml @@ -48,7 +48,7 @@ keystone_services: keystone-httpd: container_name: "keystone_httpd" group: "keystone" - enabled: "{{ enable_keystone_federation | bool }}" + enabled: "{{ enable_keystone_federation | bool and keystone_wsgi_provider == 'uwsgi' }}" image: "{{ keystone_httpd_image_full }}" volumes: "{{ keystone_httpd_default_volumes + keystone_httpd_extra_volumes }}" dimensions: "{{ keystone_httpd_dimensions }}" @@ -265,7 +265,10 @@ keystone_remote_id_attribute_oidc: "HTTP_OIDC_ISS" keystone_container_federation_oidc_metadata_folder: "{{ '/etc/apache2/metadata' if kolla_base_distro in ['debian', 'ubuntu'] else '/etc/httpd/metadata' }}" keystone_container_federation_oidc_idp_certificate_folder: "{{ '/etc/apache2/cert' if kolla_base_distro in ['debian', 'ubuntu'] else '/etc/httpd/cert' }}" keystone_container_federation_oidc_attribute_mappings_folder: "{{ container_config_directory }}/federation/oidc/attribute_maps" -keystone_host_federation_base_folder: "{{ node_config_directory }}/keystone/federation" +keystone_host_federation_base_folder: >- + {{ node_config_directory }}/{{ + 'keystone-httpd' if keystone_wsgi_provider == 'uwsgi' else 'keystone' + }}/federation keystone_host_federation_oidc_metadata_folder: "{{ keystone_host_federation_base_folder }}/oidc/metadata" keystone_host_federation_oidc_idp_certificate_folder: "{{ keystone_host_federation_base_folder }}/oidc/cert" keystone_host_federation_oidc_attribute_mappings_folder: "{{ keystone_host_federation_base_folder }}/oidc/attribute_maps" diff --git a/ansible/roles/keystone/tasks/register.yml b/ansible/roles/keystone/tasks/register.yml index c5d730b94f..cea5330c57 100644 --- a/ansible/roles/keystone/tasks/register.yml +++ b/ansible/roles/keystone/tasks/register.yml @@ -3,13 +3,15 @@ become: true ansible.builtin.command: > {{ kolla_container_engine }} exec keystone kolla_keystone_bootstrap - {{ openstack_auth.username }} {{ openstack_auth.password }} {{ openstack_auth.project_name }} - admin {{ keystone_internal_url }} {{ keystone_public_url }} {{ item }} + {{ keystone_admin_user }} {{ keystone_admin_password }} {{ keystone_admin_project }} + admin {{ keystone_internal_url }} {{ keystone_public_url }} {{ region }} register: keystone_bootstrap changed_when: (keystone_bootstrap.stdout | from_json).changed failed_when: (keystone_bootstrap.stdout | from_json).failed run_once: true - with_items: "{{ multiple_regions_names }}" + loop: "{{ multiple_regions_names }}" + loop_control: + loop_var: region - name: Register keystone service, endpoints, and users in Keystone ansible.builtin.import_role: @@ -27,6 +29,7 @@ module_args: name: "{{ keystone_default_user_role }}" auth: "{{ openstack_keystone_auth }}" + cloud: "{{ openstack_auth_cloud }}" endpoint_type: "{{ openstack_interface }}" cacert: "{{ openstack_cacert }}" region_name: "{{ openstack_region_name }}" diff --git a/ansible/roles/keystone/tasks/register_identity_providers.yml b/ansible/roles/keystone/tasks/register_identity_providers.yml index 475b8f38ad..ab00002fb2 100644 --- a/ansible/roles/keystone/tasks/register_identity_providers.yml +++ b/ansible/roles/keystone/tasks/register_identity_providers.yml @@ -1,240 +1,167 @@ --- - name: List configured attribute mappings (that can be used by IdPs) - ansible.builtin.command: > - {{ kolla_container_engine }} exec -t keystone openstack - --os-auth-url={{ openstack_auth.auth_url }} - --os-password={{ openstack_auth.password }} - --os-username={{ openstack_auth.username }} - --os-identity-api-version=3 - --os-interface={{ openstack_interface }} - --os-system-scope="all" - --os-user-domain-name={{ openstack_auth.user_domain_name }} - --os-region-name={{ openstack_region_name }} - {% if openstack_cacert != '' %}--os-cacert={{ openstack_cacert }} {% endif %} - mapping list -c ID --format value - run_once: true - changed_when: false become: true - register: existing_mappings_register - -- name: Register existing mappings - ansible.builtin.set_fact: - existing_mappings: "{{ existing_mappings_register.stdout_lines | map('trim') | list }}" + kolla_toolbox: + container_engine: "{{ kolla_container_engine }}" + module_name: openstack.cloud.federation_mapping_info + module_args: + auth: "{{ openstack_auth }}" + cloud: "{{ openstack_auth_cloud }}" + region_name: "{{ openstack_region_name }}" + interface: "{{ openstack_interface }}" + ca_cert: "{{ openstack_cacert if openstack_cacert != '' else omit }}" + run_once: true + register: existing_mappings - name: Remove unmanaged attribute mappings - changed_when: true - ansible.builtin.command: > - {{ kolla_container_engine }} exec -t keystone openstack - --os-auth-url={{ openstack_auth.auth_url }} - --os-password={{ openstack_auth.password }} - --os-username={{ openstack_auth.username }} - --os-identity-api-version=3 - --os-interface={{ openstack_interface }} - --os-user-domain-name={{ openstack_auth.user_domain_name }} - --os-system-scope="all" - --os-region-name={{ openstack_region_name }} - {% if openstack_cacert != '' %}--os-cacert={{ openstack_cacert }} {% endif %} - mapping delete {{ item }} - run_once: true become: true - with_items: "{{ existing_mappings }}" + kolla_toolbox: + container_engine: "{{ kolla_container_engine }}" + module_name: openstack.cloud.federation_mapping + module_args: + auth: "{{ openstack_auth }}" + cloud: "{{ openstack_auth_cloud }}" + region_name: "{{ openstack_region_name }}" + interface: "{{ openstack_interface }}" + ca_cert: "{{ openstack_cacert if openstack_cacert != '' else omit }}" + name: "{{ item.name }}" + state: absent + run_once: true + with_items: "{{ existing_mappings.mappings }}" when: - - item not in (keystone_identity_mappings | map(attribute='name') | list) + - item.name not in (keystone_identity_mappings | map(attribute='name') | list) - keystone_should_remove_attribute_mappings - name: Create unexisting domains become: true - changed_when: true kolla_toolbox: container_engine: "{{ kolla_container_engine }}" - module_name: "os_keystone_domain" + module_name: "openstack.cloud.identity_domain" module_args: - name: "{{ item.openstack_domain }}" auth: "{{ openstack_auth }}" - endpoint_type: "{{ openstack_interface }}" - cacert: "{{ openstack_cacert }}" + cloud: "{{ openstack_auth_cloud }}" region_name: "{{ openstack_region_name }}" + interface: "{{ openstack_interface }}" + ca_cert: "{{ openstack_cacert if openstack_cacert != '' else omit }}" + name: "{{ item.openstack_domain }}" + state: present run_once: true with_items: "{{ keystone_identity_providers }}" - name: Register attribute mappings in OpenStack become: true - changed_when: true - ansible.builtin.command: > - {{ kolla_container_engine }} exec -t keystone openstack - --os-auth-url={{ openstack_auth.auth_url }} - --os-password={{ openstack_auth.password }} - --os-username={{ openstack_auth.username }} - --os-identity-api-version=3 - --os-interface {{ openstack_interface }} - --os-system-scope="all" - --os-user-domain-name={{ openstack_auth.user_domain_name }} - --os-region-name={{ openstack_region_name }} - {% if openstack_cacert != '' %}--os-cacert={{ openstack_cacert }} {% endif %} - mapping create - --rules "{{ keystone_container_federation_oidc_attribute_mappings_folder }}/{{ item.file | basename }}" - {{ item.name }} - run_once: true - when: - - item.name not in existing_mappings - with_items: "{{ keystone_identity_mappings }}" - -- name: Update existing attribute mappings in OpenStack - become: true - changed_when: true - ansible.builtin.command: > - {{ kolla_container_engine }} exec -t keystone openstack - --os-auth-url={{ openstack_auth.auth_url }} - --os-password={{ openstack_auth.password }} - --os-username={{ openstack_auth.username }} - --os-identity-api-version=3 - --os-interface={{ openstack_interface }} - --os-system-scope="all" - --os-user-domain-name={{ openstack_auth.user_domain_name }} - --os-region-name={{ openstack_region_name }} - {% if openstack_cacert != '' %}--os-cacert={{ openstack_cacert }} {% endif %} - mapping set - --rules="{{ keystone_container_federation_oidc_attribute_mappings_folder }}/{{ item.file | basename }}" - {{ item.name }} + kolla_toolbox: + container_engine: "{{ kolla_container_engine }}" + module_name: openstack.cloud.federation_mapping + module_args: + auth: "{{ openstack_auth }}" + cloud: "{{ openstack_auth_cloud }}" + region_name: "{{ openstack_region_name }}" + interface: "{{ openstack_interface }}" + ca_cert: "{{ openstack_cacert if openstack_cacert != '' else omit }}" + name: "{{ item.name }}" + rules: "{{ '{{ keystone_identity_mapping_rules | from_json }}' }}" + state: present + module_extra_vars: + keystone_identity_mapping_rules: "{{ lookup('ansible.builtin.file', item.file) }}" run_once: true - when: - - item.name in existing_mappings with_items: "{{ keystone_identity_mappings }}" - name: List configured IdPs become: true - ansible.builtin.command: > - {{ kolla_container_engine }} exec -t keystone openstack - --os-auth-url={{ openstack_auth.auth_url }} - --os-password={{ openstack_auth.password }} - --os-username={{ openstack_auth.username }} - --os-identity-api-version=3 - --os-interface={{ openstack_interface }} - --os-system-scope="all" - --os-user-domain-name={{ openstack_auth.user_domain_name }} - --os-region-name={{ openstack_region_name }} - {% if openstack_cacert != '' %}--os-cacert={{ openstack_cacert }} {% endif %} - identity provider list -c ID --format value + kolla_toolbox: + container_engine: "{{ kolla_container_engine }}" + module_name: openstack.cloud.federation_idp_info + module_args: + auth: "{{ openstack_auth }}" + cloud: "{{ openstack_auth_cloud }}" + region_name: "{{ openstack_region_name }}" + interface: "{{ openstack_interface }}" + ca_cert: "{{ openstack_cacert if openstack_cacert != '' else omit }}" run_once: true - changed_when: false - register: existing_idps_register - -- name: Register existing idps - ansible.builtin.set_fact: - existing_idps: "{{ existing_idps_register.stdout.split('\n') | map('trim') | list }}" + register: existing_idps - name: Remove unmanaged identity providers become: true - changed_when: true - ansible.builtin.command: > - {{ kolla_container_engine }} exec -t keystone openstack - --os-auth-url={{ openstack_auth.auth_url }} - --os-password={{ openstack_auth.password }} - --os-username={{ openstack_auth.username }} - --os-identity-api-version=3 - --os-interface={{ openstack_interface }} - --os-system-scope="all" - --os-user-domain-name={{ openstack_auth.user_domain_name }} - --os-region-name={ openstack_region_name }} - {% if openstack_cacert != '' %}--os-cacert={{ openstack_cacert }}{% endif %} - identity provider delete {{ item }} + kolla_toolbox: + container_engine: "{{ kolla_container_engine }}" + module_name: openstack.cloud.federation_idp + module_args: + auth: "{{ openstack_auth }}" + cloud: "{{ openstack_auth_cloud }}" + region_name: "{{ openstack_region_name }}" + interface: "{{ openstack_interface }}" + ca_cert: "{{ openstack_cacert if openstack_cacert != '' else omit }}" + name: "{{ item.name }}" + state: absent run_once: true - with_items: "{{ existing_idps }}" + with_items: "{{ existing_idps.identity_providers }}" when: - - item not in (keystone_identity_providers | map(attribute='name') | list) + - item.name not in (keystone_identity_providers | map(attribute='name') | list) - keystone_should_remove_identity_providers -- name: Register Identity Providers in OpenStack +- name: Gather Identity Domains information become: true - changed_when: true - ansible.builtin.command: > - {{ kolla_container_engine }} exec -t keystone openstack - --os-auth-url={{ openstack_auth.auth_url }} - --os-password={{ openstack_auth.password }} - --os-username={{ openstack_auth.username }} - --os-identity-api-version=3 - --os-interface={{ openstack_interface }} - --os-system-scope="all" - --os-user-domain-name={{ openstack_auth.user_domain_name }} - --os-region-name={{ openstack_region_name }} - {% if openstack_cacert != '' %}--os-cacert={{ openstack_cacert }}{% endif %} - identity provider create - --description "{{ item.public_name }}" - --remote-id "{{ item.identifier }}" - --domain "{{ item.openstack_domain }}" - {{ item.name }} + kolla_toolbox: + container_engine: "{{ kolla_container_engine }}" + module_name: openstack.cloud.identity_domain_info + module_args: + auth: "{{ openstack_auth }}" + cloud: "{{ openstack_auth_cloud }}" + region_name: "{{ openstack_region_name }}" + interface: "{{ openstack_interface }}" + ca_cert: "{{ openstack_cacert if openstack_cacert != '' else omit }}" run_once: true - when: - - item.name not in existing_idps - with_items: "{{ keystone_identity_providers }}" + register: existing_identity_domains -- name: Update Identity Providers in OpenStack according to Kolla-Ansible configurations - become: true - changed_when: true - ansible.builtin.command: > - {{ kolla_container_engine }} exec -t keystone openstack - --os-auth-url={{ openstack_auth.auth_url }} - --os-password={{ openstack_auth.password }} - --os-username={{ openstack_auth.username }} - --os-identity-api-version=3 - --os-interface {{ openstack_interface }} - --os-system-scope "all" - --os-user-domain-name {{ openstack_auth.user_domain_name }} - --os-region-name {{ openstack_region_name }} - {% if openstack_cacert != '' %}--os-cacert {{ openstack_cacert }} {% endif %} - identity provider set - --description "{{ item.public_name }}" - --remote-id "{{ item.identifier }}" - "{{ item.name }}" +- name: Verify that required Identity Domains exist + ansible.builtin.fail: + msg: > + Domain "{{ item.openstack_domain }}" was not found in OpenStack. + Please create it first or check your keystone_identity_providers configuration. run_once: true - when: - - item.name in existing_idps - with_items: "{{ keystone_identity_providers }}" + loop: "{{ keystone_identity_providers }}" + when: > + existing_identity_domains.domains | + selectattr('name', 'equalto', item.openstack_domain) | + list | length == 0 -- name: Configure attribute mappings for each Identity Provider. (We expect the mappings to be configured by the operator) +- name: Register Identity Providers in OpenStack become: true - changed_when: true - ansible.builtin.command: > - {{ kolla_container_engine }} exec -t keystone openstack - --os-auth-url={{ openstack_auth.auth_url }} - --os-password={{ openstack_auth.password }} - --os-username={{ openstack_auth.username }} - --os-identity-api-version=3 - --os-interface={{ openstack_interface }} - --os-system-scope="all" - --os-user-domain-name={{ openstack_auth.user_domain_name }} - --os-region-name={{ openstack_region_name }} - {% if openstack_cacert != '' %}--os-cacert={{ openstack_cacert }}{% endif %} - federation protocol create - --mapping {{ item.attribute_mapping }} - --identity-provider {{ item.name }} - {{ item.protocol }} + kolla_toolbox: + container_engine: "{{ kolla_container_engine }}" + module_name: openstack.cloud.federation_idp + module_args: + auth: "{{ openstack_auth }}" + cloud: "{{ openstack_auth_cloud }}" + region_name: "{{ openstack_region_name }}" + interface: "{{ openstack_interface }}" + ca_cert: "{{ openstack_cacert if openstack_cacert != '' else omit }}" + description: "{{ item.public_name }}" + remote_ids: "{{ '{{ keystone_identity_provider_remote_ids | from_json }}' }}" + domain_id: "{{ existing_identity_domains.domains | selectattr('name', 'equalto', item.openstack_domain) | map(attribute='id') | first }}" + name: "{{ item.name }}" + is_enabled: true + state: present + module_extra_vars: + keystone_identity_provider_remote_ids: "{{ [item.identifier] | to_json }}" run_once: true - when: - - item.name not in existing_idps with_items: "{{ keystone_identity_providers }}" -- name: Update attribute mappings for each Identity Provider. (We expect the mappings to be configured by the operator). +- name: Configure attribute mappings for each Identity Provider. (We expect the mappings to be configured by the operator) become: true - changed_when: true - ansible.builtin.command: > - {{ kolla_container_engine }} exec -t keystone openstack - --os-auth-url={{ openstack_auth.auth_url }} - --os-password={{ openstack_auth.password }} - --os-username={{ openstack_auth.username }} - --os-identity-api-version=3 - --os-interface={{ openstack_interface }} - --os-system-scope="all" - --os-user-domain-name={{ openstack_auth.user_domain_name }} - --os-region-name={{ openstack_region_name }} - {% if openstack_cacert != '' %}--os-cacert={{ openstack_cacert }}{% endif %} - federation protocol set - --identity-provider {{ item.name }} - --mapping {{ item.attribute_mapping }} - {{ item.protocol }} + kolla_toolbox: + container_engine: "{{ kolla_container_engine }}" + module_name: openstack.cloud.keystone_federation_protocol + module_args: + auth: "{{ openstack_auth }}" + cloud: "{{ openstack_auth_cloud }}" + region_name: "{{ openstack_region_name }}" + interface: "{{ openstack_interface }}" + ca_cert: "{{ openstack_cacert if openstack_cacert != '' else omit }}" + idp: "{{ item.name }}" + mapping: "{{ item.attribute_mapping }}" + name: "{{ item.protocol }}" + state: present run_once: true - register: result - failed_when: result.rc not in [0, 1] # This command returns RC 1 on success, so we need to add this to avoid fails. - when: - - item.name in existing_idps with_items: "{{ keystone_identity_providers }}" diff --git a/ansible/roles/keystone/templates/keystone-httpd.json.j2 b/ansible/roles/keystone/templates/keystone-httpd.json.j2 index b82376afce..e16cf98be1 100644 --- a/ansible/roles/keystone/templates/keystone-httpd.json.j2 +++ b/ansible/roles/keystone/templates/keystone-httpd.json.j2 @@ -36,6 +36,12 @@ "owner": "{{ apache_user }}:{{ apache_user }}", "perm": "0600", "merge": true + }, + { + "source": "{{ container_config_directory }}/federation/modoidc-error-page.html", + "dest": "/var/www/html/modoidc-error-page.html", + "owner": "{{ apache_user }}:{{ apache_user }}", + "perm": "0600" }{% endif %}{% if kolla_copy_ca_into_containers | bool %}, { "source": "{{ container_config_directory }}/ca-certificates", diff --git a/ansible/roles/keystone/templates/keystone.json.j2 b/ansible/roles/keystone/templates/keystone.json.j2 index dda23b82b4..a4cf8b7fa5 100644 --- a/ansible/roles/keystone/templates/keystone.json.j2 +++ b/ansible/roles/keystone/templates/keystone.json.j2 @@ -58,7 +58,7 @@ "dest": "/etc/keystone/certs/keystone-key.pem", "owner": "keystone", "perm": "0600" - }{% endif %}{% if keystone_enable_federation_openid | bool %}, + }{% endif %}{% if keystone_enable_federation_openid | bool and keystone_wsgi_provider == 'apache' %}, { "source": "{{ container_config_directory }}/federation/oidc/metadata", "dest": "{{ keystone_container_federation_oidc_metadata_folder }}", @@ -95,7 +95,7 @@ { "path": "/var/log/kolla/keystone/keystone.log", "owner": "keystone:keystone" - },{% if keystone_enable_federation_openid | bool %} + },{% if keystone_enable_federation_openid | bool and keystone_wsgi_provider == 'apache' %} { "path": "{{ keystone_container_federation_oidc_metadata_folder }}", "owner": "{{ apache_user }}:{{ apache_user }}", diff --git a/ansible/roles/common/defaults/main.yml b/ansible/roles/kolla_toolbox/defaults/main.yml similarity index 86% rename from ansible/roles/common/defaults/main.yml rename to ansible/roles/kolla_toolbox/defaults/main.yml index cf1a1485e0..534377b1f8 100644 --- a/ansible/roles/common/defaults/main.yml +++ b/ansible/roles/kolla_toolbox/defaults/main.yml @@ -1,8 +1,8 @@ --- -common_services: +kolla_toolbox_services: kolla-toolbox: container_name: kolla_toolbox - group: kolla-toolbox + group: kolla_toolbox enabled: true image: "{{ kolla_toolbox_image_full }}" environment: @@ -16,12 +16,10 @@ common_services: #################### # Docker #################### -common_tag: "{{ openstack_tag }}" - kolla_toolbox_dimensions: "{{ default_container_dimensions }}" kolla_toolbox_image: "{{ docker_image_url }}kolla-toolbox" -kolla_toolbox_tag: "{{ common_tag }}" +kolla_toolbox_tag: "{{ openstack_tag }}" kolla_toolbox_image_full: "{{ kolla_toolbox_image }}:{{ kolla_toolbox_tag }}" kolla_toolbox_default_volumes: @@ -35,4 +33,4 @@ kolla_toolbox_extra_volumes: "{{ default_extra_volumes }}" ################### # Copy certificates ################### -common_copy_certs: "{{ kolla_copy_ca_into_containers | bool }}" +kolla_toolbox_copy_certs: "{{ kolla_copy_ca_into_containers | bool }}" diff --git a/ansible/roles/common/handlers/main.yml b/ansible/roles/kolla_toolbox/handlers/main.yml similarity index 76% rename from ansible/roles/common/handlers/main.yml rename to ansible/roles/kolla_toolbox/handlers/main.yml index c0d148d5fc..73db9be9de 100644 --- a/ansible/roles/common/handlers/main.yml +++ b/ansible/roles/kolla_toolbox/handlers/main.yml @@ -2,7 +2,7 @@ - name: Restart kolla-toolbox container vars: service_name: "kolla-toolbox" - service: "{{ common_services[service_name] }}" + service: "{{ kolla_toolbox_services[service_name] }}" become: true kolla_container: action: "recreate_or_restart_container" @@ -17,6 +17,9 @@ - Initializing toolbox container using normal user - name: Initializing toolbox container using normal user + vars: + service_name: "kolla-toolbox" + service: "{{ kolla_toolbox_services[service_name] }}" become: true - ansible.builtin.command: "{{ kolla_container_engine }} exec -t {{ common_services['kolla-toolbox']['container_name'] }} ansible --version" + ansible.builtin.command: "{{ kolla_container_engine }} exec -t {{ service['container_name'] }} ansible --version" changed_when: false diff --git a/ansible/roles/common/tasks/bootstrap.yml b/ansible/roles/kolla_toolbox/tasks/bootstrap.yml similarity index 100% rename from ansible/roles/common/tasks/bootstrap.yml rename to ansible/roles/kolla_toolbox/tasks/bootstrap.yml diff --git a/ansible/roles/common/tasks/check-containers.yml b/ansible/roles/kolla_toolbox/tasks/check-containers.yml similarity index 64% rename from ansible/roles/common/tasks/check-containers.yml rename to ansible/roles/kolla_toolbox/tasks/check-containers.yml index b450a891db..3f08716d8c 100644 --- a/ansible/roles/common/tasks/check-containers.yml +++ b/ansible/roles/kolla_toolbox/tasks/check-containers.yml @@ -1,4 +1,4 @@ --- -- name: Check common containers +- name: Check kolla_toolbox containers ansible.builtin.import_role: name: service-check-containers diff --git a/ansible/roles/common/tasks/check.yml b/ansible/roles/kolla_toolbox/tasks/check.yml similarity index 58% rename from ansible/roles/common/tasks/check.yml rename to ansible/roles/kolla_toolbox/tasks/check.yml index ea907300a1..9e77943a3a 100644 --- a/ansible/roles/common/tasks/check.yml +++ b/ansible/roles/kolla_toolbox/tasks/check.yml @@ -1,4 +1,4 @@ --- -- name: Checking Common containers +- name: Checking kolla_toolbox containers ansible.builtin.import_role: role: service-check diff --git a/ansible/roles/common/tasks/config.yml b/ansible/roles/kolla_toolbox/tasks/config.yml similarity index 69% rename from ansible/roles/common/tasks/config.yml rename to ansible/roles/kolla_toolbox/tasks/config.yml index aa962fc661..2672f9b082 100644 --- a/ansible/roles/common/tasks/config.yml +++ b/ansible/roles/kolla_toolbox/tasks/config.yml @@ -1,26 +1,21 @@ --- - name: Ensuring config directories exist vars: - service_name: "{{ item.0.service_name }}" - service: "{{ common_services[service_name] }}" + service_name: "kolla-toolbox" + service: "{{ kolla_toolbox_services[service_name] }}" ansible.builtin.file: - path: "{{ node_config_directory }}/{{ item.1 }}" + path: "{{ node_config_directory }}/{{ service_name }}" state: "directory" owner: "{{ config_owner_user }}" group: "{{ config_owner_group }}" mode: "0770" become: true - with_subelements: - - - service_name: "kolla-toolbox" - paths: - - "kolla-toolbox" - - paths when: service | service_enabled_and_mapped_to_host - name: Copying over TLS certificates ansible.builtin.include_tasks: copy-certs.yml when: - - common_copy_certs | bool + - kolla_toolbox_copy_certs | bool - name: Copying over config.json files for services ansible.builtin.template: @@ -28,7 +23,7 @@ dest: "{{ node_config_directory }}/{{ item.key }}/config.json" mode: "0660" become: true - with_dict: "{{ common_services | select_services_enabled_and_mapped_to_host }}" + with_dict: "{{ kolla_toolbox_services | select_services_enabled_and_mapped_to_host }}" - name: Ensure RabbitMQ Erlang cookie exists become: true @@ -37,7 +32,7 @@ dest: "{{ node_config_directory }}/kolla-toolbox/rabbitmq-erlang.cookie" mode: "0660" when: - - common_services['kolla-toolbox'] | service_enabled_and_mapped_to_host + - kolla_toolbox_services['kolla-toolbox'] | service_enabled_and_mapped_to_host - enable_rabbitmq | bool - name: Ensuring config directories have correct owner and permission @@ -48,9 +43,7 @@ group: "{{ config_owner_group }}" mode: "0770" ignore_errors: "{{ ansible_check_mode }}" - when: - - item.key != "kolla-toolbox" - with_dict: "{{ common_services | select_services_enabled_and_mapped_to_host }}" + with_dict: "{{ kolla_toolbox_services | select_services_enabled_and_mapped_to_host }}" - name: Copy rabbitmq-env.conf to kolla toolbox ansible.builtin.template: @@ -63,7 +56,7 @@ - "rabbitmq-env.conf.j2" become: true when: - - common_services['kolla-toolbox'] | service_enabled_and_mapped_to_host + - kolla_toolbox_services['kolla-toolbox'] | service_enabled_and_mapped_to_host - enable_rabbitmq | bool - name: Copy rabbitmq erl_inetrc to kolla toolbox @@ -77,5 +70,14 @@ - "{{ node_custom_config }}/kolla-toolbox/erl_inetrc" - "erl_inetrc.j2" when: - - common_services['kolla-toolbox'] | service_enabled_and_mapped_to_host + - kolla_toolbox_services['kolla-toolbox'] | service_enabled_and_mapped_to_host - enable_rabbitmq | bool + +- name: Copy clouds.yaml to kolla toolbox + ansible.builtin.template: + src: "clouds.yaml.j2" + dest: "{{ node_config_directory }}/kolla-toolbox/clouds.yaml" + mode: "0660" + become: true + when: + - kolla_toolbox_services['kolla-toolbox'] | service_enabled_and_mapped_to_host diff --git a/ansible/roles/common/tasks/config_validate.yml b/ansible/roles/kolla_toolbox/tasks/config_validate.yml similarity index 100% rename from ansible/roles/common/tasks/config_validate.yml rename to ansible/roles/kolla_toolbox/tasks/config_validate.yml diff --git a/ansible/roles/common/tasks/copy-certs.yml b/ansible/roles/kolla_toolbox/tasks/copy-certs.yml similarity index 71% rename from ansible/roles/common/tasks/copy-certs.yml rename to ansible/roles/kolla_toolbox/tasks/copy-certs.yml index ab906e2245..3da86d9147 100644 --- a/ansible/roles/common/tasks/copy-certs.yml +++ b/ansible/roles/kolla_toolbox/tasks/copy-certs.yml @@ -3,4 +3,4 @@ ansible.builtin.import_role: role: service-cert-copy vars: - project_services: "{{ common_services }}" + project_services: "{{ kolla_toolbox_services }}" diff --git a/ansible/roles/common/tasks/deploy-containers.yml b/ansible/roles/kolla_toolbox/tasks/deploy-containers.yml similarity index 59% rename from ansible/roles/common/tasks/deploy-containers.yml rename to ansible/roles/kolla_toolbox/tasks/deploy-containers.yml index a37ddafc0b..dea81dcaf9 100644 --- a/ansible/roles/common/tasks/deploy-containers.yml +++ b/ansible/roles/kolla_toolbox/tasks/deploy-containers.yml @@ -1,3 +1,3 @@ --- -- name: Check common containers +- name: Check kolla_toolbox containers ansible.builtin.import_tasks: check-containers.yml diff --git a/ansible/roles/common/tasks/deploy.yml b/ansible/roles/kolla_toolbox/tasks/deploy.yml similarity index 65% rename from ansible/roles/common/tasks/deploy.yml rename to ansible/roles/kolla_toolbox/tasks/deploy.yml index df6770fab7..a7a9bf2e17 100644 --- a/ansible/roles/common/tasks/deploy.yml +++ b/ansible/roles/kolla_toolbox/tasks/deploy.yml @@ -1,11 +1,11 @@ --- -- name: Configure common +- name: Configure kolla_toolbox ansible.builtin.import_tasks: config.yml -- name: Check common containers +- name: Check kolla_toolbox containers ansible.builtin.import_tasks: check-containers.yml -- name: Bootstrap common service +- name: Bootstrap kolla_toolbox service ansible.builtin.import_tasks: bootstrap.yml - name: Flush handlers diff --git a/ansible/roles/common/tasks/main.yml b/ansible/roles/kolla_toolbox/tasks/main.yml similarity index 100% rename from ansible/roles/common/tasks/main.yml rename to ansible/roles/kolla_toolbox/tasks/main.yml diff --git a/ansible/roles/common/tasks/precheck.yml b/ansible/roles/kolla_toolbox/tasks/precheck.yml similarity index 50% rename from ansible/roles/common/tasks/precheck.yml rename to ansible/roles/kolla_toolbox/tasks/precheck.yml index d3b4b6440f..98a02793ec 100644 --- a/ansible/roles/common/tasks/precheck.yml +++ b/ansible/roles/kolla_toolbox/tasks/precheck.yml @@ -1,7 +1,7 @@ --- -- name: Precheck common configuration +- name: Precheck kolla_toolbox configuration ansible.builtin.import_role: name: service-precheck vars: - service_precheck_services: "{{ common_services }}" + service_precheck_services: "{{ kolla_toolbox_services }}" service_name: "{{ project_name }}" diff --git a/ansible/roles/common/tasks/pull.yml b/ansible/roles/kolla_toolbox/tasks/pull.yml similarity index 65% rename from ansible/roles/common/tasks/pull.yml rename to ansible/roles/kolla_toolbox/tasks/pull.yml index ae366b2984..12baee1a8a 100644 --- a/ansible/roles/common/tasks/pull.yml +++ b/ansible/roles/kolla_toolbox/tasks/pull.yml @@ -1,4 +1,4 @@ --- -- name: Pull common images +- name: Pull kolla_toolbox images ansible.builtin.import_role: role: service-images-pull diff --git a/ansible/roles/common/tasks/reconfigure.yml b/ansible/roles/kolla_toolbox/tasks/reconfigure.yml similarity index 61% rename from ansible/roles/common/tasks/reconfigure.yml rename to ansible/roles/kolla_toolbox/tasks/reconfigure.yml index 36714ba9f9..8d3a74904c 100644 --- a/ansible/roles/common/tasks/reconfigure.yml +++ b/ansible/roles/kolla_toolbox/tasks/reconfigure.yml @@ -1,3 +1,3 @@ --- -- name: Deploy common +- name: Deploy kolla_toolbox ansible.builtin.import_tasks: deploy.yml diff --git a/ansible/roles/common/tasks/stop.yml b/ansible/roles/kolla_toolbox/tasks/stop.yml similarity index 53% rename from ansible/roles/common/tasks/stop.yml rename to ansible/roles/kolla_toolbox/tasks/stop.yml index ead296fade..336f44a019 100644 --- a/ansible/roles/common/tasks/stop.yml +++ b/ansible/roles/kolla_toolbox/tasks/stop.yml @@ -1,7 +1,7 @@ --- -- name: Stop common containers +- name: Stop kolla_toolbox containers ansible.builtin.import_role: name: service-stop vars: - project_services: "{{ common_services }}" + project_services: "{{ kolla_toolbox_services }}" service_name: "{{ project_name }}" diff --git a/ansible/roles/common/tasks/upgrade.yml b/ansible/roles/kolla_toolbox/tasks/upgrade.yml similarity index 69% rename from ansible/roles/common/tasks/upgrade.yml rename to ansible/roles/kolla_toolbox/tasks/upgrade.yml index fde501e3d3..56b1cdeafd 100644 --- a/ansible/roles/common/tasks/upgrade.yml +++ b/ansible/roles/kolla_toolbox/tasks/upgrade.yml @@ -1,8 +1,8 @@ --- -- name: Configure common +- name: Configure kolla_toolbox ansible.builtin.import_tasks: config.yml -- name: Check common containers +- name: Check kolla_toolbox containers ansible.builtin.import_tasks: check-containers.yml - name: Flush handlers diff --git a/ansible/roles/kolla_toolbox/templates/clouds.yaml.j2 b/ansible/roles/kolla_toolbox/templates/clouds.yaml.j2 new file mode 100644 index 0000000000..1cacc7d55d --- /dev/null +++ b/ansible/roles/kolla_toolbox/templates/clouds.yaml.j2 @@ -0,0 +1,57 @@ +clouds: + kolla-admin: + auth: + auth_url: {{ keystone_public_url }} + project_domain_name: {{ default_project_domain_name }} + user_domain_name: {{ default_user_domain_name }} + project_name: {{ keystone_admin_project }} + username: {{ keystone_admin_user }} + region_name: {{ openstack_region_name }} +{% if kolla_admin_openrc_cacert is not none and kolla_admin_openrc_cacert | length > 0 %} + cacert: {{ kolla_admin_openrc_cacert }} +{% endif %} + kolla-admin-system: + auth: + auth_url: {{ keystone_public_url }} + user_domain_name: {{ default_user_domain_name }} + system_scope: all + username: {{ keystone_admin_user }} + region_name: {{ openstack_region_name }} +{% if kolla_admin_openrc_cacert is not none and kolla_admin_openrc_cacert | length > 0 %} + cacert: {{ kolla_admin_openrc_cacert }} +{% endif %} + kolla-admin-internal: + auth: + auth_url: {{ keystone_internal_url }} + project_domain_name: {{ default_project_domain_name }} + user_domain_name: {{ default_user_domain_name }} + project_name: {{ keystone_admin_project }} + username: {{ keystone_admin_user }} + interface: internal + region_name: {{ openstack_region_name }} +{% if kolla_admin_openrc_cacert is not none and kolla_admin_openrc_cacert | length > 0 %} + cacert: {{ kolla_admin_openrc_cacert }} +{% endif %} + kolla-admin-system-internal: + auth: + auth_url: {{ keystone_internal_url }} + user_domain_name: {{ default_user_domain_name }} + system_scope: all + username: {{ keystone_admin_user }} + interface: internal + region_name: {{ openstack_region_name }} +{% if kolla_admin_openrc_cacert is not none and kolla_admin_openrc_cacert | length > 0 %} + cacert: {{ kolla_admin_openrc_cacert }} +{% endif %} + kolla-octavia-internal: + auth: + auth_url: {{ keystone_internal_url }} + project_domain_name: {{ default_project_domain_name }} + user_domain_name: {{ default_user_domain_name }} + project_name: {{ octavia_service_auth_project }} + username: octavia + interface: internal + region_name: {{ openstack_region_name }} +{% if kolla_admin_openrc_cacert is not none and kolla_admin_openrc_cacert | length > 0 %} + cacert: {{ kolla_admin_openrc_cacert }} +{% endif %} diff --git a/ansible/roles/common/templates/erl_inetrc.j2 b/ansible/roles/kolla_toolbox/templates/erl_inetrc.j2 similarity index 100% rename from ansible/roles/common/templates/erl_inetrc.j2 rename to ansible/roles/kolla_toolbox/templates/erl_inetrc.j2 diff --git a/ansible/roles/kolla_toolbox/templates/kolla-toolbox.json.j2 b/ansible/roles/kolla_toolbox/templates/kolla-toolbox.json.j2 new file mode 100644 index 0000000000..712a4782e3 --- /dev/null +++ b/ansible/roles/kolla_toolbox/templates/kolla-toolbox.json.j2 @@ -0,0 +1,48 @@ +{ + "command": "kolla_toolbox", + "config_files": [ + { + "source": "{{ container_config_directory }}/clouds.yaml", + "dest": "/var/lib/ansible/.config/openstack/clouds.yaml", + "owner": "ansible", + "perm": "0600" + }{% if enable_rabbitmq | bool %}, + { + "source": "{{ container_config_directory }}/rabbitmq-erlang.cookie", + "dest": "/var/lib/rabbitmq/.erlang.cookie", + "owner": "rabbitmq", + "perm": "0600" + }, + { + "source": "{{ container_config_directory }}/rabbitmq-env.conf", + "dest": "/etc/rabbitmq/rabbitmq-env.conf", + "owner": "rabbitmq", + "perm": "0600" + }, + { + "source": "{{ container_config_directory }}/erl_inetrc", + "dest": "/etc/rabbitmq/erl_inetrc", + "owner": "rabbitmq", + "perm": "0600" + }, + { + "source": "{{ container_config_directory }}/clouds.yaml", + "dest": "/var/lib/ansible/.config/openstack/clouds.yaml", + "owner": "ansible", + "perm": "0600" + }{% 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/ansible.log", + "perm": "0664", + "owner": "ansible:kolla" + } + ] +} diff --git a/ansible/roles/common/templates/rabbitmq-env.conf.j2 b/ansible/roles/kolla_toolbox/templates/rabbitmq-env.conf.j2 similarity index 100% rename from ansible/roles/common/templates/rabbitmq-env.conf.j2 rename to ansible/roles/kolla_toolbox/templates/rabbitmq-env.conf.j2 diff --git a/ansible/roles/common/templates/rabbitmq-erlang.cookie.j2 b/ansible/roles/kolla_toolbox/templates/rabbitmq-erlang.cookie.j2 similarity index 100% rename from ansible/roles/common/templates/rabbitmq-erlang.cookie.j2 rename to ansible/roles/kolla_toolbox/templates/rabbitmq-erlang.cookie.j2 diff --git a/ansible/roles/kolla_toolbox/vars/main.yml b/ansible/roles/kolla_toolbox/vars/main.yml new file mode 100644 index 0000000000..6c6d367e26 --- /dev/null +++ b/ansible/roles/kolla_toolbox/vars/main.yml @@ -0,0 +1,2 @@ +--- +project_name: "kolla_toolbox" diff --git a/ansible/roles/magnum/tasks/register.yml b/ansible/roles/magnum/tasks/register.yml index b36c7d762a..dfe99761a6 100644 --- a/ansible/roles/magnum/tasks/register.yml +++ b/ansible/roles/magnum/tasks/register.yml @@ -16,6 +16,7 @@ name: "{{ magnum_trustee_domain }}" description: "Owns users and projects created by magnum" auth: "{{ openstack_magnum_auth }}" + cloud: "{{ openstack_auth_cloud }}" endpoint_type: "{{ openstack_interface }}" cacert: "{{ openstack_cacert }}" region_name: "{{ openstack_region_name }}" @@ -33,6 +34,7 @@ password: "{{ magnum_keystone_password }}" update_password: "{{ 'always' if update_keystone_service_user_passwords | bool else 'on_create' }}" auth: "{{ openstack_magnum_auth }}" + cloud: "{{ openstack_auth_cloud }}" endpoint_type: "{{ openstack_interface }}" cacert: "{{ openstack_cacert }}" region_name: "{{ openstack_region_name }}" @@ -48,6 +50,7 @@ user: "{{ magnum_trustee_domain_admin }}" role: "admin" auth: "{{ openstack_magnum_auth }}" + cloud: "{{ openstack_auth_cloud }}" endpoint_type: "{{ openstack_interface }}" cacert: "{{ openstack_cacert }}" region_name: "{{ openstack_region_name }}" diff --git a/ansible/roles/neutron/defaults/main.yml b/ansible/roles/neutron/defaults/main.yml index 0518e3d8d3..206320a24d 100644 --- a/ansible/roles/neutron/defaults/main.yml +++ b/ansible/roles/neutron/defaults/main.yml @@ -215,6 +215,29 @@ neutron_services: volumes: "{{ neutron_ovn_agent_default_volumes + neutron_ovn_agent_extra_volumes }}" dimensions: "{{ neutron_ovn_agent_dimensions }}" healthcheck: "{{ neutron_ovn_agent_healthcheck }}" + neutron-ovn-vpn-agent: + container_name: "neutron_ovn_vpn_agent" + image: "{{ neutron_ovn_vpn_agent_image_full }}" + privileged: false + cgroupns_mode: "private" + pid_mode: "host" + cap_add: + - NET_ADMIN + - SYS_ADMIN + - SYS_PTRACE + - DAC_OVERRIDE + - DAC_READ_SEARCH + - SETPCAP + security_opt: + - "apparmor=unconfined" + - "seccomp=unconfined" + - "label=disable" + enabled: "{{ enable_neutron_vpnaas | bool and neutron_plugin_agent == 'ovn' }}" + group: neutron-ovn-vpn-agent + host_in_groups: "{{ inventory_hostname in groups['neutron-ovn-vpn-agent'] }}" + volumes: "{{ neutron_ovn_vpn_agent_default_volumes + neutron_ovn_vpn_agent_extra_volumes }}" + dimensions: "{{ neutron_ovn_vpn_agent_dimensions }}" + healthcheck: "{{ neutron_ovn_vpn_agent_healthcheck }}" #################### # Config Validate @@ -339,6 +362,10 @@ neutron_ovn_agent_image: "{{ docker_image_url }}neutron-ovn-agent" neutron_ovn_agent_tag: "{{ neutron_tag }}" neutron_ovn_agent_image_full: "{{ neutron_ovn_agent_image }}:{{ neutron_ovn_agent_tag }}" +neutron_ovn_vpn_agent_image: "{{ docker_image_url }}neutron-ovn-vpn-agent" +neutron_ovn_vpn_agent_tag: "{{ neutron_tag }}" +neutron_ovn_vpn_agent_image_full: "{{ neutron_ovn_vpn_agent_image }}:{{ neutron_ovn_vpn_agent_tag }}" + neutron_agent_dimensions: "{{ default_container_dimensions }}" neutron_dhcp_agent_dimensions: "{{ neutron_agent_dimensions }}" @@ -358,6 +385,7 @@ neutron_ovn_agent_dimensions: "{{ neutron_agent_dimensions }}" neutron_ovn_maintenance_worker_dimensions: "{{ default_container_dimensions }}" neutron_periodic_worker_dimensions: "{{ default_container_dimensions }}" neutron_rpc_server_dimensions: "{{ default_container_dimensions }}" +neutron_ovn_vpn_agent_dimensions: "{{ neutron_agent_dimensions }}" neutron_dhcp_agent_enable_healthchecks: "{{ enable_container_healthchecks }}" neutron_dhcp_agent_healthcheck_interval: "{{ default_container_healthcheck_interval }}" @@ -532,6 +560,19 @@ neutron_rpc_server_healthcheck: test: "{% if neutron_rpc_server_enable_healthchecks | bool %}{{ neutron_rpc_server_healthcheck_test }}{% else %}NONE{% endif %}" timeout: "{{ neutron_rpc_server_healthcheck_timeout }}" +neutron_ovn_vpn_agent_enable_healthchecks: "{{ enable_container_healthchecks }}" +neutron_ovn_vpn_agent_healthcheck_interval: "{{ default_container_healthcheck_interval }}" +neutron_ovn_vpn_agent_healthcheck_retries: "{{ default_container_healthcheck_retries }}" +neutron_ovn_vpn_agent_healthcheck_start_period: "{{ default_container_healthcheck_start_period }}" +neutron_ovn_vpn_agent_healthcheck_test: ["CMD-SHELL", "healthcheck_port neutron-ovn-vpn-agent {{ om_rpc_port }}"] +neutron_ovn_vpn_agent_healthcheck_timeout: "{{ default_container_healthcheck_timeout }}" +neutron_ovn_vpn_agent_healthcheck: + interval: "{{ neutron_ovn_vpn_agent_healthcheck_interval }}" + retries: "{{ neutron_ovn_vpn_agent_healthcheck_retries }}" + start_period: "{{ neutron_ovn_vpn_agent_healthcheck_start_period }}" + test: "{% if neutron_ovn_vpn_agent_enable_healthchecks | bool %}{{ neutron_ovn_vpn_agent_healthcheck_test }}{% else %}NONE{% endif %}" + timeout: "{{ neutron_ovn_vpn_agent_healthcheck_timeout }}" + neutron_dhcp_agent_default_volumes: - "{{ node_config_directory }}/neutron-dhcp-agent/:{{ container_config_directory }}/:ro" - "/etc/localtime:/etc/localtime:ro" @@ -648,6 +689,14 @@ neutron_rpc_server_default_volumes: - "/etc/localtime:/etc/localtime:ro" - "kolla_logs:/var/log/kolla/" - "{{ '/dev/shm:/dev/shm' }}" +neutron_ovn_vpn_agent_default_volumes: + - "{{ node_config_directory }}/neutron-ovn-vpn-agent/:{{ container_config_directory }}/:ro" + - "/etc/localtime:/etc/localtime:ro" + - "{{ '/etc/timezone:/etc/timezone:ro' if ansible_facts.os_family == 'Debian' else '' }}" + - "/run/netns:/run/netns:shared" + - "kolla_logs:/var/log/kolla/" + - "{{ '/dev/shm:/dev/shm' }}" + - "/bin/true:/usr/sbin/sysctl:ro" neutron_extra_volumes: "{{ default_extra_volumes }}" neutron_dhcp_agent_extra_volumes: "{{ neutron_extra_volumes }}" @@ -667,6 +716,7 @@ neutron_ovn_agent_extra_volumes: "{{ neutron_extra_volumes }}" neutron_ovn_maintenance_worker_extra_volumes: "{{ neutron_extra_volumes }}" neutron_periodic_worker_extra_volumes: "{{ neutron_extra_volumes }}" neutron_rpc_server_extra_volumes: "{{ neutron_extra_volumes }}" +neutron_ovn_vpn_agent_extra_volumes: "{{ neutron_extra_volumes }}" #################### # OpenStack @@ -787,7 +837,9 @@ service_plugins: - name: "trunk" enabled: "{{ enable_neutron_trunk | bool }}" - name: "vpnaas" - enabled: "{{ enable_neutron_vpnaas | bool }}" + enabled: "{{ enable_neutron_vpnaas | bool and neutron_plugin_agent != 'ovn' }}" + - name: "ovn-vpnaas" + enabled: "{{ enable_neutron_vpnaas | bool and neutron_plugin_agent == 'ovn' }}" - name: "port_forwarding" enabled: "{{ enable_neutron_port_forwarding | bool }}" - name: "ovn-router" diff --git a/ansible/roles/neutron/handlers/main.yml b/ansible/roles/neutron/handlers/main.yml index 2845fbce67..16e60fbad6 100644 --- a/ansible/roles/neutron/handlers/main.yml +++ b/ansible/roles/neutron/handlers/main.yml @@ -328,3 +328,24 @@ dimensions: "{{ service.dimensions }}" privileged: "{{ service.privileged | default(False) }}" healthcheck: "{{ service.healthcheck | default(omit) }}" + +- name: Restart neutron-ovn-vpn-agent container + vars: + service_name: "neutron-ovn-vpn-agent" + service: "{{ neutron_services[service_name] }}" + become: true + kolla_container: + action: "recreate_or_restart_container" + common_options: "{{ docker_common_options }}" + environment: "{{ service.environment | default(omit) }}" + name: "{{ service.container_name }}" + image: "{{ service.image }}" + user: "{{ service.user | default(omit) }}" + cap_add: "{{ service.cap_add | default(omit) }}" + security_opt: "{{ service.security_opt | default(omit) }}" + pid_mode: "{{ service.pid_mode | default(omit) }}" + cgroupns_mode: "{{ service.cgroupns_mode | default(omit) }}" + volumes: "{{ service.volumes }}" + dimensions: "{{ service.dimensions }}" + privileged: "{{ service.privileged | default(False) }}" + healthcheck: "{{ service.healthcheck | default(omit) }}" diff --git a/ansible/roles/neutron/tasks/config.yml b/ansible/roles/neutron/tasks/config.yml index 7c1a773e4d..76cf0db16a 100644 --- a/ansible/roles/neutron/tasks/config.yml +++ b/ansible/roles/neutron/tasks/config.yml @@ -77,6 +77,7 @@ - "neutron-ovn-agent" - "neutron-ovn-maintenance-worker" - "neutron-ovn-metadata-agent" + - "neutron-ovn-vpn-agent" - "neutron-periodic-worker" - "neutron-rpc-server" - "neutron-server" @@ -293,6 +294,21 @@ mode: "0660" when: service | service_enabled_and_mapped_to_host +- name: Copying over neutron_ovn_vpn_agent.ini + become: true + vars: + service_name: "neutron-ovn-vpn-agent" + service: "{{ neutron_services[service_name] }}" + merge_configs: + sources: + - "{{ role_path }}/templates/neutron_ovn_vpn_agent.ini.j2" + - "{{ node_custom_config }}/neutron/neutron_ovn_vpn_agent.ini" + dest: "{{ node_config_directory }}/{{ service_name }}/neutron_ovn_vpn_agent.ini" + mode: "0660" + when: service | service_enabled_and_mapped_to_host + notify: + - "Restart {{ service_name }} container" + - name: Copying over metering_agent.ini become: true vars: diff --git a/ansible/roles/neutron/templates/l3_agent.ini.j2 b/ansible/roles/neutron/templates/l3_agent.ini.j2 index 0422b4d246..5d17398426 100644 --- a/ansible/roles/neutron/templates/l3_agent.ini.j2 +++ b/ansible/roles/neutron/templates/l3_agent.ini.j2 @@ -10,9 +10,6 @@ agent_mode = {{ neutron_compute_dvr_mode }} {% else %} agent_mode = legacy {% endif %} -{% if enable_neutron_agent_ha | bool %} -ha_vrrp_health_check_interval = 5 -{% endif %} [agent] {% if neutron_l3_agent_extensions %} extensions = "{{ neutron_l3_agent_extensions|map(attribute='name')|join(',') }}" diff --git a/ansible/roles/neutron/templates/neutron-ovn-vpn-agent.json.j2 b/ansible/roles/neutron/templates/neutron-ovn-vpn-agent.json.j2 new file mode 100644 index 0000000000..4814642ee4 --- /dev/null +++ b/ansible/roles/neutron/templates/neutron-ovn-vpn-agent.json.j2 @@ -0,0 +1,41 @@ +{ + "command": "neutron-ovn-vpn-agent --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/neutron_ovn_vpn_agent.ini", + "config_files": [ + { + "source": "{{ container_config_directory }}/neutron.conf", + "dest": "/etc/neutron/neutron.conf", + "owner": "neutron", + "perm": "0600" + }, + { + "source": "{{ container_config_directory }}/neutron_ovn_vpn_agent.ini", + "dest": "/etc/neutron/neutron_ovn_vpn_agent.ini", + "owner": "neutron", + "perm": "0600" + } + {% if neutron_policy_file is defined %},{ + "source": "{{ container_config_directory }}/{{ neutron_policy_file }}", + "dest": "/etc/neutron/{{ neutron_policy_file }}", + "owner": "neutron", + "perm": "0600" + }{% 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/neutron", + "owner": "neutron:neutron", + "recurse": true + }, + { + "path": "/var/lib/neutron/kolla", + "owner": "neutron:neutron", + "recurse": true + } + ] +} diff --git a/ansible/roles/neutron/templates/neutron_ovn_vpn_agent.ini.j2 b/ansible/roles/neutron/templates/neutron_ovn_vpn_agent.ini.j2 new file mode 100644 index 0000000000..c2a62b97a0 --- /dev/null +++ b/ansible/roles/neutron/templates/neutron_ovn_vpn_agent.ini.j2 @@ -0,0 +1,17 @@ +{% set vpn_device_driver = 'OvnStrongSwanDriver' if kolla_base_distro in ['ubuntu', 'debian'] else 'OvnLibreSwanDriver' %} +[DEFAULT] +transport_url = {{ rpc_transport_url }} +interface_driver = neutron.agent.linux.interface.OVSInterfaceDriver + +[AGENT] +extensions = vpnaas + +[vpnagent] +vpn_device_driver = neutron_vpnaas.services.vpn.device_drivers.ovn_ipsec.{{ vpn_device_driver }} + +[ovs] +ovsdb_connection = tcp:127.0.0.1:{{ ovsdb_port }} +ovsdb_timeout = {{ ovsdb_timeout }} + +[ovn] +ovn_sb_connection = {{ ovn_sb_connection_no_relay }} diff --git a/ansible/roles/neutron/templates/neutron_vpnaas.conf.j2 b/ansible/roles/neutron/templates/neutron_vpnaas.conf.j2 index 01e2ec3358..1ad3136d7f 100644 --- a/ansible/roles/neutron/templates/neutron_vpnaas.conf.j2 +++ b/ansible/roles/neutron/templates/neutron_vpnaas.conf.j2 @@ -1,2 +1,4 @@ +{% set implementation = 'strongswan' if kolla_base_distro in ['ubuntu', 'debian'] else 'openswan' %} +{% set vpn_driver = 'VPN:' ~ implementation ~ ':neutron_vpnaas.services.vpn.service_drivers.ovn_ipsec.IPsecOvnVPNDriver:default' if neutron_plugin_agent == 'ovn' else 'VPN:openswan:neutron_vpnaas.services.vpn.service_drivers.ipsec.IPsecVPNDriver:default' %} [service_providers] -service_provider = VPN:openswan:neutron_vpnaas.services.vpn.service_drivers.ipsec.IPsecVPNDriver:default +service_provider = {{ vpn_driver }} diff --git a/ansible/roles/nova-cell/tasks/wait_discover_computes.yml b/ansible/roles/nova-cell/tasks/wait_discover_computes.yml index 90b8efa431..d930f8dea5 100644 --- a/ansible/roles/nova-cell/tasks/wait_discover_computes.yml +++ b/ansible/roles/nova-cell/tasks/wait_discover_computes.yml @@ -27,13 +27,13 @@ ansible.builtin.command: > {{ kolla_container_engine }} exec kolla_toolbox openstack --os-interface {{ openstack_interface }} - --os-auth-url {{ openstack_auth.auth_url }} - --os-project-domain-name {{ openstack_auth.domain_name }} - --os-project-name {{ openstack_auth.project_name }} - --os-username {{ openstack_auth.username }} - --os-password {{ openstack_auth.password }} + --os-auth-url {{ keystone_internal_url }} + --os-project-domain-name {{ default_project_domain_name }} + --os-project-name {{ keystone_admin_project }} + --os-username {{ keystone_admin_user }} + --os-password {{ keystone_admin_password }} --os-identity-api-version 3 - --os-user-domain-name {{ openstack_auth.user_domain_name }} + --os-user-domain-name {{ default_user_domain_name }} --os-region-name {{ openstack_region_name }} {% if openstack_cacert != '' %}--os-cacert {{ openstack_cacert }}{% endif %} compute service list --format json --column Host --service nova-compute diff --git a/ansible/roles/nova-cell/templates/nova.conf.j2 b/ansible/roles/nova-cell/templates/nova.conf.j2 index 4f5c2f88d0..2950dfcc4d 100644 --- a/ansible/roles/nova-cell/templates/nova.conf.j2 +++ b/ansible/roles/nova-cell/templates/nova.conf.j2 @@ -94,7 +94,7 @@ proxyclient_address = {{ api_interface_address }} [ironic] username = {{ ironic_keystone_user }} password = {{ ironic_keystone_password }} -auth_url = {{ openstack_auth.auth_url }} +auth_url = {{ keystone_internal_url }} cafile = {{ openstack_cacert }} auth_type = password project_name = service diff --git a/ansible/roles/octavia/defaults/main.yml b/ansible/roles/octavia/defaults/main.yml index a75ee1770a..4e53dac618 100644 --- a/ansible/roles/octavia/defaults/main.yml +++ b/ansible/roles/octavia/defaults/main.yml @@ -250,11 +250,8 @@ octavia_logging_debug: "{{ openstack_logging_debug }}" octavia_keystone_user: "octavia" -# Project that Octavia will use to interact with other services. Note that in -# Train and earlier releases this was "admin". -octavia_service_auth_project: "service" - openstack_octavia_auth: "{{ openstack_auth }}" +openstack_octavia_auth_cloud: "kolla-octavia-internal" octavia_api_workers: "{{ openstack_service_workers }}" octavia_healthmanager_health_workers: "{{ openstack_service_workers }}" @@ -314,11 +311,7 @@ octavia_loadbalancer_topology: "SINGLE" # OpenStack auth used when registering resources for Octavia. octavia_user_auth: - auth_url: "{{ keystone_internal_url }}" - username: "octavia" password: "{{ octavia_keystone_password }}" - project_name: "{{ octavia_service_auth_project }}" - domain_name: "{{ default_project_domain_name }}" # Octavia amphora flavor. # See os_nova_flavor for details. Supported parameters: diff --git a/ansible/roles/octavia/tasks/get_resources_info.yml b/ansible/roles/octavia/tasks/get_resources_info.yml index ed4a4e4e12..a93aba43a1 100644 --- a/ansible/roles/octavia/tasks/get_resources_info.yml +++ b/ansible/roles/octavia/tasks/get_resources_info.yml @@ -6,6 +6,7 @@ module_name: openstack.cloud.compute_flavor_info module_args: auth: "{{ octavia_user_auth }}" + cloud: "{{ openstack_octavia_auth_cloud }}" cacert: "{{ openstack_cacert }}" endpoint_type: "{{ openstack_interface }}" region_name: "{{ openstack_region_name }}" @@ -22,6 +23,7 @@ module_name: openstack.cloud.project_info module_args: auth: "{{ octavia_user_auth }}" + cloud: "{{ openstack_octavia_auth_cloud }}" cacert: "{{ openstack_cacert }}" endpoint_type: "{{ openstack_interface }}" region_name: "{{ openstack_region_name }}" @@ -40,6 +42,7 @@ module_name: openstack.cloud.security_group module_args: auth: "{{ octavia_user_auth }}" + cloud: "{{ openstack_octavia_auth_cloud }}" cacert: "{{ openstack_cacert }}" endpoint_type: "{{ openstack_interface }}" region_name: "{{ openstack_region_name }}" @@ -60,6 +63,7 @@ module_name: openstack.cloud.networks_info module_args: auth: "{{ octavia_user_auth }}" + cloud: "{{ openstack_octavia_auth_cloud }}" cacert: "{{ openstack_cacert }}" endpoint_type: "{{ openstack_interface }}" region_name: "{{ openstack_region_name }}" diff --git a/ansible/roles/octavia/tasks/hm-interface.yml b/ansible/roles/octavia/tasks/hm-interface.yml index 60a7561fac..82ed4b0de9 100644 --- a/ansible/roles/octavia/tasks/hm-interface.yml +++ b/ansible/roles/octavia/tasks/hm-interface.yml @@ -6,6 +6,7 @@ module_name: openstack.cloud.port module_args: auth: "{{ octavia_user_auth }}" + cloud: "{{ openstack_octavia_auth_cloud }}" cacert: "{{ openstack_cacert }}" endpoint_type: "{{ openstack_interface }}" region_name: "{{ openstack_region_name }}" @@ -26,13 +27,7 @@ port_id: "{{ port_info.port.id }}" ansible.builtin.command: > {{ kolla_container_engine }} exec kolla_toolbox openstack - --os-interface {{ openstack_interface }} - --os-auth-url {{ octavia_user_auth.auth_url }} - --os-identity-api-version 3 - --os-project-domain-name {{ octavia_user_auth.domain_name }} - --os-project-name {{ octavia_user_auth.project_name }} - --os-region-name {{ openstack_region_name }} - --os-username {{ octavia_user_auth.username }} + --os-cloud {{ openstack_octavia_auth_cloud }} --os-password {{ octavia_user_auth.password }} {% if openstack_cacert != '' %}--os-cacert {{ openstack_cacert }} {% endif %} port set --host {{ ansible_facts.nodename }} {{ port_id }} diff --git a/ansible/roles/octavia/tasks/prepare.yml b/ansible/roles/octavia/tasks/prepare.yml index 3e6ffa1a31..fb73c935e9 100644 --- a/ansible/roles/octavia/tasks/prepare.yml +++ b/ansible/roles/octavia/tasks/prepare.yml @@ -6,6 +6,7 @@ module_name: openstack.cloud.compute_flavor module_args: auth: "{{ octavia_user_auth }}" + cloud: "{{ openstack_octavia_auth_cloud }}" cacert: "{{ openstack_cacert }}" endpoint_type: "{{ openstack_interface }}" region_name: "{{ openstack_region_name }}" @@ -30,6 +31,7 @@ module_name: openstack.cloud.keypair module_args: auth: "{{ octavia_user_auth }}" + cloud: "{{ openstack_octavia_auth_cloud }}" cacert: "{{ openstack_cacert }}" endpoint_type: "{{ openstack_interface }}" region_name: "{{ openstack_region_name }}" @@ -46,6 +48,7 @@ module_name: openstack.cloud.project_info module_args: auth: "{{ octavia_user_auth }}" + cloud: "{{ openstack_octavia_auth_cloud }}" cacert: "{{ openstack_cacert }}" endpoint_type: "{{ openstack_interface }}" region_name: "{{ openstack_region_name }}" @@ -61,6 +64,7 @@ module_name: openstack.cloud.security_group module_args: auth: "{{ octavia_user_auth }}" + cloud: "{{ openstack_octavia_auth_cloud }}" cacert: "{{ openstack_cacert }}" endpoint_type: "{{ openstack_interface }}" region_name: "{{ openstack_region_name }}" @@ -81,6 +85,7 @@ module_name: openstack.cloud.security_group_rule module_args: auth: "{{ octavia_user_auth }}" + cloud: "{{ openstack_octavia_auth_cloud }}" cacert: "{{ openstack_cacert }}" endpoint_type: "{{ openstack_interface }}" region_name: "{{ openstack_region_name }}" @@ -103,6 +108,7 @@ module_name: openstack.cloud.network module_args: auth: "{{ octavia_user_auth }}" + cloud: "{{ openstack_octavia_auth_cloud }}" cacert: "{{ openstack_cacert }}" endpoint_type: "{{ openstack_interface }}" region_name: "{{ openstack_region_name }}" @@ -125,6 +131,7 @@ module_name: openstack.cloud.subnet module_args: auth: "{{ octavia_user_auth }}" + cloud: "{{ openstack_octavia_auth_cloud }}" cacert: "{{ openstack_cacert }}" endpoint_type: "{{ openstack_interface }}" region_name: "{{ openstack_region_name }}" @@ -150,6 +157,7 @@ module_name: openstack.cloud.router module_args: auth: "{{ octavia_user_auth }}" + cloud: "{{ openstack_octavia_auth_cloud }}" cacert: "{{ openstack_cacert }}" endpoint_type: "{{ openstack_interface }}" region_name: "{{ openstack_region_name }}" diff --git a/ansible/roles/octavia/tasks/register.yml b/ansible/roles/octavia/tasks/register.yml index a9f6a7775e..6b763bc413 100644 --- a/ansible/roles/octavia/tasks/register.yml +++ b/ansible/roles/octavia/tasks/register.yml @@ -15,6 +15,7 @@ module_args: name: "{{ item }}" auth: "{{ openstack_octavia_auth }}" + cloud: "{{ openstack_auth_cloud }}" endpoint_type: "{{ openstack_interface }}" cacert: "{{ openstack_cacert }}" region_name: "{{ openstack_region_name }}" diff --git a/ansible/roles/openvswitch/defaults/main.yml b/ansible/roles/openvswitch/defaults/main.yml index aea56f828a..1eabdd65c5 100644 --- a/ansible/roles/openvswitch/defaults/main.yml +++ b/ansible/roles/openvswitch/defaults/main.yml @@ -21,6 +21,7 @@ openvswitch_services: image: "{{ openvswitch_vswitchd_image_full }}" enabled: "{{ enable_openvswitch }}" group: openvswitch + pid_mode: host host_in_groups: >- {{ inventory_hostname in groups['compute'] diff --git a/ansible/roles/openvswitch/handlers/main.yml b/ansible/roles/openvswitch/handlers/main.yml index a4fbd3f02a..cf29888def 100644 --- a/ansible/roles/openvswitch/handlers/main.yml +++ b/ansible/roles/openvswitch/handlers/main.yml @@ -38,3 +38,4 @@ privileged: "{{ service.privileged | default(False) }}" dimensions: "{{ service.dimensions }}" healthcheck: "{{ service.healthcheck }}" + pid_mode: "{{ service.pid_mode }}" diff --git a/ansible/roles/ovn-controller/defaults/main.yml b/ansible/roles/ovn-controller/defaults/main.yml index e5a32f3ac7..8cc7dc3092 100644 --- a/ansible/roles/ovn-controller/defaults/main.yml +++ b/ansible/roles/ovn-controller/defaults/main.yml @@ -22,6 +22,7 @@ ovn_controller_dimensions: "{{ default_container_dimensions }}" ovn_controller_default_volumes: - "{{ node_config_directory }}/ovn-controller/:{{ container_config_directory }}/:ro" - "/run/openvswitch:/run/openvswitch:shared" + - "/run/ovn:/run/ovn:shared" - "/etc/localtime:/etc/localtime:ro" - "kolla_logs:/var/log/kolla/" diff --git a/ansible/roles/ovn-controller/tasks/config.yml b/ansible/roles/ovn-controller/tasks/config.yml index d2a789ec54..e64f5ddf42 100644 --- a/ansible/roles/ovn-controller/tasks/config.yml +++ b/ansible/roles/ovn-controller/tasks/config.yml @@ -9,6 +9,15 @@ become: true with_dict: "{{ ovn_controller_services | select_services_enabled_and_mapped_to_host }}" +- name: Create /run/ovn directory on host + become: true + ansible.builtin.file: + path: /run/ovn + state: directory + mode: "0770" + owner: "{{ config_owner_user }}" + group: "{{ config_owner_group }}" + - name: Copying over config.json files for services ansible.builtin.template: src: "{{ item.key }}.json.j2" diff --git a/ansible/roles/ovn-db/defaults/main.yml b/ansible/roles/ovn-db/defaults/main.yml index f01a739ced..7a17087a64 100644 --- a/ansible/roles/ovn-db/defaults/main.yml +++ b/ansible/roles/ovn-db/defaults/main.yml @@ -70,20 +70,24 @@ ovn_sb_db_relay_dimensions: "{{ default_container_dimensions }}" ovn_northd_default_volumes: - "{{ node_config_directory }}/ovn-northd/:{{ container_config_directory }}/:ro" - "/etc/localtime:/etc/localtime:ro" + - "/run/ovn:/run/ovn:shared" - "kolla_logs:/var/log/kolla/" ovn_nb_db_default_volumes: - "{{ node_config_directory }}/ovn-nb-db/:{{ container_config_directory }}/:ro" - "/etc/localtime:/etc/localtime:ro" - "ovn_nb_db:/var/lib/openvswitch/ovn-nb/" + - "/run/ovn:/run/ovn:shared" - "kolla_logs:/var/log/kolla/" ovn_sb_db_default_volumes: - "{{ node_config_directory }}/ovn-sb-db/:{{ container_config_directory }}/:ro" - "/etc/localtime:/etc/localtime:ro" - "ovn_sb_db:/var/lib/openvswitch/ovn-sb/" + - "/run/ovn:/run/ovn:shared" - "kolla_logs:/var/log/kolla/" ovn_sb_db_relay_default_volumes: - "{{ node_config_directory }}/ovn-sb-db-relay{{ ('-' + item | string) if item is defined }}/:{{ container_config_directory }}/:ro" - "/etc/localtime:/etc/localtime:ro" + - "/run/ovn:/run/ovn:shared" - "kolla_logs:/var/log/kolla/" ovn_db_extra_volumes: "{{ default_extra_volumes }}" diff --git a/ansible/roles/ovn-db/tasks/config.yml b/ansible/roles/ovn-db/tasks/config.yml index 21dc08069c..4adfeea3e2 100644 --- a/ansible/roles/ovn-db/tasks/config.yml +++ b/ansible/roles/ovn-db/tasks/config.yml @@ -1,4 +1,13 @@ --- +- name: Create /run/ovn directory on host + become: true + ansible.builtin.file: + path: /run/ovn + state: directory + mode: "0770" + owner: "{{ config_owner_user }}" + group: "{{ config_owner_group }}" + - name: Ensuring config directories exist ansible.builtin.file: path: "{{ node_config_directory }}/{{ item.key }}" diff --git a/ansible/roles/prometheus/defaults/main.yml b/ansible/roles/prometheus/defaults/main.yml index 03eaae027b..1145286c8c 100644 --- a/ansible/roles/prometheus/defaults/main.yml +++ b/ansible/roles/prometheus/defaults/main.yml @@ -121,6 +121,14 @@ prometheus_services: image: "{{ prometheus_libvirt_exporter_image_full }}" volumes: "{{ prometheus_libvirt_exporter_default_volumes + prometheus_libvirt_exporter_extra_volumes }}" dimensions: "{{ prometheus_libvirt_exporter_dimensions }}" + prometheus-openstack-network-exporter: + container_name: "prometheus_openstack_network_exporter" + group: "prometheus-openstack-network-exporter" + enabled: "{{ enable_prometheus_openstack_network_exporter | bool }}" + image: "{{ prometheus_openstack_network_exporter_image_full }}" + volumes: "{{ prometheus_openstack_network_exporter_default_volumes + prometheus_openstack_network_exporter_extra_volumes }}" + dimensions: "{{ prometheus_openstack_network_exporter_dimensions }}" + pid_mode: host prometheus-valkey-exporter: container_name: "prometheus_valkey_exporter" group: "prometheus-valkey-exporter" @@ -405,6 +413,10 @@ prometheus_libvirt_exporter_image: "{{ docker_image_url }}prometheus-libvirt-exp prometheus_libvirt_exporter_tag: "{{ prometheus_tag }}" prometheus_libvirt_exporter_image_full: "{{ prometheus_libvirt_exporter_image }}:{{ prometheus_libvirt_exporter_tag }}" +prometheus_openstack_network_exporter_image: "{{ docker_image_url }}prometheus-openstack-network-exporter" +prometheus_openstack_network_exporter_tag: "{{ prometheus_tag }}" +prometheus_openstack_network_exporter_image_full: "{{ prometheus_openstack_network_exporter_image }}:{{ prometheus_openstack_network_exporter_tag }}" + prometheus_valkey_exporter_image: "{{ docker_image_url }}prometheus-valkey-exporter" prometheus_valkey_exporter_tag: "{{ prometheus_tag }}" prometheus_valkey_exporter_image_full: "{{ prometheus_valkey_exporter_image }}:{{ prometheus_valkey_exporter_tag }}" @@ -417,6 +429,7 @@ prometheus_openstack_exporter_dimensions: "{{ default_container_dimensions }}" prometheus_elasticsearch_exporter_dimensions: "{{ default_container_dimensions }}" prometheus_blackbox_exporter_dimensions: "{{ default_container_dimensions }}" prometheus_libvirt_exporter_dimensions: "{{ default_container_dimensions }}" +prometheus_openstack_network_exporter_dimensions: "{{ default_container_dimensions }}" prometheus_valkey_exporter_dimensions: "{{ default_container_dimensions }}" prometheus_server_default_volumes: @@ -453,6 +466,13 @@ prometheus_libvirt_exporter_default_volumes: - "{{ node_config_directory }}/prometheus-libvirt-exporter/:{{ container_config_directory }}/:ro" - "/etc/localtime:/etc/localtime:ro" - "/run/libvirt:/run/libvirt:ro" +prometheus_openstack_network_exporter_default_volumes: + - "{{ node_config_directory }}/prometheus-openstack-network-exporter/:{{ container_config_directory }}/:ro" + - "/etc/localtime:/etc/localtime:ro" + - "/run/ovn:/run/ovn:ro" + - "/run/openvswitch:/run/openvswitch:ro" + - "{{ '/etc/timezone:/etc/timezone:ro' if ansible_facts.os_family == 'Debian' else '' }}" + - "kolla_logs:/var/log/kolla/" prometheus_valkey_exporter_default_volumes: - "{{ node_config_directory }}/prometheus-valkey-exporter/:{{ container_config_directory }}/:ro" - "/etc/localtime:/etc/localtime:ro" @@ -467,6 +487,7 @@ prometheus_openstack_exporter_extra_volumes: "{{ prometheus_extra_volumes }}" prometheus_elasticsearch_exporter_extra_volumes: "{{ prometheus_extra_volumes }}" prometheus_blackbox_exporter_extra_volumes: "{{ prometheus_extra_volumes }}" prometheus_libvirt_exporter_extra_volumes: "{{ prometheus_extra_volumes }}" +prometheus_openstack_network_exporter_extra_volumes: "{{ prometheus_extra_volumes }}" prometheus_valkey_exporter_extra_volumes: "{{ prometheus_extra_volumes }}" prometheus_openstack_exporter_disabled_volume: "{{ '--disable-service.volume' if not enable_cinder | bool else '' }}" @@ -496,6 +517,11 @@ prometheus_openstack_exporter_cmdline_extras: "" prometheus_alertmanager_external_url: "{{ internal_protocol }}://{{ kolla_internal_fqdn | put_address_in_context('url') }}:{{ prometheus_alertmanager_port }}" +############ +# Intervals +############ +prometheus_openstack_network_exporter_interval: "{{ prometheus_scrape_interval }}" + ################### # Copy certificates ################### diff --git a/ansible/roles/prometheus/handlers/main.yml b/ansible/roles/prometheus/handlers/main.yml index f83129840d..0765efca09 100644 --- a/ansible/roles/prometheus/handlers/main.yml +++ b/ansible/roles/prometheus/handlers/main.yml @@ -105,6 +105,20 @@ volumes: "{{ service.volumes }}" dimensions: "{{ service.dimensions }}" +- name: Restart prometheus-openstack-network-exporter container + vars: + service_name: "prometheus-openstack-network-exporter" + service: "{{ prometheus_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 }}" + dimensions: "{{ service.dimensions }}" + pid_mode: "{{ service.pid_mode }}" + - name: Restart prometheus-valkey-exporter container vars: service_name: "prometheus-valkey-exporter" diff --git a/ansible/roles/prometheus/tasks/config.yml b/ansible/roles/prometheus/tasks/config.yml index a86eab67bf..9145230b43 100644 --- a/ansible/roles/prometheus/tasks/config.yml +++ b/ansible/roles/prometheus/tasks/config.yml @@ -176,6 +176,20 @@ - "{{ node_custom_config }}/prometheus/prometheus-blackbox-exporter.yml" - "{{ role_path }}/templates/prometheus-blackbox-exporter.yml.j2" +- name: Copying config file for openstack network exporter + become: true + vars: + service: "{{ prometheus_services['prometheus-openstack-network-exporter'] }}" + ansible.builtin.template: + src: "{{ item }}" + dest: "{{ node_config_directory }}/prometheus-openstack-network-exporter/openstack-network-exporter.yaml" + mode: "0660" + when: service | service_enabled_and_mapped_to_host + with_first_found: + - "{{ node_custom_config }}/prometheus-openstack-network-exporter/{{ inventory_hostname }}/openstack-network-exporter.yaml" + - "{{ node_custom_config }}/prometheus-openstack-network-exporter/openstack-network-exporter.yaml" + - "{{ role_path }}/templates/openstack-network-exporter.yaml.j2" + - name: Copy extra prometheus server config files vars: base: "{{ node_custom_config }}/prometheus/" diff --git a/ansible/roles/prometheus/tasks/precheck.yml b/ansible/roles/prometheus/tasks/precheck.yml index 9dfc666e55..d4bdf0eba0 100644 --- a/ansible/roles/prometheus/tasks/precheck.yml +++ b/ansible/roles/prometheus/tasks/precheck.yml @@ -20,6 +20,7 @@ - prometheus_elasticsearch_exporter - prometheus_blackbox_exporter - prometheus_libvirt_exporter + - prometheus_openstack_network_exporter check_mode: false register: container_facts @@ -159,3 +160,17 @@ - enable_prometheus_libvirt_exporter | bool with_items: - "{{ prometheus_libvirt_exporter_port }}" + +- name: Checking free ports for Prometheus network-exporter + ansible.builtin.wait_for: + host: "{{ 'api' | kolla_address }}" + port: "{{ item }}" + connect_timeout: 1 + timeout: 1 + state: stopped + when: + - container_facts.containers['prometheus_openstack_network_exporter'] is not defined + - inventory_hostname in groups['prometheus-openstack-network-exporter'] + - enable_prometheus_openstack_network_exporter | bool + with_items: + - "{{ prometheus_openstack_network_exporter_port }}" diff --git a/ansible/roles/prometheus/templates/openstack-network-exporter.yaml.j2 b/ansible/roles/prometheus/templates/openstack-network-exporter.yaml.j2 new file mode 100644 index 0000000000..819f9e36f7 --- /dev/null +++ b/ansible/roles/prometheus/templates/openstack-network-exporter.yaml.j2 @@ -0,0 +1 @@ +http-listen: "{{ api_interface_address | put_address_in_context('url') }}:{{ prometheus_openstack_network_exporter_port }}" diff --git a/ansible/roles/prometheus/templates/prometheus-openstack-network-exporter.json.j2 b/ansible/roles/prometheus/templates/prometheus-openstack-network-exporter.json.j2 new file mode 100644 index 0000000000..ea74a9b7ae --- /dev/null +++ b/ansible/roles/prometheus/templates/prometheus-openstack-network-exporter.json.j2 @@ -0,0 +1,17 @@ +{ + "command": "/opt/openstack-network-exporter/dataplane-node-exporter", + "config_files": [ + { + "source": "{{ container_config_directory }}/openstack-network-exporter.yaml", + "dest": "/etc/dataplane-node-exporter.yaml", + "owner": "prometheus", + "perm": "0600" + }{% 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 %} + ] +} diff --git a/ansible/roles/prometheus/templates/prometheus.yml.j2 b/ansible/roles/prometheus/templates/prometheus.yml.j2 index f07e89ceac..e6d95467e5 100644 --- a/ansible/roles/prometheus/templates/prometheus.yml.j2 +++ b/ansible/roles/prometheus/templates/prometheus.yml.j2 @@ -212,6 +212,21 @@ scrape_configs: {% endfor %} {% endif %} +{% if enable_prometheus_openstack_network_exporter | bool %} + - job_name: network_exporter + scrape_interval: {{ prometheus_openstack_network_exporter_interval }} + honor_labels: true + static_configs: +{% for host in groups["prometheus-openstack-network-exporter"] %} + - targets: + - '{{ 'api' | kolla_address(host, override_var='prometheus_target_address') | put_address_in_context('url') }}:{{ hostvars[host]['prometheus_openstack_network_exporter_port'] }}' +{% if hostvars[host].prometheus_instance_label | default(false, true) %} + labels: + instance: "{{ hostvars[host].prometheus_instance_label }}" +{% endif %} +{% endfor %} +{% endif %} + {% if enable_prometheus_etcd_integration | bool %} - job_name: etcd {% if etcd_enable_tls | bool %} diff --git a/ansible/roles/service-ks-register/tasks/main.yml b/ansible/roles/service-ks-register/tasks/main.yml index 242e597b60..2b875f8080 100644 --- a/ansible/roles/service-ks-register/tasks/main.yml +++ b/ansible/roles/service-ks-register/tasks/main.yml @@ -13,6 +13,7 @@ description: "{{ item.description | default(omit) }}" region_name: "{{ service_ks_register_region_name }}" auth: "{{ service_ks_register_auth }}" + cloud: "{{ openstack_auth_cloud }}" interface: "{{ service_ks_register_interface }}" cacert: "{{ service_ks_cacert }}" state: "{{ item.state | default('present') }}" @@ -36,6 +37,7 @@ region: "{{ service_ks_register_endpoint_region }}" region_name: "{{ service_ks_register_region_name }}" auth: "{{ service_ks_register_auth }}" + cloud: "{{ openstack_auth_cloud }}" interface: "{{ service_ks_register_interface }}" cacert: "{{ service_ks_cacert }}" state: "{{ item.state | default('present') }}" @@ -59,6 +61,7 @@ domain: "{{ service_ks_register_domain }}" region_name: "{{ service_ks_register_region_name }}" auth: "{{ service_ks_register_auth }}" + cloud: "{{ openstack_auth_cloud }}" interface: "{{ service_ks_register_interface }}" cacert: "{{ service_ks_cacert }}" with_items: "{{ service_ks_register_users | map(attribute='project') | unique | list }}" @@ -83,6 +86,7 @@ domain: "{{ service_ks_register_domain }}" region_name: "{{ service_ks_register_region_name }}" auth: "{{ service_ks_register_auth }}" + cloud: "{{ openstack_auth_cloud }}" interface: "{{ service_ks_register_interface }}" cacert: "{{ service_ks_cacert }}" with_items: "{{ service_ks_register_users }}" @@ -101,6 +105,7 @@ name: "{{ item }}" region_name: "{{ service_ks_register_region_name }}" auth: "{{ service_ks_register_auth }}" + cloud: "{{ openstack_auth_cloud }}" interface: "{{ service_ks_register_interface }}" cacert: "{{ service_ks_cacert }}" with_items: "{{ service_ks_register_users | map(attribute='role') | unique | list + service_ks_register_roles }}" @@ -121,6 +126,7 @@ system: "{{ item.system | default(omit) }}" region_name: "{{ service_ks_register_region_name }}" auth: "{{ service_ks_register_auth }}" + cloud: "{{ openstack_auth_cloud }}" interface: "{{ service_ks_register_interface }}" cacert: "{{ service_ks_cacert }}" state: "{{ item.state | default('present') }}" diff --git a/ansible/site.yml b/ansible/site.yml index 08a072ccfd..51838593ce 100644 --- a/ansible/site.yml +++ b/ansible/site.yml @@ -97,10 +97,10 @@ roles: - logs -- name: Apply role common +- name: Apply role kolla_toolbox gather_facts: false hosts: - - kolla-toolbox + - kolla_toolbox serial: '{{ kolla_serial|default("0") }}' max_fail_percentage: >- {{ common_max_fail_percentage | @@ -108,8 +108,9 @@ default(100) }} tags: - common + - kolla_toolbox roles: - - role: common + - role: kolla_toolbox - name: Apply role cron gather_facts: false @@ -473,6 +474,7 @@ - prometheus-elasticsearch-exporter - prometheus-blackbox-exporter - prometheus-libvirt-exporter + - prometheus-openstack-network-exporter - prometheus-valkey-exporter - "&enable_prometheus_True" serial: '{{ kolla_serial|default("0") }}' @@ -556,8 +558,8 @@ gather_facts: false hosts: # NOTE(mgoddard): This is only used to register Keystone services, and - # can run on any host running kolla-toolbox. - - kolla-toolbox + # can run on any host running kolla_toolbox. + - kolla_toolbox - "&enable_ceph_rgw_True" serial: '{{ kolla_serial|default("0") }}' max_fail_percentage: >- diff --git a/ansible/roles/common/templates/admin-openrc-system.sh.j2 b/ansible/templates/admin-openrc-system.sh.j2 similarity index 100% rename from ansible/roles/common/templates/admin-openrc-system.sh.j2 rename to ansible/templates/admin-openrc-system.sh.j2 diff --git a/ansible/roles/common/templates/admin-openrc.sh.j2 b/ansible/templates/admin-openrc.sh.j2 similarity index 100% rename from ansible/roles/common/templates/admin-openrc.sh.j2 rename to ansible/templates/admin-openrc.sh.j2 diff --git a/ansible/roles/common/templates/clouds.yaml.j2 b/ansible/templates/clouds.yaml.j2 similarity index 100% rename from ansible/roles/common/templates/clouds.yaml.j2 rename to ansible/templates/clouds.yaml.j2 diff --git a/ansible/roles/common/templates/public-openrc-system.sh.j2 b/ansible/templates/public-openrc-system.sh.j2 similarity index 100% rename from ansible/roles/common/templates/public-openrc-system.sh.j2 rename to ansible/templates/public-openrc-system.sh.j2 diff --git a/ansible/roles/common/templates/public-openrc.sh.j2 b/ansible/templates/public-openrc.sh.j2 similarity index 100% rename from ansible/roles/common/templates/public-openrc.sh.j2 rename to ansible/templates/public-openrc.sh.j2 diff --git a/doc/source/admin/acme.rst b/doc/source/admin/acme.rst index 6a12efe11e..2955c9f3af 100644 --- a/doc/source/admin/acme.rst +++ b/doc/source/admin/acme.rst @@ -26,7 +26,7 @@ is ``192.168.1.1``, the config would look like the following: .. code-block:: yaml - enable_horizon: "yes" + enable_horizon: true acme_client_servers: - server certbot 192.168.1.1:80 diff --git a/doc/source/admin/advanced-configuration.rst b/doc/source/admin/advanced-configuration.rst index 579dd11ca9..7ece68e3ae 100644 --- a/doc/source/admin/advanced-configuration.rst +++ b/doc/source/admin/advanced-configuration.rst @@ -216,7 +216,7 @@ adding: .. code-block:: yaml - enable_haproxy: "no" + enable_haproxy: false Note this method is not recommended and generally not tested by the Kolla community, but included since sometimes a free IP is not available @@ -233,7 +233,7 @@ first disable the deployment of the central logging. .. code-block:: yaml - enable_central_logging: "no" + enable_central_logging: false Now you can use the parameter ``elasticsearch_address`` to configure the address of the external Elasticsearch environment. diff --git a/doc/source/admin/mariadb-backup-and-restore.rst b/doc/source/admin/mariadb-backup-and-restore.rst index 596b7f9529..f6e77fe4b9 100644 --- a/doc/source/admin/mariadb-backup-and-restore.rst +++ b/doc/source/admin/mariadb-backup-and-restore.rst @@ -27,7 +27,7 @@ Firstly, enable backups via ``globals.yml``: .. code-block:: console - enable_mariabackup: "yes" + enable_mariabackup: true Then, kick off a reconfiguration of MariaDB: diff --git a/doc/source/admin/tls.rst b/doc/source/admin/tls.rst index 3183c45e8d..a78f4c5999 100644 --- a/doc/source/admin/tls.rst +++ b/doc/source/admin/tls.rst @@ -48,10 +48,10 @@ APIs, configure the following in ``globals.yml``: .. code-block:: yaml - kolla_enable_tls_internal: "yes" - kolla_enable_tls_external: "yes" - kolla_enable_tls_backend: "yes" - kolla_copy_ca_into_containers: "yes" + kolla_enable_tls_internal: true + kolla_enable_tls_external: true + kolla_enable_tls_backend: true + kolla_copy_ca_into_containers: true If deploying on Debian or Ubuntu: @@ -100,13 +100,13 @@ encryption: .. code-block:: yaml - kolla_enable_tls_external: "yes" + kolla_enable_tls_external: true To enable internal TLS encryption: .. code-block:: yaml - kolla_enable_tls_internal: "yes" + kolla_enable_tls_internal: true Two certificate files are required to use TLS securely with authentication, which will be provided by your Certificate Authority: @@ -218,8 +218,18 @@ Enabling TLS on the backend services secures communication between the HAProxy listing on the internal/external VIP and the OpenStack services. It also enables secure end-to-end communication between OpenStack services that support TLS termination. The OpenStack services that support -backend TLS termination in Victoria are: Nova, Ironic, Neutron, Keystone, -Glance, Heat, Placement, Horizon, Barbican, and Cinder. +backend TLS termination are: + +* Barbican +* Cinder +* Glance +* Heat +* Horizon +* Ironic +* Keystone +* Neutron +* Nova +* Placement The configuration variables that control back-end TLS for service endpoints are: @@ -235,11 +245,11 @@ communication: .. code-block:: yaml - kolla_enable_tls_backend: "yes" + kolla_enable_tls_backend: true It is also possible to enable back-end TLS on a per-service basis. For example, to enable back-end TLS for Keystone, set ``keystone_enable_tls_backend`` to -``yes``. +``true``. The default values for ``haproxy_backend_cacert`` and ``haproxy_backend_cacert_dir`` should suffice if the certificate is in the @@ -284,7 +294,7 @@ disable verification of the backend certificate: .. code-block:: yaml - kolla_verify_tls_backend: "no" + kolla_verify_tls_backend: false Generating TLS certificates with Let's Encrypt ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -297,7 +307,7 @@ must be configured in ``globals.yml``: .. code-block:: yaml - enable_letsencrypt: "yes" + enable_letsencrypt: true letsencrypt_email: "" The Let's Encrypt container will attempt to renew your certificates every 12 diff --git a/doc/source/reference/bare-metal/ironic-guide.rst b/doc/source/reference/bare-metal/ironic-guide.rst index 962ece7628..75c3865f2a 100644 --- a/doc/source/reference/bare-metal/ironic-guide.rst +++ b/doc/source/reference/bare-metal/ironic-guide.rst @@ -16,7 +16,7 @@ Enable Ironic in ``/etc/kolla/globals.yml``: .. code-block:: yaml - enable_ironic: "yes" + enable_ironic: true In the same file, define a network interface as the default NIC for dnsmasq and define a network to be used for the Ironic cleaning network: @@ -125,7 +125,7 @@ PXE filter service: .. code-block:: yaml - enable_ironic_pxe_filter: "yes" + enable_ironic_pxe_filter: true The PXE filter container runs alongside ``ironic-dnsmasq`` and cleans up stale DHCP entries. It is especially useful when auto discovery is enabled and when @@ -189,20 +189,20 @@ keystone could be installed in one region (let's say region 1) and ironic - in another region (let's say region 2). In this case we don't install keystone together with ironic in region 2, but have to configure ironic to connect to existing keystone in region 1. To deploy ironic in this way we have to set -variable ``enable_keystone`` to ``"no"``. +variable ``enable_keystone`` to ``false``. .. code-block:: yaml - enable_keystone: "no" + enable_keystone: false It will prevent keystone from being installed in region 2. To add keystone-related sections in ironic.conf, it is also needed to set -variable ``ironic_enable_keystone_integration`` to ``"yes"`` +variable ``ironic_enable_keystone_integration`` to ``true`` .. code-block:: yaml - ironic_enable_keystone_integration: "yes" + ironic_enable_keystone_integration: true Avoiding problems with high availability ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/source/reference/compute/nova-cells-guide.rst b/doc/source/reference/compute/nova-cells-guide.rst index a808bc0835..616ba0a5f5 100644 --- a/doc/source/reference/compute/nova-cells-guide.rst +++ b/doc/source/reference/compute/nova-cells-guide.rst @@ -170,7 +170,7 @@ Support for deployment of multiple cells is disabled by default - nova is deployed in single conductor mode. Deployment of multiple cells may be enabled by setting ``enable_cells`` to -``yes`` in ``globals.yml``. This deploys nova in superconductor mode, with +``true`` in ``globals.yml``. This deploys nova in superconductor mode, with separate conductors for each cell. Naming cells diff --git a/doc/source/reference/compute/nova-fake-driver.rst b/doc/source/reference/compute/nova-fake-driver.rst index df003f8f46..bef4d17813 100644 --- a/doc/source/reference/compute/nova-fake-driver.rst +++ b/doc/source/reference/compute/nova-fake-driver.rst @@ -29,7 +29,7 @@ the command line options. .. code-block:: yaml - enable_nova_fake: "yes" + enable_nova_fake: true num_nova_fake_per_node: 5 Each Compute node will run 5 ``nova-compute`` containers and 5 diff --git a/doc/source/reference/compute/nova-guide.rst b/doc/source/reference/compute/nova-guide.rst index 87757f9308..1069030bb6 100644 --- a/doc/source/reference/compute/nova-guide.rst +++ b/doc/source/reference/compute/nova-guide.rst @@ -7,7 +7,7 @@ this is via Virtual Machines (VMs), but may also be via bare metal servers if Nova is coupled with Ironic. Nova is enabled by default, but may be disabled by setting ``enable_nova`` to -``no`` in ``globals.yml``. +``false`` in ``globals.yml``. Virtualisation Drivers ====================== @@ -43,7 +43,7 @@ Consoles The console driver may be selected via ``nova_console`` in ``globals.yml``. Valid options are ``none``, ``novnc`` and ``spice``. Additionally, serial console support can be enabled by setting -``enable_nova_serialconsole_proxy`` to ``yes``. +``enable_nova_serialconsole_proxy`` to ``true``. ``spice`` consoles have additional configuration options used by Kolla Ansible: diff --git a/doc/source/reference/compute/zun-guide.rst b/doc/source/reference/compute/zun-guide.rst index 9959dede1a..8df209a735 100644 --- a/doc/source/reference/compute/zun-guide.rst +++ b/doc/source/reference/compute/zun-guide.rst @@ -17,11 +17,11 @@ following variables: .. code-block:: yaml - enable_zun: "yes" - enable_kuryr: "yes" - enable_etcd: "yes" - docker_configure_for_zun: "yes" - containerd_configure_for_zun: "yes" + enable_zun: true + enable_kuryr: true + enable_etcd: true + docker_configure_for_zun: true + containerd_configure_for_zun: true Docker reconfiguration requires rebootstrapping before deploy. Make sure you understand the consequences of restarting Docker. diff --git a/doc/source/reference/containers/kuryr-guide.rst b/doc/source/reference/containers/kuryr-guide.rst index f748d16c5a..f85451d57e 100644 --- a/doc/source/reference/containers/kuryr-guide.rst +++ b/doc/source/reference/containers/kuryr-guide.rst @@ -33,8 +33,8 @@ following variables .. code-block:: yaml - enable_etcd: "yes" - enable_kuryr: "yes" + enable_etcd: true + enable_kuryr: true Deploy the OpenStack cloud and kuryr network plugin diff --git a/doc/source/reference/databases/external-mariadb-guide.rst b/doc/source/reference/databases/external-mariadb-guide.rst index 90b5f79080..55cba4c2b8 100644 --- a/doc/source/reference/databases/external-mariadb-guide.rst +++ b/doc/source/reference/databases/external-mariadb-guide.rst @@ -31,7 +31,7 @@ by ensuring the following line exists within ``/etc/kolla/globals.yml`` : .. code-block:: yaml - enable_mariadb: "no" + enable_mariadb: false There are two ways in which you can use external MariaDB: * Using an already load-balanced MariaDB address @@ -60,7 +60,7 @@ need to do the following: .. note:: - If ``enable_external_mariadb_load_balancer`` is set to ``no`` + If ``enable_external_mariadb_load_balancer`` is set to ``false`` (default), the external DB load balancer should be accessible from all nodes during your deployment. @@ -87,7 +87,7 @@ according to the following configuration: .. code-block:: yaml - enable_external_mariadb_load_balancer: yes + enable_external_mariadb_load_balancer: true Using External MariaDB with a privileged user ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/source/reference/high-availability/haproxy-guide.rst b/doc/source/reference/high-availability/haproxy-guide.rst index 0d1219789c..02e09158b0 100644 --- a/doc/source/reference/high-availability/haproxy-guide.rst +++ b/doc/source/reference/high-availability/haproxy-guide.rst @@ -19,8 +19,8 @@ setting the following in ``/etc/kolla/globals.yml``: .. code-block:: yaml - enable_haproxy: "no" - enable_keepalived: "no" + enable_haproxy: false + enable_keepalived: false Single external frontend for services ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -91,7 +91,7 @@ disabled by setting the following in ``/etc/kolla/globals.yml``: .. code-block:: yaml - haproxy_enable_http2: "no" + haproxy_enable_http2: false SSL/TLS Settings ---------------- diff --git a/doc/source/reference/logging-and-monitoring/central-logging-guide.rst b/doc/source/reference/logging-and-monitoring/central-logging-guide.rst index f9b96697db..870be297f5 100644 --- a/doc/source/reference/logging-and-monitoring/central-logging-guide.rst +++ b/doc/source/reference/logging-and-monitoring/central-logging-guide.rst @@ -16,7 +16,7 @@ the following: .. code-block:: yaml - enable_central_logging: "yes" + enable_central_logging: true OpenSearch ~~~~~~~~~~ diff --git a/doc/source/reference/logging-and-monitoring/grafana-guide.rst b/doc/source/reference/logging-and-monitoring/grafana-guide.rst index 6f89c2016f..412ca88e12 100644 --- a/doc/source/reference/logging-and-monitoring/grafana-guide.rst +++ b/doc/source/reference/logging-and-monitoring/grafana-guide.rst @@ -20,13 +20,13 @@ and change the following: .. code-block:: yaml - enable_grafana: "yes" + enable_grafana: true If you would like to set up Prometheus as a data source, additionally set: .. code-block:: yaml - enable_prometheus: "yes" + enable_prometheus: true Please follow :doc:`Prometheus Guide ` for more information. diff --git a/doc/source/reference/logging-and-monitoring/osprofiler-guide.rst b/doc/source/reference/logging-and-monitoring/osprofiler-guide.rst index 9951d44721..fd56f65dc7 100644 --- a/doc/source/reference/logging-and-monitoring/osprofiler-guide.rst +++ b/doc/source/reference/logging-and-monitoring/osprofiler-guide.rst @@ -22,8 +22,8 @@ Enable ``OSprofiler`` in ``/etc/kolla/globals.yml`` file: .. code-block:: yaml - enable_osprofiler: "yes" - enable_elasticsearch: "yes" + enable_osprofiler: true + enable_elasticsearch: true Verify operation ---------------- diff --git a/doc/source/reference/logging-and-monitoring/prometheus-guide.rst b/doc/source/reference/logging-and-monitoring/prometheus-guide.rst index d1e4109fc3..0680099a3b 100644 --- a/doc/source/reference/logging-and-monitoring/prometheus-guide.rst +++ b/doc/source/reference/logging-and-monitoring/prometheus-guide.rst @@ -18,13 +18,13 @@ and change the following: .. code-block:: yaml - enable_prometheus: "yes" + enable_prometheus: true Note: This will deploy Prometheus version 2.x. Any potentially existing Prometheus 1.x instances deployed by previous Kolla Ansible releases will conflict with current version and should be manually stopped and/or removed. If you would like to stay with version 1.x, set the ``enable_prometheus`` -variable to ``no``. +variable to ``false``. In order to remove leftover volume containing Prometheus 1.x data, execute: diff --git a/doc/source/reference/message-queues/external-rabbitmq-guide.rst b/doc/source/reference/message-queues/external-rabbitmq-guide.rst index 10277f6413..571751657c 100644 --- a/doc/source/reference/message-queues/external-rabbitmq-guide.rst +++ b/doc/source/reference/message-queues/external-rabbitmq-guide.rst @@ -23,7 +23,7 @@ by ensuring the following line exists within ``/etc/kolla/globals.yml`` : .. code-block:: yaml - enable_rabbitmq: "no" + enable_rabbitmq: false Overwriting transport_url within ``globals.yml`` diff --git a/doc/source/reference/networking/designate-guide.rst b/doc/source/reference/networking/designate-guide.rst index aa0932b879..a46eb4da30 100644 --- a/doc/source/reference/networking/designate-guide.rst +++ b/doc/source/reference/networking/designate-guide.rst @@ -23,7 +23,7 @@ Enable Designate service in ``/etc/kolla/globals.yml`` .. code-block:: yaml - enable_designate: "yes" + enable_designate: true neutron_dns_domain: "example.org." .. important:: @@ -54,7 +54,7 @@ Configure Designate options in ``/etc/kolla/globals.yml`` 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 ``valkey`` - when ``valkey`` is enabled (``enable_valkey`` is set to ``yes``). + when ``valkey`` is enabled (``enable_valkey`` is set to ``true``). The following additional variables are required depending on which backend you intend to use: @@ -108,7 +108,7 @@ to trigger record creation & deletion. .. note:: Service ``designate-sink`` in kolla deployments is disabled by default - and can be enabled by ``designate_enable_notifications_sink: yes``. + and can be enabled by ``designate_enable_notifications_sink: true``. Create default Designate Zone for Neutron: diff --git a/doc/source/reference/networking/dpdk.rst b/doc/source/reference/networking/dpdk.rst index 478596a661..96f9e52e51 100644 --- a/doc/source/reference/networking/dpdk.rst +++ b/doc/source/reference/networking/dpdk.rst @@ -71,8 +71,8 @@ To enable ovs-dpdk, add the following configuration to .. code-block:: yaml ovs_datapath: "netdev" - enable_ovs_dpdk: yes - enable_openvswitch: yes + enable_ovs_dpdk: true + enable_openvswitch: true tunnel_interface: "dpdk_bridge" neutron_bridge_name: "dpdk_bridge" diff --git a/doc/source/reference/networking/neutron-extensions.rst b/doc/source/reference/networking/neutron-extensions.rst index 2e8be4b138..2dbdb441e3 100644 --- a/doc/source/reference/networking/neutron-extensions.rst +++ b/doc/source/reference/networking/neutron-extensions.rst @@ -14,7 +14,7 @@ Modify the ``/etc/kolla/globals.yml`` file as the following example shows: .. code-block:: yaml - enable_neutron_sfc: "yes" + enable_neutron_sfc: true Verification ------------ @@ -37,7 +37,7 @@ Modify the ``/etc/kolla/globals.yml`` file as the following example shows: .. code-block:: yaml - enable_neutron_fwaas: "yes" + enable_neutron_fwaas: true For more information on FWaaS in Neutron refer to the :neutron-doc:`Neutron FWaaS docs `. @@ -45,6 +45,13 @@ For more information on FWaaS in Neutron refer to the Neutron VPNaaS (VPN-as-a-Service) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. warning:: + + OVN VPNaaS is currently not supported on RHEL 10 based distributions + (e.g., Rocky Linux 10, CentOS Stream 10) due to an upstream bug in + Neutron. See `LP#2146308 `_ + for details. + Preparation and deployment -------------------------- @@ -52,7 +59,7 @@ Modify the ``/etc/kolla/globals.yml`` file as the following example shows: .. code-block:: yaml - enable_neutron_vpnaas: "yes" + enable_neutron_vpnaas: true Verification ------------ @@ -60,15 +67,20 @@ Verification VPNaaS is a complex subject, hence this document provides directions for a simple smoke test to verify the service is up and running. -On the network node(s), the ``neutron_vpnaas_agent`` should be up (image naming -and versioning may differ depending on deploy configuration): +In ml2/ovn setups a special neutron_ovn_vpn_agent is running on neutron +node(s). +Version may differ depending on deploy configuration: .. code-block:: console - # docker ps --filter name=neutron_vpnaas_agent + # docker ps --filter name=neutron_ovn_vpn_agent + + CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES + 7f6efad28d30 kolla/neutron-ovn-vpn-agent:18.1.0 "dumb-init --single-…" 7 days ago Up 7 days (healthy) neutron_ovn_vpn_agent + +On ml2/ovs deployments there is no special agent. +The vpnaas code is running inside the neutron_l3_agent container. - CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES - 97d25657d55e operator:5000/kolla/centos-source-neutron-vpnaas-agent:4.0.0 "kolla_start" 44 minutes ago Up 44 minutes neutron_vpnaas_agent .. warning:: @@ -92,21 +104,20 @@ Verify both VPN services are active: .. code-block:: console - # neutron vpn-service-list + # openstack vpn service list - +--------------------------------------+----------+--------------------------------------+--------+ - | id | name | router_id | status | - +--------------------------------------+----------+--------------------------------------+--------+ - | ad941ec4-5f3d-4a30-aae2-1ab3f4347eb1 | vpn_west | 051f7ce3-4301-43cc-bfbd-7ffd59af539e | ACTIVE | - | edce15db-696f-46d8-9bad-03d087f1f682 | vpn_east | 058842e0-1d01-4230-af8d-0ba6d0da8b1f | ACTIVE | - +--------------------------------------+----------+--------------------------------------+--------+ + +--------------------------------------+----------+--------------------------------------+--------+--------+-------+--------+ + | ID | Name | Router | Subnet | Flavor | State | Status | + +--------------------------------------+----------+--------------------------------------+--------+--------+-------+--------+ + | 03f85023-28d9-4f35-a10e-2c8dd3c11b65 | vpn_west | e3603217-fd22-404c-b27e-9285c2a79a17 | None | None | True | ACTIVE | + | 1abdc71a-2eb7-4b2a-8871-eb9d91f39957 | vpn_east | 3485bdd2-4c42-449e-ae9f-d071a8cb9e5c | None | None | True | ACTIVE | + +--------------------------------------+----------+--------------------------------------+--------+--------+-------+--------+ Two VMs can now be booted, one on vpn_east, the other on vpn_west, and encrypted ping packets observed being sent from one to the other. -For more information on this and VPNaaS in Neutron refer to the -:neutron-vpnaas-doc:`Neutron VPNaaS Testing ` -and the `OpenStack wiki `_. +For more information on VPNaaS in Neutron refer to the +`OpenStack docs `_. Trunking ~~~~~~~~ @@ -119,7 +130,7 @@ Modify the ``/etc/kolla/globals.yml`` file as the following example shows: .. code-block:: yaml - enable_neutron_trunk: "yes" + enable_neutron_trunk: true Neutron Logging Framework ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -131,7 +142,7 @@ Modify the ``/etc/kolla/globals.yml`` file as the following example shows: .. code-block:: yaml - enable_neutron_packet_logging: "yes" + enable_neutron_packet_logging: true For OVS deployment, you need to override the firewall driver in `openvswitch_agent.ini` to: diff --git a/doc/source/reference/networking/neutron.rst b/doc/source/reference/networking/neutron.rst index 3fec073a50..b4f7a884fd 100644 --- a/doc/source/reference/networking/neutron.rst +++ b/doc/source/reference/networking/neutron.rst @@ -109,7 +109,7 @@ To use provider networks in instances you also need to set the following in .. code-block:: yaml - enable_neutron_provider_networks: yes + enable_neutron_provider_networks: true For provider networks, compute hosts must have an external bridge created and configured by Ansible (this is also necessary when @@ -188,7 +188,7 @@ L3 and DHCP agents can be created in a high availability (HA) state with: .. code-block:: yaml - enable_neutron_agent_ha: "yes" + enable_neutron_agent_ha: true This allows networking to fail over across controllers if the active agent is stopped. If this option is enabled, it can be advantageous to also set: @@ -275,7 +275,7 @@ In order to deploy Neutron OVN Agent you need to set the following: .. path /etc/kolla/globals.yml .. code-block:: yaml - neutron_enable_ovn_agent: "yes" + neutron_enable_ovn_agent: true Currently the agent is only needed for QoS for hardware offloaded ports. @@ -306,7 +306,7 @@ set the following (assuming neutron SR-IOV agent is also enabled using .. path /etc/kolla/globals.yml .. code-block:: yaml - enable_neutron_mlnx: "yes" + enable_neutron_mlnx: true Additionally, you will also need to provide physnet:interface mappings via ``neutron_mlnx_physnet_mappings`` which is presented to diff --git a/doc/source/reference/networking/octavia.rst b/doc/source/reference/networking/octavia.rst index 7a29d67fa8..33a64bd6c4 100644 --- a/doc/source/reference/networking/octavia.rst +++ b/doc/source/reference/networking/octavia.rst @@ -14,7 +14,7 @@ Enable the octavia service in ``globals.yml``: .. code-block:: yaml - enable_octavia: "yes" + enable_octavia: true Amphora provider ================ @@ -96,7 +96,7 @@ networks: .. code-block:: yaml - enable_neutron_provider_networks: yes + enable_neutron_provider_networks: true Configure the name of the network interface on the controllers used to access the Octavia management network. If using a VLAN provider network, ensure that @@ -219,7 +219,7 @@ For example: allocation_pool_start: "10.1.2.100" allocation_pool_end: "10.1.2.200" gateway_ip: "10.1.2.1" - enable_dhcp: yes + enable_dhcp: true Deploy Octavia with Kolla Ansible: @@ -252,16 +252,6 @@ as follows: Ensure that you have executed ``kolla-ansible post-deploy`` and set ``enable_octavia`` to yes in ``global.yml`` -.. note:: - - In Train and earlier releases, resources should be registered in the - ``admin`` project. This is configured via ``octavia_service_auth_project``, - and may be set to ``service`` to avoid a breaking change when upgrading to - Ussuri. Changing the project on an existing system requires at a minimum - registering a new security group in the new project. Ideally the flavor and - network should be recreated in the new project, although this will impact - existing Amphorae. - Amphora flavor ~~~~~~~~~~~~~~ diff --git a/doc/source/reference/networking/sriov.rst b/doc/source/reference/networking/sriov.rst index 73afa7b0f0..94417bfa0e 100644 --- a/doc/source/reference/networking/sriov.rst +++ b/doc/source/reference/networking/sriov.rst @@ -21,7 +21,7 @@ shows which automatically appends ``sriovnicswitch`` to the .. path /etc/kolla/globals.yml .. code-block:: yaml - enable_neutron_sriov: "yes" + enable_neutron_sriov: true It is also a requirement to define physnet:interface mappings for all SRIOV devices as shown in the following example where ``sriovtenant1`` is the diff --git a/doc/source/reference/orchestration-and-nfv/tacker-guide.rst b/doc/source/reference/orchestration-and-nfv/tacker-guide.rst index 4c99e72e15..95e82031e5 100644 --- a/doc/source/reference/orchestration-and-nfv/tacker-guide.rst +++ b/doc/source/reference/orchestration-and-nfv/tacker-guide.rst @@ -40,8 +40,8 @@ In order to enable them, you need to edit the file .. code-block:: yaml - enable_tacker: "yes" - enable_barbican: "yes" + enable_tacker: true + enable_barbican: true .. warning:: diff --git a/doc/source/reference/shared-services/glance-guide.rst b/doc/source/reference/shared-services/glance-guide.rst index 082bd40c68..d8e73e44d5 100644 --- a/doc/source/reference/shared-services/glance-guide.rst +++ b/doc/source/reference/shared-services/glance-guide.rst @@ -99,7 +99,7 @@ need to be enabled. .. code-block:: yaml - glance_enable_rolling_upgrade: "yes" + glance_enable_rolling_upgrade: true .. warning:: @@ -118,7 +118,7 @@ It is the default mode, ensure rolling upgrade method is not enabled. .. code-block:: yaml - glance_enable_rolling_upgrade: "no" + glance_enable_rolling_upgrade: false Other configuration @@ -131,7 +131,7 @@ Glance cache is disabled by default, it can be enabled by: .. code-block:: yaml - enable_glance_image_cache: "yes" + enable_glance_image_cache: true glance_cache_max_size: "10737418240" # 10GB by default .. warning:: @@ -154,7 +154,7 @@ is disabled by default, it can be enabled by: .. code-block:: yaml - glance_enable_property_protection: "yes" + glance_enable_property_protection: true and defining ``property-protections-rules.conf`` under @@ -170,7 +170,7 @@ is disabled by default, it can be enabled by: .. code-block:: yaml - glance_enable_interoperable_image_import: "yes" + glance_enable_interoperable_image_import: true and defining ``glance-image-import.conf`` under ``{{ node_custom_config }}/glance/``. diff --git a/doc/source/reference/shared-services/keystone-guide.rst b/doc/source/reference/shared-services/keystone-guide.rst index 5f5bc60ac6..173766022f 100644 --- a/doc/source/reference/shared-services/keystone-guide.rst +++ b/doc/source/reference/shared-services/keystone-guide.rst @@ -131,6 +131,11 @@ openstack_domain The OpenStack domain that the Identity Provider belongs. +.. note:: + Kolla-Ansible does not support duplicate openstack_domain names, + where the ID of the domain is different, but the name is the same. + This is an edge case that is hard to take into account. + protocol ******** diff --git a/doc/source/reference/shared-services/skyline-guide.rst b/doc/source/reference/shared-services/skyline-guide.rst index fb735c997c..4aea2beb74 100644 --- a/doc/source/reference/shared-services/skyline-guide.rst +++ b/doc/source/reference/shared-services/skyline-guide.rst @@ -12,18 +12,18 @@ Single Sign On (SSO) Skyline supports SSO with an Openid IdP. When you configure an IdP with protocol openid, Kolla will automatically enable SSO and set up the trusted dashboard url for Keystone. If you don't want to use SSO in Skyline, you can -disable it by setting ``skyline_enable_sso`` to "no": +disable it by setting ``skyline_enable_sso`` to ``false``: .. code-block:: yaml - skyline_enable_sso: "no" + skyline_enable_sso: false If you want to enable it without setting up the IdP with Kolla you can simply enable it with: .. code-block:: yaml - skyline_enable_sso: "yes" + skyline_enable_sso: true Customize logos ~~~~~~~~~~~~~~~ diff --git a/doc/source/reference/storage/cinder-guide-lightbits.rst b/doc/source/reference/storage/cinder-guide-lightbits.rst index b09d0e4a1f..dc1ea7ec0c 100644 --- a/doc/source/reference/storage/cinder-guide-lightbits.rst +++ b/doc/source/reference/storage/cinder-guide-lightbits.rst @@ -13,7 +13,7 @@ configure the ``Lightbits labs`` Cinder driver in .. code-block:: yaml - enable_cinder_backend_lightbits: "yes" + enable_cinder_backend_lightbits: true .. end diff --git a/doc/source/reference/storage/cinder-guide-pure.rst b/doc/source/reference/storage/cinder-guide-pure.rst index 0970d98eac..c261047619 100644 --- a/doc/source/reference/storage/cinder-guide-pure.rst +++ b/doc/source/reference/storage/cinder-guide-pure.rst @@ -12,7 +12,7 @@ configure the ``FlashArray iSCSI`` Cinder driver in ``/etc/kolla/globals.yml``. .. code-block:: yaml - enable_cinder_backend_pure_iscsi: "yes" + enable_cinder_backend_pure_iscsi: true .. end @@ -21,7 +21,7 @@ configure the ``FlashArray FC`` Cinder driver in ``/etc/kolla/globals.yml``. .. code-block:: yaml - enable_cinder_backend_pure_fc: "yes" + enable_cinder_backend_pure_fc: true .. end @@ -31,7 +31,7 @@ configure the ``FlashArray NVMe-RoCE`` Cinder driver in .. code-block:: yaml - enable_cinder_backend_pure_roce: "yes" + enable_cinder_backend_pure_roce: true .. end @@ -45,7 +45,7 @@ configure the ``FlashArray NVMe-TCP`` Cinder driver in .. code-block:: yaml - enable_cinder_backend_pure_nvme_tcp: "yes" + enable_cinder_backend_pure_nvme_tcp: true .. end diff --git a/doc/source/reference/storage/cinder-guide-quobyte.rst b/doc/source/reference/storage/cinder-guide-quobyte.rst index ce38223fa6..0423756b83 100644 --- a/doc/source/reference/storage/cinder-guide-quobyte.rst +++ b/doc/source/reference/storage/cinder-guide-quobyte.rst @@ -12,7 +12,7 @@ Cinder driver in ``/etc/kolla/globals.yml``. .. code-block:: yaml - enable_cinder_backend_quobyte: "yes" + enable_cinder_backend_quobyte: true .. end diff --git a/doc/source/reference/storage/cinder-guide.rst b/doc/source/reference/storage/cinder-guide.rst index 9f8a5bf2aa..07192f0fb3 100644 --- a/doc/source/reference/storage/cinder-guide.rst +++ b/doc/source/reference/storage/cinder-guide.rst @@ -65,7 +65,7 @@ Enable the ``lvm`` backend in ``/etc/kolla/globals.yml``: .. code-block:: yaml - enable_cinder_backend_lvm: "yes" + enable_cinder_backend_lvm: true .. note:: @@ -105,7 +105,7 @@ Finally, enable the ``nfs`` backend in ``/etc/kolla/globals.yml``: .. code-block:: yaml - enable_cinder_backend_nfs: "yes" + enable_cinder_backend_nfs: true Validation ~~~~~~~~~~ @@ -161,7 +161,7 @@ exist on the server and following parameter must be specified in .. code-block:: yaml - enable_cinder_backend_lvm: "yes" + enable_cinder_backend_lvm: true For Ubuntu and LVM2/iSCSI ------------------------- @@ -202,9 +202,9 @@ the following parameter must be specified in ``globals.yml``: .. code-block:: yaml - enable_cinder_backend_iscsi: "yes" + enable_cinder_backend_iscsi: true -Also ``enable_cinder_backend_lvm`` should be set to ``no`` in this case. +Also ``enable_cinder_backend_lvm`` should be set to ``false`` in this case. Skip Cinder prechecks for Custom backends ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/source/reference/storage/external-ceph-guide.rst b/doc/source/reference/storage/external-ceph-guide.rst index f37678eb29..49e64d6c32 100644 --- a/doc/source/reference/storage/external-ceph-guide.rst +++ b/doc/source/reference/storage/external-ceph-guide.rst @@ -412,7 +412,7 @@ for Ceph includes following steps: .. code-block:: yaml - enable_manila_backend_cephfs_native: "yes" + enable_manila_backend_cephfs_native: true * Configure Ceph authentication details in ``/etc/kolla/globals.yml``: diff --git a/doc/source/reference/storage/manila-guide.rst b/doc/source/reference/storage/manila-guide.rst index fa0f2f11fc..d0d09dce94 100644 --- a/doc/source/reference/storage/manila-guide.rst +++ b/doc/source/reference/storage/manila-guide.rst @@ -39,14 +39,14 @@ Cinder is required, enable it in ``/etc/kolla/globals.yml``: .. code-block:: console - enable_cinder: "yes" + enable_cinder: true Enable Manila and generic back end in ``/etc/kolla/globals.yml``: .. code-block:: console - enable_manila: "yes" - enable_manila_backend_generic: "yes" + enable_manila: true + enable_manila_backend_generic: true By default Manila uses instance flavor id 100 for its file systems. For Manila to work, either create a new nova flavor with id 100 (use *nova flavor-create*) diff --git a/doc/source/reference/storage/manila-hnas-guide.rst b/doc/source/reference/storage/manila-hnas-guide.rst index 7de399828c..107205982e 100644 --- a/doc/source/reference/storage/manila-hnas-guide.rst +++ b/doc/source/reference/storage/manila-hnas-guide.rst @@ -77,8 +77,8 @@ Enable Shared File Systems service and HNAS driver in .. code-block:: yaml - enable_manila: "yes" - enable_manila_backend_hnas: "yes" + enable_manila: true + enable_manila_backend_hnas: true Configure the OpenStack networking so it can reach HNAS Management interface and HNAS EVS Data interface. diff --git a/doc/source/reference/storage/manila-pure-guide.rst b/doc/source/reference/storage/manila-pure-guide.rst index 46c1f2fdff..9cb3e756ae 100644 --- a/doc/source/reference/storage/manila-pure-guide.rst +++ b/doc/source/reference/storage/manila-pure-guide.rst @@ -61,8 +61,8 @@ Enable Shared File Systems service and FlashBlade driver in .. code-block:: yaml - enable_manila: "yes" - enable_manila_backend_flashblade: "yes" + enable_manila: true + enable_manila_backend_flashblade: true Configure the OpenStack networking so it can reach FlashBlade Management interface and FlashBlade Data interface. diff --git a/doc/source/user/multi-regions.rst b/doc/source/user/multi-regions.rst index dcee26d162..8d4c4043ac 100644 --- a/doc/source/user/multi-regions.rst +++ b/doc/source/user/multi-regions.rst @@ -29,8 +29,8 @@ Keystone and Horizon are enabled: .. code-block:: console - enable_keystone: "yes" - enable_horizon: "yes" + enable_keystone: true + enable_horizon: true Then, change the value of ``multiple_regions_names`` to add names of other regions. In this example, we consider two regions. The current one, @@ -71,14 +71,6 @@ the value of ``kolla_internal_fqdn`` in RegionOne: keystone_internal_url: "{{ internal_protocol }}://{{ kolla_internal_fqdn_r1 }}:{{ keystone_public_port }}" - openstack_auth: - auth_url: "{{ keystone_internal_url }}" - username: "{{ keystone_admin_user }}" - password: "{{ keystone_admin_password }}" - user_domain_name: "{{ default_user_domain_name }}" - project_name: "{{ keystone_admin_project }}" - domain_name: "default" - .. note:: If the ``kolla_internal_vip_address`` and/or the @@ -151,7 +143,7 @@ unnecessary in this region and run ``kolla-ansible``: .. code-block:: yaml - enable_keystone: "no" - enable_horizon: "no" + enable_keystone: false + enable_horizon: false The configuration is the same for any other region. diff --git a/doc/source/user/operating-kolla.rst b/doc/source/user/operating-kolla.rst index 8e931997da..44e3ddd881 100644 --- a/doc/source/user/operating-kolla.rst +++ b/doc/source/user/operating-kolla.rst @@ -43,7 +43,7 @@ Upgrade procedure .. note:: - If you have set ``enable_cells`` to ``yes`` then you should read the + If you have set ``enable_cells`` to ``true`` then you should read the upgrade notes in the :ref:`Nova cells guide`. Kolla's strategy for upgrades is to never make a mess and to follow consistent @@ -111,8 +111,7 @@ If performing a skip-level (SLURP) upgrade, update ``ansible`` or pip3 install --upgrade 'ansible-core>=|ANSIBLE_CORE_VERSION_MIN|,<|ANSIBLE_CORE_VERSION_MAX|.99' -If upgrading to a Yoga release or later, install or upgrade Ansible Galaxy -dependencies: +Install or upgrade Ansible Galaxy dependencies: .. code-block:: console @@ -150,7 +149,7 @@ For example: .. code-block:: console cp /etc/kolla/passwords.yml passwords.yml.old - cp kolla-ansible/etc/kolla/passwords.yml passwords.yml.new + cp /path/to/venv/share/kolla-ansible/etc/kolla/passwords.yml passwords.yml.new kolla-genpwd -p passwords.yml.new kolla-mergepwd --old passwords.yml.old --new passwords.yml.new --final /etc/kolla/passwords.yml @@ -316,6 +315,8 @@ Tools ----- Kolla ships with several utilities intended to facilitate ease of operation. +If you installed Kolla Ansible in a virtual environment, these scripts are +located in ``/path/to/venv/share/kolla-ansible/tools/``. ``tools/cleanup-containers`` is used to remove deployed containers from the system. This can be useful when you want to do a new clean deployment. It will diff --git a/doc/source/user/quickstart-development.rst b/doc/source/user/quickstart-development.rst index 6e29a2ad51..f61e972cce 100644 --- a/doc/source/user/quickstart-development.rst +++ b/doc/source/user/quickstart-development.rst @@ -98,7 +98,7 @@ Install Kolla-ansible git clone --branch |KOLLA_BRANCH_NAME| https://opendev.org/openstack/kolla-ansible -#. Install requirements of ``kolla`` and ``kolla-ansible``: +#. Install ``kolla-ansible`` and its dependencies: .. code-block:: console @@ -160,8 +160,7 @@ manually or by running random password generator: .. code-block:: console - cd kolla-ansible/tools - ./generate_passwords.py + kolla-genpwd Kolla globals.yml ----------------- @@ -244,7 +243,7 @@ There are a few options that are required to deploy Kolla Ansible: By default Kolla Ansible provides a bare compute kit, however it does provide support for a vast selection of additional services. To enable them, set - ``enable_*`` to "yes". + ``enable_*`` to ``true``. Kolla now supports many OpenStack services, there is `a list of available services @@ -283,27 +282,28 @@ need to setup basic host-level dependencies, like docker. Kolla Ansible provides a playbook that will install all required services in the correct versions. -The following assumes the use of the ``all-in-one`` inventory. If using a -different inventory, such as ``multinode``, replace the ``-i`` argument -accordingly. +The following assumes the use of the ``all-in-one`` inventory in your +current directory. +If using a different inventory, such as ``multinode``, replace the ``-i`` +argument accordingly. #. Bootstrap servers with kolla deploy dependencies: .. code-block:: console - kolla-ansible bootstrap-servers -i ../all-in-one + kolla-ansible bootstrap-servers -i all-in-one #. Do pre-deployment checks for hosts: .. code-block:: console - kolla-ansible prechecks -i ../all-in-one + kolla-ansible prechecks -i all-in-one #. Finally proceed to actual OpenStack deployment: .. code-block:: console - kolla-ansible deploy -i ../all-in-one + kolla-ansible deploy -i all-in-one When this playbook finishes, OpenStack should be up, running and functional! If error occurs during execution, refer to diff --git a/doc/source/user/quickstart.rst b/doc/source/user/quickstart.rst index f02401fc25..f2978b95ac 100644 --- a/doc/source/user/quickstart.rst +++ b/doc/source/user/quickstart.rst @@ -235,11 +235,11 @@ There are a few options that are required to deploy Kolla Ansible: By default Kolla Ansible provides a bare compute kit, however it does provide support for a vast selection of additional services. To enable them, set - ``enable_*`` to "yes". + ``enable_*`` to ``true``. Kolla now supports many OpenStack services, there is `a list of available services - `_. + `_. For more information about service configuration, Please refer to the :kolla-ansible-doc:`Services Reference Guide `. diff --git a/doc/source/user/troubleshooting.rst b/doc/source/user/troubleshooting.rst index 76a9ac6047..289b89220e 100644 --- a/doc/source/user/troubleshooting.rst +++ b/doc/source/user/troubleshooting.rst @@ -48,7 +48,7 @@ Debugging Kolla ~~~~~~~~~~~~~~~ The status of containers after deployment can be determined on the deployment -targets by executing: +targets by executing (use `podman` instead of `docker` if applicable): .. code-block:: console @@ -76,8 +76,10 @@ If the stdout logs are needed, please run: Note that most of the containers don't log to stdout so the above command will provide no information. -To learn more about Docker command line operation please refer to `Docker -documentation `__. +To learn more about container engine command line operation, please refer +to the `Docker +documentation `__ or the `Podman +documentation `__. The log volume "kolla_logs" is linked to ``/var/log/kolla`` on the host. You can find all kolla logs in there. diff --git a/etc/kolla/globals.yml b/etc/kolla/globals.yml index da9246a4d9..b4ade81cae 100644 --- a/etc/kolla/globals.yml +++ b/etc/kolla/globals.yml @@ -733,6 +733,7 @@ workaround_ansible_issue_8743: true #enable_prometheus_elasticsearch_exporter: "{{ enable_prometheus | bool and enable_elasticsearch | bool }}" #enable_prometheus_blackbox_exporter: "{{ enable_prometheus | bool }}" #enable_prometheus_libvirt_exporter: "{{ enable_prometheus | bool and enable_nova | bool and nova_compute_virt_type in ['kvm', 'qemu'] }}" +#enable_prometheus_openstack_network_exporter: "{{ enable_prometheus | bool }}" #enable_prometheus_etcd_integration: "{{ enable_prometheus | bool and enable_etcd | bool }}" #enable_prometheus_valkey_exporter: "{{ enable_prometheus | bool and enable_valkey | bool }}" diff --git a/lint-requirements.txt b/lint-requirements.txt index a7adc68a30..fba7ae1269 100644 --- a/lint-requirements.txt +++ b/lint-requirements.txt @@ -1,11 +1,11 @@ ansible>=12,<14 # GPLv3 -ansible-lint<26 # MIT +ansible-lint===26.4.0 # MIT bandit>=1.1.0 # Apache-2.0 bashate>=0.5.1 # Apache-2.0 codespell<3 # GPLv2 doc8>=0.6.0 # Apache-2.0 hacking>=3.0.1 # Apache-2.0 -j2lint<2 # MIT +j2lint===1.2.0 # MIT pycodestyle>=2.11.0 # MIT reno>=3.1.0 # Apache-2.0 yamllint>=1.22.0 #GPL3 diff --git a/releasenotes/notes/add-prometheus-network-exporter-b5eb1e0e7a33077a.yaml b/releasenotes/notes/add-prometheus-network-exporter-b5eb1e0e7a33077a.yaml new file mode 100644 index 0000000000..39aef5acaa --- /dev/null +++ b/releasenotes/notes/add-prometheus-network-exporter-b5eb1e0e7a33077a.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Adds support for deploying ``OpenStack Network Exporter`` for gathering + OVS/OVN related metrics. This is enabled by default when using + Prometheus. diff --git a/releasenotes/notes/bug-2093414-7cd37ece5c306507.yaml b/releasenotes/notes/bug-2093414-7cd37ece5c306507.yaml new file mode 100644 index 0000000000..3b1d0ce59c --- /dev/null +++ b/releasenotes/notes/bug-2093414-7cd37ece5c306507.yaml @@ -0,0 +1,12 @@ +--- +upgrade: + - | + The default session cache backend for Horizon has changed when + Valkey is enabled. If ``enable_valkey`` is set to ``true``, + Valkey will be used as the preferred backend to improve + availability. +fixes: + - | + Improves Horizon availability when cache nodes fail by adding + support for Valkey as a session cache backend. + `LP#2093414 `__ diff --git a/releasenotes/notes/bug-2134455-idp-fixes-aa7064473be5e44d.yaml b/releasenotes/notes/bug-2134455-idp-fixes-aa7064473be5e44d.yaml new file mode 100644 index 0000000000..6c82cc1784 --- /dev/null +++ b/releasenotes/notes/bug-2134455-idp-fixes-aa7064473be5e44d.yaml @@ -0,0 +1,20 @@ +--- +deprecations: + - | + Remove option to set OIDCHTMLErrorTemplate in Debian 13 and Rocky 10. + As this option was removed in 2.4.14 version of modoidc auth plugin. + It is still present in Ubuntu Noble and can be used there. This applies + only when using `keystone_wsgi_provider: apache`, which is not the default. +fixes: + - | + Fixes federation path for new keystone-httpd container. Previously + the normal keystone container running apache wsgi was used. After + migration to the uwsgi container the federation logic remained in + the keystone-httpd container, but the federation files were never + mounted there. + `LP#2134455 `__. +other: + - | + Add more CI coverage for Federation codepath. Migrate ansible to use + `openstack.cloud` ansible collection modules for configuring federation. + Previously it was done using python-openstackclient. diff --git a/releasenotes/notes/diable_ha_vrrp_health_check_interval-c211e930802bd8dd.yaml b/releasenotes/notes/diable_ha_vrrp_health_check_interval-c211e930802bd8dd.yaml new file mode 100644 index 0000000000..4c3a6f28f0 --- /dev/null +++ b/releasenotes/notes/diable_ha_vrrp_health_check_interval-c211e930802bd8dd.yaml @@ -0,0 +1,8 @@ +--- +upgrade: + - | + By default, ML2/OVS L3 routers no longer set + ``ha_vrrp_health_check_interval`` when + ``enable_neutron_agent_ha`` is true. + This is to prevent stability issues when + Neutron is unable to keep up with L3 router state changes. diff --git a/releasenotes/notes/implement-neutron-ovn-vpn-agent-b848fb4c245e415e.yaml b/releasenotes/notes/implement-neutron-ovn-vpn-agent-b848fb4c245e415e.yaml new file mode 100644 index 0000000000..dd9ab57a12 --- /dev/null +++ b/releasenotes/notes/implement-neutron-ovn-vpn-agent-b848fb4c245e415e.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Add support for deploying neutron_ovn_vpn_agent. + This enables the use of vpnaas in ovn environments. + `__ diff --git a/releasenotes/notes/rename-kolla-toolbox-role-31e3b6c34519f68c.yaml b/releasenotes/notes/rename-kolla-toolbox-role-31e3b6c34519f68c.yaml new file mode 100644 index 0000000000..ecfcd43704 --- /dev/null +++ b/releasenotes/notes/rename-kolla-toolbox-role-31e3b6c34519f68c.yaml @@ -0,0 +1,10 @@ +--- +upgrade: + - | + ``common`` Ansible role has been renamed to ``kolla_toolbox``. + Also the ``kolla-toolbox`` Ansible inventory group has been renamed + to ``kolla_toolbox`` to be in line with Ansible requirements. + The tag for ``kolla_toolbox`` deployment task has also been + renamed. + Users should update their inventories and inventory overrides to + reflect this change. diff --git a/releasenotes/notes/toolbox-clouds-yaml-23faf5809aece04c.yaml b/releasenotes/notes/toolbox-clouds-yaml-23faf5809aece04c.yaml new file mode 100644 index 0000000000..7435b4aefd --- /dev/null +++ b/releasenotes/notes/toolbox-clouds-yaml-23faf5809aece04c.yaml @@ -0,0 +1,7 @@ +--- +upgrade: + - | + ``kolla-toolbox`` and all kolla_toolbox based invocations of Ansible + openstack.cloud modules have been reworked to use clouds.yaml. + ``openstack_auth`` variable is only used for passing keystone admin + password for services bootstrap runs. diff --git a/roles/kolla-ansible-check/defaults/main.yml b/roles/kolla-ansible-check/defaults/main.yml new file mode 100644 index 0000000000..21c0fa9064 --- /dev/null +++ b/roles/kolla-ansible-check/defaults/main.yml @@ -0,0 +1,27 @@ +--- +kolla_ansible_check_passwords_file: /etc/kolla/passwords.yml +kolla_ansible_check_ignore_keys: + # TODO(mnasiadka): ansible/roles/nova-cell/tasks/external_ceph.yml#L163 + - cinder_rbd_secret_uuid + # TODO(mnasiadka): ansible/roles/nova-cell/tasks/external_ceph.yml#L163 + - rbd_secret_uuid + # TODO(mnasiadka): Fix in ansible/roles/mariadb/tasks/bootstrap_cluster.yml#L14 + - database_password + # TODO(mnasiadka): Fix in ansible/roles/heat/tasks/bootstrap_service.yml#L22 + - heat_domain_admin_password + # TODO(mnasiadka): Fix openstack_auth all over the place in kolla_toolbox module_args + - keystone_admin_password + # TODO(mnasiadka): Fix in ansible/roles/nova/tasks/map_cell0.yml#L12 + - nova_database_password + # TODO(mnasiadka): Fix in ansible/roles/octavia-certificates/tasks/server_ca.yml + - octavia_ca_password + # TODO(mnasiadka): Fix in ansible/roles/octavia-certificates/tasks/server_ca.yml + - octavia_client_ca_password + # TODO(mnasiadka): Fix openstack_auth all over the place in kolla_toolbox module_args + - octavia_keystone_password + # TODO(mnasiadka): Fix in ansible/roles/valkey/tasks/check.yml#L10 + - valkey_master_password + # TODO(mnasiadka) Fix in ansible/roles/grafana/tasks/post_config.yml#L24 + - prometheus_alertmanager_password + # TODO(mnasiadka) Fix in ansible/roles/rabbitmq/defaults/main.yml#L11 + - rabbitmq_cluster_cookie diff --git a/roles/kolla-ansible-check/library/kolla_ansible_password_check.py b/roles/kolla-ansible-check/library/kolla_ansible_password_check.py new file mode 100644 index 0000000000..2771386385 --- /dev/null +++ b/roles/kolla-ansible-check/library/kolla_ansible_password_check.py @@ -0,0 +1,413 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright 2026 StackHPC Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ansible.module_utils.basic import AnsibleModule +import atexit +import os +import subprocess +import tempfile + +__metaclass__ = type + +DOCUMENTATION = r""" +--- +module: kolla_ansible_password_check +short_description: Check kolla-ansible passwords.yml for leaked secrets +description: + - Reads a kolla-ansible passwords.yml file and searches the systemd journal + for any occurrences of the password values. + - Reports which variable names had their secrets found in the journal. + - Fails if any leaked secrets are detected. + - All secret values are handled internally and never appear in Ansible + output, logs, or return values — only variable names are ever surfaced. +version_added: "1.0.0" +author: + - Michal Nasiadka +options: + passwords_file: + description: + - Path to the kolla-ansible passwords.yml file on the remote host. + type: path + required: true + min_password_length: + description: + - Minimum length a password value must have to be checked. + - Very short values (e.g. single characters) are skipped to avoid + false positives. + type: int + default: 8 + journalctl_args: + description: + - Extra arguments passed verbatim to journalctl + (e.g. C(--since "1 hour ago")). + - Do not include C(--no-pager) or C(-g) / C(--grep) as these are added + automatically. + type: str + default: "" + fail_on_leaked: + description: + - Whether to fail the task when leaked secrets are found. + - Set to C(false) to report leaks without failing, useful for dry-runs. + type: bool + default: true + return_stdout: + description: + - When C(true), include the journalctl output for each leaked entry + in the C(leaked_entries) return value. + - Has no effect when there are no leaks. + - Note that journalctl output for a leaked entry will contain the + secret value. Use C(no_log) on any subsequent tasks that display + C(leaked_entries) if you need to protect it. + type: bool + default: false + ignore_keys: + description: + - List of variable names whose presence in the journal should not be + treated as a leak. + - Entries in this list are still checked against the journal; they are + just excluded from C(leaked_keys), C(leaked_entries), and the failure + condition. + - Matched entries are reported separately in C(ignored_leaked_keys) so + there is a full audit trail of what was intentionally allowed. + type: list + elements: str + default: [] +notes: + - Requires C(journalctl) and C(grep) to be available on the remote host. + - Must be run with sufficient privileges to read the journal + (typically requires C(become: true)). + - The journal is dumped once to a temporary file and then C(grep -F) is + run per password against that file, which is significantly faster than + running C(journalctl --grep) once per password. + - The temporary file is deleted automatically when the module exits. + - Secret values are B(never) included in module return data, only variable + names are returned, making this safe to use without C(no_log). +requirements: + - journalctl (systemd) + - PyYAML +""" + +EXAMPLES = r""" +- name: Check kolla passwords for journal leaks + kolla_ansible_password_check: + passwords_file: /etc/kolla/passwords.yml + become: true + register: leak_result + +- name: Show which keys leaked + ansible.builtin.debug: + msg: "Leaked keys: {{ leak_result.leaked_keys }}" + when: leak_result.leaked_keys | length > 0 + +# Non-failing variant for reporting +- name: Audit journal leaks without failing + kolla_ansible_password_check: + passwords_file: /etc/kolla/passwords.yml + fail_on_leaked: false + journalctl_args: '--since "24 hours ago"' + become: true + register: audit_result +""" + +RETURN = r""" +leaked_keys: + description: + - List of variable names from passwords.yml whose values were found in + the journal. Never contains the actual secret values. + type: list + elements: str + returned: always + sample: ["keystone_db_password", "nova_keystone_password"] +checked_count: + description: Number of password entries that were actually checked. + type: int + returned: always + sample: 42 +skipped_count: + description: + - Number of entries skipped because their value was empty, null, + non-string, or shorter than min_password_length. + type: int + returned: always + sample: 5 +msg: + description: Human-readable summary of the check result. + type: str + returned: always + sample: "No secrets found in journal. Checked 42 entries." +leaked_entries: + description: + - Mapping of leaked variable names to their journalctl output. + - Only populated when C(return_stdout: true) and leaks are found. + - The journalctl output will contain the secret value — treat accordingly. + type: dict + returned: when return_stdout is true and leaks are found + sample: {"keystone_db_password": "Mar 26 ... keystone_db_password=s3cr3t"} +ignored_leaked_keys: + description: + - List of variable names that were found in the journal but are present + in C(ignore_keys) and therefore excluded from C(leaked_keys). + - Always returned so there is a full audit trail of intentional allowances. + type: list + elements: str + returned: always + sample: ["deployment_ssh_key"] +""" + +try: + import yaml + HAS_YAML = True +except ImportError: + HAS_YAML = False + + +def load_passwords(module, passwords_file): + """Load and parse the kolla passwords YAML file. + + Returns a dict of {variable_name: password_value}. + Aborts the module on any read/parse error. + """ + if not os.path.isfile(passwords_file): + module.fail_json( + msg="passwords_file not found: {}".format(passwords_file)) + + try: + with open(passwords_file, "r") as fh: + content = fh.read() + except OSError as exc: + module.fail_json( + msg="Cannot read passwords_file: {}".format(str(exc))) + + try: + data = yaml.safe_load(content) + except yaml.YAMLError as exc: + module.fail_json( + msg="Failed to parse passwords YAML: {}".format(str(exc))) + + if data is None: + return {} + if not isinstance(data, dict): + module.fail_json( + msg="passwords_file must contain a YAML mapping at the top level" + ) + + return data + + +def dump_journal(module, extra_args): + """Dump the full journal to a temporary file. + + Returns the path to the temp file. The file is registered for deletion + via atexit so it is cleaned up even if the module exits unexpectedly. + """ + try: + tmp = tempfile.NamedTemporaryFile( + prefix="kolla_password_check_", + suffix=".log", + delete=False, + ) + tmp.close() + except OSError as exc: + module.fail_json(msg="Failed to create temp file: {}".format(str(exc))) + + # Register cleanup before the subprocess so the file is always removed. + atexit.register(_unlink_silent, tmp.name) + + cmd = ["journalctl", "--no-pager"] + if extra_args: + cmd.extend(extra_args.split()) + + try: + with open(tmp.name, "w") as fh: + result = subprocess.run( + cmd, + stdout=fh, + stderr=subprocess.PIPE, + ) + except OSError as exc: + module.fail_json(msg="Failed to run journalctl: {}".format(str(exc))) + + if result.returncode != 0: + stderr_text = result.stderr.decode("utf-8", errors="replace").strip() + module.fail_json( + msg="journalctl exited with code {}: {}".format( + result.returncode, stderr_text + ) + ) + + return tmp.name + + +def grep_journal(module, journal_file, value, return_stdout): + """Search journal_file for value using grep -F (fixed string). + + Returns (found, matching_lines) where matching_lines is a string of + all matching lines (only populated when return_stdout is True). + """ + # -F: fixed string (no regex, no escaping needed) + # -q: quiet — exit 0 immediately on first match when return_stdout is False + cmd = ["grep", "-F"] + if not return_stdout: + cmd.append("-q") + cmd.extend(["--", value, journal_file]) + + try: + result = subprocess.run( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + except OSError as exc: + module.fail_json(msg="Failed to run grep: {}".format(str(exc))) + + # grep exits 0 = match found, 1 = no match, 2+ = error. + if result.returncode == 0: + stdout = result.stdout.decode( + "utf-8", errors="replace") if return_stdout else "" + return True, stdout + elif result.returncode == 1: + return False, "" + else: + stderr_text = result.stderr.decode("utf-8", errors="replace").strip() + module.warn( + "grep returned exit code {} while checking an entry. " + "stderr: {}".format(result.returncode, stderr_text) + ) + return False, "" + + +def _unlink_silent(path): + """Delete a file, ignoring errors (used as atexit handler).""" + try: + os.unlink(path) + except OSError: + pass + + +def run_module(): + module_args = dict( + passwords_file=dict(type="path", required=True), + min_password_length=dict(type="int", default=8), + journalctl_args=dict(type="str", default=""), + fail_on_leaked=dict(type="bool", default=True), + return_stdout=dict(type="bool", default=False), + ignore_keys=dict(type="list", elements="str", default=[]), + ) + + module = AnsibleModule( + argument_spec=module_args, + supports_check_mode=True, + ) + + if not HAS_YAML: + module.fail_json(msg="PyYAML is required for this module.") + + passwords_file = module.params["passwords_file"] + min_length = module.params["min_password_length"] + extra_args = module.params["journalctl_args"] + fail_on_leaked = module.params["fail_on_leaked"] + return_stdout = module.params["return_stdout"] + ignore_keys = set(module.params["ignore_keys"]) + + passwords = load_passwords(module, passwords_file) + + leaked_keys = [] + leaked_entries = {} + ignored_leaked_keys = [] + checked_count = 0 + skipped_count = 0 + + if not module.check_mode: + journal_file = dump_journal(module, extra_args) + + for idx, (key, value) in enumerate(passwords.items()): + # Skip null, non-string, or suspiciously short values. + if not isinstance(value, str): + skipped_count += 1 + continue + if len(value) < min_length: + skipped_count += 1 + continue + + checked_count += 1 + + # In check mode we report what *would* be checked without hitting + # journalctl, since we can't know what the journal contains. + if module.check_mode: + continue + + found, stdout = grep_journal( + module, journal_file, value, return_stdout) + if found: + if key in ignore_keys: + # Found in journal but explicitly allowed — track separately + # for audit purposes but do not treat as a failure. + ignored_leaked_keys.append(key) + else: + # Only the key name is stored by default — the secret value is + # intentionally never written to any Ansible data structure + # unless return_stdout is explicitly requested. + leaked_keys.append(key) + if return_stdout: + leaked_entries[key] = stdout + + if leaked_keys: + summary = ( + "Leaked secrets found in journal for {} variable(s): {}. " + "Checked {} entries, skipped {}.".format( + len(leaked_keys), + ", ".join(leaked_keys), + checked_count, + skipped_count, + ) + ) + else: + summary = ( + "No secrets found in journal. " + "Checked {} entries, skipped {}.""".format( + checked_count, + skipped_count + ) + ) + + if ignored_leaked_keys: + summary += " Ignored {} allowed variable(s): {}.".format( + len(ignored_leaked_keys), ", ".join(ignored_leaked_keys) + ) + + result = dict( + changed=False, + leaked_keys=leaked_keys, + leaked_entries=leaked_entries, + ignored_leaked_keys=ignored_leaked_keys, + checked_count=checked_count, + skipped_count=skipped_count, + msg=summary, + ) + + if leaked_keys and fail_on_leaked: + module.fail_json(**result) + + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/roles/kolla-ansible-check/tasks/main.yml b/roles/kolla-ansible-check/tasks/main.yml new file mode 100644 index 0000000000..c027438d94 --- /dev/null +++ b/roles/kolla-ansible-check/tasks/main.yml @@ -0,0 +1,4 @@ +--- +- name: Import passwords.yml + ansible.builtin.import_tasks: passwords.yml + when: not is_upgrade diff --git a/roles/kolla-ansible-check/tasks/passwords.yml b/roles/kolla-ansible-check/tasks/passwords.yml new file mode 100644 index 0000000000..6919090b24 --- /dev/null +++ b/roles/kolla-ansible-check/tasks/passwords.yml @@ -0,0 +1,7 @@ +--- +- name: Test for leaked passwords in journal + become: true + kolla_ansible_password_check: + passwords_file: "{{ kolla_ansible_check_passwords_file }}" + ignore_keys: "{{ kolla_ansible_check_ignore_keys }}" + when: inventory_hostname == 'primary' diff --git a/roles/kolla-ansible-test-dashboard/tasks/main.yml b/roles/kolla-ansible-test-dashboard/tasks/main.yml index 02b218212f..12950d77c3 100644 --- a/roles/kolla-ansible-test-dashboard/tasks/main.yml +++ b/roles/kolla-ansible-test-dashboard/tasks/main.yml @@ -88,6 +88,7 @@ - name: Run testinfra tests environment: HORIZON_PROTO: "{{ 'https' if tls_enabled | bool else 'http' }}" + SCENARIO: "{{ scenario }}" ansible.builtin.shell: cmd: > . {{ kolla_ansible_venv_path }}/bin/activate && diff --git a/roles/openstack-clients/defaults/main.yml b/roles/openstack-clients/defaults/main.yml index 6b1e3c6d97..e1f53e2799 100644 --- a/roles/openstack-clients/defaults/main.yml +++ b/roles/openstack-clients/defaults/main.yml @@ -14,6 +14,8 @@ openstack_clients_pip_packages: enabled: "{{ scenario == 'ironic' }}" - package: python-magnumclient enabled: "{{ scenario == 'magnum' }}" + - package: python-neutronclient + enabled: "{{ scenario == 'ovn' }}" - package: python-masakariclient enabled: "{{ scenario == 'masakari' }}" - package: python-mistralclient diff --git a/roles/test-ovn-vpnaas/defaults/main.yml b/roles/test-ovn-vpnaas/defaults/main.yml new file mode 100644 index 0000000000..e55c4d338e --- /dev/null +++ b/roles/test-ovn-vpnaas/defaults/main.yml @@ -0,0 +1,14 @@ +--- +ovn_vpnaas_openrc: "/etc/kolla/admin-openrc.sh" +ovn_vpnaas_venv: "{{ ansible_env.HOME }}/openstackclient-venv" + +ovn_vpnaas_activate: ". {{ ovn_vpnaas_venv }}/bin/activate &&" + +ovn_vpnaas_west_cidr: "192.168.10.0/24" +ovn_vpnaas_east_cidr: "192.168.20.0/24" +ovn_vpnaas_psk: "secret" + +ovn_vpnaas_consistency_retries: 10 +ovn_vpnaas_consistency_delay: 5 +ovn_vpnaas_tunnel_retries: 20 +ovn_vpnaas_tunnel_delay: 15 diff --git a/roles/test-ovn-vpnaas/tasks/cleanup_site.yml b/roles/test-ovn-vpnaas/tasks/cleanup_site.yml new file mode 100644 index 0000000000..403e3020d2 --- /dev/null +++ b/roles/test-ovn-vpnaas/tasks/cleanup_site.yml @@ -0,0 +1,46 @@ +--- +- name: "VPNaaS | Cleanup | Site: {{ site_to_clean }}" + block: + - name: "VPNaaS | Cleanup | Delete Connection" + ansible.builtin.shell: | + {{ ovn_vpnaas_activate }} + openstack vpn ipsec site connection delete "conn_{{ site_to_clean }}" || true + environment: "{{ os_auth_env }}" + changed_when: false + + - name: "VPNaaS | Cleanup | Delete VPN Service" + ansible.builtin.shell: | + {{ ovn_vpnaas_activate }} + openstack vpn service delete "vpn_{{ site_to_clean }}" || true + environment: "{{ os_auth_env }}" + changed_when: false + + - name: "VPNaaS | Cleanup | Delete Endpoint Groups" + ansible.builtin.shell: | + {{ ovn_vpnaas_activate }} + openstack vpn endpoint group delete "{{ site_to_clean }}-local-epg" || true + openstack vpn endpoint group delete "{{ site_to_clean }}-peer-epg" || true + environment: "{{ os_auth_env }}" + changed_when: false + + - name: "VPNaaS | Cleanup | Remove Subnet from Router" + ansible.builtin.shell: | + {{ ovn_vpnaas_activate }} + openstack router remove subnet "router_{{ site_to_clean }}" "subnet_{{ site_to_clean }}" || true + environment: "{{ os_auth_env }}" + changed_when: false + + - name: "VPNaaS | Cleanup | Delete Router" + ansible.builtin.shell: | + {{ ovn_vpnaas_activate }} + openstack router delete "router_{{ site_to_clean }}" || true + environment: "{{ os_auth_env }}" + changed_when: false + + - name: "VPNaaS | Cleanup | Delete Network/Subnet" + ansible.builtin.shell: | + {{ ovn_vpnaas_activate }} + openstack subnet delete "subnet_{{ site_to_clean }}" || true + openstack network delete "net_{{ site_to_clean }}" || true + environment: "{{ os_auth_env }}" + changed_when: false diff --git a/roles/test-ovn-vpnaas/tasks/init_env.yml b/roles/test-ovn-vpnaas/tasks/init_env.yml new file mode 100644 index 0000000000..d448c95fc4 --- /dev/null +++ b/roles/test-ovn-vpnaas/tasks/init_env.yml @@ -0,0 +1,33 @@ +--- +- name: VPNaaS | Install requirements in venv + ansible.builtin.pip: + name: + - "python-neutronclient" + - "openstacksdk" + virtualenv: "{{ ovn_vpnaas_venv }}" + state: present + +- name: VPNaaS | Load OpenStack credentials from openrc + ansible.builtin.shell: | + set -o pipefail + . {{ ovn_vpnaas_openrc }} + env | grep ^OS_ + args: + executable: /bin/bash + register: openrc_env + changed_when: false + +- name: VPNaaS | Convert OS_* env to dict + ansible.builtin.set_fact: + os_auth_env: >- + {{ + dict( + openrc_env.stdout_lines + | map('split', '=', 1) + | list + ) + }} + +- name: VPNaaS | Add venv to PATH + ansible.builtin.set_fact: + os_auth_env: "{{ os_auth_env | combine({'PATH': ovn_vpnaas_venv + '/bin:' + ansible_facts['env']['PATH']}) }}" diff --git a/roles/test-ovn-vpnaas/tasks/main.yml b/roles/test-ovn-vpnaas/tasks/main.yml new file mode 100644 index 0000000000..ee5a718e0f --- /dev/null +++ b/roles/test-ovn-vpnaas/tasks/main.yml @@ -0,0 +1,211 @@ +--- +- name: VPNaaS | Init ENV + ansible.builtin.include_tasks: init_env.yml + +- name: VPNaaS | Check if VPN agents are alive and reporting + ansible.builtin.shell: | + set -o pipefail + {{ ovn_vpnaas_activate }} + openstack network agent list -f value -c Binary -c Alive | grep "vpn-agent" | awk '{print $2}' + args: + executable: /bin/bash + register: vpn_agents_alive + until: + - vpn_agents_alive.stdout != "" + - "'False' not in vpn_agents_alive.stdout" + retries: 10 + delay: 5 + environment: "{{ os_auth_env }}" + changed_when: false + +- name: VPNaaS | Create IKE and IPsec Policies + ansible.builtin.shell: | + {{ ovn_vpnaas_activate }} + openstack vpn ike policy create ikepolicy --ike-version v2 --auth-algorithm sha256 --encryption-algorithm aes-256 --pfs group14 || true + openstack vpn ipsec policy create ipsecpolicy --auth-algorithm sha256 --encryption-algorithm aes-256 --pfs group14 || true + environment: "{{ os_auth_env }}" + changed_when: false + +- name: VPNaaS | Setup Network Infrastructure + ansible.builtin.include_tasks: setup_site.yml + vars: + site_name: "{{ item.name }}" + site_cidr: "{{ item.cidr }}" + peer_cidr: "{{ item.peer }}" + loop: + - { name: 'west', cidr: "{{ ovn_vpnaas_west_cidr }}", peer: "{{ ovn_vpnaas_east_cidr }}" } + - { name: 'east', cidr: "{{ ovn_vpnaas_east_cidr }}", peer: "{{ ovn_vpnaas_west_cidr }}" } + +- name: VPNaaS | Wait for OVN Agent to settle + ansible.builtin.pause: + minutes: 2 + +- name: VPNaaS | Check if VPN service west exists + ansible.builtin.shell: | + set -o pipefail + {{ ovn_vpnaas_activate }} + openstack vpn service list -f value -c ID -c Name | awk '$2=="vpn_west" {print $1}' | head -n 1 + args: + executable: /bin/bash + environment: "{{ os_auth_env }}" + register: check_vpn_west + changed_when: false + +- name: VPNaaS | Create VPN service | west + ansible.builtin.shell: | + {{ ovn_vpnaas_activate }} + openstack vpn service create --router "router_west" "vpn_west" + environment: "{{ os_auth_env }}" + when: check_vpn_west.stdout | trim == "" + failed_when: false + changed_when: false + +- name: VPNaaS | Settle database consistency before next service + ansible.builtin.pause: + seconds: 20 + +- name: VPNaaS | Ensure VPN service west exists and get ID + ansible.builtin.shell: | + set -o pipefail + {{ ovn_vpnaas_activate }} + openstack vpn service list -f value -c ID -c Name | awk '$2=="vpn_west" {print $1}' | head -n 1 + args: + executable: /bin/bash + register: vpn_svc_west_out + until: + - vpn_svc_west_out.rc == 0 + - vpn_svc_west_out.stdout | trim != "" + retries: 20 + delay: 10 + environment: "{{ os_auth_env }}" + changed_when: false + +- name: VPNaaS | Check if VPN service east exists + ansible.builtin.shell: | + set -o pipefail + {{ ovn_vpnaas_activate }} + openstack vpn service list -f value -c ID -c Name | awk '$2=="vpn_east" {print $1}' | head -n 1 + args: + executable: /bin/bash + environment: "{{ os_auth_env }}" + register: check_vpn_east + changed_when: false + +- name: VPNaaS | Create VPN service | east + ansible.builtin.shell: | + {{ ovn_vpnaas_activate }} + openstack vpn service create --router "router_east" "vpn_east" + environment: "{{ os_auth_env }}" + when: check_vpn_east.stdout | trim == "" + failed_when: false + changed_when: false + +- name: VPNaaS | Settle database consistency before next service + ansible.builtin.pause: + seconds: 20 + +- name: VPNaaS | Ensure VPN service east exists in DB + ansible.builtin.shell: | + set -o pipefail + {{ ovn_vpnaas_activate }} + openstack vpn service list -f value -c ID -c Name | awk '$2=="vpn_east" {print $1}' | head -n 1 + args: + executable: /bin/bash + register: vpn_svc_east_out + until: + - vpn_svc_east_out.rc == 0 + - vpn_svc_east_out.stdout | trim != "" + retries: 20 + delay: 10 + environment: "{{ os_auth_env }}" + changed_when: false + +- name: VPNaaS | Create Endpoint Groups + ansible.builtin.shell: | + {{ ovn_vpnaas_activate }} + openstack vpn endpoint group create --type subnet --value "subnet_{{ item.name }}" "{{ item.name }}-local-epg" || true + openstack vpn endpoint group create --type cidr --value "{{ item.peer }}" "{{ item.name }}-peer-epg" || true + loop: + - { name: 'west', peer: "{{ ovn_vpnaas_east_cidr }}" } + - { name: 'east', peer: "{{ ovn_vpnaas_west_cidr }}" } + environment: "{{ os_auth_env }}" + changed_when: false + +- name: VPNaaS | Get Public IPs + ansible.builtin.shell: | + {{ ovn_vpnaas_activate }} + openstack vpn service show "{{ item }}" -f value -c ext_v4_ip + register: vpn_ips + until: + - vpn_ips.stdout | trim != "" + - vpn_ips.stdout | trim != "None" + retries: 24 + delay: 10 + loop: + - "{{ vpn_svc_west_out.stdout.strip() }}" + - "{{ vpn_svc_east_out.stdout.strip() }}" + environment: "{{ os_auth_env }}" + changed_when: false + +- name: VPNaaS | Establish Connections + ansible.builtin.shell: | + {{ ovn_vpnaas_activate }} + openstack vpn ipsec site connection create "conn_east" --vpnservice "{{ vpn_svc_east_out.stdout.strip() }}" --ikepolicy ikepolicy \ + --ipsecpolicy ipsecpolicy --local-endpoint-group east-local-epg --peer-address "{{ vpn_ips.results[0].stdout.strip() }}" \ + --peer-id "{{ vpn_ips.results[0].stdout.strip() }}" --peer-endpoint-group east-peer-epg --psk {{ ovn_vpnaas_psk }} || true + + openstack vpn ipsec site connection create "conn_west" --vpnservice "{{ vpn_svc_west_out.stdout.strip() }}" --ikepolicy ikepolicy \ + --ipsecpolicy ipsecpolicy --local-endpoint-group west-local-epg --peer-address "{{ vpn_ips.results[1].stdout.strip() }}" \ + --peer-id "{{ vpn_ips.results[1].stdout.strip() }}" --peer-endpoint-group west-peer-epg --psk {{ ovn_vpnaas_psk }} || true + environment: "{{ os_auth_env }}" + changed_when: false + +- name: VPNaaS | Wait for Tunnel to be ACTIVE + ansible.builtin.shell: | + {{ ovn_vpnaas_activate }} + openstack vpn ipsec site connection show "conn_{{ item }}" -f value -c status + register: tunnel_status + until: tunnel_status.stdout == "ACTIVE" + retries: "{{ ovn_vpnaas_tunnel_retries }}" + delay: "{{ ovn_vpnaas_tunnel_delay }}" + loop: ["west", "east"] + environment: "{{ os_auth_env }}" + changed_when: false + +- name: VPNaaS | SHOW TUNNEL STATUS RESULT + ansible.builtin.debug: + msg: + - "************************************************************" + - "CONNECTION: conn_{{ item.item }}" + - "STATUS: {{ item.stdout }}" + - "RESULT: TUNNEL ESTABLISHED SUCCESSFULLY!" + - "************************************************************" + loop: "{{ tunnel_status.results }}" + loop_control: + label: "{{ item.item }}" + +- name: VPNaaS | Show Full Connection Details + ansible.builtin.shell: | + {{ ovn_vpnaas_activate }} + openstack vpn ipsec site connection list + environment: "{{ os_auth_env }}" + register: final_list + changed_when: false + +- name: VPNaaS | Print Connection List Table + ansible.builtin.debug: + var: final_list.stdout_lines + +- name: VPNaaS | Final Cleanup + ansible.builtin.include_tasks: cleanup_site.yml + loop: ["west", "east"] + loop_control: + loop_var: site_to_clean + +- name: VPNaaS | Cleanup | Global Policies + ansible.builtin.shell: | + {{ ovn_vpnaas_activate }} + openstack vpn ipsec policy delete ipsecpolicy || true + openstack vpn ike policy delete ikepolicy || true + environment: "{{ os_auth_env }}" + changed_when: false diff --git a/roles/test-ovn-vpnaas/tasks/setup_site.yml b/roles/test-ovn-vpnaas/tasks/setup_site.yml new file mode 100644 index 0000000000..f683dc5967 --- /dev/null +++ b/roles/test-ovn-vpnaas/tasks/setup_site.yml @@ -0,0 +1,76 @@ +--- +- name: VPNaaS | Create network | {{ site_name }} + ansible.builtin.shell: | + {{ ovn_vpnaas_activate }} + openstack network create "net_{{ site_name }}" + environment: "{{ os_auth_env }}" + register: net_create + failed_when: + - net_create.rc != 0 + - "'already exists' not in net_create.stderr" + retries: "{{ ovn_vpnaas_consistency_retries }}" + delay: "{{ ovn_vpnaas_consistency_delay }}" + until: net_create.rc == 0 or 'already exists' in net_create.stderr + changed_when: false + +- name: VPNaaS | Create subnet | {{ site_name }} + ansible.builtin.shell: | + {{ ovn_vpnaas_activate }} + openstack subnet create --network "net_{{ site_name }}" --subnet-range "{{ site_cidr }}" "subnet_{{ site_name }}" + environment: "{{ os_auth_env }}" + register: subnet_create + failed_when: + - subnet_create.rc != 0 + - "'already exists' not in subnet_create.stderr" + retries: "{{ ovn_vpnaas_consistency_retries }}" + delay: "{{ ovn_vpnaas_consistency_delay }}" + until: subnet_create.rc == 0 or 'already exists' in subnet_create.stderr + changed_when: false + +- name: VPNaaS | Create router | {{ site_name }} + ansible.builtin.shell: | + {{ ovn_vpnaas_activate }} + openstack router create --external-gateway public1 "router_{{ site_name }}" + environment: "{{ os_auth_env }}" + failed_when: false + changed_when: false + +- name: VPNaaS | Debug | List all routers + ansible.builtin.shell: | + {{ ovn_vpnaas_activate }} + openstack router list + environment: "{{ os_auth_env }}" + register: all_routers_debug + changed_when: false + +- name: VPNaaS | Debug | Show router list output + ansible.builtin.debug: + var: all_routers_debug.stdout_lines + +- name: VPNaaS | Get router ID | {{ site_name }} + ansible.builtin.shell: | + set -o pipefail + {{ ovn_vpnaas_activate }} + openstack router list --name "router_{{ site_name }}" -f value -c ID | head -n 1 + args: + executable: /bin/bash + register: current_router_id + until: current_router_id.stdout != "" + retries: 5 + delay: 10 + environment: "{{ os_auth_env }}" + changed_when: false + +- name: VPNaaS | Attach subnet to router | {{ site_name }} + ansible.builtin.shell: | + {{ ovn_vpnaas_activate }} + openstack router add subnet "{{ current_router_id.stdout.strip() }}" "subnet_{{ site_name }}" + environment: "{{ os_auth_env }}" + register: router_add_result + failed_when: + - router_add_result.rc != 0 + - "'already has an interface' not in router_add_result.stderr" + retries: "{{ ovn_vpnaas_consistency_retries }}" + delay: "{{ ovn_vpnaas_consistency_delay }}" + until: router_add_result.rc == 0 or 'already has an interface' in router_add_result.stderr + changed_when: false diff --git a/tests/run.yml b/tests/run.yml index 57a3de61b1..775eb2630d 100644 --- a/tests/run.yml +++ b/tests/run.yml @@ -164,6 +164,8 @@ - neutron - nova - bifrost + - keystone-httpd/federation/oidc/metadata + - keystone-httpd/federation/oidc/attribute_maps - name: Generate configuration files template: @@ -210,6 +212,19 @@ - src: "tests/templates/tenks-deploy-config.yml.j2" dest: "{{ ansible_env.HOME }}/tenks.yml" when: "{{ scenario == 'ironic' }}" + # keystone-federation config + - src: "tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.conf.j2" + dest: "/etc/kolla/config/keystone-httpd/federation/oidc/metadata/idp.example.org%2Frealms%2Fexample.conf" + when: "{{ scenario == 'federation' }}" + - src: "tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.provider.j2" + dest: "/etc/kolla/config/keystone-httpd/federation/oidc/metadata/idp.example.org%2Frealms%2Fexample.provider" + when: "{{ scenario == 'federation' }}" + - src: "tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.client.j2" + dest: "/etc/kolla/config/keystone-httpd/federation/oidc/metadata/idp.example.org%2Frealms%2Fexample.client" + when: "{{ scenario == 'federation' }}" + - src: "tests/templates/keystone-federation/attribute_mapping.json" + dest: "/etc/kolla/config/keystone-httpd/federation/oidc/attribute_maps/attribute_mapping.json" + when: "{{ scenario == 'federation' }}" when: item.when | default(true) - block: @@ -414,6 +429,14 @@ SCENARIO: "{{ scenario }}" when: openstack_core_tested or scenario in ['ironic', 'magnum', 'nfv', 'zun', 'octavia'] + - name: Test OVN VPNaaS + import_role: + name: test-ovn-vpnaas + when: + - scenario == 'ovn' + # FIXME(neutron): Enable when https://bugs.launchpad.net/neutron/+bug/2146308 is fixed + - not (ansible_facts.os_family == 'RedHat' and ansible_facts.distribution_major_version == '10') + - name: Run test-ovn.sh script script: cmd: test-ovn.sh @@ -788,6 +811,10 @@ executable: /bin/bash chdir: "{{ kolla_ansible_src_dir }}" + - name: Import role kolla-ansible-check + import_role: + name: kolla-ansible-check + - hosts: primary any_errors_fatal: true tasks: diff --git a/tests/templates/globals-default.j2 b/tests/templates/globals-default.j2 index 80f34b0aa9..5ed9428101 100644 --- a/tests/templates/globals-default.j2 +++ b/tests/templates/globals-default.j2 @@ -195,10 +195,13 @@ neutron_plugin_agent: "ovn" neutron_ovn_distributed_fip: "yes" neutron_enable_ovn_agent: "yes" ovn_sb_db_relay_count: "3" +enable_neutron_vpnaas: "yes" enable_octavia: "yes" octavia_provider_drivers: "ovn:OVN provider" octavia_provider_agents: "ovn" neutron_dns_domain: "example.org." +enable_prometheus: true +enable_prometheus_openstack_exporter: "no" {% endif %} {% if scenario == "prometheus-opensearch" %} @@ -282,6 +285,17 @@ enable_valkey: "yes" {% if scenario == "federation" %} enable_keystone_federation: true +keystone_identity_providers: + - name: "example_provider" + openstack_domain: "Default" + protocol: "openid" + identifier: "https://idp.example.org/realms/example" + public_name: "Example Provider" + attribute_mapping: "sso_oidc_mapping" + metadata_folder: "/etc/kolla/config/keystone-httpd/federation/oidc/metadata" +keystone_identity_mappings: + - name: "sso_oidc_mapping" + file: "/etc/kolla/config/keystone-httpd/federation/oidc/attribute_maps/attribute_mapping.json" {% endif %} mariadb_monitor_read_only_interval: "30000" diff --git a/tests/templates/inventory.j2 b/tests/templates/inventory.j2 index 1e28332982..e9f5da5ad6 100644 --- a/tests/templates/inventory.j2 +++ b/tests/templates/inventory.j2 @@ -255,17 +255,16 @@ common {% if is_upgrade | bool %} [kolla-logs:children] common -{% endif %} [kolla-toolbox:children] common +{% endif %} [kolla_logs:children] -control -network -compute -storage -monitoring +common + +[kolla_toolbox:children] +common [opensearch:children] control @@ -348,6 +347,9 @@ control compute network +[neutron-ovn-vpn-agent:children] +neutron + # Cinder [cinder-api:children] cinder @@ -631,6 +633,10 @@ monitoring [prometheus-libvirt-exporter:children] compute +[prometheus-openstack-network-exporter:children] +compute +network + # NOTE(yoctozepto): In CI we want to test Masakari HA but not of other services, # to conserve the resources. Hence, we set Masakari groups to use both # primary and secondary while the parent group (control) uses only primary. diff --git a/tests/templates/keystone-federation/attribute_mapping.json b/tests/templates/keystone-federation/attribute_mapping.json new file mode 100644 index 0000000000..022cbafd29 --- /dev/null +++ b/tests/templates/keystone-federation/attribute_mapping.json @@ -0,0 +1,42 @@ +[ + { + "local": [ + { + "user": { + "name": "{0}", + "email": "{1}", + "domain": { + "name": "{2}" + } + }, + "domain": { + "name": "{2}" + }, + "projects": [ + { + "name": "{3}", + "roles": [ + { + "name": "member" + } + ] + } + ] + } + ], + "remote": [ + { + "type": "OIDC-preferred_username" + }, + { + "type": "OIDC-email" + }, + { + "type": "OIDC-openstack-user-domain" + }, + { + "type": "OIDC-openstack-default-project" + } + ] + } +] diff --git a/tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.client.j2 b/tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.client.j2 new file mode 100644 index 0000000000..253898f3a6 --- /dev/null +++ b/tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.client.j2 @@ -0,0 +1,4 @@ +{ + "client_id":"keystone", + "client_secret":"example_secret" +} diff --git a/tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.conf.j2 b/tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.conf.j2 new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.conf.j2 @@ -0,0 +1 @@ +{} diff --git a/tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.provider.j2 b/tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.provider.j2 new file mode 100644 index 0000000000..c45eb26f97 --- /dev/null +++ b/tests/templates/keystone-federation/idp.example.org%2Frealms%2Fexample.provider.j2 @@ -0,0 +1,324 @@ +{ + "issuer": "https://idp.example.org/realms/example", + "authorization_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/auth", + "token_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/token", + "introspection_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/token/introspect", + "userinfo_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/userinfo", + "end_session_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/logout", + "frontchannel_logout_session_supported": true, + "frontchannel_logout_supported": true, + "jwks_uri": "https://idp.example.org/realms/example/protocol/openid-connect/certs", + "check_session_iframe": "https://idp.example.org/realms/example/protocol/openid-connect/login-status-iframe.html", + "grant_types_supported": [ + "authorization_code", + "implicit", + "refresh_token", + "password", + "client_credentials", + "urn:openid:params:grant-type:ciba", + "urn:ietf:params:oauth:grant-type:device_code" + ], + "acr_values_supported": [ + "0", + "1" + ], + "response_types_supported": [ + "code", + "none", + "id_token", + "token", + "id_token token", + "code id_token", + "code token", + "code id_token token" + ], + "subject_types_supported": [ + "public", + "pairwise" + ], + "prompt_values_supported": [ + "none", + "login", + "consent" + ], + "id_token_signing_alg_values_supported": [ + "PS384", + "RS384", + "EdDSA", + "ES384", + "HS256", + "HS512", + "ES256", + "RS256", + "HS384", + "ES512", + "PS256", + "PS512", + "RS512" + ], + "id_token_encryption_alg_values_supported": [ + "ECDH-ES+A256KW", + "ECDH-ES+A192KW", + "ECDH-ES+A128KW", + "RSA-OAEP", + "RSA-OAEP-256", + "RSA1_5", + "ECDH-ES" + ], + "id_token_encryption_enc_values_supported": [ + "A256GCM", + "A192GCM", + "A128GCM", + "A128CBC-HS256", + "A192CBC-HS384", + "A256CBC-HS512" + ], + "userinfo_signing_alg_values_supported": [ + "PS384", + "RS384", + "EdDSA", + "ES384", + "HS256", + "HS512", + "ES256", + "RS256", + "HS384", + "ES512", + "PS256", + "PS512", + "RS512", + "none" + ], + "userinfo_encryption_alg_values_supported": [ + "ECDH-ES+A256KW", + "ECDH-ES+A192KW", + "ECDH-ES+A128KW", + "RSA-OAEP", + "RSA-OAEP-256", + "RSA1_5", + "ECDH-ES" + ], + "userinfo_encryption_enc_values_supported": [ + "A256GCM", + "A192GCM", + "A128GCM", + "A128CBC-HS256", + "A192CBC-HS384", + "A256CBC-HS512" + ], + "request_object_signing_alg_values_supported": [ + "PS384", + "RS384", + "EdDSA", + "ES384", + "HS256", + "HS512", + "ES256", + "RS256", + "HS384", + "ES512", + "PS256", + "PS512", + "RS512", + "none" + ], + "request_object_encryption_alg_values_supported": [ + "ECDH-ES+A256KW", + "ECDH-ES+A192KW", + "ECDH-ES+A128KW", + "RSA-OAEP", + "RSA-OAEP-256", + "RSA1_5", + "ECDH-ES" + ], + "request_object_encryption_enc_values_supported": [ + "A256GCM", + "A192GCM", + "A128GCM", + "A128CBC-HS256", + "A192CBC-HS384", + "A256CBC-HS512" + ], + "response_modes_supported": [ + "query", + "fragment", + "form_post", + "query.jwt", + "fragment.jwt", + "form_post.jwt", + "jwt" + ], + "registration_endpoint": "https://idp.example.org/realms/example/clients-registrations/openid-connect", + "token_endpoint_auth_methods_supported": [ + "private_key_jwt", + "client_secret_basic", + "client_secret_post", + "tls_client_auth", + "client_secret_jwt" + ], + "token_endpoint_auth_signing_alg_values_supported": [ + "PS384", + "RS384", + "EdDSA", + "ES384", + "HS256", + "HS512", + "ES256", + "RS256", + "HS384", + "ES512", + "PS256", + "PS512", + "RS512" + ], + "introspection_endpoint_auth_methods_supported": [ + "private_key_jwt", + "client_secret_basic", + "client_secret_post", + "tls_client_auth", + "client_secret_jwt" + ], + "introspection_endpoint_auth_signing_alg_values_supported": [ + "PS384", + "RS384", + "EdDSA", + "ES384", + "HS256", + "HS512", + "ES256", + "RS256", + "HS384", + "ES512", + "PS256", + "PS512", + "RS512" + ], + "authorization_signing_alg_values_supported": [ + "PS384", + "RS384", + "EdDSA", + "ES384", + "HS256", + "HS512", + "ES256", + "RS256", + "HS384", + "ES512", + "PS256", + "PS512", + "RS512" + ], + "authorization_encryption_alg_values_supported": [ + "ECDH-ES+A256KW", + "ECDH-ES+A192KW", + "ECDH-ES+A128KW", + "RSA-OAEP", + "RSA-OAEP-256", + "RSA1_5", + "ECDH-ES" + ], + "authorization_encryption_enc_values_supported": [ + "A256GCM", + "A192GCM", + "A128GCM", + "A128CBC-HS256", + "A192CBC-HS384", + "A256CBC-HS512" + ], + "claims_supported": [ + "aud", + "sub", + "iss", + "auth_time", + "name", + "given_name", + "family_name", + "preferred_username", + "email", + "acr" + ], + "claim_types_supported": [ + "normal" + ], + "claims_parameter_supported": true, + "scopes_supported": [ + "openid", + "roles", + "acr", + "profile", + "address", + "basic", + "offline_access", + "groups", + "email", + "phone", + "service_account", + "web-origins", + "microprofile-jwt" + ], + "request_parameter_supported": true, + "request_uri_parameter_supported": true, + "require_request_uri_registration": true, + "code_challenge_methods_supported": [ + "plain", + "S256" + ], + "tls_client_certificate_bound_access_tokens": true, + "revocation_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/revoke", + "revocation_endpoint_auth_methods_supported": [ + "private_key_jwt", + "client_secret_basic", + "client_secret_post", + "tls_client_auth", + "client_secret_jwt" + ], + "revocation_endpoint_auth_signing_alg_values_supported": [ + "PS384", + "RS384", + "EdDSA", + "ES384", + "HS256", + "HS512", + "ES256", + "RS256", + "HS384", + "ES512", + "PS256", + "PS512", + "RS512" + ], + "backchannel_logout_supported": true, + "backchannel_logout_session_supported": true, + "device_authorization_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/auth/device", + "backchannel_token_delivery_modes_supported": [ + "poll", + "ping" + ], + "backchannel_authentication_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/ext/ciba/auth", + "backchannel_authentication_request_signing_alg_values_supported": [ + "PS384", + "RS384", + "EdDSA", + "ES384", + "ES256", + "RS256", + "ES512", + "PS256", + "PS512", + "RS512" + ], + "require_pushed_authorization_requests": false, + "pushed_authorization_request_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/ext/par/request", + "mtls_endpoint_aliases": { + "token_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/token", + "revocation_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/revoke", + "introspection_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/token/introspect", + "device_authorization_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/auth/device", + "registration_endpoint": "https://idp.example.org/realms/example/clients-registrations/openid-connect", + "userinfo_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/userinfo", + "pushed_authorization_request_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/ext/par/request", + "backchannel_authentication_endpoint": "https://idp.example.org/realms/example/protocol/openid-connect/ext/ciba/auth" + }, + "authorization_response_iss_parameter_supported": true +} + diff --git a/tests/templates/mariadb-overrides.j2 b/tests/templates/mariadb-overrides.j2 index e87de71085..05dcd1c120 100644 --- a/tests/templates/mariadb-overrides.j2 +++ b/tests/templates/mariadb-overrides.j2 @@ -3,3 +3,4 @@ max_connections = 300 innodb_buffer_pool_size = 1024M max_heap_table_size = 32M tmp_table_size = 32M +wsrep_slave_threads = 8 diff --git a/tests/testinfra/test_horizon.py b/tests/testinfra/test_horizon.py index 9b27e47000..0c1527a9df 100644 --- a/tests/testinfra/test_horizon.py +++ b/tests/testinfra/test_horizon.py @@ -12,13 +12,17 @@ # License for the specific language governing permissions and limitations # under the License. +import os +import pytest import time import yaml from pathlib import Path from selenium.common.exceptions import TimeoutException +from selenium.common.exceptions import WebDriverException from selenium import webdriver from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import Select from selenium.webdriver.support.ui import WebDriverWait home = Path.home() @@ -122,3 +126,50 @@ def test_horizon_login(host): raise e finally: driver.quit() + + +@pytest.mark.skipif( + os.getenv("SCENARIO") != "federation", + reason=( + "Current scenario is not federation. " + "Not running test." + ) +) +def test_horizon_login_federation(host): + + firefox_options = webdriver.FirefoxOptions() + selenium_url = host.environment().get( + 'SELENIUM_REMOTE_URL', 'http://localhost:4500/wd/hub') + + driver = webdriver.Remote( + command_executor=selenium_url, + options=firefox_options) + + horizon_proto = host.environment().get('HORIZON_PROTO') + horizon_url = horizon_proto + "://192.0.2.10" + login_url = '/'.join(( + horizon_url, + 'auth', + 'login')) + + try: + driver.get(login_url) + auth_type_field = driver.find_element(By.ID, 'id_auth_type') + select = Select(auth_type_field) + select.select_by_value('example_provider_openid') + button = driver.find_element(By.CSS_SELECTOR, '.btn-primary') + + try: + button.click() + except WebDriverException as e: + if "Reached error page" in str(e) or "dnsNotFound" in str(e): + pass # This is expected behavior, so we ignore the exception + else: + raise # Re-raise if it failed for an unexpected reason + + assert "idp.example.org" in driver.current_url # nosec B101 + + except TimeoutException as e: + raise e + finally: + driver.quit() diff --git a/tools/init-vpn b/tools/init-vpn index bdcc85c4b0..86dda9130c 100755 --- a/tools/init-vpn +++ b/tools/init-vpn @@ -1,66 +1,129 @@ #!/usr/bin/env bash - # Script originally copied from https://wiki.openstack.org/wiki/Neutron/VPNaaS/HowToInstall -# Test for credentials set -if [[ "${OS_USERNAME}" == "" ]]; then - echo "No Keystone credentials specified. Try running source openrc" - exit -fi - -EXT_NW_ID=`neutron net-list | awk '/public/{print $2}'` -WEST_SUBNET='192.168.1.0/24' -EAST_SUBNET='192.168.2.0/24' +WEST_SUBNET='192.168.10.0/24' +EAST_SUBNET='192.168.20.0/24' function setup_site(){ local site_name=$1 local cidr=$2 - neutron net-create net_$site_name - neutron subnet-create --name subnet_$site_name net_$site_name $2 - neutron router-create router_$site_name - neutron router-interface-add router_$site_name subnet_$site_name - neutron router-gateway-set router_$site_name $EXT_NW_ID - neutron vpn-service-create --name vpn_$site_name router_$site_name subnet_$site_name + echo ">>> Creating network and subnet for site '$site_name'..." + openstack network create net_$site_name + openstack subnet create --network net_$site_name --subnet-range $cidr subnet_$site_name + + echo ">>> Creating router '$site_name' with external gateway 'public1'..." + openstack router create --external-gateway public1 router_$site_name + openstack router add subnet router_$site_name subnet_$site_name + + echo ">>> Creating VPN service for site '$site_name'..." + openstack vpn service create vpn_$site_name --router router_$site_name + + echo ">>> Creating local endpoint group for site '$site_name'..." + openstack vpn endpoint group create ${site_name}-local-epg --type subnet --value subnet_$site_name } function get_external_ip(){ - local router_id=`neutron router-show $1 | awk '/ id /{print $4}'` - echo `neutron router-list | grep '$router_id' | awk -F '"' '{print $16}'` + openstack vpn service show -f value -c ext_v4_ip $1 } function clean_site(){ local site_name=$1 - neutron ipsec-site-connection-delete conn_$site_name - neutron vpn-service-list | awk '/vpn_'$site_name'/{print "neutron vpn-service-delete " $2}' | -bash - neutron router-gateway-clear router_$site_name - neutron router-interface-delete router_$site_name subnet_$site_name - neutron router-list | awk '/router_'$site_name'/{print "neutron router-delete " $2}' | bash - neutron subnet-list | awk '/subnet_'$site_name'/{print "neutron subnet-delete " $2}' | bash - neutron net-list | awk '/net_'$site_name'/{print "neutron net-delete " $2}' | bash + echo ">>> Cleaning configuration for site '$site_name'..." + openstack vpn ipsec site connection delete conn_$site_name || true + openstack vpn service delete vpn_$site_name || true + openstack vpn endpoint group delete ${site_name}-local-epg || true + openstack router remove subnet router_$site_name subnet_$site_name || true + openstack router unset --external-gateway router_$site_name || true + openstack router delete router_$site_name || true + openstack subnet delete subnet_$site_name || true + openstack network delete net_$site_name || true } function setup(){ - neutron vpn-ikepolicy-create ikepolicy1 - neutron vpn-ipsecpolicy-create ipsecpolicy1 + echo ">>> Creating IKE policy..." + openstack vpn ike policy create ikepolicy --ike-version v2 --auth-algorithm sha256 --encryption-algorithm aes-256 --pfs group14 + + echo ">>> Creating IPSec policy..." + openstack vpn ipsec policy create ipsecpolicy --auth-algorithm sha256 --encryption-algorithm aes-256 --pfs group14 + + echo ">>> Configuring WEST site..." setup_site west $WEST_SUBNET - WEST_IP=$(get_external_ip router_west) + echo ">>> Creating peer endpoint group for WEST..." + openstack vpn endpoint group create west-peer-epg --type cidr --value $EAST_SUBNET + WEST_IP=$(get_external_ip vpn_west) + echo ">>> VPN WEST external IP: $WEST_IP" + + echo ">>> Configuring EAST site..." setup_site east $EAST_SUBNET - EAST_IP=$(get_external_ip router_east) - neutron ipsec-site-connection-create --name conn_east --vpnservice-id vpn_east --ikepolicy-id \ -ikepolicy1 --ipsecpolicy-id ipsecpolicy1 --peer-address $WEST_IP --peer-id $WEST_IP --peer-cidr \ -$WEST_SUBNET --psk secret - neutron ipsec-site-connection-create --name conn_west --vpnservice-id vpn_west --ikepolicy-id \ -ikepolicy1 --ipsecpolicy-id ipsecpolicy1 --peer-address $EAST_IP --peer-id $EAST_IP --peer-cidr \ -$EAST_SUBNET --psk secret + echo ">>> Creating peer endpoint group for EAST..." + openstack vpn endpoint group create east-peer-epg --type cidr --value $WEST_SUBNET + EAST_IP=$(get_external_ip vpn_east) + echo ">>> VPN EAST external IP: $EAST_IP" + + echo ">>> Creating VPN connection 'conn_east'..." + openstack vpn ipsec site connection create conn_east --vpnservice vpn_east --ikepolicy ikepolicy \ + --ipsecpolicy ipsecpolicy --local-endpoint-group east-local-epg --peer-address $WEST_IP \ + --peer-id $WEST_IP --peer-endpoint-group east-peer-epg --psk secret + + echo ">>> Creating VPN connection 'conn_west'..." + openstack vpn ipsec site connection create conn_west --vpnservice vpn_west --ikepolicy ikepolicy \ + --ipsecpolicy ipsecpolicy --local-endpoint-group west-local-epg --peer-address $EAST_IP \ + --peer-id $EAST_IP --peer-endpoint-group west-peer-epg --psk secret + + echo ">>> Waiting for VPN connections to become ACTIVE..." + wait_for_vpn_active conn_east + wait_for_vpn_active conn_west + + echo ">>> All VPN connections are ACTIVE!" +} + +function wait_for_vpn_active(){ + local conn_name=$1 + local timeout=300 + local interval=10 + local elapsed=0 + + echo ">>> Checking VPN status for $conn_name every $interval seconds (timeout: $timeout seconds)..." + + while true; do + STATUS=$(openstack vpn ipsec site connection show $conn_name -f value -c status) + if [ "$STATUS" == "ACTIVE" ]; then + echo ">>> VPN connection $conn_name is ACTIVE" + break + fi + + if [ $elapsed -ge $timeout ]; then + echo ">>> Timeout waiting for VPN connection $conn_name to become ACTIVE" + exit 1 + fi + + sleep $interval + elapsed=$((elapsed + interval)) + done } function cleanup(){ + echo ">>> Cleaning all VPN configurations..." clean_site west clean_site east - neutron vpn-ikepolicy-delete ikepolicy1 - neutron vpn-ipsecpolicy-delete ipsecpolicy1 + openstack vpn endpoint group delete west-peer-epg || true + openstack vpn endpoint group delete east-peer-epg || true + openstack vpn ike policy delete ikepolicy || true + openstack vpn ipsec policy delete ipsecpolicy || true +} + +function check() { + if [ -z ${OS_USERNAME} ]; then + echo ">>> Keystone credentials not found. Try: source /etc/kolla/admin-openrc.sh" + exit 1 + fi } +check cleanup setup + +echo ">>> Displaying current VPN connections:" +openstack vpn ipsec site connection list + +echo ">>> VPN setup completed successfully." diff --git a/zuul.d/scenarios/aio.yaml b/zuul.d/scenarios/aio.yaml index 4a89a11a7f..95fa0a9e08 100644 --- a/zuul.d/scenarios/aio.yaml +++ b/zuul.d/scenarios/aio.yaml @@ -3,10 +3,12 @@ parent: kolla-ansible-base name: kolla-ansible-aio-base files: !inherit + - ^ansible/post-deploy.yml - ^ansible/group_vars/all/(common|cron|fluentd|glance|haproxy|heat|horizon|keepalived|keystone|loadbalancer|neutron|nova|nova-cell|openvswitch|placement|proxysql|rabbitmq).yml - ^ansible/group_vars/baremetal/ansible-python-interpreter.yml - ^ansible/(action_plugins|filter_plugins|library|module_utils)/ - ^ansible/roles/(common|cron|fluentd|glance|haproxy-config|heat|horizon|keystone|loadbalancer|loadbalancer-config|neutron|nova|nova-cell|openvswitch|placement|proxysql|rabbitmq|service.*)/ + - ^ansible/templates/ - ^kolla_ansible/ - ^roles/kolla-ansible-(deploy|tempest|test-dashboard|reconfigure)/ - ^tests/testinfra/test_horizon.py diff --git a/zuul.d/scenarios/keystone-federation.yaml b/zuul.d/scenarios/keystone-federation.yaml index 2f43e15ef1..f319880e91 100644 --- a/zuul.d/scenarios/keystone-federation.yaml +++ b/zuul.d/scenarios/keystone-federation.yaml @@ -6,6 +6,8 @@ files: !inherit - ^ansible/group_vars/all/keystone.yml - ^ansible/roles/keystone/ + - ^tests/templates/keystone-federation/ + - ^tests/testinfra/test_horizon.py vars: scenario: federation scenario_images_extra: diff --git a/zuul.d/scenarios/mariadb.yaml b/zuul.d/scenarios/mariadb.yaml index d82bddaf4f..ab433ecdb5 100644 --- a/zuul.d/scenarios/mariadb.yaml +++ b/zuul.d/scenarios/mariadb.yaml @@ -6,6 +6,7 @@ files: !inherit - ^ansible/group_vars/all/mariadb.yml - ^ansible/roles/(loadbalancer|loadbalancer-config|mariadb|proxysql-config)/ + - ^tests/templates/mariadb-overrides.j2 - ^tests/test-mariadb.sh vars: scenario: mariadb diff --git a/zuul.d/scenarios/octavia.yaml b/zuul.d/scenarios/octavia.yaml index 5625e63cf1..8a0e716cdb 100644 --- a/zuul.d/scenarios/octavia.yaml +++ b/zuul.d/scenarios/octavia.yaml @@ -4,6 +4,7 @@ parent: kolla-ansible-base voting: false files: !inherit + - ^ansible/post-deploy.yml - ^ansible/group_vars/all/(octavia|valkey).yml - ^ansible/roles/(octavia|octavia-certificates|valkey)/ - ^tests/test-octavia.sh