diff --git a/ansible/library/kolla_docker.py b/ansible/library/kolla_docker.py
index 4e731da7ad88ec49bde81eb2d03ca2ec379aad3c..860ff507701d363528acde54d2d9d92105341742 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 669caf9fd9a6a0d8a670087f4b65a4c82f0041a9..b67bd95870dc200385e62502eb66e801688c3f85 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 0000000000000000000000000000000000000000..168506f32f7667dcfed1cdf7fc2d473d53077b8d
--- /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 33ce56728e250ce1c8fcc848f6a738397b5cf4d7..6b29b23add2db4664d3e2bd4134b822508d7281d 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 2bd74e11529e0ba2531396bfd0a655c028cf1a0d..cb4909be17c7dc113695e5b6f653be22180ad515 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 da2192252ae1a41bda7ef7285f60362f6651e399..f770711274175a8f4f5f774359e59cf54e9e8228 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 dd699eef0783f17b4f7bf5a20713a4e4a1900355..14bf9ac8c854a6f877e450a749cb329b763976bb 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 430dd19cd679e1f15b3b4f10d3e41e824bc7c9b0..743ff8fa1dba003aac16d5e10b6eeaef83ea8642 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 0d03e77145b35d9a2302d4cceee597d0daec0573..4d32080e0170a3b11036e3996ad19b18fb44dcb4 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 a78074c303cd8bcd5f6272dbe5163b3a3c01ea64..0000000000000000000000000000000000000000
--- 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 0000000000000000000000000000000000000000..0412f922007a7f378c97bb3f400feefc81408a8d
--- /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 659729b199f913668b9b9e540434740cc2aca5f2..0000000000000000000000000000000000000000
--- 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 6ea62dc01bef9ea2a45f8084d30de4cd55f3d3d4..0000000000000000000000000000000000000000
--- 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 aa5fe4dd00b2997adde05085756a3318eee8453e..0000000000000000000000000000000000000000
--- 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 01592261754a0baed2aa3ca188c1e2c5c8ff0d24..0000000000000000000000000000000000000000
--- 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 bc24e375e12c5e07e1b739bb2e53ca7b1e1e2028..1ee7056c8d3b17eec080233fbb55afdb05c6a1fb 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