Change ordering of /etc/ operations to improve upgrades

This change matches an earlier modification to os_neutron

Currently we symlink /etc/<service> to empty directory at pre-stage,
and filling it with config only during post_install. This means,
that policies and rootwrap filters are not working properly until
playbook execution finish. Additionally, we replace sudoers file
with new path in it, which makes current operations impossible for
the service, since rootwrap can not gain sudo privileges.

With this change we move symlinking and rootwrap steps to handlers,
which means that we will do replace configs while service is stopped.

During post_install we place all of the configs inside the venv,
which is versioned at the moment.

This way we minimise downtime of the service while performing upgrades

Closes-Bug: #2056180

Change-Id: I9c8212408c21e09895ee5805011aecb40b689a13
This commit is contained in:
Andrew Bonney 2024-11-13 09:14:38 +00:00
parent d106a515eb
commit 61be9e722d
8 changed files with 56 additions and 61 deletions

View File

@ -330,7 +330,7 @@ nova_console_proxy_types:
- "{{ nova_ironic_console_type }}" - "{{ nova_ironic_console_type }}"
# Nova console ssl info, presently only used by novnc console type # Nova console ssl info, presently only used by novnc console type
nova_console_ssl_dir: "/etc/nova/ssl" nova_console_ssl_dir: "{{ nova_system_home_folder }}/console_ssl"
nova_console_ssl_cert: "{{ nova_console_ssl_dir }}/nova-console.pem" nova_console_ssl_cert: "{{ nova_console_ssl_dir }}/nova-console.pem"
nova_console_ssl_key: "{{ nova_console_ssl_dir }}/nova-console.key" nova_console_ssl_key: "{{ nova_console_ssl_dir }}/nova-console.key"
@ -832,8 +832,8 @@ nova_pki_certificates:
condition: "{{ nova_pki_certificates_condition | bool }}" condition: "{{ nova_pki_certificates_condition | bool }}"
# nova destination files for SSL certificates # nova destination files for SSL certificates
nova_ssl_cert: /etc/nova/nova.pem nova_ssl_cert: "{{ nova_system_home_folder }}/nova.pem"
nova_ssl_key: /etc/nova/nova.key nova_ssl_key: "{{ nova_system_home_folder }}/nova.key"
# Installation details for SSL certificates # Installation details for SSL certificates
nova_pki_install_certificates: nova_pki_install_certificates:

View File

@ -55,6 +55,30 @@
- "'nova_compute' in group_names" - "'nova_compute' in group_names"
- nova_virt_type != 'ironic' - nova_virt_type != 'ironic'
- name: Symlink nova config directory
file:
# NOTE(cloudnull): The "src" path is relative. This ensures all files remain
# within the host/container confines when connecting to
# them using the connection plugin or the root filesystem.
src: "{{ nova_conf_version_dir | regex_replace('^/', '../') }}"
dest: "{{ nova_conf_dir }}"
state: link
force: true
when: nova_install_method == 'source'
listen:
- "venv changed"
- name: Drop sudoers file
template:
src: "sudoers.j2"
dest: "/etc/sudoers.d/{{ nova_system_user_name }}_sudoers"
mode: "0440"
owner: "root"
group: "root"
listen:
- "Restart nova services"
- "venv changed"
- name: Stop services - name: Stop services
service: service:
name: "{{ item.service_name }}" name: "{{ item.service_name }}"

View File

@ -21,7 +21,7 @@
# This needs to be done after Compute hosts are added. # This needs to be done after Compute hosts are added.
- name: Perform a cell_v2 discover - name: Perform a cell_v2 discover
command: >- command: >-
{{ _db_nova_bin }}/nova-manage cell_v2 discover_hosts{{ (debug | bool) | ternary(' --verbose', '') }}{{ {{ _db_nova_bin }}/nova-manage --config-file {{ nova_conf_version_dir }}/nova.conf cell_v2 discover_hosts{{ (debug | bool) | ternary(' --verbose', '') }}{{
(nova_ironic_used | bool) | ternary(' --by-service', '') }} (nova_ironic_used | bool) | ternary(' --by-service', '') }}
become: yes become: yes
become_user: "{{ _db_nova_system_user_name }}" become_user: "{{ _db_nova_system_user_name }}"
@ -34,7 +34,7 @@
# intervention is required to resolve the issue causing remaining updates to fail. # intervention is required to resolve the issue causing remaining updates to fail.
# It should be considered successfully completed only when the exit status is 0. # It should be considered successfully completed only when the exit status is 0.
- name: Perform online data migrations - name: Perform online data migrations
command: "{{ _db_nova_bin }}/nova-manage db online_data_migrations" command: "{{ _db_nova_bin }}/nova-manage --config-file {{ nova_conf_version_dir }}/nova.conf db online_data_migrations"
become: yes become: yes
become_user: "{{ _db_nova_system_user_name }}" become_user: "{{ _db_nova_system_user_name }}"
changed_when: false changed_when: false

