From 1a682fab280233f6aae6219a3381412de9f2c403 Mon Sep 17 00:00:00 2001
From: Eduardo Gonzalez <dabarren@gmail.com>
Date: Thu, 22 Nov 2018 11:30:44 +0100
Subject: [PATCH] Support stop specific containers

With this change, an operator may be able to stop a
service container without stopping all services in a host.
This change is the starting point to start
fast-forward upgrades support.
In next changes new flags will be introducced to disable
stop dataplane services during upgrades.

Change-Id: Ifde7a39d7d8596ef0d7405ecf1ac1d49a459d9ef
Implements: blueprint support-stop-containers
---
 ansible/group_vars/all.yml                    |   9 ++
 ansible/roles/barbican/tasks/stop.yml         |   6 +
 ansible/roles/bifrost/tasks/stop.yml          |   9 ++
 ansible/roles/blazar/tasks/stop.yml           |   6 +
 ansible/roles/ceilometer/tasks/stop.yml       |   6 +
 ansible/roles/ceph/tasks/stop.yml             |  63 ++++++++
 ansible/roles/chrony/tasks/stop.yml           |   6 +
 ansible/roles/cinder/tasks/stop.yml           |   6 +
 ansible/roles/cloudkitty/tasks/stop.yml       |   6 +
 ansible/roles/collectd/tasks/stop.yml         |   6 +
 ansible/roles/common/tasks/stop.yml           |   6 +
 ansible/roles/congress/tasks/stop.yml         |   6 +
 ansible/roles/designate/tasks/stop.yml        |   6 +
 ansible/roles/elasticsearch/tasks/stop.yml    |   6 +
 ansible/roles/etcd/tasks/stop.yml             |   6 +
 ansible/roles/freezer/tasks/stop.yml          |   6 +
 ansible/roles/glance/tasks/stop.yml           |   6 +
 ansible/roles/gnocchi/tasks/stop.yml          |   6 +
 ansible/roles/grafana/tasks/stop.yml          |   6 +
 ansible/roles/haproxy/tasks/stop.yml          |   6 +
 ansible/roles/heat/tasks/stop.yml             |   6 +
 ansible/roles/horizon/tasks/stop.yml          |   6 +
 ansible/roles/influxdb/tasks/stop.yml         |   6 +
 ansible/roles/ironic/tasks/stop.yml           |   6 +
 ansible/roles/iscsi/tasks/stop.yml            |  19 +++
 ansible/roles/kafka/tasks/stop.yml            |   6 +
 ansible/roles/karbor/tasks/stop.yml           |   6 +
 ansible/roles/keystone/tasks/stop.yml         |   6 +
 ansible/roles/kibana/tasks/stop.yml           |   6 +
 ansible/roles/kuryr/tasks/stop.yml            |   6 +
 ansible/roles/magnum/tasks/stop.yml           |   6 +
 ansible/roles/manila/tasks/stop.yml           |   6 +
 ansible/roles/mariadb/tasks/stop.yml          |   6 +
 ansible/roles/memcached/tasks/stop.yml        |   6 +
 ansible/roles/mistral/tasks/stop.yml          |   6 +
 ansible/roles/monasca/tasks/stop.yml          |   6 +
 ansible/roles/mongodb/tasks/stop.yml          |   6 +
 ansible/roles/multipathd/tasks/stop.yml       |   6 +
 ansible/roles/murano/tasks/stop.yml           |   6 +
 ansible/roles/neutron/tasks/stop.yml          |   6 +
 .../check.yml => nova-hyperv/tasks/stop.yml}  |   0
 ansible/roles/nova/tasks/stop.yml             |   6 +
 ansible/roles/octavia/tasks/stop.yml          |   6 +
 ansible/roles/opendaylight/tasks/stop.yml     |   6 +
 ansible/roles/openvswitch/tasks/stop.yml      |   6 +
 ansible/roles/ovs-dpdk/tasks/stop.yml         |   6 +
 ansible/roles/panko/tasks/stop.yml            |   6 +
 ansible/roles/prometheus/tasks/stop.yml       |   6 +
 ansible/roles/qdrouterd/tasks/stop.yml        |   6 +
 ansible/roles/rabbitmq/tasks/stop.yml         |   6 +
 ansible/roles/rally/tasks/stop.yml            |   6 +
 ansible/roles/redis/tasks/stop.yml            |   6 +
 ansible/roles/sahara/tasks/stop.yml           |   6 +
 ansible/roles/searchlight/tasks/stop.yml      |   6 +
 ansible/roles/senlin/tasks/stop.yml           |   6 +
 ansible/roles/service-stop/tasks/main.yml     |  12 ++
 ansible/roles/skydive/tasks/stop.yml          |   6 +
 ansible/roles/solum/tasks/stop.yml            |   6 +
 ansible/roles/stop/tasks/copy_tools.yml       |  17 ---
 ansible/roles/stop/tasks/main.yml             |   4 -
 ansible/roles/stop/tasks/stop_containers.yml  |   3 -
 ansible/roles/storm/tasks/stop.yml            |   6 +
 ansible/roles/swift/tasks/stop.yml            | 136 ++++++++++++++++++
 ansible/roles/tacker/tasks/stop.yml           |   6 +
 ansible/roles/telegraf/tasks/stop.yml         |   6 +
 ansible/roles/tempest/tasks/stop.yml          |   6 +
 ansible/roles/trove/tasks/stop.yml            |   6 +
 ansible/roles/vitrage/tasks/stop.yml          |   6 +
 ansible/roles/vmtp/tasks/stop.yml             |   6 +
 ansible/roles/watcher/tasks/stop.yml          |   6 +
 ansible/roles/zookeeper/tasks/stop.yml        |   6 +
 ansible/roles/zun/tasks/stop.yml              |   6 +
 ansible/stop.yml                              |   4 -
 .../stop-per-service-85a996bb2751ed52.yaml    |  11 ++
 setup.cfg                                     |   1 -
 tools/kolla-ansible                           |  11 +-
 tools/stop-containers                         |  18 ---
 77 files changed, 641 insertions(+), 48 deletions(-)
 create mode 100644 ansible/roles/barbican/tasks/stop.yml
 create mode 100644 ansible/roles/bifrost/tasks/stop.yml
 create mode 100644 ansible/roles/blazar/tasks/stop.yml
 create mode 100644 ansible/roles/ceilometer/tasks/stop.yml
 create mode 100644 ansible/roles/ceph/tasks/stop.yml
 create mode 100644 ansible/roles/chrony/tasks/stop.yml
 create mode 100644 ansible/roles/cinder/tasks/stop.yml
 create mode 100644 ansible/roles/cloudkitty/tasks/stop.yml
 create mode 100644 ansible/roles/collectd/tasks/stop.yml
 create mode 100644 ansible/roles/common/tasks/stop.yml
 create mode 100644 ansible/roles/congress/tasks/stop.yml
 create mode 100644 ansible/roles/designate/tasks/stop.yml
 create mode 100644 ansible/roles/elasticsearch/tasks/stop.yml
 create mode 100644 ansible/roles/etcd/tasks/stop.yml
 create mode 100644 ansible/roles/freezer/tasks/stop.yml
 create mode 100644 ansible/roles/glance/tasks/stop.yml
 create mode 100644 ansible/roles/gnocchi/tasks/stop.yml
 create mode 100644 ansible/roles/grafana/tasks/stop.yml
 create mode 100644 ansible/roles/haproxy/tasks/stop.yml
 create mode 100644 ansible/roles/heat/tasks/stop.yml
 create mode 100644 ansible/roles/horizon/tasks/stop.yml
 create mode 100644 ansible/roles/influxdb/tasks/stop.yml
 create mode 100644 ansible/roles/ironic/tasks/stop.yml
 create mode 100644 ansible/roles/iscsi/tasks/stop.yml
 create mode 100644 ansible/roles/kafka/tasks/stop.yml
 create mode 100644 ansible/roles/karbor/tasks/stop.yml
 create mode 100644 ansible/roles/keystone/tasks/stop.yml
 create mode 100644 ansible/roles/kibana/tasks/stop.yml
 create mode 100644 ansible/roles/kuryr/tasks/stop.yml
 create mode 100644 ansible/roles/magnum/tasks/stop.yml
 create mode 100644 ansible/roles/manila/tasks/stop.yml
 create mode 100644 ansible/roles/mariadb/tasks/stop.yml
 create mode 100644 ansible/roles/memcached/tasks/stop.yml
 create mode 100644 ansible/roles/mistral/tasks/stop.yml
 create mode 100644 ansible/roles/monasca/tasks/stop.yml
 create mode 100644 ansible/roles/mongodb/tasks/stop.yml
 create mode 100644 ansible/roles/multipathd/tasks/stop.yml
 create mode 100644 ansible/roles/murano/tasks/stop.yml
 create mode 100644 ansible/roles/neutron/tasks/stop.yml
 rename ansible/roles/{stop/tasks/check.yml => nova-hyperv/tasks/stop.yml} (100%)
 create mode 100644 ansible/roles/nova/tasks/stop.yml
 create mode 100644 ansible/roles/octavia/tasks/stop.yml
 create mode 100644 ansible/roles/opendaylight/tasks/stop.yml
 create mode 100644 ansible/roles/openvswitch/tasks/stop.yml
 create mode 100644 ansible/roles/ovs-dpdk/tasks/stop.yml
 create mode 100644 ansible/roles/panko/tasks/stop.yml
 create mode 100644 ansible/roles/prometheus/tasks/stop.yml
 create mode 100644 ansible/roles/qdrouterd/tasks/stop.yml
 create mode 100644 ansible/roles/rabbitmq/tasks/stop.yml
 create mode 100644 ansible/roles/rally/tasks/stop.yml
 create mode 100644 ansible/roles/redis/tasks/stop.yml
 create mode 100644 ansible/roles/sahara/tasks/stop.yml
 create mode 100644 ansible/roles/searchlight/tasks/stop.yml
 create mode 100644 ansible/roles/senlin/tasks/stop.yml
 create mode 100644 ansible/roles/service-stop/tasks/main.yml
 create mode 100644 ansible/roles/skydive/tasks/stop.yml
 create mode 100644 ansible/roles/solum/tasks/stop.yml
 delete mode 100644 ansible/roles/stop/tasks/copy_tools.yml
 delete mode 100644 ansible/roles/stop/tasks/main.yml
 delete mode 100644 ansible/roles/stop/tasks/stop_containers.yml
 create mode 100644 ansible/roles/storm/tasks/stop.yml
 create mode 100644 ansible/roles/swift/tasks/stop.yml
 create mode 100644 ansible/roles/tacker/tasks/stop.yml
 create mode 100644 ansible/roles/telegraf/tasks/stop.yml
 create mode 100644 ansible/roles/tempest/tasks/stop.yml
 create mode 100644 ansible/roles/trove/tasks/stop.yml
 create mode 100644 ansible/roles/vitrage/tasks/stop.yml
 create mode 100644 ansible/roles/vmtp/tasks/stop.yml
 create mode 100644 ansible/roles/watcher/tasks/stop.yml
 create mode 100644 ansible/roles/zookeeper/tasks/stop.yml
 create mode 100644 ansible/roles/zun/tasks/stop.yml
 delete mode 100644 ansible/stop.yml
 create mode 100644 releasenotes/notes/stop-per-service-85a996bb2751ed52.yaml
 delete mode 100755 tools/stop-containers

diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml
index 4974e51a21..c1a2940150 100644
--- a/ansible/group_vars/all.yml
+++ b/ansible/group_vars/all.yml
@@ -581,6 +581,15 @@ monasca_agent_user: "monasca-agent"
 # can access these from the Monasca APIs.
 monasca_control_plane_project: "monasca_control_plane"
 
+####################
+# Global Options
+####################
+# List of containers to skip during stop command in YAML list format
+# skip_stop_containers:
+#   - container1
+#   - container2
+skip_stop_containers: []
+
 ####################
 # Logging options
 ####################
diff --git a/ansible/roles/barbican/tasks/stop.yml b/ansible/roles/barbican/tasks/stop.yml
new file mode 100644
index 0000000000..f7a415e26a
--- /dev/null
+++ b/ansible/roles/barbican/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ barbican_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/bifrost/tasks/stop.yml b/ansible/roles/bifrost/tasks/stop.yml
new file mode 100644
index 0000000000..797bd828cd
--- /dev/null
+++ b/ansible/roles/bifrost/tasks/stop.yml
@@ -0,0 +1,9 @@
+---
+- name: Stopping bifrost_deploy container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "bifrost_deploy"
+  when:
+    - inventory_hostname in groups['bifrost']
+    - "'bifrost_deploy' not in skip_stop_containers"
diff --git a/ansible/roles/blazar/tasks/stop.yml b/ansible/roles/blazar/tasks/stop.yml
new file mode 100644
index 0000000000..bd95ef5162
--- /dev/null
+++ b/ansible/roles/blazar/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ blazar_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/ceilometer/tasks/stop.yml b/ansible/roles/ceilometer/tasks/stop.yml
new file mode 100644
index 0000000000..fe151a027d
--- /dev/null
+++ b/ansible/roles/ceilometer/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ ceilometer_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/ceph/tasks/stop.yml b/ansible/roles/ceph/tasks/stop.yml
new file mode 100644
index 0000000000..e3852b5fde
--- /dev/null
+++ b/ansible/roles/ceph/tasks/stop.yml
@@ -0,0 +1,63 @@
+---
+- name: Stopping ceph-mon container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "ceph_mon"
+  when:
+    - inventory_hostname in groups['ceph-mon']
+    - "'ceph_mon' not in skip_stop_containers"
+
+- name: Find running ceph-osds containers
+  command: "docker ps --filter name=ceph_osd_ --format {% raw %}{{.Names}}{% endraw %}"
+  register: ceph_osd_containers
+
+- name: Stopping ceph-osd container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ item }}"
+  with_items: "{{ ceph_osd_containers.stdout_lines }}"
+  when:
+    - inventory_hostname in groups['ceph-osd']
+    - ceph_osd_containers.stdout_lines | length >= 1
+    - item not in skip_stop_containers
+
+- name: Stopping ceph-rgw container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "ceph_rgw"
+  when:
+    - inventory_hostname in groups['ceph-rgw']
+    - enable_ceph_rgw | bool
+    - "'ceph_rgw' not in skip_stop_containers"
+
+- name: Stopping ceph-mgr container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "ceph_mgr"
+  when:
+    - inventory_hostname in groups['ceph-mgr']
+    - "'ceph_mgr' not in skip_stop_containers"
+
+- name: Stopping ceph-mds container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "ceph_mds"
+  when:
+    - enable_ceph_mds | bool
+    - inventory_hostname in groups['ceph-mds']
+    - "'ceph_mds' not in skip_stop_containers"
+
+- name: Stopping ceph-nfs container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "ceph_nfs"
+  when:
+    - enable_ceph_nfs | bool
+    - inventory_hostname in groups['ceph-nfs']
+    - "'ceph_nfs' not in skip_stop_containers"
diff --git a/ansible/roles/chrony/tasks/stop.yml b/ansible/roles/chrony/tasks/stop.yml
new file mode 100644
index 0000000000..03883ff363
--- /dev/null
+++ b/ansible/roles/chrony/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ chrony_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/cinder/tasks/stop.yml b/ansible/roles/cinder/tasks/stop.yml
new file mode 100644
index 0000000000..7de1a95d76
--- /dev/null
+++ b/ansible/roles/cinder/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ cinder_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/cloudkitty/tasks/stop.yml b/ansible/roles/cloudkitty/tasks/stop.yml
new file mode 100644
index 0000000000..22c0f26568
--- /dev/null
+++ b/ansible/roles/cloudkitty/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ cloudkitty_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/collectd/tasks/stop.yml b/ansible/roles/collectd/tasks/stop.yml
new file mode 100644
index 0000000000..01794e8685
--- /dev/null
+++ b/ansible/roles/collectd/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ collectd_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/common/tasks/stop.yml b/ansible/roles/common/tasks/stop.yml
new file mode 100644
index 0000000000..3b2aaf7e48
--- /dev/null
+++ b/ansible/roles/common/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ common_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/congress/tasks/stop.yml b/ansible/roles/congress/tasks/stop.yml
new file mode 100644
index 0000000000..8c2f0dbda0
--- /dev/null
+++ b/ansible/roles/congress/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ congress_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/designate/tasks/stop.yml b/ansible/roles/designate/tasks/stop.yml
new file mode 100644
index 0000000000..166323f5a8
--- /dev/null
+++ b/ansible/roles/designate/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ designate_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/elasticsearch/tasks/stop.yml b/ansible/roles/elasticsearch/tasks/stop.yml
new file mode 100644
index 0000000000..bbf5ce56b3
--- /dev/null
+++ b/ansible/roles/elasticsearch/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ elasticsearch_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/etcd/tasks/stop.yml b/ansible/roles/etcd/tasks/stop.yml
new file mode 100644
index 0000000000..b68d9184d4
--- /dev/null
+++ b/ansible/roles/etcd/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ etcd_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/freezer/tasks/stop.yml b/ansible/roles/freezer/tasks/stop.yml
new file mode 100644
index 0000000000..cd9f745de0
--- /dev/null
+++ b/ansible/roles/freezer/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ freezer_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/glance/tasks/stop.yml b/ansible/roles/glance/tasks/stop.yml
new file mode 100644
index 0000000000..8f0ce1a7d8
--- /dev/null
+++ b/ansible/roles/glance/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ glance_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/gnocchi/tasks/stop.yml b/ansible/roles/gnocchi/tasks/stop.yml
new file mode 100644
index 0000000000..5bff185939
--- /dev/null
+++ b/ansible/roles/gnocchi/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ gnocchi_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/grafana/tasks/stop.yml b/ansible/roles/grafana/tasks/stop.yml
new file mode 100644
index 0000000000..4a7696c084
--- /dev/null
+++ b/ansible/roles/grafana/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ grafana_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/haproxy/tasks/stop.yml b/ansible/roles/haproxy/tasks/stop.yml
new file mode 100644
index 0000000000..aa5d0f6419
--- /dev/null
+++ b/ansible/roles/haproxy/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ haproxy_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/heat/tasks/stop.yml b/ansible/roles/heat/tasks/stop.yml
new file mode 100644
index 0000000000..5211a14f63
--- /dev/null
+++ b/ansible/roles/heat/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ heat_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/horizon/tasks/stop.yml b/ansible/roles/horizon/tasks/stop.yml
new file mode 100644
index 0000000000..4a8e5781af
--- /dev/null
+++ b/ansible/roles/horizon/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ horizon_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/influxdb/tasks/stop.yml b/ansible/roles/influxdb/tasks/stop.yml
new file mode 100644
index 0000000000..29d340ee92
--- /dev/null
+++ b/ansible/roles/influxdb/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ influxdb_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/ironic/tasks/stop.yml b/ansible/roles/ironic/tasks/stop.yml
new file mode 100644
index 0000000000..aef5c515e1
--- /dev/null
+++ b/ansible/roles/ironic/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ ironic_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/iscsi/tasks/stop.yml b/ansible/roles/iscsi/tasks/stop.yml
new file mode 100644
index 0000000000..dcb016a0a7
--- /dev/null
+++ b/ansible/roles/iscsi/tasks/stop.yml
@@ -0,0 +1,19 @@
+---
+- name: Stopping iscsid container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "iscsid"
+  when: ( ( inventory_hostname in groups['compute'] or inventory_hostname in groups['cinder-volume'] ) and enable_cinder | bool and enable_cinder_backend_iscsi | bool  )
+         or ( inventory_hostname in groups['ironic-conductor'] and enable_ironic | bool and 'iscsid' not in skip_stop_containers)
+
+- name: Stopping tgtd container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "tgtd"
+  when:
+    - inventory_hostname in groups['tgtd']
+    - enable_cinder | bool
+    - enable_cinder_backend_lvm | bool
+    - "'tgtd' not in skip_stop_containers"
diff --git a/ansible/roles/kafka/tasks/stop.yml b/ansible/roles/kafka/tasks/stop.yml
new file mode 100644
index 0000000000..f52b76f385
--- /dev/null
+++ b/ansible/roles/kafka/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ kafka_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/karbor/tasks/stop.yml b/ansible/roles/karbor/tasks/stop.yml
new file mode 100644
index 0000000000..54775a0581
--- /dev/null
+++ b/ansible/roles/karbor/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ karbor_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/keystone/tasks/stop.yml b/ansible/roles/keystone/tasks/stop.yml
new file mode 100644
index 0000000000..4463110652
--- /dev/null
+++ b/ansible/roles/keystone/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ keystone_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/kibana/tasks/stop.yml b/ansible/roles/kibana/tasks/stop.yml
new file mode 100644
index 0000000000..5c5034a464
--- /dev/null
+++ b/ansible/roles/kibana/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ kibana_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/kuryr/tasks/stop.yml b/ansible/roles/kuryr/tasks/stop.yml
new file mode 100644
index 0000000000..674769b357
--- /dev/null
+++ b/ansible/roles/kuryr/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ kuryr_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/magnum/tasks/stop.yml b/ansible/roles/magnum/tasks/stop.yml
new file mode 100644
index 0000000000..0e6c3504dc
--- /dev/null
+++ b/ansible/roles/magnum/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ magnum_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/manila/tasks/stop.yml b/ansible/roles/manila/tasks/stop.yml
new file mode 100644
index 0000000000..a65735642c
--- /dev/null
+++ b/ansible/roles/manila/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ manila_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/mariadb/tasks/stop.yml b/ansible/roles/mariadb/tasks/stop.yml
new file mode 100644
index 0000000000..d60e30573f
--- /dev/null
+++ b/ansible/roles/mariadb/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ mariadb_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/memcached/tasks/stop.yml b/ansible/roles/memcached/tasks/stop.yml
new file mode 100644
index 0000000000..2ca860f3ce
--- /dev/null
+++ b/ansible/roles/memcached/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ memcached_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/mistral/tasks/stop.yml b/ansible/roles/mistral/tasks/stop.yml
new file mode 100644
index 0000000000..e5feb22229
--- /dev/null
+++ b/ansible/roles/mistral/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ mistral_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/monasca/tasks/stop.yml b/ansible/roles/monasca/tasks/stop.yml
new file mode 100644
index 0000000000..d387236b95
--- /dev/null
+++ b/ansible/roles/monasca/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ monasca_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/mongodb/tasks/stop.yml b/ansible/roles/mongodb/tasks/stop.yml
new file mode 100644
index 0000000000..47d98263f3
--- /dev/null
+++ b/ansible/roles/mongodb/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ mongodb_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/multipathd/tasks/stop.yml b/ansible/roles/multipathd/tasks/stop.yml
new file mode 100644
index 0000000000..383564e8f1
--- /dev/null
+++ b/ansible/roles/multipathd/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ multipathd_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/murano/tasks/stop.yml b/ansible/roles/murano/tasks/stop.yml
new file mode 100644
index 0000000000..e395fe4c0c
--- /dev/null
+++ b/ansible/roles/murano/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ murano_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/neutron/tasks/stop.yml b/ansible/roles/neutron/tasks/stop.yml
new file mode 100644
index 0000000000..8c030e9e87
--- /dev/null
+++ b/ansible/roles/neutron/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ neutron_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/stop/tasks/check.yml b/ansible/roles/nova-hyperv/tasks/stop.yml
similarity index 100%
rename from ansible/roles/stop/tasks/check.yml
rename to ansible/roles/nova-hyperv/tasks/stop.yml
diff --git a/ansible/roles/nova/tasks/stop.yml b/ansible/roles/nova/tasks/stop.yml
new file mode 100644
index 0000000000..c4ddb86347
--- /dev/null
+++ b/ansible/roles/nova/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ nova_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/octavia/tasks/stop.yml b/ansible/roles/octavia/tasks/stop.yml
new file mode 100644
index 0000000000..f6a48244ed
--- /dev/null
+++ b/ansible/roles/octavia/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ octavia_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/opendaylight/tasks/stop.yml b/ansible/roles/opendaylight/tasks/stop.yml
new file mode 100644
index 0000000000..7cfd5b44ad
--- /dev/null
+++ b/ansible/roles/opendaylight/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ opendaylight_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/openvswitch/tasks/stop.yml b/ansible/roles/openvswitch/tasks/stop.yml
new file mode 100644
index 0000000000..c6c8ca2822
--- /dev/null
+++ b/ansible/roles/openvswitch/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ openvswitch_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/ovs-dpdk/tasks/stop.yml b/ansible/roles/ovs-dpdk/tasks/stop.yml
new file mode 100644
index 0000000000..a5a8a02e56
--- /dev/null
+++ b/ansible/roles/ovs-dpdk/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ ovsdpdk_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/panko/tasks/stop.yml b/ansible/roles/panko/tasks/stop.yml
new file mode 100644
index 0000000000..3d4fec5c39
--- /dev/null
+++ b/ansible/roles/panko/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ panko_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/prometheus/tasks/stop.yml b/ansible/roles/prometheus/tasks/stop.yml
new file mode 100644
index 0000000000..cda4198a6c
--- /dev/null
+++ b/ansible/roles/prometheus/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ prometheus_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/qdrouterd/tasks/stop.yml b/ansible/roles/qdrouterd/tasks/stop.yml
new file mode 100644
index 0000000000..a466a87ff7
--- /dev/null
+++ b/ansible/roles/qdrouterd/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ qdrouterd_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/rabbitmq/tasks/stop.yml b/ansible/roles/rabbitmq/tasks/stop.yml
new file mode 100644
index 0000000000..f13c35e515
--- /dev/null
+++ b/ansible/roles/rabbitmq/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ rabbitmq_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/rally/tasks/stop.yml b/ansible/roles/rally/tasks/stop.yml
new file mode 100644
index 0000000000..792d4ccfe7
--- /dev/null
+++ b/ansible/roles/rally/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ rally_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/redis/tasks/stop.yml b/ansible/roles/redis/tasks/stop.yml
new file mode 100644
index 0000000000..d4566d02e8
--- /dev/null
+++ b/ansible/roles/redis/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ redis_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/sahara/tasks/stop.yml b/ansible/roles/sahara/tasks/stop.yml
new file mode 100644
index 0000000000..02c3e6a905
--- /dev/null
+++ b/ansible/roles/sahara/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ sahara_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/searchlight/tasks/stop.yml b/ansible/roles/searchlight/tasks/stop.yml
new file mode 100644
index 0000000000..d6f795395c
--- /dev/null
+++ b/ansible/roles/searchlight/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ searchlight_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/senlin/tasks/stop.yml b/ansible/roles/senlin/tasks/stop.yml
new file mode 100644
index 0000000000..336538ad24
--- /dev/null
+++ b/ansible/roles/senlin/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ senlin_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/service-stop/tasks/main.yml b/ansible/roles/service-stop/tasks/main.yml
new file mode 100644
index 0000000000..b1db420588
--- /dev/null
+++ b/ansible/roles/service-stop/tasks/main.yml
@@ -0,0 +1,12 @@
+---
+- name: "Stopping {{ service_name }} containers"
+  vars:
+    service: "{{ item.value }}"
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "{{ service.container_name }}"
+  when:
+    - service.enabled | bool
+    - service.container_name not in skip_stop_containers
+  with_dict: "{{ project_services }}"
diff --git a/ansible/roles/skydive/tasks/stop.yml b/ansible/roles/skydive/tasks/stop.yml
new file mode 100644
index 0000000000..a6e363029c
--- /dev/null
+++ b/ansible/roles/skydive/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ skydive_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/solum/tasks/stop.yml b/ansible/roles/solum/tasks/stop.yml
new file mode 100644
index 0000000000..2667cb9227
--- /dev/null
+++ b/ansible/roles/solum/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ solum_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/stop/tasks/copy_tools.yml b/ansible/roles/stop/tasks/copy_tools.yml
deleted file mode 100644
index e6a1ec62d8..0000000000
--- a/ansible/roles/stop/tasks/copy_tools.yml
+++ /dev/null
@@ -1,17 +0,0 @@
----
-- name: Creating /kolla-stop/tools directory on node
-  file:
-    state: directory
-    path: /tmp/kolla-stop/tools
-
-- name: Copying validate-docker-execute.sh file
-  copy:
-    src: ../tools/validate-docker-execute.sh
-    dest: /tmp/kolla-stop/tools
-    mode: 0755
-
-- name: Copying stop-containers file
-  copy:
-    src: ../tools/stop-containers
-    dest: /tmp/kolla-stop/tools
-    mode: 0755
diff --git a/ansible/roles/stop/tasks/main.yml b/ansible/roles/stop/tasks/main.yml
deleted file mode 100644
index deb3ddfae1..0000000000
--- a/ansible/roles/stop/tasks/main.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-- include_tasks: copy_tools.yml
-
-- include_tasks: stop_containers.yml
diff --git a/ansible/roles/stop/tasks/stop_containers.yml b/ansible/roles/stop/tasks/stop_containers.yml
deleted file mode 100644
index df184d0fe2..0000000000
--- a/ansible/roles/stop/tasks/stop_containers.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-- name: Stopping Kolla containers
-  command: /tmp/kolla-stop/tools/stop-containers
diff --git a/ansible/roles/storm/tasks/stop.yml b/ansible/roles/storm/tasks/stop.yml
new file mode 100644
index 0000000000..2bc5681d68
--- /dev/null
+++ b/ansible/roles/storm/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ storm_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/swift/tasks/stop.yml b/ansible/roles/swift/tasks/stop.yml
new file mode 100644
index 0000000000..19ec5a08f0
--- /dev/null
+++ b/ansible/roles/swift/tasks/stop.yml
@@ -0,0 +1,136 @@
+---
+- name: Stopping swift-rsyncd container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "swift_rsyncd"
+  when: ( inventory_hostname in groups['swift-account-server'] or
+          inventory_hostname in groups['swift-container-server'] or
+          inventory_hostname in groups['swift-object-server'] ) and
+          'swift_rsyncd' not in skip_stop_containers
+
+- name: Stopping swift-account-server container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "swift_account_server"
+  when:
+    - inventory_hostname in groups['swift-account-server']
+    - "'swift_account_server' not in skip_stop_containers"
+
+- name: Stopping swift-account-auditor container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "swift_account_auditor"
+  when:
+    - inventory_hostname in groups['swift-account-server']
+    - "'swift_object_auditor' not in skip_stop_containers"
+
+- name: Stopping swift-account-replicator container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "swift_account_replicator"
+  when:
+    - inventory_hostname in groups['swift-account-server']
+    - "'swift_account_replicator' not in skip_stop_containers"
+
+- name: Stopping swift-account-reaper container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "swift_account_reaper"
+  when:
+    - inventory_hostname in groups['swift-account-server']
+    - "'swift_account_reaper' not in skip_stop_containers"
+
+- name: Stopping swift-container-server container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "swift_container_server"
+  when:
+    - inventory_hostname in groups['swift-container-server']
+    - "'swift_container_server' not in skip_stop_containers"
+
+- name: Stopping swift-container-auditor container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "swift_container_auditor"
+  when:
+    - inventory_hostname in groups['swift-container-server']
+    - "'swift_container_auditor' not in skip_stop_containers"
+
+- name: Stopping swift-container-replicator container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "swift_container_replicator"
+  when:
+    - inventory_hostname in groups['swift-container-server']
+    - "'swift_container_replicator' not in skip_stop_containers"
+
+- name: Stopping swift-container-updater container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "swift_container_updater"
+  when:
+    - inventory_hostname in groups['swift-container-server']
+    - "'swift_container_updater' not in skip_stop_containers"
+
+- name: Stopping swift-object-server container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "swift_object_server"
+  when:
+    - inventory_hostname in groups['swift-object-server']
+    - "'swift_object_server' not in skip_stop_containers"
+
+- name: Stopping swift-object-auditor container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "swift_object_auditor"
+  when:
+    - inventory_hostname in groups['swift-object-server']
+    - "'swift_object_auditor' not in skip_stop_containers"
+
+- name: Stopping swift-object-replicator container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "swift_object_replicator"
+  when:
+    - inventory_hostname in groups['swift-object-server']
+    - "'swift_object_replicator' not in skip_stop_containers"
+
+- name: Stopping swift-object-updater container
+  kolla_docker:
+    action: "start_container"
+    common_options: "{{ docker_common_options }}"
+    name: "swift_object_updater"
+  when:
+    - inventory_hostname in groups['swift-object-server']
+    - "'swift_object_updater' not in skip_stop_containers"
+
+- name: Stopping swift-object-expirer container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "swift_object_expirer"
+  when:
+    - inventory_hostname in groups['swift-object-server']
+    - "'swift_object_expirer' not in skip_stop_containers"
+
+- name: Stopping swift-proxy-server container
+  kolla_docker:
+    action: "stop_container"
+    common_options: "{{ docker_common_options }}"
+    name: "swift_proxy_server"
+  when:
+    - inventory_hostname in groups['swift-proxy-server']
+    - "'swift_proxy_server' not in skip_stop_containers"
diff --git a/ansible/roles/tacker/tasks/stop.yml b/ansible/roles/tacker/tasks/stop.yml
new file mode 100644
index 0000000000..026d386a1d
--- /dev/null
+++ b/ansible/roles/tacker/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ tacker_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/telegraf/tasks/stop.yml b/ansible/roles/telegraf/tasks/stop.yml
new file mode 100644
index 0000000000..e30795e6a0
--- /dev/null
+++ b/ansible/roles/telegraf/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ telegraf_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/tempest/tasks/stop.yml b/ansible/roles/tempest/tasks/stop.yml
new file mode 100644
index 0000000000..86989d6615
--- /dev/null
+++ b/ansible/roles/tempest/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ tempest_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/trove/tasks/stop.yml b/ansible/roles/trove/tasks/stop.yml
new file mode 100644
index 0000000000..35f3021d1c
--- /dev/null
+++ b/ansible/roles/trove/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ trove_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/vitrage/tasks/stop.yml b/ansible/roles/vitrage/tasks/stop.yml
new file mode 100644
index 0000000000..4f5c631bf6
--- /dev/null
+++ b/ansible/roles/vitrage/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ vitrage_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/vmtp/tasks/stop.yml b/ansible/roles/vmtp/tasks/stop.yml
new file mode 100644
index 0000000000..3dc1e86830
--- /dev/null
+++ b/ansible/roles/vmtp/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ vmtp_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/watcher/tasks/stop.yml b/ansible/roles/watcher/tasks/stop.yml
new file mode 100644
index 0000000000..c0e95da490
--- /dev/null
+++ b/ansible/roles/watcher/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ watcher_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/zookeeper/tasks/stop.yml b/ansible/roles/zookeeper/tasks/stop.yml
new file mode 100644
index 0000000000..62f198d765
--- /dev/null
+++ b/ansible/roles/zookeeper/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ zookeeper_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/roles/zun/tasks/stop.yml b/ansible/roles/zun/tasks/stop.yml
new file mode 100644
index 0000000000..f07c93fee6
--- /dev/null
+++ b/ansible/roles/zun/tasks/stop.yml
@@ -0,0 +1,6 @@
+---
+- import_role:
+    role: service-stop
+  vars:
+    project_services: "{{ zun_services }}"
+    service_name: "{{ project_name }}"
diff --git a/ansible/stop.yml b/ansible/stop.yml
deleted file mode 100644
index 0ff7bf494f..0000000000
--- a/ansible/stop.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-- hosts: all
-  roles:
-    - stop
diff --git a/releasenotes/notes/stop-per-service-85a996bb2751ed52.yaml b/releasenotes/notes/stop-per-service-85a996bb2751ed52.yaml
new file mode 100644
index 0000000000..a669f507d5
--- /dev/null
+++ b/releasenotes/notes/stop-per-service-85a996bb2751ed52.yaml
@@ -0,0 +1,11 @@
+---
+features:
+  - |
+    Add support to stop a service with ``kolla-ansible stop`` command.
+    This feature will allow to stop specific services with ``--tags`` and
+    ``--limit`` to a host.
+upgrade:
+  - |
+    New ``kolla-ansible stop`` command requires the usage of
+    ``--yes-i-really-really-mean-it`` to avoid accidentally
+    stopping services.
diff --git a/setup.cfg b/setup.cfg
index 7fc0546a1b..228ea5b598 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -28,7 +28,6 @@ data_files =
     share/kolla-ansible/tools = tools/cleanup-containers
     share/kolla-ansible/tools = tools/cleanup-host
     share/kolla-ansible/tools = tools/cleanup-images
