feat: move pxc to operator
diff --git a/atmosphere/cmd/operator.py b/atmosphere/cmd/operator.py
index 2725a92..fbef0e1 100644
--- a/atmosphere/cmd/operator.py
+++ b/atmosphere/cmd/operator.py
@@ -1,6 +1,5 @@
 import time
 
-import taskflow.engines
 from watchdog.events import FileSystemEventHandler
 from watchdog.observers import Observer
 
@@ -20,14 +19,14 @@
         for c in config._root_config:
             group = conf.get(c.name)
             setattr(CONF, c.name, group)
-        engine = taskflow.engines.load(flows.get_deployment_flow())
+        engine = flows.get_engine()
         engine.run()
 
 
 def main():
     LOG.info("Starting Atmosphere operator")
 
-    engine = taskflow.engines.load(flows.get_deployment_flow())
+    engine = flows.get_engine()
     engine.run()
     LOG.info("Atmosphere operator successfully started")
 
diff --git a/atmosphere/flows.py b/atmosphere/flows.py
index c938ccf..0c8b2bd 100644
--- a/atmosphere/flows.py
+++ b/atmosphere/flows.py
@@ -1,112 +1,98 @@
+from taskflow import engines
 from taskflow.patterns import graph_flow
 
 from atmosphere.config import CONF
+from atmosphere.tasks import constants
 from atmosphere.tasks.composite import openstack_helm
 from atmosphere.tasks.kubernetes import flux, v1
 
-NAMESPACE_CERT_MANAGER = "cert-manager"
-NAMESPACE_KUBE_SYSTEM = "kube-system"
-NAMESPACE_MONITORING = "monitoring"
-NAMESPACE_OPENSTACK = "openstack"
 
