From 35f93355720f6503ebf86baa2c3bd576f6e6a076 Mon Sep 17 00:00:00 2001
From: Jeffrey Zhang <zhang.lei.fly@gmail.com>
Date: Tue, 6 Dec 2016 17:12:20 +0800
Subject: [PATCH] Optimize reconfigure action for nova

Change-Id: Ida7c955d9ddf7b7dc3289001958326c38c62d0c9
Partially-implements: blueprint better-reconfigure
---
 ansible/library/kolla_docker.py               |   4 +
 ansible/roles/nova/defaults/main.yml          | 124 ++++++
 ansible/roles/nova/handlers/main.yml          | 284 +++++++++++++
 .../roles/nova/tasks/bootstrap_service.yml    |  11 +-
 ansible/roles/nova/tasks/config-nova-fake.yml |  27 ++
 ansible/roles/nova/tasks/config.yml           | 143 ++++---
 ansible/roles/nova/tasks/deploy.yml           |  18 +-
 ansible/roles/nova/tasks/precheck.yml         |  28 +-
 ansible/roles/nova/tasks/pull.yml             |  87 +---
 ansible/roles/nova/tasks/reconfigure.yml      | 374 +-----------------
 ansible/roles/nova/tasks/start.yml            |   6 -
 ansible/roles/nova/tasks/start_compute.yml    | 111 ------
 ansible/roles/nova/tasks/start_conductors.yml |  12 -
 .../roles/nova/tasks/start_controllers.yml    |  80 ----
 ansible/roles/nova/tasks/upgrade.yml          |   9 +-
 15 files changed, 565 insertions(+), 753 deletions(-)
 create mode 100644 ansible/roles/nova/handlers/main.yml
 mode change 100644 => 120000 ansible/roles/nova/tasks/reconfigure.yml
 delete mode 100644 ansible/roles/nova/tasks/start.yml
 delete mode 100644 ansible/roles/nova/tasks/start_compute.yml
 delete mode 100644 ansible/roles/nova/tasks/start_conductors.yml
 delete mode 100644 ansible/roles/nova/tasks/start_controllers.yml

diff --git a/ansible/library/kolla_docker.py b/ansible/library/kolla_docker.py
index 4e731da7a..860ff5077 100644
--- a/ansible/library/kolla_docker.py
+++ b/ansible/library/kolla_docker.py
@@ -736,6 +736,10 @@ def generate_module():
             continue
         new_args[key] = value
 
+    # if pid_mode = ""/None/False, remove it
+    if not new_args.get('pid_mode', False):
+        new_args.pop('pid_mode', None)
+
     module.params = new_args
     return module
 
diff --git a/ansible/roles/nova/defaults/main.yml b/ansible/roles/nova/defaults/main.yml
index 669caf9fd..b67bd9587 100644
--- a/ansible/roles/nova/defaults/main.yml
+++ b/ansible/roles/nova/defaults/main.yml
@@ -1,6 +1,130 @@
 ---
 project_name: "nova"
 
+nova_services:
+  nova-libvirt:
+    container_name: nova_libvirt
+    group: compute
+    enabled: True
+    image: "{{ nova_libvirt_image_full }}"
+    pid_mode: "host"
+    privileged: True
+    volumes:
+      - "{{ node_config_directory }}/nova-libvirt/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "/lib/modules:/lib/modules:ro"
+      - "/run/:/run/:shared"
+      - "/dev:/dev"
+      - "/sys/fs/cgroup:/sys/fs/cgroup"
+      - "kolla_logs:/var/log/kolla/"
+      - "libvirtd:/var/lib/libvirt"
+      - "nova_compute:/var/lib/nova/"
+      - "{% if enable_cinder_backend_nfs | bool %}/var/lib/nova/mnt:/var/lib/nova/mnt:shared{% endif %}"
+      - "nova_libvirt_qemu:/etc/libvirt/qemu"
+  nova-ssh:
+    container_name: "nova_ssh"
+    group: "compute"
+    image: "{{ nova_ssh_image_full }}"
+    enabled: True
+    volumes:
+      - "{{ node_config_directory }}/nova-ssh/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "kolla_logs:/var/log/kolla"
+      - "nova_compute:/var/lib/nova"
+      - "/var/lib/nova/mnt:/var/lib/nova/mnt:shared"
+      - "heka_socket:/var/lib/kolla/heka/"
+  nova-api:
+    container_name: "nova_api"
+    group: "nova-api"
+    image: "{{ nova_api_image_full }}"
+    enabled: True
+    privileged: True
+    volumes:
+      - "{{ node_config_directory }}/nova-api/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "/lib/modules:/lib/modules:ro"
+      - "kolla_logs:/var/log/kolla/"
+  nova-consoleauth:
+    container_name: "nova_consoleauth"
+    group: "nova-consoleauth"
+    image: "{{ nova_consoleauth_image_full }}"
+    enabled: True
+    volumes:
+      - "{{ node_config_directory }}/nova-consoleauth/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "kolla_logs:/var/log/kolla/"
+  nova-novncproxy:
+    container_name: "nova_novncproxy"
+    group: "nova-novncproxy"
+    image: "{{ nova_novncproxy_image_full }}"
+    enabled: "{{ nova_console == 'novnc' }}"
+    volumes:
+      - "{{ node_config_directory }}/nova-novncproxy/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "kolla_logs:/var/log/kolla/"
+  nova-scheduler:
+    container_name: "nova_scheduler"
+    group: "nova-scheduler"
+    image: "{{ nova_scheduler_image_full }}"
+    enabled: True
+    volumes:
+      - "{{ node_config_directory }}/nova-scheduler/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "kolla_logs:/var/log/kolla/"
+  nova-spicehtml5proxy:
+    container_name: "nova_spicehtml5proxy"
+    group: "nova-spicehtml5proxy"
+    image: "{{ nova_spicehtml5proxy_image_full }}"
+    enabled: "{{ nova_console == 'spice' }}"
+    volumes:
+      - "{{ node_config_directory }}/nova-spicehtml5proxy/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "kolla_logs:/var/log/kolla/"
+  nova-serialproxy:
+    container_name: "nova_serialproxy"
+    group: "nova-serialproxy"
+    image: "{{ nova_serialproxy_image_full }}"
+    enabled: "{{ enable_nova_serialconsole_proxy | bool }}"
+    volumes:
+      - "{{ node_config_directory }}/nova-serialproxy/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "kolla_logs:/var/log/kolla/"
+  nova-conductor:
+    container_name: "nova_conductor"
+    group: "nova-conductor"
+    enabled: True
+    image: "{{ nova_conductor_image_full }}"
+    volumes:
+      - "{{ node_config_directory }}/nova-conductor/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "kolla_logs:/var/log/kolla/"
+  nova-compute:
+    container_name: "nova_compute"
+    group: "compute"
+    image: "{{ nova_compute_image_full }}"
+    privileged: True
+    enabled: "{{ not enable_nova_fake | bool or not enable_ironic | bool }}"
+    volumes:
+      - "{{ node_config_directory }}/nova-compute/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "/lib/modules:/lib/modules:ro"
+      - "/run:/run:shared"
+      - "/dev:/dev"
+      - "kolla_logs:/var/log/kolla/"
+      - "{% if enable_iscsid | bool %}iscsi_info:/etc/iscsi{% endif %}"
+      - "libvirtd:/var/lib/libvirt"
+      - "nova_compute:/var/lib/nova/"
+      - "{% if enable_cinder_backend_nfs | bool %}/var/lib/nova/mnt:/var/lib/nova/mnt:shared{% endif %}"
+  nova-compute-ironic:
+    container_name: "nova_compute_ironic"
+    group: "nova-compute-ironic"
+    image: "{{ nova_compute_ironic_image_full }}"
+    enabled: "{{ enable_ironic | bool }}"
+    volumes:
+      - "{{ node_config_directory }}/nova-compute-ironic/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "kolla_logs:/var/log/kolla/"
+
 ####################
 # Ceph
 ####################
