Implement tooling to sync Helm charts (#1105)

Signed-off-by: Mohammed Naser <mnaser@vexxhost.com>
diff --git a/.ansible-lint b/.ansible-lint
index c21cd67..99ed625 100644
--- a/.ansible-lint
+++ b/.ansible-lint
@@ -8,7 +8,6 @@
   - plugins/filter
   - roles/defaults/vars/main.yml
   - roles/kube_prometheus_stack/files/jsonnet
-  - vendir.lock.yml
 
 mock_roles:
   - opendev.container_registry
diff --git a/.charts.yml b/.charts.yml
new file mode 100644
index 0000000..a4ff95a
--- /dev/null
+++ b/.charts.yml
@@ -0,0 +1,269 @@
+charts:
+  - name: barbican
+    version: 0.3.6
+    repository:
+      url: https://tarballs.openstack.org/openstack-helm
+  - name: ceph-csi-rbd
+    version: 3.5.1
+    repository:
+      url: https://ceph.github.io/csi-charts
+  - name: ceph-provisioners
+    version: 0.1.8
+    repository:
+      url: https://tarballs.openstack.org/openstack-helm-infra
+  - name: godaddy-webhook
+    version: 0.3.0
+    repository:
+      url: https://snowdrop.github.io/godaddy-webhook
+  - name: cert-manager-webhook-infoblox-wapi
+    version: 1.5.2
+    repository:
+      url: https://luisico.github.io/cert-manager-webhook-infoblox-wapi
+  - name: cinder
+    version: 0.3.15
+    repository:
+      url: https://tarballs.openstack.org/openstack-helm
+    dependencies:
+      - name: helm-toolkit
+        repository: https://tarballs.openstack.org/openstack-helm-infra
+        version: 0.2.55
+    patches:
+      gerrit:
+        review.opendev.org:
+          - 899814
+  - name: coredns
+    version: 1.19.4
+    repository:
+      url: https://coredns.github.io/helm
+  - name: designate
+    version: 0.2.9
+    repository:
+      url: https://tarballs.openstack.org/openstack-helm
+    dependencies:
+      - name: helm-toolkit
+        repository: https://tarballs.openstack.org/openstack-helm-infra
+        version: 0.2.55
+    patches:
+      gerrit:
+        review.opendev.org:
+          - 899932
+  - name: glance
+    version: 0.4.15
+    repository:
+      url: https://tarballs.openstack.org/openstack-helm
+    dependencies:
+      - name: helm-toolkit
+        repository: https://tarballs.openstack.org/openstack-helm-infra
+        version: 0.2.55
+    patches:
+      gerrit:
+        review.opendev.org:
+          - 899864
+  - name: heat
+    version: 0.3.7
+    repository:
+      url: https://tarballs.openstack.org/openstack-helm
+    dependencies:
+      - name: helm-toolkit
+        repository: https://tarballs.openstack.org/openstack-helm-infra
+        version: 0.2.55
+    patches:
+      gerrit:
+        review.opendev.org:
+          - 899931
+  - name: horizon
+    version: 0.3.15
+    repository:
+      url: https://tarballs.openstack.org/openstack-helm
+    dependencies:
+      - name: helm-toolkit
+        repository: https://tarballs.openstack.org/openstack-helm-infra
+        version: 0.2.55
+  - name: ingress-nginx
+    version: 4.0.17
+    repository:
+      url: https://kubernetes.github.io/ingress-nginx
+  - name: keycloak
+    version: 16.0.3
+    repository:
+      url: https://charts.bitnami.com/bitnami
+  - name: keystone
+    version: 0.3.5
+    repository:
+      url: https://tarballs.openstack.org/openstack-helm
+    dependencies:
+      - name: helm-toolkit
+        repository: https://tarballs.openstack.org/openstack-helm-infra
+        version: 0.2.55
+    patches:
+      gerrit:
+        review.opendev.org:
+          - 899867
+  - name: kube-prometheus-stack
+    version: 58.0.0
+    repository:
+      url: https://prometheus-community.github.io/helm-charts
+  - name: libvirt
+    version: 0.1.27
+    repository:
+      url: https://tarballs.openstack.org/openstack-helm-infra
+    dependencies:
+      - name: helm-toolkit
+        repository: https://tarballs.openstack.org/openstack-helm-infra
+        version: 0.2.56
+    patches:
+      gerrit:
+        review.opendev.org:
+          - 893406
+  - name: loki
+    version: 5.47.2
+    repository:
+      url: https://grafana.github.io/helm-charts
+  - name: magnum
+    version: 0.2.9
+    repository:
+      url: https://tarballs.openstack.org/openstack-helm
+    dependencies:
+      - name: helm-toolkit
+        repository: https://tarballs.openstack.org/openstack-helm-infra
+        version: 0.2.55
+    patches:
+      gerrit:
+        review.opendev.org:
+          - 899926
+  - name: manila
+    version: 0.1.7
+    repository:
+      url: https://tarballs.openstack.org/openstack-helm
+    dependencies:
+      - name: helm-toolkit
+        repository: https://tarballs.openstack.org/openstack-helm-infra
+        version: 0.2.55
+    patches:
+      gerrit:
+        review.opendev.org:
+          - 883168
+          - 899923
+  - name: memcached
+    version: 0.1.12
+    repository:
+      url: https://tarballs.openstack.org/openstack-helm-infra
+  - name: neutron
+    version: 0.3.29
+    repository:
+      url: https://tarballs.openstack.org/openstack-helm
+    dependencies:
+      - name: helm-toolkit
+        repository: https://tarballs.openstack.org/openstack-helm-infra
+        version: 0.2.55
+    patches:
+      gerrit:
+        review.opendev.org:
+          - 902767
+          - 914886
+  - name: node-feature-discovery
+    version: 0.11.2
+    repository:
+      url: https://kubernetes-sigs.github.io/node-feature-discovery/charts
+  - name: nova
+    version: 0.3.27
+    repository:
+      url: https://tarballs.openstack.org/openstack-helm
+    dependencies:
+      - name: helm-toolkit
+        repository: https://tarballs.openstack.org/openstack-helm-infra
+        version: 0.2.55
+    patches:
+      gerrit:
+        review.opendev.org:
+          - 899809
+          - 904250
+  - name: octavia
+    version: 0.2.9
+    repository:
+      url: https://tarballs.openstack.org/openstack-helm
+    dependencies:
+      - name: helm-toolkit
+        repository: https://tarballs.openstack.org/openstack-helm-infra
+        version: 0.2.55
+    patches:
+      gerrit:
+        review.opendev.org:
+          - 899918
+  - name: openvswitch
+    version: 0.1.19
+    repository:
+      url: https://tarballs.openstack.org/openstack-helm-infra
+    dependencies:
+      - name: helm-toolkit
+        repository: https://tarballs.openstack.org/openstack-helm-infra
+        version: 0.2.56
+  - name: ovn
+    version: 0.1.4
+    repository:
+      url: https://tarballs.openstack.org/openstack-helm-infra
+    dependencies:
+      - name: helm-toolkit
+        repository: https://tarballs.openstack.org/openstack-helm-infra
+        version: 0.2.56
+    patches:
+      gerrit:
+        review.opendev.org:
+          - 893739
+          - 914807
+  - name: placement
+    version: 0.3.9
+    repository:
+      url: https://tarballs.openstack.org/openstack-helm
+    dependencies:
+      - name: helm-toolkit
+        repository: https://tarballs.openstack.org/openstack-helm-infra
+        version: 0.2.55
+    patches:
+      gerrit:
+        review.opendev.org:
+          - 899914
+  - name: prometheus-pushgateway
+    version: 1.16.0
+    repository:
+      url: https://prometheus-community.github.io/helm-charts
+  - name: pxc-operator
+    version: 1.13.3
+    repository:
+      url: https://percona.github.io/percona-helm-charts
+  - name: rabbitmq-cluster-operator
+    version: 2.6.6
+    repository:
+      url: https://charts.bitnami.com/bitnami
+  - name: rook-ceph
+    version: 1.10.10
+    repository:
+      url: https://charts.rook.io/release
+  - name: rook-ceph-cluster
+    version: 1.10.10
+    repository:
+      url: https://charts.rook.io/release
+  - name: senlin
+    version: 0.2.9
+    repository:
+      url: https://tarballs.openstack.org/openstack-helm
+    dependencies:
+      - name: helm-toolkit
+        repository: https://tarballs.openstack.org/openstack-helm-infra
+        version: 0.2.55
+    patches:
+      gerrit:
+        review.opendev.org:
+          - 899913
+  - name: tempest
+    version: 0.2.8
+    repository:
+      url: https://tarballs.openstack.org/openstack-helm
+    dependencies:
+      - name: helm-toolkit
+        repository: https://tarballs.openstack.org/openstack-helm-infra
+        version: 0.2.55
+  - name: vector
+    version: 0.32.0
+    repository:
+      url: https://vectordotdev.github.io/helm-charts
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
deleted file mode 100644
index 5ef716e..0000000
--- a/.github/workflows/lint.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-name: lint
-on:
-  pull_request:
-
-jobs:
-  Pre-commit:
-    runs-on: ubuntu-latest
-    steps:
-      - name: Checkout project
-        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
-
-      - name: Setup Python
-        uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5
-
-      - name: Get Python info
-        id: python_info
-        run: echo info=$(python -VV | sha256sum | cut -d' ' -f1) >> $GITHUB_OUTPUT
-
-      - name: Create pre-commit cache
-        uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4
-        with:
-          path: ~/.cache/pre-commit
-          key: pre-commit|${{ steps.python_info.outputs.info }}|${{ hashFiles('.pre-commit-config.yaml') }}
-
-      - name: Setup pre-commit
-        uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 60a0756..f42c49e 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -9,24 +9,17 @@
       - id: trailing-whitespace
         exclude: ^images/.*/patches/.*\.patch$
 
-  - repo: https://github.com/compilerla/conventional-pre-commit
-    rev: v2.0.0
-    hooks:
-      - id: conventional-pre-commit
-        stages:
-          - commit-msg
-
   - repo: https://github.com/psf/black
-    rev: 22.8.0
+    rev: 24.4.0
     hooks:
       - id: black
 
   - repo: https://github.com/pycqa/flake8
-    rev: 5.0.4
+    rev: 7.0.0
     hooks:
       - id: flake8
 
   - repo: https://github.com/pycqa/isort
-    rev: 5.12.0
+    rev: 5.13.2
     hooks:
       - id: isort
diff --git a/build/sync-charts.py b/build/sync-charts.py
new file mode 100644
index 0000000..ce32da0
--- /dev/null
+++ b/build/sync-charts.py
@@ -0,0 +1,273 @@
+# Copyright (c) 2024 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.
+
+import asyncio
+import os
+import pathlib
+import textwrap
+from datetime import datetime, timezone
+
+import aiopath
+import aioshutil
+import platformdirs
+from asynctempfile import NamedTemporaryFile
+from gerrit import GerritClient
+from pydantic import BaseModel, HttpUrl, PrivateAttr
+from pydantic_yaml import parse_yaml_file_as, to_yaml_file
+
+
+class ChartRepository(BaseModel):
+    url: HttpUrl
+
+    @property
+    def name(self):
+        return self.url.host.replace(".", "-") + self.url.path.replace("/", "-")
+
+
+class ChartPatches(BaseModel):
+    gerrit: dict[str, list[int]] = {}
+
+
+class ChartDependency(BaseModel):
+    name: str
+    repository: HttpUrl
+    version: str
+
+
+class ChartRequirements(BaseModel):
+    dependencies: list[ChartDependency] = []
+
+
+class ChartLock(BaseModel):
+    dependencies: list[ChartDependency] = []
+    digest: str
+    generated: datetime
+
+    class Config:
+        json_encoders = {
+            "generated": lambda dt: dt.isoformat(),
+        }
+
+
+class Chart(BaseModel):
+    name: str
+    version: str
+    repository: ChartRepository
+    dependencies: list[ChartDependency] = []
+    patches: ChartPatches = ChartPatches()
+
+
+async def patch(input: bytes, path: aiopath.AsyncPath):
+    async with NamedTemporaryFile() as temp_file:
+        await temp_file.write(
+            textwrap.dedent(
+                f"""\
+                {path.name}/*
+                """
+            )
+            .strip()
+            .encode()
+        )
+        await temp_file.flush()
+
+        proc = await asyncio.create_subprocess_shell(
+            f"filterdiff -p1 -I {temp_file.name}",
+            stdin=asyncio.subprocess.PIPE,
+            stdout=asyncio.subprocess.PIPE,
+            stderr=asyncio.subprocess.PIPE,
+        )
+        stdout, stderr = await proc.communicate(input=input)
+        if proc.returncode != 0:
+            raise Exception(stderr)
+
+    async with NamedTemporaryFile() as temp_file:
+        await temp_file.write(
+            textwrap.dedent(
+                f"""\
+                {path.name}/Chart.yaml
+                """
+            )
+            .strip()
+            .encode()
+        )
+        await temp_file.flush()
+
+        proc = await asyncio.create_subprocess_shell(
+            f"filterdiff -p1 -X {temp_file.name}",
+            stdin=asyncio.subprocess.PIPE,
+            stdout=asyncio.subprocess.PIPE,
+            stderr=asyncio.subprocess.PIPE,
+        )
+        stdout, stderr = await proc.communicate(input=stdout)
+        if proc.returncode != 0:
+            raise Exception(stderr)
+
+    proc = await asyncio.create_subprocess_shell(
+        f"patch -p2 -d {path} -E",
+        stdin=asyncio.subprocess.PIPE,
+        stdout=asyncio.subprocess.PIPE,
+        stderr=asyncio.subprocess.PIPE,
+    )
+    stdout, stderr = await proc.communicate(input=stdout)
+    if proc.returncode != 0:
+        raise Exception(stdout)
+
+
+class Config(BaseModel):
+    charts: list[Chart]
+
+    _workspace: pathlib.Path = PrivateAttr(
+        default=pathlib.Path(
+            platformdirs.user_cache_dir("atmosphere-sync-charts", "vexxhost")
+        )
+    )
+
+    @property
+    def repositories(self):
+        repositories = []
+
+        for chart in self.charts:
+            if chart.repository in repositories:
+                continue
+            repositories.append(chart.repository)
+
+        return repositories
+
+    async def _helm(self, args: list[str]):
+        proc = await asyncio.create_subprocess_shell(
+            f"helm {' '.join(args)}",
+            env={**dict(os.environ), **{"HOME": str(self._workspace)}},
+        )
+        await proc.communicate()
+        if proc.returncode != 0:
+            raise Exception(f"helm {' '.join(args)} failed")
+
+    async def _fetch_chart(self, chart: Chart, path="charts"):
+        charts_path: aiopath.AsyncPath = aiopath.AsyncPath(path)
+        chart_path = charts_path / chart.name
+
+        try:
+            await aioshutil.rmtree(f"{path}/{chart.name}-{chart.version}")
+        except FileNotFoundError:
+            pass
+
+        try:
+            try:
+                os.rename(
+                    f"{path}/{chart.name}", f"{path}/{chart.name}-{chart.version}"
+                )
+            except FileNotFoundError:
+                pass
+
+            await self._helm(
+                [
+                    "fetch",
+                    "--untar",
+                    f"--destination={path}",
+                    f"{chart.repository.name}/{chart.name}",
+                    f"--version={chart.version}",
+                ]
+            )
+        except Exception:
+            os.rename(f"{path}/{chart.name}-{chart.version}", f"{path}/{chart.name}")
+            raise
+
+        try:
+            await aioshutil.rmtree(f"{path}/{chart.name}-{chart.version}")
+        except FileNotFoundError:
+            pass
+
+        if chart.dependencies:
+            requirements = ChartRequirements(dependencies=chart.dependencies)
+            to_yaml_file(f"{path}/{chart.name}/requirements.yaml", requirements)
+
+            await asyncio.gather(
+                *[
+                    aioshutil.rmtree(f"{path}/{chart.name}/charts/{req.name}")
+                    for req in chart.dependencies
+                ]
+            )
+
+            await self._helm(
+                ["dependency", "update", "--skip-refresh", f"{path}/{chart.name}"]
+            )
+
+            await asyncio.gather(
+                *[
+                    aioshutil.unpack_archive(
+                        f"{path}/{chart.name}/charts/{req.name}-{req.version}.tgz",
+                        f"{path}/{chart.name}/charts",
+                    )
+                    for req in chart.dependencies
+                ]
+            )
+
+            await asyncio.gather(
+                *[
+                    (chart_path / "charts" / f"{req.name}-{req.version}.tgz").unlink()
+                    for req in chart.dependencies
+                ]
+            )
+
+            for req in chart.dependencies:
+                lock = parse_yaml_file_as(
+                    ChartLock,
+                    f"{path}/{chart.name}/charts/{req.name}/requirements.lock",
+                )
+                lock.generated = datetime.min.replace(tzinfo=timezone.utc)
+                to_yaml_file(
+                    f"{path}/{chart.name}/charts/{req.name}/requirements.lock", lock
+                )
+
+            # Reset the generated time in the lock file to make things reproducible
+            lock = parse_yaml_file_as(
+                ChartLock, f"{path}/{chart.name}/requirements.lock"
+            )
+            lock.generated = datetime.min.replace(tzinfo=timezone.utc)
+            to_yaml_file(f"{path}/{chart.name}/requirements.lock", lock)
+
+        for gerrit, changes in chart.patches.gerrit.items():
+            client = GerritClient(base_url=f"https://{gerrit}")
+
+            for change_id in changes:
+                change = client.changes.get(change_id)
+                gerrit_patch = change.get_revision().get_patch(decode=True)
+                await patch(input=gerrit_patch.encode(), path=chart_path)
+
+        patches_path = charts_path / "patches" / chart.name
+        if await patches_path.exists():
+            async for patch_path in patches_path.glob("*.patch"):
+                async with patch_path.open(mode="rb") as patch_file:
+                    patch_data = await patch_file.read()
+                    await patch(input=patch_data, path=chart_path)
+
+    async def fetch_charts(self):
+        await asyncio.gather(
+            *[
+                self._helm(["repo", "add", repo.name, str(repo.url)])
+                for repo in self.repositories
+            ]
+        )
+        await self._helm(["repo", "update"])
+
+        await asyncio.gather(*[self._fetch_chart(chart) for chart in self.charts])
+
+
+async def main():
+    config = parse_yaml_file_as(Config, ".charts.yml")
+    await config.fetch_charts()
+
+
+if __name__ == "__main__":
+    asyncio.run(main())
diff --git a/charts/cinder/charts/helm-toolkit/requirements.lock b/charts/cinder/charts/helm-toolkit/requirements.lock
new file mode 100644
index 0000000..808bd94
--- /dev/null
+++ b/charts/cinder/charts/helm-toolkit/requirements.lock
@@ -0,0 +1,3 @@
+dependencies: []
+digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/cinder/requirements.lock b/charts/cinder/requirements.lock
index 67c5213..e346dde 100644
--- a/charts/cinder/requirements.lock
+++ b/charts/cinder/requirements.lock
@@ -1,6 +1,6 @@
 dependencies:
 - name: helm-toolkit
-  repository: file://../../openstack-helm-infra/helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
   version: 0.2.55
-digest: sha256:f25556fa4f0b285a96cbf853e72555c04e65772daf0ffa6b518321e5e249f5ca
-generated: "2023-11-22T20:14:58.592049716Z"
+digest: sha256:92b4001062b365cd9687eb926780c7f64e17e488262c1167339ade0fe600b368
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/cinder/requirements.yaml b/charts/cinder/requirements.yaml
index 4124d01..6ab539f 100644
--- a/charts/cinder/requirements.yaml
+++ b/charts/cinder/requirements.yaml
@@ -1,16 +1,4 @@
-# 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.
-
 dependencies:
-  - name: helm-toolkit
-    repository: file://../../openstack-helm-infra/helm-toolkit
-    version: ">= 0.1.0"
+- name: helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
+  version: 0.2.55
diff --git a/charts/designate/charts/helm-toolkit/requirements.lock b/charts/designate/charts/helm-toolkit/requirements.lock
new file mode 100644
index 0000000..808bd94
--- /dev/null
+++ b/charts/designate/charts/helm-toolkit/requirements.lock
@@ -0,0 +1,3 @@
+dependencies: []
+digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/designate/requirements.lock b/charts/designate/requirements.lock
index b454b93..e346dde 100644
--- a/charts/designate/requirements.lock
+++ b/charts/designate/requirements.lock
@@ -1,6 +1,6 @@
 dependencies:
 - name: helm-toolkit
-  repository: file://../../openstack-helm-infra/helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
   version: 0.2.55
-digest: sha256:f25556fa4f0b285a96cbf853e72555c04e65772daf0ffa6b518321e5e249f5ca
-generated: "2023-11-22T20:14:54.685042515Z"
+digest: sha256:92b4001062b365cd9687eb926780c7f64e17e488262c1167339ade0fe600b368
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/designate/requirements.yaml b/charts/designate/requirements.yaml
index 4124d01..6ab539f 100644
--- a/charts/designate/requirements.yaml
+++ b/charts/designate/requirements.yaml
@@ -1,16 +1,4 @@
-# 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.
-
 dependencies:
-  - name: helm-toolkit
-    repository: file://../../openstack-helm-infra/helm-toolkit
-    version: ">= 0.1.0"
+- name: helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
+  version: 0.2.55
diff --git a/charts/glance/charts/helm-toolkit/requirements.lock b/charts/glance/charts/helm-toolkit/requirements.lock
new file mode 100644
index 0000000..808bd94
--- /dev/null
+++ b/charts/glance/charts/helm-toolkit/requirements.lock
@@ -0,0 +1,3 @@
+dependencies: []
+digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/glance/requirements.lock b/charts/glance/requirements.lock
index 1005916..e346dde 100644
--- a/charts/glance/requirements.lock
+++ b/charts/glance/requirements.lock
@@ -1,6 +1,6 @@
 dependencies:
 - name: helm-toolkit
-  repository: file://../../openstack-helm-infra/helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
   version: 0.2.55
-digest: sha256:f25556fa4f0b285a96cbf853e72555c04e65772daf0ffa6b518321e5e249f5ca
-generated: "2023-11-09T15:11:39.317300744Z"
+digest: sha256:92b4001062b365cd9687eb926780c7f64e17e488262c1167339ade0fe600b368
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/glance/requirements.yaml b/charts/glance/requirements.yaml
index 4124d01..6ab539f 100644
--- a/charts/glance/requirements.yaml
+++ b/charts/glance/requirements.yaml
@@ -1,16 +1,4 @@
-# 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.
-
 dependencies:
-  - name: helm-toolkit
-    repository: file://../../openstack-helm-infra/helm-toolkit
-    version: ">= 0.1.0"
+- name: helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
+  version: 0.2.55
diff --git a/charts/cert-manager-webhook-godaddy/.helmignore b/charts/godaddy-webhook/.helmignore
similarity index 100%
rename from charts/cert-manager-webhook-godaddy/.helmignore
rename to charts/godaddy-webhook/.helmignore
diff --git a/charts/cert-manager-webhook-godaddy/Chart.yaml b/charts/godaddy-webhook/Chart.yaml
similarity index 100%
rename from charts/cert-manager-webhook-godaddy/Chart.yaml
rename to charts/godaddy-webhook/Chart.yaml
diff --git a/charts/cert-manager-webhook-godaddy/templates/NOTES.txt b/charts/godaddy-webhook/templates/NOTES.txt
similarity index 100%
rename from charts/cert-manager-webhook-godaddy/templates/NOTES.txt
rename to charts/godaddy-webhook/templates/NOTES.txt
diff --git a/charts/cert-manager-webhook-godaddy/templates/_helpers.tpl b/charts/godaddy-webhook/templates/_helpers.tpl
similarity index 100%
rename from charts/cert-manager-webhook-godaddy/templates/_helpers.tpl
rename to charts/godaddy-webhook/templates/_helpers.tpl
diff --git a/charts/cert-manager-webhook-godaddy/templates/apiservice.yaml b/charts/godaddy-webhook/templates/apiservice.yaml
similarity index 100%
rename from charts/cert-manager-webhook-godaddy/templates/apiservice.yaml
rename to charts/godaddy-webhook/templates/apiservice.yaml
diff --git a/charts/cert-manager-webhook-godaddy/templates/deployment.yaml b/charts/godaddy-webhook/templates/deployment.yaml
similarity index 100%
rename from charts/cert-manager-webhook-godaddy/templates/deployment.yaml
rename to charts/godaddy-webhook/templates/deployment.yaml
diff --git a/charts/cert-manager-webhook-godaddy/templates/pki.yaml b/charts/godaddy-webhook/templates/pki.yaml
similarity index 100%
rename from charts/cert-manager-webhook-godaddy/templates/pki.yaml
rename to charts/godaddy-webhook/templates/pki.yaml
diff --git a/charts/cert-manager-webhook-godaddy/templates/rbac.yaml b/charts/godaddy-webhook/templates/rbac.yaml
similarity index 100%
rename from charts/cert-manager-webhook-godaddy/templates/rbac.yaml
rename to charts/godaddy-webhook/templates/rbac.yaml
diff --git a/charts/cert-manager-webhook-godaddy/templates/service.yaml b/charts/godaddy-webhook/templates/service.yaml
similarity index 100%
rename from charts/cert-manager-webhook-godaddy/templates/service.yaml
rename to charts/godaddy-webhook/templates/service.yaml
diff --git a/charts/cert-manager-webhook-godaddy/values.yaml b/charts/godaddy-webhook/values.yaml
similarity index 100%
rename from charts/cert-manager-webhook-godaddy/values.yaml
rename to charts/godaddy-webhook/values.yaml
diff --git a/charts/heat/charts/helm-toolkit/requirements.lock b/charts/heat/charts/helm-toolkit/requirements.lock
new file mode 100644
index 0000000..808bd94
--- /dev/null
+++ b/charts/heat/charts/helm-toolkit/requirements.lock
@@ -0,0 +1,3 @@
+dependencies: []
+digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/heat/requirements.lock b/charts/heat/requirements.lock
index 4057c92..e346dde 100644
--- a/charts/heat/requirements.lock
+++ b/charts/heat/requirements.lock
@@ -1,6 +1,6 @@
 dependencies:
 - name: helm-toolkit
-  repository: file://../../openstack-helm-infra/helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
   version: 0.2.55
-digest: sha256:f25556fa4f0b285a96cbf853e72555c04e65772daf0ffa6b518321e5e249f5ca
-generated: "2023-11-20T16:59:14.214540302Z"
+digest: sha256:92b4001062b365cd9687eb926780c7f64e17e488262c1167339ade0fe600b368
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/heat/requirements.yaml b/charts/heat/requirements.yaml
index 4124d01..6ab539f 100644
--- a/charts/heat/requirements.yaml
+++ b/charts/heat/requirements.yaml
@@ -1,16 +1,4 @@
-# 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.
-
 dependencies:
-  - name: helm-toolkit
-    repository: file://../../openstack-helm-infra/helm-toolkit
-    version: ">= 0.1.0"
+- name: helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
+  version: 0.2.55
diff --git a/charts/horizon/charts/helm-toolkit/requirements.lock b/charts/horizon/charts/helm-toolkit/requirements.lock
new file mode 100644
index 0000000..808bd94
--- /dev/null
+++ b/charts/horizon/charts/helm-toolkit/requirements.lock
@@ -0,0 +1,3 @@
+dependencies: []
+digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/horizon/requirements.lock b/charts/horizon/requirements.lock
index d605ea5..e346dde 100644
--- a/charts/horizon/requirements.lock
+++ b/charts/horizon/requirements.lock
@@ -1,6 +1,6 @@
 dependencies:
 - name: helm-toolkit
-  repository: file://../../openstack-helm-infra/helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
   version: 0.2.55
-digest: sha256:f25556fa4f0b285a96cbf853e72555c04e65772daf0ffa6b518321e5e249f5ca
-generated: "2023-11-22T20:15:05.83595607Z"
+digest: sha256:92b4001062b365cd9687eb926780c7f64e17e488262c1167339ade0fe600b368
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/horizon/requirements.yaml b/charts/horizon/requirements.yaml
index 4124d01..6ab539f 100644
--- a/charts/horizon/requirements.yaml
+++ b/charts/horizon/requirements.yaml
@@ -1,16 +1,4 @@
-# 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.
-
 dependencies:
-  - name: helm-toolkit
-    repository: file://../../openstack-helm-infra/helm-toolkit
-    version: ">= 0.1.0"
+- name: helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
+  version: 0.2.55
diff --git a/charts/keystone/charts/helm-toolkit/requirements.lock b/charts/keystone/charts/helm-toolkit/requirements.lock
new file mode 100644
index 0000000..808bd94
--- /dev/null
+++ b/charts/keystone/charts/helm-toolkit/requirements.lock
@@ -0,0 +1,3 @@
+dependencies: []
+digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/keystone/requirements.lock b/charts/keystone/requirements.lock
index a2fbbec..e346dde 100644
--- a/charts/keystone/requirements.lock
+++ b/charts/keystone/requirements.lock
@@ -1,6 +1,6 @@
 dependencies:
 - name: helm-toolkit
-  repository: file://../../openstack-helm-infra/helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
   version: 0.2.55
-digest: sha256:f25556fa4f0b285a96cbf853e72555c04e65772daf0ffa6b518321e5e249f5ca
-generated: "2023-11-15T23:04:58.660312058Z"
+digest: sha256:92b4001062b365cd9687eb926780c7f64e17e488262c1167339ade0fe600b368
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/keystone/requirements.yaml b/charts/keystone/requirements.yaml
index 4124d01..6ab539f 100644
--- a/charts/keystone/requirements.yaml
+++ b/charts/keystone/requirements.yaml
@@ -1,16 +1,4 @@
-# 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.
-
 dependencies:
-  - name: helm-toolkit
-    repository: file://../../openstack-helm-infra/helm-toolkit
-    version: ">= 0.1.0"
+- name: helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
+  version: 0.2.55
diff --git a/charts/libvirt/charts/helm-toolkit/requirements.lock b/charts/libvirt/charts/helm-toolkit/requirements.lock
index 474adbc..808bd94 100644
--- a/charts/libvirt/charts/helm-toolkit/requirements.lock
+++ b/charts/libvirt/charts/helm-toolkit/requirements.lock
@@ -1,3 +1,3 @@
 dependencies: []
 digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726
-generated: "2023-11-29T02:39:33.120856137Z"
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/libvirt/requirements.lock b/charts/libvirt/requirements.lock
index 41e4298..5cfd353 100644
--- a/charts/libvirt/requirements.lock
+++ b/charts/libvirt/requirements.lock
@@ -1,6 +1,6 @@
 dependencies:
 - name: helm-toolkit
-  repository: file://../helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
   version: 0.2.56
-digest: sha256:2341734ff37eda298acb943a81ff603ee8edd5cfcbe655dba5943b485b64f9e3
-generated: "2023-11-29T02:39:38.485927956Z"
+digest: sha256:aacff4a999f7d7cc6a011849a6b040e36a8a168af72da9d0db2f00a346974769
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/libvirt/requirements.yaml b/charts/libvirt/requirements.yaml
index 84f0aff..2590759 100644
--- a/charts/libvirt/requirements.yaml
+++ b/charts/libvirt/requirements.yaml
@@ -1,18 +1,4 @@
-# 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.
-
----
 dependencies:
-  - name: helm-toolkit
-    repository: file://../helm-toolkit
-    version: ">= 0.1.0"
-...
+- name: helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
+  version: 0.2.56
diff --git a/charts/magnum/charts/helm-toolkit/requirements.lock b/charts/magnum/charts/helm-toolkit/requirements.lock
new file mode 100644
index 0000000..808bd94
--- /dev/null
+++ b/charts/magnum/charts/helm-toolkit/requirements.lock
@@ -0,0 +1,3 @@
+dependencies: []
+digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/magnum/requirements.lock b/charts/magnum/requirements.lock
index f10f451..e346dde 100644
--- a/charts/magnum/requirements.lock
+++ b/charts/magnum/requirements.lock
@@ -1,6 +1,6 @@
 dependencies:
 - name: helm-toolkit
-  repository: file://../../openstack-helm-infra/helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
   version: 0.2.55
-digest: sha256:f25556fa4f0b285a96cbf853e72555c04e65772daf0ffa6b518321e5e249f5ca
-generated: "2023-11-22T20:15:14.57130025Z"
+digest: sha256:92b4001062b365cd9687eb926780c7f64e17e488262c1167339ade0fe600b368
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/magnum/requirements.yaml b/charts/magnum/requirements.yaml
index 4124d01..6ab539f 100644
--- a/charts/magnum/requirements.yaml
+++ b/charts/magnum/requirements.yaml
@@ -1,16 +1,4 @@
-# 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.
-
 dependencies:
-  - name: helm-toolkit
-    repository: file://../../openstack-helm-infra/helm-toolkit
-    version: ">= 0.1.0"
+- name: helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
+  version: 0.2.55
diff --git a/charts/manila/charts/helm-toolkit/requirements.lock b/charts/manila/charts/helm-toolkit/requirements.lock
new file mode 100644
index 0000000..808bd94
--- /dev/null
+++ b/charts/manila/charts/helm-toolkit/requirements.lock
@@ -0,0 +1,3 @@
+dependencies: []
+digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/manila/requirements.lock b/charts/manila/requirements.lock
index 8d56ee1..e346dde 100644
--- a/charts/manila/requirements.lock
+++ b/charts/manila/requirements.lock
@@ -1,6 +1,6 @@
 dependencies:
 - name: helm-toolkit
-  repository: file://../../openstack-helm-infra/helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
   version: 0.2.55
-digest: sha256:f25556fa4f0b285a96cbf853e72555c04e65772daf0ffa6b518321e5e249f5ca
-generated: "2023-11-22T20:15:09.875210224Z"
+digest: sha256:92b4001062b365cd9687eb926780c7f64e17e488262c1167339ade0fe600b368
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/manila/requirements.yaml b/charts/manila/requirements.yaml
index 4124d01..6ab539f 100644
--- a/charts/manila/requirements.yaml
+++ b/charts/manila/requirements.yaml
@@ -1,16 +1,4 @@
-# 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.
-
 dependencies:
-  - name: helm-toolkit
-    repository: file://../../openstack-helm-infra/helm-toolkit
-    version: ">= 0.1.0"
+- name: helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
+  version: 0.2.55
diff --git a/charts/neutron/charts/helm-toolkit/requirements.lock b/charts/neutron/charts/helm-toolkit/requirements.lock
new file mode 100644
index 0000000..808bd94
--- /dev/null
+++ b/charts/neutron/charts/helm-toolkit/requirements.lock
@@ -0,0 +1,3 @@
+dependencies: []
+digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/neutron/requirements.lock b/charts/neutron/requirements.lock
index 9cc2f76..e346dde 100644
--- a/charts/neutron/requirements.lock
+++ b/charts/neutron/requirements.lock
@@ -1,6 +1,6 @@
 dependencies:
 - name: helm-toolkit
-  repository: file://../../openstack-helm-infra/helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
   version: 0.2.55
-digest: sha256:f25556fa4f0b285a96cbf853e72555c04e65772daf0ffa6b518321e5e249f5ca
-generated: "2023-11-22T20:14:55.619219382Z"
+digest: sha256:92b4001062b365cd9687eb926780c7f64e17e488262c1167339ade0fe600b368
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/neutron/requirements.yaml b/charts/neutron/requirements.yaml
index 4124d01..6ab539f 100644
--- a/charts/neutron/requirements.yaml
+++ b/charts/neutron/requirements.yaml
@@ -1,16 +1,4 @@
-# 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.
-
 dependencies:
-  - name: helm-toolkit
-    repository: file://../../openstack-helm-infra/helm-toolkit
-    version: ">= 0.1.0"
+- name: helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
+  version: 0.2.55
diff --git a/charts/neutron/templates/daemonset-ovn-metadata-agent.yaml b/charts/neutron/templates/daemonset-ovn-metadata-agent.yaml
index 598c74c..f6dde55 100644
--- a/charts/neutron/templates/daemonset-ovn-metadata-agent.yaml
+++ b/charts/neutron/templates/daemonset-ovn-metadata-agent.yaml
@@ -100,8 +100,8 @@
           command:
             - /tmp/neutron-metadata-agent-init.sh
           volumeMounts:
-            - name: run
-              mountPath: /run
+            - name: run-openvswitch
+              mountPath: /run/openvswitch
             - name: pod-tmp
               mountPath: /tmp
             - name: neutron-bin
diff --git a/charts/nova/charts/helm-toolkit/requirements.lock b/charts/nova/charts/helm-toolkit/requirements.lock
new file mode 100644
index 0000000..808bd94
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/requirements.lock
@@ -0,0 +1,3 @@
+dependencies: []
+digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/nova/requirements.lock b/charts/nova/requirements.lock
index 5c187eb..e346dde 100644
--- a/charts/nova/requirements.lock
+++ b/charts/nova/requirements.lock
@@ -1,6 +1,6 @@
 dependencies:
 - name: helm-toolkit
-  repository: file://../../openstack-helm-infra/helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
   version: 0.2.55
-digest: sha256:f25556fa4f0b285a96cbf853e72555c04e65772daf0ffa6b518321e5e249f5ca
-generated: "2023-11-03T00:16:38.441631616Z"
+digest: sha256:92b4001062b365cd9687eb926780c7f64e17e488262c1167339ade0fe600b368
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/nova/requirements.yaml b/charts/nova/requirements.yaml
index 4124d01..6ab539f 100644
--- a/charts/nova/requirements.yaml
+++ b/charts/nova/requirements.yaml
@@ -1,16 +1,4 @@
-# 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.
-
 dependencies:
-  - name: helm-toolkit
-    repository: file://../../openstack-helm-infra/helm-toolkit
-    version: ">= 0.1.0"
+- name: helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
+  version: 0.2.55
diff --git a/charts/octavia/charts/helm-toolkit/requirements.lock b/charts/octavia/charts/helm-toolkit/requirements.lock
new file mode 100644
index 0000000..808bd94
--- /dev/null
+++ b/charts/octavia/charts/helm-toolkit/requirements.lock
@@ -0,0 +1,3 @@
+dependencies: []
+digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/octavia/requirements.lock b/charts/octavia/requirements.lock
index f24caac..e346dde 100644
--- a/charts/octavia/requirements.lock
+++ b/charts/octavia/requirements.lock
@@ -1,6 +1,6 @@
 dependencies:
 - name: helm-toolkit
-  repository: file://../../openstack-helm-infra/helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
   version: 0.2.55
-digest: sha256:f25556fa4f0b285a96cbf853e72555c04e65772daf0ffa6b518321e5e249f5ca
-generated: "2023-11-22T20:15:15.673945271Z"
+digest: sha256:92b4001062b365cd9687eb926780c7f64e17e488262c1167339ade0fe600b368
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/octavia/requirements.yaml b/charts/octavia/requirements.yaml
index 512dcb4..6ab539f 100644
--- a/charts/octavia/requirements.yaml
+++ b/charts/octavia/requirements.yaml
@@ -1,18 +1,4 @@
-# Copyright 2019 Samsung Electronics Co., Ltd.
-#
-# 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.
-
 dependencies:
-  - name: helm-toolkit
-    repository: file://../../openstack-helm-infra/helm-toolkit
-    version: ">= 0.1.0"
+- name: helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
+  version: 0.2.55
diff --git a/charts/openvswitch/charts/helm-toolkit/requirements.lock b/charts/openvswitch/charts/helm-toolkit/requirements.lock
index 474adbc..808bd94 100644
--- a/charts/openvswitch/charts/helm-toolkit/requirements.lock
+++ b/charts/openvswitch/charts/helm-toolkit/requirements.lock
@@ -1,3 +1,3 @@
 dependencies: []
 digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726
-generated: "2023-11-29T02:39:33.120856137Z"
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/openvswitch/requirements.lock b/charts/openvswitch/requirements.lock
index a9a0bd4..5cfd353 100644
--- a/charts/openvswitch/requirements.lock
+++ b/charts/openvswitch/requirements.lock
@@ -1,6 +1,6 @@
 dependencies:
 - name: helm-toolkit
-  repository: file://../helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
   version: 0.2.56
-digest: sha256:2341734ff37eda298acb943a81ff603ee8edd5cfcbe655dba5943b485b64f9e3
-generated: "2023-11-29T02:39:43.736465441Z"
+digest: sha256:aacff4a999f7d7cc6a011849a6b040e36a8a168af72da9d0db2f00a346974769
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/openvswitch/requirements.yaml b/charts/openvswitch/requirements.yaml
index 84f0aff..2590759 100644
--- a/charts/openvswitch/requirements.yaml
+++ b/charts/openvswitch/requirements.yaml
@@ -1,18 +1,4 @@
-# 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.
-
----
 dependencies:
-  - name: helm-toolkit
-    repository: file://../helm-toolkit
-    version: ">= 0.1.0"
-...
+- name: helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
+  version: 0.2.56
diff --git a/charts/ovn/charts/helm-toolkit/requirements.lock b/charts/ovn/charts/helm-toolkit/requirements.lock
index 474adbc..808bd94 100644
--- a/charts/ovn/charts/helm-toolkit/requirements.lock
+++ b/charts/ovn/charts/helm-toolkit/requirements.lock
@@ -1,3 +1,3 @@
 dependencies: []
 digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726
-generated: "2023-11-29T02:39:33.120856137Z"
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/ovn/requirements.lock b/charts/ovn/requirements.lock
index 0e9719e..5cfd353 100644
--- a/charts/ovn/requirements.lock
+++ b/charts/ovn/requirements.lock
@@ -1,6 +1,6 @@
 dependencies:
 - name: helm-toolkit
-  repository: file://../helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
   version: 0.2.56
-digest: sha256:2341734ff37eda298acb943a81ff603ee8edd5cfcbe655dba5943b485b64f9e3
-generated: "2023-11-29T02:39:38.134714677Z"
+digest: sha256:aacff4a999f7d7cc6a011849a6b040e36a8a168af72da9d0db2f00a346974769
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/ovn/requirements.yaml b/charts/ovn/requirements.yaml
index 84f0aff..2590759 100644
--- a/charts/ovn/requirements.yaml
+++ b/charts/ovn/requirements.yaml
@@ -1,18 +1,4 @@
-# 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.
-
----
 dependencies:
-  - name: helm-toolkit
-    repository: file://../helm-toolkit
-    version: ">= 0.1.0"
-...
+- name: helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
+  version: 0.2.56
diff --git a/charts/patches/cinder/0001-tune-uwsgi-config.patch b/charts/patches/cinder/0001-tune-uwsgi-config.patch
new file mode 100644
index 0000000..c6d1e6a
--- /dev/null
+++ b/charts/patches/cinder/0001-tune-uwsgi-config.patch
@@ -0,0 +1,25 @@
+diff --git b/cinder/values.yaml a/charts/cinder/values.yaml
+index 0c50ec60..12351a60 100644
+--- b/cinder/values.yaml
++++ a/cinder/values.yaml
+@@ -1015,15 +1015,20 @@ conf:
+     uwsgi:
+       add-header: "Connection: close"
+       buffer-size: 65535
++      chunked-input-limit: "4096000"
+       die-on-term: true
+       enable-threads: true
+       exit-on-reload: false
+       hook-master-start: unix_signal:15 gracefully_kill_them_all
++      http-auto-chunked: true
++      http-raw-body: true
+       lazy-apps: true
+       log-x-forwarded-for: true
+       master: true
++      need-app: true
+       procname-prefix-spaced: "cinder-api:"
+       route-user-agent: '^kube-probe.* donotlog:'
++      socket-timeout: 10
+       thunder-lock: true
+       worker-reload-mercy: 80
+       wsgi-file: /var/lib/openstack/bin/cinder-wsgi
diff --git a/charts/patches/designate/0001-tune-uwsgi-config.patch b/charts/patches/designate/0001-tune-uwsgi-config.patch
new file mode 100644
index 0000000..6493965
--- /dev/null
+++ b/charts/patches/designate/0001-tune-uwsgi-config.patch
@@ -0,0 +1,25 @@
+diff --git b/designate/values.yaml a/charts/designate/values.yaml
+index 80051e75..71694146 100644
+--- b/designate/values.yaml
++++ a/designate/values.yaml
+@@ -532,15 +532,20 @@ conf:
+     uwsgi:
+       add-header: "Connection: close"
+       buffer-size: 65535
++      chunked-input-limit: "4096000"
+       die-on-term: true
+       enable-threads: true
+       exit-on-reload: false
+       hook-master-start: unix_signal:15 gracefully_kill_them_all
++      http-auto-chunked: true
++      http-raw-body: true
+       lazy-apps: true
+       log-x-forwarded-for: true
+       master: true
++      need-app: true
+       procname-prefix-spaced: "designate-api:"
+       route-user-agent: '^kube-probe.* donotlog:'
++      socket-timeout: 10
+       thunder-lock: true
+       worker-reload-mercy: 80
+       wsgi-file: /var/lib/openstack/bin/designate-api-wsgi
diff --git a/charts/patches/glance/0001-tune-uwsgi-config.patch b/charts/patches/glance/0001-tune-uwsgi-config.patch
new file mode 100644
index 0000000..be37404
--- /dev/null
+++ b/charts/patches/glance/0001-tune-uwsgi-config.patch
@@ -0,0 +1,25 @@
+diff --git b/glance/values.yaml a/charts/glance/values.yaml
+index d2c3f504..85ddf18b 100644
+--- b/glance/values.yaml
++++ a/glance/values.yaml
+@@ -393,15 +393,20 @@ conf:
+     uwsgi:
+       add-header: "Connection: close"
+       buffer-size: 65535
++      chunked-input-limit: "4096000"
+       die-on-term: true
+       enable-threads: true
+       exit-on-reload: false
+       hook-master-start: unix_signal:15 gracefully_kill_them_all
++      http-auto-chunked: true
++      http-raw-body: true
+       lazy-apps: true
+       log-x-forwarded-for: true
+       master: true
++      need-app: true
+       procname-prefix-spaced: "glance-api:"
+       route-user-agent: '^kube-probe.* donotlog:'
++      socket-timeout: 10
+       thunder-lock: true
+       worker-reload-mercy: 80
+       wsgi-file: /var/lib/openstack/bin/glance-wsgi-api
diff --git a/charts/patches/heat/0001-tune-uwsgi-config.patch b/charts/patches/heat/0001-tune-uwsgi-config.patch
new file mode 100644
index 0000000..7047470
--- /dev/null
+++ b/charts/patches/heat/0001-tune-uwsgi-config.patch
@@ -0,0 +1,46 @@
+diff --git b/heat/values.yaml a/charts/heat/values.yaml
+index c9b8cdd9..1cf8bdc4 100644
+--- b/heat/values.yaml
++++ a/heat/values.yaml
+@@ -494,15 +494,20 @@ conf:
+     uwsgi:
+       add-header: "Connection: close"
+       buffer-size: 65535
++      chunked-input-limit: "4096000"
+       die-on-term: true
+       enable-threads: true
+       exit-on-reload: false
+       hook-master-start: unix_signal:15 gracefully_kill_them_all
++      http-auto-chunked: true
++      http-raw-body: true
+       lazy-apps: true
+       log-x-forwarded-for: true
+       master: true
++      need-app: true
+       procname-prefix-spaced: "heat-api:"
+       route-user-agent: '^kube-probe.* donotlog:'
++      socket-timeout: 10
+       thunder-lock: true
+       worker-reload-mercy: 80
+       wsgi-file: /var/lib/openstack/bin/heat-wsgi-api
+@@ -510,15 +515,20 @@ conf:
+     uwsgi:
+       add-header: "Connection: close"
+       buffer-size: 65535
++      chunked-input-limit: 4096000
+       die-on-term: true
+       enable-threads: true
+       exit-on-reload: false
+       hook-master-start: unix_signal:15 gracefully_kill_them_all
++      http-auto-chunked: true
++      http-raw-body: true
+       lazy-apps: true
+       log-x-forwarded-for: true
+       master: true
++      need-app: true
+       procname-prefix-spaced: "heat-api-cfn:"
+       route-user-agent: '^kube-probe.* donotlog:'
++      socket-timeout: 10
+       thunder-lock: true
+       worker-reload-mercy: 80
+       wsgi-file: /var/lib/openstack/bin/heat-wsgi-api-cfn
diff --git a/charts/patches/horizon/0001-switch-to-pymemcache.patch b/charts/patches/horizon/0001-switch-to-pymemcache.patch
new file mode 100644
index 0000000..2b0f2c0
--- /dev/null
+++ b/charts/patches/horizon/0001-switch-to-pymemcache.patch
@@ -0,0 +1,13 @@
+diff --git b/horizon/values.yaml a/charts/horizon/values.yaml
+index 8cfaf5b4..36de4ee3 100644
+--- b/horizon/values.yaml
++++ a/horizon/values.yaml
+@@ -385,7 +385,7 @@ conf:
+ 
+         CACHES = {
+             'default': {
+-                'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
++                'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
+                 'LOCATION': '{{ tuple "oslo_cache" "internal" "memcache" . | include "helm-toolkit.endpoints.host_and_port_endpoint_uri_lookup" }}',
+             }
+         }
diff --git a/charts/patches/horizon/0002-fix-config-for-new-django.patch b/charts/patches/horizon/0002-fix-config-for-new-django.patch
new file mode 100644
index 0000000..f0a69a9
--- /dev/null
+++ b/charts/patches/horizon/0002-fix-config-for-new-django.patch
@@ -0,0 +1,13 @@
+diff --git b/horizon/values.yaml a/charts/horizon/values.yaml
+index 7d2567c1..36de4ee3 100644
+--- b/horizon/values.yaml
++++ a/horizon/values.yaml
+@@ -253,7 +253,7 @@ conf:
+       template: |
+         import os
+ 
+-        from django.utils.translation import ugettext_lazy as _
++        from django.utils.translation import gettext_lazy as _
+ 
+         from openstack_dashboard import exceptions
+ 
diff --git a/charts/patches/horizon/0003-bump-pymysql-version.patch b/charts/patches/horizon/0003-bump-pymysql-version.patch
new file mode 100644
index 0000000..7685862
--- /dev/null
+++ b/charts/patches/horizon/0003-bump-pymysql-version.patch
@@ -0,0 +1,25 @@
+diff --git b/horizon/templates/bin/_django.wsgi.tpl a/charts/horizon/templates/bin/_django.wsgi.tpl
+index 4626f21a..cbf87fbf 100644
+--- b/horizon/templates/bin/_django.wsgi.tpl
++++ a/horizon/templates/bin/_django.wsgi.tpl
+@@ -22,8 +22,6 @@ import os
+ import sys
+ 
+ import pymysql
+-
+-pymysql.version_info = (1, 4, 0, "final", 0)
+ pymysql.install_as_MySQLdb()
+ 
+ from django.core.wsgi import get_wsgi_application
+diff --git b/horizon/templates/bin/_manage.py.tpl a/charts/horizon/templates/bin/_manage.py.tpl
+index 105a32c8..1b21cfc9 100644
+--- b/horizon/templates/bin/_manage.py.tpl
++++ a/horizon/templates/bin/_manage.py.tpl
+@@ -23,7 +23,6 @@ import os
+ import sys
+ 
+ import pymysql
+-pymysql.version_info = (1, 4, 0, "final", 0)
+ pymysql.install_as_MySQLdb()
+ 
+ from django.core.management import execute_from_command_line
diff --git a/charts/patches/libvirt/0001-use-libvirt-tls-sidecar.patch b/charts/patches/libvirt/0001-use-libvirt-tls-sidecar.patch
new file mode 100644
index 0000000..24b0b3c
--- /dev/null
+++ b/charts/patches/libvirt/0001-use-libvirt-tls-sidecar.patch
@@ -0,0 +1,398 @@
+diff --git b/libvirt/templates/bin/_libvirt.sh.tpl a/charts/libvirt/templates/bin/_libvirt.sh.tpl
+index 0f96c0be..d87a1262 100644
+--- b/libvirt/templates/bin/_libvirt.sh.tpl
++++ a/libvirt/templates/bin/_libvirt.sh.tpl
+@@ -16,31 +16,30 @@ limitations under the License.
+ 
+ set -ex
+ 
+-# NOTE(mnaser): This will move the API certificates into the expected location.
+-if [ -f /tmp/api.crt ]; then
+-  mkdir -p /etc/pki/CA /etc/pki/libvirt/private
+-
+-  cp /tmp/api-ca.crt {{ .Values.conf.libvirt.ca_file }}
+-  cp /tmp/api-ca.crt /etc/pki/qemu/ca-cert.pem
+-
+-  cp /tmp/api.crt {{ .Values.conf.libvirt.cert_file }}
+-  cp /tmp/api.crt /etc/pki/libvirt/clientcert.pem
+-  cp /tmp/api.crt /etc/pki/qemu/server-cert.pem
+-  cp /tmp/api.crt /etc/pki/qemu/client-cert.pem
+-
+-  cp /tmp/api.key {{ .Values.conf.libvirt.key_file }}
+-  cp /tmp/api.key /etc/pki/libvirt/private/clientkey.pem
+-  cp /tmp/api.key /etc/pki/qemu/server-key.pem
+-  cp /tmp/api.key /etc/pki/qemu/client-key.pem
+-fi
++wait_for_file() {
++  local file=$1
+ 
+-# NOTE(mnaser): This will move the VNC certificates into the expected location.
+-if [ -f /tmp/vnc.crt ]; then
+-  mkdir -p /etc/pki/libvirt-vnc
+-  mv /tmp/vnc.key /etc/pki/libvirt-vnc/server-key.pem
+-  mv /tmp/vnc.crt /etc/pki/libvirt-vnc/server-cert.pem
+-  mv /tmp/vnc-ca.crt /etc/pki/libvirt-vnc/ca-cert.pem
+-fi
++  while [ ! -f $file ]; do
++    sleep 1
++  done
++}
++
++wait_for_file {{ .Values.conf.libvirt.ca_file }}
++wait_for_file /etc/pki/qemu/ca-cert.pem
++
++wait_for_file {{ .Values.conf.libvirt.cert_file }}
++wait_for_file /etc/pki/libvirt/clientcert.pem
++wait_for_file /etc/pki/qemu/server-cert.pem
++wait_for_file /etc/pki/qemu/client-cert.pem
++
++wait_for_file {{ .Values.conf.libvirt.key_file }}
++wait_for_file /etc/pki/libvirt/private/clientkey.pem
++wait_for_file /etc/pki/qemu/server-key.pem
++wait_for_file /etc/pki/qemu/client-key.pem
++
++wait_for_file /etc/pki/libvirt-vnc/ca-cert.pem
++wait_for_file /etc/pki/libvirt-vnc/server-cert.pem
++wait_for_file /etc/pki/libvirt-vnc/server-key.pem
+ 
+ # TODO: We disable cgroup functionality for cgroup v2, we should fix this in the future
+ if $(stat -fc %T /sys/fs/cgroup/ | grep -q cgroup2fs); then
+diff --git b/libvirt/templates/bin/_wait-for-libvirt.sh.tpl a/charts/libvirt/templates/bin/_wait-for-libvirt.sh.tpl
+new file mode 100644
+index 00000000..65eca54b
+--- /dev/null
++++ a/libvirt/templates/bin/_wait-for-libvirt.sh.tpl
+@@ -0,0 +1,27 @@
++#!/bin/bash
++
++{{/*
++Copyright (c) 2023 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.
++*/}}
++
++set -xe
++
++# NOTE(mnaser): We use this script in the postStart hook of the libvirt
++#               container to ensure that the libvirt daemon is running
++#               before we start the exporter.
++until virsh list --all; do
++    echo "Waiting for libvirt to be ready..."
++    sleep 1
++done
+diff --git b/libvirt/templates/configmap-bin.yaml a/charts/libvirt/templates/configmap-bin.yaml
+index 9b74179f..99a0c815 100644
+--- b/libvirt/templates/configmap-bin.yaml
++++ a/libvirt/templates/configmap-bin.yaml
+@@ -26,10 +26,8 @@ data:
+ {{- end }}
+   libvirt.sh: |
+ {{ tuple "bin/_libvirt.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+-{{- if or (eq .Values.conf.libvirt.listen_tls "1") (eq .Values.conf.qemu.vnc_tls "1") }}
+-  cert-init.sh: |
+-{{ tpl .Values.scripts.cert_init_sh . | indent 4 }}
+-{{- end }}
++  wait-for-libvirt.sh: |
++{{ tuple "bin/_wait-for-libvirt.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+ {{- if .Values.conf.ceph.enabled }}
+   ceph-keyring.sh: |
+ {{ tuple "bin/_ceph-keyring.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+diff --git b/libvirt/templates/daemonset-libvirt.yaml a/charts/libvirt/templates/daemonset-libvirt.yaml
+index 35cd6e14..51b3c1f3 100644
+--- b/libvirt/templates/daemonset-libvirt.yaml
++++ a/libvirt/templates/daemonset-libvirt.yaml
+@@ -32,10 +32,6 @@ exec:
+ {{- $configMapName := index . 1 }}
+ {{- $serviceAccountName := index . 2 }}
+ {{- $envAll := index . 3 }}
+-{{- $ssl_enabled := false }}
+-{{- if eq $envAll.Values.conf.libvirt.listen_tls "1" }}
+-{{- $ssl_enabled = true }}
+-{{- end }}
+ {{- with $envAll }}
+ 
+ {{- $mounts_libvirt := .Values.pod.mounts.libvirt.libvirt }}
+@@ -60,6 +56,7 @@ spec:
+       labels:
+ {{ tuple $envAll .Chart.Name $daemonset | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+       annotations:
++        kubectl.kubernetes.io/default-container: libvirt
+ {{- dict "envAll" $envAll "podName" "libvirt-libvirt-default" "containerNames" (list "libvirt") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
+ {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+         configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
+@@ -79,80 +76,6 @@ spec:
+       initContainers:
+ {{ tuple $envAll "pod_dependency" $mounts_libvirt_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+ {{ dict "envAll" $envAll | include "helm-toolkit.snippets.kubernetes_apparmor_loader_init_container" | indent 8 }}
+-{{- if $ssl_enabled }}
+-        - name: cert-init-api
+-{{ tuple $envAll "kubectl" | include "helm-toolkit.snippets.image" | indent 10 }}
+-{{ dict "envAll" $envAll "application" "libvirt" "container" "cert_init" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+-          command:
+-            - /tmp/cert-init.sh
+-          env:
+-            - name: TYPE
+-              value: api
+-            - name: ISSUER_KIND
+-              value: {{ .Values.issuers.libvirt.kind }}
+-            - name: ISSUER_NAME
+-              value: {{ .Values.issuers.libvirt.name }}
+-            - name: POD_UID
+-              valueFrom:
+-                fieldRef:
+-                  fieldPath: metadata.uid
+-            - name: POD_NAME
+-              valueFrom:
+-                fieldRef:
+-                  fieldPath: metadata.name
+-            - name: POD_NAMESPACE
+-              valueFrom:
+-                fieldRef:
+-                  fieldPath: metadata.namespace
+-            - name: POD_IP
+-              valueFrom:
+-                fieldRef:
+-                  fieldPath: status.podIP
+-          volumeMounts:
+-            - name: pod-tmp
+-              mountPath: /tmp
+-            - name: libvirt-bin
+-              mountPath: /tmp/cert-init.sh
+-              subPath: cert-init.sh
+-              readOnly: true
+-{{- end }}
+-{{- if eq .Values.conf.qemu.vnc_tls "1" }}
+-        - name: cert-init-vnc
+-{{ tuple $envAll "kubectl" | include "helm-toolkit.snippets.image" | indent 10 }}
+-{{ dict "envAll" $envAll "application" "libvirt" "container" "cert_init" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+-          command:
+-            - /tmp/cert-init.sh
+-          env:
+-            - name: TYPE
+-              value: vnc
+-            - name: ISSUER_KIND
+-              value: {{ .Values.issuers.vencrypt.kind }}
+-            - name: ISSUER_NAME
+-              value: {{ .Values.issuers.vencrypt.name }}
+-            - name: POD_UID
+-              valueFrom:
+-                fieldRef:
+-                  fieldPath: metadata.uid
+-            - name: POD_NAME
+-              valueFrom:
+-                fieldRef:
+-                  fieldPath: metadata.name
+-            - name: POD_NAMESPACE
+-              valueFrom:
+-                fieldRef:
+-                  fieldPath: metadata.namespace
+-            - name: POD_IP
+-              valueFrom:
+-                fieldRef:
+-                  fieldPath: status.podIP
+-          volumeMounts:
+-            - name: pod-tmp
+-              mountPath: /tmp
+-            - name: libvirt-bin
+-              mountPath: /tmp/cert-init.sh
+-              subPath: cert-init.sh
+-              readOnly: true
+-{{- end }}
+ {{- if .Values.conf.ceph.enabled }}
+         {{- if empty .Values.conf.ceph.cinder.keyring }}
+         - name: ceph-admin-keyring-placement
+@@ -205,6 +128,44 @@ spec:
+               readOnly: true
+ {{- end }}
+       containers:
++        - name: tls-sidecar
++{{ tuple $envAll "libvirt_tls_sidecar" | include "helm-toolkit.snippets.image" | indent 10 }}
++{{ tuple $envAll $envAll.Values.pod.resources.libvirt_tls_sidecar | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
++{{ dict "envAll" $envAll "application" "libvirt" "container" "libvirt_tls_sidecar" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
++          env:
++            - name: API_ISSUER_KIND
++              value: {{ .Values.issuers.libvirt.kind }}
++            - name: API_ISSUER_NAME
++              value: {{ .Values.issuers.libvirt.name }}
++            - name: VNC_ISSUER_KIND
++              value: {{ .Values.issuers.vencrypt.kind }}
++            - name: VNC_ISSUER_NAME
++              value: {{ .Values.issuers.vencrypt.name }}
++            - name: POD_UID
++              valueFrom:
++                fieldRef:
++                  fieldPath: metadata.uid
++            - name: POD_NAME
++              valueFrom:
++                fieldRef:
++                  fieldPath: metadata.name
++            - name: POD_NAMESPACE
++              valueFrom:
++                fieldRef:
++                  fieldPath: metadata.namespace
++            - name: POD_IP
++              valueFrom:
++                fieldRef:
++                  fieldPath: status.podIP
++          volumeMounts:
++            - name: etc-pki-qemu
++              mountPath: /etc/pki/qemu
++            - name: etc-pki-ca
++              mountPath: /etc/pki/CA
++            - name: etc-pki-libvirt
++              mountPath: /etc/pki/libvirt
++            - name: etc-pki-libvirt-vnc
++              mountPath: /etc/pki/libvirt-vnc
+         - name: libvirt
+ {{ tuple $envAll "libvirt" | include "helm-toolkit.snippets.image" | indent 10 }}
+ {{ tuple $envAll $envAll.Values.pod.resources.libvirt | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+@@ -231,6 +192,10 @@ spec:
+           command:
+             - /tmp/libvirt.sh
+           lifecycle:
++            postStart:
++              exec:
++                command:
++                  - /tmp/wait-for-libvirt.sh
+             preStop:
+               exec:
+                 command:
+@@ -239,16 +204,24 @@ spec:
+                   - |-
+                     kill $(cat /var/run/libvirtd.pid)
+           volumeMounts:
+-{{- if $ssl_enabled }}
+             - name: etc-pki-qemu
+               mountPath: /etc/pki/qemu
+-{{- end }}
++            - name: etc-pki-ca
++              mountPath: /etc/pki/CA
++            - name: etc-pki-libvirt
++              mountPath: /etc/pki/libvirt
++            - name: etc-pki-libvirt-vnc
++              mountPath: /etc/pki/libvirt-vnc
+             - name: pod-tmp
+               mountPath: /tmp
+             - name: libvirt-bin
+               mountPath: /tmp/libvirt.sh
+               subPath: libvirt.sh
+               readOnly: true
++            - name: libvirt-bin
++              mountPath: /tmp/wait-for-libvirt.sh
++              subPath: wait-for-libvirt.sh
++              readOnly: true
+             - name: libvirt-etc
+               mountPath: /etc/libvirt/libvirtd.conf
+               subPath: libvirtd.conf
+@@ -328,11 +301,15 @@ spec:
+               {{- end }}
+         {{- end }}
+       volumes:
+-{{- if $ssl_enabled }}
+         - name: etc-pki-qemu
+           hostPath:
+             path: /etc/pki/qemu
+-{{- end }}
++        - name: etc-pki-ca
++          emptyDir: {}
++        - name: etc-pki-libvirt
++          emptyDir: {}
++        - name: etc-pki-libvirt-vnc
++          emptyDir: {}
+         - name: pod-tmp
+           emptyDir: {}
+         - name: libvirt-bin
+diff --git b/libvirt/templates/role-cert-manager.yaml a/charts/libvirt/templates/role-cert-manager.yaml
+index b830690c..c7f7b3cd 100644
+--- b/libvirt/templates/role-cert-manager.yaml
++++ a/libvirt/templates/role-cert-manager.yaml
+@@ -48,7 +48,9 @@ rules:
+       - ""
+     verbs:
+       - get
++      - list
+       - patch
++      - watch
+     resources:
+       - secrets
+-{{- end -}}
+\ No newline at end of file
++{{- end -}}
+diff --git b/libvirt/values.yaml a/charts/libvirt/values.yaml
+index 207b8fbf..4ab23536 100644
+--- b/libvirt/values.yaml
++++ a/libvirt/values.yaml
+@@ -27,6 +27,7 @@ labels:
+ images:
+   tags:
+     libvirt: docker.io/openstackhelm/libvirt:latest-ubuntu_focal
++    libvirt_tls_sidecar: ghcr.io/vexxhost/atmosphere/libvirt-tls-sidecar:latest
+     libvirt_exporter: vexxhost/libvirtd-exporter:latest
+     ceph_config_helper: 'docker.io/openstackhelm/ceph-config-helper:ubuntu_focal_18.2.0-1-20231013'
+     dep_check: quay.io/airshipit/kubernetes-entrypoint:v1.0.0
+@@ -271,55 +272,6 @@ dependencies:
+         - endpoint: internal
+           service: local_image_registry
+ 
+-scripts:
+-  # Script is included here (vs in bin/) to allow overriding.
+-  cert_init_sh: |
+-    #!/bin/bash
+-    set -x
+-
+-    HOSTNAME_FQDN=$(hostname --fqdn)
+-
+-    # Script to create certs for each libvirt pod based on pod IP (by default).
+-    cat <<EOF | kubectl apply -f -
+-    apiVersion: cert-manager.io/v1
+-    kind: Certificate
+-    metadata:
+-      name: ${POD_NAME}-${TYPE}
+-      namespace: ${POD_NAMESPACE}
+-      ownerReferences:
+-        - apiVersion: v1
+-          kind: Pod
+-          name: ${POD_NAME}
+-          uid: ${POD_UID}
+-    spec:
+-      secretName: ${POD_NAME}-${TYPE}
+-      commonName: ${POD_IP}
+-      usages:
+-      - client auth
+-      - server auth
+-      dnsNames:
+-      - ${HOSTNAME}
+-      - ${HOSTNAME_FQDN}
+-      ipAddresses:
+-      - ${POD_IP}
+-      issuerRef:
+-        kind: ${ISSUER_KIND}
+-        name: ${ISSUER_NAME}
+-    EOF
+-
+-    kubectl -n ${POD_NAMESPACE} wait --for=condition=Ready --timeout=300s \
+-      certificate/${POD_NAME}-${TYPE}
+-
+-    # NOTE(mnaser): cert-manager does not clean-up the secrets when the certificate
+-    #               is deleted, so we should add an owner reference to the secret
+-    #               to ensure that it is cleaned up when the pod is deleted.
+-    kubectl -n ${POD_NAMESPACE} patch secret ${POD_NAME}-${TYPE} \
+-      --type=json -p='[{"op": "add", "path": "/metadata/ownerReferences", "value": [{"apiVersion": "v1", "kind": "Pod", "name": "'${POD_NAME}'", "uid": "'${POD_UID}'"}]}]'
+-
+-    kubectl -n ${POD_NAMESPACE} get secret ${POD_NAME}-${TYPE} -o jsonpath='{.data.tls\.crt}' | base64 -d > /tmp/${TYPE}.crt
+-    kubectl -n ${POD_NAMESPACE} get secret ${POD_NAME}-${TYPE} -o jsonpath='{.data.tls\.key}' | base64 -d > /tmp/${TYPE}.key
+-    kubectl -n ${POD_NAMESPACE} get secret ${POD_NAME}-${TYPE} -o jsonpath='{.data.ca\.crt}' | base64 -d > /tmp/${TYPE}-ca.crt
+-
+ manifests:
+   configmap_bin: true
+   configmap_etc: true
diff --git a/charts/patches/magnum/0001-tune-uwsgi-config.patch b/charts/patches/magnum/0001-tune-uwsgi-config.patch
new file mode 100644
index 0000000..3a0d903
--- /dev/null
+++ b/charts/patches/magnum/0001-tune-uwsgi-config.patch
@@ -0,0 +1,25 @@
+diff --git b/magnum/values.yaml a/charts/magnum/values.yaml
+index 56232eb8..88b4203e 100644
+--- b/magnum/values.yaml
++++ a/magnum/values.yaml
+@@ -161,15 +161,20 @@ conf:
+     uwsgi:
+       add-header: "Connection: close"
+       buffer-size: 65535
++      chunked-input-limit: "4096000"
+       die-on-term: true
+       enable-threads: true
+       exit-on-reload: false
+       hook-master-start: unix_signal:15 gracefully_kill_them_all
++      http-auto-chunked: true
++      http-raw-body: true
+       lazy-apps: true
+       log-x-forwarded-for: true
+       master: true
++      need-app: true
+       procname-prefix-spaced: "magnum-api:"
+       route-user-agent: '^kube-probe.* donotlog:'
++      socket-timeout: 10
+       thunder-lock: true
+       worker-reload-mercy: 80
+       wsgi-file: /var/lib/openstack/bin/magnum-api-wsgi
diff --git a/charts/patches/manila/0001-tune-uwsgi-config.patch b/charts/patches/manila/0001-tune-uwsgi-config.patch
new file mode 100644
index 0000000..cd87606
--- /dev/null
+++ b/charts/patches/manila/0001-tune-uwsgi-config.patch
@@ -0,0 +1,25 @@
+diff --git b/manila/values.yaml a/charts/manila/values.yaml
+index e54f214c..f820bc1f 100644
+--- b/manila/values.yaml
++++ a/manila/values.yaml
+@@ -806,15 +806,20 @@ conf:
+     uwsgi:
+       add-header: "Connection: close"
+       buffer-size: 65535
++      chunked-input-limit: "4096000"
+       die-on-term: true
+       enable-threads: true
+       exit-on-reload: false
+       hook-master-start: unix_signal:15 gracefully_kill_them_all
++      http-auto-chunked: true
++      http-raw-body: true
+       lazy-apps: true
+       log-x-forwarded-for: true
+       master: true
++      need-app: true
+       procname-prefix-spaced: "manila-api:"
+       route-user-agent: '^kube-probe.* donotlog:'
++      socket-timeout: 10
+       thunder-lock: true
+       worker-reload-mercy: 80
+       wsgi-file: /var/lib/openstack/bin/manila-wsgi
diff --git a/charts/patches/neutron/0001-fix-role-for-user.patch b/charts/patches/neutron/0001-fix-role-for-user.patch
new file mode 100644
index 0000000..0a05416
--- /dev/null
+++ b/charts/patches/neutron/0001-fix-role-for-user.patch
@@ -0,0 +1,13 @@
+diff --git b/neutron/values.yaml a/charts/neutron/values.yaml
+index 747baa53..8d5e9446 100644
+--- b/neutron/values.yaml
++++ a/neutron/values.yaml
+@@ -2316,7 +2316,7 @@ endpoints:
+         user_domain_name: default
+         project_domain_name: default
+       neutron:
+-        role: admin
++        role: admin,service
+         region_name: RegionOne
+         username: neutron
+         password: password
diff --git a/charts/patches/nova/0001-tune-uwsgi-config.patch b/charts/patches/nova/0001-tune-uwsgi-config.patch
new file mode 100644
index 0000000..eb6e791
--- /dev/null
+++ b/charts/patches/nova/0001-tune-uwsgi-config.patch
@@ -0,0 +1,46 @@
+diff --git b/nova/values.yaml a/charts/nova/values.yaml
+index df2e2ff6..fe02e605 100644
+--- b/nova/values.yaml
++++ a/nova/values.yaml
+@@ -1539,15 +1539,20 @@ conf:
+     uwsgi:
+       add-header: "Connection: close"
+       buffer-size: 65535
++      chunked-input-limit: "4096000"
+       die-on-term: true
+       enable-threads: true
+       exit-on-reload: false
+       hook-master-start: unix_signal:15 gracefully_kill_them_all
++      http-auto-chunked: true
++      http-raw-body: true
+       lazy-apps: true
+       log-x-forwarded-for: true
+       master: true
++      need-app: true
+       procname-prefix-spaced: "nova-api:"
+       route-user-agent: '^kube-probe.* donotlog:'
++      socket-timeout: 10
+       thunder-lock: true
+       worker-reload-mercy: 80
+       wsgi-file: /var/lib/openstack/bin/nova-api-wsgi
+@@ -1555,15 +1560,20 @@ conf:
+     uwsgi:
+       add-header: "Connection: close"
+       buffer-size: 65535
++      chunked-input-limit: 4096000
+       die-on-term: true
+       enable-threads: true
+       exit-on-reload: false
+       hook-master-start: unix_signal:15 gracefully_kill_them_all
++      http-auto-chunked: true
++      http-raw-body: true
+       lazy-apps: true
+       log-x-forwarded-for: true
+       master: true
++      need-app: true
+       procname-prefix-spaced: "nova-metadata:"
+       route-user-agent: '^kube-probe.* donotlog:'
++      socket-timeout: 10
+       thunder-lock: true
+       worker-reload-mercy: 80
+       wsgi-file: /var/lib/openstack/bin/nova-metadata-wsgi
diff --git a/charts/patches/octavia/0001-tune-uwsgi-config.patch b/charts/patches/octavia/0001-tune-uwsgi-config.patch
new file mode 100644
index 0000000..209e413
--- /dev/null
+++ b/charts/patches/octavia/0001-tune-uwsgi-config.patch
@@ -0,0 +1,25 @@
+diff --git b/octavia/values.yaml a/charts/octavia/values.yaml
+index 699aa05d..b15114a5 100644
+--- b/octavia/values.yaml
++++ a/octavia/values.yaml
+@@ -336,15 +336,20 @@ conf:
+       processes: 4
+       add-header: "Connection: close"
+       buffer-size: 65535
++      chunked-input-limit: "4096000"
+       die-on-term: true
+       enable-threads: true
+       exit-on-reload: false
+       hook-master-start: unix_signal:15 gracefully_kill_them_all
++      http-auto-chunked: true
++      http-raw-body: true
+       lazy-apps: true
+       log-x-forwarded-for: true
+       master: true
++      need-app: true
+       procname-prefix-spaced: "octavia-api:"
+       route-user-agent: '^kube-probe.* donotlog:'
++      socket-timeout: 10
+       thunder-lock: true
+       worker-reload-mercy: 80
+       wsgi-file: /var/lib/openstack/bin/octavia-wsgi
diff --git a/charts/patches/ovn/0001-switch-to-ovn-kubernetes.patch b/charts/patches/ovn/0001-switch-to-ovn-kubernetes.patch
new file mode 100644
index 0000000..f8dc4c1
--- /dev/null
+++ b/charts/patches/ovn/0001-switch-to-ovn-kubernetes.patch
@@ -0,0 +1,1015 @@
+diff --git b/ovn/templates/bin/_ovn-controller-init.sh.tpl a/charts/ovn/templates/bin/_ovn-controller-init.sh.tpl
+index 1e61577d..77e1e687 100644
+--- b/ovn/templates/bin/_ovn-controller-init.sh.tpl
++++ a/ovn/templates/bin/_ovn-controller-init.sh.tpl
+@@ -14,6 +14,8 @@
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+ 
++ANNOTATION_KEY="atmosphere.cloud/ovn-system-id"
++
+ function get_ip_address_from_interface {
+   local interface=$1
+   local ip=$(ip -4 -o addr s "${interface}" | awk '{ print $4; exit }' | awk -F '/' '{print $1}')
+@@ -75,6 +77,19 @@ function migrate_ip_from_nic {
+   set -e
+ }
+ 
++function get_current_system_id {
++  ovs-vsctl --if-exists get Open_vSwitch . external_ids:system-id | tr -d '"'
++}
++
++function get_stored_system_id {
++  kubectl get node "$NODE_NAME" -o "jsonpath={.metadata.annotations.atmosphere\.cloud/ovn-system-id}"
++}
++
++function store_system_id() {
++  local system_id=$1
++  kubectl annotate node "$NODE_NAME" "$ANNOTATION_KEY=$system_id"
++}
++
+ # Detect tunnel interface
+ tunnel_interface="{{- .Values.network.interface.tunnel -}}"
+ if [ -z "${tunnel_interface}" ] ; then
+@@ -89,13 +104,25 @@ if [ -z "${tunnel_interface}" ] ; then
+ fi
+ ovs-vsctl set open . external_ids:ovn-encap-ip="$(get_ip_address_from_interface ${tunnel_interface})"
+ 
+-# Configure system ID
+-set +e
+-ovs-vsctl get open . external-ids:system-id
+-if [ $? -eq 1 ]; then
+-  ovs-vsctl set open . external-ids:system-id="$(uuidgen)"
++# Get the stored system-id from the Kubernetes node annotation
++stored_system_id=$(get_stored_system_id)
++
++# Get the current system-id set in OVS
++current_system_id=$(get_current_system_id)
++
++if [ -n "$stored_system_id" ] && [ "$stored_system_id" != "$current_system_id" ]; then
++  # If the annotation exists and does not match the current system-id, set the system-id to the stored one
++  ovs-vsctl set Open_vSwitch . external_ids:system-id="$stored_system_id"
++elif [ -z "$current_system_id" ]; then
++  # If no current system-id is set, generate a new one
++  current_system_id=$(uuidgen)
++  ovs-vsctl set Open_vSwitch . external_ids:system-id="$current_system_id"
++  # Store the new system-id in the Kubernetes node annotation
++  store_system_id "$current_system_id"
++elif [ -z "$stored_system_id" ]; then
++  # If there is no stored system-id, store the current one
++  store_system_id "$current_system_id"
+ fi
+-set -e
+ 
+ # Configure OVN remote
+ {{- if empty .Values.conf.ovn_remote -}}
+@@ -118,6 +145,9 @@ ovs-vsctl set open . external-ids:ovn-encap-type="{{ .Values.conf.ovn_encap_type
+ ovs-vsctl set open . external-ids:ovn-bridge="{{ .Values.conf.ovn_bridge }}"
+ ovs-vsctl set open . external-ids:ovn-bridge-mappings="{{ .Values.conf.ovn_bridge_mappings }}"
+ ovs-vsctl set open . external-ids:ovn-cms-options="${OVN_CMS_OPTIONS}"
++{{ if .Values.conf.ovn_bridge_datapath_type -}}
++ovs-vsctl set open . external-ids:ovn-bridge-datapath-type="{{ .Values.conf.ovn_bridge_datapath_type }}"
++{{- end }}
+ 
+ # Configure hostname
+ {{- if .Values.conf.use_fqdn.compute }}
+diff --git b/ovn/templates/clusterrole-controller.yaml a/charts/ovn/templates/clusterrole-controller.yaml
+new file mode 100644
+index 00000000..8291f65a
+--- /dev/null
++++ a/ovn/templates/clusterrole-controller.yaml
+@@ -0,0 +1,12 @@
++apiVersion: rbac.authorization.k8s.io/v1
++kind: ClusterRole
++metadata:
++  name: ovn-controller
++rules:
++- apiGroups:
++  - ""
++  resources:
++  - nodes
++  verbs:
++  - get
++  - patch
+diff --git b/ovn/templates/clusterrolebinding-controller.yaml a/charts/ovn/templates/clusterrolebinding-controller.yaml
+new file mode 100644
+index 00000000..c95ef5e9
+--- /dev/null
++++ a/ovn/templates/clusterrolebinding-controller.yaml
+@@ -0,0 +1,15 @@
++apiVersion: rbac.authorization.k8s.io/v1
++kind: ClusterRoleBinding
++metadata:
++  name: ovn-controller
++roleRef:
++  apiGroup: rbac.authorization.k8s.io
++  kind: ClusterRole
++  name: ovn-controller
++subjects:
++- kind: ServiceAccount
++  name: ovn-controller
++  namespace: {{ .Release.Namespace }}
++- kind: ServiceAccount
++  name: ovn-controller-gw
++  namespace: {{ .Release.Namespace }}
+diff --git b/ovn/templates/configmap-bin.yaml a/charts/ovn/templates/configmap-bin.yaml
+index a849dd8a..82001f99 100644
+--- b/ovn/templates/configmap-bin.yaml
++++ a/ovn/templates/configmap-bin.yaml
+@@ -24,12 +24,6 @@ data:
+   image-repo-sync.sh: |
+ {{- include "helm-toolkit.scripts.image_repo_sync" . | indent 4 }}
+ {{- end }}
+-  ovsdb-server.sh: |
+-{{ tuple "bin/_ovsdb-server.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+-  ovn-northd.sh: |
+-{{ tuple "bin/_ovn-northd.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+   ovn-controller-init.sh: |
+ {{ tuple "bin/_ovn-controller-init.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+-  ovn-controller.sh: |
+-{{ tuple "bin/_ovn-controller.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+ {{- end }}
+diff --git b/ovn/templates/daemonset-controller-gw.yaml a/charts/ovn/templates/daemonset-controller-gw.yaml
+index 6307bbab..eb309c5e 100644
+--- b/ovn/templates/daemonset-controller-gw.yaml
++++ a/ovn/templates/daemonset-controller-gw.yaml
+@@ -12,6 +12,15 @@ See the License for the specific language governing permissions and
+ limitations under the License.
+ */}}
+ 
++{{- define "controllerGatewayReadinessProbeTemplate" }}
++exec:
++  command:
++    - /usr/bin/ovn-kube-util
++    - readiness-probe
++    - -t
++    - ovn-controller
++{{- end }}
++
+ {{- if .Values.manifests.daemonset_ovn_controller_gw }}
+ {{- $envAll := . }}
+ 
+@@ -59,6 +68,10 @@ spec:
+           env:
+             - name: OVN_CMS_OPTIONS
+               value: {{ .Values.conf.gw_ovn_cms_options | quote }}
++            - name: NODE_NAME
++              valueFrom:
++                fieldRef:
++                  fieldPath: spec.nodeName
+           volumeMounts:
+             - name: ovn-bin
+               mountPath: /tmp/ovn-controller-init.sh
+@@ -72,25 +85,33 @@ spec:
+               readOnly: true
+       containers:
+         - name: controller
++          command:
++            - /root/ovnkube.sh
++            - ovn-controller
+ {{ tuple $envAll "ovn_controller" | include "helm-toolkit.snippets.image" | indent 10 }}
+ {{ tuple $envAll $envAll.Values.pod.resources.server | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+ {{ dict "envAll" $envAll "application" "ovn_controller_gw" "container" "controller" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+-          command:
+-            - /tmp/ovn-controller.sh
+-            - start
+-          lifecycle:
+-            preStop:
+-              exec:
+-                command:
+-                  - /tmp/ovn-controller.sh
+-                  - stop
++{{ dict "envAll" . "component" "ovn_controller_gw" "container" "controller" "type" "readiness" "probeTemplate" (include "controllerGatewayReadinessProbeTemplate" . | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
++          env:
++            - name: OVN_DAEMONSET_VERSION
++              value: "3"
++            - name: OVN_LOGLEVEL_CONTROLLER
++              value: "-vconsole:info -vfile:info"
++            - name: OVN_KUBERNETES_NAMESPACE
++              valueFrom:
++                fieldRef:
++                  fieldPath: metadata.namespace
++            - name: OVN_KUBERNETES_NB_STATEFULSET
++              value: ovn-ovsdb-nb
++            - name: OVN_KUBERNETES_SB_STATEFULSET
++              value: ovn-ovsdb-sb
++            - name: OVN_SSL_ENABLE
++              value: "no"
+           volumeMounts:
+-            - name: ovn-bin
+-              mountPath: /tmp/ovn-controller.sh
+-              subPath: ovn-controller.sh
+-              readOnly: true
+             - name: run-openvswitch
+-              mountPath: /run/openvswitch
++              mountPath: /var/run/ovn
++            - name: run-openvswitch
++              mountPath: /var/run/openvswitch
+       volumes:
+         - name: ovn-bin
+           configMap:
+diff --git b/ovn/templates/daemonset-controller.yaml a/charts/ovn/templates/daemonset-controller.yaml
+index 85daf70b..b6b0b048 100644
+--- b/ovn/templates/daemonset-controller.yaml
++++ a/ovn/templates/daemonset-controller.yaml
+@@ -12,6 +12,15 @@ See the License for the specific language governing permissions and
+ limitations under the License.
+ */}}
+ 
++{{- define "controllerReadinessProbeTemplate" }}
++exec:
++  command:
++    - /usr/bin/ovn-kube-util
++    - readiness-probe
++    - -t
++    - ovn-controller
++{{- end }}
++
+ {{- if .Values.manifests.daemonset_ovn_controller }}
+ {{- $envAll := . }}
+ 
+@@ -59,6 +68,10 @@ spec:
+           env:
+             - name: OVN_CMS_OPTIONS
+               value: {{ .Values.conf.ovn_cms_options | quote }}
++            - name: NODE_NAME
++              valueFrom:
++                fieldRef:
++                  fieldPath: spec.nodeName
+           volumeMounts:
+             - name: ovn-bin
+               mountPath: /tmp/ovn-controller-init.sh
+@@ -72,25 +85,33 @@ spec:
+               readOnly: true
+       containers:
+         - name: controller
++          command:
++            - /root/ovnkube.sh
++            - ovn-controller
+ {{ tuple $envAll "ovn_controller" | include "helm-toolkit.snippets.image" | indent 10 }}
+ {{ tuple $envAll $envAll.Values.pod.resources.server | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+ {{ dict "envAll" $envAll "application" "ovn_controller" "container" "controller" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+-          command:
+-            - /tmp/ovn-controller.sh
+-            - start
+-          lifecycle:
+-            preStop:
+-              exec:
+-                command:
+-                  - /tmp/ovn-controller.sh
+-                  - stop
++{{ dict "envAll" . "component" "ovn_controller" "container" "controller" "type" "readiness" "probeTemplate" (include "controllerReadinessProbeTemplate" . | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
++          env:
++            - name: OVN_DAEMONSET_VERSION
++              value: "3"
++            - name: OVN_LOGLEVEL_CONTROLLER
++              value: "-vconsole:info -vfile:info"
++            - name: OVN_KUBERNETES_NAMESPACE
++              valueFrom:
++                fieldRef:
++                  fieldPath: metadata.namespace
++            - name: OVN_KUBERNETES_NB_STATEFULSET
++              value: ovn-ovsdb-nb
++            - name: OVN_KUBERNETES_SB_STATEFULSET
++              value: ovn-ovsdb-sb
++            - name: OVN_SSL_ENABLE
++              value: "no"
+           volumeMounts:
+-            - name: ovn-bin
+-              mountPath: /tmp/ovn-controller.sh
+-              subPath: ovn-controller.sh
+-              readOnly: true
+             - name: run-openvswitch
+-              mountPath: /run/openvswitch
++              mountPath: /var/run/ovn
++            - name: run-openvswitch
++              mountPath: /var/run/openvswitch
+       volumes:
+         - name: ovn-bin
+           configMap:
+diff --git b/ovn/templates/deployment-northd.yaml a/charts/ovn/templates/deployment-northd.yaml
+index e3afdd05..ae31b357 100644
+--- b/ovn/templates/deployment-northd.yaml
++++ a/ovn/templates/deployment-northd.yaml
+@@ -12,18 +12,13 @@ See the License for the specific language governing permissions and
+ limitations under the License.
+ */}}
+ 
+-{{- define "livenessProbeTemplate" }}
++{{- define "northdReadinessProbeTemplate" }}
+ exec:
+   command:
+-    - /tmp/ovn-northd.sh
+-    - liveness
+-{{- end }}
+-
+-{{- define "readinessProbeTemplate" }}
+-exec:
+-  command:
+-    - /tmp/ovn-northd.sh
+-    - readiness
++    - /usr/bin/ovn-kube-util
++    - readiness-probe
++    - -t
++    - ovn-northd
+ {{- end }}
+ 
+ {{- if .Values.manifests.deployment_northd }}
+@@ -60,28 +55,26 @@ spec:
+ {{- tuple $envAll "ovn_northd" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+       containers:
+         - name: northd
++          command:
++            - /root/ovnkube.sh
++            - run-ovn-northd
+ {{ tuple $envAll "ovn_northd" | include "helm-toolkit.snippets.image" | indent 10 }}
+ {{ tuple $envAll $envAll.Values.pod.resources.server | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+ {{ dict "envAll" $envAll "application" "ovn_northd" "container" "northd" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+-{{ dict "envAll" . "component" "ovn_northd" "container" "northd" "type" "liveness" "probeTemplate" (include "livenessProbeTemplate" . | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+-{{ dict "envAll" . "component" "ovn_northd" "container" "northd" "type" "readiness" "probeTemplate" (include "readinessProbeTemplate" . | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+-          command:
+-            - /tmp/ovn-northd.sh
+-            - start
+-          lifecycle:
+-            preStop:
+-              exec:
+-                command:
+-                  - /tmp/ovn-northd.sh
+-                  - stop
+-          volumeMounts:
+-            - name: ovn-bin
+-              mountPath: /tmp/ovn-northd.sh
+-              subPath: ovn-northd.sh
+-              readOnly: true
+-      volumes:
+-        - name: ovn-bin
+-          configMap:
+-            name: ovn-bin
+-            defaultMode: 0555
++{{ dict "envAll" . "component" "ovn_northd" "container" "northd" "type" "readiness" "probeTemplate" (include "northdReadinessProbeTemplate" . | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
++          env:
++            - name: OVN_DAEMONSET_VERSION
++              value: "3"
++            - name: OVN_LOGLEVEL_NORTHD
++              value: "-vconsole:info -vfile:info"
++            - name: OVN_KUBERNETES_NAMESPACE
++              valueFrom:
++                fieldRef:
++                  fieldPath: metadata.namespace
++            - name: OVN_KUBERNETES_NB_STATEFULSET
++              value: ovn-ovsdb-nb
++            - name: OVN_KUBERNETES_SB_STATEFULSET
++              value: ovn-ovsdb-sb
++            - name: OVN_SSL_ENABLE
++              value: "no"
+ {{- end }}
+diff --git b/ovn/templates/role-controller.yaml a/charts/ovn/templates/role-controller.yaml
+new file mode 100644
+index 00000000..de3cfa6d
+--- /dev/null
++++ a/ovn/templates/role-controller.yaml
+@@ -0,0 +1,11 @@
++apiVersion: rbac.authorization.k8s.io/v1
++kind: Role
++metadata:
++  name: ovn-controller
++rules:
++- apiGroups:
++  - discovery.k8s.io
++  resources:
++  - endpointslices
++  verbs:
++  - list
+diff --git b/ovn/templates/role-northd.yaml a/charts/ovn/templates/role-northd.yaml
+new file mode 100644
+index 00000000..ca02fae6
+--- /dev/null
++++ a/ovn/templates/role-northd.yaml
+@@ -0,0 +1,11 @@
++apiVersion: rbac.authorization.k8s.io/v1
++kind: Role
++metadata:
++  name: ovn-northd
++rules:
++- apiGroups:
++  - discovery.k8s.io
++  resources:
++  - endpointslices
++  verbs:
++  - list
+diff --git b/ovn/templates/role-ovsdb.yaml a/charts/ovn/templates/role-ovsdb.yaml
+new file mode 100644
+index 00000000..10e0e239
+--- /dev/null
++++ a/ovn/templates/role-ovsdb.yaml
+@@ -0,0 +1,19 @@
++apiVersion: rbac.authorization.k8s.io/v1
++kind: Role
++metadata:
++  name: ovn-ovsdb
++rules:
++- apiGroups:
++  - "apps"
++  resources:
++  - statefulsets
++  verbs:
++  - get
++- apiGroups:
++  - ""
++  resources:
++  - pods
++  - endpoints
++  verbs:
++  - list
++  - get
+diff --git b/ovn/templates/rolebinding-controller.yaml a/charts/ovn/templates/rolebinding-controller.yaml
+new file mode 100644
+index 00000000..7973c7e2
+--- /dev/null
++++ a/ovn/templates/rolebinding-controller.yaml
+@@ -0,0 +1,13 @@
++apiVersion: rbac.authorization.k8s.io/v1
++kind: RoleBinding
++metadata:
++  name: ovn-controller
++roleRef:
++  apiGroup: rbac.authorization.k8s.io
++  kind: Role
++  name: ovn-controller
++subjects:
++- kind: ServiceAccount
++  name: ovn-controller
++- kind: ServiceAccount
++  name: ovn-controller-gw
+diff --git b/ovn/templates/rolebinding-northd.yaml a/charts/ovn/templates/rolebinding-northd.yaml
+new file mode 100644
+index 00000000..428a4707
+--- /dev/null
++++ a/ovn/templates/rolebinding-northd.yaml
+@@ -0,0 +1,11 @@
++apiVersion: rbac.authorization.k8s.io/v1
++kind: RoleBinding
++metadata:
++  name: ovn-northd
++roleRef:
++  apiGroup: rbac.authorization.k8s.io
++  kind: Role
++  name: ovn-northd
++subjects:
++- kind: ServiceAccount
++  name: ovn-northd
+diff --git b/ovn/templates/rolebinding-ovsdb.yaml a/charts/ovn/templates/rolebinding-ovsdb.yaml
+new file mode 100644
+index 00000000..f32382bc
+--- /dev/null
++++ a/ovn/templates/rolebinding-ovsdb.yaml
+@@ -0,0 +1,13 @@
++apiVersion: rbac.authorization.k8s.io/v1
++kind: RoleBinding
++metadata:
++  name: ovn-ovsdb
++roleRef:
++  apiGroup: rbac.authorization.k8s.io
++  kind: Role
++  name: ovn-ovsdb
++subjects:
++- kind: ServiceAccount
++  name: ovn-ovsdb-nb
++- kind: ServiceAccount
++  name: ovn-ovsdb-sb
+diff --git b/ovn/templates/service-ovsdb-nb.yaml a/charts/ovn/templates/service-ovsdb-nb.yaml
+index b93da9b8..56f7cd09 100644
+--- b/ovn/templates/service-ovsdb-nb.yaml
++++ a/ovn/templates/service-ovsdb-nb.yaml
+@@ -20,6 +20,7 @@ kind: Service
+ metadata:
+   name: {{ tuple "ovn-ovsdb-nb" "direct" . | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }}
+ spec:
++  publishNotReadyAddresses: true
+   ports:
+     - name: ovsdb
+       port: {{ tuple "ovn-ovsdb-nb" "internal" "ovsdb" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+diff --git b/ovn/templates/service-ovsdb-sb.yaml a/charts/ovn/templates/service-ovsdb-sb.yaml
+index 70f62c6e..4a6b5864 100644
+--- b/ovn/templates/service-ovsdb-sb.yaml
++++ a/ovn/templates/service-ovsdb-sb.yaml
+@@ -20,6 +20,7 @@ kind: Service
+ metadata:
+   name: {{ tuple "ovn-ovsdb-sb" "direct" . | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }}
+ spec:
++  publishNotReadyAddresses: true
+   ports:
+     - name: ovsdb
+       port: {{ tuple "ovn-ovsdb-sb" "internal" "ovsdb" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+diff --git b/ovn/templates/statefulset-ovsdb-nb.yaml a/charts/ovn/templates/statefulset-ovsdb-nb.yaml
+index c8198279..4866074e 100644
+--- b/ovn/templates/statefulset-ovsdb-nb.yaml
++++ a/ovn/templates/statefulset-ovsdb-nb.yaml
+@@ -12,6 +12,19 @@ See the License for the specific language governing permissions and
+ limitations under the License.
+ */}}
+ 
++{{- define "ovnnbReadinessProbeTemplate" }}
++exec:
++  command:
++    - /usr/bin/ovn-kube-util
++    - readiness-probe
++    - -t
++{{- if gt (int .Values.pod.replicas.ovn_ovsdb_nb) 1 }}
++    - ovnnb-db-raft
++{{- else }}
++    - ovnnb-db
++{{- end }}
++{{- end }}
++
+ {{- if .Values.manifests.statefulset_ovn_ovsdb_nb }}
+ {{- $envAll := . }}
+ 
+@@ -28,6 +41,7 @@ metadata:
+ {{ tuple $envAll "ovn" "ovn-ovsdb-nb" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+ spec:
+   serviceName: {{ tuple "ovn-ovsdb-nb" "direct" . | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }}
++  podManagementPolicy: Parallel
+   replicas: {{ .Values.pod.replicas.ovn_ovsdb_nb }}
+   selector:
+     matchLabels:
+@@ -49,41 +63,54 @@ spec:
+ {{- tuple $envAll "ovn_ovsdb_nb" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+       containers:
+         - name: ovsdb
++          command:
++            - /root/ovnkube.sh
++{{- if gt (int .Values.pod.replicas.ovn_ovsdb_nb) 1 }}
++            - nb-ovsdb-raft
++{{- else }}
++            - nb-ovsdb
++{{- end }}
+ {{ tuple $envAll "ovn_ovsdb_nb" | include "helm-toolkit.snippets.image" | indent 10 }}
+ {{ tuple $envAll $envAll.Values.pod.resources.server | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
++{{ dict "envAll" . "component" "ovn_ovsdb_nb" "container" "ovsdb" "type" "readiness" "probeTemplate" (include "ovnnbReadinessProbeTemplate" . | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+           ports:
+             - containerPort: {{ tuple "ovn-ovsdb-nb" "internal" "ovsdb" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+             - containerPort: {{ tuple "ovn-ovsdb-nb" "internal" "raft" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+           env:
+-            - name: OVS_DATABASE
+-              value: nb
+-            - name: OVS_PORT
++            - name: OVN_DAEMONSET_VERSION
++              value: "3"
++            - name: OVN_LOGLEVEL_NB
++              value: "-vconsole:info -vfile:info"
++            - name: OVN_KUBERNETES_NAMESPACE
++              valueFrom:
++                fieldRef:
++                  fieldPath: metadata.namespace
++            - name: OVN_KUBERNETES_STATEFULSET
++              value: ovn-ovsdb-nb
++            - name: POD_NAME
++              valueFrom:
++                fieldRef:
++                  fieldPath: metadata.name
++            - name: OVN_SSL_ENABLE
++              value: "no"
++            - name: ENABLE_IPSEC
++              value: "false"
++            - name: OVN_NB_RAFT_ELECTION_TIMER
++              value: "1000"
++            - name: OVN_NB_PORT
+               value: {{ tuple "ovn-ovsdb-nb" "internal" "ovsdb" . | include "helm-toolkit.endpoints.endpoint_port_lookup" | quote }}
+-          command:
+-            - /tmp/ovsdb-server.sh
+-            - start
+-          lifecycle:
+-            preStop:
+-              exec:
+-                command:
+-                  - /tmp/ovsdb-server.sh
+-                  - stop
++            - name: OVN_NB_RAFT_PORT
++              value: {{ tuple "ovn-ovsdb-nb" "internal" "raft" . | include "helm-toolkit.endpoints.endpoint_port_lookup" | quote }}
+           volumeMounts:
+-            - name: ovn-bin
+-              mountPath: /tmp/ovsdb-server.sh
+-              subPath: ovsdb-server.sh
+-              readOnly: true
+             - name: run-openvswitch
+-              mountPath: /run/openvswitch
++              mountPath: /var/run/openvswitch
++            - name: run-openvswitch
++              mountPath: /var/run/ovn
+             - name: data
+-              mountPath: {{ $envAll.Values.volume.ovn_ovsdb_nb.path }}
++              mountPath: /etc/ovn
+       volumes:
+         - name: run-openvswitch
+           emptyDir: {}
+-        - name: ovn-bin
+-          configMap:
+-            name: ovn-bin
+-            defaultMode: 0555
+ {{- if not .Values.volume.ovn_ovsdb_nb.enabled }}
+         - name: data
+           emptyDir: {}
+diff --git b/ovn/templates/statefulset-ovsdb-sb.yaml a/charts/ovn/templates/statefulset-ovsdb-sb.yaml
+index 916ef94d..92af96de 100644
+--- b/ovn/templates/statefulset-ovsdb-sb.yaml
++++ a/ovn/templates/statefulset-ovsdb-sb.yaml
+@@ -12,6 +12,19 @@ See the License for the specific language governing permissions and
+ limitations under the License.
+ */}}
+ 
++{{- define "ovnsbReadinessProbeTemplate" }}
++exec:
++  command:
++    - /usr/bin/ovn-kube-util
++    - readiness-probe
++    - -t
++{{- if gt (int .Values.pod.replicas.ovn_ovsdb_sb) 1 }}
++    - ovnsb-db-raft
++{{- else }}
++    - ovnsb-db
++{{- end }}
++{{- end }}
++
+ {{- if .Values.manifests.statefulset_ovn_ovsdb_sb }}
+ {{- $envAll := . }}
+ 
+@@ -28,6 +41,7 @@ metadata:
+ {{ tuple $envAll "ovn" "ovn-ovsdb-sb" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+ spec:
+   serviceName: {{ tuple "ovn-ovsdb-sb" "direct" . | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }}
++  podManagementPolicy: Parallel
+   replicas: {{ .Values.pod.replicas.ovn_ovsdb_sb }}
+   selector:
+     matchLabels:
+@@ -49,41 +63,54 @@ spec:
+ {{- tuple $envAll "ovn_ovsdb_sb" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+       containers:
+         - name: ovsdb
++          command:
++            - /root/ovnkube.sh
++{{- if gt (int .Values.pod.replicas.ovn_ovsdb_sb) 1 }}
++            - sb-ovsdb-raft
++{{- else }}
++            - sb-ovsdb
++{{- end }}
+ {{ tuple $envAll "ovn_ovsdb_sb" | include "helm-toolkit.snippets.image" | indent 10 }}
+ {{ tuple $envAll $envAll.Values.pod.resources.server | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
++{{ dict "envAll" . "component" "ovn_ovsdb_sb" "container" "ovsdb" "type" "readiness" "probeTemplate" (include "ovnsbReadinessProbeTemplate" . | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+           ports:
+             - containerPort: {{ tuple "ovn-ovsdb-sb" "internal" "ovsdb" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+             - containerPort: {{ tuple "ovn-ovsdb-sb" "internal" "raft" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+           env:
+-            - name: OVS_DATABASE
+-              value: sb
+-            - name: OVS_PORT
++            - name: OVN_DAEMONSET_VERSION
++              value: "3"
++            - name: OVN_LOGLEVEL_SB
++              value: "-vconsole:info -vfile:info"
++            - name: OVN_KUBERNETES_NAMESPACE
++              valueFrom:
++                fieldRef:
++                  fieldPath: metadata.namespace
++            - name: OVN_KUBERNETES_STATEFULSET
++              value: ovn-ovsdb-sb
++            - name: POD_NAME
++              valueFrom:
++                fieldRef:
++                  fieldPath: metadata.name
++            - name: OVN_SSL_ENABLE
++              value: "no"
++            - name: ENABLE_IPSEC
++              value: "false"
++            - name: OVN_SB_RAFT_ELECTION_TIMER
++              value: "1000"
++            - name: OVN_SB_PORT
+               value: {{ tuple "ovn-ovsdb-sb" "internal" "ovsdb" . | include "helm-toolkit.endpoints.endpoint_port_lookup" | quote }}
+-          command:
+-            - /tmp/ovsdb-server.sh
+-            - start
+-          lifecycle:
+-            preStop:
+-              exec:
+-                command:
+-                  - /tmp/ovsdb-server.sh
+-                  - stop
++            - name: OVN_SB_RAFT_PORT
++              value: {{ tuple "ovn-ovsdb-sb" "internal" "raft" . | include "helm-toolkit.endpoints.endpoint_port_lookup" | quote }}
+           volumeMounts:
+-            - name: ovn-bin
+-              mountPath: /tmp/ovsdb-server.sh
+-              subPath: ovsdb-server.sh
+-              readOnly: true
+             - name: run-openvswitch
+-              mountPath: /run/openvswitch
++              mountPath: /var/run/openvswitch
++            - name: run-openvswitch
++              mountPath: /var/run/ovn
+             - name: data
+-              mountPath: {{ $envAll.Values.volume.ovn_ovsdb_sb.path }}
++              mountPath: /etc/ovn
+       volumes:
+         - name: run-openvswitch
+           emptyDir: {}
+-        - name: ovn-bin
+-          configMap:
+-            name: ovn-bin
+-            defaultMode: 0555
+ {{- if not .Values.volume.ovn_ovsdb_sb.enabled }}
+         - name: data
+           emptyDir: {}
+@@ -93,10 +120,10 @@ spec:
+         name: data
+       spec:
+         accessModes: ["ReadWriteOnce"]
++        storageClassName: {{ $envAll.Values.volume.ovn_ovsdb_sb.class_name }}
+         resources:
+           requests:
+             storage: {{ $envAll.Values.volume.ovn_ovsdb_sb.size }}
+-        storageClassName: {{ $envAll.Values.volume.ovn_ovsdb_sb.class_name }}
+ {{- end }}
+ 
+ {{- end }}
+diff --git b/ovn/values.yaml a/charts/ovn/values.yaml
+index 518dd71e..214dd16f 100644
+--- b/ovn/values.yaml
++++ a/ovn/values.yaml
+@@ -52,12 +52,10 @@ labels:
+ 
+ volume:
+   ovn_ovsdb_nb:
+-    path: /var/lib/ovn
+     enabled: true
+     class_name: general
+     size: 5Gi
+   ovn_ovsdb_sb:
+-    path: /var/lib/ovn
+     enabled: true
+     class_name: general
+     size: 5Gi
+@@ -76,6 +74,8 @@ conf:
+   ovn_encap_type: geneve
+   ovn_bridge: br-int
+   ovn_bridge_mappings: external:br-ex
++  # For DPDK enabled environments, enable netdev datapath type for br-int
++  # ovn_bridge_datapath_type: netdev
+ 
+   # auto_bridge_add:
+   #   br-private: eth0
+@@ -138,13 +138,41 @@ pod:
+         readiness:
+           enabled: true
+           params:
+-            initialDelaySeconds: 5
+-            timeoutSeconds: 10
+-        liveness:
++            initialDelaySeconds: 30
++            timeoutSeconds: 30
++            periodSeconds: 60
++    ovn_ovsdb_nb:
++      ovsdb:
++        readiness:
++          enabled: true
++          params:
++            initialDelaySeconds: 30
++            timeoutSeconds: 30
++            periodSeconds: 60
++    ovn_ovsdb_sb:
++      ovsdb:
++        readiness:
++          enabled: true
++          params:
++            initialDelaySeconds: 30
++            timeoutSeconds: 30
++            periodSeconds: 60
++    ovn_controller:
++      controller:
++        readiness:
++          enabled: true
++          params:
++            initialDelaySeconds: 30
++            timeoutSeconds: 30
++            periodSeconds: 60
++    ovn_controller_gw:
++      controller:
++        readiness:
+           enabled: true
+           params:
+-            initialDelaySeconds: 5
+-            timeoutSeconds: 10
++            initialDelaySeconds: 30
++            timeoutSeconds: 30
++            periodSeconds: 60
+   dns_policy: "ClusterFirstWithHostNet"
+   replicas:
+     ovn_ovsdb_nb: 1
+@@ -179,18 +207,18 @@ pod:
+     ovs:
+       ovn_ovsdb_nb:
+         requests:
+-          memory: "128Mi"
++          memory: "384Mi"
+           cpu: "100m"
+         limits:
+           memory: "1024Mi"
+-          cpu: "2000m"
++          cpu: "1000m"
+       ovn_ovsdb_sb:
+         requests:
+-          memory: "128Mi"
++          memory: "384Mi"
+           cpu: "100m"
+         limits:
+           memory: "1024Mi"
+-          cpu: "2000m"
++          cpu: "1000m"
+       ovn_northd:
+         requests:
+           memory: "128Mi"
+diff --git b/ovn/templates/bin/_ovn-controller.sh.tpl a/charts/ovn/templates/bin/_ovn-controller.sh.tpl
+deleted file mode 100644
+index ecb659d2..00000000
+--- b/ovn/templates/bin/_ovn-controller.sh.tpl
++++ /dev/null
+@@ -1,39 +0,0 @@
+-#!/bin/bash -xe
+-
+-# Copyright 2023 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.
+-
+-COMMAND="${@:-start}"
+-
+-function start () {
+-  /usr/share/ovn/scripts/ovn-ctl start_controller \
+-    --ovn-manage-ovsdb=no
+-
+-  tail --follow=name /var/log/ovn/ovn-controller.log
+-}
+-
+-function stop () {
+-  /usr/share/ovn/scripts/ovn-ctl stop_controller
+-  pkill tail
+-}
+-
+-function liveness () {
+-  ovs-appctl -t /var/run/ovn/ovn-controller.$(cat /var/run/ovn/ovn-controller.pid).ctl status
+-}
+-
+-function readiness () {
+-  ovs-appctl -t /var/run/ovn/ovn-controller.$(cat /var/run/ovn/ovn-controller.pid).ctl status
+-}
+-
+-$COMMAND
+diff --git b/ovn/templates/bin/_ovn-northd.sh.tpl a/charts/ovn/templates/bin/_ovn-northd.sh.tpl
+deleted file mode 100644
+index fefd793c..00000000
+--- b/ovn/templates/bin/_ovn-northd.sh.tpl
++++ /dev/null
+@@ -1,57 +0,0 @@
+-#!/bin/bash -xe
+-
+-# Copyright 2023 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.
+-
+-COMMAND="${@:-start}"
+-
+-{{- $nb_svc_name := "ovn-ovsdb-nb" -}}
+-{{- $nb_svc := (tuple $nb_svc_name "internal" . | include "helm-toolkit.endpoints.hostname_fqdn_endpoint_lookup") -}}
+-{{- $nb_port := (tuple "ovn-ovsdb-nb" "internal" "ovsdb" . | include "helm-toolkit.endpoints.endpoint_port_lookup") -}}
+-{{- $nb_service_list := list -}}
+-{{- range $i := until (.Values.pod.replicas.ovn_ovsdb_nb | int) -}}
+-  {{- $nb_service_list = printf "tcp:%s-%d.%s:%s" $nb_svc_name $i $nb_svc $nb_port | append $nb_service_list -}}
+-{{- end -}}
+-
+-{{- $sb_svc_name := "ovn-ovsdb-sb" -}}
+-{{- $sb_svc := (tuple $sb_svc_name "internal" . | include "helm-toolkit.endpoints.hostname_fqdn_endpoint_lookup") -}}
+-{{- $sb_port := (tuple "ovn-ovsdb-sb" "internal" "ovsdb" . | include "helm-toolkit.endpoints.endpoint_port_lookup") -}}
+-{{- $sb_service_list := list -}}
+-{{- range $i := until (.Values.pod.replicas.ovn_ovsdb_sb | int) -}}
+-  {{- $sb_service_list = printf "tcp:%s-%d.%s:%s" $sb_svc_name $i $sb_svc $sb_port | append $sb_service_list -}}
+-{{- end }}
+-
+-function start () {
+-  /usr/share/ovn/scripts/ovn-ctl start_northd \
+-    --ovn-manage-ovsdb=no \
+-    --ovn-northd-nb-db={{ include "helm-toolkit.utils.joinListWithComma" $nb_service_list }} \
+-    --ovn-northd-sb-db={{ include "helm-toolkit.utils.joinListWithComma" $sb_service_list }}
+-
+-  tail --follow=name /var/log/ovn/ovn-northd.log
+-}
+-
+-function stop () {
+-  /usr/share/ovn/scripts/ovn-ctl stop_northd
+-  pkill tail
+-}
+-
+-function liveness () {
+-  ovs-appctl -t /var/run/ovn/ovn-northd.$(cat /var/run/ovn/ovn-northd.pid).ctl status
+-}
+-
+-function readiness () {
+-  ovs-appctl -t /var/run/ovn/ovn-northd.$(cat /var/run/ovn/ovn-northd.pid).ctl status
+-}
+-
+-$COMMAND
+diff --git b/ovn/templates/bin/_ovsdb-server.sh.tpl a/charts/ovn/templates/bin/_ovsdb-server.sh.tpl
+deleted file mode 100644
+index e023505b..00000000
+--- b/ovn/templates/bin/_ovsdb-server.sh.tpl
++++ /dev/null
+@@ -1,72 +0,0 @@
+-#!/bin/bash -xe
+-
+-# Copyright 2023 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.
+-
+-COMMAND="${@:-start}"
+-
+-OVSDB_HOST=$(hostname -f)
+-ARGS=(
+-  --db-${OVS_DATABASE}-create-insecure-remote=yes
+-  --db-${OVS_DATABASE}-cluster-local-proto=tcp
+-  --db-${OVS_DATABASE}-cluster-local-addr=$(hostname -f)
+-)
+-
+-if [[ ! $HOSTNAME == *-0 && $OVSDB_HOST =~ (.+)-([0-9]+)\. ]]; then
+-  OVSDB_BOOTSTRAP_HOST="${BASH_REMATCH[1]}-0.${OVSDB_HOST#*.}"
+-
+-  ARGS+=(
+-    --db-${OVS_DATABASE}-cluster-remote-proto=tcp
+-    --db-${OVS_DATABASE}-cluster-remote-addr=${OVSDB_BOOTSTRAP_HOST}
+-  )
+-fi
+-
+-function start () {
+-  /usr/share/ovn/scripts/ovn-ctl start_${OVS_DATABASE}_ovsdb ${ARGS[@]}
+-
+-  tail --follow=name /var/log/ovn/ovsdb-server-${OVS_DATABASE}.log
+-}
+-
+-function stop () {
+-  /usr/share/ovn/scripts/ovn-ctl stop_${OVS_DATABASE}_ovsdb
+-  pkill tail
+-}
+-
+-function liveness () {
+-  if [[ $OVS_DATABASE == "nb" ]]; then
+-    OVN_DATABASE="Northbound"
+-  elif [[ $OVS_DATABASE == "sb" ]]; then
+-    OVN_DATABASE="Southbound"
+-  else
+-    echo "OVS_DATABASE must be nb or sb"
+-    exit 1
+-  fi
+-
+-  ovs-appctl -t /var/run/ovn/ovn${OVS_DATABASE}_db.ctl cluster/status OVN_${OVN_DATABASE}
+-}
+-
+-function readiness () {
+-  if [[ $OVS_DATABASE == "nb" ]]; then
+-    OVN_DATABASE="Northbound"
+-  elif [[ $OVS_DATABASE == "sb" ]]; then
+-    OVN_DATABASE="Southbound"
+-  else
+-    echo "OVS_DATABASE must be nb or sb"
+-    exit 1
+-  fi
+-
+-  ovs-appctl -t /var/run/ovn/ovn${OVS_DATABASE}_db.ctl cluster/status OVN_${OVN_DATABASE}
+-}
+-
+-$COMMAND
diff --git a/charts/patches/placement/0001-tune-uwsgi-config.patch b/charts/patches/placement/0001-tune-uwsgi-config.patch
new file mode 100644
index 0000000..7a1597f
--- /dev/null
+++ b/charts/patches/placement/0001-tune-uwsgi-config.patch
@@ -0,0 +1,25 @@
+diff --git b/placement/values.yaml a/charts/placement/values.yaml
+index 2f4b3539..c5752676 100644
+--- b/placement/values.yaml
++++ a/placement/values.yaml
+@@ -141,15 +141,20 @@ conf:
+       processes: 4
+       add-header: "Connection: close"
+       buffer-size: 65535
++      chunked-input-limit: "4096000"
+       die-on-term: true
+       enable-threads: true
+       exit-on-reload: false
+       hook-master-start: unix_signal:15 gracefully_kill_them_all
++      http-auto-chunked: true
++      http-raw-body: true
+       lazy-apps: true
+       log-x-forwarded-for: true
+       master: true
++      need-app: true
+       procname-prefix-spaced: "placement-api:"
+       route-user-agent: '^kube-probe.* donotlog:'
++      socket-timeout: 10
+       thunder-lock: true
+       worker-reload-mercy: 80
+       wsgi-file: /var/lib/openstack/bin/placement-api
diff --git a/charts/patches/senlin/0001-tune-uwsgi-config.patch b/charts/patches/senlin/0001-tune-uwsgi-config.patch
new file mode 100644
index 0000000..0c96c34
--- /dev/null
+++ b/charts/patches/senlin/0001-tune-uwsgi-config.patch
@@ -0,0 +1,25 @@
+diff --git b/senlin/values.yaml a/charts/senlin/values.yaml
+index d4f72483..5631c58b 100644
+--- b/senlin/values.yaml
++++ a/senlin/values.yaml
+@@ -208,15 +215,20 @@ conf:
+     uwsgi:
+       add-header: "Connection: close"
+       buffer-size: 65535
++      chunked-input-limit: "4096000"
+       die-on-term: true
+       enable-threads: true
+       exit-on-reload: false
+       hook-master-start: unix_signal:15 gracefully_kill_them_all
++      http-auto-chunked: true
++      http-raw-body: true
+       lazy-apps: true
+       log-x-forwarded-for: true
+       master: true
++      need-app: true
+       procname-prefix-spaced: "senlin-api:"
+       route-user-agent: '^kube-probe.* donotlog:'
++      socket-timeout: 10
+       thunder-lock: true
+       worker-reload-mercy: 80
+       wsgi-file: /var/lib/openstack/bin/senlin-wsgi-api
diff --git a/charts/patches/senlin/0002-fix-paste-file.patch b/charts/patches/senlin/0002-fix-paste-file.patch
new file mode 100644
index 0000000..717c0ff
--- /dev/null
+++ b/charts/patches/senlin/0002-fix-paste-file.patch
@@ -0,0 +1,40 @@
+diff --git b/senlin/values.yaml a/charts/senlin/values.yaml
+index 48bf86ab..5631c58b 100644
+--- b/senlin/values.yaml
++++ a/senlin/values.yaml
+@@ -98,7 +98,7 @@ conf:
+                   - network: public
+   paste:
+     pipeline:senlin-api:
+-      pipeline: request_id faultwrap ssl versionnegotiation webhook authtoken context trust apiv1app
++      pipeline: cors http_proxy_to_wsgi request_id faultwrap versionnegotiation osprofiler webhook authtoken context trust apiv1app
+     app:apiv1app:
+       paste.app_factory: senlin.api.common.wsgi:app_factory
+       senlin.app_factory: senlin.api.openstack.v1.router:API
+@@ -110,8 +110,7 @@ conf:
+     filter:context:
+       paste.filter_factory: senlin.api.common.wsgi:filter_factory
+       senlin.filter_factory: senlin.api.middleware:context_filter
+-    filter:ssl:
+-      paste.filter_factory: oslo_middleware.ssl:SSLMiddleware.factory
++      oslo_config_project: senlin
+     filter:versionnegotiation:
+       paste.filter_factory: senlin.api.common.wsgi:filter_factory
+       senlin.filter_factory: senlin.api.middleware:version_filter
+@@ -121,8 +120,16 @@ conf:
+     filter:webhook:
+       paste.filter_factory: senlin.api.common.wsgi:filter_factory
+       senlin.filter_factory: senlin.api.middleware:webhook_filter
++    filter:http_proxy_to_wsgi:
++      paste.filter_factory: oslo_middleware.http_proxy_to_wsgi:HTTPProxyToWSGI.factory
++      oslo_config_project: senlin
+     filter:authtoken:
+       paste.filter_factory: keystonemiddleware.auth_token:filter_factory
++    filter:osprofiler:
++      paste.filter_factory: osprofiler.web:WsgiMiddleware.factory
++    filter:cors:
++      paste.filter_factory: oslo_middleware.cors:filter_factory
++      oslo_config_project: senlin
+   policy: {}
+   senlin:
+     DEFAULT:
diff --git a/charts/patches/tempest/0001-mount-results-locally.patch b/charts/patches/tempest/0001-mount-results-locally.patch
new file mode 100644
index 0000000..db1ab3a
--- /dev/null
+++ b/charts/patches/tempest/0001-mount-results-locally.patch
@@ -0,0 +1,23 @@
+diff --git b/tempest/templates/job-run-tests.yaml a/charts/tempest/templates/job-run-tests.yaml
+index fc375235..fa1c3618 100644
+--- b/tempest/templates/job-run-tests.yaml
++++ a/tempest/templates/job-run-tests.yaml
+@@ -97,6 +97,8 @@ spec:
+               subPath: test-whitelist
+               readOnly: true
+ {{- end }}
++            - name: stestr
++              mountPath: /.stestr
+             - name: tempest-reports
+               mountPath: /var/lib/tempest/data
+ {{- dict "enabled" (or .Values.manifests.certificates .Values.tls.identity) "name" .Values.secrets.tls.identity.api.internal "path" "/etc/tempest/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+@@ -113,6 +115,9 @@ spec:
+           configMap:
+             name: tempest-bin
+             defaultMode: 0555
++        - name: stestr
++          hostPath:
++            path: /tmp/stestr
+         - name: tempest-reports
+         {{- if not .Values.pvc.enabled }}
+           emptyDir: {}
diff --git a/charts/placement/charts/helm-toolkit/requirements.lock b/charts/placement/charts/helm-toolkit/requirements.lock
new file mode 100644
index 0000000..808bd94
--- /dev/null
+++ b/charts/placement/charts/helm-toolkit/requirements.lock
@@ -0,0 +1,3 @@
+dependencies: []
+digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/placement/requirements.lock b/charts/placement/requirements.lock
index 1984052..e346dde 100644
--- a/charts/placement/requirements.lock
+++ b/charts/placement/requirements.lock
@@ -1,6 +1,6 @@
 dependencies:
 - name: helm-toolkit
-  repository: file://../../openstack-helm-infra/helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
   version: 0.2.55
-digest: sha256:f25556fa4f0b285a96cbf853e72555c04e65772daf0ffa6b518321e5e249f5ca
-generated: "2023-11-22T20:15:04.838002001Z"
+digest: sha256:92b4001062b365cd9687eb926780c7f64e17e488262c1167339ade0fe600b368
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/placement/requirements.yaml b/charts/placement/requirements.yaml
index 639dab0..6ab539f 100644
--- a/charts/placement/requirements.yaml
+++ b/charts/placement/requirements.yaml
@@ -1,18 +1,4 @@
-# Copyright 2019 Intel Corporation.
-#
-# 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.
-
 dependencies:
-  - name: helm-toolkit
-    repository: file://../../openstack-helm-infra/helm-toolkit
-    version: ">= 0.1.0"
+- name: helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
+  version: 0.2.55
diff --git a/charts/senlin/charts/helm-toolkit/requirements.lock b/charts/senlin/charts/helm-toolkit/requirements.lock
new file mode 100644
index 0000000..808bd94
--- /dev/null
+++ b/charts/senlin/charts/helm-toolkit/requirements.lock
@@ -0,0 +1,3 @@
+dependencies: []
+digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/senlin/requirements.lock b/charts/senlin/requirements.lock
index d43449c..e346dde 100644
--- a/charts/senlin/requirements.lock
+++ b/charts/senlin/requirements.lock
@@ -1,6 +1,6 @@
 dependencies:
 - name: helm-toolkit
-  repository: file://../../openstack-helm-infra/helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
   version: 0.2.55
-digest: sha256:f25556fa4f0b285a96cbf853e72555c04e65772daf0ffa6b518321e5e249f5ca
-generated: "2023-11-22T20:15:02.349435177Z"
+digest: sha256:92b4001062b365cd9687eb926780c7f64e17e488262c1167339ade0fe600b368
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/senlin/requirements.yaml b/charts/senlin/requirements.yaml
index 4124d01..6ab539f 100644
--- a/charts/senlin/requirements.yaml
+++ b/charts/senlin/requirements.yaml
@@ -1,16 +1,4 @@
-# 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.
-
 dependencies:
-  - name: helm-toolkit
-    repository: file://../../openstack-helm-infra/helm-toolkit
-    version: ">= 0.1.0"
+- name: helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
+  version: 0.2.55
diff --git a/charts/tempest/charts/helm-toolkit/requirements.lock b/charts/tempest/charts/helm-toolkit/requirements.lock
new file mode 100644
index 0000000..808bd94
--- /dev/null
+++ b/charts/tempest/charts/helm-toolkit/requirements.lock
@@ -0,0 +1,3 @@
+dependencies: []
+digest: sha256:643d5437104296e21d906ecb15b2c96ad278f20cfc4af53b12bb6069bd853726
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/tempest/requirements.lock b/charts/tempest/requirements.lock
index cc2292f..e346dde 100644
--- a/charts/tempest/requirements.lock
+++ b/charts/tempest/requirements.lock
@@ -1,6 +1,6 @@
 dependencies:
 - name: helm-toolkit
-  repository: file://../../openstack-helm-infra/helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
   version: 0.2.55
-digest: sha256:f25556fa4f0b285a96cbf853e72555c04e65772daf0ffa6b518321e5e249f5ca
-generated: "2023-11-22T20:15:05.422266295Z"
+digest: sha256:92b4001062b365cd9687eb926780c7f64e17e488262c1167339ade0fe600b368
+generated: '0001-01-01T00:00:00Z'
diff --git a/charts/tempest/requirements.yaml b/charts/tempest/requirements.yaml
index 4124d01..6ab539f 100644
--- a/charts/tempest/requirements.yaml
+++ b/charts/tempest/requirements.yaml
@@ -1,16 +1,4 @@
-# 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.
-
 dependencies:
-  - name: helm-toolkit
-    repository: file://../../openstack-helm-infra/helm-toolkit
-    version: ">= 0.1.0"
+- name: helm-toolkit
+  repository: https://tarballs.openstack.org/openstack-helm-infra
+  version: 0.2.55
diff --git a/flake.nix b/flake.nix
index f29612c..4eec2f5 100644
--- a/flake.nix
+++ b/flake.nix
@@ -21,9 +21,9 @@
               go
               kubernetes-helm
               nixpkgs-fmt
+              patchutils
               poetry
               python311Packages.tox
-              vendir
             ];
           };
         }
diff --git a/hack/sync-charts.sh b/hack/sync-charts.sh
deleted file mode 100755
index c05e759..0000000
--- a/hack/sync-charts.sh
+++ /dev/null
@@ -1,158 +0,0 @@
-#!/bin/bash
-
-# Copyright (c) 2023 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.
-
-# This script is used to sync the charts from the upstream repositories into
-# the charts directory.  It is used to update the charts to the versions which
-# are defined in this file.
-
-set -xe
-
-# Determine the root path for Atmosphere
-ATMOSPHERE="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." >/dev/null 2>&1 && pwd )"
-
-# Sync using "vendir"
-vendir sync
-
-# Keystone
-curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899867/revisions/1/patch?download' \
-  | base64 --decode \
-  | filterdiff -p1 -x 'releasenotes/*' \
-  | filterdiff -p2 -x 'Chart.yaml' \
-  | filterdiff -p1 -i 'keystone/*' \
-  | patch -p2 -d ${ATMOSPHERE}/charts/keystone
-rm -fv ${ATMOSPHERE}/charts/keystone/templates/bin/{_domain-manage-init.sh.tpl,_domain-manage.py.tpl}
-
-# Glance
-curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899864/revisions/2/patch?download' \
-  | base64 --decode \
-  | filterdiff -p1 -x 'releasenotes/*' \
-  | filterdiff -p2 -x 'Chart.yaml' \
-  | filterdiff -p1 -i 'glance/*' \
-  | patch -p2 -d ${ATMOSPHERE}/charts/glance
-
-# Cinder
-curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899814/revisions/1/patch?download' \
-  | base64 --decode \
-  | filterdiff -p1 -x 'releasenotes/*' \
-  | filterdiff -p2 -x 'Chart.yaml' \
-  | filterdiff -p1 -i 'cinder/*' \
-  | patch -p2 -d ${ATMOSPHERE}/charts/cinder
-
-# Placement
-curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899914/revisions/3/patch?download' \
-  | base64 --decode \
-  | filterdiff -p1 -x 'releasenotes/*' \
-  | filterdiff -p2 -x 'Chart.yaml' \
-  | filterdiff -p1 -i 'placement/*' \
-  | patch -p2 -d ${ATMOSPHERE}/charts/placement
-
-# Libvirt
-curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm-infra~893406/revisions/9/patch?download' \
-  | base64 --decode \
-  | filterdiff -p1 -x 'releasenotes/*' \
-  | filterdiff -p2 -x 'Chart.yaml' \
-  | filterdiff -p1 -i 'libvirt/*' \
-  | patch -p2 -d ${ATMOSPHERE}/charts/libvirt
-
-# OVN
-curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm-infra~893739/revisions/2/patch?download' \
-  | base64 --decode \
-  | filterdiff -p1 -x 'releasenotes/*' \
-  | filterdiff -p2 -x 'Chart.yaml' \
-  | filterdiff -p1 -i 'ovn/*' \
-  | patch -p2 -d ${ATMOSPHERE}/charts/ovn
-curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm-infra~914807/revisions/1/patch?download' \
-  | base64 --decode \
-  | filterdiff -p1 -x 'releasenotes/*' \
-  | filterdiff -p2 -x 'Chart.yaml' \
-  | filterdiff -p1 -i 'ovn/*' \
-  | patch -p2 -d ${ATMOSPHERE}/charts/ovn
-
-# Nova
-curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899809/revisions/2/patch?download' \
-  | base64 --decode \
-  | filterdiff -p1 -x 'releasenotes/*' \
-  | filterdiff -p2 -x 'Chart.yaml' \
-  | filterdiff -p1 -i 'nova/*' \
-  | patch -p2 -d ${ATMOSPHERE}/charts/nova
-curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~904250/revisions/3/patch?download' \
-  | base64 --decode \
-  | filterdiff -p1 -x 'releasenotes/*' \
-  | filterdiff -p2 -x 'Chart.yaml' \
-  | filterdiff -p1 -i 'nova/*' \
-  | patch -p2 -d ${ATMOSPHERE}/charts/nova
-
-# Senlin
-curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899913/revisions/1/patch?download' \
-  | base64 --decode \
-  | filterdiff -p1 -x 'releasenotes/*' \
-  | filterdiff -p2 -x 'Chart.yaml' \
-  | filterdiff -p1 -i 'senlin/*' \
-  | patch -p2 -d ${ATMOSPHERE}/charts/senlin
-
-# Designate
-curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899932/revisions/1/patch?download' \
-  | base64 --decode \
-  | filterdiff -p1 -x 'releasenotes/*' \
-  | filterdiff -p2 -x 'Chart.yaml' \
-  | filterdiff -p1 -i 'designate/*' \
-  | patch -p2 -d ${ATMOSPHERE}/charts/designate
-
-# Heat
-curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899931/revisions/1/patch?download' \
-  | base64 --decode \
-  | filterdiff -p1 -x 'releasenotes/*' \
-  | filterdiff -p2 -x 'Chart.yaml' \
-  | filterdiff -p1 -i 'heat/*' \
-  | patch -p2 -d ${ATMOSPHERE}/charts/heat
-
-# Octavia
-curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899918/revisions/1/patch?download' \
-  | base64 --decode \
-  | filterdiff -p1 -x 'releasenotes/*' \
-  | filterdiff -p2 -x 'Chart.yaml' \
-  | filterdiff -p1 -i 'octavia/*' \
-  | patch -p2 -d ${ATMOSPHERE}/charts/octavia
-
-# Magnum
-curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899926/revisions/1/patch?download' \
-  | base64 --decode \
-  | filterdiff -p1 -x 'releasenotes/*' \
-  | filterdiff -p2 -x 'Chart.yaml' \
-  | filterdiff -p1 -i 'magnum/*' \
-  | patch -p2 -d ${ATMOSPHERE}/charts/magnum
-
-# Manila
-curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~883168/revisions/11/patch?download' \
-  | base64 --decode \
-  | filterdiff -p1 -x 'releasenotes/*' \
-  | filterdiff -p2 -x 'Chart.yaml' \
-  | filterdiff -p1 -i 'manila/*' \
-  | patch -p2 -d ${ATMOSPHERE}/charts/manila
-curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899923/revisions/1/patch?download' \
-  | base64 --decode \
-  | filterdiff -p1 -x 'releasenotes/*' \
-  | filterdiff -p2 -x 'Chart.yaml' \
-  | filterdiff -p1 -i 'manila/*' \
-  | patch -p2 -d ${ATMOSPHERE}/charts/manila
-
-# Neutron
-curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~902767/revisions/1/patch?download' \
-  | base64 --decode \
-  | filterdiff -p1 -x 'releasenotes/*' \
-  | filterdiff -p2 -x 'Chart.yaml' \
-  | filterdiff -p1 -i 'neutron/*' \
-  | patch -p2 -d ${ATMOSPHERE}/charts/neutron
diff --git a/roles/cluster_issuer/defaults/main.yml b/roles/cluster_issuer/defaults/main.yml
index f877cda..f66a246 100644
--- a/roles/cluster_issuer/defaults/main.yml
+++ b/roles/cluster_issuer/defaults/main.yml
@@ -36,8 +36,8 @@
 # cluster_issuer_acme_route53_secret_access_key: <AWS_SECRET_ACCESS_KEY>
 
 cluster_issuer_acme_godaddy_helm_release_name: cert-manager-webhook-godaddy
-cluster_issuer_acme_godaddy_helm_chart_path: "../../charts/cert-manager-webhook-godaddy/"
-cluster_issuer_acme_godaddy_helm_chart_ref: /usr/local/src/cert-manager-webhook-godaddy
+cluster_issuer_acme_godaddy_helm_chart_path: "../../charts/godaddy-webhook/"
+cluster_issuer_acme_godaddy_helm_chart_ref: /usr/local/src/godaddy-webhook
 cluster_issuer_acme_godaddy_helm_release_namespace: cert-manager
 cluster_issuer_acme_godaddy_helm_values: {}
 
diff --git a/tox.ini b/tox.ini
index 684a265..2ae75ad 100644
--- a/tox.ini
+++ b/tox.ini
@@ -5,8 +5,6 @@
 usedevelop = True
 setenv =
   VIRTUAL_ENV={envdir}
-  LANGUAGE=en_US
-  LC_ALL=en_US.utf-8
   OS_STDOUT_CAPTURE=1
   OS_STDERR_CAPTURE=1
   OS_TEST_TIMEOUT=160
@@ -30,6 +28,29 @@
 commands =
   python3 {toxinidir}/build/pin-images.py roles/defaults/vars/main.yml roles/defaults/vars/main.yml
 
+[testenv:sync-charts]
+skipsdist = True
+deps =
+  aiopath
+  aioshutil
+  asynctempfile
+  GitPython
+  platformdirs
+  pydantic
+  pydantic-yaml
+  python-gerrit-api
+commands =
+  python3 {toxinidir}/build/sync-charts.py
+
+[testenv:linters]
+skipsdist = True
+deps =
+  {[testenv:sync-charts]deps}
+  pre-commit
+commands =
+  pre-commit run --all-files --show-diff-on-failure
+  python3 {toxinidir}/build/sync-charts.py --check
+
 [testenv:molecule-keycloak]
 commands =
   molecule test -s keycloak
diff --git a/vendir.lock.yml b/vendir.lock.yml
deleted file mode 100644
index 1e32933..0000000
--- a/vendir.lock.yml
+++ /dev/null
@@ -1,153 +0,0 @@
-apiVersion: vendir.k14s.io/v1alpha1
-directories:
-- contents:
-  - helmChart:
-      appVersion: v1.0.0
-      version: 0.3.6
-    path: barbican
-  - helmChart:
-      appVersion: 3.5.1
-      version: 3.5.1
-    path: ceph-csi-rbd
-  - helmChart:
-      appVersion: v1.0.0
-      version: 0.1.8
-    path: ceph-provisioners
-  - helmChart:
-      appVersion: 0.3.0
-      version: 0.3.0
-    path: cert-manager-webhook-godaddy
-  - helmChart:
-      appVersion: 1.5.0
-      version: 1.5.2
-    path: cert-manager-webhook-infoblox-wapi
-  - helmChart:
-      appVersion: v1.0.0
-      version: 0.3.15
-    path: cinder
-  - helmChart:
-      appVersion: 1.9.3
-      version: 1.19.4
-    path: coredns
-  - helmChart:
-      appVersion: v1.0.0
-      version: 0.2.9
-    path: designate
-  - helmChart:
-      appVersion: v1.0.0
-      version: 0.4.15
-    path: glance
-  - helmChart:
-      appVersion: v1.0.0
-      version: 0.3.7
-    path: heat
-  - helmChart:
-      appVersion: v1.0.0
-      version: 0.3.15
-    path: horizon
-  - helmChart:
-      appVersion: 1.1.1
-      version: 4.0.17
-    path: ingress-nginx
-  - helmChart:
-      appVersion: 22.0.1
-      version: 16.0.3
-    path: keycloak
-  - helmChart:
-      appVersion: v1.0.0
-      version: 0.3.5
-    path: keystone
-  - helmChart:
-      appVersion: v0.73.0
-      version: 58.0.0
-    path: kube-prometheus-stack
-  - helmChart:
-      appVersion: v1.0.0
-      version: 0.1.27
-    path: libvirt
-  - git:
-      commitTitle: Fix missing plugins/github-release image for arm platform...
-      sha: 97e0501428f0a5bcac49ecd0bfdb051797c4a6c5
-      tags:
-      - v0.0.24
-    path: local-path-provisioner
-  - helmChart:
-      appVersion: 2.9.6
-      version: 5.47.2
-    path: loki
-  - helmChart:
-      appVersion: v1.0.0
-      version: 0.2.9
-    path: magnum
-  - helmChart:
-      appVersion: v1.0.0
-      version: 0.1.7
-    path: manila
-  - helmChart:
-      appVersion: v1.5.5
-      version: 0.1.12
-    path: memcached
-  - helmChart:
-      appVersion: v1.0.0
-      version: 0.3.29
-    path: neutron
-  - helmChart:
-      appVersion: v0.11.2
-      version: 0.11.2
-    path: node-feature-discovery
-  - helmChart:
-      appVersion: v1.0.0
-      version: 0.3.27
-    path: nova
-  - helmChart:
-      appVersion: v1.0.0
-      version: 0.2.9
-    path: octavia
-  - helmChart:
-      appVersion: v1.0.0
-      version: 0.1.19
-    path: openvswitch
-  - helmChart:
-      appVersion: v23.3.0
-      version: 0.1.4
-    path: ovn
-  - helmChart:
-      appVersion: v1.0.0
-      version: 0.3.9
-    path: placement
-  - helmChart:
-      appVersion: 1.4.2
-      version: 1.16.0
-    path: prometheus-pushgateway
-  - helmChart:
-      appVersion: 1.12.0
-      version: 1.12.0
-    path: pxc-operator
-  - helmChart:
-      appVersion: 1.13.1
-      version: 2.6.6
-    path: rabbitmq-cluster-operator
-  - helmChart:
-      appVersion: v1.10.10
-      version: v1.10.10
-    path: rook-ceph
-  - helmChart:
-      appVersion: v1.10.10
-      version: v1.10.10
-    path: rook-ceph-cluster
-  - helmChart:
-      appVersion: v1.0.0
-      version: 0.2.9
-    path: senlin
-  - manual: {}
-    path: staffeln
-  - helmChart:
-      appVersion: v1.0.0
-      version: 0.2.8
-    path: tempest
-  - helmChart:
-      appVersion: 0.37.0-distroless-libc
-      version: 0.32.0
-    path: vector
-  path: charts
-kind: LockConfig
diff --git a/vendir.yml b/vendir.yml
deleted file mode 100644
index a089a59..0000000
--- a/vendir.yml
+++ /dev/null
@@ -1,395 +0,0 @@
-apiVersion: vendir.k14s.io/v1alpha1
-kind: Config
-directories:
-  - path: charts
-    contents:
-      - path: barbican
-        helmChart:
-          name: barbican
-          version: 0.3.6
-          repository:
-            url: https://tarballs.openstack.org/openstack-helm
-      - path: ceph-csi-rbd
-        helmChart:
-          name: ceph-csi-rbd
-          version: 3.5.1
-          repository:
-            url: https://ceph.github.io/csi-charts
-      - path: ceph-provisioners
-        helmChart:
-          name: ceph-provisioners
-          version: 0.1.8
-          repository:
-            url: https://tarballs.openstack.org/openstack-helm-infra
-      - path: cert-manager-webhook-godaddy
-        helmChart:
-          name: godaddy-webhook
-          version: 0.3.0
-          repository:
-            url: https://snowdrop.github.io/godaddy-webhook
-      - path: cert-manager-webhook-infoblox-wapi
-        helmChart:
-          name: cert-manager-webhook-infoblox-wapi
-          version: 1.5.2
-          repository:
-            url: https://luisico.github.io/cert-manager-webhook-infoblox-wapi
-      - path: cinder
-        helmChart:
-          name: cinder
-          version: 0.3.15
-          repository:
-            url: https://tarballs.openstack.org/openstack-helm
-      - path: coredns
-        helmChart:
-          name: coredns
-          version: 1.19.4
-          repository:
-            url: https://coredns.github.io/helm
-      - path: designate
-        helmChart:
-          name: designate
-          version: 0.2.9
-          repository:
-            url: https://tarballs.openstack.org/openstack-helm
-      - path: glance
-        helmChart:
-          name: glance
-          version: 0.4.15
-          repository:
-            url: https://tarballs.openstack.org/openstack-helm
-      - path: heat
-        helmChart:
-          name: heat
-          version: 0.3.7
-          repository:
-            url: https://tarballs.openstack.org/openstack-helm
-      - path: horizon
-        helmChart:
-          name: horizon
-          version: 0.3.15
-          repository:
-            url: https://tarballs.openstack.org/openstack-helm
-      - path: ingress-nginx
-        helmChart:
-          name: ingress-nginx
-          version: 4.0.17
-          repository:
-            url: https://kubernetes.github.io/ingress-nginx
-      - path: keycloak
-        helmChart:
-          name: keycloak
-          version: 16.0.3
-          repository:
-            url: https://charts.bitnami.com/bitnami
-      - path: keystone
-        helmChart:
-          name: keystone
-          version: 0.3.5
-          repository:
-            url: https://tarballs.openstack.org/openstack-helm
-      - path: kube-prometheus-stack
-        helmChart:
-          name: kube-prometheus-stack
-          version: 58.0.0
-          repository:
-            url: https://prometheus-community.github.io/helm-charts
-      - path: libvirt
-        helmChart:
-          name: libvirt
-          version: 0.1.27
-          repository:
-            url: https://tarballs.openstack.org/openstack-helm-infra
-      - path: local-path-provisioner
-        git:
-          url: https://github.com/rancher/local-path-provisioner
-          ref: v0.0.24
-        newRootPath: deploy/chart/local-path-provisioner
-      - path: loki
-        helmChart:
-          name: loki
-          version: 5.47.2
-          repository:
-            url: https://grafana.github.io/helm-charts
-      - path: magnum
-        helmChart:
-          name: magnum
-          version: 0.2.9
-          repository:
-            url: https://tarballs.openstack.org/openstack-helm
-      - path: manila
-        helmChart:
-          name: manila
-          version: 0.1.7
-          repository:
-            url: https://tarballs.openstack.org/openstack-helm
-      - path: memcached
-        helmChart:
-          name: memcached
-          version: 0.1.12
-          repository:
-            url: https://tarballs.openstack.org/openstack-helm-infra
-      - path: neutron
-        helmChart:
-          name: neutron
-          version: 0.3.29
-          repository:
-            url: https://tarballs.openstack.org/openstack-helm/
-      - path: node-feature-discovery
-        helmChart:
-          name: node-feature-discovery
-          version: 0.11.2
-          repository:
-            url: https://kubernetes-sigs.github.io/node-feature-discovery/charts
-      - path: nova
-        helmChart:
-          name: nova
-          version: 0.3.27
-          repository:
-            url: https://tarballs.openstack.org/openstack-helm
-      - path: octavia
-        helmChart:
-          name: octavia
-          version: 0.2.9
-          repository:
-            url: https://tarballs.openstack.org/openstack-helm
-      - path: openvswitch
-        helmChart:
-          name: openvswitch
-          version: 0.1.19
-          repository:
-            url: https://tarballs.openstack.org/openstack-helm-infra
-      - path: ovn
-        helmChart:
-          name: ovn
-          version: 0.1.4
-          repository:
-            url: https://tarballs.openstack.org/openstack-helm-infra
-      - path: placement
-        helmChart:
-          name: placement
-          version: 0.3.9
-          repository:
-            url: https://tarballs.openstack.org/openstack-helm/
-      - path: prometheus-pushgateway
-        helmChart:
-          name: prometheus-pushgateway
-          version: 1.16.0
-          repository:
-            url: https://prometheus-community.github.io/helm-charts
-      - path: pxc-operator
-        helmChart:
-          name: pxc-operator
-          version: 1.12.0
-          repository:
-            url: https://percona.github.io/percona-helm-charts
-      - path: rabbitmq-cluster-operator
-        helmChart:
-          name: rabbitmq-cluster-operator
-          version: 2.6.6
-          repository:
-            url: https://charts.bitnami.com/bitnami
-      - path: rook-ceph
-        helmChart:
-          name: rook-ceph
-          version: 1.10.10
-          repository:
-            url: https://charts.rook.io/release
-      - path: rook-ceph-cluster
-        helmChart:
-          name: rook-ceph-cluster
-          version: 1.10.10
-          repository:
-            url: https://charts.rook.io/release
-      - path: senlin
-        helmChart:
-          name: senlin
-          version: 0.2.9
-          repository:
-            url: https://tarballs.openstack.org/openstack-helm
-      - path: staffeln
-        manual: {}
-      - path: tempest
-        helmChart:
-          name: tempest
-          version: 0.2.8
-          repository:
-            url: https://tarballs.openstack.org/openstack-helm
-      - path: vector
-        helmChart:
-          name: vector
-          version: 0.32.0
-          repository:
-            url: https://vectordotdev.github.io/helm-charts
-
-
-# KEYSTONE_VERSION=0.3.5
-# curl -sL https://tarballs.opendev.org/openstack/openstack-helm/keystone-${KEYSTONE_VERSION}.tgz \
-#   | tar -xz -C ${ATMOSPHERE}/charts
-# curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899867/revisions/1/patch?download' \
-#   | base64 --decode \
-#   | filterdiff -p1 -x 'releasenotes/*' \
-#   | filterdiff -p2 -x 'Chart.yaml' \
-#   | filterdiff -p1 -i 'keystone/*' \
-#   | patch -p2 -d ${ATMOSPHERE}/charts/keystone
-# # Remove extra files before 899867 merged
-# rm -fv ${ATMOSPHERE}/charts/keystone/templates/bin/_domain-manage-init.sh.tpl ${ATMOSPHERE}/charts/keystone/templates/bin/_domain-manage.py.tpl
-
-# GLANCE_VERSION=0.4.15
-# curl -sL https://tarballs.opendev.org/openstack/openstack-helm/glance-${GLANCE_VERSION}.tgz \
-#   | tar -xz -C ${ATMOSPHERE}/charts
-# curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899864/revisions/2/patch?download' \
-#   | base64 --decode \
-#   | filterdiff -p1 -x 'releasenotes/*' \
-#   | filterdiff -p2 -x 'Chart.yaml' \
-#   | filterdiff -p1 -i 'glance/*' \
-#   | patch -p2 -d ${ATMOSPHERE}/charts/glance
-
-# CINDER_VERSION=0.3.15
-# curl -sL https://tarballs.opendev.org/openstack/openstack-helm/cinder-${CINDER_VERSION}.tgz \
-#   | tar -xz -C ${ATMOSPHERE}/charts
-# curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899814/revisions/1/patch?download' \
-#   | base64 --decode \
-#   | filterdiff -p1 -x 'releasenotes/*' \
-#   | filterdiff -p2 -x 'Chart.yaml' \
-#   | filterdiff -p1 -i 'cinder/*' \
-#   | patch -p2 -d ${ATMOSPHERE}/charts/cinder
-
-# PLACEMENT_VERSION=0.3.9
-# curl -sL https://tarballs.opendev.org/openstack/openstack-helm/placement-${PLACEMENT_VERSION}.tgz \
-#   | tar -xz -C ${ATMOSPHERE}/charts
-# curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899914/revisions/3/patch?download' \
-#   | base64 --decode \
-#   | filterdiff -p1 -x 'releasenotes/*' \
-#   | filterdiff -p2 -x 'Chart.yaml' \
-#   | filterdiff -p1 -i 'placement/*' \
-#   | patch -p2 -d ${ATMOSPHERE}/charts/placement
-# # Remove extra files before 899914 merged
-# rm -rfv ${ATMOSPHERE}/charts/placement/values_overrides/
-
-# LIBVIRT_VERSION=0.1.27
-# curl -sL https://tarballs.opendev.org/openstack/openstack-helm-infra/libvirt-${LIBVIRT_VERSION}.tgz \
-#   | tar -xz -C ${ATMOSPHERE}/charts
-# curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm-infra~893406/revisions/9/patch?download' \
-#   | base64 --decode \
-#   | filterdiff -p1 -x 'releasenotes/*' \
-#   | filterdiff -p2 -x 'Chart.yaml' \
-#   | filterdiff -p1 -i 'libvirt/*' \
-#   | patch -p2 -d ${ATMOSPHERE}/charts/libvirt
-
-# LOCAL_PATH_PROVISIONER_VERSION=0.0.24
-# curl -sL https://github.com/rancher/local-path-provisioner/archive/refs/tags/v${LOCAL_PATH_PROVISIONER_VERSION}.tar.gz \
-#   | tar -xz -C ${ATMOSPHERE}/charts --strip-components=3 local-path-provisioner-${LOCAL_PATH_PROVISIONER_VERSION}/deploy/chart/
-
-# OVN_VERSION=0.1.4
-# curl -sL https://tarballs.opendev.org/openstack/openstack-helm-infra/ovn-${OVN_VERSION}.tgz \
-#   | tar -xz -C ${ATMOSPHERE}/charts
-# curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm-infra~893739/revisions/2/patch?download' \
-#   | base64 --decode \
-#   | filterdiff -p1 -x 'releasenotes/*' \
-#   | filterdiff -p2 -x 'Chart.yaml' \
-#   | filterdiff -p1 -i 'ovn/*' \
-#   | patch -p2 -d ${ATMOSPHERE}/charts/ovn
-
-# NEUTRON_VERSION=0.3.24
-# curl -sL https://tarballs.opendev.org/openstack/openstack-helm/neutron-${NEUTRON_VERSION}.tgz \
-#   | tar -xz -C ${ATMOSPHERE}/charts
-# curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899711/revisions/2/patch?download' \
-#   | base64 --decode \
-#   | filterdiff -p1 -x 'releasenotes/*' \
-#   | filterdiff -p2 -x 'Chart.yaml' \
-#   | filterdiff -p1 -i 'neutron/*' \
-#   | patch -p2 -d ${ATMOSPHERE}/charts/neutron
-# curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899684/revisions/4/patch?download' \
-#   | base64 --decode \
-#   | filterdiff -p1 -x 'releasenotes/*' \
-#   | filterdiff -p2 -x 'Chart.yaml' \
-#   | filterdiff -p1 -i 'neutron/*' \
-#   | patch -p2 -d ${ATMOSPHERE}/charts/neutron
-# curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899716/revisions/1/patch?download' \
-#   | base64 --decode \
-#   | filterdiff -p1 -x 'releasenotes/*' \
-#   | filterdiff -p2 -x 'Chart.yaml' \
-#   | filterdiff -p1 -i 'neutron/*' \
-#   | patch -p2 -d ${ATMOSPHERE}/charts/neutron
-# curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899933/revisions/1/patch?download' \
-#   | base64 --decode \
-#   | filterdiff -p1 -x 'releasenotes/*' \
-#   | filterdiff -p2 -x 'Chart.yaml' \
-#   | filterdiff -p1 -i 'neutron/*' \
-#   | patch -p2 -d ${ATMOSPHERE}/charts/neutron
-
-# NOVA_VERISON=0.3.27
-# curl -sL https://tarballs.opendev.org/openstack/openstack-helm/nova-${NOVA_VERISON}.tgz \
-#   | tar -xz -C ${ATMOSPHERE}/charts
-# curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899809/revisions/2/patch?download' \
-#   | base64 --decode \
-#   | filterdiff -p1 -x 'releasenotes/*' \
-#   | filterdiff -p2 -x 'Chart.yaml' \
-#   | filterdiff -p1 -i 'nova/*' \
-#   | patch -p2 -d ${ATMOSPHERE}/charts/nova
-
-# SENLIN_VERSION=0.2.9
-# curl -sL https://tarballs.opendev.org/openstack/openstack-helm/senlin-${SENLIN_VERSION}.tgz \
-#   | tar -xz -C ${ATMOSPHERE}/charts
-# curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899913/revisions/1/patch?download' \
-#   | base64 --decode \
-#   | filterdiff -p1 -x 'releasenotes/*' \
-#   | filterdiff -p2 -x 'Chart.yaml' \
-#   | filterdiff -p1 -i 'senlin/*' \
-#   | patch -p2 -d ${ATMOSPHERE}/charts/senlin
-
-# DESIGNATE_VERSION=0.2.9
-# curl -sL https://tarballs.opendev.org/openstack/openstack-helm/designate-${DESIGNATE_VERSION}.tgz \
-#   | tar -xz -C ${ATMOSPHERE}/charts
-# curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899932/revisions/1/patch?download' \
-#   | base64 --decode \
-#   | filterdiff -p1 -x 'releasenotes/*' \
-#   | filterdiff -p2 -x 'Chart.yaml' \
-#   | filterdiff -p1 -i 'designate/*' \
-#   | patch -p2 -d ${ATMOSPHERE}/charts/designate
-
-# HEAT_VERSION=0.3.7
-# curl -sL https://tarballs.opendev.org/openstack/openstack-helm/heat-${HEAT_VERSION}.tgz \
-#   | tar -xz -C ${ATMOSPHERE}/charts
-# curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899931/revisions/1/patch?download' \
-#   | base64 --decode \
-#   | filterdiff -p1 -x 'releasenotes/*' \
-#   | filterdiff -p2 -x 'Chart.yaml' \
-#   | filterdiff -p1 -i 'heat/*' \
-#   | patch -p2 -d ${ATMOSPHERE}/charts/heat
-
-# OCTAVIA_VERSION=0.2.9
-# curl -sL https://tarballs.opendev.org/openstack/openstack-helm/octavia-${OCTAVIA_VERSION}.tgz \
-#   | tar -xz -C ${ATMOSPHERE}/charts
-# curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899918/revisions/1/patch?download' \
-#   | base64 --decode \
-#   | filterdiff -p1 -x 'releasenotes/*' \
-#   | filterdiff -p2 -x 'Chart.yaml' \
-#   | filterdiff -p1 -i 'octavia/*' \
-#   | patch -p2 -d ${ATMOSPHERE}/charts/octavia
-
-# MAGNUM_VERSION=0.2.9
-# curl -sL https://tarballs.opendev.org/openstack/openstack-helm/magnum-${MAGNUM_VERSION}.tgz \
-#   | tar -xz -C ${ATMOSPHERE}/charts
-# curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899926/revisions/1/patch?download' \
-#   | base64 --decode \
-#   | filterdiff -p1 -x 'releasenotes/*' \
-#   | filterdiff -p2 -x 'Chart.yaml' \
-#   | filterdiff -p1 -i 'magnum/*' \
-#   | patch -p2 -d ${ATMOSPHERE}/charts/magnum
-
-# MANILA_VERSION=0.1.7
-# curl -sL https://tarballs.opendev.org/openstack/openstack-helm/manila-${MANILA_VERSION}.tgz \
-#   | tar -xz -C ${ATMOSPHERE}/charts
-# curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~883168/revisions/11/patch?download' \
-#   | base64 --decode \
-#   | filterdiff -p1 -x 'releasenotes/*' \
-#   | filterdiff -p2 -x 'Chart.yaml' \
-#   | filterdiff -p1 -i 'manila/*' \
-#   | patch -p2 -d ${ATMOSPHERE}/charts/manila
-# curl 'https://review.opendev.org/changes/openstack%2Fopenstack-helm~899923/revisions/1/patch?download' \
-#   | base64 --decode \
-#   | filterdiff -p1 -x 'releasenotes/*' \
-#   | filterdiff -p2 -x 'Chart.yaml' \
-#   | filterdiff -p1 -i 'manila/*' \
-#   | patch -p2 -d ${ATMOSPHERE}/charts/manila
diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml
index 31fcd3e..c78e4f1 100644
--- a/zuul.d/jobs.yaml
+++ b/zuul.d/jobs.yaml
@@ -13,6 +13,11 @@
 # under the License.
 
 - job:
+    name: atmosphere-linters
+    parent: tox-linters
+    pre-run: zuul.d/playbooks/linters/pre.yml
+
+- job:
     name: atmosphere-build-collection
     pre-run: zuul.d/playbooks/build-collection/pre.yml
     run: zuul.d/playbooks/build-collection/run.yml
diff --git a/zuul.d/playbooks/linters/pre.yml b/zuul.d/playbooks/linters/pre.yml
new file mode 100644
index 0000000..bb40794
--- /dev/null
+++ b/zuul.d/playbooks/linters/pre.yml
@@ -0,0 +1,24 @@
+# Copyright (c) 2024 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.
+
+- hosts: all
+  roles:
+    - role: ensure-helm
+      helm_version: 3.13.3
+  tasks:
+    - name: Install patchutils
+      become: true
+      ansible.builtin.package:
+        name: patchutils
+        state: present
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 7089996..a0206ea 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -16,6 +16,7 @@
     merge-mode: squash-merge
     check:
       jobs:
+        - atmosphere-linters
         - atmosphere-build-collection
         - atmosphere-molecule-aio-keycloak:
             dependencies: &molecule_check_dependencies
@@ -79,6 +80,7 @@
             dependencies: *molecule_check_dependencies
     gate:
       jobs:
+        - atmosphere-linters
         - atmosphere-build-collection
         - atmosphere-molecule-aio-keycloak:
             dependencies: &molecule_gate_dependencies