-HELM_REPOSITORY_BITNAMI = "bitnami"
-HELM_REPOSITORY_CEPH = "ceph"
-HELM_REPOSITORY_COREDNS = "coredns"
-HELM_REPOSITORY_INGRESS_NGINX = "ingress-nginx"
-HELM_REPOSITORY_JETSTACK = "jetstack"
-HELM_REPOSITORY_NODE_FEATURE_DISCOVERY = "node-feature-discovery"
-HELM_REPOSITORY_OPENSTACK_HELM = "openstack-helm"
-HELM_REPOSITORY_OPENSTACK_HELM_INFRA = "openstack-helm-infra"
-HELM_REPOSITORY_PERCONA = "percona"
-HELM_REPOSITORY_PROMETHEUS_COMMUINTY = "prometheus-community"
-
-CONTROL_PLANE_NODE_SELECTOR = {
-    "openstack-control-plane": "enabled",
-}
-
-NODE_FEATURE_DISCOVERY_VALUES = {
-    "master": {"nodeSelector": CONTROL_PLANE_NODE_SELECTOR}
-}
-
-PERCONA_XTRADB_OPERATOR_VALUES = {
-    "nodeSelector": CONTROL_PLANE_NODE_SELECTOR,
-}
+def get_engine():
+    return engines.load(
+        get_deployment_flow(),
+        executor="greenthreaded",
+        engine="parallel",
+        max_workers=4,
+    )
 
 
 def get_deployment_flow():
     flow = graph_flow.Flow("deploy").add(
         # kube-system
-        v1.ApplyNamespaceTask(name=NAMESPACE_KUBE_SYSTEM),
+        v1.ApplyNamespaceTask(name=constants.NAMESPACE_KUBE_SYSTEM),
         flux.ApplyHelmRepositoryTask(
-            namespace=NAMESPACE_KUBE_SYSTEM,
-            name=HELM_REPOSITORY_CEPH,
+            namespace=constants.NAMESPACE_KUBE_SYSTEM,
+            name=constants.HELM_REPOSITORY_CEPH,
             url="https://ceph.github.io/csi-charts",
         ),
         # cert-manager
-        v1.ApplyNamespaceTask(name=NAMESPACE_CERT_MANAGER),
+        v1.ApplyNamespaceTask(name=constants.NAMESPACE_CERT_MANAGER),
         flux.ApplyHelmRepositoryTask(
-            namespace=NAMESPACE_CERT_MANAGER,
-            name=HELM_REPOSITORY_JETSTACK,
+            namespace=constants.NAMESPACE_CERT_MANAGER,
+            name=constants.HELM_REPOSITORY_JETSTACK,
             url="https://charts.jetstack.io",
         ),
         # monitoring
-        v1.ApplyNamespaceTask(name=NAMESPACE_MONITORING),
+        v1.ApplyNamespaceTask(name=constants.NAMESPACE_MONITORING),
         flux.ApplyHelmRepositoryTask(
-            namespace=NAMESPACE_MONITORING,
-            name=HELM_REPOSITORY_PROMETHEUS_COMMUINTY,
+            namespace=constants.NAMESPACE_MONITORING,
+            name=constants.HELM_REPOSITORY_PROMETHEUS_COMMUINTY,
             url="https://prometheus-community.github.io/helm-charts",
         ),
         flux.ApplyHelmRepositoryTask(
-            namespace=NAMESPACE_MONITORING,
-            name=HELM_REPOSITORY_NODE_FEATURE_DISCOVERY,
+            namespace=constants.NAMESPACE_MONITORING,
+            name=constants.HELM_REPOSITORY_NODE_FEATURE_DISCOVERY,
             url="https://kubernetes-sigs.github.io/node-feature-discovery/charts",
         ),
         flux.ApplyHelmReleaseTask(
-            namespace=NAMESPACE_MONITORING,
+            namespace=constants.NAMESPACE_MONITORING,
             name="node-feature-discovery",
-            repository=HELM_REPOSITORY_NODE_FEATURE_DISCOVERY,
+            repository=constants.HELM_REPOSITORY_NODE_FEATURE_DISCOVERY,
             chart="node-feature-discovery",
             version="0.11.2",
-            values=NODE_FEATURE_DISCOVERY_VALUES,
+            values=constants.HELM_RELEASE_NODE_FEATURE_DISCOVERY_VALUES,
         ),
         # openstack
-        v1.ApplyNamespaceTask(name=NAMESPACE_OPENSTACK),
+        v1.ApplyNamespaceTask(name=constants.NAMESPACE_OPENSTACK),
         flux.ApplyHelmRepositoryTask(
-            namespace=NAMESPACE_OPENSTACK,
-            name=HELM_REPOSITORY_BITNAMI,
+            namespace=constants.NAMESPACE_OPENSTACK,
+            name=constants.HELM_REPOSITORY_BITNAMI,
             url="https://charts.bitnami.com/bitnami",
         ),
         flux.ApplyHelmRepositoryTask(
-            namespace=NAMESPACE_OPENSTACK,
-            name=HELM_REPOSITORY_PERCONA,
+            namespace=constants.NAMESPACE_OPENSTACK,
+            name=constants.HELM_REPOSITORY_PERCONA,
             url="https://percona.github.io/percona-helm-charts/",
         ),
         flux.ApplyHelmReleaseTask(
-            namespace=NAMESPACE_OPENSTACK,
-            name="pxc-operator",
-            repository=HELM_REPOSITORY_PERCONA,
-            chart="pxc-operator",
-            version="1.10.0",
-            values=PERCONA_XTRADB_OPERATOR_VALUES,
+            namespace=constants.NAMESPACE_OPENSTACK,
+            name=constants.HELM_RELEASE_PXC_OPERATOR_NAME,
+            repository=constants.HELM_REPOSITORY_PERCONA,
+            chart=constants.HELM_RELEASE_PXC_OPERATOR_NAME,
+            version=constants.HELM_RELEASE_PXC_OPERATOR_VERSION,
+            values=constants.HELM_RELEASE_PXC_OPERATOR_VALUES,
+        ),
+        openstack_helm.ApplyPerconaXtraDBClusterTask(
+            namespace=constants.NAMESPACE_OPENSTACK,
         ),
         flux.ApplyHelmRepositoryTask(
-            namespace=NAMESPACE_OPENSTACK,
-            name=HELM_REPOSITORY_INGRESS_NGINX,
+            namespace=constants.NAMESPACE_OPENSTACK,
+            name=constants.HELM_REPOSITORY_INGRESS_NGINX,
             url="https://kubernetes.github.io/ingress-nginx",
         ),
         flux.ApplyHelmRepositoryTask(
-            namespace=NAMESPACE_OPENSTACK,
-            name=HELM_REPOSITORY_OPENSTACK_HELM_INFRA,
+            namespace=constants.NAMESPACE_OPENSTACK,
+            name=constants.HELM_REPOSITORY_OPENSTACK_HELM_INFRA,
             url="https://tarballs.opendev.org/openstack/openstack-helm-infra/",
         ),
         flux.ApplyHelmRepositoryTask(
-            namespace=NAMESPACE_OPENSTACK,
-            name=HELM_REPOSITORY_COREDNS,
+            namespace=constants.NAMESPACE_OPENSTACK,
+            name=constants.HELM_REPOSITORY_COREDNS,
             url="https://coredns.github.io/helm",
         ),
         flux.ApplyHelmRepositoryTask(
-            namespace=NAMESPACE_OPENSTACK,
-            name=HELM_REPOSITORY_OPENSTACK_HELM,
+            namespace=constants.NAMESPACE_OPENSTACK,
+            name=constants.HELM_REPOSITORY_OPENSTACK_HELM,
             url="https://tarballs.opendev.org/openstack/openstack-helm/",
         ),
     )