diff --git a/ansible/roles/nova/handlers/main.yml b/ansible/roles/nova/handlers/main.yml
new file mode 100644
index 000000000..168506f32
--- /dev/null
+++ b/ansible/roles/nova/handlers/main.yml
@@ -0,0 +1,284 @@
+---
+- name: Restart nova-ssh container
+  vars:
+    service_name: "nova-ssh"
+    service: "{{ nova_services[service_name] }}"
+    config_json: "{{ config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    nova_ssh_container: "{{ check_nova_containers.results|selectattr('item.key', 'equalto', service_name)|first }}"
+  kolla_docker:
+    action: "recreate_or_restart_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ service.container_name }}"
+    image: "{{ service.image }}"
+    pid_mode: "{{ service.pid_mode | default('') }}"
+    privileged: "{{ service.privileged | default(False) }}"
+    volumes: "{{ service.volumes|reject('equalto', '')|list }}"
+  when:
+    - action != "config"
+    - inventory_hostname in groups[service.group]
+    - service.enabled | bool
+    - config_json.changed | bool
+      or nova_ssh_confs.changed | bool
+      or nova_ssh_container.changed | bool
+
+- name: Restart nova-libvirt container
+  vars:
+    service_name: "nova-libvirt"
+    service: "{{ nova_services[service_name] }}"
+    config_json: "{{ config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    nova_libvirt_container: "{{ check_nova_containers.results|selectattr('item.key', 'equalto', service_name)|first }}"
+  kolla_docker:
+    action: "recreate_or_restart_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ service.container_name }}"
+    image: "{{ service.image }}"
+    pid_mode: "{{ service.pid_mode | default('') }}"
+    privileged: "{{ service.privileged | default(False) }}"
+    volumes: "{{ service.volumes|reject('equalto', '')|list }}"
+  # NOTE(Jeffrey4l): retry 5 to remove nova_libvirt container because when
+  # guests running, nova_libvirt will raise error even though it is removed.
+  retries: 5
+  when:
+    - action != "config"
+    - inventory_hostname in groups[service.group]
+    - service.enabled | bool
+    - config_json.changed | bool
+      or nova_libvirt_confs.changed | bool
+      or nova_libvirt_container.changed | bool
+
+- name: Restart nova-api container
+  vars:
+    service_name: "nova-api"
+    service: "{{ nova_services[service_name] }}"
+    config_json: "{{ config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    nova_conf: "{{ nova_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    policy_json: "{{ policy_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    nova_api_container: "{{ check_nova_containers.results|selectattr('item.key', 'equalto', service_name)|first }}"
+  kolla_docker:
+    action: "recreate_or_restart_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ service.container_name }}"
+    image: "{{ service.image }}"
+    privileged: "{{ service.privileged | default(False) }}"
+    volumes: "{{ service.volumes|reject('equalto', '')|list }}"
+  when:
+    - action != "config"
+    - inventory_hostname in groups[service.group]
+    - service.enabled | bool
+    - config_json.changed | bool
+      or nova_conf.changed | bool
+      or policy_json.changed | bool
+      or nova_api_container.changed | bool
+
+- name: Restart nova-consoleauth container
+  vars:
+    service_name: "nova-consoleauth"
+    service: "{{ nova_services[service_name] }}"
+    config_json: "{{ config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    nova_conf: "{{ nova_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    policy_json: "{{ policy_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    nova_consoleauth_container: "{{ check_nova_containers.results|selectattr('item.key', 'equalto', service_name)|first }}"
+  kolla_docker:
+    action: "recreate_or_restart_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ service.container_name }}"
+    image: "{{ service.image }}"
+    privileged: "{{ service.privileged | default(False) }}"
+    volumes: "{{ service.volumes|reject('equalto', '')|list }}"
+  when:
+    - action != "config"
+    - inventory_hostname in groups[service.group]
+    - service.enabled | bool
+    - config_json.changed | bool
+      or nova_conf.changed | bool
+      or policy_json.changed | bool
+      or nova_consoleauth_container.changed | bool
+
+- name: Restart nova-novncproxy container
+  vars:
+    service_name: "nova-novncproxy"
+    service: "{{ nova_services[service_name] }}"
+    config_json: "{{ config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    nova_conf: "{{ nova_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    policy_json: "{{ policy_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    nova_novncproxy_container: "{{ check_nova_containers.results|selectattr('item.key', 'equalto', service_name)|first }}"
+  kolla_docker:
+    action: "recreate_or_restart_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ service.container_name }}"
+    image: "{{ service.image }}"
+    privileged: "{{ service.privileged | default(False) }}"
+    volumes: "{{ service.volumes|reject('equalto', '')|list }}"
+  when:
+    - action != "config"
+    - inventory_hostname in groups[service.group]
+    - service.enabled | bool
+    - config_json.changed | bool
+      or nova_conf.changed | bool
+      or policy_json.changed | bool
+      or nova_novncproxy_container.changed | bool
+
+- name: Restart nova-spicehtml5proxy container
+  vars:
+    service_name: "nova-spicehtml5proxy"
+    service: "{{ nova_services[service_name] }}"
+    config_json: "{{ config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    nova_conf: "{{ nova_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    policy_json: "{{ policy_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    nova_spicehtml5proxy_container: "{{ check_nova_containers.results|selectattr('item.key', 'equalto', service_name)|first }}"
+  kolla_docker:
+    action: "recreate_or_restart_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ service.container_name }}"
+    image: "{{ service.image }}"
+    privileged: "{{ service.privileged | default(False) }}"
+    volumes: "{{ service.volumes|reject('equalto', '')|list }}"
+  when:
+    - action != "config"
+    - inventory_hostname in groups[service.group]
+    - service.enabled | bool
+    - config_json.changed | bool
+      or nova_conf.changed | bool
+      or policy_json.changed | bool
+      or nova_spicehtml5proxy_container.changed | bool
+
+- name: Restart nova-serialproxy container
+  vars:
+    service_name: "nova-spicehtml5proxy"
+    service: "{{ nova_services[service_name] }}"
+    config_json: "{{ config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    nova_conf: "{{ nova_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    policy_json: "{{ policy_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    nova_spicehtml5proxy_container: "{{ check_nova_containers.results|selectattr('item.key', 'equalto', service_name)|first }}"
+  kolla_docker:
+    action: "recreate_or_restart_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ service.container_name }}"
+    image: "{{ service.image }}"
+    privileged: "{{ service.privileged | default(False) }}"
+    volumes: "{{ service.volumes|reject('equalto', '')|list }}"
+  when:
+    - action != "config"
+    - inventory_hostname in groups[service.group]
+    - service.enabled | bool
+    - config_json.changed | bool
+      or nova_conf.changed | bool
+      or policy_json.changed | bool
+      or nova_spicehtml5proxy_container.changed | bool
+
+- name: Restart nova-scheduler container
+  vars:
+    service_name: "nova-scheduler"
+    service: "{{ nova_services[service_name] }}"
+    config_json: "{{ config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    nova_conf: "{{ nova_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    policy_json: "{{ policy_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    nova_scheduler_container: "{{ check_nova_containers.results|selectattr('item.key', 'equalto', service_name)|first }}"
+  kolla_docker:
+    action: "recreate_or_restart_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ service.container_name }}"
+    image: "{{ service.image }}"
+    privileged: "{{ service.privileged | default(False) }}"
+    volumes: "{{ service.volumes|reject('equalto', '')|list }}"
+  when:
+    - action != "config"
+    - inventory_hostname in groups[service.group]
+    - service.enabled | bool
+    - config_json.changed | bool
+      or nova_conf.changed | bool
+      or policy_json.changed | bool
+      or nova_scheduler_container.changed | bool
+
+- name: Restart nova-conductor container
+  vars:
+    service_name: "nova-conductor"
+    service: "{{ nova_services[service_name] }}"
+    config_json: "{{ config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    nova_conf: "{{ nova_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    policy_json: "{{ policy_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    nova_conductor_container: "{{ check_nova_containers.results|selectattr('item.key', 'equalto', service_name)|first }}"
+  kolla_docker:
+    action: "recreate_or_restart_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ service.container_name }}"
+    image: "{{ service.image }}"
+    privileged: "{{ service.privileged | default(False) }}"
+    volumes: "{{ service.volumes|reject('equalto', '')|list }}"
+  when:
+    - action != "config"
+    - inventory_hostname in groups[service.group]
+    - service.enabled | bool
+    - config_json.changed | bool
+      or nova_conf.changed | bool
+      or policy_json.changed | bool
+      or nova_conductor_container.changed | bool
+
+- name: Restart nova-compute container
+  vars:
+    service_name: "nova-compute"
+    service: "{{ nova_services[service_name] }}"
+    config_json: "{{ config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    nova_conf: "{{ nova_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    policy_json: "{{ policy_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    nova_compute_container: "{{ check_nova_containers.results|selectattr('item.key', 'equalto', service_name)|first }}"
+  kolla_docker:
+    action: "recreate_or_restart_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ service.container_name }}"
+    image: "{{ service.image }}"
+    privileged: "{{ service.privileged | default(False) }}"
+    volumes: "{{ service.volumes|reject('equalto', '')|list }}"
+  when:
+    - action != "config"
+    - inventory_hostname in groups[service.group]
+    - service.enabled | bool
+    - config_json.changed | bool
+      or nova_conf.changed | bool
+      or policy_json.changed | bool
+      or nova_compute_container.changed | bool
+
+- name: Restart nova-compute-ironic container
+  vars:
+    service_name: "nova-compute-ironic"
+    service: "{{ nova_services[service_name] }}"
+    config_json: "{{ config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    nova_conf: "{{ nova_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    policy_json: "{{ policy_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    nova_compute_ironic_container: "{{ check_nova_containers.results|selectattr('item.key', 'equalto', service_name)|first }}"
+  kolla_docker:
+    action: "recreate_or_restart_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ service.container_name }}"
+    image: "{{ service.image }}"
+    privileged: "{{ service.privileged | default(False) }}"
+    volumes: "{{ service.volumes|reject('equalto', '')|list }}"
+  when:
+    - action != "config"
+    - inventory_hostname in groups[service.group]
+    - service.enabled | bool
+    - config_json.changed | bool
+      or nova_conf.changed | bool
+      or policy_json.changed | bool
+      or nova_compute_ironic_container.changed | bool
+
+# nova-compute-fake is special. It will start multi numbers of container
+# so put all variables here rather than defaults/main.yml file
+- name: Restart nova-compute-fake containers
+  kolla_docker:
+    action: "recreate_or_restart_container"
+    common_options: "{{ docker_common_options }}"
+    name: "nova_compute_fake_{{ item }}"
+    image: "{{ nova_compute_image_full }}"
+    privileged: True
+    volumes:
+      - "{{ node_config_directory }}/nova-compute-fake-{{ item }}/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "/lib/modules:/lib/modules:ro"
+      - "/run:/run:shared"
+      - "kolla_logs:/var/log/kolla/"
+  with_sequence: start=1 end={{ num_nova_fake_per_node }}
+  when:
+    - action != "config"
+    - inventory_hostname in groups['compute']
+    - enable_nova_fake | bool
diff --git a/ansible/roles/nova/tasks/bootstrap_service.yml b/ansible/roles/nova/tasks/bootstrap_service.yml
index 33ce56728..6b29b23ad 100644
--- a/ansible/roles/nova/tasks/bootstrap_service.yml
+++ b/ansible/roles/nova/tasks/bootstrap_service.yml
@@ -1,5 +1,7 @@
 ---
 - name: Running Nova bootstrap container
+  vars:
+    nova_api: "{{ nova_services['nova-api'] }}"
   kolla_docker:
     action: "start_container"
     common_options: "{{ docker_common_options }}"
@@ -7,14 +9,11 @@
     environment:
       KOLLA_BOOTSTRAP:
       KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}"
-    image: "{{ nova_api_image_full }}"
+    image: "{{ nova_api.image }}"
     labels:
       BOOTSTRAP:
     name: "bootstrap_nova"
     restart_policy: "never"
-    volumes:
-      - "{{ node_config_directory }}/nova-api/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "kolla_logs:/var/log/kolla/"
+    volumes: "{{ nova_api.volumes }}"
   run_once: True
-  delegate_to: "{{ groups['nova-api'][0] }}"
+  delegate_to: "{{ groups[nova_api.group][0] }}"
diff --git a/ansible/roles/nova/tasks/config-nova-fake.yml b/ansible/roles/nova/tasks/config-nova-fake.yml
index 2bd74e115..cb4909be1 100644
--- a/ansible/roles/nova/tasks/config-nova-fake.yml
+++ b/ansible/roles/nova/tasks/config-nova-fake.yml
@@ -5,12 +5,16 @@
     state: "directory"
     recurse: yes
   with_sequence: start=1 end={{ num_nova_fake_per_node }}
+  notify:
+    - Restart nova-compute-fake containers
 
 - name: Copying over config.json files for services
   template:
     src: "nova-compute.json.j2"
     dest: "{{ node_config_directory }}/nova-compute-fake-{{ item }}/config.json"
   with_sequence: start=1 end={{ num_nova_fake_per_node }}
+  notify:
+    - Restart nova-compute-fake containers
 
 - name: Copying over nova.conf
   merge_configs:
@@ -26,3 +30,26 @@
       - "{{ node_config_directory }}/config/nova/{{ inventory_hostname }}/nova.conf"
     dest: "{{ node_config_directory }}/nova-compute-fake-{{ item }}/nova.conf"
   with_sequence: start=1 end={{ num_nova_fake_per_node }}
+  notify:
+    - Restart nova-compute-fake containers
+
+- name: Check nova-compute-fake containers
+  kolla_docker:
+    action: "compare_container"
+    common_options: "{{ docker_common_options }}"
+    name: "nova_compute_fake_{{ item }}"
+    image: "{{ nova_compute_image_full }}"
+    privileged: True
+    volumes:
+      - "{{ node_config_directory }}/nova-compute-fake-{{ item }}/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "/lib/modules:/lib/modules:ro"
+      - "/run:/run:shared"
+      - "kolla_logs:/var/log/kolla/"
+  with_sequence: start=1 end={{ num_nova_fake_per_node }}
+  when:
+    - action != "config"
+    - inventory_hostname in groups['compute']
+    - enable_nova_fake | bool
+  notify:
+    - Restart nova-compute-fake containers
diff --git a/ansible/roles/nova/tasks/config.yml b/ansible/roles/nova/tasks/config.yml
index da2192252..f77071127 100644
--- a/ansible/roles/nova/tasks/config.yml
+++ b/ansible/roles/nova/tasks/config.yml
@@ -12,98 +12,137 @@
 
 - name: Ensuring config directories exist
   file:
-    path: "{{ node_config_directory }}/{{ item }}"
+    path: "{{ node_config_directory }}/{{ item.key }}"
     state: "directory"
     recurse: yes
-  with_items:
-    - "nova-api"
-    - "nova-compute"
-    - "nova-compute-ironic"
-    - "nova-conductor"
-    - "nova-consoleauth"
-    - "nova-libvirt"
-    - "nova-novncproxy"
-    - "nova-scheduler"
-    - "nova-spicehtml5proxy"
-    - "nova-ssh"
-    - "nova-serialproxy"
+  when:
+    - inventory_hostname in groups[item.value.group]
+    - item.value.enabled | bool
+  with_dict: "{{ nova_services }}"
 
 - name: Copying over config.json files for services
   template:
-    src: "{{ item }}.json.j2"
-    dest: "{{ node_config_directory }}/{{ item }}/config.json"
-  with_items:
-    - "nova-api"
-    - "nova-compute"
-    - "nova-compute-ironic"
-    - "nova-conductor"
-    - "nova-consoleauth"
-    - "nova-libvirt"
-    - "nova-novncproxy"
-    - "nova-scheduler"
-    - "nova-spicehtml5proxy"
-    - "nova-ssh"
-    - "nova-serialproxy"
+    src: "{{ item.key }}.json.j2"
+    dest: "{{ node_config_directory }}/{{ item.key }}/config.json"
+  register: config_jsons
+  when:
+    - inventory_hostname in groups[item.value.group]
+    - item.value.enabled | bool
+  with_dict: "{{ nova_services }}"
+  notify:
+    - "Restart {{ item.key }} container"
 
 - name: Copying over nova.conf
+  vars:
+    services_require_nova_conf:
+      - nova-api
+      - nova-compute
+      - nova-compute-ironic
+      - nova-conductor
+      - nova-consoleauth
+      - nova-novncproxy
+      - nova-serialproxy
+      - nova-scheduler
+      - nova-spicehtml5proxy
   merge_configs:
     vars:
-      service_name: "{{ item }}"
+      service_name: "{{ item.key }}"
     sources:
       - "{{ role_path }}/templates/nova.conf.j2"
       - "{{ node_custom_config }}/global.conf"
       - "{{ node_custom_config }}/database.conf"
       - "{{ node_custom_config }}/messaging.conf"
       - "{{ node_custom_config }}/nova.conf"
-      - "{{ node_custom_config }}/nova/{{ item }}.conf"
+      - "{{ node_custom_config }}/nova/{{ item.key }}.conf"
       - "{{ node_custom_config }}/nova/{{ inventory_hostname }}/nova.conf"
-    dest: "{{ node_config_directory }}/{{ item }}/nova.conf"
-  with_items:
-    - "nova-api"
-    - "nova-compute"
-    - "nova-compute-ironic"
-    - "nova-conductor"
-    - "nova-consoleauth"
-    - "nova-novncproxy"
-    - "nova-scheduler"
-    - "nova-spicehtml5proxy"
-    - "nova-serialproxy"
+    dest: "{{ node_config_directory }}/{{ item.key }}/nova.conf"
+  register: nova_confs
+  when:
+    - inventory_hostname in groups[item.value.group]
+    - item.value.enabled | bool
+    - item.key in services_require_nova_conf
+  with_dict: "{{ nova_services }}"
+  notify:
+    - "Restart {{ item.key }} container"
 
 - name: Copying over libvirt configuration
+  vars:
+    service: "{{ nova_services['nova-libvirt'] }}"
   template:
     src: "{{ item.src }}"
     dest: "{{ node_config_directory }}/nova-libvirt/{{ item.dest }}"
+  register: nova_libvirt_confs
+  when:
+    - inventory_hostname in groups[service.group]
+    - service.enabled | bool
   with_items:
     - { src: "qemu.conf.j2", dest: "qemu.conf" }
     - { src: "libvirtd.conf.j2", dest: "libvirtd.conf" }
+  notify:
+    - Restart nova-libvirt container
 
 - name: Copying files for nova-ssh
+  vars:
+    service: "{{ nova_services['nova-ssh'] }}"
   template:
     src: "{{ item.src }}"
     dest: "{{ node_config_directory }}/nova-ssh/{{ item.dest }}"
+  register: nova_ssh_confs
+  when:
+    - inventory_hostname in groups[service.group]
+    - service.enabled | bool
   with_items:
     - { src: "sshd_config.j2", dest: "sshd_config" }
     - { src: "id_rsa", dest: "id_rsa" }
     - { src: "id_rsa.pub", dest: "id_rsa.pub" }
     - { src: "ssh_config.j2", dest: "ssh_config" }
+  notify:
+    - Restart nova-ssh container
 
 - name: Check if policies shall be overwritten
   local_action: stat path="{{ node_custom_config }}/nova/policy.json"
   register: nova_policy
 
 - name: Copying over existing policy.json
+  vars:
+    services_require_policy_json:
+      - nova-api
+      - nova-compute
+      - nova-compute-ironic
+      - nova-conductor
+      - nova-consoleauth
+      - nova-novncproxy
+      - nova-serialproxy
+      - nova-scheduler
+      - nova-spicehtml5proxy
   template:
     src: "{{ node_custom_config }}/nova/policy.json"
-    dest: "{{ node_config_directory }}/{{ item }}/policy.json"
-  with_items:
-    - "nova-api"
-    - "nova-compute"
-    - "nova-compute-ironic"
-    - "nova-conductor"
-    - "nova-consoleauth"
-    - "nova-novncproxy"
-    - "nova-scheduler"
-    - "nova-spicehtml5proxy"
-    - "nova-serialproxy"
+    dest: "{{ node_config_directory }}/{{ item.key }}/policy.json"
+  register: policy_jsons
+  when:
+    - inventory_hostname in groups[item.value.group]
+    - item.value.enabled | bool
+    - nova_policy.stat.exists | bool
+    - item.key in services_require_policy_json
+  with_dict: "{{ nova_services }}"
+  notify:
+    - "Restart {{ item.key }} container"
+
+# check whether the containers parameter is changed. If yes, trigger the handler
+- name: Check nova containers
+  kolla_docker:
+    action: "compare_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ item.value.container_name }}"
+    image: "{{ item.value.image }}"
+    pid_mode: "{{ item.value.pid_mode|default('') }}"
+    privileged: "{{ item.value.privileged|default(False) }}"
+    volumes: "{{ item.value.volumes|reject('equalto', '')|list }}"
+  register: check_nova_containers
   when:
-    nova_policy.stat.exists
+    - action != "config"
+    - inventory_hostname in groups[item.value.group]
+    - item.value.enabled | bool
+  with_dict: "{{ nova_services }}"
+  notify:
+    - "Restart {{ item.key }} container"
diff --git a/ansible/roles/nova/tasks/deploy.yml b/ansible/roles/nova/tasks/deploy.yml
index dd699eef0..14bf9ac8c 100644
--- a/ansible/roles/nova/tasks/deploy.yml
+++ b/ansible/roles/nova/tasks/deploy.yml
@@ -19,13 +19,6 @@
   when: inventory_hostname in groups['nova-api']
 
 - include: config.yml
-  when: inventory_hostname in groups['compute'] or
-        inventory_hostname in groups['nova-api'] or
-        inventory_hostname in groups['nova-conductor'] or
-        inventory_hostname in groups['nova-consoleauth'] or
-        inventory_hostname in groups['nova-novncproxy'] or
-        inventory_hostname in groups['nova-scheduler'] or
-        inventory_hostname in groups['nova-serialproxy']
 
 - include: config-nova-fake.yml
   when:
@@ -36,12 +29,5 @@
   when: inventory_hostname in groups['nova-api'] or
         inventory_hostname in groups['compute']
 
-- include: start.yml
-  when: inventory_hostname in groups['compute'] or
-        inventory_hostname in groups['nova-api'] or
-        inventory_hostname in groups['nova-conductor'] or
-        inventory_hostname in groups['nova-consoleauth'] or
-        inventory_hostname in groups['nova-novncproxy'] or
-        inventory_hostname in groups['nova-scheduler'] or
-        inventory_hostname in groups['nova-serialproxy']
-
+- name: Flush handlers
+  meta: flush_handlers
diff --git a/ansible/roles/nova/tasks/precheck.yml b/ansible/roles/nova/tasks/precheck.yml
index 430dd19cd..743ff8fa1 100644
--- a/ansible/roles/nova/tasks/precheck.yml
+++ b/ansible/roles/nova/tasks/precheck.yml
@@ -9,6 +9,8 @@
   register: container_facts
 
 - name: Checking free port for Nova API
+  vars:
+    nova_api: "{{ nova_services['nova-api'] }}"
   wait_for:
     host: "{{ hostvars[inventory_hostname]['ansible_' + api_interface]['ipv4']['address'] }}"
     port: "{{ nova_api_port }}"
@@ -16,9 +18,12 @@
     state: stopped
   when:
     - container_facts['nova_api'] is not defined
-    - inventory_hostname in groups['nova-api']
+    - inventory_hostname in groups[nova_api.group]
+    - nova_api.enabled | bool
 
 - name: Checking free port for Nova Metadata
+  vars:
+    nova_api: "{{ nova_services['nova-api'] }}"
   wait_for:
     host: "{{ hostvars[inventory_hostname]['ansible_' + api_interface]['ipv4']['address'] }}"
     port: "{{ nova_metadata_port }}"
@@ -26,9 +31,12 @@
     state: stopped
   when:
     - container_facts['nova_api'] is not defined
-    - inventory_hostname in groups['nova-api']
+    - inventory_hostname in groups[nova_api.group]
+    - nova_api.enabled | bool
 
 - name: Checking free port for Nova NoVNC Proxy
+  vars:
+    nova_novncproxy: "{{ nova_services['nova-novncproxy'] }}"
   wait_for:
     host: "{{ hostvars[inventory_hostname]['ansible_' + api_interface]['ipv4']['address'] }}"
     port: "{{ nova_novncproxy_port }}"
@@ -36,10 +44,12 @@
     state: stopped
   when:
     - container_facts['nova_novncproxy'] is not defined
-    - nova_console == 'novnc'
-    - inventory_hostname in groups['nova-novncproxy']
+    - nova_novncproxy.enabled | bool
+    - inventory_hostname in groups[nova_novncproxy.group]
 
 - name: Checking free port for Nova Serial Proxy
+  vars:
+    nova_serialproxy: "{{ nova_services['nova-serialproxy'] }}"
   wait_for:
     host: "{{ hostvars[inventory_hostname]['ansible_' + api_interface]['ipv4']['address'] }}"
     port: "{{ nova_serialproxy_port }}"
@@ -47,10 +57,12 @@
     state: stopped
   when:
     - container_facts['nova_serialproxy'] is not defined
-    - enable_nova_serialconsole_proxy | bool
-    - inventory_hostname in groups['nova-serialproxy']
+    - nova_serialproxy.enabled | bool
+    - inventory_hostname in groups[nova_serialproxy.group]
 
 - name: Checking free port for Nova Spice HTML5 Proxy
+  vars:
+    nova_spicehtml5proxy: "{{ nova_services['nova-spicehtml5proxy'] }}"
   wait_for:
     host: "{{ hostvars[inventory_hostname]['ansible_' + api_interface]['ipv4']['address'] }}"
     port: "{{ nova_spicehtml5proxy_port }}"
@@ -58,5 +70,5 @@
     state: stopped
   when:
     - container_facts['nova_spicehtml5proxy'] is not defined
-    - nova_console == 'spice'
-    - inventory_hostname in groups['nova-spicehtml5proxy']
+    - nova_spicehtml5proxy.enabled | bool
+    - inventory_hostname in groups[nova_spicehtml5proxy.group]
diff --git a/ansible/roles/nova/tasks/pull.yml b/ansible/roles/nova/tasks/pull.yml
index 0d03e7714..4d32080e0 100644
--- a/ansible/roles/nova/tasks/pull.yml
+++ b/ansible/roles/nova/tasks/pull.yml
@@ -1,87 +1,10 @@
 ---
-- name: Pulling nova-api image
+- name: Pulling nova images
   kolla_docker:
     action: "pull_image"
     common_options: "{{ docker_common_options }}"
-    image: "{{ nova_api_image_full }}"
-  when: inventory_hostname in groups['nova-api']
-
-- name: Pulling nova-compute image
-  kolla_docker:
-    action: "pull_image"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_compute_image_full }}"
-  when:
-    - not enable_nova_fake | bool
-    - inventory_hostname in groups['compute']
-
-- name: Pulling nova-compute-ironic image
-  kolla_docker:
-    action: "pull_image"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_compute_ironic_image_full }}"
-  when:
-    - enable_ironic | bool
-    - inventory_hostname in groups['nova-compute-ironic']
-
-- name: Pulling nova-conductor image
-  kolla_docker:
-    action: "pull_image"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_conductor_image_full }}"
-  when: inventory_hostname in groups['nova-conductor']
-
-- name: Pulling nova-consoleauth image
-  kolla_docker:
-    action: "pull_image"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_consoleauth_image_full }}"
-  when: inventory_hostname in groups['nova-consoleauth']
-
-- name: Pulling nova-libvirt image
-  kolla_docker:
-    action: "pull_image"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_libvirt_image_full }}"
-  when: inventory_hostname in groups['compute']
-
-- name: Pulling nova-ssh image
-  kolla_docker:
-    action: "pull_image"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_ssh_image_full }}"
-  when: inventory_hostname in groups['compute']
-
-- name: Pulling nova-novncproxy image
-  kolla_docker:
-    action: "pull_image"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_novncproxy_image_full }}"
-  when:
-    - inventory_hostname in groups['nova-novncproxy']
-    - nova_console == 'novnc'
-
-- name: Pulling nova-scheduler image
-  kolla_docker:
-    action: "pull_image"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_scheduler_image_full }}"
-  when: inventory_hostname in groups['nova-scheduler']
-
-- name: Pulling nova-serialproxy image
-  kolla_docker:
-    action: "pull_image"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_serialproxy_image_full }}"
-  when:
-    - inventory_hostname in groups['nova-serialproxy']
-    - enable_nova_serialconsole_proxy | bool
-
-- name: Pulling nova-spicehtml5proxy image
-  kolla_docker:
-    action: "pull_image"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_spicehtml5proxy_image_full }}"
+    image: "{{ item.value.image }}"
   when:
-    - inventory_hostname in groups['nova-spicehtml5proxy']
-    - nova_console == 'spice'
+    - inventory_hostname in groups[item.value.group]
+    - item.value.enabled | bool
+  with_dict: "{{ nova_services }}"
diff --git a/ansible/roles/nova/tasks/reconfigure.yml b/ansible/roles/nova/tasks/reconfigure.yml
deleted file mode 100644
index a78074c30..000000000
--- a/ansible/roles/nova/tasks/reconfigure.yml
+++ /dev/null
@@ -1,373 +0,0 @@
----
-- name: Ensuring the nova libvirt, ssh, conductor, api, consoleauth and scheduler containers are up
-  kolla_docker:
-    name: "{{ item.name }}"
-    action: "get_container_state"
-  register: container_state
-  failed_when: container_state.Running == false
-  when: inventory_hostname in groups[item.group]
-  with_items:
-    - { name: nova_libvirt, group: compute }
-    - { name: nova_ssh, group: compute }
-    - { name: nova_conductor, group: nova-conductor }
-    - { name: nova_api, group: nova-api }
-    - { name: nova_consoleauth, group: nova-consoleauth }
-    - { name: nova_scheduler, group: nova-scheduler }
-
-- name: Ensuring the nova_compute container is up
-  kolla_docker:
-    name: "nova_compute"
-    action: "get_container_state"
-  register: container_state
-  failed_when: container_state.Running == false
-  when:
-    - not enable_nova_fake | bool
-    - inventory_hostname in groups['compute']
-
-- name: Ensuring the nova_compute_ironic container is up
-  kolla_docker:
-    name: "nova_compute_ironic"
-    action: "get_container_state"
-  register: container_state
-  failed_when: container_state.Running == false
-  when:
-    - enable_ironic | bool
-    - inventory_hostname in groups['nova-compute-ironic']
-
-- name: Ensuring the nova_novncproxy container is up
-  kolla_docker:
-    name: "nova_novncproxy"
-    action: "get_container_state"
-  register: container_state
-  failed_when: container_state.Running == false
-  when:
-    - nova_console == 'novnc'
-    - inventory_hostname in groups['nova-novncproxy']
-
-- name: Ensuring the nova_spicehtml5proxy container is up
-  kolla_docker:
-    name: "nova_spicehtml5proxy"
-    action: "get_container_state"
-  register: container_state
-  failed_when: container_state.Running == false
-  when:
-    - nova_console == 'spice'
-    - inventory_hostname in groups['nova-spicehtml5proxy']
-
-- name: Ensuring the nova_serialproxy container is up
-  kolla_docker:
-    name: "nova_serialproxy"
-    action: "get_container_state"
-  register: container_state
-  failed_when: container_state.Running == false
-  when:
-    - enable_nova_serialconsole_proxy | bool
-    - inventory_hostname in groups['nova-serialproxy']
-
-- include: config.yml
-
-- name: Check the configs for nova libvirt, ssh, conductor, api, consoleauth and scheduler containers
-  command: docker exec {{ item.name }} /usr/local/bin/kolla_set_configs --check
-  changed_when: false
-  failed_when: false
-  register: check_results
-  when: inventory_hostname in groups[item.group]
-  with_items:
-    - { name: nova_libvirt, group: compute }
-    - { name: nova_ssh, group: compute }
-    - { name: nova_conductor, group: nova-conductor }
-    - { name: nova_api, group: nova-api }
-    - { name: nova_consoleauth, group: nova-consoleauth }
-    - { name: nova_scheduler, group: nova-scheduler }
-
-- name: Check the configs in the nova_compute container
-  command: docker exec nova_compute /usr/local/bin/kolla_set_configs --check
-  changed_when: false
-  failed_when: false
-  register: nova_compute_check_result
-  when:
-    - not enable_nova_fake | bool
-    - inventory_hostname in groups['compute']
-
-- name: Check the configs in the nova_compute_ironic container
-  command: docker exec nova_compute_ironic /usr/local/bin/kolla_set_configs --check
-  changed_when: false
-  failed_when: false
-  register: nova_compute_ironic_check_result
-  when:
-    - enable_ironic | bool
-    - inventory_hostname in groups['nova-compute-ironic']
-
-- name: Check the configs in the nova_novncproxy container
-  command: docker exec nova_novncproxy /usr/local/bin/kolla_set_configs --check
-  changed_when: false
-  failed_when: false
-  register: nova_novncproxy_check_result
-  when:
-    - nova_console == 'novnc'
-    - inventory_hostname in groups['nova-novncproxy']
-
-- name: Check the configs in the nova_spicehtml5proxy container
-  command: docker exec nova_spicehtml5proxy /usr/local/bin/kolla_set_configs --check
-  changed_when: false
-  failed_when: false
-  register: nova_spicehtml5proxy_check_result
-  when:
-    - nova_console == 'spice'
-    - inventory_hostname in groups['nova-spicehtml5proxy']
-
-- name: Check the configs in the nova_serialproxy container
-  command: docker exec nova_serialproxy /usr/local/bin/kolla_set_configs --check
-  changed_when: false
-  failed_when: false
-  register: nova_serialproxy_check_result
-  when:
-    - enable_nova_serialconsole_proxy | bool
-    - inventory_hostname in groups['nova-serialproxy']
-
-# NOTE(jeffrey4l): when config_strategy == 'COPY_ALWAYS'
-# and container env['KOLLA_CONFIG_STRATEGY'] == 'COPY_ONCE',
-# just remove the container and start again
-- name: Containers config strategy for nova libvirt, ssh, conductor, api, consoleauth and scheduler containers
-  kolla_docker:
-    name: "{{ item.name }}"
-    action: "get_container_env"
-  register: container_envs
-  when: inventory_hostname in groups[item.group]
-  with_items:
-    - { name: nova_libvirt, group: compute }
-    - { name: nova_ssh, group: compute }
-    - { name: nova_conductor, group: nova-conductor }
-    - { name: nova_api, group: nova-api }
-    - { name: nova_consoleauth, group: nova-consoleauth }
-    - { name: nova_scheduler, group: nova-scheduler }
-
-- name: Container config strategy for nova_compute
-  kolla_docker:
-    name: nova_compute
-    action: "get_container_env"
-  register: nova_compute_container_env
-  when:
-    - not enable_nova_fake | bool
-    - inventory_hostname in groups['compute']
-
-- name: Container config strategy for nova_compute_ironic
-  kolla_docker:
-    name: nova_compute_ironic
-    action: "get_container_env"
-  register: nova_compute_ironic_container_env
-  when:
-    - enable_ironic | bool
-    - inventory_hostname in groups['nova-compute-ironic']
-
-- name: Container config strategy for nova_novncproxy
-  kolla_docker:
-    name: nova_novncproxy
-    action: "get_container_env"
-  register: nova_novncproxy_container_env
-  when:
-    - nova_console == 'novnc'
-    - inventory_hostname in groups['nova-novncproxy']
-
-- name: Container config strategy for nova_spicehtml5proxy
-  kolla_docker:
-    name: nova_spicehtml5proxy
-    action: "get_container_env"
-  register: nova_spicehtml5proxy_container_env
-  when:
-    - nova_console == 'spice'
-    - inventory_hostname in groups['nova-spicehtml5proxy']
-
-- name: Container config strategy for nova_serialproxy
-  kolla_docker:
-    name: nova_serialproxy
-    action: "get_container_env"
-  register: nova_serialproxy_container_env
-  when:
-    - enable_nova_serialconsole_proxy | bool
-    - inventory_hostname in groups['nova-serialproxy']
-
-- name: Remove the nova libvirt, ssh, conductor, api, consoleauth and scheduler containers
-  kolla_docker:
-    name: "{{ item[0]['name'] }}"
-    action: "remove_container"
-  register: remove_containers
-  until: remote_container|success
-  retries: "{{ item[0]['retries']|default(0) }}"
-  when:
-    - inventory_hostname in groups[item[0]['group']]
-    - config_strategy == "COPY_ONCE" or item[1]['KOLLA_CONFIG_STRATEGY'] == 'COPY_ONCE'
-    - item[2]['rc'] == 1
-  with_together:
-    # NOTE(Jeffrey4l): retry 1 to remove nova_libvirt container because when
-    # guests running, nova_libvirt will raise error even though it is removed.
-    - [{ name: nova_libvirt, group: compute, retries: 1 },
-       { name: nova_ssh, group: compute },
-       { name: nova_conductor, group: nova-conductor },
-       { name: nova_api, group: nova-api },
-       { name: nova_consoleauth, group: nova-consoleauth },
-       { name: nova_scheduler, group: nova-scheduler }]
-    - "{{ container_envs.results }}"
-    - "{{ check_results.results }}"
-
-- name: Remove nova_compute container
-  kolla_docker:
-    name: nova_compute
-    action: "remove_container"
-  register: remove_nova_compute_container
-  when:
-    - not enable_nova_fake | bool
-    - inventory_hostname in groups['compute']
-    - config_strategy == 'COPY_ONCE' or nova_compute_container_env['KOLLA_CONFIG_STRATEGY'] == 'COPY_ONCE'
-    - nova_compute_check_result['rc'] == 1
-
-- name: Remove nova_compute_ironic container
-  kolla_docker:
-    name: nova_compute_ironic
-    action: "remove_container"
-  register: remove_nova_compute_ironic_container
-  when:
-    - enable_ironic | bool
-    - inventory_hostname in groups['nova-compute-ironic']
-    - config_strategy == 'COPY_ONCE' or nova_compute_ironic_container_env['KOLLA_CONFIG_STRATEGY'] == 'COPY_ONCE'
-    - nova_compute_ironic_check_result['rc'] == 1
-
-- name: Remove nova_novncproxy container
-  kolla_docker:
-    name: nova_novncproxy
-    action: "remove_container"
-  register: remove_nova_novncproxy_container
-  when:
-    - nova_console == 'novnc'
-    - inventory_hostname in groups['nova-novncproxy']
-    - config_strategy == 'COPY_ONCE' or nova_novncproxy_container_env['KOLLA_CONFIG_STRATEGY'] == 'COPY_ONCE'
-    - nova_novncproxy_check_result['rc'] == 1
-
-- name: Remove nova_spicehtml5proxy container
-  kolla_docker:
-    name: nova_spicehtml5proxy
-    action: "remove_container"
-  register: remove_nova_spicehtml5proxy_container
-  when:
-    - nova_console == 'spice'
-    - inventory_hostname in groups['nova-spicehtml5proxy']
-    - config_strategy == 'COPY_ONCE' or nova_spicehtml5proxy_container_env['KOLLA_CONFIG_STRATEGY'] == 'COPY_ONCE'
-    - nova_spicehtml5proxy_check_result['rc'] == 1
-
-- name: Remove nova_serialproxy container
-  kolla_docker:
-    name: nova_serialproxy
-    action: "remove_container"
-  register: remove_nova_serialproxy_container
-  when:
-    - enable_nova_serialconsole_proxy | bool
-    - inventory_hostname in groups['nova-serialproxy']
-    - config_strategy == 'COPY_ONCE' or nova_serialproxy_container_env['KOLLA_CONFIG_STRATEGY'] == 'COPY_ONCE'
-    - nova_serialproxy_check_result['rc'] == 1
-
-- include: start.yml
-  when: remove_containers.changed
-
-- include: start.yml
-  when:
-    - not enable_nova_fake | bool
-    - remove_nova_compute_container.changed
-
-- include: start.yml
-  when:
-    - enable_ironic | bool
-    - remove_nova_compute_ironic_container.changed
-
-- include: start.yml
-  when:
-    - enable_ironic | bool
-    - remove_nova_compute_ironic_container.changed
-
-- include: start.yml
-  when:
-    - nova_console == 'novnc'
-    - remove_nova_novncproxy_container.changed
-
-- include: start.yml
-  when:
-    - nova_console == 'spice'
-    - remove_nova_spicehtml5proxy_container.changed
-
-- include: start.yml
-  when:
-    - enable_nova_serialconsole_proxy | bool
-    - remove_nova_serialproxy_container.changed
-
-- name: Restart the nova libvirt, ssh, conductor, api, consoleauth and scheduler containers
-  kolla_docker:
-    name: "{{ item[0]['name'] }}"
-    action: "restart_container"
-  when:
-    - config_strategy == 'COPY_ALWAYS'
-    - inventory_hostname in groups[item[0]['group']]
-    - item[1]['KOLLA_CONFIG_STRATEGY'] != 'COPY_ONCE'
-    - item[2]['rc'] == 1
-  with_together:
-    - [{ name: nova_libvirt, group: compute },
-       { name: nova_ssh, group: compute },
-       { name: nova_conductor, group: nova-conductor },
-       { name: nova_api, group: nova-api },
-       { name: nova_consoleauth, group: nova-consoleauth },
-       { name: nova_scheduler, group: nova-scheduler }]
-    - "{{ container_envs.results }}"
-    - "{{ check_results.results }}"
-
-- name: Restart the nova_compute container
-  kolla_docker:
-    name: "nova_compute"
-    action: "restart_container"
-  when:
-    - not enable_nova_fake | bool
-    - config_strategy == 'COPY_ALWAYS'
-    - inventory_hostname in groups['compute']
-    - nova_compute_container_env['KOLLA_CONFIG_STRATEGY'] != 'COPY_ONCE'
-    - nova_compute_check_result['rc'] == 1
-
-- name: Restart the nova_compute_ironic container
-  kolla_docker:
-    name: "nova_compute_ironic"
-    action: "restart_container"
-  when:
-    - enable_ironic | bool
-    - config_strategy == 'COPY_ALWAYS'
-    - inventory_hostname in groups['nova-compute-ironic']
-    - nova_compute_ironic_container_env['KOLLA_CONFIG_STRATEGY'] != 'COPY_ONCE'
-    - nova_compute_ironic_check_result['rc'] == 1
-
-- name: Restart the nova_novncproxy container
-  kolla_docker:
-    name: "nova_novncproxy"
-    action: "restart_container"
-  when:
-    - nova_console == 'novnc'
-    - config_strategy == 'COPY_ALWAYS'
-    - inventory_hostname in groups['nova-novncproxy']
-    - nova_novncproxy_container_env['KOLLA_CONFIG_STRATEGY'] != 'COPY_ONCE'
-    - nova_novncproxy_check_result['rc'] == 1
-
-- name: Restart the nova_spicehtml5proxy container
-  kolla_docker:
-    name: "nova_spicehtml5proxy"
-    action: "restart_container"
-  when:
-    - nova_console == 'spice'
-    - config_strategy == 'COPY_ALWAYS'
-    - inventory_hostname in groups['nova-spicehtml5proxy']
-    - nova_spicehtml5proxy_container_env['KOLLA_CONFIG_STRATEGY'] != 'COPY_ONCE'
-    - nova_spicehtml5proxy_check_result['rc'] == 1
-
-- name: Restart the nova_serialproxy container
-  kolla_docker:
-    name: "nova_serialproxy"
-    action: "restart_container"
-  when:
-    - enable_nova_serialconsole_proxy | bool
-    - config_strategy == 'COPY_ALWAYS'
-    - inventory_hostname in groups['nova-serialproxy']
-    - nova_serialproxy_container_env['KOLLA_CONFIG_STRATEGY'] != 'COPY_ONCE'
-    - nova_serialproxy_check_result['rc'] == 1
diff --git a/ansible/roles/nova/tasks/reconfigure.yml b/ansible/roles/nova/tasks/reconfigure.yml
new file mode 120000
index 000000000..0412f9220
--- /dev/null
+++ b/ansible/roles/nova/tasks/reconfigure.yml
@@ -0,0 +1 @@
+deploy.yml
\ No newline at end of file
diff --git a/ansible/roles/nova/tasks/start.yml b/ansible/roles/nova/tasks/start.yml
deleted file mode 100644
index 659729b19..000000000
--- a/ansible/roles/nova/tasks/start.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-- include: start_controllers.yml
-
-- include: start_conductors.yml
-
-- include: start_compute.yml
diff --git a/ansible/roles/nova/tasks/start_compute.yml b/ansible/roles/nova/tasks/start_compute.yml
deleted file mode 100644
index 6ea62dc01..000000000
--- a/ansible/roles/nova/tasks/start_compute.yml
+++ /dev/null
@@ -1,111 +0,0 @@
----
-- name: Prepare nova-libvirt volumes list
-  set_fact:
-    libvirt_volumes:
-      - "{{ node_config_directory }}/nova-libvirt/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "/lib/modules:/lib/modules:ro"
-      - "/run/:/run/:shared"
-      - "/dev:/dev"
-      - "/sys/fs/cgroup:/sys/fs/cgroup"
-      - "kolla_logs:/var/log/kolla/"
-      - "libvirtd:/var/lib/libvirt"
-      - "nova_compute:/var/lib/nova/"
-      - "{% if enable_cinder_backend_nfs | bool %}/var/lib/nova/mnt:/var/lib/nova/mnt:shared{% endif %}"
-      - "nova_libvirt_qemu:/etc/libvirt/qemu"
-
-- name: Starting nova-libvirt container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_libvirt_image_full }}"
-    name: "nova_libvirt"
-    pid_mode: "host"
-    privileged: True
-    volumes: '{{ libvirt_volumes | reject("equalto", "") | list }}'
-  register: start_nova_libvirt_container
-  # NOTE(Jeffrey4l): retry 5 to remove nova_libvirt container because when
-  # guests running, nova_libvirt will raise error even though it is removed.
-  retries: 5
-  until: start_nova_libvirt_container|success
-  when: inventory_hostname in groups['compute']
-
-- name: Prepare nova-compute volumes list
-  set_fact:
-     nova_compute_volumes:
-      - "{{ node_config_directory }}/nova-compute/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "/lib/modules:/lib/modules:ro"
-      - "/run:/run:shared"
-      - "/dev:/dev"
-      - "kolla_logs:/var/log/kolla/"
-      - "{% if enable_iscsid | bool %}iscsi_info:/etc/iscsi{% endif %}"
-      - "libvirtd:/var/lib/libvirt"
-      - "nova_compute:/var/lib/nova/"
-      - "{% if enable_cinder_backend_nfs | bool %}/var/lib/nova/mnt:/var/lib/nova/mnt:shared{% endif %}"
-
-- name: Starting nova-compute container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_compute_image_full }}"
-    name: "nova_compute"
-    privileged: True
-    volumes: '{{ nova_compute_volumes | reject("equalto", "") | list }}'
-  when:
-    - not enable_nova_fake | bool
-    - not enable_ironic | bool
-    - inventory_hostname in groups['compute']
-
-- name: Starting nova-compute-ironic container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_compute_ironic_image_full }}"
-    name: "nova_compute_ironic"
-    volumes:
-      - "{{ node_config_directory }}/nova-compute-ironic/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "kolla_logs:/var/log/kolla/"
-  when:
-    - enable_ironic | bool
-    - inventory_hostname in groups['nova-compute-ironic']
-
-- name: Starting nova-compute-fake containers
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_compute_image_full }}"
-    name: "nova_compute_fake_{{ item }}"
-    privileged: True
-    volumes:
-      - "{{ node_config_directory }}/nova-compute-fake-{{ item }}/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "/lib/modules:/lib/modules:ro"
-      - "/run:/run:shared"
-      - "kolla_logs:/var/log/kolla/"
-  with_sequence: start=1 end={{ num_nova_fake_per_node }}
-  when:
-    - enable_nova_fake | bool
-    - inventory_hostname in groups['compute']
-
-- name: Prepare nova-ssh volumes list
-  set_fact:
-    nova_ssh_volumes:
-      - "{{ node_config_directory }}/nova-ssh/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "kolla_logs:/var/log/kolla"
-      - "nova_compute:/var/lib/nova"
-      - "{% if enable_cinder_backend_nfs | bool %}/var/lib/nova/mnt:/var/lib/nova/mnt:shared{% endif %}"
-      - "heka_socket:/var/lib/kolla/heka/"
-
-- name: Starting nova-ssh container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_ssh_image_full }}"
-    name: "nova_ssh"
-    volumes: '{{ nova_ssh_volumes | reject("equalto", "") | list }}'
-  # TODO(jeffrey4l): how to handle the nova-compute-fake and
-  # nova-compute-ironic
-  when: inventory_hostname in groups['compute']
diff --git a/ansible/roles/nova/tasks/start_conductors.yml b/ansible/roles/nova/tasks/start_conductors.yml
deleted file mode 100644
index aa5fe4dd0..000000000
--- a/ansible/roles/nova/tasks/start_conductors.yml
+++ /dev/null
@@ -1,12 +0,0 @@
----
-- name: Starting nova-conductor container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    name: "nova_conductor"
-    image: "{{ nova_conductor_image_full }}"
-    volumes:
-      - "{{ node_config_directory }}/nova-conductor/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "kolla_logs:/var/log/kolla/"
-  when: inventory_hostname in groups['nova-conductor']
diff --git a/ansible/roles/nova/tasks/start_controllers.yml b/ansible/roles/nova/tasks/start_controllers.yml
deleted file mode 100644
index 015922617..000000000
--- a/ansible/roles/nova/tasks/start_controllers.yml
+++ /dev/null
@@ -1,80 +0,0 @@
----
-- name: Starting nova-api container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_api_image_full }}"
-    name: "nova_api"
-    privileged: True
-    volumes:
-      - "{{ node_config_directory }}/nova-api/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "/lib/modules:/lib/modules:ro"
-      - "kolla_logs:/var/log/kolla/"
-  when: inventory_hostname in groups['nova-api']
-
-- name: Starting nova-consoleauth container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_consoleauth_image_full }}"
-    name: "nova_consoleauth"
-    volumes:
-      - "{{ node_config_directory }}/nova-consoleauth/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "kolla_logs:/var/log/kolla/"
-  when: inventory_hostname in groups['nova-consoleauth']
-
-- name: Starting nova-novncproxy container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_novncproxy_image_full }}"
-    name: "nova_novncproxy"
-    volumes:
-      - "{{ node_config_directory }}/nova-novncproxy/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "kolla_logs:/var/log/kolla/"
-  when:
-    - inventory_hostname in groups['nova-novncproxy']
-    - nova_console == 'novnc'
-
-- name: Starting nova-scheduler container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_scheduler_image_full }}"
-    name: "nova_scheduler"
-    volumes:
-      - "{{ node_config_directory }}/nova-scheduler/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "kolla_logs:/var/log/kolla/"
-  when: inventory_hostname in groups['nova-scheduler']
-
-- name: Starting nova-serialproxy container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_serialproxy_image_full }}"
-    name: "nova_serialproxy"
-    volumes:
-      - "{{ node_config_directory }}/nova-serialproxy/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "kolla_logs:/var/log/kolla/"
-  when:
-    - inventory_hostname in groups['nova-serialproxy']
-    - enable_nova_serialconsole_proxy | bool
-
-- name: Starting nova-spicehtml5proxy container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ nova_spicehtml5proxy_image_full }}"
-    name: "nova_spicehtml5proxy"
-    volumes:
-      - "{{ node_config_directory }}/nova-spicehtml5proxy/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "kolla_logs:/var/log/kolla/"
-  when:
-    - inventory_hostname in groups['nova-spicehtml5proxy']
-    - nova_console == 'spice'
diff --git a/ansible/roles/nova/tasks/upgrade.yml b/ansible/roles/nova/tasks/upgrade.yml
index bc24e375e..1ee7056c8 100644
--- a/ansible/roles/nova/tasks/upgrade.yml
+++ b/ansible/roles/nova/tasks/upgrade.yml
@@ -29,10 +29,5 @@
     - inventory_hostname in groups['nova-conductor']
     - conductor_differs['result']
 
-- include: start_conductors.yml
-
-- include: start_controllers.yml
-
-- include: start_compute.yml
-
-- include: reload.yml
+- name: Flush handlers
+  meta: flush_handlers
-- 
GitLab