View File

@ -14,7 +14,7 @@
# limitations under the License. # limitations under the License.
- name: Synchronize the nova API DB schema - name: Synchronize the nova API DB schema
command: "{{ nova_bin }}/nova-manage api_db sync" command: "{{ nova_bin }}/nova-manage --config-file {{ nova_conf_version_dir }}/nova.conf api_db sync"
become: yes become: yes
become_user: "{{ nova_system_user_name }}" become_user: "{{ nova_system_user_name }}"
changed_when: false changed_when: false
@ -22,7 +22,7 @@
# We need to check for existance of the cell, since nova-manage cell_v2 create_cell # We need to check for existance of the cell, since nova-manage cell_v2 create_cell
# might be not idempotent due to the bug https://bugs.launchpad.net/nova/+bug/1923899 # might be not idempotent due to the bug https://bugs.launchpad.net/nova/+bug/1923899
- name: Get UUID of Nova Cells - name: Get UUID of Nova Cells
command: "{{ nova_bin }}/nova-manage cell_v2 list_cells" command: "{{ nova_bin }}/nova-manage --config-file {{ nova_conf_version_dir }}/nova.conf cell_v2 list_cells"
become: yes become: yes
become_user: "{{ nova_system_user_name }}" become_user: "{{ nova_system_user_name }}"
changed_when: false changed_when: false
@ -39,7 +39,7 @@
# it conditionally. # it conditionally.
- name: Create the cell0 mapping entry in the nova API DB - name: Create the cell0 mapping entry in the nova API DB
command: >- command: >-
{{ nova_bin }}/nova-manage cell_v2 map_cell0 {{ nova_bin }}/nova-manage --config-file {{ nova_conf_version_dir }}/nova.conf cell_v2 map_cell0
--database_connection mysql+pymysql://{{ nova_api_galera_user }}:{{ nova_api_container_mysql_password }}@{{ nova_api_galera_address }}/{{ --database_connection mysql+pymysql://{{ nova_api_galera_user }}:{{ nova_api_container_mysql_password }}@{{ nova_api_galera_address }}/{{
nova_cell0_database }}?charset=utf8{% if nova_galera_use_ssl | bool %}&ssl_verify_cert=true{% nova_cell0_database }}?charset=utf8{% if nova_galera_use_ssl | bool %}&ssl_verify_cert=true{%
if nova_galera_ssl_ca_cert | length > 0 %}&ssl_ca={{ nova_galera_ssl_ca_cert }}{% endif %}{% endif %} if nova_galera_ssl_ca_cert | length > 0 %}&ssl_ca={{ nova_galera_ssl_ca_cert }}{% endif %}{% endif %}
@ -51,7 +51,7 @@
- name: Update the cell0 mapping entry in the nova API DB - name: Update the cell0 mapping entry in the nova API DB
command: >- command: >-
{{ nova_bin }}/nova-manage cell_v2 update_cell --cell_uuid 00000000-0000-0000-0000-000000000000 {{ nova_bin }}/nova-manage --config-file {{ nova_conf_version_dir }}/nova.conf cell_v2 update_cell --cell_uuid 00000000-0000-0000-0000-000000000000
--database_connection mysql+pymysql://{{ nova_api_galera_user }}:{{ nova_api_container_mysql_password }}@{{ nova_api_galera_address }}/{{ --database_connection mysql+pymysql://{{ nova_api_galera_user }}:{{ nova_api_container_mysql_password }}@{{ nova_api_galera_address }}/{{
nova_cell0_database }}?charset=utf8{% if nova_galera_use_ssl | bool %}&ssl_verify_cert=true{% nova_cell0_database }}?charset=utf8{% if nova_galera_use_ssl | bool %}&ssl_verify_cert=true{%
if nova_galera_ssl_ca_cert | length > 0 %}&ssl_ca={{ nova_galera_ssl_ca_cert }}{% endif %}{% endif %} if nova_galera_ssl_ca_cert | length > 0 %}&ssl_ca={{ nova_galera_ssl_ca_cert }}{% endif %}{% endif %}
@ -66,14 +66,14 @@
('ssl_verify_cert' in _cell0_record[0] and not nova_galera_use_ssl) ('ssl_verify_cert' in _cell0_record[0] and not nova_galera_use_ssl)
- name: Synchronize the nova DB schema - name: Synchronize the nova DB schema
command: "{{ nova_bin }}/nova-manage db sync" command: "{{ nova_bin }}/nova-manage --config-file {{ nova_conf_version_dir }}/nova.conf db sync"
become: yes become: yes
become_user: "{{ nova_system_user_name }}" become_user: "{{ nova_system_user_name }}"
changed_when: false changed_when: false
- name: Create the cell1 mapping entry in the nova API DB - name: Create the cell1 mapping entry in the nova API DB
command: >- command: >-
{{ nova_bin }}/nova-manage cell_v2 create_cell {{ nova_bin }}/nova-manage --config-file {{ nova_conf_version_dir }}/nova.conf cell_v2 create_cell
--name {{ nova_cell1_name }} --name {{ nova_cell1_name }}
--database_connection {scheme}://{username}:{password}@{hostname}:{port}/{path}?{query} --database_connection {scheme}://{username}:{password}@{hostname}:{port}/{path}?{query}
--transport-url {scheme}://{username}:{password}@{hostname}:{port}/{{ ( --transport-url {scheme}://{username}:{password}@{hostname}:{port}/{{ (
@ -96,7 +96,7 @@
- name: "Change the template for cell {{ nova_cell1_name }}" - name: "Change the template for cell {{ nova_cell1_name }}"
command: >- command: >-
{{ nova_bin }}/nova-manage cell_v2 update_cell {{ nova_bin }}/nova-manage --config-file {{ nova_conf_version_dir }}/nova.conf cell_v2 update_cell
--cell_uuid {{ _cell1_record[0].split()[3] }} --cell_uuid {{ _cell1_record[0].split()[3] }}
--database_connection {scheme}://{username}:{password}@{hostname}:{port}/{path}?{query} --database_connection {scheme}://{username}:{password}@{hostname}:{port}/{path}?{query}
--transport-url {scheme}://{username}:{password}@{hostname}:{port}/{{ ( --transport-url {scheme}://{username}:{password}@{hostname}:{port}/{{ (
@ -115,7 +115,7 @@
# mapping setup and before actual service restart. # mapping setup and before actual service restart.
# https://docs.openstack.org/nova/latest/cli/nova-status.html # https://docs.openstack.org/nova/latest/cli/nova-status.html
- name: Run nova-status upgrade check to validate a healthy configuration - name: Run nova-status upgrade check to validate a healthy configuration
command: "{{ nova_bin }}/nova-status upgrade check" command: "{{ nova_bin }}/nova-status --config-file {{ nova_conf_version_dir }}/nova.conf upgrade check"
become: yes become: yes
become_user: "{{ nova_system_user_name }}" become_user: "{{ nova_system_user_name }}"
register: nova_status_upgrade_check register: nova_status_upgrade_check