@@ -114,16 +100,16 @@
     if CONF.memcached.enabled:
         flow.add(
             openstack_helm.ApplyReleaseSecretTask(
-                namespace=NAMESPACE_OPENSTACK, chart="memcached"
+                namespace=constants.NAMESPACE_OPENSTACK, chart="memcached"
             ),
             openstack_helm.ApplyHelmReleaseTask(
-                namespace=NAMESPACE_OPENSTACK,
-                repository=HELM_REPOSITORY_OPENSTACK_HELM_INFRA,
+                namespace=constants.NAMESPACE_OPENSTACK,
+                repository=constants.HELM_REPOSITORY_OPENSTACK_HELM_INFRA,
                 name="memcached",
                 version="0.1.12",
             ),
             v1.ApplyServiceTask(
-                namespace=NAMESPACE_OPENSTACK,
+                namespace=constants.NAMESPACE_OPENSTACK,
                 name="memcached-metrics",
                 labels={
                     "application": "memcached",
diff --git a/atmosphere/tasks/composite/openstack_helm.py b/atmosphere/tasks/composite/openstack_helm.py
index b8a0332..76501cc 100644
--- a/atmosphere/tasks/composite/openstack_helm.py
+++ b/atmosphere/tasks/composite/openstack_helm.py
@@ -1,5 +1,8 @@
+import pykube
+
 from atmosphere.models.openstack_helm import values
-from atmosphere.tasks.kubernetes import flux, v1
+from atmosphere.tasks import constants
+from atmosphere.tasks.kubernetes import base, flux, v1
 
 
 class ApplyReleaseSecretTask(v1.ApplySecretTask):
@@ -35,3 +38,83 @@
             ],
             requires=set([f"secret-{namespace}-atmosphere-{name}"]),
         )
+
+
+class PerconaXtraDBCluster(pykube.objects.NamespacedAPIObject):
+    version = "pxc.percona.com/v1-10-0"
+    endpoint = "perconaxtradbclusters"
+    kind = "PerconaXtraDBCluster"
+
+
+class ApplyPerconaXtraDBClusterTask(base.ApplyKubernetesObjectTask):
+    def __init__(self, namespace: str):
+        super().__init__(
+            kind=PerconaXtraDBCluster,
+            namespace=namespace,
+            name="percona-xtradb",
+            requires=[
+                f"helm-release-{namespace}-{constants.HELM_RELEASE_PXC_OPERATOR_NAME}",
+                "name",
+            ],
+            inject={"name": "percona-xtradb"},
+        )
+
+    def generate_object(self, namespace, name, **kwargs) -> PerconaXtraDBCluster:
+        return PerconaXtraDBCluster(
+            self.api,
+            {
+                "apiVersion": self._obj_kind.version,
+                "kind": self._obj_kind.kind,
+                "metadata": {
+                    "name": name,
+                    "namespace": namespace.name,
+                },
+                "spec": {
+                    "crVersion": "1.10.0",
+                    "secretsName": "percona-xtradb",
+                    "pxc": {
+                        "size": 3,
+                        "image": "percona/percona-xtradb-cluster:5.7.39-31.61",
+                        "autoRecovery": True,
+                        "configuration": "[mysqld]\nmax_connections=8192\n",
+                        "sidecars": [
+                            {
+                                "name": "exporter",
+                                "image": "quay.io/prometheus/mysqld-exporter:v0.14.0",
+                                "ports": [{"name": "metrics", "containerPort": 9104}],
+                                "livenessProbe": {
+                                    "httpGet": {"path": "/", "port": 9104}
+                                },
+                                "env": [
+                                    {
+                                        "name": "MONITOR_PASSWORD",
+                                        "valueFrom": {
+                                            "secretKeyRef": {
+                                                "name": "percona-xtradb",
+                                                "key": "monitor",
+                                            }
+                                        },
+                                    },
+                                    {
+                                        "name": "DATA_SOURCE_NAME",
+                                        "value": "monitor:$(MONITOR_PASSWORD)@(localhost:3306)/",
+                                    },
+                                ],
+                            }
+                        ],
+                        "nodeSelector": constants.NODE_SELECTOR_CONTROL_PLANE,
+                        "volumeSpec": {
+                            "persistentVolumeClaim": {
+                                "resources": {"requests": {"storage": "160Gi"}}
+                            }
+                        },
+                    },
+                    "haproxy": {
+                        "enabled": True,
+                        "size": 3,
+                        "image": "percona/percona-xtradb-cluster-operator:1.10.0-haproxy",
+                        "nodeSelector": {"openstack-control-plane": "enabled"},
+                    },
+                },
+            },
+        )
diff --git a/atmosphere/tasks/constants.py b/atmosphere/tasks/constants.py
new file mode 100644
index 0000000..531a065
--- /dev/null
+++ b/atmosphere/tasks/constants.py
@@ -0,0 +1,29 @@
+NODE_SELECTOR_CONTROL_PLANE = {
+    "openstack-control-plane": "enabled",
+}
+
+NAMESPACE_CERT_MANAGER = "cert-manager"
+NAMESPACE_KUBE_SYSTEM = "kube-system"
+NAMESPACE_MONITORING = "monitoring"
+NAMESPACE_OPENSTACK = "openstack"
+
+HELM_REPOSITORY_BITNAMI = "bitnami"
+HELM_REPOSITORY_CEPH = "ceph"
+HELM_REPOSITORY_COREDNS = "coredns"
+HELM_REPOSITORY_INGRESS_NGINX = "ingress-nginx"
+HELM_REPOSITORY_JETSTACK = "jetstack"
+HELM_REPOSITORY_NODE_FEATURE_DISCOVERY = "node-feature-discovery"
+HELM_REPOSITORY_OPENSTACK_HELM = "openstack-helm"
+HELM_REPOSITORY_OPENSTACK_HELM_INFRA = "openstack-helm-infra"
+HELM_REPOSITORY_PERCONA = "percona"
+HELM_REPOSITORY_PROMETHEUS_COMMUINTY = "prometheus-community"
+
+HELM_RELEASE_NODE_FEATURE_DISCOVERY_VALUES = {
+    "master": {"nodeSelector": NODE_SELECTOR_CONTROL_PLANE}
+}
+
+HELM_RELEASE_PXC_OPERATOR_NAME = "pxc-operator"
+HELM_RELEASE_PXC_OPERATOR_VERSION = "1.10.0"
+HELM_RELEASE_PXC_OPERATOR_VALUES = {
+    "nodeSelector": NODE_SELECTOR_CONTROL_PLANE,
+}
diff --git a/atmosphere/tasks/kubernetes/base.py b/atmosphere/tasks/kubernetes/base.py
index f4dc47a..c675307 100644
--- a/atmosphere/tasks/kubernetes/base.py
+++ b/atmosphere/tasks/kubernetes/base.py
@@ -46,11 +46,16 @@
         )
         if self._obj_namespace:
             log = log.bind(namespace=self._obj_namespace)
