From 4b9100a612ba0e9449d792b2783b9ec50a8fb28e Mon Sep 17 00:00:00 2001 From: Jesse Pretorius Date: Mon, 24 Apr 2017 15:11:43 +0100 Subject: [PATCH] Perform an atomic policy file change The policy.json file is currently read continually by the services and is not only read on service start. We therefore cannot template directly to the file read by the service (if the service is already running) because the new policies may not be valid until the service restarts. This is particularly important during a major upgrade. We therefore only put the policy file in place after the service restart. This patch also tidies up the handlers and some of the install tasks to simplify them and reduce the tasks/code a little. Change-Id: Icba9df7be6012576eca0afb040a6953809cc9a5f --- defaults/main.yml | 9 +++ handlers/main.yml | 111 ++++++++++++++++------------- tasks/main.yml | 10 +-- tasks/nova_compute_wait.yml | 25 ------- tasks/nova_init_common.yml | 27 ------- tasks/nova_init_systemd.yml | 24 ++++--- tasks/nova_placement_uwsgi.yml | 19 ----- tasks/nova_post_install.yml | 2 +- templates/nova-systemd-init.j2 | 6 +- templates/nova-systemd-tmpfiles.j2 | 4 +- vars/main.yml | 20 +++--- 11 files changed, 101 insertions(+), 156 deletions(-) delete mode 100644 tasks/nova_compute_wait.yml delete mode 100644 tasks/nova_init_common.yml diff --git a/defaults/main.yml b/defaults/main.yml index ef1e61b9..2ed01874 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -431,36 +431,44 @@ nova_services: group: nova_api_metadata service_name: nova-api-metadata init_config_overrides: "{{ nova_api_metadata_init_overrides }}" + start_order: 4 nova-api-os-compute: group: nova_api_os_compute service_name: nova-api-os-compute init_config_overrides: "{{ nova_api_os_compute_init_overrides }}" + start_order: 3 nova-compute: group: nova_compute service_name: nova-compute init_config_overrides: "{{ nova_compute_init_overrides }}" + start_order: 5 nova-conductor: group: nova_conductor service_name: nova-conductor init_config_overrides: "{{ nova_conductor_init_overrides }}" + start_order: 1 nova-consoleauth: group: nova_console service_name: nova-consoleauth init_config_overrides: "{{ nova_consoleauth_init_overrides }}" + start_order: 2 nova-novncproxy: group: nova_console service_name: nova-novncproxy init_config_overrides: "{{ nova_novncproxy_init_overrides }}" condition: "{{ nova_console_type == 'novnc' }}" + start_order: 4 nova-scheduler: group: nova_scheduler service_name: nova-scheduler init_config_overrides: "{{ nova_scheduler_init_overrides }}" + start_order: 2 nova-spicehtml5proxy: group: nova_console service_name: nova-spicehtml5proxy init_config_overrides: "{{ nova_spicehtml5proxy_init_overrides }}" condition: "{{ nova_console_type == 'spice' }}" + start_order: 4 nova-placement-api: group: nova_api_placement service_name: nova-placement-api @@ -468,6 +476,7 @@ nova_services: condition: "{{ nova_placement_service_enabled | bool }}" log_string: "--logto " program_override: "{{ nova_bin }}/uwsgi --ini /etc/uwsgi/nova-placement-uwsgi.ini" + start_order: 3 nova_novnc_pip_packages: diff --git a/handlers/main.yml b/handlers/main.yml index e4acab28..6bd2af2c 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -12,67 +12,78 @@ # 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. + - name: Restart libvirt-bin - systemd: + service: name: "{{ libvirt_service_name }}" + enabled: yes state: "restarted" - daemon_reload: yes + daemon_reload: "{{ (ansible_service_mgr == 'systemd') | ternary('yes', omit) }}" -- name: Restart nova services - command: /bin/true - notify: - - Restart nova conductor - - Restart nova API - - Restart nova misc services - - Restart nova compute +- name: Stop services + service: + name: "{{ item.service_name }}" + enabled: yes + state: "stopped" + daemon_reload: "{{ (ansible_service_mgr == 'systemd') | ternary('yes', omit) }}" + with_items: "{{ filtered_nova_services }}" + register: _stop + until: _stop | success + retries: 5 + delay: 2 + listen: "Restart nova services" -- name: Restart nova conductor - systemd: - name: "{{ nova_services['nova-conductor']['service_name'] }}" - state: "restarted" - daemon_reload: yes - register: nova_conductor_restart - when: '"nova-conductor" in filtered_nova_services' +# Note (odyssey4me): +# The policy.json file is currently read continually by the services +# and is not only read on service start. We therefore cannot template +# directly to the file read by the service because the new policies +# may not be valid until the service restarts. This is particularly +# important during a major upgrade. We therefore only put the policy +# file in place after the service has been stopped. +# +- name: Copy new policy file into place + copy: + src: "/etc/nova/policy.json-{{ nova_venv_tag }}" + dest: "/etc/nova/policy.json" + owner: "root" + group: "{{ nova_system_group_name }}" + mode: "0640" + remote_src: yes + listen: "Restart nova services" -- name: Restart nova API - systemd: - name: "{{ nova_services['nova-api-os-compute']['service_name'] }}" - state: "restarted" - daemon_reload: yes - register: nova_api_restart - when: '"nova-api-os-compute" in filtered_nova_services' +- name: Start services + service: + name: "{{ item.service_name }}" + enabled: yes + state: "started" + daemon_reload: "{{ (ansible_service_mgr == 'systemd') | ternary('yes', omit) }}" + with_items: "{{ filtered_nova_services }}" + register: _start + until: _start | success + retries: 5 + delay: 2 + listen: "Restart nova services" -# Used for services where restart ordering does not matter -- name: Restart nova misc services - systemd: - name: "{{ nova_services[item]['service_name'] }}" - state: "restarted" - daemon_reload: yes - register: nova_misc_restart - with_items: - - nova-api-metadata - - nova-consoleauth - - nova-novncproxy - - nova-scheduler - - nova-spicehtml5proxy - - nova-placement-api - when: 'item in filtered_nova_services' - -- name: Restart nova compute - systemd: - name: "{{ nova_services['nova-compute']['service_name'] }}" - state: "restarted" - daemon_reload: yes - register: nova_compute_restart - when: '"nova-compute" in filtered_nova_services' +- name: Wait for the nova-compute service to initialize + command: "openstack --os-cloud default compute service list --service nova-compute --format value --column Host" + register: _compute_host_list + retries: 10 + delay: 5 + until: "ansible_nodename in _compute_host_list.stdout_lines" + when: + - "'nova_compute' in group_names" + - "nova_discover_hosts_in_cells_interval | int < 1" + listen: "Restart nova services" - name: Reload Nginx - systemd: + service: name: nginx enabled: yes state: reloaded - register: nova_nginx_restart - until: nova_nginx_restart | success + daemon_reload: "{{ (ansible_service_mgr == 'systemd') | ternary('yes', omit) }}" + register: _restart + until: _restart | success retries: 5 delay: 2 - when: inventory_hostname in groups['nova_api_placement'] + when: + - inventory_hostname in groups['nova_api_placement'] diff --git a/tasks/main.yml b/tasks/main.yml index 6fdda849..6b653792 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -59,7 +59,7 @@ tags: - nova-config -- include: nova_init_common.yml +- include: "nova_init_{{ ansible_service_mgr}}.yml" tags: - nova-config @@ -85,14 +85,6 @@ - name: Flush handlers meta: flush_handlers -- include: nova_compute_wait.yml - when: - - "'nova_compute' in group_names" - - nova_compute_restart | default(dict(changed=False)) | changed - - nova_discover_hosts_in_cells_interval | int < 1 - tags: - - nova-config - - include: nova_db_post_setup.yml when: - inventory_hostname == groups['nova_api_os_compute'][0] diff --git a/tasks/nova_compute_wait.yml b/tasks/nova_compute_wait.yml deleted file mode 100644 index 533bb851..00000000 --- a/tasks/nova_compute_wait.yml +++ /dev/null @@ -1,25 +0,0 @@ ---- -# Copyright 2017, Logan Vig -# -# 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. - -- name: Wait for the nova-compute service to initialize - command: openstack --os-cloud default compute service list -f json - changed_when: false - register: nova_service_list - retries: 10 - delay: 5 - until: "ansible_nodename in (nova_service_list.stdout - | from_json - | selectattr('Binary', 'equalto', 'nova-compute') - | map(attribute='Host') | list)" diff --git a/tasks/nova_init_common.yml b/tasks/nova_init_common.yml deleted file mode 100644 index 2ff6d4f1..00000000 --- a/tasks/nova_init_common.yml +++ /dev/null @@ -1,27 +0,0 @@ ---- -# Copyright 2016, Rackspace US, Inc. -# -# 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. - -- include: nova_init_systemd.yml - when: - - ansible_service_mgr == 'systemd' - -- name: Load service - service: - name: "{{ item.value.service_name }}" - enabled: "yes" - state: "started" - with_dict: "{{ filtered_nova_services }}" - notify: - - Restart nova services diff --git a/tasks/nova_init_systemd.yml b/tasks/nova_init_systemd.yml index 099ebf5e..fd5c72bc 100644 --- a/tasks/nova_init_systemd.yml +++ b/tasks/nova_init_systemd.yml @@ -15,49 +15,51 @@ - name: Create TEMP run dir file: - path: "/var/run/{{ item.value.service_name }}" + path: "/var/run/{{ item.service_name }}" state: directory owner: "{{ nova_system_user_name }}" group: "{{ nova_system_group_name }}" mode: "02755" - with_dict: "{{ filtered_nova_services }}" + with_items: "{{ filtered_nova_services }}" - name: Create TEMP lock dir file: - path: "/var/lock/{{ item.value.service_name }}" + path: "/var/lock/{{ item.service_name }}" state: directory owner: "{{ nova_system_user_name }}" group: "{{ nova_system_group_name }}" mode: "02755" - with_dict: "{{ filtered_nova_services }}" + with_items: "{{ filtered_nova_services }}" # TODO(mgariepy): # Remove this in Pike as it only needed to handle upgrades # from Newton->Newton and Newton->Ocata - name: Cleanup old tmpfiles.d entry file: - path: "/etc/tmpfiles.d/{{ item.value.service_name }}.conf" + path: "/etc/tmpfiles.d/{{ item.service_name }}.conf" state: absent - with_dict: "{{ filtered_nova_services }}" + with_items: "{{ filtered_nova_services }}" - name: Create tmpfiles.d entry template: src: "nova-systemd-tmpfiles.j2" - dest: "/etc/tmpfiles.d/openstack-{{ item.value.service_name }}.conf" + dest: "/etc/tmpfiles.d/openstack-{{ item.service_name }}.conf" mode: "0644" owner: "root" group: "root" - with_dict: "{{ filtered_nova_services }}" + with_items: "{{ filtered_nova_services }}" + notify: + - Restart nova services - name: Place the systemd init script config_template: src: "nova-systemd-init.j2" - dest: "/etc/systemd/system/{{ item.value.service_name }}.service" + dest: "/etc/systemd/system/{{ item.service_name }}.service" mode: "0644" owner: "root" group: "root" - config_overrides: "{{ item.value.init_config_overrides }}" + config_overrides: "{{ item.init_config_overrides }}" config_type: "ini" - with_dict: "{{ filtered_nova_services }}" + with_items: "{{ filtered_nova_services }}" notify: - Restart nova services diff --git a/tasks/nova_placement_uwsgi.yml b/tasks/nova_placement_uwsgi.yml index dc64e6ca..7e8ec78c 100644 --- a/tasks/nova_placement_uwsgi.yml +++ b/tasks/nova_placement_uwsgi.yml @@ -29,22 +29,3 @@ config_type: ini notify: - Restart nova services - -- include: nova_init_common.yml - vars: - program_name: "nova-placement-api" - service_name: "nova-placement-api" - system_user: "{{ nova_system_user_name }}" - system_group: "{{ nova_system_group_name }}" - service_home: "{{ nova_system_user_home }}" - notify: - - Restart nova services - -- name: Ensure uwsgi service started - systemd: - name: "nova-placement-api" - state: started - register: nova_placement_start - until: nova_placement_start | success - retries: 5 - delay: 2 diff --git a/tasks/nova_post_install.yml b/tasks/nova_post_install.yml index 67773441..3821b800 100644 --- a/tasks/nova_post_install.yml +++ b/tasks/nova_post_install.yml @@ -48,7 +48,7 @@ config_overrides: "{{ nova_api_paste_ini_overrides }}" config_type: "ini" - src: "policy.json.j2" - dest: "/etc/nova/policy.json" + dest: "/etc/nova/policy.json-{{ nova_venv_tag }}" config_overrides: "{{ nova_policy_overrides }}" config_type: "json" notify: Restart nova services diff --git a/templates/nova-systemd-init.j2 b/templates/nova-systemd-init.j2 index 41d007f8..2ace9662 100644 --- a/templates/nova-systemd-init.j2 +++ b/templates/nova-systemd-init.j2 @@ -10,10 +10,10 @@ Type=simple User={{ nova_system_user_name }} Group={{ nova_system_group_name }} -{% if item.value.program_override is defined %} -ExecStart={{ item.value.program_override }} {{ item.value.program_config_options|default('') }} {{ item.value.log_string|default('--log-file=') }}/var/log/nova/{{ item.value.service_name }}.log +{% if item.program_override is defined %} +ExecStart={{ item.program_override }} {{ item.program_config_options | default('') }} {{ item.log_string | default('--log-file=') }}/var/log/nova/{{ item.service_name }}.log {% else %} -ExecStart={{ nova_bin }}/{{ item.value.service_name }} {{ item.value.program_config_options|default('') }} {{ item.value.log_string|default('--log-file=') }}/var/log/nova/{{ item.value.service_name }}.log +ExecStart={{ nova_bin }}/{{ item.service_name }} {{ item.program_config_options | default('') }} {{ item.log_string | default('--log-file=') }}/var/log/nova/{{ item.service_name }}.log {% endif %} # Give a reasonable amount of time for the server to start up/shut down diff --git a/templates/nova-systemd-tmpfiles.j2 b/templates/nova-systemd-tmpfiles.j2 index 4ee37ffc..a7ccda3a 100644 --- a/templates/nova-systemd-tmpfiles.j2 +++ b/templates/nova-systemd-tmpfiles.j2 @@ -1,5 +1,5 @@ # {{ ansible_managed }} -D /var/lock/{{ item.value.service_name }} 2755 {{ nova_system_user_name }} {{ nova_system_group_name }} -D /var/run/{{ item.value.service_name }} 2755 {{ nova_system_user_name }} {{ nova_system_group_name }} +D /var/lock/{{ item.service_name }} 2755 {{ nova_system_user_name }} {{ nova_system_group_name }} +D /var/run/{{ item.service_name }} 2755 {{ nova_system_user_name }} {{ nova_system_group_name }} D {{ nova_lock_path }} 2755 {{ nova_system_user_name }} {{ nova_system_group_name }} diff --git a/vars/main.yml b/vars/main.yml index 0d7392f2..5d654644 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -49,12 +49,14 @@ nova_package_list: |- # Compile a list of the services on a host based on whether # the host is in the host group and the service is enabled. # -filtered_nova_services: > - {%- set services = nova_services.copy() %} - {%- for key,value in nova_services.items() %} - {%- if value.group not in group_names or - (value.condition is defined and not value.condition) %} - {%- set _ = services.pop(key) %} - {%- endif %} - {%- endfor %} - {{- services -}} +filtered_nova_services: |- + {% set services = [] %} + {% for key, value in nova_services.items() %} + {% if (value['group'] in group_names) and + (('condition' not in value) or + ('condition' in value and value['condition'])) %} + {% set _ = value.update({'service_key': key}) %} + {% set _ = services.append(value) %} + {% endif %} + {% endfor %} + {{ services | sort(attribute='start_order') }}