View File

@ -36,14 +36,14 @@
group: "{{ item.group | default(nova_system_group_name) }}" group: "{{ item.group | default(nova_system_group_name) }}"
mode: "{{ item.mode | default(omit) }}" mode: "{{ item.mode | default(omit) }}"
with_items: with_items:
- path: "/etc/nova/rootwrap.d" - path: "{{ nova_conf_version_dir }}/rootwrap.d"
owner: "root" owner: "root"
group: "root" group: "root"
- name: Copy nova rootwrap filter config - name: Copy nova rootwrap filter config
copy: copy:
src: "{{ item }}" src: "{{ item }}"
dest: "/etc/nova/rootwrap.d/" dest: "{{ nova_conf_version_dir }}/rootwrap.d/"
owner: "root" owner: "root"
group: "root" group: "root"
mode: "0644" mode: "0644"
@ -68,11 +68,11 @@
yml_multilines: "{{ item.yml_multilines | default(omit) }}" yml_multilines: "{{ item.yml_multilines | default(omit) }}"
with_items: with_items:
- src: "nova.conf.j2" - src: "nova.conf.j2"
dest: "/etc/nova/nova.conf" dest: "{{ nova_conf_version_dir }}/nova.conf"
config_overrides: "{{ nova_nova_conf_overrides }}" config_overrides: "{{ nova_nova_conf_overrides }}"
config_type: "ini" config_type: "ini"
- src: "vendor_data.json.j2" - src: "vendor_data.json.j2"
dest: "/etc/nova/vendor_data.json" dest: "{{ nova_conf_version_dir }}/vendor_data.json"
config_overrides: "{{ nova_vendor_data_overrides }}" config_overrides: "{{ nova_vendor_data_overrides }}"
config_type: "json" config_type: "json"
yml_multilines: True yml_multilines: True
@ -86,7 +86,7 @@
- name: Implement policy.yaml if there are overrides configured - name: Implement policy.yaml if there are overrides configured
openstack.config_template.config_template: openstack.config_template.config_template:
content: "{{ nova_policy_overrides }}" content: "{{ nova_policy_overrides }}"
dest: "/etc/nova/policy.yaml" dest: "{{ nova_conf_version_dir }}/policy.yaml"
owner: "root" owner: "root"
group: "{{ nova_system_group_name }}" group: "{{ nova_system_group_name }}"
mode: "0640" mode: "0640"
@ -100,7 +100,7 @@
- name: Implement compute host provider.yaml if there are overrides configured - name: Implement compute host provider.yaml if there are overrides configured
openstack.config_template.config_template: openstack.config_template.config_template:
content: "{{ item.content }}" content: "{{ item.content }}"
dest: "/etc/nova/provider_config/{{ item.name }}.yaml" dest: "{{ nova_conf_version_dir }}/provider_config/{{ item.name }}.yaml"
owner: "root" owner: "root"
group: "{{ nova_system_group_name }}" group: "{{ nova_system_group_name }}"
mode: "0640" mode: "0640"
@ -115,7 +115,7 @@
- name: Remove legacy policy.yaml file - name: Remove legacy policy.yaml file
file: file:
path: "/etc/nova/policy.yaml" path: "{{ nova_conf_dir }}/policy.yaml"
state: absent state: absent
when: when:
- nova_policy_overrides | length == 0 - nova_policy_overrides | length == 0
@ -174,14 +174,3 @@
tags: tags:
- nova-config - nova-config
- nova-post-install - nova-post-install
- name: Drop sudoers file
template:
src: "sudoers.j2"
dest: "/etc/sudoers.d/{{ nova_system_user_name }}_sudoers"
mode: "0440"
owner: "root"
group: "root"
tags:
- sudoers
- nova-sudoers