+        if self.requires:
+            log = log.bind(requires=list(self.requires))
         return log
 
     def generate_object(self, *args, **kwargs) -> pykube.objects.APIObject:
         raise NotImplementedError
 
+    def wait_for_resource(self, resource: pykube.objects.APIObject):
+        pass
+
     def execute(self, *args, **kwargs):
         self.logger.debug("Ensuring resource")
 
@@ -71,6 +76,8 @@
         resource.api.raise_for_status(resp)
         resource.set_obj(resp.json())
 
+        self.wait_for_resource(resource)
+
         self.logger.info("Ensured resource")
 
         return {
diff --git a/atmosphere/tasks/kubernetes/flux.py b/atmosphere/tasks/kubernetes/flux.py
index 91ff59d..027c5b4 100644
--- a/atmosphere/tasks/kubernetes/flux.py
+++ b/atmosphere/tasks/kubernetes/flux.py
@@ -1,4 +1,6 @@
 import pykube
+from oslo_utils import strutils
+from tenacity import retry, retry_if_result, stop_after_delay
 
 from atmosphere import logger
 from atmosphere.tasks.kubernetes import base
@@ -140,13 +142,13 @@
             },
         )
 
-    def update_object(
-        self,
-        resource: HelmRelease,
-        values: dict = {},
-        values_from: list = [],
-        *args,
-        **kwargs,
-    ):
-        resource.obj["spec"]["values"] = values
-        resource.obj["spec"]["valuesFrom"] = values_from
+    @retry(retry=retry_if_result(lambda f: f is False), stop=stop_after_delay(30))
+    def wait_for_resource(self, resource: HelmRelease, *args, **kwargs) -> bool:
+        resource.reload()
+
+        conditions = {
+            condition["type"]: strutils.bool_from_string(condition["status"])
+            for condition in resource.obj["status"].get("conditions", [])
+        }
+
+        return conditions.get("Ready", False) and conditions.get("Released", False)
diff --git a/atmosphere/tests/integration/test_deploy.py b/atmosphere/tests/integration/test_deploy.py
index 8b9c5fa..dc2d45e 100644
--- a/atmosphere/tests/integration/test_deploy.py
+++ b/atmosphere/tests/integration/test_deploy.py
@@ -1,6 +1,5 @@
 import confspirator
 import pykube
-import taskflow.engines
 
 from atmosphere import flows
 from atmosphere.config import CONF
@@ -15,7 +14,7 @@
 
     flux_cluster.kubectl("create", "namespace", "openstack")
 
