From a4beb63c20f17cd0b31c0688833bd03115ee7be4 Mon Sep 17 00:00:00 2001
From: Jeffrey Zhang <zhang.lei.fly@gmail.com>
Date: Tue, 24 Jan 2017 11:25:17 +0800
Subject: [PATCH] Optimize reconfigure action for neutron

Partially-implements: blueprint better-reconfigure
Change-Id: I3879b9339b54e1d063dd1c4673bac85ced333335
---
 ansible/roles/neutron/defaults/main.yml       | 206 ++++++++++
 ansible/roles/neutron/handlers/main.yml       | 361 ++++++++++++++++++
 .../roles/neutron/tasks/bootstrap_service.yml |  41 +-
 .../neutron/tasks/config-neutron-fake.yml     |  43 +++
 ansible/roles/neutron/tasks/config.yml        | 310 +++++++++------
 ansible/roles/neutron/tasks/deploy.yml        |  19 +-
 ansible/roles/neutron/tasks/pull.yml          |  93 +----
 ansible/roles/neutron/tasks/reconfigure.yml   | 325 +---------------
 ansible/roles/neutron/tasks/start.yml         | 303 ---------------
 ansible/roles/neutron/tasks/upgrade.yml       |  17 +-
 10 files changed, 839 insertions(+), 879 deletions(-)
 create mode 100644 ansible/roles/neutron/handlers/main.yml
 mode change 100644 => 120000 ansible/roles/neutron/tasks/reconfigure.yml
 delete mode 100644 ansible/roles/neutron/tasks/start.yml

diff --git a/ansible/roles/neutron/defaults/main.yml b/ansible/roles/neutron/defaults/main.yml
index 2b2636ab7b..3a849ae9f5 100644
--- a/ansible/roles/neutron/defaults/main.yml
+++ b/ansible/roles/neutron/defaults/main.yml
@@ -1,6 +1,212 @@
 ---
 project_name: "neutron"
 
+neutron_services:
+  openvswitch-db-server:
+    container_name: "openvswitch_db"
+    image: "{{ openvswitch_db_image_full }}"
+    enabled: "{{ neutron_plugin_agent == 'openvswitch' }}"
+    host_in_groups: >-
+      {{
+        inventory_hostname in groups['compute']
+        or (enable_manila | bool and inventory_hostname in groups['manila-share'])
+        or inventory_hostname in groups['neutron-dhcp-agent']
+        or inventory_hostname in groups['neutron-l3-agent']
+        or inventory_hostname in groups['neutron-metadata-agent']
+        or inventory_hostname in groups['neutron-vpnaas-agent']
+      }}
+    volumes:
+      - "{{ node_config_directory }}/openvswitch-db-server/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "/run:/run:shared"
+      - "kolla_logs:/var/log/kolla/"
+      - "openvswitch_db:/var/lib/openvswitch/"
+  openvswitch-vswitchd:
+    container_name: "openvswitch_vswitchd"
+    image: "{{ openvswitch_vswitchd_image_full }}"
+    enabled: "{{ neutron_plugin_agent == 'openvswitch' }}"
+    host_in_groups: >-
+      {{
+        inventory_hostname in groups['compute']
+        or (enable_manila | bool and inventory_hostname in groups['manila-share'])
+        or inventory_hostname in groups['neutron-dhcp-agent']
+        or inventory_hostname in groups['neutron-l3-agent']
+        or inventory_hostname in groups['neutron-metadata-agent']
+        or inventory_hostname in groups['neutron-vpnaas-agent']
+      }}
+    privileged: True
+    volumes:
+      - "{{ node_config_directory }}/openvswitch-vswitchd/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "/lib/modules:/lib/modules:ro"
+      - "/run:/run:shared"
+      - "kolla_logs:/var/log/kolla/"
+  neutron-server:
+    container_name: "neutron_server"
+    image: "{{ neutron_server_image_full }}"
+    enabled: true
+    group: "neutron-server"
+    host_in_groups: "{{ inventory_hostname in groups['neutron-server'] }}"
+    volumes:
+      - "{{ node_config_directory }}/neutron-server/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "kolla_logs:/var/log/kolla/"
+  neutron-openvswitch-agent:
+    container_name: "neutron_openvswitch_agent"
+    image: "{{ neutron_openvswitch_agent_image_full }}"
+    enabled: "{{ neutron_plugin_agent == 'openvswitch' }}"
+    privileged: True
+    host_in_groups: >-
+      {{
+        ( inventory_hostname in groups['compute']
+          or (enable_manila | bool and inventory_hostname in groups['manila-share'])
+          or inventory_hostname in groups['neutron-dhcp-agent']
+          or inventory_hostname in groups['neutron-l3-agent']
+          or inventory_hostname in groups['neutron-metadata-agent']
+          or inventory_hostname in groups['neutron-vpnaas-agent']
+          and not enable_nova_fake | bool
+        ) or
+        ( inventory_hostname in groups['neutron-dhcp-agent']
+          or inventory_hostname in groups['neutron-l3-agent']
+          or inventory_hostname in groups['neutron-metadata-agent']
+          or inventory_hostname in groups['neutron-vpnaas-agent']
+          and enable_nova_fake | bool
+        )
+      }}
+    volumes:
+      - "{{ node_config_directory }}/neutron-openvswitch-agent/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "/lib/modules:/lib/modules:ro"
+      - "/run:/run:shared"
+      - "kolla_logs:/var/log/kolla/"
+  neutron-sfc-agent:
+    container_name: "neutron_sfc_agent"
+    image: "{{ neutron_sfc_agent_image_full }}"
+    enabled: "{{ neutron_plugin_agent == 'sfc' }}"
+    privileged: True
+    host_in_groups: >-
+      {{
+        ( inventory_hostname in groups['compute']
+          or (enable_manila | bool and inventory_hostname in groups['manila-share'])
+          or inventory_hostname in groups['neutron-dhcp-agent']
+          or inventory_hostname in groups['neutron-l3-agent']
+          or inventory_hostname in groups['neutron-metadata-agent']
+          and not enable_nova_fake | bool
+        ) or
+        ( inventory_hostname in groups['neutron-dhcp-agent']
+          or inventory_hostname in groups['neutron-l3-agent']
+          or inventory_hostname in groups['neutron-metadata-agent']
+          and enable_nova_fake | bool
+        )
+      }}
+    volumes:
+      - "{{ node_config_directory }}/neutron-sfc-agent/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "/lib/modules:/lib/modules:ro"
+      - "/run:/run:shared"
+      - "kolla_logs:/var/log/kolla/"
+  neutron-linuxbridge-agent:
+    container_name: "neutron_linuxbridge_agent"
+    image: "{{  neutron_linuxbridge_agent_image_full }}"
+    privileged: True
+    enabled: "{{ neutron_plugin_agent == 'linuxbridge' }}"
+    environment:
+      KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}"
+      NEUTRON_BRIDGE: "br-ex"
+      NEUTRON_INTERFACE: "{{ neutron_external_interface }}"
+    host_in_groups: >-
+      {{
+        inventory_hostname in groups['compute']
+        or (enable_manila | bool and inventory_hostname in groups['manila-share'])
+        or inventory_hostname in groups['neutron-dhcp-agent']
+        or inventory_hostname in groups['neutron-l3-agent']
+        or inventory_hostname in groups['neutron-metadata-agent']
+        or inventory_hostname in groups['neutron-vpnaas-agent']
+      }}
+    volumes:
+      - "{{ node_config_directory }}/neutron-linuxbridge-agent/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "/lib/modules:/lib/modules:ro"
+      - "/run:/run:shared"
+      - "kolla_logs:/var/log/kolla/"
+  neutron-dhcp-agent:
+    container_name: "neutron_dhcp_agent"
+    image: "{{ neutron_dhcp_agent_image_full }}"
+    privileged: True
+    enabled: True
+    group: "neutron-dhcp-agent"
+    host_in_groups: "{{ inventory_hostname in groups['neutron-dhcp-agent'] }}"
+    volumes:
+      - "{{ node_config_directory }}/neutron-dhcp-agent/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "/run/:/run/:shared"
+      - "/run/netns/:/run/netns/:shared"
+      - "neutron_metadata_socket:/var/lib/neutron/kolla/"
+      - "kolla_logs:/var/log/kolla/"
+  neutron-l3-agent:
+    container_name: "neutron_l3_agent"
+    image: "{{ neutron_l3_agent_image_full }}"
+    privileged: True
+    enabled: "{{ not enable_neutron_vpnaas | bool }}"
+    host_in_groups: >-
+      {{
+        inventory_hostname in groups['neutron-l3-agent']
+        or (inventory_hostname in groups['compute'] and enable_neutron_dvr | bool)
+      }}
+    volumes:
+      - "{{ node_config_directory }}/neutron-l3-agent/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "/run:/run:shared"
+      - "/run/netns/:/run/netns/:shared"
+      - "neutron_metadata_socket:/var/lib/neutron/kolla/"
+      - "kolla_logs:/var/log/kolla/"
+  neutron-lbaas-agent:
+    container_name: "neutron_lbaas_agent"
+    image: "{{ neutron_lbaas_agent_image_full }}"
+    privileged: True
+    enabled: "{{ enable_neutron_lbaas | bool }}"
+    group: "neutron-lbaas-agent"
+    host_in_groups: "{{ inventory_hostname in groups['neutron-lbaas-agent'] }}"
+    volumes:
+      - "{{ node_config_directory }}/neutron-lbaas-agent/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "/run:/run:shared"
+      - "/run/netns/:/run/netns/:shared"
+      - "neutron_metadata_socket:/var/lib/neutron/kolla/"
+      - "kolla_logs:/var/log/kolla/"
+  neutron-metadata-agent:
+    container_name: "neutron_metadata_agent"
+    image: "{{ neutron_metadata_agent_image_full }}"
+    privileged: True
+    enabled: true
+    host_in_groups: >-
+      {{
+        inventory_hostname in groups['neutron-metadata-agent']
+        or (inventory_hostname in groups['compute'] and enable_neutron_dvr | bool)
+      }}
+    volumes:
+      - "{{ node_config_directory }}/neutron-metadata-agent/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "/run/netns/:/run/netns/:shared"
+      - "neutron_metadata_socket:/var/lib/neutron/kolla/"
+      - "kolla_logs:/var/log/kolla/"
+  neutron-vpnaas-agent:
+    container_name: "neutron_vpnaas_agent"
+    image: "{{ neutron_vpnaas_agent_image_full }}"
+    privileged: True
+    enabled: "{{ enable_neutron_vpnaas | bool }}"
+    group: "neutron-vpnaas-agent"
+    host_in_groups: "{{ inventory_hostname in groups['neutron-vpnaas-agent'] }}"
+    volumes:
+      - "{{ node_config_directory }}/neutron-vpnaas-agent/:{{ container_config_directory }}/:ro"
+      - "/etc/localtime:/etc/localtime:ro"
+      - "/run:/run:shared"
+      - "/run/netns/:/run/netns/:shared"
+      - "/lib/modules:/lib/modules:ro"
+      - "neutron_metadata_socket:/var/lib/neutron/kolla/"
+      - "kolla_logs:/var/log/kolla/"
+
+
 ####################
 # Database
 ####################