View File

@ -53,12 +53,12 @@
block: block:
- name: Stat config directory - name: Stat config directory
stat: stat:
path: "/etc/nova" path: "{{ nova_conf_dir }}"
register: nova_conf_dir_stat register: nova_conf_dir_stat
- name: Remove the config directory - name: Remove the config directory
file: file:
path: "/etc/nova" path: "{{ nova_conf_dir }}"
state: absent state: absent
when: when:
- nova_conf_dir_stat.stat.isdir is defined and - nova_conf_dir_stat.stat.isdir is defined and
@ -69,12 +69,10 @@
- name: Create nova dir - name: Create nova dir
file: file:
path: "{{ item.path }}" path: "{{ item.path }}"
src: "{{ item.src | default(omit) }}"
state: "{{ item.state | default('directory') }}" state: "{{ item.state | default('directory') }}"
owner: "{{ item.owner | default(nova_system_user_name) }}" owner: "{{ item.owner | default(nova_system_user_name) }}"
group: "{{ item.group | default(nova_system_group_name) }}" group: "{{ item.group | default(nova_system_group_name) }}"
mode: "{{ item.mode | default('0755') }}" mode: "{{ item.mode | default('0755') }}"
force: "{{ item.force | default(omit) }}"
when: when:
- (item.condition | default(true)) | bool - (item.condition | default(true)) | bool
- item.path not in nova_mount_points - item.path not in nova_mount_points
@ -82,17 +80,9 @@
- path: "/openstack" - path: "/openstack"
owner: "root" owner: "root"
group: "root" group: "root"
- path: "{{ (nova_install_method == 'distro') | ternary('/etc/nova', (nova_bin | dirname) + '/etc/nova') }}" - path: "{{ nova_conf_version_dir }}"
mode: "0755" mode: "0755"
# NOTE(cloudnull): The "src" path is relative. This ensures all files remain - path: "{{ nova_conf_version_dir }}/provider_config"
# within the host/container confines when connecting to
# them using the connection plugin or the root filesystem.
- path: "/etc/nova"
src: "{{ nova_bin | dirname | regex_replace('^/', '../') }}/etc/nova"
state: link
force: true
condition: "{{ nova_install_method == 'source' }}"
- path: "/etc/nova/provider_config"
owner: "root" owner: "root"
mode: "0640" mode: "0640"
- path: "/etc/sudoers.d" - path: "/etc/sudoers.d"
@ -107,17 +97,6 @@
tags: tags:
- nova-dirs - nova-dirs
- name: Drop sudoers file
template:
src: "sudoers.j2"
dest: "/etc/sudoers.d/{{ nova_system_user_name }}_sudoers"
mode: "0440"
owner: "root"
group: "root"
tags:
- sudoers
- nova-sudoers
- name: Set default nova console for ppc64le - name: Set default nova console for ppc64le
set_fact: set_fact:
nova_console_type: "novnc" nova_console_type: "novnc"