-    share/kolla-ansible/tools = tools/stop-containers
     share/kolla-ansible/tools = tools/ovs-dpdkctl.sh
     share/kolla-ansible/doc = doc/*
     share/kolla-ansible/etc_examples = etc/*
diff --git a/tools/kolla-ansible b/tools/kolla-ansible
index 0706d7a763..96024a348f 100755
--- a/tools/kolla-ansible
+++ b/tools/kolla-ansible
@@ -330,7 +330,16 @@ EOF
         ;;
 (stop)
         ACTION="Stop Kolla containers"
-        PLAYBOOK="${BASEDIR}/ansible/stop.yml"
+        EXTRA_OPTS="$EXTRA_OPTS -e kolla_action=stop"
+        if [[ "${DANGER_CONFIRM}" != "--yes-i-really-really-mean-it" ]]; then
+            cat << EOF
+WARNING:
+    This will stop all deployed kolla containers, limit with tags is possible and also with
+    skip_stop_containers variable. To confirm, please add the following option:
+    --yes-i-really-really-mean-it
+EOF
+            exit 1
+        fi
         ;;
 (certificates)
         ACTION="Generate TLS Certificates"
diff --git a/tools/stop-containers b/tools/stop-containers
deleted file mode 100755
index f12c50f44a..0000000000
--- a/tools/stop-containers
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-if [[ $(pgrep qemu) ]]; then
-    echo "Some qemu processes were detected."
-    echo "Docker will not be able to stop the nova_libvirt container with those running."
-    echo "Please clean them up before rerunning this script."
-    exit 1
-fi
-
-if [ -n "$1" ]; then
-    containers_to_stop=($(docker ps | grep -E "$1" | awk '{print $1}'))
-else
-    containers_to_stop=$(docker ps --filter "label=kolla_version" --format "{{.Names}}" -a)
-fi
-
-echo "Stopping containers..."
-(docker stop -t 30 ${containers_to_stop} 2>&1) > /dev/null
-
-echo "All containers stopped!"