diff --git a/ansible/inventory/all-in-one b/ansible/inventory/all-in-one
index e0c1fd323ed97ad9cb1eb4b39e00439c4c4f2830..80bf8f783bfaaa04ae47387c6311404d7f9b5632 100644
--- a/ansible/inventory/all-in-one
+++ b/ansible/inventory/all-in-one
@@ -20,10 +20,19 @@ localhost       ansible_connection=local
 
 # You can explicitly specify which hosts run each project by updating the
 # groups in the sections below. Common services are grouped together.
+
+[common:children]
+control
+network
+compute
+storage
+monitoring
+
 [chrony-server:children]
 haproxy
 
 [chrony:children]
+control
 network
 compute
 storage
@@ -250,6 +259,19 @@ control
 # function appropriately. For example, neutron-metadata-agent must run on the
 # same host as the l3-agent and (depending on configuration) the dhcp-agent.
 
+# Common
+[cron:children]
+common
+
+[fluentd:children]
+common
+
+[kolla-logs:children]
+common
+
+[kolla-toolbox:children]
+common
+
 # Elasticsearch Curator
 [elasticsearch-curator:children]
 elasticsearch
diff --git a/ansible/inventory/multinode b/ansible/inventory/multinode
index 3512de4d6dbddcd3f9cbbd473e676b998726375a..9a4ec0705844d3b38283f2d0f0938ff1b1748535 100644
--- a/ansible/inventory/multinode
+++ b/ansible/inventory/multinode
@@ -44,6 +44,14 @@ control
 
 # You can explicitly specify which hosts run each project by updating the
 # groups in the sections below. Common services are grouped together.
+
+[common:children]
+control
+network
+compute
+storage
+monitoring
+
 [chrony-server:children]
 haproxy
 
@@ -269,6 +277,19 @@ control
 # function appropriately. For example, neutron-metadata-agent must run on the
 # same host as the l3-agent and (depending on configuration) the dhcp-agent.
 
+# Common
+[cron:children]
+common
+
+[fluentd:children]
+common
+
+[kolla-logs:children]
+common
+
+[kolla-toolbox:children]
+common
+
 # Elasticsearch Curator
 [elasticsearch-curator:children]
 elasticsearch
diff --git a/ansible/roles/aodh/meta/main.yml b/ansible/roles/aodh/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/aodh/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/barbican/meta/main.yml b/ansible/roles/barbican/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/barbican/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/blazar/meta/main.yml b/ansible/roles/blazar/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/blazar/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/ceilometer/meta/main.yml b/ansible/roles/ceilometer/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/ceilometer/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/chrony/meta/main.yml b/ansible/roles/chrony/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/chrony/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/cinder/meta/main.yml b/ansible/roles/cinder/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/cinder/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/cloudkitty/meta/main.yml b/ansible/roles/cloudkitty/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/cloudkitty/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/collectd/meta/main.yml b/ansible/roles/collectd/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/collectd/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/common/defaults/main.yml b/ansible/roles/common/defaults/main.yml
index f50c325ec30b40138ff997415cfc10505b2f0ecd..2569c41a8659f8aa130513613a937b2d3e53293e 100644
--- a/ansible/roles/common/defaults/main.yml
+++ b/ansible/roles/common/defaults/main.yml
@@ -1,14 +1,10 @@
 ---
 project_name: "common"
 
-# Due to the way we do our inventory, ansible does not pick up on the fact that
-# this role has already run. We can track what has run with host facts.
-common_run: False
-
 common_services:
   fluentd:
     container_name: fluentd
-    group: all
+    group: fluentd
     enabled: "{{ enable_fluentd | bool }}"
     image: "{{ fluentd_image_full }}"
     environment:
@@ -17,7 +13,7 @@ common_services:
     dimensions: "{{ fluentd_dimensions }}"
   kolla-toolbox:
     container_name: kolla_toolbox
-    group: all
+    group: kolla-toolbox
     enabled: True
     image: "{{ kolla_toolbox_image_full }}"
     environment:
@@ -29,7 +25,7 @@ common_services:
   # DUMMY_ENVIRONMENT is needed because empty environment is not supported
   cron:
     container_name: cron
-    group: all
+    group: cron
     enabled: True
     image: "{{ cron_image_full }}"
     environment:
diff --git a/ansible/roles/common/tasks/bootstrap.yml b/ansible/roles/common/tasks/bootstrap.yml
index 67026082a4448c97d4bf36eef8d2c0bc0b28ab4b..eb824bf6525a9ae534cf51e24672df73fe205a3b 100644
--- a/ansible/roles/common/tasks/bootstrap.yml
+++ b/ansible/roles/common/tasks/bootstrap.yml
@@ -5,6 +5,7 @@
     action: "create_volume"
     common_options: "{{ docker_common_options }}"
     name: "kolla_logs"
+  when: inventory_hostname in groups['kolla-logs']
 
 - name: Link kolla_logs volume to /var/log/kolla
   become: true
@@ -12,3 +13,4 @@
     src: "{{ docker_runtime_directory or '/var/lib/docker' }}/volumes/kolla_logs/_data"
     path: /var/log/kolla
     state: link
+  when: inventory_hostname in groups['kolla-logs']
diff --git a/ansible/roles/common/tasks/check-containers.yml b/ansible/roles/common/tasks/check-containers.yml
index 1f00f006da864347cd6bcdd3a19b82fc979271af..45f110a01b0d991110000063212bf280be6ddda0 100644
--- a/ansible/roles/common/tasks/check-containers.yml
+++ b/ansible/roles/common/tasks/check-containers.yml
@@ -11,7 +11,7 @@
     privileged: "{{ item.value.privileged | default(False) }}"
     environment: "{{ item.value.environment }}"
   when:
-    - item.value.enabled | bool
+    - item.value | service_enabled_and_mapped_to_host
   with_dict: "{{ common_services }}"
   notify:
     - "Restart {{ item.key }} container"
diff --git a/ansible/roles/common/tasks/config.yml b/ansible/roles/common/tasks/config.yml
index fc18f4972021a580da3058358e88bdea857c95ba..5c4a0f474b2055221bb1914a5f169a30d64122a9 100644
--- a/ansible/roles/common/tasks/config.yml
+++ b/ansible/roles/common/tasks/config.yml
@@ -1,30 +1,32 @@
 ---
 - name: Ensuring config directories exist
+  vars:
+    service_name: "{{ item.0.service_name }}"
+    service: "{{ common_services[service_name] }}"
   file:
-    path: "{{ node_config_directory }}/{{ item }}"
+    path: "{{ node_config_directory }}/{{ item.1 }}"
     state: "directory"
     owner: "{{ config_owner_user }}"
     group: "{{ config_owner_group }}"
     mode: "0770"
   become: true
-  with_items:
-    - "kolla-toolbox"
-    - "cron"
-    - "cron/logrotate"
-
-- name: Ensuring fluentd config directories exist
-  file:
-    path: "{{ node_config_directory }}/{{ item }}"
-    state: "directory"
-    mode: "0770"
-  become: true
-  with_items:
-    - "fluentd"
-    - "fluentd/input"
-    - "fluentd/output"
-    - "fluentd/format"
-    - "fluentd/filter"
-  when: enable_fluentd | bool
+  with_subelements:
+    - - service_name: "cron"
+        paths:
+          - "cron"
+          - "cron/logrotate"
+      - service_name: "fluentd"
+        paths:
+          - "fluentd"
+          - "fluentd/input"
+          - "fluentd/output"
+          - "fluentd/format"
+          - "fluentd/filter"
+      - service_name: "kolla-toolbox"
+        paths:
+          - "kolla-toolbox"
+    - paths
+  when: service | service_enabled_and_mapped_to_host
 
 - name: Ensure fluentd image is present for label check
   vars:
@@ -35,7 +37,7 @@
     action: "ensure_image"
     common_options: "{{ docker_common_options }}"
     image: "{{ service.image }}"
-  when: enable_fluentd | bool
+  when: service | service_enabled_and_mapped_to_host
 
 - name: Fetch fluentd image labels
   vars:
@@ -45,12 +47,12 @@
   docker_image_info:
     name: "{{ service.image }}"
   register: fluentd_labels
-  when: enable_fluentd | bool
+  when: service | service_enabled_and_mapped_to_host
 
 - name: Set fluentd facts
   set_fact:
     fluentd_binary: "{{ fluentd_labels.images.0.ContainerConfig.Labels.fluentd_binary }}"