View File

@ -310,11 +310,11 @@ insecure = {{ keystone_service_adminuri_insecure | bool }}
{% endif %} {% endif %}
[wsgi] [wsgi]
api_paste_config = /etc/nova/api-paste.ini api_paste_config = {{ nova_conf_dir }}/api-paste.ini
[api] [api]
vendordata_jsonfile_path = /etc/nova/vendor_data.json vendordata_jsonfile_path = {{ nova_conf_dir }}/vendor_data.json
dhcp_domain = {{ nova_dhcp_domain }} dhcp_domain = {{ nova_dhcp_domain }}
[scheduler] [scheduler]

View File

@ -13,6 +13,9 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
nova_conf_dir: /etc/nova
nova_conf_version_dir: "{{ (nova_install_method == 'distro') | ternary(nova_conf_dir, (nova_bin | dirname) + nova_conf_dir) }}"
_nova_is_first_play_host: >- _nova_is_first_play_host: >-
{{ {{
(nova_services['nova-conductor']['group'] in group_names and (nova_services['nova-conductor']['group'] in group_names and
@ -119,16 +122,16 @@ nova_mount_points: |-
_nova_rootwrap_conf_overrides: _nova_rootwrap_conf_overrides:
DEFAULT: DEFAULT:
filters_path: "/etc/nova/rootwrap.d,/usr/share/nova/rootwrap" filters_path: "{{ nova_conf_dir }}/rootwrap.d,/usr/share/nova/rootwrap"
exec_dirs: "{{ nova_bin }},/sbin,/usr/sbin,/bin,/usr/bin,/usr/local/bin,/usr/local/sbin" exec_dirs: "{{ nova_bin }},/sbin,/usr/sbin,/bin,/usr/bin,/usr/local/bin,/usr/local/sbin"
nova_core_files: nova_core_files:
- tmp_f: "/tmp/api-paste.ini" - tmp_f: "/tmp/api-paste.ini"
target_f: "/etc/nova/api-paste.ini" target_f: "{{ nova_conf_version_dir }}/api-paste.ini"
config_overrides: "{{ nova_api_paste_ini_overrides }}" config_overrides: "{{ nova_api_paste_ini_overrides }}"
config_type: "ini" config_type: "ini"
- tmp_f: "/tmp/rootwrap.conf" - tmp_f: "/tmp/rootwrap.conf"
target_f: "/etc/nova/rootwrap.conf" target_f: "{{ nova_conf_version_dir }}/rootwrap.conf"
config_overrides: "{{ _nova_rootwrap_conf_overrides | combine(nova_rootwrap_conf_overrides, recursive=True) }}" config_overrides: "{{ _nova_rootwrap_conf_overrides | combine(nova_rootwrap_conf_overrides, recursive=True) }}"
config_type: "ini" config_type: "ini"
owner: "root" owner: "root"