-    engine = taskflow.engines.load(flows.get_deployment_flow())
+    engine = flows.get_engine()
     engine.run()
 
     initial_memcache_secret = pykube.Secret.objects(
@@ -31,7 +30,7 @@
             ],
         },
     ):
-        engine = taskflow.engines.load(flows.get_deployment_flow())
+        engine = flows.get_engine()
         engine.run()
 
     updated_memcache_secret = pykube.Secret.objects(
diff --git a/playbooks/openstack.yml b/playbooks/openstack.yml
index 45eb83e..c1da7f5 100644
--- a/playbooks/openstack.yml
+++ b/playbooks/openstack.yml
@@ -64,10 +64,6 @@
       tags:
         - keepalived
 
-    - role: percona_xtradb_cluster
-      tags:
-        - percona-xtradb-cluster
-
     - role: rabbitmq_operator
       tags:
         - rabbitmq-operator
diff --git a/poetry.lock b/poetry.lock
index e629795..613801f 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -224,6 +224,22 @@
 wrapt = ">=1.7.0"
 
 [[package]]
+name = "dnspython"
+version = "2.2.1"
+description = "DNS toolkit"
+category = "main"
+optional = false
+python-versions = ">=3.6,<4.0"
+
+[package.extras]
+curio = ["curio (>=1.2,<2.0)", "sniffio (>=1.1,<2.0)"]
+dnssec = ["cryptography (>=2.6,<37.0)"]
+doh = ["h2 (>=4.1.0)", "httpx (>=0.21.1)", "requests (>=2.23.0,<3.0.0)", "requests-toolbelt (>=0.9.1,<0.10.0)"]
+idna = ["idna (>=2.1,<4.0)"]
+trio = ["trio (>=0.14,<0.20)"]
+wmi = ["wmi (>=1.5.1,<2.0.0)"]
+
+[[package]]
 name = "enrich"
 version = "1.2.7"
 description = "enrich"
@@ -238,6 +254,19 @@
 test = ["mock (>=3.0.5)", "pytest (>=5.4.0)", "pytest-cov (>=2.7.1)", "pytest-mock (>=3.3.1)", "pytest-plus", "pytest-xdist (>=1.29.0)"]
 
 [[package]]
+name = "eventlet"
+version = "0.33.1"
+description = "Highly concurrent networking library"
+category = "main"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+dnspython = ">=1.15.0"
+greenlet = ">=0.3"
+six = ">=1.10.0"
+
+[[package]]
 name = "fasteners"
 version = "0.18"
 description = "A python package that provides useful locks"
@@ -282,6 +311,17 @@
 python-versions = ">=3.6"
 
 [[package]]
+name = "greenlet"
+version = "1.1.3"
+description = "Lightweight in-process concurrent programming"
+category = "main"
+optional = false
+python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*"
+
+[package.extras]
+docs = ["Sphinx"]
+
+[[package]]
 name = "idna"
 version = "3.4"
 description = "Internationalized Domain Names in Applications (IDNA)"
@@ -1023,7 +1063,7 @@
 [metadata]
 lock-version = "1.1"
 python-versions = "^3.10"
-content-hash = "809d8297ae7633cbd5137a97295d6c6ced139626b8174c6360c0cb2cb23c09e2"
+content-hash = "2467ec3e1730d789b4b33c269da9c86b57a804c7560c78eeb05dd08784da4017"
 
 [metadata.files]
 ansible-compat = [
@@ -1149,10 +1189,18 @@
     {file = "debtcollector-2.5.0-py3-none-any.whl", hash = "sha256:1393a527d2c72f143ffa6a629e9c33face6642634eece475b48cab7b04ba61f3"},
     {file = "debtcollector-2.5.0.tar.gz", hash = "sha256:dc9d1ad3f745c43f4bbedbca30f9ffe8905a8c028c9926e61077847d5ea257ab"},
 ]
+dnspython = [
+    {file = "dnspython-2.2.1-py3-none-any.whl", hash = "sha256:a851e51367fb93e9e1361732c1d60dab63eff98712e503ea7d92e6eccb109b4f"},
+    {file = "dnspython-2.2.1.tar.gz", hash = "sha256:0f7569a4a6ff151958b64304071d370daa3243d15941a7beedf0c9fe5105603e"},
+]
 enrich = [
     {file = "enrich-1.2.7-py3-none-any.whl", hash = "sha256:f29b2c8c124b4dbd7c975ab5c3568f6c7a47938ea3b7d2106c8a3bd346545e4f"},
     {file = "enrich-1.2.7.tar.gz", hash = "sha256:0a2ab0d2931dff8947012602d1234d2a3ee002d9a355b5d70be6bf5466008893"},
 ]
+eventlet = [
+    {file = "eventlet-0.33.1-py2.py3-none-any.whl", hash = "sha256:a085922698e5029f820cf311a648ac324d73cec0e4792877609d978a4b5bbf31"},
+    {file = "eventlet-0.33.1.tar.gz", hash = "sha256:afbe17f06a58491e9aebd7a4a03e70b0b63fd4cf76d8307bae07f280479b1515"},
+]
 fasteners = [
     {file = "fasteners-0.18-py3-none-any.whl", hash = "sha256:1d4caf5f8db57b0e4107d94fd5a1d02510a450dced6ca77d1839064c1bacf20c"},
     {file = "fasteners-0.18.tar.gz", hash = "sha256:cb7c13ef91e0c7e4fe4af38ecaf6b904ec3f5ce0dda06d34924b6b74b869d953"},
@@ -1169,6 +1217,62 @@
     {file = "futurist-2.4.1-py3-none-any.whl", hash = "sha256:3ef3a1f63eca3c4f6ebc8f4cff0bb1492241a0df93622e0bf3e6e90ca822e0e0"},
     {file = "futurist-2.4.1.tar.gz", hash = "sha256:9c1760a877c0fe3260d04b6a6d4352a6d25ac58e483f1d6cd495e33dc3740ff7"},
 ]
+greenlet = [
+    {file = "greenlet-1.1.3-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:8c287ae7ac921dfde88b1c125bd9590b7ec3c900c2d3db5197f1286e144e712b"},
+    {file = "greenlet-1.1.3-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:870a48007872d12e95a996fca3c03a64290d3ea2e61076aa35d3b253cf34cd32"},
+    {file = "greenlet-1.1.3-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:7c5227963409551ae4a6938beb70d56bf1918c554a287d3da6853526212fbe0a"},
+    {file = "greenlet-1.1.3-cp27-cp27m-win32.whl", hash = "sha256:9fae214f6c43cd47f7bef98c56919b9222481e833be2915f6857a1e9e8a15318"},
+    {file = "greenlet-1.1.3-cp27-cp27m-win_amd64.whl", hash = "sha256:de431765bd5fe62119e0bc6bc6e7b17ac53017ae1782acf88fcf6b7eae475a49"},
+    {file = "greenlet-1.1.3-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:510c3b15587afce9800198b4b142202b323bf4b4b5f9d6c79cb9a35e5e3c30d2"},
+    {file = "greenlet-1.1.3-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:9951dcbd37850da32b2cb6e391f621c1ee456191c6ae5528af4a34afe357c30e"},
+    {file = "greenlet-1.1.3-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:07c58e169bbe1e87b8bbf15a5c1b779a7616df9fd3e61cadc9d691740015b4f8"},
+    {file = "greenlet-1.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df02fdec0c533301497acb0bc0f27f479a3a63dcdc3a099ae33a902857f07477"},
+    {file = "greenlet-1.1.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c88e134d51d5e82315a7c32b914a58751b7353eb5268dbd02eabf020b4c4700"},
+    {file = "greenlet-1.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b41d19c0cfe5c259fe6c539fd75051cd39a5d33d05482f885faf43f7f5e7d26"},
+    {file = "greenlet-1.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:6f5d4b2280ceea76c55c893827961ed0a6eadd5a584a7c4e6e6dd7bc10dfdd96"},
+    {file = "greenlet-1.1.3-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:184416e481295832350a4bf731ba619a92f5689bf5d0fa4341e98b98b1265bd7"},
+    {file = "greenlet-1.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd0404d154084a371e6d2bafc787201612a1359c2dee688ae334f9118aa0bf47"},
+    {file = "greenlet-1.1.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7a43bbfa9b6cfdfaeefbd91038dde65ea2c421dc387ed171613df340650874f2"},
+    {file = "greenlet-1.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce5b64dfe8d0cca407d88b0ee619d80d4215a2612c1af8c98a92180e7109f4b5"},
+    {file = "greenlet-1.1.3-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:903fa5716b8fbb21019268b44f73f3748c41d1a30d71b4a49c84b642c2fed5fa"},
+    {file = "greenlet-1.1.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:0118817c9341ef2b0f75f5af79ac377e4da6ff637e5ee4ac91802c0e379dadb4"},
+    {file = "greenlet-1.1.3-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:466ce0928e33421ee84ae04c4ac6f253a3a3e6b8d600a79bd43fd4403e0a7a76"},
+    {file = "greenlet-1.1.3-cp35-cp35m-win32.whl", hash = "sha256:65ad1a7a463a2a6f863661329a944a5802c7129f7ad33583dcc11069c17e622c"},
+    {file = "greenlet-1.1.3-cp35-cp35m-win_amd64.whl", hash = "sha256:7532a46505470be30cbf1dbadb20379fb481244f1ca54207d7df3bf0bbab6a20"},
+    {file = "greenlet-1.1.3-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:caff52cb5cd7626872d9696aee5b794abe172804beb7db52eed1fd5824b63910"},
+    {file = "greenlet-1.1.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:db41f3845eb579b544c962864cce2c2a0257fe30f0f1e18e51b1e8cbb4e0ac6d"},
+    {file = "greenlet-1.1.3-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e8533f5111704d75de3139bf0b8136d3a6c1642c55c067866fa0a51c2155ee33"},
+    {file = "greenlet-1.1.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9537e4baf0db67f382eb29255a03154fcd4984638303ff9baaa738b10371fa57"},
+    {file = "greenlet-1.1.3-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8bfd36f368efe0ab2a6aa3db7f14598aac454b06849fb633b762ddbede1db90"},
+    {file = "greenlet-1.1.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0877a9a2129a2c56a2eae2da016743db7d9d6a05d5e1c198f1b7808c602a30e"},
+    {file = "greenlet-1.1.3-cp36-cp36m-win32.whl", hash = "sha256:88b04e12c9b041a1e0bcb886fec709c488192638a9a7a3677513ac6ba81d8e79"},
+    {file = "greenlet-1.1.3-cp36-cp36m-win_amd64.whl", hash = "sha256:4f166b4aca8d7d489e82d74627a7069ab34211ef5ebb57c300ec4b9337b60fc0"},
+    {file = "greenlet-1.1.3-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:cd16a89efe3a003029c87ff19e9fba635864e064da646bc749fc1908a4af18f3"},
+    {file = "greenlet-1.1.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5b756e6730ea59b2745072e28ad27f4c837084688e6a6b3633c8b1e509e6ae0e"},
+    {file = "greenlet-1.1.3-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:9b2f7d0408ddeb8ea1fd43d3db79a8cefaccadd2a812f021333b338ed6b10aba"},
+    {file = "greenlet-1.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44b4817c34c9272c65550b788913620f1fdc80362b209bc9d7dd2f40d8793080"},
+    {file = "greenlet-1.1.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d58a5a71c4c37354f9e0c24c9c8321f0185f6945ef027460b809f4bb474bfe41"},
+    {file = "greenlet-1.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1dd51d2650e70c6c4af37f454737bf4a11e568945b27f74b471e8e2a9fd21268"},
+    {file = "greenlet-1.1.3-cp37-cp37m-win32.whl", hash = "sha256:048d2bed76c2aa6de7af500ae0ea51dd2267aec0e0f2a436981159053d0bc7cc"},
+    {file = "greenlet-1.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:77e41db75f9958f2083e03e9dd39da12247b3430c92267df3af77c83d8ff9eed"},
+    {file = "greenlet-1.1.3-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:1626185d938d7381631e48e6f7713e8d4b964be246073e1a1d15c2f061ac9f08"},
+    {file = "greenlet-1.1.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:1ec2779774d8e42ed0440cf8bc55540175187e8e934f2be25199bf4ed948cd9e"},
+    {file = "greenlet-1.1.3-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:f2f908239b7098799b8845e5936c2ccb91d8c2323be02e82f8dcb4a80dcf4a25"},
+    {file = "greenlet-1.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b181e9aa6cb2f5ec0cacc8cee6e5a3093416c841ba32c185c30c160487f0380"},
+    {file = "greenlet-1.1.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2cf45e339cabea16c07586306a31cfcc5a3b5e1626d365714d283732afed6809"},
+    {file = "greenlet-1.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6200a11f003ec26815f7e3d2ded01b43a3810be3528dd760d2f1fa777490c3cd"},
+    {file = "greenlet-1.1.3-cp38-cp38-win32.whl", hash = "sha256:db5b25265010a1b3dca6a174a443a0ed4c4ab12d5e2883a11c97d6e6d59b12f9"},
+    {file = "greenlet-1.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:095a980288fe05adf3d002fbb180c99bdcf0f930e220aa66fcd56e7914a38202"},
+    {file = "greenlet-1.1.3-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:cbc1eb55342cbac8f7ec159088d54e2cfdd5ddf61c87b8bbe682d113789331b2"},
+    {file = "greenlet-1.1.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:694ffa7144fa5cc526c8f4512665003a39fa09ef00d19bbca5c8d3406db72fbe"},
+    {file = "greenlet-1.1.3-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:aa741c1a8a8cc25eb3a3a01a62bdb5095a773d8c6a86470bde7f607a447e7905"},
+    {file = "greenlet-1.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3a669f11289a8995d24fbfc0e63f8289dd03c9aaa0cc8f1eab31d18ca61a382"},
+    {file = "greenlet-1.1.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76a53bfa10b367ee734b95988bd82a9a5f0038a25030f9f23bbbc005010ca600"},
+    {file = "greenlet-1.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fb0aa7f6996879551fd67461d5d3ab0c3c0245da98be90c89fcb7a18d437403"},
+    {file = "greenlet-1.1.3-cp39-cp39-win32.whl", hash = "sha256:5fbe1ab72b998ca77ceabbae63a9b2e2dc2d963f4299b9b278252ddba142d3f1"},
+    {file = "greenlet-1.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:ffe73f9e7aea404722058405ff24041e59d31ca23d1da0895af48050a07b6932"},
+    {file = "greenlet-1.1.3.tar.gz", hash = "sha256:bcb6c6dd1d6be6d38d6db283747d07fda089ff8c559a835236560a4410340455"},
+]
 idna = [
     {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
     {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
diff --git a/pyproject.toml b/pyproject.toml
index aa82023..43fef11 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -19,6 +19,7 @@
 better-exceptions = "^0.3.3"
 mergedeep = "^1.3.4"
 taskflow = "^5.0.0"
+eventlet = "^0.33.1"
 
 [tool.poetry.group.dev.dependencies]
 pytest = "^7.1.3"
diff --git a/roles/percona_xtradb_cluster/README.md b/roles/percona_xtradb_cluster/README.md
deleted file mode 100644
index 4ad8d78..0000000
--- a/roles/percona_xtradb_cluster/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# `percona_xtradb_cluster`
diff --git a/roles/percona_xtradb_cluster/meta/main.yml b/roles/percona_xtradb_cluster/meta/main.yml
deleted file mode 100644
index 596a60f..0000000
--- a/roles/percona_xtradb_cluster/meta/main.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (c) 2022 VEXXHOST, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-galaxy_info:
-  author: VEXXHOST, Inc.
-  description: Ansible role for Percona XtraDB Cluster
-  license: Apache-2.0
-  min_ansible_version: 5.5.0
-  standalone: false
-  platforms:
-    - name: Ubuntu
-      versions:
-        - focal
-
-dependencies:
-  - role: atmosphere
diff --git a/roles/percona_xtradb_cluster/tasks/main.yml b/roles/percona_xtradb_cluster/tasks/main.yml
deleted file mode 100644
index 71258e6..0000000
--- a/roles/percona_xtradb_cluster/tasks/main.yml
+++ /dev/null
@@ -1,98 +0,0 @@
-# Copyright (c) 2022 VEXXHOST, Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-- name: Deploy operator
-  kubernetes.core.k8s:
-    state: present
-    definition:
-      - apiVersion: helm.toolkit.fluxcd.io/v2beta1
-        kind: HelmRelease
-        metadata:
-          name: pxc-operator
-          namespace: openstack
-        spec:
-          interval: 60s
-          chart:
-            spec:
-              chart: pxc-operator
-              version: 1.10.0
-              sourceRef:
-                kind: HelmRepository
-                name: percona
-          install:
-            crds: CreateReplace
-          upgrade:
-            crds: CreateReplace
-          values:
-            nodeSelector:
-              openstack-control-plane: enabled
-
-- name: Deploy cluster
-  kubernetes.core.k8s:
-    state: present
-    definition:
-      - apiVersion: pxc.percona.com/v1-10-0
-        kind: PerconaXtraDBCluster
-        metadata:
-          name: percona-xtradb
-          namespace: openstack
-        spec:
-          crVersion: 1.10.0
-          secretsName: percona-xtradb
-          pxc:
-            size: 3
-            # NOTE(mnaser): https://jira.percona.com/browse/PXC-3914
-            image: us-docker.pkg.dev/vexxhost-infra/openstack/percona-xtradb-cluster:5.7.36-31.55-socatfix
-            autoRecovery: true
-            configuration: |
-              [mysqld]
-              max_connections=8192
-            sidecars:
-              - name: exporter
-                image: quay.io/prometheus/mysqld-exporter:v0.14.0
-                ports:
-                  - name: metrics
-                    containerPort: 9104
-                livenessProbe:
-                  httpGet:
-                    path: /
-                    port: 9104
-                env:
-                  - name: MONITOR_PASSWORD
-                    valueFrom:
-                      secretKeyRef:
-                        name: percona-xtradb
-                        key: monitor
-                  - name: DATA_SOURCE_NAME
-                    value: "monitor:$(MONITOR_PASSWORD)@(localhost:3306)/"
-            nodeSelector:
-              openstack-control-plane: enabled
-            volumeSpec:
-              persistentVolumeClaim:
-                resources:
-                  requests:
-                    storage: 160Gi
-          haproxy:
-            enabled: true
-            size: 3
-            image: percona/percona-xtradb-cluster-operator:1.10.0-haproxy
-            nodeSelector:
-              openstack-control-plane: enabled
-  # NOTE(mnaser): Since we haven't moved to the operator pattern yet, we need to
-  #               keep retrying a few times as the CRDs might not be installed
-  #               yet.
-  retries: 60
-  delay: 5
-  register: _result
-  until: _result is not failed