-  when: enable_fluentd | bool
+  when: common_services.fluentd | service_enabled_and_mapped_to_host
 
 - include_tasks: copy-certs.yml
   when:
@@ -62,7 +64,7 @@
     dest: "{{ node_config_directory }}/{{ item.key }}/config.json"
     mode: "0660"
   become: true
-  when: item.value.enabled | bool
+  when: item.value | service_enabled_and_mapped_to_host
   with_dict: "{{ common_services }}"
   notify:
     - "Restart {{ item.key }} container"
@@ -74,8 +76,7 @@
   run_once: True
   register: find_custom_fluentd_inputs
   delegate_to: localhost
-  when:
-    - enable_fluentd | bool
+  when: common_services.fluentd | service_enabled_and_mapped_to_host
 
 - name: Copying over fluentd input config files
   vars:
@@ -86,7 +87,7 @@
     mode: "0660"
   become: true
   when:
-    - enable_fluentd | bool
+    - common_services.fluentd | service_enabled_and_mapped_to_host
     - item ~ '.conf' not in customised_input_files
   with_items:
     - "00-global"
@@ -107,7 +108,7 @@
     dest: "{{ node_config_directory }}/fluentd/input/{{ item.path | basename }}"
     mode: "0660"
   when:
-    - enable_fluentd | bool
+    - common_services.fluentd | service_enabled_and_mapped_to_host
   with_items: "{{ find_custom_fluentd_inputs.files }}"
   notify:
     - Restart fluentd container
@@ -117,6 +118,8 @@
     log_direct_to_elasticsearch: "{{ ( enable_elasticsearch | bool or
                 ( elasticsearch_address != kolla_internal_vip_address )) and
                 not enable_monasca | bool }}"
+  when:
+    - common_services.fluentd | service_enabled_and_mapped_to_host
 
 - name: Find custom fluentd output config files
   find:
@@ -126,7 +129,7 @@
   register: find_custom_fluentd_outputs
   delegate_to: localhost
   when:
-    - enable_fluentd | bool
+    - common_services.fluentd | service_enabled_and_mapped_to_host
 
 - name: Copying over fluentd output config files
   vars:
@@ -137,7 +140,7 @@
     mode: "0660"
   become: true
   when:
-    - enable_fluentd | bool
+    - common_services.fluentd | service_enabled_and_mapped_to_host
     - item.enabled | bool
     - item.name ~ '.conf' not in customised_output_files
   with_items:
@@ -156,7 +159,7 @@
     state: "absent"
   become: true
   when:
-    - enable_fluentd | bool
+    - common_services.fluentd | service_enabled_and_mapped_to_host
     - item.disable | bool
   with_items:
     - name: "02-monasca"
@@ -173,7 +176,7 @@
     mode: "0660"
   become: true
   when:
-    - enable_fluentd | bool
+    - common_services.fluentd | service_enabled_and_mapped_to_host
   with_items: "{{ find_custom_fluentd_outputs.files }}"
   notify:
     - Restart fluentd container
@@ -186,7 +189,7 @@
   register: find_custom_fluentd_format
   delegate_to: localhost
   when:
-    - enable_fluentd | bool
+    - common_services.fluentd | service_enabled_and_mapped_to_host
 
 - name: Copying over fluentd format config files
   vars:
@@ -200,7 +203,7 @@
     - "apache_access"
     - "wsgi_access"
   when:
-    - enable_fluentd | bool
+    - common_services.fluentd | service_enabled_and_mapped_to_host
     - item ~ '.conf' not in customised_format_files
   notify:
     - Restart fluentd container
@@ -211,7 +214,7 @@
     dest: "{{ node_config_directory }}/fluentd/format/{{ item.path | basename }}"
     mode: "0660"
   when:
-    - enable_fluentd | bool
+    - common_services.fluentd | service_enabled_and_mapped_to_host
   with_items: "{{ find_custom_fluentd_format.files }}"
   notify:
     - Restart fluentd container
@@ -223,7 +226,7 @@
   run_once: True
   register: find_custom_fluentd_filters
   delegate_to: localhost
-  when: enable_fluentd | bool
+  when: common_services.fluentd | service_enabled_and_mapped_to_host
 
 - name: Copying over fluentd filter config files
   vars:
@@ -242,7 +245,7 @@
     - src: 02-parser
       dest: 02-parser
   when:
-    - enable_fluentd | bool
+    - common_services.fluentd | service_enabled_and_mapped_to_host
     - item.src ~ '.conf' not in customised_filter_files
   notify:
     - Restart fluentd container
@@ -254,7 +257,8 @@
     mode: "0660"
   become: true
   with_items: "{{ find_custom_fluentd_filters.files }}"
-  when: enable_fluentd | bool
+  when:
+    - common_services.fluentd | service_enabled_and_mapped_to_host
   notify:
     - Restart fluentd container
 
@@ -266,7 +270,7 @@
   become: true
   with_items:
     - "fluentd"
-  when: enable_fluentd | bool
+  when: common_services.fluentd | service_enabled_and_mapped_to_host
   notify:
     - Restart fluentd container
 
@@ -276,7 +280,9 @@
     dest: "{{ node_config_directory }}/cron/logrotate/{{ item.name }}.conf"
     mode: "0660"
   become: true
-  when: item.enabled | bool
+  when:
+    - common_services.cron | service_enabled_and_mapped_to_host
+    - item.enabled | bool
   with_items:
     - { name: "ansible", enabled: "yes" }
     - { name: "aodh", enabled: "{{ enable_aodh }}" }
@@ -348,7 +354,9 @@
     content: "{{ rabbitmq_cluster_cookie }}"
     dest: "{{ node_config_directory }}/kolla-toolbox/rabbitmq-erlang.cookie"
     mode: "0660"
-  when: enable_rabbitmq | bool
+  when:
+    - common_services['kolla-toolbox'] | service_enabled_and_mapped_to_host
+    - enable_rabbitmq | bool
   notify:
     - Restart kolla-toolbox container
 
@@ -361,7 +369,7 @@
     mode: "0770"
   ignore_errors: "{{ ansible_check_mode }}"
   when:
-    - item.value.enabled | bool
+    - item.value | service_enabled_and_mapped_to_host
     - item.key != "kolla-toolbox"
   with_dict: "{{ common_services }}"
 
@@ -374,7 +382,8 @@
     mode: "0600"
   become: true
   when:
-    api_address_family == "ipv6"
+    - common_services['kolla-toolbox'] | service_enabled_and_mapped_to_host
+    - api_address_family == "ipv6"
 
 - name: Copy rabbitmq erl_intr to kolla toolbox
   copy:
@@ -384,7 +393,8 @@
     mode: "0600"
   become: true
   when:
-    api_address_family == "ipv6"
+    - common_services['kolla-toolbox'] | service_enabled_and_mapped_to_host
+    - api_address_family == "ipv6"
 
 - include_tasks: check-containers.yml
   when: kolla_action != "config"
diff --git a/ansible/roles/common/tasks/main.yml b/ansible/roles/common/tasks/main.yml
index a314ca5a4a7c2b0023c3b90813b0c28357fa7b2b..bc5d1e62576375cb42a2a0d62540aa54d212db7c 100644
--- a/ansible/roles/common/tasks/main.yml
+++ b/ansible/roles/common/tasks/main.yml
@@ -1,10 +1,2 @@
 ---
 - include_tasks: "{{ kolla_action }}.yml"
-  tags: common
-  when: not common_run
-
-- name: Registering common role has run
-  set_fact:
-    common_run: True
-  tags: common
-  when: not common_run
diff --git a/ansible/roles/common/tasks/pull.yml b/ansible/roles/common/tasks/pull.yml
index 2a18e9ce51544b1b2802c4be18eac13619ac2684..7f7fefbcc392033001a18fdb5785ab00a82209a4 100644
--- a/ansible/roles/common/tasks/pull.yml
+++ b/ansible/roles/common/tasks/pull.yml
@@ -6,5 +6,5 @@
     common_options: "{{ docker_common_options }}"
     image: "{{ item.value.image }}"
   when:
-    - item.value.enabled | bool
+    - item.value | service_enabled_and_mapped_to_host
   with_dict: "{{ common_services }}"