diff --git a/ansible/roles/neutron/handlers/main.yml b/ansible/roles/neutron/handlers/main.yml
new file mode 100644
index 0000000000..f68c65b224
--- /dev/null
+++ b/ansible/roles/neutron/handlers/main.yml
@@ -0,0 +1,361 @@
+---
+- name: Restart openvswitch-db-server container
+  vars:
+    service_name: "openvswitch-db-server"
+    service: "{{ neutron_services[service_name] }}"
+    config_json: "{{ neutron_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    openvswitch_db_container: "{{ check_neutron_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 }}"
+    volumes: "{{ service.volumes }}"
+  when:
+    - action != "config"
+    - service.enabled | bool
+    - service.host_in_groups | bool
+    - config_json | changed
+      or openvswitch_db_container | changed
+  notify:
+    - Waiting the openvswitch_db service to be ready
+    - Ensuring OVS bridge is properly setup
+
+- name: Waiting the openvswitch_db service to be ready
+  command: docker exec openvswitch_db ovs-vsctl --no-wait show
+  register: check_result
+  until: check_result | success
+  changed_when: False
+  retries: 30
+  delay: 2
+  notify:
+
+- name: Ensuring OVS bridge is properly setup
+  command: docker exec openvswitch_db /usr/local/bin/kolla_ensure_openvswitch_configured {{ item.0 }} {{ item.1 }}
+  register: status
+  changed_when: status.stdout.find('changed') != -1
+  with_together:
+    - "{{ neutron_bridge_name.split(',') }}"
+    - "{{ neutron_external_interface.split(',') }}"
+
+- name: Restart openvswitch-vswitchd container
+  vars:
+    service_name: "openvswitch-vswitchd"
+    service: "{{ neutron_services[service_name] }}"
+    config_json: "{{ neutron_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    openvswitch_vswitchd_container: "{{ check_neutron_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 }}"
+    volumes: "{{ service.volumes }}"
+    privileged: "{{ service.privileged | default(False) }}"
+  when:
+    - action != "config"
+    - service.enabled | bool
+    - service.host_in_groups | bool
+    - config_json | changed
+      or openvswitch_vswitchd_container | changed
+
+- name: Restart neutron-server container
+  vars:
+    service_name: "neutron-server"
+    service: "{{ neutron_services[service_name] }}"
+    config_json: "{{ neutron_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_conf: "{{ neutron_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_lbaas_conf: "{{ neutron_lbaas_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_ml2_conf: "{{ neutron_ml2_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    policy_json: "{{ policy_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_server_container: "{{ check_neutron_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 }}"
+    volumes: "{{ service.volumes }}"
+    privileged: "{{ service.privileged | default(False) }}"
+  when:
+    - action != "config"
+    - service.enabled | bool
+    - service.host_in_groups | bool
+    - config_json | changed
+      or neutron_conf | changed
+      or neutron_lbaas_conf | changed
+      or neutron_vpnaas_conf | changed
+      or neutron_ml2_conf | changed
+      or policy_json | changed
+      or neutron_server_container | changed
+
+- name: Restart neutron-openvswitch-agent container
+  vars:
+    service_name: "neutron-openvswitch-agent"
+    service: "{{ neutron_services[service_name] }}"
+    config_json: "{{ neutron_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_conf: "{{ neutron_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_ml2_conf: "{{ neutron_ml2_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    policy_json: "{{ policy_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_openvswitch_agent_container: "{{ check_neutron_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 }}"
+    volumes: "{{ service.volumes }}"
+    privileged: "{{ service.privileged | default(False) }}"
+  when:
+    - action != "config"
+    - service.enabled | bool
+    - service.host_in_groups | bool
+    - config_json | changed
+      or neutron_conf | changed
+      or neutron_ml2_conf | changed
+      or policy_json | changed
+      or neutron_openvswitch_agent_container | changed
+
+- name: Restart fake neutron-openvswitch-agent container
+  vars:
+    service_name: "neutron-openvswitch-agent"
+    service: "{{ neutron_services[service_name] }}"
+    config_json: "{{ neutron_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_conf: "{{ neutron_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_ml2_conf: "{{ neutron_ml2_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    policy_json: "{{ policy_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_openvswitch_agent_container: "{{ check_neutron_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 }}"
+    volumes: "{{ service.volumes }}"
+    privileged: "{{ service.privileged | default(False) }}"
+  with_sequence: "start=1 end={{ num_nova_fake_per_node }}"
+  when:
+    - action != "config"
+    - enabled_nova_fake | bool
+    - neutron_plugin_agent == "openvswitch"
+    - inventory_hostname in groups["compute"]
+    - fake_config_json | changed
+      or fake_neutron_conf | changed
+      or fake_neutron_ml2_conf_ini | changed
+      or check_fake_neutron_openvswitch_agent | changed
+
+- name: Restart fake neutron-sfc-agent container
+  vars:
+    service_name: "neutron-sfc-agent"
+    service: "{{ neutron_services[service_name] }}"
+    config_json: "{{ neutron_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_conf: "{{ neutron_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_ml2_conf: "{{ neutron_ml2_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    policy_json: "{{ policy_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_sfc_agent_container: "{{ check_neutron_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 }}"
+    volumes: "{{ service.volumes }}"
+    privileged: "{{ service.privileged | default(False) }}"
+  with_sequence: "start=1 end={{ num_nova_fake_per_node }}"
+  when:
+    - action != "config"
+    - enabled_nova_fake | bool
+    - neutron_plugin_agent == "sfc"
+    - inventory_hostname in groups["compute"]
+    - fake_config_json | changed
+      or fake_neutron_conf | changed
+      or fake_neutron_ml2_conf_ini | changed
+      or check_fake_neutron_sfc_agent | changed
+
+# TODO(Jeffrey4l): sfc do not have config.json file at all. it is not finished
+- name: Restart neutron-sfc-agent container
+  vars:
+    service_name: "neutron-sfc-agent"
+    service: "{{ neutron_services[service_name] }}"
+    config_json: "{{ neutron_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_sfc_agent_container: "{{ check_neutron_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 }}"
+    volumes: "{{ service.volumes }}"
+    privileged: "{{ service.privileged | default(False) }}"
+  when:
+    - action != "config"
+    - service.enabled | bool
+    - service.host_in_groups | bool
+    - config_json | changed
+      or neutron_sfc_agent_container | changed
+
+- name: Restart neutron-linuxbridge-agent container
+  vars:
+    service_name: "neutron-linuxbridge-agent"
+    service: "{{ neutron_services[service_name] }}"
+    config_json: "{{ neutron_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_conf: "{{ neutron_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_ml2_conf: "{{ neutron_ml2_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    policy_json: "{{ policy_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_linuxbridge_agent_container: "{{ check_neutron_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 }}"
+    environment: "{{ service.environment }}"
+    volumes: "{{ service.volumes }}"
+    privileged: "{{ service.privileged | default(False) }}"
+  when:
+    - action != "config"
+    - service.enabled | bool
+    - service.host_in_groups | bool
+    - config_json | changed
+      or neutron_conf | changed
+      or neutron_ml2_conf | changed
+      or policy_json | changed
+      or neutron_linuxbridge_agent_container | changed
+
+- name: Restart neutron-dhcp-agent container
+  vars:
+    service_name: "neutron-dhcp-agent"
+    service: "{{ neutron_services[service_name] }}"
+    config_json: "{{ neutron_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_conf: "{{ neutron_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_ml2_conf: "{{ neutron_ml2_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    policy_json: "{{ policy_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_dhcp_agent_container: "{{ check_neutron_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 }}"
+    volumes: "{{ service.volumes }}"
+    privileged: "{{ service.privileged | default(False) }}"
+  when:
+    - action != "config"
+    - service.enabled | bool
+    - service.host_in_groups | bool
+    - config_json | changed
+      or neutron_conf | changed
+      or neutron_ml2_conf | changed
+      or dhcp_agent_ini | changed
+      or dnsmasq_conf | changed
+      or policy_json | changed
+      or neutron_dhcp_agent_container | changed
+
+- name: Restart neutron-l3-agent container
+  vars:
+    service_name: "neutron-l3-agent"
+    service: "{{ neutron_services[service_name] }}"
+    config_json: "{{ neutron_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_conf: "{{ neutron_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_ml2_conf: "{{ neutron_ml2_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_l3_agent_ini: "{{ neutron_l3_agent_inis.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_fwaas_driver_ini: "{{ neutron_fwaas_driver_inis.results|selectattr('item.key', 'equalto', service_name)|first }}"
+
+    policy_json: "{{ policy_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_l3_agent_container: "{{ check_neutron_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 }}"
+    volumes: "{{ service.volumes }}"
+    privileged: "{{ service.privileged | default(False) }}"
+  when:
+    - action != "config"
+    - service.enabled | bool
+    - service.host_in_groups | bool
+    - config_json | changed
+      or neutron_conf | changed
+      or neutron_ml2_conf | changed
+      or neutron_l3_agent_ini | changed
+      or neutron_fwaas_driver_ini | changed
+      or policy_json | changed
+      or neutron_l3_agent_container | changed
+
+- name: Restart neutron-lbaas-agent container
+  vars:
+    service_name: "neutron-lbaas-agent"
+    service: "{{ neutron_services[service_name] }}"
+    config_json: "{{ neutron_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_conf: "{{ neutron_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_lbaas_conf: "{{ neutron_lbaas_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_ml2_conf: "{{ neutron_ml2_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    policy_json: "{{ policy_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_lbaas_agent_container: "{{ check_neutron_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 }}"
+    volumes: "{{ service.volumes }}"
+    privileged: "{{ service.privileged | default(False) }}"
+  when:
+    - action != "config"
+    - service.enabled | bool
+    - service.host_in_groups | bool
+    - config_json | changed
+      or neutron_conf | changed
+      or neutron_ml2_conf | changed
+      or neutron_lbaas_agent_ini | changed
+      or policy_json | changed
+      or neutron_lbaas_agent_container | changed
+
+- name: Restart neutron-metadata-agent container
+  vars:
+    service_name: "neutron-metadata-agent"
+    service: "{{ neutron_services[service_name] }}"
+    config_json: "{{ neutron_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_conf: "{{ neutron_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_ml2_conf: "{{ neutron_ml2_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    policy_json: "{{ policy_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_metadata_agent_container: "{{ check_neutron_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 }}"
+    volumes: "{{ service.volumes }}"
+    privileged: "{{ service.privileged | default(False) }}"
+  when:
+    - action != "config"
+    - service.enabled | bool
+    - service.host_in_groups | bool
+    - config_json | changed
+      or neutron_conf | changed
+      or neutron_ml2_conf | changed
+      or neutron_metadata_agent_ini | changed
+      or policy_json | changed
+      or neutron_metadata_agent_container | changed
+
+- name: Restart neutron-vpnaas-agent container
+  vars:
+    service_name: "neutron-vpnaas-agent"
+    service: "{{ neutron_services[service_name] }}"
+    config_json: "{{ neutron_config_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_conf: "{{ neutron_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_ml2_conf: "{{ neutron_ml2_confs.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_l3_agent_ini: "{{ neutron_l3_agent_inis.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_fwaas_driver_ini: "{{ neutron_fwaas_driver_inis.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    policy_json: "{{ policy_jsons.results|selectattr('item.key', 'equalto', service_name)|first }}"
+    neutron_vpnaas_agent_container: "{{ check_neutron_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 }}"
+    volumes: "{{ service.volumes }}"
+    privileged: "{{ service.privileged | default(False) }}"
+  when:
+    - action != "config"
+    - service.enabled | bool
+    - service.host_in_groups | bool
+    - config_json | changed
+      or neutron_conf | changed
+      or neutron_ml2_conf | changed
+      or neutron_l3_agent_ini | changed
+      or neutron_fwaas_driver_ini | changed
+      or neutron_vpnaas_agent_ini | changed
+      or policy_json | changed
+      or neutron_vpnaas_agent_container | changed
diff --git a/ansible/roles/neutron/tasks/bootstrap_service.yml b/ansible/roles/neutron/tasks/bootstrap_service.yml
index 50d114535f..4a1ed71940 100644
--- a/ansible/roles/neutron/tasks/bootstrap_service.yml
+++ b/ansible/roles/neutron/tasks/bootstrap_service.yml
@@ -1,5 +1,7 @@
 ---
 - name: Running Neutron bootstrap container
+  vars:
+    neutron_server: "{{ neutron_services['neutron-server'] }}"
   kolla_docker:
     action: "start_container"
     common_options: "{{ docker_common_options }}"
@@ -7,19 +9,18 @@
     environment:
       KOLLA_BOOTSTRAP:
       KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}"
-    image: "{{ neutron_server_image_full }}"
+    image: "{{ neutron_server.image }}"
     labels:
       BOOTSTRAP:
     name: "bootstrap_neutron"
     restart_policy: "never"
-    volumes:
-      - "{{ node_config_directory }}/neutron-server/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "kolla_logs:/var/log/kolla/"
+    volumes: "{{ neutron_server.volumes }}"
   run_once: True
-  delegate_to: "{{ groups['neutron-server'][0] }}"
+  delegate_to: "{{ groups[neutron_server.group][0] }}"
 
 - name: Running Neutron lbaas bootstrap container
+  vars:
+    neutron_lbaas_agent: "{{ neutron_services['neutron-lbaas-agent'] }}"
   kolla_docker:
     action: "start_container"
     common_options: "{{ docker_common_options }}"
@@ -27,22 +28,21 @@
     environment:
       KOLLA_BOOTSTRAP:
       KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}"
-    image: "{{ neutron_lbaas_agent_image_full }}"
+    image: "{{ neutron_lbaas_agent.image }}"
     labels:
       BOOTSTRAP:
     name: "bootstrap_neutron_lbaas_agent"
     restart_policy: "never"
-    volumes:
-      - "{{ node_config_directory }}/neutron-lbaas-agent/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "kolla_logs:/var/log/kolla/"
+    volumes: "{{ neutron_lbaas_agent.volumes }}"
   when:
-    - enable_neutron_lbaas | bool
-    - inventory_hostname in groups['neutron-lbaas-agent']
+    - neutron_lbaas_agent.enabled | bool
+    - neutron_lbaas_agent.host_in_groups | bool
   run_once: True
-  delegate_to: "{{ groups['neutron-lbaas-agent'][0] }}"
+  delegate_to: "{{ groups[neutron_lbaas_agent.group][0] }}"
 
 - name: Running Neutron vpnaas bootstrap container
+  vars:
+    neutron_vpnaas_agent: "{{ neutron_services['neutron-vpnaas-agent'] }}"
   kolla_docker:
     action: "start_container"
     common_options: "{{ docker_common_options }}"
@@ -50,17 +50,14 @@
     environment:
       KOLLA_BOOTSTRAP:
       KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}"
-    image: "{{ neutron_vpnaas_agent_image_full }}"
+    image: "{{ neutron_vpnaas_agent.image }}"
     labels:
       BOOTSTRAP:
     name: "bootstrap_neutron_vpnaas_agent"
     restart_policy: "never"
-    volumes:
-      - "{{ node_config_directory }}/neutron-vpnaas-agent/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "kolla_logs:/var/log/kolla/"
+    volumes: "{{ neutron_vpnaas_agent.image }}"
   when:
-    - enable_neutron_vpnaas | bool
-    - inventory_hostname in groups['neutron-vpnaas-agent']
+    - neutron_vpnaas_agent.enabled | bool
+    - neutron_vpnaas_agent.host_in_groups | bool
   run_once: True
-  delegate_to: "{{ groups['neutron-vpnaas-agent'][0] }}"
+  delegate_to: "{{ groups[neutron_vpnaas_agent.group][0] }}"
diff --git a/ansible/roles/neutron/tasks/config-neutron-fake.yml b/ansible/roles/neutron/tasks/config-neutron-fake.yml
index 7051911f00..396f7db058 100644
--- a/ansible/roles/neutron/tasks/config-neutron-fake.yml
+++ b/ansible/roles/neutron/tasks/config-neutron-fake.yml
@@ -11,6 +11,7 @@
   template:
     src: "neutron-openvswitch-agent.json.j2"
     dest: "{{ node_config_directory }}/neutron-openvswitch-agent-fake-{{ item }}/config.json"
+  register: fake_config_json
   with_sequence: start=1 end={{ num_nova_fake_per_node }}
   when:
     - inventory_hostname in groups['compute']
@@ -29,6 +30,7 @@
       - "{{ node_config_directory }}/config/neutron/{{ item }}.conf"
       - "{{ node_config_directory }}/config/neutron/{{ inventory_hostname }}/neutron.conf"
     dest: "{{ node_config_directory }}/neutron-openvswitch-agent-fake-{{ item }}/neutron.conf"
+  register: fake_neutron_conf
   with_sequence: start=1 end={{ num_nova_fake_per_node }}
   when:
     - inventory_hostname in groups['compute']
@@ -43,7 +45,48 @@
       - "{{ node_config_directory }}/config/neutron/ml2_conf.ini"
       - "{{ node_config_directory }}/config/neutron/{{ inventory_hostname }}/neutron.conf"
     dest: "{{ node_config_directory }}/neutron-openvswitch-agent-fake-{{ item }}/ml2_conf.ini"
+  register: fake_neutron_ml2_conf_ini
   with_sequence: start=1 end={{ num_nova_fake_per_node }}
   when:
     - inventory_hostname in groups['compute']
     - neutron_plugin_agent == "openvswitch"
+
+- name: Checking neutron-openvswitch-agent container for nova fake node
+  vars:
+    neutron_openvswitch_agent: "{{ neutron_services['neutron-openvswitch-agent'] }}"
+  kolla_docker:
+    action: "compare_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ neutron_openvswitch_agent.container_name }}"
+    image: "{{ neutron_openvswitch_agent.image }}"
+    privileged: "{{ neutron_openvswitch_agent.privileged | default(False) }}"
+    volumes: "{{ neutron_openvswitch_agent.volumes }}"
+  register: check_fake_neutron_openvswitch_agent
+  when:
+    - action != "config"
+    - enable_nova_fake | bool
+    - neutron_plugin_agent == "openvswitch"
+    - inventory_hostname in groups["compute"]
+  with_sequence: "start=1 end={{ num_nova_fake_per_node }}"
+  notify:
+    - Restart fake neutron-openvswitch-agent container
+
+- name: Checking neutron-sfc-agent container for nova fake node
+  vars:
+    neutron_sfc_agent: "{{ neutron_services['neutron-sfc-agent'] }}"
+  kolla_docker:
+    action: "compare_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ neutron_sfc_agent.container_name }}"
+    image: "{{ neutron_sfc_agent.image }}"
+    privileged: "{{ neutron_sfc_agent.privileged | default(False) }}"
+    volumes: "{{ neutron_sfc_agent.volumes }}"
+  register: check_fake_neutron_sfc_agent
+  when:
+    - action != "config"
+    - enable_nova_fake | bool
+    - neutron_plugin_agent == "sfc"
+    - inventory_hostname in groups["compute"]
+  with_sequence: "start=1 end={{ num_nova_fake_per_node }}"
+  notify:
+    - Restart fake neutron-sfc-agent container
diff --git a/ansible/roles/neutron/tasks/config.yml b/ansible/roles/neutron/tasks/config.yml
index e46049fb93..be6a139bf7 100644
--- a/ansible/roles/neutron/tasks/config.yml
+++ b/ansible/roles/neutron/tasks/config.yml
@@ -1,5 +1,8 @@
 ---
 - name: Setting sysctl values
+  vars:
+    neutron_l3_agent: "{{ neutron_services['neutron-l3-agent'] }}"
+    neutron_vpnaas_agent: "{{ neutron_services['neutron-vpnaas-agent'] }}"
   sysctl: name={{ item.name }} value={{ item.value }} sysctl_set=yes
   with_items:
     - { name: "net.ipv4.ip_forward", value: 1}
@@ -7,202 +10,289 @@
     - { name: "net.ipv4.conf.default.rp_filter", value: 0}
   when:
     - set_sysctl | bool
-    - inventory_hostname in groups['neutron-l3-agent']
-      or inventory_hostname in groups['neutron-vpnaas-agent']
+    - (neutron_l3_agent.enabled | bool and neutron_l3_agent.host_in_groups | bool)
+      or (neutron_vpnaas_agent.enabled | bool and  neutron_vpnaas_agent.host_in_groups | bool)
 
 - name: Ensuring config directories exist
   file:
-    path: "{{ node_config_directory }}/{{ item }}"
+    path: "{{ node_config_directory }}/{{ item.key }}"
     state: "directory"
     recurse: yes
-  with_items:
-    - "neutron-dhcp-agent"
-    - "neutron-l3-agent"
-    - "neutron-linuxbridge-agent"
-    - "neutron-metadata-agent"
-    - "neutron-openvswitch-agent"
-    - "neutron-server"
-    - "openvswitch-db-server"
-    - "openvswitch-vswitchd"
-    - "neutron-lbaas-agent"
-    - "neutron-vpnaas-agent"
+  when:
+    - item.value.enabled | bool
+    - item.value.host_in_groups | bool
+  with_dict: "{{ neutron_services }}"
 
 - name: Copying over config.json files for services
   template:
-    src: "{{ item }}.json.j2"
-    dest: "{{ node_config_directory }}/{{ item }}/config.json"
-  with_items:
-    - "neutron-dhcp-agent"
-    - "neutron-l3-agent"
-    - "neutron-linuxbridge-agent"
-    - "neutron-metadata-agent"
-    - "neutron-openvswitch-agent"
-    - "neutron-server"
-    - "openvswitch-db-server"
-    - "openvswitch-vswitchd"
-    - "neutron-lbaas-agent"
-    - "neutron-vpnaas-agent"
+    src: "{{ item.key }}.json.j2"
+    dest: "{{ node_config_directory }}/{{ item.key }}/config.json"
+  register: neutron_config_jsons
+  when:
+    - item.value.enabled | bool
+    - item.value.host_in_groups | bool
+  with_dict: "{{ neutron_services }}"
+  notify:
+    - "Restart {{ item.key }} container"
 
 - name: Copying over neutron.conf
+  vars:
+    service_name: "{{ item.key }}"
+    services_need_neutron_conf:
+      - "neutron-dhcp-agent"
+      - "neutron-l3-agent"
+      - "neutron-linuxbridge-agent"
+      - "neutron-metadata-agent"
+      - "neutron-openvswitch-agent"
+      - "neutron-server"
+      - "neutron-lbaas-agent"
+      - "neutron-vpnaas-agent"
   merge_configs:
-    vars:
-      service_name: "{{ item }}"
     sources:
       - "{{ role_path }}/templates/neutron.conf.j2"
       - "{{ node_custom_config }}/global.conf"
       - "{{ node_custom_config }}/database.conf"
       - "{{ node_custom_config }}/messaging.conf"
       - "{{ node_custom_config }}/neutron.conf"
-      - "{{ node_custom_config }}/neutron/{{ item }}.conf"
+      - "{{ node_custom_config }}/neutron/{{ item.key }}.conf"
       - "{{ node_custom_config }}/neutron/{{ inventory_hostname }}/neutron.conf"
-    dest: "{{ node_config_directory }}/{{ item }}/neutron.conf"
-  with_items:
-    - "neutron-dhcp-agent"
-    - "neutron-l3-agent"
-    - "neutron-linuxbridge-agent"
-    - "neutron-metadata-agent"
-    - "neutron-openvswitch-agent"
-    - "neutron-server"
-    - "neutron-lbaas-agent"
-    - "neutron-vpnaas-agent"
+    dest: "{{ node_config_directory }}/{{ item.key }}/neutron.conf"
+  register: neutron_confs
+  when:
+    - item.value.enabled | bool
+    - item.value.host_in_groups | bool
+    - item.key in services_need_neutron_conf
+  with_dict: "{{ neutron_services }}"
+  notify:
+    - "Restart {{ item.key }} container"
 
 - name: Copying over neutron_lbaas.conf
+  vars:
+    service_name: "{{ item.key }}"
+    services_need_neutron_lbaas_conf:
+      - "neutron-server"
+      - "neutron-lbaas-agent"
   merge_configs:
-    vars:
-      service_name: "{{ item }}"
     sources:
       - "{{ role_path }}/templates/neutron_lbaas.conf.j2"
       - "{{ node_custom_config }}/neutron/neutron_lbaas.conf"
       - "{{ node_custom_config }}/neutron/{{ inventory_hostname }}/neutron_lbaas.conf"
-    dest: "{{ node_config_directory }}/{{ item }}/neutron_lbaas.conf"
-  with_items:
-    - "neutron-server"
-    - "neutron-lbaas-agent"
+    dest: "{{ node_config_directory }}/{{ item.key }}/neutron_lbaas.conf"
+  register: neutron_lbaas_confs
+  when:
+    - item.value.enabled | bool
+    - item.value.host_in_groups | bool
+    - item.key in services_need_neutron_lbaas_conf
+  with_dict: "{{ neutron_services }}"
+  notify:
+    - "Restart {{ item.key }} container"
 
 - name: Copying over neutron_vpnaas.conf
+  vars:
+    service_name: "neutron-server"
+    neutron_server: "{{ neutron_services[service_name] }}"
   merge_configs:
-    vars:
-      service_name: "{{ item }}"
     sources:
       - "{{ role_path }}/templates/neutron_vpnaas.conf.j2"
       - "{{ node_custom_config }}/neutron/neutron_vpnaas.conf"
       - "{{ node_custom_config }}/neutron/{{ inventory_hostname }}/neutron_vpnaas.conf"
-    dest: "{{ node_config_directory }}/{{ item }}/neutron_vpnaas.conf"
-  with_items:
-    - "neutron-server"
+    dest: "{{ node_config_directory }}/{{ service_name }}/neutron_vpnaas.conf"
+  register: neutron_vpnaas_conf
+  when:
+    - neutron_server.enabled | bool
+    - neutron_server.host_in_groups | bool
+  notify:
+    - "Restart {{ service_name }} container"
 
 - name: Copying over ml2_conf.ini
+  vars:
+    service_name: "{{ item.key }}"
+    services_need_ml2_conf_ini:
+      - "neutron-dhcp-agent"
+      - "neutron-l3-agent"
+      - "neutron-linuxbridge-agent"
+      - "neutron-lbaas-agent"
+      - "neutron-metadata-agent"
+      - "neutron-openvswitch-agent"
+      - "neutron-server"
+      - "neutron-vpnaas-agent"
   merge_configs:
-    vars:
-      service_name: "{{ item }}"
     sources:
       - "{{ role_path }}/templates/ml2_conf.ini.j2"
       - "{{ node_custom_config }}/neutron/ml2_conf.ini"
       - "{{ node_custom_config }}/neutron/{{ inventory_hostname }}/ml2_conf.ini"
-    dest: "{{ node_config_directory }}/{{ item }}/ml2_conf.ini"
-  with_items:
-    - "neutron-dhcp-agent"
-    - "neutron-l3-agent"
-    - "neutron-linuxbridge-agent"
-    - "neutron-lbaas-agent"
-    - "neutron-metadata-agent"
-    - "neutron-openvswitch-agent"
-    - "neutron-server"
-    - "neutron-vpnaas-agent"
+    dest: "{{ node_config_directory }}/{{ service_name }}/ml2_conf.ini"
+  register: neutron_ml2_confs
+  when:
+    - item.key in services_need_ml2_conf_ini
+    - item.value.enabled | bool
+    - item.value.host_in_groups | bool
+  with_dict: "{{ neutron_services }}"
+  notify:
+    - "Restart {{ item.key }} container"
 
 - name: Copying over dhcp_agent.ini
+  vars:
+    service_name: "neutron-dhcp-agent"
+    neutron_dhcp_agent: "{{ neutron_services[service_name] }}"
   merge_configs:
-    vars:
-      service_name: "{{ item }}"
     sources:
       - "{{ role_path }}/templates/dhcp_agent.ini.j2"
       - "{{ node_custom_config }}/neutron/dhcp_agent.ini"
       - "{{ node_custom_config }}/neutron/{{ inventory_hostname }}/dhcp_agent.ini"
-    dest: "{{ node_config_directory }}/{{ item }}/dhcp_agent.ini"
-  with_items:
-    - "neutron-dhcp-agent"
+    dest: "{{ node_config_directory }}/{{ service_name }}/dhcp_agent.ini"
+  register: dhcp_agent_ini
+  when:
+    - neutron_dhcp_agent.enabled | bool
+    - neutron_dhcp_agent.host_in_groups | bool
+  notify:
+    - "Restart {{ service_name }} container"
 
 - name: Copying over dnsmasq.conf
+  vars:
+    service_name: "neutron-dhcp-agent"
+    neutron_dhcp_agent: "{{ neutron_services[service_name] }}"
   template:
     src: "dnsmasq.conf.j2"
-    dest: "{{ node_config_directory }}/{{ item }}/dnsmasq.conf"
-  with_items:
-    - "neutron-dhcp-agent"
+    dest: "{{ node_config_directory }}/{{ service_name }}/dnsmasq.conf"
+  register: dnsmasq_conf
+  when:
+    - neutron_dhcp_agent.enabled | bool
+    - neutron_dhcp_agent.host_in_groups | bool
+  notify:
+    - "Restart {{ service_name }} container"
 
 - name: Copying over l3_agent.ini
+  vars:
+    service_name: "{{ item.key }}"
+    services_need_l3_agent_ini:
+      - "neutron-l3-agent"
+      - "neutron-vpnaas-agent"
   merge_configs:
-    vars:
-      service_name: "{{ item }}"
     sources:
       - "{{ role_path }}/templates/l3_agent.ini.j2"
       - "{{ node_custom_config }}/neutron/l3_agent.ini"
       - "{{ node_custom_config }}/neutron/{{ inventory_hostname }}/l3_agent.ini"
-    dest: "{{ node_config_directory }}/{{ item }}/l3_agent.ini"
-  with_items:
-    - "neutron-l3-agent"
-    - "neutron-vpnaas-agent"
+    dest: "{{ node_config_directory }}/{{ service_name }}/l3_agent.ini"
+  register: neutron_l3_agent_inis
+  when:
+    - item.key in services_need_l3_agent_ini
+    - item.value.enabled | bool
+    - item.value.host_in_groups | bool
+  with_dict: "{{ neutron_services }}"
+  notify:
+    - "Restart {{ item.key }} container"
 
 - name: Copying over fwaas_driver.ini
+  vars:
+    service_name: "{{ item.key }}"
+    services_need_fwaas_driver_ini:
+      - "neutron-l3-agent"
+      - "neutron-vpnaas-agent"
   merge_configs:
-    vars:
-      service_name: "{{ item }}"
     sources:
       - "{{ role_path }}/templates/fwaas_driver.ini.j2"
       - "{{ node_custom_config }}/neutron/fwaas_driver.ini"
-    dest: "{{ node_config_directory }}/{{ item }}/fwaas_driver.ini"
-  with_items:
-    - "neutron-l3-agent"
-    - "neutron-vpnaas-agent"
+    dest: "{{ node_config_directory }}/{{ service_name }}/fwaas_driver.ini"
+  register: neutron_fwaas_driver_inis
+  when:
+    - item.key in services_need_fwaas_driver_ini
+    - item.value.enabled | bool
+    - item.value.host_in_groups | bool
+  with_dict: "{{ neutron_services }}"
+  notify:
+    - "Restart {{ item.key }} container"
 
 - name: Copying over metadata_agent.ini
+  vars:
+    service_name: "neutron-metadata-agent"
+    neutron_metadata_agent: "{{ neutron_services[service_name] }}"
   merge_configs:
-    vars:
-      service_name: "{{ item }}"
     sources:
       - "{{ role_path }}/templates/metadata_agent.ini.j2"
       - "{{ node_custom_config }}/neutron/metadata_agent.ini"
-    dest: "{{ node_config_directory }}/{{ item }}/metadata_agent.ini"
-  with_items:
-    - "neutron-metadata-agent"
+    dest: "{{ node_config_directory }}/{{ service_name }}/metadata_agent.ini"
+  register: neutron_metadata_agent_ini
+  when:
+    - neutron_metadata_agent.enabled | bool
+    - neutron_metadata_agent.host_in_groups | bool
+  notify:
+    - "Restart {{ service_name }} container"
 
 - name: Copying over lbaas_agent.ini
+  vars:
+    service_name: "neutron-lbaas-agent"
+    neutron_lbaas_agent: "{{ neutron_services['neutron-lbaas-agent'] }}"
   merge_configs:
-    vars:
-      service_name: "{{ item }}"
     sources:
       - "{{ role_path }}/templates/lbaas_agent.ini.j2"
       - "{{ node_custom_config }}/neutron/lbaas_agent.ini"
-    dest: "{{ node_config_directory }}/{{ item }}/lbaas_agent.ini"
-  with_items:
-    - "neutron-lbaas-agent"
+    dest: "{{ node_config_directory }}/{{ service_name }}/lbaas_agent.ini"
+  register: neutron_lbaas_agent_ini
+  when:
+    - neutron_lbaas_agent.enabled | bool
+    - neutron_lbaas_agent.host_in_groups | bool
+  notify:
+    - "Restart {{ service_name }} container"
 
 - name: Copying over vpnaas_agent.ini
+  vars:
+    service_name: "neutron-vpnaas-agent"
+    neutron_vpnaas_agent: "{{ neutron_services['neutron-vpnaas-agent'] }}"
   merge_configs:
-    vars:
-      service_name: "{{ item }}"
     sources:
       - "{{ role_path }}/templates/vpnaas_agent.ini.j2"
-      - "{{ node_custom_config }}/neutron/vpnaas_agent.ini"
-    dest: "{{ node_config_directory }}/{{ item }}/vpnaas_agent.ini"
-  with_items:
-    - "neutron-vpnaas-agent"
+      - "{{ node_custom_config }}/config/neutron/vpnaas_agent.ini"
+    dest: "{{ node_config_directory }}/{{ service_name }}/vpnaas_agent.ini"
+  register: neutron_vpnaas_agent_ini
+  when:
+    - neutron_vpnaas_agent.enabled | bool
+    - neutron_vpnaas_agent.host_in_groups | bool
+  notify:
+    - "Restart {{ service_name }} container"
 
 - name: Check if policies shall be overwritten
   local_action: stat path="{{ node_custom_config }}/neutron/policy.json"
   register: neutron_policy
 
 - name: Copying over existing policy.json
+  vars:
+    service_name: "{{ item.key }}"
+    services_need_policy_json:
+      - "neutron-dhcp-agent"
+      - "neutron-l3-agent"
+      - "neutron-linuxbridge-agent"
+      - "neutron-metadata-agent"
+      - "neutron-openvswitch-agent"
+      - "neutron-server"
+      - "neutron-lbaas-agent"
+      - "neutron-vpnaas-agent"
   template:
     src: "{{ node_custom_config }}/neutron/policy.json"
-    dest: "{{ node_config_directory }}/{{ item }}/policy.json"
-  with_items:
-    - "neutron-dhcp-agent"
-    - "neutron-l3-agent"
-    - "neutron-linuxbridge-agent"
-    - "neutron-metadata-agent"
-    - "neutron-openvswitch-agent"
-    - "neutron-server"
-    - "neutron-lbaas-agent"
-    - "neutron-vpnaas-agent"
+    dest: "{{ node_config_directory }}/{{ service_name }}/policy.json"
+  register: policy_jsons
   when:
-    neutron_policy.stat.exists
+    - neutron_policy.stat.exists | bool
+    - item.value.enabled | bool
+    - item.value.host_in_groups | bool
+  with_dict: "{{ neutron_services }}"
+  notify:
+    - "Restart {{ item.key }} container"
+
+# TODO check the environment change
+- name: Check neutron containers
+  kolla_docker:
+    action: "compare_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ item.value.container_name }}"
+    image: "{{ item.value.image }}"
+    privileged: "{{ item.value.privileged | default(False) }}"
+    volumes: "{{ item.value.volumes }}"
+  register: check_neutron_containers
+  when:
+    - action != "config"
+    - item.value.enabled | bool
+    - item.value.host_in_groups | bool
+  with_dict: "{{ neutron_services }}"
+  notify:
+    - "Restart {{ item.key }} container"
diff --git a/ansible/roles/neutron/tasks/deploy.yml b/ansible/roles/neutron/tasks/deploy.yml
index 7274697135..afd6f19097 100644
--- a/ansible/roles/neutron/tasks/deploy.yml
+++ b/ansible/roles/neutron/tasks/deploy.yml
@@ -6,14 +6,6 @@
   when: inventory_hostname in groups['neutron-server']
 
 - include: config.yml
-  when: inventory_hostname in groups['compute']
-        or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-        or inventory_hostname in groups['neutron-dhcp-agent']
-        or inventory_hostname in groups['neutron-l3-agent']
-        or inventory_hostname in groups['neutron-metadata-agent']
-        or inventory_hostname in groups['neutron-server']
-        or inventory_hostname in groups['neutron-lbaas-agent']
-        or inventory_hostname in groups['neutron-vpnaas-agent']
 
 - include: config-neutron-fake.yml
   when:
@@ -23,12 +15,5 @@
 - include: bootstrap.yml
   when: inventory_hostname in groups['neutron-server']
 
-- include: start.yml
-  when: inventory_hostname in groups['compute']
-        or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-        or inventory_hostname in groups['neutron-dhcp-agent']
-        or inventory_hostname in groups['neutron-l3-agent']
-        or inventory_hostname in groups['neutron-metadata-agent']
-        or inventory_hostname in groups['neutron-server']
-        or inventory_hostname in groups['neutron-lbaas-agent']
-        or inventory_hostname in groups['neutron-vpnaas-agent']
+- name: Flush Handlers
+  meta: flush_handlers
diff --git a/ansible/roles/neutron/tasks/pull.yml b/ansible/roles/neutron/tasks/pull.yml
index 620ff60415..d7f5a3678a 100644
--- a/ansible/roles/neutron/tasks/pull.yml
+++ b/ansible/roles/neutron/tasks/pull.yml
@@ -1,93 +1,10 @@
 ---
-- name: Pulling neutron-dhcp-agent image
+- name: Pulling neutron images
   kolla_docker:
     action: "pull_image"
     common_options: "{{ docker_common_options }}"
-    image: "{{ neutron_dhcp_agent_image_full }}"
-  when: inventory_hostname in groups['neutron-dhcp-agent']
-
-- name: Pulling neutron-l3-agent image
-  kolla_docker:
-    action: "pull_image"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ neutron_l3_agent_image_full }}"
-  when: inventory_hostname in groups['neutron-l3-agent']
-
-- name: Pulling neutron-linuxbridge-agent image
-  kolla_docker:
-    action: "pull_image"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ neutron_linuxbridge_agent_image_full }}"
+    image: "{{ item.value.image }}"
   when:
-    - (inventory_hostname in groups['compute']
-       or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-       or inventory_hostname in groups['neutron-dhcp-agent']
-       or inventory_hostname in groups['neutron-l3-agent']
-       or inventory_hostname in groups['neutron-metadata-agent']
-       or inventory_hostname in groups['neutron-vpnaas-agent'])
-    - neutron_plugin_agent == "linuxbridge"
-
-- name: Pulling neutron-metadata-agent image
-  kolla_docker:
-    action: "pull_image"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ neutron_metadata_agent_image_full }}"
-  when: inventory_hostname in groups['neutron-metadata-agent']
-
-- name: Pulling neutron-openvswitch-agent image
-  kolla_docker:
-    action: "pull_image"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ neutron_openvswitch_agent_image_full }}"
-  when:
-    - (inventory_hostname in groups['compute']
-       or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-       or inventory_hostname in groups['neutron-dhcp-agent']
-       or inventory_hostname in groups['neutron-l3-agent']
-       or inventory_hostname in groups['neutron-metadata-agent']
-       or inventory_hostname in groups['neutron-vpnaas-agent'])
-    - neutron_plugin_agent == "openvswitch"
-
-- name: Pulling neutron-vpnaas-agent image
-  kolla_docker:
-    action: "pull_image"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ neutron_vpnaas_agent_image_full }}"
-  when:
-    - enable_neutron_vpnaas | bool
-    - inventory_hostname in groups['neutron-vpnaas-agent']
-
-- name: Pulling neutron-server image
-  kolla_docker:
-    action: "pull_image"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ neutron_server_image_full }}"
-  when: inventory_hostname in groups['neutron-server']
-
-- name: Pulling openvswitch-db image
-  kolla_docker:
-    action: "pull_image"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ openvswitch_db_image_full }}"
-  when:
-    - (inventory_hostname in groups['compute']
-       or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-       or inventory_hostname in groups['neutron-dhcp-agent']
-       or inventory_hostname in groups['neutron-l3-agent']
-       or inventory_hostname in groups['neutron-metadata-agent']
-       or inventory_hostname in groups['neutron-vpnaas-agent'])
-    - neutron_plugin_agent == "openvswitch"
-
-- name: Pulling openvswitch-vswitchd image
-  kolla_docker:
-    action: "pull_image"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ openvswitch_vswitchd_image_full }}"
-  when:
-    - (inventory_hostname in groups['compute']
-       or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-       or inventory_hostname in groups['neutron-dhcp-agent']
-       or inventory_hostname in groups['neutron-l3-agent']
-       or inventory_hostname in groups['neutron-metadata-agent']
-       or inventory_hostname in groups['neutron-vpnaas-agent'])
-    - neutron_plugin_agent == "openvswitch"
+    - item.value.enabled | bool
+    - item.value.host_in_groups | bool
+  with_dict: "{{ neutron_services }}"
diff --git a/ansible/roles/neutron/tasks/reconfigure.yml b/ansible/roles/neutron/tasks/reconfigure.yml
deleted file mode 100644
index ad8ef35aba..0000000000
--- a/ansible/roles/neutron/tasks/reconfigure.yml
+++ /dev/null
@@ -1,324 +0,0 @@
----
-- name: Ensuring the containers running neutron-server and neutron agents are up
-  kolla_docker:
-    name: "{{ item.name }}"
-    action: "get_container_state"
-  register: neutron_container_states
-  failed_when: neutron_container_states.Running == false
-  when:
-    - "{{ item.enabled|default(True) }}"
-    - inventory_hostname in groups[item.group]
-  with_items:
-    - { name: neutron_server, group: neutron-server }
-    - { name: neutron_dhcp_agent, group: neutron-dhcp-agent }
-    - { name: neutron_l3_agent, group: neutron-l3-agent }
-    - { name: neutron_l3_agent, group: compute, enabled: "{{ enable_neutron_dvr | bool }}" }
-    - { name: neutron_lbaas_agent, group: neutron-lbaas-agent, enabled: "{{ enable_neutron_lbaas | bool }}" }
-    - { name: neutron_metadata_agent, group: neutron-metadata-agent }    
-    - { name: neutron_metadata_agent, group: compute, enabled: "{{ enable_neutron_dvr | bool }}" }
-    - { name: neutron_vpnaas_agent, group: neutron-vpnaas-agent, enabled: "{{ enable_neutron_vpnaas | bool }}" }
-
-- name: Ensuring the neutron_openvswitch_agent container is up
-  kolla_docker:
-    name: neutron_openvswitch_agent
-    action: "get_container_state"
-  register: openvswitch_agent_container_states
-  failed_when: openvswitch_agent_container_states.Running == false
-  when:
-    - neutron_plugin_agent == "openvswitch"
-    - (
-        ( inventory_hostname in groups['compute']
-          or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-          or inventory_hostname in groups['neutron-dhcp-agent']
-          or inventory_hostname in groups['neutron-l3-agent']
-          or inventory_hostname in groups['neutron-lbaas-agent']
-          or inventory_hostname in groups['neutron-metadata-agent']
-          or inventory_hostname in groups['neutron-vpnaas-agent']
-          and not enable_nova_fake | bool
-        ) or
-        ( inventory_hostname in groups['neutron-dhcp-agent']
-          or inventory_hostname in groups['neutron-l3-agent']
-          or inventory_hostname in groups['neutron-lbaas-agent']
-          or inventory_hostname in groups['neutron-metadata-agent']
-          or inventory_hostname in groups['neutron-vpnaas-agent']
-          and enable_nova_fake | bool
-        )
-      )
-
-- name: Ensuring the neutron_linuxbridge_agent container is up
-  kolla_docker:
-    name: neutron_linuxbridge_agent
-    action: "get_container_state"
-  register: linuxbridge_agent_container_states
-  failed_when: linuxbridge_agent_container_states.Running == false
-  when:
-    - neutron_plugin_agent == "linuxbridge"
-    - (inventory_hostname in groups['compute']
-       or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-       or inventory_hostname in groups['neutron-dhcp-agent']
-       or inventory_hostname in groups['neutron-l3-agent']
-       or inventory_hostname in groups['neutron-lbaas-agent']
-       or inventory_hostname in groups['neutron-metadata-agent']
-       or inventory_hostname in groups['neutron-vpnaas-agent'])
-
-- include: config.yml
-
-- name: Check the configs in containers running neutron-server and neutron agents
-  command: docker exec {{ item.name }} /usr/local/bin/kolla_set_configs --check
-  changed_when: false
-  failed_when: false
-  register: neutron_check_results
-  when:
-    - "{{ item.enabled|default(True) }}"
-    - inventory_hostname in groups[item.group]
-  with_items:
-    - { name: neutron_server, group: neutron-server }
-    - { name: neutron_dhcp_agent, group: neutron-dhcp-agent }
-    - { name: neutron_l3_agent, group: neutron-l3-agent }
-    - { name: neutron_l3_agent, group: compute, enabled: "{{ enable_neutron_dvr | bool }}" }
-    - { name: neutron_lbaas_agent, group: neutron-lbaas-agent, enabled: "{{ enable_neutron_lbaas | bool }}" }
-    - { name: neutron_metadata_agent, group: neutron-metadata-agent }
-    - { name: neutron_metadata_agent, group: compute, enabled: "{{ enable_neutron_dvr | bool }}" }
-    - { name: neutron_vpnaas_agent, group: neutron-vpnaas-agent, enabled: "{{ enable_neutron_vpnaas | bool }}" }
-
-- name: Check the configs in the neutron_openvswitch_agent container
-  command: docker exec neutron_openvswitch_agent /usr/local/bin/kolla_set_configs --check
-  changed_when: false
-  failed_when: false
-  register: openvswitch_agent_check_results
-  when:
-    - neutron_plugin_agent == "openvswitch"
-    - (
-        ( inventory_hostname in groups['compute']
-          or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-          or inventory_hostname in groups['neutron-dhcp-agent']
-          or inventory_hostname in groups['neutron-l3-agent']
-          or inventory_hostname in groups['neutron-lbaas-agent']
-          or inventory_hostname in groups['neutron-metadata-agent']
-          or inventory_hostname in groups['neutron-vpnaas-agent']
-          and not enable_nova_fake | bool
-        ) or
-        ( inventory_hostname in groups['neutron-dhcp-agent']
-          or inventory_hostname in groups['neutron-l3-agent']
-          or inventory_hostname in groups['neutron-lbaas-agent']
-          or inventory_hostname in groups['neutron-metadata-agent']
-          or inventory_hostname in groups['neutron-vpnaas-agent']
-          and enable_nova_fake | bool
-        )
-      )
-
-- name: Check the configs in the neutron_linuxbridge_agent container
-  command: docker exec neutron_linuxbridge_agent /usr/local/bin/kolla_set_configs --check
-  changed_when: false
-  failed_when: false
-  register: linuxbridge_agent_check_results
-  when:
-    - neutron_plugin_agent == "linuxbridge"
-    - (inventory_hostname in groups['compute']
-       or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-       or inventory_hostname in groups['neutron-dhcp-agent']
-       or inventory_hostname in groups['neutron-l3-agent']
-       or inventory_hostname in groups['neutron-lbaas-agent']
-       or inventory_hostname in groups['neutron-metadata-agent']
-       or inventory_hostname in groups['neutron-vpnaas-agent'])
-
-# 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 containers running neutron-server and neutron agents
-  kolla_docker:
-    name: "{{ item.name }}"
-    action: "get_container_env"
-  register: neutron_container_envs
-  when:
-    - "{{ item.enabled|default(True) }}"
-    - inventory_hostname in groups[item.group]
-  with_items:
-    - { name: neutron_server, group: neutron-server }
-    - { name: neutron_dhcp_agent, group: neutron-dhcp-agent }
-    - { name: neutron_l3_agent, group: neutron-l3-agent }
-    - { name: neutron_l3_agent, group: compute, enabled: "{{ enable_neutron_dvr | bool }}" }
-    - { name: neutron_lbaas_agent, group: neutron-lbaas-agent, enabled: "{{ enable_neutron_lbaas | bool }}" }
-    - { name: neutron_metadata_agent, group: neutron-metadata-agent }
-    - { name: neutron_metadata_agent, group: compute, enabled: "{{ enable_neutron_dvr | bool }}" }
-    - { name: neutron_vpnaas_agent, group: neutron-vpnaas-agent, enabled: "{{ enable_neutron_vpnaas | bool }}" }
-
-- name: Container config strategy for the neutron_openvswitch_agent container
-  kolla_docker:
-    name: "neutron_openvswitch_agent"
-    action: "get_container_env"
-  register: openvswitch_agent_envs
-  when:
-    - neutron_plugin_agent == "openvswitch"
-    - (
-        ( not enable_nova_fake | bool
-          and inventory_hostname in groups['compute']
-          or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-          or inventory_hostname in groups['neutron-dhcp-agent']
-          or inventory_hostname in groups['neutron-l3-agent']
-          or inventory_hostname in groups['neutron-lbaas-agent']
-          or inventory_hostname in groups['neutron-metadata-agent']
-          or inventory_hostname in groups['neutron-vpnaas-agent']
-        ) or
-        ( enable_nova_fake | bool
-          and inventory_hostname in groups['neutron-dhcp-agent']
-          or inventory_hostname in groups['neutron-l3-agent']
-          or inventory_hostname in groups['neutron-lbaas-agent']
-          or inventory_hostname in groups['neutron-metadata-agent']
-          or inventory_hostname in groups['neutron-vpnaas-agent']
-        )
-      )
-
-- name: Container config strategy for the neutron_linuxbridge_agent container
-  kolla_docker:
-    name: "neutron_linuxbridge_agent"
-    action: "get_container_env"
-  register: linuxbridge_agent_envs
-  when:
-    - neutron_plugin_agent == "linuxbridge"
-    - (inventory_hostname in groups['compute']
-       or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-       or inventory_hostname in groups['neutron-dhcp-agent']
-       or inventory_hostname in groups['neutron-l3-agent']
-       or inventory_hostname in groups['neutron-lbaas-agent']
-       or inventory_hostname in groups['neutron-metadata-agent']
-       or inventory_hostname in groups['neutron-vpnaas-agent'])
-
-- name: Remove the containers running neutron-server and neutron agents
-  kolla_docker:
-    name: "{{ item[0]['name'] }}"
-    action: "remove_container"
-  register: neutron_remove_containers
-  when:
-    - "{{ item[0].enabled | default(True) }}"
-    - 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:
-    - [{ name: neutron_server, group: neutron-server },
-       { name: neutron_dhcp_agent, group: neutron-dhcp-agent },
-       { name: neutron_l3_agent, group: neutron-l3-agent },
-       { name: neutron_l3_agent, group: compute, enabled: "{{ enable_neutron_dvr | bool }}" },
-       { name: neutron_lbaas_agent, group: neutron-lbaas-agent, enabled: "{{ enable_neutron_lbaas | bool }}" },
-       { name: neutron_metadata_agent, group: neutron-metadata-agent },
-       { name: neutron_metadata_agent, group: compute, enabled: "{{ enable_neutron_dvr | bool }}" },
-       { name: neutron_vpnaas_agent, group: neutron-vpnaas-agent, enabled: "{{ enable_neutron_vpnaas | bool }}" }]
-    - "{{ neutron_container_envs.results }}"
-    - "{{ neutron_check_results.results }}"
-
-- name: Remove the neutron_openvswitch_agent container
-  kolla_docker:
-    name: "neutron_openvswitch_agent"
-    action: "remove_container"
-  register: openvswitch_agent_remove_containers
-  when:
-    - neutron_plugin_agent == "openvswitch"
-    - (
-        ( not enable_nova_fake | bool
-          and inventory_hostname in groups['compute']
-          or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-          or inventory_hostname in groups['neutron-dhcp-agent']
-          or inventory_hostname in groups['neutron-l3-agent']
-          or inventory_hostname in groups['neutron-lbaas-agent']
-          or inventory_hostname in groups['neutron-metadata-agent']
-          or inventory_hostname in groups['neutron-vpnaas-agent']
-        ) or
-        ( enable_nova_fake | bool
-          and inventory_hostname in groups['neutron-dhcp-agent']
-          or inventory_hostname in groups['neutron-l3-agent']
-          or inventory_hostname in groups['neutron-lbaas-agent']
-          or inventory_hostname in groups['neutron-metadata-agent']
-          or inventory_hostname in groups['neutron-vpnaas-agent']
-        )
-      )
-    - config_strategy == "COPY_ONCE" or openvswitch_agent_envs['KOLLA_CONFIG_STRATEGY'] == 'COPY_ONCE'
-    - openvswitch_agent_check_results['rc'] == 1
-
-- name: Remove the neutron_linuxbridge_agent container
-  kolla_docker:
-    name: "neutron_linuxbridge_agent"
-    action: "remove_container"
-  register: linuxbridge_agent_remove_containers
-  when:
-    - neutron_plugin_agent == "linuxbridge"
-    - (inventory_hostname in groups['compute']
-       or inventory_hostname in groups['manila-share']
-       or inventory_hostname in groups['neutron-dhcp-agent']
-       or inventory_hostname in groups['neutron-l3-agent']
-       or inventory_hostname in groups['neutron-lbaas-agent']
-       or inventory_hostname in groups['neutron-metadata-agent']
-       or inventory_hostname in groups['neutron-vpnaas-agent'])
-    - config_strategy == "COPY_ONCE" or linuxbridge_agent_envs['KOLLA_CONFIG_STRATEGY'] == 'COPY_ONCE'
-    - linuxbridge_agent_check_results['rc'] == 1
-
-- include: start.yml
-  when: neutron_remove_containers.changed
-        or openvswitch_agent_remove_containers.changed
-        or linuxbridge_agent_remove_containers.changed
-
-- name: Restart containers running neutron-server and neutron agents
-  kolla_docker:
-    name: "{{ item[0]['name'] }}"
-    action: "restart_container"
-  when:
-    - "{{ item[0].enabled|default(True) }}"
-    - 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: neutron_server, group: neutron-server },
-       { name: neutron_dhcp_agent, group: neutron-dhcp-agent },
-       { name: neutron_l3_agent, group: neutron-l3-agent },
-       { name: neutron_l3_agent, group: compute, enabled: "{{ enable_neutron_dvr | bool }}" },
-       { name: neutron_lbaas_agent, group: neutron-lbaas-agent, enabled: "{{ enable_neutron_lbaas | bool }}" },
-       { name: neutron_metadata_agent, group: neutron-metadata-agent },
-       { name: neutron_metadata_agent, group: compute, enabled: "{{ enable_neutron_dvr | bool }}" },
-       { name: neutron_vpnaas_agent, group: neutron-vpnaas-agent, enabled: "{{ enable_neutron_vpnaas | bool }}" }]
-    - "{{ neutron_container_envs.results }}"
-    - "{{ neutron_check_results.results }}"
-
-- name: Restart the neutron_openvswitch_agent container
-  kolla_docker:
-    name: "neutron_openvswitch_agent"
-    action: "restart_container"
-  when:
-    - config_strategy == 'COPY_ALWAYS'
-    - neutron_plugin_agent == "openvswitch"
-    - (
-        ( inventory_hostname in groups['compute']
-          or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-          or inventory_hostname in groups['neutron-dhcp-agent']
-          or inventory_hostname in groups['neutron-l3-agent']
-          or inventory_hostname in groups['neutron-lbaas-agent']
-          or inventory_hostname in groups['neutron-metadata-agent']
-          or inventory_hostname in groups['neutron-vpnaas-agent']
-          and not enable_nova_fake | bool
-        ) or
-        ( inventory_hostname in groups['neutron-dhcp-agent']
-          or inventory_hostname in groups['neutron-l3-agent']
-          or inventory_hostname in groups['neutron-lbaas-agent']
-          or inventory_hostname in groups['neutron-metadata-agent']
-          or inventory_hostname in groups['neutron-vpnaas-agent']
-          and enable_nova_fake | bool
-        )
-      )
-    - openvswitch_agent_envs['KOLLA_CONFIG_STRATEGY'] != 'COPY_ONCE'
-    - openvswitch_agent_check_results['rc'] == 1
-
-- name: Restart the neutron_linuxbridge_agent container
-  kolla_docker:
-    name: "neutron_linuxbridge_agent"
-    action: "restart_container"
-  when:
-    - config_strategy == 'COPY_ALWAYS'
-    - neutron_plugin_agent == "linuxbridge"
-    - (inventory_hostname in groups['compute']
-       or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-       or inventory_hostname in groups['neutron-dhcp-agent']
-       or inventory_hostname in groups['neutron-l3-agent']
-       or inventory_hostname in groups['neutron-lbaas-agent']
-       or inventory_hostname in groups['neutron-metadata-agent']
-       or inventory_hostname in groups['neutron-vpnaas-agent'])
-    - linuxbridge_agent_envs['KOLLA_CONFIG_STRATEGY'] != 'COPY_ONCE'
-    - linuxbridge_agent_check_results['rc'] == 1
diff --git a/ansible/roles/neutron/tasks/reconfigure.yml b/ansible/roles/neutron/tasks/reconfigure.yml
new file mode 120000
index 0000000000..0412f92200
--- /dev/null
+++ b/ansible/roles/neutron/tasks/reconfigure.yml
@@ -0,0 +1 @@
+deploy.yml
\ No newline at end of file
diff --git a/ansible/roles/neutron/tasks/start.yml b/ansible/roles/neutron/tasks/start.yml
deleted file mode 100644
index 9c5009f857..0000000000
--- a/ansible/roles/neutron/tasks/start.yml
+++ /dev/null
@@ -1,303 +0,0 @@
----
-- name: Starting openvswitch-db container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ openvswitch_db_image_full }}"
-    name: "openvswitch_db"
-    volumes:
-      - "{{ node_config_directory }}/openvswitch-db-server/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "/run:/run:shared"
-      - "kolla_logs:/var/log/kolla/"
-      - "openvswitch_db:/var/lib/openvswitch/"
-  when:
-    - (inventory_hostname in groups['compute']
-       or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-       or inventory_hostname in groups['neutron-dhcp-agent']
-       or inventory_hostname in groups['neutron-l3-agent']
-       or inventory_hostname in groups['neutron-metadata-agent']
-       or inventory_hostname in groups['neutron-vpnaas-agent'])
-    - neutron_plugin_agent == "openvswitch"
-
-- name: Waiting the openvswitch_db service to be ready
-  command: docker exec openvswitch_db ovs-vsctl --no-wait show
-  register: check_result
-  until: check_result | success
-  changed_when: False
-  retries: 30
-  delay: 2
-  when:
-    - (inventory_hostname in groups['compute']
-       or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-       or inventory_hostname in groups['neutron-dhcp-agent']
-       or inventory_hostname in groups['neutron-l3-agent']
-       or inventory_hostname in groups['neutron-metadata-agent']
-       or inventory_hostname in groups['neutron-vpnaas-agent'])
-    - neutron_plugin_agent == "openvswitch"
-
-- name: Ensuring OVS bridge is properly setup
-  command: docker exec openvswitch_db /usr/local/bin/kolla_ensure_openvswitch_configured {{ item.0 }} {{ item.1 }}
-  register: status
-  changed_when: status.stdout.find('changed') != -1
-  when:
-    - (inventory_hostname in groups['compute']
-       or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-       or inventory_hostname in groups['neutron-dhcp-agent']
-       or inventory_hostname in groups['neutron-l3-agent']
-       or inventory_hostname in groups['neutron-metadata-agent']
-       or inventory_hostname in groups['neutron-vpnaas-agent'])
-    - neutron_plugin_agent == "openvswitch"
-  with_together:
-    - "{{ neutron_bridge_name.split(',') }}"
-    - "{{ neutron_external_interface.split(',') }}"
-
-- name: Starting openvswitch-vswitchd container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ openvswitch_vswitchd_image_full }}"
-    name: "openvswitch_vswitchd"
-    privileged: True
-    volumes:
-      - "{{ node_config_directory }}/openvswitch-vswitchd/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "/lib/modules:/lib/modules:ro"
-      - "/run:/run:shared"
-      - "kolla_logs:/var/log/kolla/"
-  when:
-    - (inventory_hostname in groups['compute']
-       or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-       or inventory_hostname in groups['neutron-dhcp-agent']
-       or inventory_hostname in groups['neutron-l3-agent']
-       or inventory_hostname in groups['neutron-metadata-agent']
-       or inventory_hostname in groups['neutron-vpnaas-agent'])
-    - neutron_plugin_agent == "openvswitch"
-
-- name: Starting neutron-server container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ neutron_server_image_full }}"
-    name: "neutron_server"
-    volumes:
-      - "{{ node_config_directory }}/neutron-server/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "kolla_logs:/var/log/kolla/"
-  when: inventory_hostname in groups['neutron-server']
-
-- name: Starting neutron-openvswitch-agent container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ neutron_openvswitch_agent_image_full }}"
-    name: "neutron_openvswitch_agent"
-    privileged: True
-    volumes:
-      - "{{ node_config_directory }}/neutron-openvswitch-agent/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "/lib/modules:/lib/modules:ro"
-      - "/run:/run:shared"
-      - "kolla_logs:/var/log/kolla/"
-  when:
-    - (
-        ( inventory_hostname in groups['compute']
-          or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-          or inventory_hostname in groups['neutron-dhcp-agent']
-          or inventory_hostname in groups['neutron-l3-agent']
-          or inventory_hostname in groups['neutron-metadata-agent']
-          or inventory_hostname in groups['neutron-vpnaas-agent']
-          and not enable_nova_fake | bool
-        ) or
-        ( inventory_hostname in groups['neutron-dhcp-agent']
-          or inventory_hostname in groups['neutron-l3-agent']
-          or inventory_hostname in groups['neutron-metadata-agent']
-          or inventory_hostname in groups['neutron-vpnaas-agent']
-          and enable_nova_fake | bool
-        )
-      )
-    - neutron_plugin_agent == "openvswitch"
-
-- name: Starting neutron-sfc-agent container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ neutron_sfc_agent_image_full }}"
-    name: "neutron_sfc_agent"
-    privileged: True
-    volumes:
-      - "{{ node_config_directory }}/neutron-sfc-agent/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "/lib/modules:/lib/modules:ro"
-      - "/run:/run:shared"
-      - "kolla_logs:/var/log/kolla/"
-  when:
-    - (
-        ( inventory_hostname in groups['compute']
-          or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-          or inventory_hostname in groups['neutron-dhcp-agent']
-          or inventory_hostname in groups['neutron-l3-agent']
-          or inventory_hostname in groups['neutron-metadata-agent']
-          and not enable_nova_fake | bool
-        ) or
-        ( inventory_hostname in groups['neutron-dhcp-agent']
-          or inventory_hostname in groups['neutron-l3-agent']
-          or inventory_hostname in groups['neutron-metadata-agent']
-          and enable_nova_fake | bool
-        )
-      )
-    - neutron_plugin_agent == "sfc"
-
-- name: Starting neutron-openvswitch-agent container for fake nova compute
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ neutron_openvswitch_agent_image_full }}"
-    name: "neutron_openvswitch_agent_fake_{{ item }}"
-    privileged: True
-    volumes:
-      - "{{ node_config_directory }}/neutron-openvswitch-agent-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:
-    - inventory_hostname in groups['compute']
-    - neutron_plugin_agent == "openvswitch"
-    - enable_nova_fake | bool
-
-- name: Starting neutron-sfc-agent container for fake nova compute
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ neutron_sfc_agent_image_full }}"
-    name: "neutron_sfc_agent_fake_{{ item }}"
-    privileged: True
-    volumes:
-      - "{{ node_config_directory }}/neutron-sfc-agent-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:
-    - inventory_hostname in groups['compute']
-    - neutron_plugin_agent == "sfc"
-    - enable_nova_fake | bool
-
-- name: Starting neutron-linuxbridge-agent container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    environment:
-      KOLLA_CONFIG_STRATEGY: "{{ config_strategy }}"
-      NEUTRON_BRIDGE: "br-ex"
-      NEUTRON_INTERFACE: "{{ neutron_external_interface }}"
-    image: "{{ neutron_linuxbridge_agent_image_full }}"
-    name: "neutron_linuxbridge_agent"
-    privileged: True
-    volumes:
-      - "{{ node_config_directory }}/neutron-linuxbridge-agent/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "/lib/modules:/lib/modules:ro"
-      - "/run:/run:shared"
-      - "kolla_logs:/var/log/kolla/"
-  when:
-    - (inventory_hostname in groups['compute']
-       or (enable_manila | bool and inventory_hostname in groups['manila-share'])
-       or inventory_hostname in groups['neutron-dhcp-agent']
-       or inventory_hostname in groups['neutron-l3-agent']
-       or inventory_hostname in groups['neutron-metadata-agent']
-       or inventory_hostname in groups['neutron-vpnaas-agent'])
-    - neutron_plugin_agent == "linuxbridge"
-
-- name: Starting neutron-dhcp-agent container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ neutron_dhcp_agent_image_full }}"
-    name: "neutron_dhcp_agent"
-    privileged: True
-    volumes:
-      - "{{ node_config_directory }}/neutron-dhcp-agent/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "/run/:/run/:shared"
-      - "/run/netns/:/run/netns/:shared"
-      - "neutron_metadata_socket:/var/lib/neutron/kolla/"
-      - "kolla_logs:/var/log/kolla/"
-  when:
-    - inventory_hostname in groups['neutron-dhcp-agent']
-
-- name: Starting neutron-l3-agent container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ neutron_l3_agent_image_full }}"
-    name: "neutron_l3_agent"
-    privileged: True
-    volumes:
-      - "{{ node_config_directory }}/neutron-l3-agent/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "/run:/run:shared"
-      - "/run/netns/:/run/netns/:shared"
-      - "neutron_metadata_socket:/var/lib/neutron/kolla/"
-      - "kolla_logs:/var/log/kolla/"
-  when:
-    - (inventory_hostname in groups['neutron-l3-agent']
-       or (inventory_hostname in groups['compute'] and enable_neutron_dvr | bool))
-    - not enable_neutron_vpnaas | bool
-
-- name: Starting neutron-lbaas-agent container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ neutron_lbaas_agent_image_full }}"
-    name: "neutron_lbaas_agent"
-    privileged: True
-    volumes:
-      - "{{ node_config_directory }}/neutron-lbaas-agent/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "/run:/run:shared"
-      - "/run/netns/:/run/netns/:shared"
-      - "neutron_metadata_socket:/var/lib/neutron/kolla/"
-      - "kolla_logs:/var/log/kolla/"
-  when:
-    - enable_neutron_lbaas | bool
-    - inventory_hostname in groups['neutron-lbaas-agent']
-
-- name: Starting neutron-metadata-agent container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ neutron_metadata_agent_image_full }}"
-    name: "neutron_metadata_agent"
-    privileged: True
-    volumes:
-      - "{{ node_config_directory }}/neutron-metadata-agent/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "/run/netns/:/run/netns/:shared"
-      - "neutron_metadata_socket:/var/lib/neutron/kolla/"
-      - "kolla_logs:/var/log/kolla/"
-  when:
-    - (inventory_hostname in groups['neutron-metadata-agent']
-       or (inventory_hostname in groups['compute'] and enable_neutron_dvr | bool))
-
-- name: Starting neutron-vpnaas-agent container
-  kolla_docker:
-    action: "start_container"
-    common_options: "{{ docker_common_options }}"
-    image: "{{ neutron_vpnaas_agent_image_full }}"
-    name: "neutron_vpnaas_agent"
-    privileged: True
-    volumes:
-      - "{{ node_config_directory }}/neutron-vpnaas-agent/:{{ container_config_directory }}/:ro"
-      - "/etc/localtime:/etc/localtime:ro"
-      - "/run:/run:shared"
-      - "/run/netns/:/run/netns/:shared"
-      - "/lib/modules:/lib/modules:ro"
-      - "neutron_metadata_socket:/var/lib/neutron/kolla/"
-      - "kolla_logs:/var/log/kolla/"
-  when:
-    - enable_neutron_vpnaas | bool
-    - inventory_hostname in groups['neutron-vpnaas-agent']
diff --git a/ansible/roles/neutron/tasks/upgrade.yml b/ansible/roles/neutron/tasks/upgrade.yml
index 84b6f5b569..973545e091 100644
--- a/ansible/roles/neutron/tasks/upgrade.yml
+++ b/ansible/roles/neutron/tasks/upgrade.yml
@@ -1,12 +1,5 @@
 ---
 - include: config.yml
-  when: inventory_hostname in groups['compute']
-        or inventory_hostname in groups['neutron-dhcp-agent']
-        or inventory_hostname in groups['neutron-l3-agent']
-        or inventory_hostname in groups['neutron-lbaas-agent']
-        or inventory_hostname in groups['neutron-metadata-agent']
-        or inventory_hostname in groups['neutron-server']
-        or inventory_hostname in groups['neutron-vpnaas-agent']
 
 - include: config-neutron-fake.yml
   when:
@@ -16,11 +9,5 @@
 - include: bootstrap_service.yml
   when: inventory_hostname in groups['neutron-server']
 
-- include: start.yml
-  when: inventory_hostname in groups['compute']
-        or inventory_hostname in groups['neutron-dhcp-agent']
-        or inventory_hostname in groups['neutron-l3-agent']
-        or inventory_hostname in groups['neutron-lbaas-agent']
-        or inventory_hostname in groups['neutron-metadata-agent']
-        or inventory_hostname in groups['neutron-server']
-        or inventory_hostname in groups['neutron-vpnaas-agent']
+- name: Flush Handlers
+  meta: flush_handlers