diff --git a/ansible/roles/cyborg/meta/main.yml b/ansible/roles/cyborg/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/cyborg/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/designate/meta/main.yml b/ansible/roles/designate/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/designate/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/elasticsearch/meta/main.yml b/ansible/roles/elasticsearch/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/elasticsearch/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/etcd/meta/main.yml b/ansible/roles/etcd/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/etcd/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/freezer/meta/main.yml b/ansible/roles/freezer/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/freezer/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/glance/meta/main.yml b/ansible/roles/glance/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/glance/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/gnocchi/meta/main.yml b/ansible/roles/gnocchi/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/gnocchi/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/grafana/meta/main.yml b/ansible/roles/grafana/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/grafana/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/haproxy/meta/main.yml b/ansible/roles/haproxy/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/haproxy/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/heat/meta/main.yml b/ansible/roles/heat/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/heat/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/horizon/meta/main.yml b/ansible/roles/horizon/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/horizon/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/influxdb/meta/main.yml b/ansible/roles/influxdb/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/influxdb/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/ironic/meta/main.yml b/ansible/roles/ironic/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/ironic/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/iscsi/meta/main.yml b/ansible/roles/iscsi/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/iscsi/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/kafka/meta/main.yml b/ansible/roles/kafka/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/kafka/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/karbor/meta/main.yml b/ansible/roles/karbor/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/karbor/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/keystone/meta/main.yml b/ansible/roles/keystone/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/keystone/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/kibana/meta/main.yml b/ansible/roles/kibana/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/kibana/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/kuryr/meta/main.yml b/ansible/roles/kuryr/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/kuryr/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/magnum/meta/main.yml b/ansible/roles/magnum/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/magnum/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/manila/meta/main.yml b/ansible/roles/manila/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/manila/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/mariadb/meta/main.yml b/ansible/roles/mariadb/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/mariadb/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/masakari/meta/main.yml b/ansible/roles/masakari/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/masakari/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/mistral/meta/main.yml b/ansible/roles/mistral/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/mistral/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/monasca/meta/main.yml b/ansible/roles/monasca/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/monasca/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/murano/meta/main.yml b/ansible/roles/murano/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/murano/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/neutron/meta/main.yml b/ansible/roles/neutron/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/neutron/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/nova-cell/meta/main.yml b/ansible/roles/nova-cell/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/nova-cell/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/nova-hyperv/meta/main.yml b/ansible/roles/nova-hyperv/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/nova-hyperv/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/nova/meta/main.yml b/ansible/roles/nova/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/nova/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/octavia/meta/main.yml b/ansible/roles/octavia/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/octavia/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/openvswitch/meta/main.yml b/ansible/roles/openvswitch/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/openvswitch/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/ovn/meta/main.yml b/ansible/roles/ovn/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/ovn/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/ovs-dpdk/meta/main.yml b/ansible/roles/ovs-dpdk/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/ovs-dpdk/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/panko/meta/main.yml b/ansible/roles/panko/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/panko/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/placement/meta/main.yml b/ansible/roles/placement/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/placement/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/prometheus/meta/main.yml b/ansible/roles/prometheus/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/prometheus/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/qdrouterd/meta/main.yml b/ansible/roles/qdrouterd/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/qdrouterd/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/qinling/meta/main.yml b/ansible/roles/qinling/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/qinling/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/rabbitmq/meta/main.yml b/ansible/roles/rabbitmq/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/rabbitmq/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/rally/meta/main.yml b/ansible/roles/rally/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/rally/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/redis/meta/main.yml b/ansible/roles/redis/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/redis/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/sahara/meta/main.yml b/ansible/roles/sahara/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/sahara/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/searchlight/meta/main.yml b/ansible/roles/searchlight/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/searchlight/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/senlin/meta/main.yml b/ansible/roles/senlin/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/senlin/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/skydive/meta/main.yml b/ansible/roles/skydive/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/skydive/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/solum/meta/main.yml b/ansible/roles/solum/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/solum/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/storm/meta/main.yml b/ansible/roles/storm/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/storm/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/swift/meta/main.yml b/ansible/roles/swift/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/swift/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/tacker/meta/main.yml b/ansible/roles/tacker/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/tacker/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/telegraf/meta/main.yml b/ansible/roles/telegraf/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/telegraf/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/tempest/meta/main.yml b/ansible/roles/tempest/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/tempest/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/trove/meta/main.yml b/ansible/roles/trove/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/trove/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/vitrage/meta/main.yml b/ansible/roles/vitrage/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/vitrage/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/vmtp/meta/main.yml b/ansible/roles/vmtp/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/vmtp/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/watcher/meta/main.yml b/ansible/roles/watcher/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/watcher/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/zookeeper/meta/main.yml b/ansible/roles/zookeeper/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/zookeeper/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/roles/zun/meta/main.yml b/ansible/roles/zun/meta/main.yml
deleted file mode 100644
index 6b4fff8fef6f81d35b73a30c90de45639db41cc9..0000000000000000000000000000000000000000
--- a/ansible/roles/zun/meta/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-dependencies:
-  - { role: common }
diff --git a/ansible/site.yml b/ansible/site.yml
index cab5e1d937ebba3c311403ce0cc4bd5161a6acc2..4c21276a9cb9502554fd8c988ab13f5d40309da7 100644
--- a/ansible/site.yml
+++ b/ansible/site.yml
@@ -92,6 +92,19 @@
   roles:
     - role: prechecks
 
+- name: Apply role common
+  gather_facts: false
+  hosts:
+    - cron
+    - fluentd
+    - kolla-logs
+    - kolla-toolbox
+  serial: '{{ kolla_serial|default("0") }}'
+  tags:
+    - common
+  roles:
+    - role: common
+
 - name: Apply role chrony
   gather_facts: false
   hosts:
diff --git a/releasenotes/notes/separate-common-play-09a1aa1ac7d0797a.yaml b/releasenotes/notes/separate-common-play-09a1aa1ac7d0797a.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..08d558889ca6be9bdf67e82e4c67456dbf35f31c
--- /dev/null
+++ b/releasenotes/notes/separate-common-play-09a1aa1ac7d0797a.yaml
@@ -0,0 +1,20 @@
+---
+features:
+  - |
+    Extracts the common role into a separate play. This provides a performance
+    benefit at scale, since the role dependency mechanism used previously had a
+    overhead. This change allows the only common role to be executed by
+    specifying the ``common`` tag.
+upgrade:
+  - |
+    The common role is now executed in a separate play. This introduces a few
+    small changes in behaviour:
+
+    * the common role is now run for all hosts at the beginning, rather than
+      prior to their first enabled service
+    * hosts must be in the necessary group for each of the common services
+      (``cron``, ``fluentd``, ``kolla-logs``, ``kolla-toolbox``) in order to
+      have that service deployed
+    * if tags are specified for another service e.g. nova, the common role
+      will *not* automatically run for matching hosts. The common tag must
+      be specified explicitly
diff --git a/tests/templates/inventory.j2 b/tests/templates/inventory.j2
index 8cd1d2ecc2997d05178ec78845eaceda056abb0e..1c3c755559becdc08dd82ebaa174853b0e48cbce 100644
--- a/tests/templates/inventory.j2
+++ b/tests/templates/inventory.j2
@@ -58,6 +58,14 @@ control
 
 # You can explicitly specify which hosts run each project by updating the
 # groups in the sections below. Common services are grouped together.
+
+[common:children]
+control
+network
+compute
+storage
+monitoring
+
 [chrony-server:children]
 haproxy
 
@@ -283,6 +291,19 @@ control
 # function appropriately. For example, neutron-metadata-agent must run on the
 # same host as the l3-agent and (depending on configuration) the dhcp-agent.
 
+# Common
+[cron:children]
+common
+
+[fluentd:children]
+common
+
+[kolla-logs:children]
+common
+
+[kolla-toolbox:children]
+common
+
 # Elasticsearch Curator
 [elasticsearch-curator:children]
 elasticsearch
diff --git a/tools/kolla-ansible b/tools/kolla-ansible
index ebc085f2445d35b991fd00dfa1b0f266af34e662..2d01cf62a62cdb56276f3ae2cdceb32552705e8b 100755
--- a/tools/kolla-ansible
+++ b/tools/kolla-ansible
@@ -343,12 +343,12 @@ case "$1" in
         ;;
 (mariadb_recovery)
         ACTION="Attempting to restart mariadb cluster"
-        EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=deploy -e common_run=true"
+        EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=deploy"
         PLAYBOOK="${BASEDIR}/ansible/mariadb_recovery.yml"
         ;;
 (mariadb_backup)
         ACTION="Backup MariaDB databases"
-        EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=backup -e mariadb_backup_type=${BACKUP_TYPE} -e common_run=true"
+        EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=backup -e mariadb_backup_type=${BACKUP_TYPE}"
         PLAYBOOK="${BASEDIR}/ansible/mariadb_backup.yml"
         ;;
 (destroy)