chore: bundle all osh charts
diff --git a/charts/nova/.helmignore b/charts/nova/.helmignore
new file mode 100644
index 0000000..b54c347
--- /dev/null
+++ b/charts/nova/.helmignore
@@ -0,0 +1 @@
+values_overrides
diff --git a/charts/nova/Chart.yaml b/charts/nova/Chart.yaml
new file mode 100644
index 0000000..e43c866
--- /dev/null
+++ b/charts/nova/Chart.yaml
@@ -0,0 +1,12 @@
+apiVersion: v1
+appVersion: v1.0.0
+description: OpenStack-Helm Nova
+home: https://docs.openstack.org/nova/latest/
+icon: https://www.openstack.org/themes/openstack/images/project-mascots/Nova/OpenStack_Project_Nova_vertical.png
+maintainers:
+- name: OpenStack-Helm Authors
+name: nova
+sources:
+- https://opendev.org/openstack/nova
+- https://opendev.org/openstack/openstack-helm
+version: 0.2.32
diff --git a/charts/nova/charts/helm-toolkit/Chart.yaml b/charts/nova/charts/helm-toolkit/Chart.yaml
new file mode 100644
index 0000000..751c291
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/Chart.yaml
@@ -0,0 +1,12 @@
+apiVersion: v1
+appVersion: v1.0.0
+description: OpenStack-Helm Helm-Toolkit
+home: https://docs.openstack.org/openstack-helm
+icon: https://www.openstack.org/themes/openstack/images/project-mascots/OpenStack-Helm/OpenStack_Project_OpenStackHelm_vertical.png
+maintainers:
+- name: OpenStack-Helm Authors
+name: helm-toolkit
+sources:
+- https://opendev.org/openstack/openstack-helm-infra
+- https://opendev.org/openstack/openstack-helm
+version: 0.2.38
diff --git a/charts/nova/charts/helm-toolkit/requirements.yaml b/charts/nova/charts/helm-toolkit/requirements.yaml
new file mode 100644
index 0000000..27fb08a
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/requirements.yaml
@@ -0,0 +1,15 @@
+# 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: []
+...
diff --git a/charts/nova/charts/helm-toolkit/templates/endpoints/_authenticated_endpoint_uri_lookup.tpl b/charts/nova/charts/helm-toolkit/templates/endpoints/_authenticated_endpoint_uri_lookup.tpl
new file mode 100644
index 0000000..12b84de
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/endpoints/_authenticated_endpoint_uri_lookup.tpl
@@ -0,0 +1,58 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Resolves database, or basic auth, style endpoints
+values: |
+  endpoints:
+    cluster_domain_suffix: cluster.local
+    oslo_db:
+      auth:
+        admin:
+          username: root
+          password: password
+        service_username:
+          username: username
+          password: password
+      hosts:
+        default: mariadb
+      host_fqdn_override:
+        default: null
+      path: /dbname
+      scheme: mysql+pymysql
+      port:
+        mysql:
+          default: 3306
+usage: |
+  {{ tuple "oslo_db" "internal" "service_username" "mysql" . | include "helm-toolkit.endpoints.authenticated_endpoint_uri_lookup" }}
+return: |
+  mysql+pymysql://serviceuser:password@mariadb.default.svc.cluster.local:3306/dbname
+*/}}
+
+{{- define "helm-toolkit.endpoints.authenticated_endpoint_uri_lookup" -}}
+{{- $type := index . 0 -}}
+{{- $endpoint := index . 1 -}}
+{{- $userclass := index . 2 -}}
+{{- $port := index . 3 -}}
+{{- $context := index . 4 -}}
+{{- $endpointScheme := tuple $type $endpoint $port $context | include "helm-toolkit.endpoints.keystone_endpoint_scheme_lookup" }}
+{{- $userMap := index $context.Values.endpoints ( $type | replace "-" "_" ) "auth" $userclass }}
+{{- $endpointUser := index $userMap "username" }}
+{{- $endpointPass := index $userMap "password" }}
+{{- $endpointHost := tuple $type $endpoint $context | include "helm-toolkit.endpoints.endpoint_host_lookup" }}
+{{- $endpointPort := tuple $type $endpoint $port $context | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+{{- $endpointPath := tuple $type $endpoint $port $context | include "helm-toolkit.endpoints.keystone_endpoint_path_lookup" }}
+{{- printf "%s://%s:%s@%s:%s%s" $endpointScheme $endpointUser $endpointPass $endpointHost $endpointPort $endpointPath -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/endpoints/_authenticated_transport_endpoint_uri_lookup.tpl b/charts/nova/charts/helm-toolkit/templates/endpoints/_authenticated_transport_endpoint_uri_lookup.tpl
new file mode 100644
index 0000000..b7cf287
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/endpoints/_authenticated_transport_endpoint_uri_lookup.tpl
@@ -0,0 +1,121 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Resolves endpoint string suitible for use with oslo.messaging transport url
+  See: https://docs.openstack.org/oslo.messaging/latest/reference/transport.html#oslo_messaging.TransportURL
+examples:
+  - values: |
+      endpoints:
+        cluster_domain_suffix: cluster.local
+        oslo_messaging:
+          auth:
+            cinder:
+              username: cinder
+              password: password
+          statefulset:
+            replicas: 2
+            name: rabbitmq-rabbitmq
+          hosts:
+            default: rabbitmq
+          host_fqdn_override:
+            default: null
+          path: /cinder
+          scheme: rabbit
+          port:
+            amqp:
+              default: 5672
+    usage: |
+      {{ tuple "oslo_messaging" "internal" "cinder" "amqp" . | include "helm-toolkit.endpoints.authenticated_transport_endpoint_uri_lookup" }}
+    return: |
+      rabbit://cinder:password@rabbitmq-rabbitmq-0.rabbitmq.default.svc.cluster.local:5672,cinder:password@rabbitmq-rabbitmq-1.rabbitmq.default.svc.cluster.local:5672/cinder
+  - values: |
+      endpoints:
+        cluster_domain_suffix: cluster.local
+        oslo_messaging:
+          auth:
+            cinder:
+              username: cinder
+              password: password
+          statefulset: null
+          hosts:
+            default: rabbitmq
+          host_fqdn_override:
+            default: null
+          path: /cinder
+          scheme: rabbit
+          port:
+            amqp:
+              default: 5672
+    usage: |
+      {{ tuple "oslo_messaging" "internal" "cinder" "amqp" . | include "helm-toolkit.endpoints.authenticated_transport_endpoint_uri_lookup" }}
+    return: |
+      rabbit://cinder:password@rabbitmq.default.svc.cluster.local:5672/cinder
+  - values: |
+      endpoints:
+        cluster_domain_suffix: cluster.local
+        oslo_messaging:
+          auth:
+            cinder:
+              username: cinder
+              password: password
+          statefulset:
+            replicas: 2
+            name: rabbitmq-rabbitmq
+          hosts:
+            default: rabbitmq
+          host_fqdn_override:
+            default: rabbitmq.openstackhelm.org
+          path: /cinder
+          scheme: rabbit
+          port:
+            amqp:
+              default: 5672
+    usage: |
+      {{ tuple "oslo_messaging" "internal" "cinder" "amqp" . | include "helm-toolkit.endpoints.authenticated_transport_endpoint_uri_lookup" }}
+    return: |
+      rabbit://cinder:password@rabbitmq.openstackhelm.org:5672/cinder
+*/}}
+
+{{- define "helm-toolkit.endpoints.authenticated_transport_endpoint_uri_lookup" -}}
+{{-   $type := index . 0 -}}
+{{-   $endpoint := index . 1 -}}
+{{-   $userclass := index . 2 -}}
+{{-   $port := index . 3 -}}
+{{-   $context := index . 4 -}}
+{{-   $endpointScheme := tuple $type $endpoint $port $context | include "helm-toolkit.endpoints.keystone_endpoint_scheme_lookup" }}
+{{-   $userMap := index $context.Values.endpoints ( $type | replace "-" "_" ) "auth" $userclass }}
+{{-   $ssMap := index $context.Values.endpoints ( $type | replace "-" "_" ) "statefulset" | default false}}
+{{-   $hostFqdnOverride := index $context.Values.endpoints ( $type | replace "-" "_" ) "host_fqdn_override" }}
+{{-   $endpointUser := index $userMap "username" }}
+{{-   $endpointPass := index $userMap "password" }}
+{{-   $endpointHostSuffix := tuple $type $endpoint $context | include "helm-toolkit.endpoints.endpoint_host_lookup" }}
+{{-   $endpointPort := tuple $type $endpoint $port $context | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+{{-   $local := dict "endpointCredsAndHosts" list -}}
+{{-   if not (or (index $hostFqdnOverride $endpoint | default ( index $hostFqdnOverride "default" ) ) ( not $ssMap ) ) }}
+{{-     $endpointHostPrefix := $ssMap.name }}
+{{-     range $podInt := until ( atoi (print $ssMap.replicas ) ) }}
+{{-       $endpointCredAndHost := printf "%s:%s@%s-%d.%s:%s" $endpointUser $endpointPass $endpointHostPrefix $podInt $endpointHostSuffix $endpointPort }}
+{{-       $_ := set $local "endpointCredsAndHosts" ( append $local.endpointCredsAndHosts $endpointCredAndHost ) }}
+{{-     end }}
+{{-   else }}
+{{-     $endpointHost := tuple $type $endpoint $context | include "helm-toolkit.endpoints.endpoint_host_lookup" }}
+{{-     $endpointCredAndHost := printf "%s:%s@%s:%s" $endpointUser $endpointPass $endpointHost $endpointPort }}
+{{-     $_ := set $local "endpointCredsAndHosts" ( append $local.endpointCredsAndHosts $endpointCredAndHost ) }}
+{{-   end }}
+{{-   $endpointCredsAndHosts := include "helm-toolkit.utils.joinListWithComma" $local.endpointCredsAndHosts }}
+{{-   $endpointPath := tuple $type $endpoint $port $context | include "helm-toolkit.endpoints.keystone_endpoint_path_lookup" }}
+{{-   printf "%s://%s%s" $endpointScheme $endpointCredsAndHosts $endpointPath }}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/endpoints/_endpoint_host_lookup.tpl b/charts/nova/charts/helm-toolkit/templates/endpoints/_endpoint_host_lookup.tpl
new file mode 100644
index 0000000..fb8bbe7
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/endpoints/_endpoint_host_lookup.tpl
@@ -0,0 +1,90 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Resolves either the fully qualified hostname, of if defined in the host field
+  IPv4 for an endpoint.
+examples:
+  - values: |
+      endpoints:
+        cluster_domain_suffix: cluster.local
+        oslo_db:
+          hosts:
+            default: mariadb
+          host_fqdn_override:
+            default: null
+    usage: |
+      {{ tuple "oslo_db" "internal" . | include "helm-toolkit.endpoints.endpoint_host_lookup" }}
+    return: |
+      mariadb.default.svc.cluster.local
+  - values: |
+      endpoints:
+        cluster_domain_suffix: cluster.local
+        oslo_db:
+          hosts:
+            default:
+             host: mariadb
+          host_fqdn_override:
+            default: null
+    usage: |
+      {{ tuple "oslo_db" "internal" . | include "helm-toolkit.endpoints.endpoint_host_lookup" }}
+    return: |
+      mariadb.default.svc.cluster.local
+  - values: |
+      endpoints:
+        cluster_domain_suffix: cluster.local
+        oslo_db:
+          hosts:
+            default: 127.0.0.1
+          host_fqdn_override:
+            default: null
+    usage: |
+      {{ tuple "oslo_db" "internal" . | include "helm-toolkit.endpoints.endpoint_host_lookup" }}
+    return: |
+      127.0.0.1
+  - values: |
+      endpoints:
+        cluster_domain_suffix: cluster.local
+        oslo_db:
+          hosts:
+            default:
+             host: 127.0.0.1
+          host_fqdn_override:
+            default: null
+    usage: |
+      {{ tuple "oslo_db" "internal" . | include "helm-toolkit.endpoints.endpoint_host_lookup" }}
+    return: |
+      127.0.0.1
+*/}}
+
+{{- define "helm-toolkit.endpoints.endpoint_host_lookup" -}}
+{{- $type := index . 0 -}}
+{{- $endpoint := index . 1 -}}
+{{- $context := index . 2 -}}
+{{- $endpointMap := index $context.Values.endpoints ( $type | replace "-" "_" ) }}
+{{- $endpointScheme := $endpointMap.scheme }}
+{{- $_ := set $context.Values "__endpointHost" ( index $endpointMap.hosts $endpoint | default $endpointMap.hosts.default ) }}
+{{- if kindIs "map" $context.Values.__endpointHost }}
+{{- $_ := set $context.Values "__endpointHost" ( index $context.Values.__endpointHost "host" ) }}
+{{- end }}
+{{- $endpointHost := $context.Values.__endpointHost }}
+{{- if regexMatch "[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+" $endpointHost }}
+{{- $endpointHostname := printf "%s" $endpointHost }}
+{{- printf "%s" $endpointHostname -}}
+{{- else }}
+{{- $endpointHostname := tuple $type $endpoint $context | include "helm-toolkit.endpoints.hostname_fqdn_endpoint_lookup" }}
+{{- printf "%s" $endpointHostname -}}
+{{- end }}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/endpoints/_endpoint_port_lookup.tpl b/charts/nova/charts/helm-toolkit/templates/endpoints/_endpoint_port_lookup.tpl
new file mode 100644
index 0000000..447efe7
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/endpoints/_endpoint_port_lookup.tpl
@@ -0,0 +1,41 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Resolves the port for an endpoint
+values: |
+  endpoints:
+    cluster_domain_suffix: cluster.local
+    oslo_db:
+      port:
+        mysql:
+          default: 3306
+usage: |
+  {{ tuple "oslo_db" "internal" "mysql" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+return: |
+  3306
+*/}}
+
+{{- define "helm-toolkit.endpoints.endpoint_port_lookup" -}}
+{{- $type := index . 0 -}}
+{{- $endpoint := index . 1 -}}
+{{- $port := index . 2 -}}
+{{- $context := index . 3 -}}
+{{- $typeYamlSafe := $type | replace "-" "_" }}
+{{- $endpointMap := index $context.Values.endpoints $typeYamlSafe }}
+{{- $endpointPortMAP := index $endpointMap.port $port }}
+{{- $endpointPort := index $endpointPortMAP $endpoint | default ( index $endpointPortMAP "default" ) }}
+{{- printf "%1.f" $endpointPort -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/endpoints/_endpoint_token_lookup.tpl b/charts/nova/charts/helm-toolkit/templates/endpoints/_endpoint_token_lookup.tpl
new file mode 100644
index 0000000..3a268c0
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/endpoints/_endpoint_token_lookup.tpl
@@ -0,0 +1,36 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Gets the token for an endpoint
+values: |
+  endpoints:
+    keystone:
+      auth:
+        admin:
+          token: zh78JzXgw6YUKy2e
+usage: |
+  {{ tuple "keystone" "admin" . | include "helm-toolkit.endpoints.endpoint_token_lookup" }}
+return: |
+  zh78JzXgw6YUKy2e
+*/}}
+
+{{- define "helm-toolkit.endpoints.endpoint_token_lookup" -}}
+{{- $type := index . 0 -}}
+{{- $userName := index . 1 -}}
+{{- $context := index . 2 -}}
+{{- $serviceToken := index $context.Values.endpoints ( $type | replace "-" "_" ) "auth" $userName "token" }}
+{{- printf "%s" $serviceToken -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/endpoints/_host_and_port_endpoint_uri_lookup.tpl b/charts/nova/charts/helm-toolkit/templates/endpoints/_host_and_port_endpoint_uri_lookup.tpl
new file mode 100644
index 0000000..6877b7b
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/endpoints/_host_and_port_endpoint_uri_lookup.tpl
@@ -0,0 +1,59 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Resolves 'hostname:port' for an endpoint
+examples:
+  - values: |
+      endpoints:
+        cluster_domain_suffix: cluster.local
+        oslo_db:
+          hosts:
+            default: mariadb
+          host_fqdn_override:
+            default: null
+          port:
+            mysql:
+              default: 3306
+    usage: |
+      {{ tuple "oslo_db" "internal" "mysql" . | include "helm-toolkit.endpoints.host_and_port_endpoint_uri_lookup" }}
+    return: |
+      mariadb.default.svc.cluster.local:3306
+  - values: |
+      endpoints:
+        cluster_domain_suffix: cluster.local
+        oslo_db:
+          hosts:
+            default: 127.0.0.1
+          host_fqdn_override:
+            default: null
+          port:
+            mysql:
+              default: 3306
+    usage: |
+      {{ tuple "oslo_db" "internal" "mysql" . | include "helm-toolkit.endpoints.host_and_port_endpoint_uri_lookup" }}
+    return: |
+      127.0.0.1:3306
+*/}}
+
+{{- define "helm-toolkit.endpoints.host_and_port_endpoint_uri_lookup" -}}
+{{- $type := index . 0 -}}
+{{- $endpoint := index . 1 -}}
+{{- $port := index . 2 -}}
+{{- $context := index . 3 -}}
+{{- $endpointPort := tuple $type $endpoint $port $context | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+{{- $endpointHostname := tuple $type $endpoint $context | include "helm-toolkit.endpoints.endpoint_host_lookup" }}
+{{- printf "%s:%s" $endpointHostname $endpointPort -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/endpoints/_hostname_fqdn_endpoint_lookup.tpl b/charts/nova/charts/helm-toolkit/templates/endpoints/_hostname_fqdn_endpoint_lookup.tpl
new file mode 100644
index 0000000..26374e3
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/endpoints/_hostname_fqdn_endpoint_lookup.tpl
@@ -0,0 +1,76 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Resolves the fully qualified hostname for an endpoint
+examples:
+  - values: |
+      endpoints:
+        cluster_domain_suffix: cluster.local
+        oslo_db:
+          hosts:
+            default: mariadb
+          host_fqdn_override:
+            default: null
+    usage: |
+      {{ tuple "oslo_db" "internal" . | include "helm-toolkit.endpoints.hostname_fqdn_endpoint_lookup" }}
+    return: |
+      mariadb.default.svc.cluster.local
+  - values: |
+      endpoints:
+        cluster_domain_suffix: cluster.local
+        oslo_db:
+          hosts:
+            default: mariadb
+          host_fqdn_override:
+            default: mariadb.openstackhelm.openstack.org
+    usage: |
+      {{ tuple "oslo_db" "internal" . | include "helm-toolkit.endpoints.hostname_fqdn_endpoint_lookup" }}
+    return: |
+      mariadb.openstackhelm.openstack.org
+  - values: |
+      endpoints:
+        cluster_domain_suffix: cluster.local
+        oslo_db:
+          hosts:
+            default: mariadb
+          host_fqdn_override:
+            default:
+              host: mariadb.openstackhelm.openstack.org
+    usage: |
+      {{ tuple "oslo_db" "internal" . | include "helm-toolkit.endpoints.hostname_fqdn_endpoint_lookup" }}
+    return: |
+      mariadb.openstackhelm.openstack.org
+*/}}
+
+{{- define "helm-toolkit.endpoints.hostname_fqdn_endpoint_lookup" -}}
+{{- $type := index . 0 -}}
+{{- $endpoint := index . 1 -}}
+{{- $context := index . 2 -}}
+{{- $endpointMap := index $context.Values.endpoints ( $type | replace "-" "_" ) }}
+{{- $endpointHostNamespaced := tuple $type $endpoint $context | include "helm-toolkit.endpoints.hostname_namespaced_endpoint_lookup" }}
+{{- $endpointClusterHostname := printf "%s.svc.%s" $endpointHostNamespaced $context.Values.endpoints.cluster_domain_suffix }}
+{{- $_ := set $context.Values "__FQDNendpointHostDefault" ( index $endpointMap.host_fqdn_override "default" | default "" ) }}
+{{- if kindIs "map" $context.Values.__FQDNendpointHostDefault }}
+{{- $_ := set $context.Values "__FQDNendpointHostDefault" ( index $context.Values.__FQDNendpointHostDefault "host" ) }}
+{{- end }}
+{{- if kindIs "map" (index $endpointMap.host_fqdn_override $endpoint) }}
+{{- $endpointHostname := index $endpointMap.host_fqdn_override $endpoint "host" | default $context.Values.__FQDNendpointHostDefault | default $endpointClusterHostname }}
+{{- printf "%s" $endpointHostname -}}
+{{- else }}
+{{- $endpointHostname := index $endpointMap.host_fqdn_override $endpoint | default $context.Values.__FQDNendpointHostDefault | default $endpointClusterHostname }}
+{{- printf "%s" $endpointHostname -}}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/endpoints/_hostname_namespaced_endpoint_lookup.tpl b/charts/nova/charts/helm-toolkit/templates/endpoints/_hostname_namespaced_endpoint_lookup.tpl
new file mode 100644
index 0000000..9d60393
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/endpoints/_hostname_namespaced_endpoint_lookup.tpl
@@ -0,0 +1,40 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Resolves the namespace scoped hostname for an endpoint
+values: |
+  endpoints:
+    oslo_db:
+      hosts:
+        default: mariadb
+      host_fqdn_override:
+        default: null
+usage: |
+  {{ tuple "oslo_db" "internal" . | include "helm-toolkit.endpoints.hostname_namespaced_endpoint_lookup" }}
+return: |
+  mariadb.default
+*/}}
+
+{{- define "helm-toolkit.endpoints.hostname_namespaced_endpoint_lookup" -}}
+{{- $type := index . 0 -}}
+{{- $endpoint := index . 1 -}}
+{{- $context := index . 2 -}}
+{{- $endpointMap := index $context.Values.endpoints ( $type | replace "-" "_" ) }}
+{{- $namespace := $endpointMap.namespace | default $context.Release.Namespace }}
+{{- $endpointHost := tuple $type $endpoint $context | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }}
+{{- $endpointClusterHostname := printf "%s.%s" $endpointHost $namespace }}
+{{- printf "%s" $endpointClusterHostname -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/endpoints/_hostname_namespaced_endpoint_namespace_lookup.tpl b/charts/nova/charts/helm-toolkit/templates/endpoints/_hostname_namespaced_endpoint_namespace_lookup.tpl
new file mode 100644
index 0000000..cc4d4de
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/endpoints/_hostname_namespaced_endpoint_namespace_lookup.tpl
@@ -0,0 +1,38 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Resolves the namespace scoped hostname for an endpoint
+values: |
+  endpoints:
+    oslo_db:
+      hosts:
+        default: mariadb
+      host_fqdn_override:
+        default: null
+usage: |
+  {{ tuple "oslo_db" "internal" . | include "helm-toolkit.endpoints.hostname_namespaced_endpoint_namespace_lookup" }}
+return: |
+  default
+*/}}
+
+{{- define "helm-toolkit.endpoints.hostname_namespaced_endpoint_namespace_lookup" -}}
+{{- $type := index . 0 -}}
+{{- $endpoint := index . 1 -}}
+{{- $context := index . 2 -}}
+{{- $endpointMap := index $context.Values.endpoints ( $type | replace "-" "_" ) }}
+{{- $namespace := $endpointMap.namespace | default $context.Release.Namespace }}
+{{- printf "%s" $namespace -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/endpoints/_hostname_short_endpoint_lookup.tpl b/charts/nova/charts/helm-toolkit/templates/endpoints/_hostname_short_endpoint_lookup.tpl
new file mode 100644
index 0000000..f23c624
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/endpoints/_hostname_short_endpoint_lookup.tpl
@@ -0,0 +1,61 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Resolves the short hostname for an endpoint
+examples:
+  - values: |
+      endpoints:
+        oslo_db:
+          hosts:
+            default: mariadb
+          host_fqdn_override:
+            default: null
+    usage: |
+      {{ tuple "oslo_db" "internal" . | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }}
+    return: |
+      mariadb
+  - values: |
+      endpoints:
+        oslo_db:
+          hosts:
+            default:
+              host: mariadb
+          host_fqdn_override:
+            default: null
+    usage: |
+      {{ tuple "oslo_db" "internal" . | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }}
+    return: |
+      mariadb
+*/}}
+
+{{- define "helm-toolkit.endpoints.hostname_short_endpoint_lookup" -}}
+{{- $type := index . 0 -}}
+{{- $endpoint := index . 1 -}}
+{{- $context := index . 2 -}}
+{{- $endpointMap := index $context.Values.endpoints ( $type | replace "-" "_" ) }}
+{{- $endpointScheme := $endpointMap.scheme }}
+{{- $_ := set $context.Values "__endpointHost" ( index $endpointMap.hosts $endpoint | default $endpointMap.hosts.default ) }}
+{{- if kindIs "map" $context.Values.__endpointHost }}
+{{- $_ := set $context.Values "__endpointHost" ( index $context.Values.__endpointHost "host" ) }}
+{{- end }}
+{{- $endpointHost := $context.Values.__endpointHost }}
+{{- if regexMatch "[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+" $endpointHost }}
+{{- printf "%s" $type -}}
+{{- else }}
+{{- $endpointHostname := printf "%s" $endpointHost }}
+{{- printf "%s" $endpointHostname -}}
+{{- end }}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/endpoints/_keystone_endpoint_name_lookup.tpl b/charts/nova/charts/helm-toolkit/templates/endpoints/_keystone_endpoint_name_lookup.tpl
new file mode 100644
index 0000000..e31c0eb
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/endpoints/_keystone_endpoint_name_lookup.tpl
@@ -0,0 +1,34 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Resolves the service name for an service type
+values: |
+  endpoints:
+    identity:
+      name: keystone
+usage: |
+  {{ tuple identity . | include "keystone_endpoint_name_lookup" }}
+return: |
+  "keystone"
+*/}}
+
+{{- define "helm-toolkit.endpoints.keystone_endpoint_name_lookup" -}}
+{{- $type := index . 0 -}}
+{{- $context := index . 1 -}}
+{{- $endpointMap := index $context.Values.endpoints ( $type | replace "-" "_" ) }}
+{{- $endpointName := index $endpointMap "name" }}
+{{- $endpointName | quote -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/endpoints/_keystone_endpoint_path_lookup.tpl b/charts/nova/charts/helm-toolkit/templates/endpoints/_keystone_endpoint_path_lookup.tpl
new file mode 100644
index 0000000..b2ec648
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/endpoints/_keystone_endpoint_path_lookup.tpl
@@ -0,0 +1,48 @@
+{{/*
+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.
+*/}}
+
+# FIXME(portdirect): it appears the port input here serves no purpose,
+# and should be removed. In addition this function is bugged, do we use it?
+
+{{/*
+abstract: |
+  Resolves the path for an endpoint
+values: |
+  endpoints:
+    cluster_domain_suffix: cluster.local
+    oslo_db:
+      path:
+       default: /dbname
+      port:
+        mysql:
+          default: 3306
+usage: |
+  {{ tuple "oslo_db" "internal" "mysql" . | include "helm-toolkit.endpoints.keystone_endpoint_path_lookup" }}
+return: |
+  /dbname
+*/}}
+
+{{- define "helm-toolkit.endpoints.keystone_endpoint_path_lookup" -}}
+{{- $type := index . 0 -}}
+{{- $endpoint := index . 1 -}}
+{{- $port := index . 2 -}}
+{{- $context := index . 3 -}}
+{{- $endpointMap := index $context.Values.endpoints ( $type | replace "-" "_" ) }}
+{{- if kindIs "string" $endpointMap.path }}
+{{- printf "%s" $endpointMap.path | default "/" -}}
+{{- else -}}
+{{- $endpointPath := index $endpointMap.path $endpoint | default $endpointMap.path.default | default "/" }}
+{{- printf "%s" $endpointPath -}}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/endpoints/_keystone_endpoint_scheme_lookup.tpl b/charts/nova/charts/helm-toolkit/templates/endpoints/_keystone_endpoint_scheme_lookup.tpl
new file mode 100644
index 0000000..b35cb0b
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/endpoints/_keystone_endpoint_scheme_lookup.tpl
@@ -0,0 +1,55 @@
+{{/*
+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.
+*/}}
+
+# FIXME(portdirect): it appears the port input here serves no purpose,
+# and should be removed. In addition this function is bugged, do we use it?
+
+{{/*
+abstract: |
+  Resolves the scheme for an endpoint
+values: |
+  endpoints:
+    cluster_domain_suffix: cluster.local
+    oslo_db:
+      scheme:
+        default:
+          mysql+pymysql
+      port:
+        mysql:
+          default: 3306
+usage: |
+  {{ tuple "oslo_db" "internal" "mysql" . | include "helm-toolkit.endpoints.keystone_endpoint_scheme_lookup" }}
+return: |
+  mysql+pymysql
+*/}}
+
+# This function returns the scheme for a service, it takes an tuple
+# input in the form: service-type, endpoint-class, port-name. eg:
+# { tuple "etcd" "internal" "client" . | include "helm-toolkit.endpoints.keystone_scheme_lookup" }
+# will return the scheme setting for this particular endpoint.  In other words, for most endpoints
+# it will return either 'http' or 'https'
+
+{{- define "helm-toolkit.endpoints.keystone_endpoint_scheme_lookup" -}}
+{{- $type := index . 0 -}}
+{{- $endpoint := index . 1 -}}
+{{- $port := index . 2 -}}
+{{- $context := index . 3 -}}
+{{- $endpointMap := index $context.Values.endpoints ( $type | replace "-" "_" ) }}
+{{- if kindIs "string" $endpointMap.scheme }}
+{{- printf "%s" $endpointMap.scheme | default "http" -}}
+{{- else -}}
+{{- $endpointScheme := index $endpointMap.scheme $endpoint | default $endpointMap.scheme.default | default "http" }}
+{{- printf "%s" $endpointScheme -}}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/endpoints/_keystone_endpoint_uri_lookup.tpl b/charts/nova/charts/helm-toolkit/templates/endpoints/_keystone_endpoint_uri_lookup.tpl
new file mode 100644
index 0000000..8d0819c
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/endpoints/_keystone_endpoint_uri_lookup.tpl
@@ -0,0 +1,52 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  This function helps resolve uri style endpoints. It will omit the port for
+  http when 80 is used, and 443 in the case of https.
+values: |
+  endpoints:
+    cluster_domain_suffix: cluster.local
+    oslo_db:
+      hosts:
+        default: mariadb
+      host_fqdn_override:
+        default: null
+      path: /dbname
+      scheme: mysql+pymysql
+      port:
+        mysql:
+          default: 3306
+usage: |
+  {{ tuple "oslo_db" "internal" "mysql" . | include "helm-toolkit.endpoints.keystone_endpoint_uri_lookup" }}
+return: |
+  mysql+pymysql://mariadb.default.svc.cluster.local:3306/dbname
+*/}}
+
+{{- define "helm-toolkit.endpoints.keystone_endpoint_uri_lookup" -}}
+{{- $type := index . 0 -}}
+{{- $endpoint := index . 1 -}}
+{{- $port := index . 2 -}}
+{{- $context := index . 3 -}}
+{{- $endpointScheme := tuple $type $endpoint $port $context | include "helm-toolkit.endpoints.keystone_endpoint_scheme_lookup" }}
+{{- $endpointHost := tuple $type $endpoint $context | include "helm-toolkit.endpoints.endpoint_host_lookup" }}
+{{- $endpointPort := tuple $type $endpoint $port $context | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+{{- $endpointPath := tuple $type $endpoint $port $context | include "helm-toolkit.endpoints.keystone_endpoint_path_lookup" }}
+{{- if or ( and ( eq $endpointScheme "http" ) ( eq $endpointPort "80" ) ) ( and ( eq $endpointScheme "https" ) ( eq $endpointPort "443" ) ) -}}
+{{- printf "%s://%s%s" $endpointScheme $endpointHost $endpointPath -}}
+{{- else -}}
+{{- printf "%s://%s:%s%s" $endpointScheme $endpointHost $endpointPort $endpointPath -}}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/endpoints/_service_name_endpoint_with_namespace_lookup.tpl b/charts/nova/charts/helm-toolkit/templates/endpoints/_service_name_endpoint_with_namespace_lookup.tpl
new file mode 100644
index 0000000..cf2ef38
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/endpoints/_service_name_endpoint_with_namespace_lookup.tpl
@@ -0,0 +1,61 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  This function returns endpoint "<namespace>:<name>" pair from an endpoint
+  definition. This is used in kubernetes-entrypoint to support dependencies
+  between different services in different namespaces.
+  returns: the endpoint namespace and the service name, delimited by a colon
+
+  Normally, the service name is constructed dynamically from the hostname
+  however when an ip address is used as the hostname, we default to
+  namespace:endpointCategoryName in order to construct a valid service name
+  however this can be overridden to a custom service name by defining
+  .service.name within the endpoint definition
+values: |
+  endpoints:
+    cluster_domain_suffix: cluster.local
+    oslo_db:
+      namespace: foo
+      hosts:
+        default: mariadb
+      host_fqdn_override:
+        default: null
+usage: |
+  {{ tuple oslo_db internal . | include "helm-toolkit.endpoints.service_name_endpoint_with_namespace_lookup" }}
+return: |
+  foo:mariadb
+*/}}
+
+{{- define "helm-toolkit.endpoints.service_name_endpoint_with_namespace_lookup" -}}
+{{- $type := index . 0 -}}
+{{- $endpoint := index . 1 -}}
+{{- $context := index . 2 -}}
+{{- $typeYamlSafe := $type | replace "-" "_" }}
+{{- $endpointMap := index $context.Values.endpoints $typeYamlSafe }}
+{{- with $endpointMap -}}
+{{- $endpointName := index .hosts $endpoint | default .hosts.default }}
+{{- $endpointNamespace := .namespace | default $context.Release.Namespace }}
+{{- if regexMatch "[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+" $endpointName }}
+{{- if .service.name }}
+{{- printf "%s:%s" $endpointNamespace .service.name -}}
+{{- else -}}
+{{- printf "%s:%s" $endpointNamespace $typeYamlSafe -}}
+{{- end -}}
+{{- else -}}
+{{- printf "%s:%s" $endpointNamespace $endpointName -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/manifests/_ceph-storageclass.tpl b/charts/nova/charts/helm-toolkit/templates/manifests/_ceph-storageclass.tpl
new file mode 100644
index 0000000..18453ee
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/manifests/_ceph-storageclass.tpl
@@ -0,0 +1,111 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Creates a manifest for kubernete ceph storageclass
+examples:
+  - values: |
+      manifests:
+        storageclass: true
+      storageclass:
+        rbd:
+          provision_storage_class: true
+          provisioner: "ceph.com/rbd"
+          metadata:
+            default_storage_class: true
+            name: general
+          parameters:
+            #We will grab the monitors value based on helm-toolkit.endpoints.host_and_port_endpoint_uri_lookup
+            pool: rbd
+            admin_id: admin
+            ceph_configmap_name: "ceph-etc"
+            admin_secret_name: "pvc-ceph-conf-combined-storageclass"
+            admin_secret_namespace: ceph
+            user_id: admin
+            user_secret_name: "pvc-ceph-client-key"
+            image_format: "2"
+            image_features: layering
+        cephfs:
+          provision_storage_class: true
+          provisioner: "ceph.com/cephfs"
+          metadata:
+            name: cephfs
+          parameters:
+            admin_id: admin
+            admin_secret_name: "pvc-ceph-cephfs-client-key"
+            admin_secret_namespace: ceph
+    usage: |
+      {{- range $storageclass, $val := .Values.storageclass }}
+      {{ dict "storageclass_data" $val "envAll" $ | include "helm-toolkit.manifests.ceph-storageclass" }}
+      {{- end }}
+    return: |
+      ---
+      apiVersion: storage.k8s.io/v1
+      kind: StorageClass
+      metadata:
+        annotations:
+          storageclass.kubernetes.io/is-default-class: "true"
+        name: general
+      provisioner: ceph.com/rbd
+      parameters:
+        monitors: ceph-mon.<ceph-namespace>.svc.<k8s-domain-name>:6789
+        adminId: admin
+        adminSecretName: pvc-ceph-conf-combined-storageclass
+        adminSecretNamespace: ceph
+        pool: rbd
+        userId: admin
+        userSecretName: pvc-ceph-client-key
+        image_format: "2"
+        image_features: layering
+      ---
+      apiVersion: storage.k8s.io/v1
+      kind: StorageClass
+      metadata:
+        name: cephfs
+      provisioner: ceph.com/cephfs
+      parameters:
+        monitors: ceph-mon.<ceph-namespace>.svc.<k8s-domain-name>:6789
+        adminId: admin
+        adminSecretName: pvc-ceph-cephfs-client-key
+        adminSecretNamespace: ceph
+*/}}
+
+{{- define "helm-toolkit.manifests.ceph-storageclass" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $monHost := $envAll.Values.conf.ceph.global.mon_host -}}
+{{- if empty $monHost -}}
+{{- $monHost = tuple "ceph_mon" "internal" "mon" $envAll | include "helm-toolkit.endpoints.host_and_port_endpoint_uri_lookup" -}}
+{{- end -}}
+{{- $storageclassData := index . "storageclass_data" -}}
+---
+{{- if $storageclassData.provision_storage_class }}
+apiVersion: storage.k8s.io/v1
+kind: StorageClass
+metadata:
+{{- if $storageclassData.metadata.default_storage_class }}
+  annotations:
+    storageclass.kubernetes.io/is-default-class: "true"
+{{- end }}
+  name: {{ $storageclassData.metadata.name }}
+provisioner: {{ $storageclassData.provisioner }}
+parameters:
+  monitors: {{ $monHost }}
+{{- range $attr, $value := $storageclassData.parameters }}
+  {{ $attr }}: {{ $value | quote }}
+{{- end }}
+allowVolumeExpansion: true
+
+{{- end }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/manifests/_certificates.tpl b/charts/nova/charts/helm-toolkit/templates/manifests/_certificates.tpl
new file mode 100644
index 0000000..8be771e
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/manifests/_certificates.tpl
@@ -0,0 +1,108 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Creates a certificate using jetstack
+examples:
+  - values: |
+      endpoints:
+        dashboard:
+          host_fqdn_override:
+            default:
+              host: null
+              tls:
+                secretName: keystone-tls-api
+                issuerRef:
+                  name: ca-issuer
+                  duration: 2160h
+                  organization:
+                    - ACME
+                  commonName: keystone-api.openstack.svc.cluster.local
+                  privateKey:
+                    size: 2048
+                  usages:
+                    - server auth
+                    - client auth
+                  dnsNames:
+                    - cluster.local
+                  issuerRef:
+                    name: ca-issuer
+    usage: |
+      {{- $opts := dict "envAll" . "service" "dashboard" "type" "internal" -}}
+      {{ $opts | include "helm-toolkit.manifests.certificates" }}
+    return: |
+      ---
+      apiVersion: cert-manager.io/v1
+      kind: Certificate
+      metadata:
+        name: keystone-tls-api
+        namespace: NAMESPACE
+      spec:
+        commonName: keystone-api.openstack.svc.cluster.local
+        dnsNames:
+        - cluster.local
+        duration: 2160h
+        issuerRef:
+          name: ca-issuer
+        privateKey:
+          size: 2048
+        organization:
+        - ACME
+        secretName: keystone-tls-api
+        usages:
+        - server auth
+        - client auth
+*/}}
+
+{{- define "helm-toolkit.manifests.certificates" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $service := index . "service" -}}
+{{- $type := index . "type" | default "" -}}
+{{- $slice := index $envAll.Values.endpoints $service "host_fqdn_override" "default" "tls" -}}
+{{/* Put in some sensible default value if one is not provided by values.yaml */}}
+{{/* If a dnsNames list is not in the values.yaml, it can be overridden by a passed-in parameter.
+  This allows user to use other HTK method to determine the URI and pass that into this method.*/}}
+{{- if not (hasKey $slice "dnsNames") -}}
+{{- $hostName := tuple $service $type $envAll | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" -}}
+{{- $dnsNames := list $hostName (printf "%s.%s" $hostName $envAll.Release.Namespace) (printf "%s.%s.svc.%s" $hostName $envAll.Release.Namespace $envAll.Values.endpoints.cluster_domain_suffix) -}}
+{{- $_ := $dnsNames | set (index $envAll.Values.endpoints $service "host_fqdn_override" "default" "tls") "dnsNames" -}}
+{{- end -}}
+{{/* Default privateKey size to 4096. This can be overridden. */}}
+{{- if not (hasKey $slice "privateKey") -}}
+{{- $_ := dict "size" ( printf "%d" 4096 | atoi ) | set (index $envAll.Values.endpoints $service "host_fqdn_override" "default" "tls") "privateKey" -}}
+{{- else if empty (index $envAll.Values.endpoints $service "host_fqdn_override" "default" "tls" "privateKey" "size") -}}
+{{- $_ := ( printf "%d" 4096 | atoi ) | set (index $envAll.Values.endpoints $service "host_fqdn_override" "default" "tls" "privateKey") "size" -}}
+{{- end -}}
+{{/* Default duration to 3 months. Note the min is 720h. This can be overridden. */}}
+{{- if not (hasKey $slice "duration") -}}
+{{- $_ := printf "%s" "2190h" | set (index $envAll.Values.endpoints $service "host_fqdn_override" "default" "tls") "duration" -}}
+{{- end -}}
+{{/* Default renewBefore to 15 days. This can be overridden. */}}
+{{- if not (hasKey $slice "renewBefore") -}}
+{{- $_ := printf "%s" "360h" | set (index $envAll.Values.endpoints $service "host_fqdn_override" "default" "tls") "renewBefore" -}}
+{{- end -}}
+{{/* Default the usage to server auth and client auth. This can be overridden. */}}
+{{- if not (hasKey $slice "usages") -}}
+{{- $_ := (list "server auth" "client auth") | set (index $envAll.Values.endpoints $service "host_fqdn_override" "default" "tls") "usages" -}}
+{{- end -}}
+---
+apiVersion: cert-manager.io/v1
+kind: Certificate
+metadata:
+  name: {{ index $envAll.Values.endpoints $service "host_fqdn_override" "default" "tls" "secretName" }}
+  namespace: {{ $envAll.Release.Namespace }}
+spec:
+{{ $slice | toYaml | indent 2 }}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/manifests/_ingress.tpl b/charts/nova/charts/helm-toolkit/templates/manifests/_ingress.tpl
new file mode 100644
index 0000000..c1693aa
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/manifests/_ingress.tpl
@@ -0,0 +1,727 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Creates a manifest for a services ingress rules.
+examples:
+  - values: |
+      network:
+        api:
+          ingress:
+            public: true
+            classes:
+              namespace: "nginx"
+              cluster: "nginx-cluster"
+            annotations:
+              nginx.ingress.kubernetes.io/rewrite-target: /
+      secrets:
+        tls:
+          key_manager:
+            api:
+              public: barbican-tls-public
+      endpoints:
+        cluster_domain_suffix: cluster.local
+        key_manager:
+          name: barbican
+          hosts:
+            default: barbican-api
+            public: barbican
+          host_fqdn_override:
+            default: null
+            public:
+              host: barbican.openstackhelm.example
+              tls:
+                crt: |
+                  FOO-CRT
+                key: |
+                  FOO-KEY
+                ca: |
+                  FOO-CA_CRT
+          path:
+            default: /
+          scheme:
+            default: http
+            public: https
+          port:
+            api:
+              default: 9311
+              public: 80
+    usage: |
+      {{- include "helm-toolkit.manifests.ingress" ( dict "envAll" . "backendServiceType" "key-manager" "backendPort" "b-api" "endpoint" "public" ) -}}
+    return: |
+      ---
+      apiVersion: networking.k8s.io/v1
+      kind: Ingress
+      metadata:
+        name: barbican
+        annotations:
+          kubernetes.io/ingress.class: "nginx"
+          nginx.ingress.kubernetes.io/rewrite-target: /
+
+      spec:
+        rules:
+          - host: barbican
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: barbican-api
+                      port:
+                        name: b-api
+          - host: barbican.default
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: barbican-api
+                      port:
+                        name: b-api
+          - host: barbican.default.svc.cluster.local
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: barbican-api
+                      port:
+                        name: b-api
+      ---
+      apiVersion: networking.k8s.io/v1
+      kind: Ingress
+      metadata:
+        name: barbican-namespace-fqdn
+        annotations:
+          kubernetes.io/ingress.class: "nginx"
+          nginx.ingress.kubernetes.io/rewrite-target: /
+
+      spec:
+        tls:
+          - secretName: barbican-tls-public
+            hosts:
+              - barbican.openstackhelm.example
+        rules:
+          - host: barbican.openstackhelm.example
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: barbican-api
+                      port:
+                        name: b-api
+      ---
+      apiVersion: networking.k8s.io/v1
+      kind: Ingress
+      metadata:
+        name: barbican-cluster-fqdn
+        annotations:
+          kubernetes.io/ingress.class: "nginx-cluster"
+          nginx.ingress.kubernetes.io/rewrite-target: /
+
+      spec:
+        tls:
+          - secretName: barbican-tls-public
+            hosts:
+              - barbican.openstackhelm.example
+        rules:
+          - host: barbican.openstackhelm.example
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: barbican-api
+                      port:
+                        name: b-api
+  - values: |
+      network:
+        api:
+          ingress:
+            public: true
+            classes:
+              namespace: "nginx"
+              cluster: "nginx-cluster"
+            annotations:
+              nginx.ingress.kubernetes.io/rewrite-target: /
+      secrets:
+        tls:
+          key_manager:
+            api:
+              public: barbican-tls-public
+      endpoints:
+        cluster_domain_suffix: cluster.local
+        key_manager:
+          name: barbican
+          hosts:
+            default: barbican-api
+            public:
+              host: barbican
+              tls:
+                crt: |
+                  FOO-CRT
+                key: |
+                  FOO-KEY
+                ca: |
+                  FOO-CA_CRT
+          host_fqdn_override:
+            default: null
+          path:
+            default: /
+          scheme:
+            default: http
+            public: https
+          port:
+            api:
+              default: 9311
+              public: 80
+    usage: |
+      {{- include "helm-toolkit.manifests.ingress" ( dict "envAll" . "backendServiceType" "key-manager" "backendPort" "b-api" "endpoint" "public" ) -}}
+    return: |
+      ---
+      apiVersion: networking.k8s.io/v1
+      kind: Ingress
+      metadata:
+        name: barbican
+        annotations:
+          kubernetes.io/ingress.class: "nginx"
+          nginx.ingress.kubernetes.io/rewrite-target: /
+
+      spec:
+        tls:
+          - secretName: barbican-tls-public
+            hosts:
+              - barbican
+              - barbican.default
+              - barbican.default.svc.cluster.local
+        rules:
+          - host: barbican
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: barbican-api
+                      port:
+                        name: b-api
+          - host: barbican.default
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: barbican-api
+                      port:
+                        name: b-api
+          - host: barbican.default.svc.cluster.local
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: barbican-api
+                      port:
+                        name: b-api
+  - values: |
+      cert_issuer_type: issuer
+      network:
+        api:
+          ingress:
+            public: true
+            classes:
+              namespace: "nginx"
+              cluster: "nginx-cluster"
+            annotations:
+              nginx.ingress.kubernetes.io/secure-backends: "true"
+              nginx.ingress.kubernetes.io/backend-protocol: "https"
+      secrets:
+        tls:
+          key_manager:
+            api:
+              public: barbican-tls-public
+              internal: barbican-tls-api
+      endpoints:
+        cluster_domain_suffix: cluster.local
+        key_manager:
+          name: barbican
+          hosts:
+            default: barbican-api
+            public:
+              host: barbican
+              tls:
+                crt: |
+                  FOO-CRT
+                key: |
+                  FOO-KEY
+                ca: |
+                  FOO-CA_CRT
+          host_fqdn_override:
+            default: null
+          path:
+            default: /
+          scheme:
+            default: http
+            public: https
+          port:
+            api:
+              default: 9311
+              public: 80
+          certs:
+            barbican_tls_api:
+              secretName: barbican-tls-api
+              issuerRef:
+                name: ca-issuer
+                kind: Issuer
+    usage: |
+      {{- include "helm-toolkit.manifests.ingress" ( dict "envAll" . "backendServiceType" "key-manager" "backendPort" "b-api" "endpoint" "public" "certIssuer" "ca-issuer" ) -}}
+    return: |
+      ---
+      apiVersion: networking.k8s.io/v1
+      kind: Ingress
+      metadata:
+        name: barbican
+        annotations:
+          kubernetes.io/ingress.class: "nginx"
+          cert-manager.io/issuer: ca-issuer
+          certmanager.k8s.io/issuer: ca-issuer
+          nginx.ingress.kubernetes.io/backend-protocol: https
+          nginx.ingress.kubernetes.io/secure-backends: "true"
+      spec:
+        tls:
+          - secretName: barbican-tls-public-certmanager
+            hosts:
+              - barbican
+              - barbican.default
+              - barbican.default.svc.cluster.local
+        rules:
+          - host: barbican
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: barbican-api
+                      port:
+                        name: b-api
+          - host: barbican.default
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: barbican-api
+                      port:
+                        name: b-api
+          - host: barbican.default.svc.cluster.local
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: barbican-api
+                      port:
+                        name: b-api
+
+  - values: |
+      network:
+        api:
+          ingress:
+            public: true
+            classes:
+              namespace: "nginx"
+              cluster: "nginx-cluster"
+            annotations:
+              nginx.ingress.kubernetes.io/secure-backends: "true"
+              nginx.ingress.kubernetes.io/backend-protocol: "https"
+      secrets:
+        tls:
+          key_manager:
+            api:
+              public: barbican-tls-public
+              internal: barbican-tls-api
+      endpoints:
+        cluster_domain_suffix: cluster.local
+        key_manager:
+          name: barbican
+          hosts:
+            default: barbican-api
+            public:
+              host: barbican
+              tls:
+                crt: |
+                  FOO-CRT
+                key: |
+                  FOO-KEY
+                ca: |
+                  FOO-CA_CRT
+          host_fqdn_override:
+            default: null
+          path:
+            default: /
+          scheme:
+            default: http
+            public: https
+          port:
+            api:
+              default: 9311
+              public: 80
+          certs:
+            barbican_tls_api:
+              secretName: barbican-tls-api
+              issuerRef:
+                name: ca-issuer
+                kind: ClusterIssuer
+    usage: |
+      {{- include "helm-toolkit.manifests.ingress" ( dict "envAll" . "backendServiceType" "key-manager" "backendPort" "b-api" "endpoint" "public" "certIssuer" "ca-issuer") -}}
+    return: |
+      ---
+      apiVersion: networking.k8s.io/v1
+      kind: Ingress
+      metadata:
+        name: barbican
+        annotations:
+          kubernetes.io/ingress.class: "nginx"
+          cert-manager.io/cluster-issuer: ca-issuer
+          certmanager.k8s.io/cluster-issuer: ca-issuer
+          nginx.ingress.kubernetes.io/backend-protocol: https
+          nginx.ingress.kubernetes.io/secure-backends: "true"
+      spec:
+        tls:
+          - secretName: barbican-tls-public-certmanager
+            hosts:
+              - barbican
+              - barbican.default
+              - barbican.default.svc.cluster.local
+        rules:
+          - host: barbican
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: barbican-api
+                      port:
+                        name: b-api
+          - host: barbican.default
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: barbican-api
+                      port:
+                        name: b-api
+          - host: barbican.default.svc.cluster.local
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: barbican-api
+                      port:
+                        name: b-api
+  # Sample usage for multiple DNS names associated with the same public
+  # endpoint and certificate
+  - values: |
+      endpoints:
+        cluster_domain_suffix: cluster.local
+        grafana:
+          name: grafana
+          hosts:
+            default: grafana-dashboard
+            public: grafana
+          host_fqdn_override:
+            public:
+              host: grafana.openstackhelm.example
+              tls:
+                dnsNames:
+                  - grafana-alt.openstackhelm.example
+                crt: "BASE64 ENCODED CERT"
+                key: "BASE64 ENCODED KEY"
+      network:
+        grafana:
+          ingress:
+            classes:
+              namespace: "nginx"
+              cluster: "nginx-cluster"
+            annotations:
+              nginx.ingress.kubernetes.io/rewrite-target: /
+      secrets:
+        tls:
+          grafana:
+            grafana:
+              public: grafana-tls-public
+    usage: |
+      {{- $ingressOpts := dict "envAll" . "backendService" "grafana" "backendServiceType" "grafana" "backendPort" "dashboard" -}}
+      {{ $ingressOpts | include "helm-toolkit.manifests.ingress" }}
+    return: |
+      ---
+      apiVersion: networking.k8s.io/v1
+      kind: Ingress
+      metadata:
+        name: grafana
+        annotations:
+          kubernetes.io/ingress.class: "nginx"
+          nginx.ingress.kubernetes.io/rewrite-target: /
+
+      spec:
+        rules:
+          - host: grafana
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: grafana-dashboard
+                      port:
+                        name: dashboard
+          - host: grafana.default
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: grafana-dashboard
+                      port:
+                        name: dashboard
+          - host: grafana.default.svc.cluster.local
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: grafana-dashboard
+                      port:
+                        name: dashboard
+      ---
+      apiVersion: networking.k8s.io/v1
+      kind: Ingress
+      metadata:
+        name: grafana-namespace-fqdn
+        annotations:
+          kubernetes.io/ingress.class: "nginx"
+          nginx.ingress.kubernetes.io/rewrite-target: /
+
+      spec:
+        tls:
+          - secretName: grafana-tls-public
+            hosts:
+              - grafana.openstackhelm.example
+              - grafana-alt.openstackhelm.example
+        rules:
+          - host: grafana.openstackhelm.example
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: grafana-dashboard
+                      port:
+                        name: dashboard
+          - host: grafana-alt.openstackhelm.example
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: grafana-dashboard
+                      port:
+                        name: dashboard
+      ---
+      apiVersion: networking.k8s.io/v1
+      kind: Ingress
+      metadata:
+        name: grafana-cluster-fqdn
+        annotations:
+          kubernetes.io/ingress.class: "nginx-cluster"
+          nginx.ingress.kubernetes.io/rewrite-target: /
+
+      spec:
+        tls:
+          - secretName: grafana-tls-public
+            hosts:
+              - grafana.openstackhelm.example
+              - grafana-alt.openstackhelm.example
+        rules:
+          - host: grafana.openstackhelm.example
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: grafana-dashboard
+                      port:
+                        name: dashboard
+          - host: grafana-alt.openstackhelm.example
+            http:
+              paths:
+                - path: /
+                  pathType: ImplementationSpecific
+                  backend:
+                    service:
+                      name: grafana-dashboard
+                      port:
+                        name: dashboard
+
+*/}}
+
+{{- define "helm-toolkit.manifests.ingress._host_rules" -}}
+{{- $vHost := index . "vHost" -}}
+{{- $backendName := index . "backendName" -}}
+{{- $backendPort := index . "backendPort" -}}
+- host: {{ $vHost }}
+  http:
+    paths:
+      - path: /
+        pathType: ImplementationSpecific
+        backend:
+          service:
+            name: {{ $backendName }}
+            port:
+{{- if or (kindIs "int" $backendPort) (regexMatch "^[0-9]{1,5}$" $backendPort) }}
+              number: {{ $backendPort | int }}
+{{- else }}
+              name: {{ $backendPort | quote }}
+{{- end }}
+{{- end }}
+
+{{- define "helm-toolkit.manifests.ingress" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $backendService := index . "backendService" | default "api" -}}
+{{- $backendServiceType := index . "backendServiceType" -}}
+{{- $backendPort := index . "backendPort" -}}
+{{- $endpoint := index . "endpoint" | default "public" -}}
+{{- $certIssuer := index . "certIssuer" | default "" -}}
+{{- $ingressName := tuple $backendServiceType $endpoint $envAll | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }}
+{{- $backendName := tuple $backendServiceType "internal" $envAll | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }}
+{{- $hostName := tuple $backendServiceType $endpoint $envAll | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }}
+{{- $hostNameFull := tuple $backendServiceType $endpoint $envAll | include "helm-toolkit.endpoints.hostname_fqdn_endpoint_lookup" }}
+{{- $certIssuerType := "cluster-issuer" -}}
+{{- if $envAll.Values.cert_issuer_type }}
+{{- $certIssuerType = $envAll.Values.cert_issuer_type }}
+{{- end }}
+---
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: {{ $ingressName }}
+  annotations:
+    kubernetes.io/ingress.class: {{ index $envAll.Values.network $backendService "ingress" "classes" "namespace" | quote }}
+{{- if $certIssuer }}
+    cert-manager.io/{{ $certIssuerType }}: {{ $certIssuer }}
+    certmanager.k8s.io/{{ $certIssuerType }}: {{ $certIssuer }}
+{{- $slice := index $envAll.Values.endpoints $backendServiceType "host_fqdn_override" "default" "tls" -}}
+{{- if (hasKey $slice "duration") }}
+    cert-manager.io/duration: {{ index $slice "duration" }}
+{{- end }}
+{{- end }}
+{{ toYaml (index $envAll.Values.network $backendService "ingress" "annotations") | indent 4 }}
+spec:
+{{- $host := index $envAll.Values.endpoints ( $backendServiceType | replace "-" "_" ) "hosts" }}
+{{- if $certIssuer }}
+{{- $secretName := index $envAll.Values.secrets "tls" ( $backendServiceType | replace "-" "_" ) $backendService $endpoint }}
+{{- $_ := required "You need to specify a secret in your values for the endpoint" $secretName }}
+  tls:
+    - secretName: {{ printf "%s-ing" $secretName }}
+      hosts:
+{{- range $key1, $vHost := tuple $hostName (printf "%s.%s" $hostName $envAll.Release.Namespace) (printf "%s.%s.svc.%s" $hostName $envAll.Release.Namespace $envAll.Values.endpoints.cluster_domain_suffix) }}
+        - {{ $vHost }}
+{{- end }}
+{{- else }}
+{{- if hasKey $host $endpoint }}
+{{- $endpointHost := index $host $endpoint }}
+{{- if kindIs "map" $endpointHost }}
+{{- if hasKey $endpointHost "tls" }}
+{{- if and ( not ( empty $endpointHost.tls.key ) ) ( not ( empty $endpointHost.tls.crt ) ) }}
+{{- $secretName := index $envAll.Values.secrets "tls" ( $backendServiceType | replace "-" "_" ) $backendService $endpoint }}
+{{- $_ := required "You need to specify a secret in your values for the endpoint" $secretName }}
+  tls:
+    - secretName: {{ $secretName }}
+      hosts:
+{{- range $key1, $vHost := tuple $hostName (printf "%s.%s" $hostName $envAll.Release.Namespace) (printf "%s.%s.svc.%s" $hostName $envAll.Release.Namespace $envAll.Values.endpoints.cluster_domain_suffix) }}
+        - {{ $vHost }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+  rules:
+{{- range $key1, $vHost := tuple $hostName (printf "%s.%s" $hostName $envAll.Release.Namespace) (printf "%s.%s.svc.%s" $hostName $envAll.Release.Namespace $envAll.Values.endpoints.cluster_domain_suffix) }}
+{{- $hostRules := dict "vHost" $vHost "backendName" $backendName "backendPort" $backendPort }}
+{{ $hostRules | include "helm-toolkit.manifests.ingress._host_rules" | indent 4 }}
+{{- end }}
+{{- if not ( hasSuffix ( printf ".%s.svc.%s" $envAll.Release.Namespace $envAll.Values.endpoints.cluster_domain_suffix) $hostNameFull) }}
+{{- range $key2, $ingressController := tuple "namespace" "cluster" }}
+{{- $vHosts := list $hostNameFull }}
+---
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: {{ printf "%s-%s-%s" $ingressName $ingressController "fqdn" }}
+  annotations:
+    kubernetes.io/ingress.class: {{ index $envAll.Values.network $backendService "ingress" "classes" $ingressController | quote }}
+{{ toYaml (index $envAll.Values.network $backendService "ingress" "annotations") | indent 4 }}
+spec:
+{{- $host := index $envAll.Values.endpoints ( $backendServiceType | replace "-" "_" ) "host_fqdn_override" }}
+{{- if hasKey $host $endpoint }}
+{{- $endpointHost := index $host $endpoint }}
+{{- if kindIs "map" $endpointHost }}
+{{- if hasKey $endpointHost "tls" }}
+{{- range $v := without (index $endpointHost.tls "dnsNames" | default list) $hostNameFull }}
+{{- $vHosts = append $vHosts $v }}
+{{- end }}
+{{- if and ( not ( empty $endpointHost.tls.key ) ) ( not ( empty $endpointHost.tls.crt ) ) }}
+{{- $secretName := index $envAll.Values.secrets "tls" ( $backendServiceType | replace "-" "_" ) $backendService $endpoint }}
+{{- $_ := required "You need to specify a secret in your values for the endpoint" $secretName }}
+  tls:
+    - secretName: {{ $secretName }}
+      hosts:
+{{- range $vHost := $vHosts }}
+        - {{ $vHost }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+  rules:
+{{- range $vHost := $vHosts }}
+{{- $hostNameFullRules := dict "vHost" $vHost "backendName" $backendName "backendPort" $backendPort }}
+{{ $hostNameFullRules | include "helm-toolkit.manifests.ingress._host_rules" | indent 4 }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/manifests/_job-bootstrap.tpl b/charts/nova/charts/helm-toolkit/templates/manifests/_job-bootstrap.tpl
new file mode 100644
index 0000000..5d98c8b
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/manifests/_job-bootstrap.tpl
@@ -0,0 +1,141 @@
+{{/*
+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 function creates a manifest for db creation and user management.
+# It can be used in charts dict created similar to the following:
+# {- $bootstrapJob := dict "envAll" . "serviceName" "senlin" -}
+# { $bootstrapJob | include "helm-toolkit.manifests.job_bootstrap" }
+
+{{- define "helm-toolkit.manifests.job_bootstrap" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $serviceName := index . "serviceName" -}}
+{{- $jobAnnotations := index . "jobAnnotations" -}}
+{{- $jobLabels := index . "jobLabels" -}}
+{{- $nodeSelector := index . "nodeSelector" | default ( dict $envAll.Values.labels.job.node_selector_key $envAll.Values.labels.job.node_selector_value ) -}}
+{{- $tolerationsEnabled := index . "tolerationsEnabled" | default false -}}
+{{- $podVolMounts := index . "podVolMounts" | default false -}}
+{{- $podVols := index . "podVols" | default false -}}
+{{- $configMapBin := index . "configMapBin" | default (printf "%s-%s" $serviceName "bin" ) -}}
+{{- $configMapEtc := index . "configMapEtc" | default (printf "%s-%s" $serviceName "etc" ) -}}
+{{- $configFile := index . "configFile" | default (printf "/etc/%s/%s.conf" $serviceName $serviceName ) -}}
+{{- $logConfigFile := index . "logConfigFile" | default (printf "/etc/%s/logging.conf" $serviceName ) -}}
+{{- $tlsSecret := index . "tlsSecret" | default "" -}}
+{{- $keystoneUser := index . "keystoneUser" | default $serviceName -}}
+{{- $openrc := index . "openrc" | default "true" -}}
+{{- $secretBin := index . "secretBin" -}}
+{{- $backoffLimit := index . "backoffLimit" | default "1000" -}}
+{{- $activeDeadlineSeconds := index . "activeDeadlineSeconds" -}}
+{{- $serviceNamePretty := $serviceName | replace "_" "-" -}}
+
+{{- $serviceAccountName := printf "%s-%s" $serviceNamePretty "bootstrap" }}
+{{ tuple $envAll "bootstrap" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: {{ printf "%s-%s" $serviceNamePretty "bootstrap" | quote }}
+  labels:
+{{ tuple $envAll $serviceName "bootstrap" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 4 }}
+{{- end }}
+  annotations:
+{{- if $jobAnnotations }}
+{{ toYaml $jobAnnotations | indent 4 }}
+{{- end }}
+spec:
+  backoffLimit: {{ $backoffLimit }}
+{{- if $activeDeadlineSeconds }}
+  activeDeadlineSeconds: {{ $activeDeadlineSeconds }}
+{{- end }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll $serviceName "bootstrap" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 8 }}
+{{- end }}
+      annotations:
+{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName }}
+      restartPolicy: OnFailure
+      {{ tuple $envAll "bootstrap" | include "helm-toolkit.snippets.kubernetes_image_pull_secrets" | indent 6 }}
+      nodeSelector:
+{{ toYaml $nodeSelector | indent 8 }}
+{{- if $tolerationsEnabled }}
+{{ tuple $envAll $serviceName | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }}
+{{- end}}
+      initContainers:
+{{ tuple $envAll "bootstrap" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container"  | indent 8 }}
+      containers:
+        - name: bootstrap
+          image: {{ $envAll.Values.images.tags.bootstrap }}
+          imagePullPolicy: {{ $envAll.Values.images.pull_policy }}
+{{ tuple $envAll $envAll.Values.pod.resources.jobs.bootstrap | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{- if eq $openrc "true" }}
+          env:
+{{- with $env := dict "ksUserSecret" ( index $envAll.Values.secrets.identity $keystoneUser ) "useCA" (ne $tlsSecret "") }}
+{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 12 }}
+{{- end }}
+{{- end }}
+          command:
+            - /bin/bash
+            - -c
+            - /tmp/bootstrap.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: bootstrap-sh
+              mountPath: /tmp/bootstrap.sh
+              subPath: bootstrap.sh
+              readOnly: true
+            - name: etc-service
+              mountPath: {{ dir $configFile | quote }}
+            - name: bootstrap-conf
+              mountPath: {{ $configFile | quote }}
+              subPath: {{ base $configFile | quote }}
+              readOnly: true
+            - name: bootstrap-conf
+              mountPath: {{ $logConfigFile | quote }}
+              subPath: {{ base $logConfigFile | quote }}
+              readOnly: true
+{{ dict "enabled" (ne $tlsSecret "") "name" $tlsSecret | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{- if $podVolMounts }}
+{{ $podVolMounts | toYaml | indent 12 }}
+{{- end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: bootstrap-sh
+{{- if $secretBin }}
+          secret:
+            secretName: {{ $secretBin | quote }}
+            defaultMode: 0555
+{{- else }}
+          configMap:
+            name: {{ $configMapBin | quote }}
+            defaultMode: 0555
+{{- end }}
+        - name: etc-service
+          emptyDir: {}
+        - name: bootstrap-conf
+          secret:
+            secretName: {{ $configMapEtc | quote }}
+            defaultMode: 0444
+{{- dict "enabled" (ne $tlsSecret "") "name" $tlsSecret | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- if $podVols }}
+{{ $podVols | toYaml | indent 8 }}
+{{- end }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/manifests/_job-db-drop-mysql.tpl b/charts/nova/charts/helm-toolkit/templates/manifests/_job-db-drop-mysql.tpl
new file mode 100644
index 0000000..62ed119
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/manifests/_job-db-drop-mysql.tpl
@@ -0,0 +1,170 @@
+{{/*
+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 function creates a manifest for db creation and user management.
+# It can be used in charts dict created similar to the following:
+# {- $dbToDropJob := dict "envAll" . "serviceName" "senlin" -}
+# { $dbToDropJob | include "helm-toolkit.manifests.job_db_drop_mysql" }
+#
+# If the service does not use oslo then the db can be managed with:
+# {- $dbToDrop := dict "inputType" "secret" "adminSecret" .Values.secrets.oslo_db.admin "userSecret" .Values.secrets.oslo_db.horizon -}
+# {- $dbToDropJob := dict "envAll" . "serviceName" "horizon" "dbToDrop" $dbToDrop -}
+# { $dbToDropJob | include "helm-toolkit.manifests.job_db_drop_mysql" }
+
+{{- define "helm-toolkit.manifests.job_db_drop_mysql" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $serviceName := index . "serviceName" -}}
+{{- $jobAnnotations := index . "jobAnnotations" -}}
+{{- $jobLabels := index . "jobLabels" -}}
+{{- $nodeSelector := index . "nodeSelector" | default ( dict $envAll.Values.labels.job.node_selector_key $envAll.Values.labels.job.node_selector_value ) -}}
+{{- $tolerationsEnabled := index . "tolerationsEnabled" | default false -}}
+{{- $configMapBin := index . "configMapBin" | default (printf "%s-%s" $serviceName "bin" ) -}}
+{{- $configMapEtc := index . "configMapEtc" | default (printf "%s-%s" $serviceName "etc" ) -}}
+{{- $dbToDrop := index . "dbToDrop" | default ( dict "adminSecret" $envAll.Values.secrets.oslo_db.admin "configFile" (printf "/etc/%s/%s.conf" $serviceName $serviceName ) "logConfigFile" (printf "/etc/%s/logging.conf" $serviceName ) "configDbSection" "database" "configDbKey" "connection" ) -}}
+{{- $dbsToDrop := default (list $dbToDrop) (index . "dbsToDrop") }}
+{{- $secretBin := index . "secretBin" -}}
+{{- $backoffLimit := index . "backoffLimit" | default "1000" -}}
+{{- $activeDeadlineSeconds := index . "activeDeadlineSeconds" -}}
+{{- $serviceNamePretty := $serviceName | replace "_" "-" -}}
+{{- $dbAdminTlsSecret := index . "dbAdminTlsSecret" | default "" -}}
+
+{{- $serviceAccountName := printf "%s-%s" $serviceNamePretty "db-drop" }}
+{{ tuple $envAll "db_drop" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: {{ printf "%s-%s" $serviceNamePretty "db-drop" | quote }}
+  labels:
+{{ tuple $envAll $serviceName "db-drop" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 4 }}
+{{- end }}
+  annotations:
+    "helm.sh/hook": pre-delete
+    "helm.sh/hook-delete-policy": hook-succeeded
+{{- if $jobAnnotations }}
+{{ toYaml $jobAnnotations | indent 4 }}
+{{- end }}
+spec:
+  backoffLimit: {{ $backoffLimit }}
+{{- if $activeDeadlineSeconds }}
+  activeDeadlineSeconds: {{ $activeDeadlineSeconds }}
+{{- end }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll $serviceName "db-drop" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 8 }}
+{{- end }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName }}
+      restartPolicy: OnFailure
+      {{ tuple $envAll "db_drop" | include "helm-toolkit.snippets.kubernetes_image_pull_secrets" | indent 6 }}
+      nodeSelector:
+{{ toYaml $nodeSelector | indent 8 }}
+{{- if $tolerationsEnabled }}
+{{ tuple $envAll $serviceName | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }}
+{{- end}}
+      initContainers:
+{{ tuple $envAll "db_drop" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+      containers:
+{{- range $key1, $dbToDrop := $dbsToDrop }}
+{{ $dbToDropType := default "oslo" $dbToDrop.inputType }}
+        - name: {{ printf "%s-%s-%d" $serviceNamePretty "db-drop" $key1 | quote }}
+          image: {{ $envAll.Values.images.tags.db_drop }}
+          imagePullPolicy: {{ $envAll.Values.images.pull_policy }}
+{{ tuple $envAll $envAll.Values.pod.resources.jobs.db_drop | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+          env:
+            - name: ROOT_DB_CONNECTION
+              valueFrom:
+                secretKeyRef:
+                  name: {{ $dbToDrop.adminSecret | quote }}
+                  key: DB_CONNECTION
+{{- if eq $dbToDropType "oslo" }}
+            - name: OPENSTACK_CONFIG_FILE
+              value: {{ $dbToDrop.configFile | quote }}
+            - name: OPENSTACK_CONFIG_DB_SECTION
+              value: {{ $dbToDrop.configDbSection | quote }}
+            - name: OPENSTACK_CONFIG_DB_KEY
+              value: {{ $dbToDrop.configDbKey | quote }}
+{{- end }}
+{{- if $envAll.Values.manifests.certificates }}
+            - name: MARIADB_X509
+              value: "REQUIRE X509"
+{{- end }}
+{{- if eq $dbToDropType "secret" }}
+            - name: DB_CONNECTION
+              valueFrom:
+                secretKeyRef:
+                  name: {{ $dbToDrop.userSecret | quote }}
+                  key: DB_CONNECTION
+{{- end }}
+          command:
+            - /tmp/db-drop.py
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: db-drop-sh
+              mountPath: /tmp/db-drop.py
+              subPath: db-drop.py
+              readOnly: true
+
+{{- if eq $dbToDropType "oslo" }}
+            - name: etc-service
+              mountPath: {{ dir $dbToDrop.configFile | quote }}
+            - name: db-drop-conf
+              mountPath: {{ $dbToDrop.configFile | quote }}
+              subPath: {{ base $dbToDrop.configFile | quote }}
+              readOnly: true
+            - name: db-drop-conf
+              mountPath: {{ $dbToDrop.logConfigFile | quote }}
+              subPath: {{ base $dbToDrop.logConfigFile | quote }}
+              readOnly: true
+{{- end }}
+{{- if $envAll.Values.manifests.certificates }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $dbAdminTlsSecret "path" "/etc/mysql/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{- end }}
+{{- end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: db-drop-sh
+{{- if $secretBin }}
+          secret:
+            secretName: {{ $secretBin | quote }}
+            defaultMode: 0555
+{{- else }}
+          configMap:
+            name: {{ $configMapBin | quote }}
+            defaultMode: 0555
+{{- end }}
+{{- if $envAll.Values.manifests.certificates }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $dbAdminTlsSecret | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- end }}
+{{- $local := dict "configMapBinFirst" true -}}
+{{- range $key1, $dbToDrop := $dbsToDrop }}
+{{- $dbToDropType := default "oslo" $dbToDrop.inputType }}
+{{- if and (eq $dbToDropType "oslo") $local.configMapBinFirst }}
+{{- $_ := set $local "configMapBinFirst" false }}
+        - name: etc-service
+          emptyDir: {}
+        - name: db-drop-conf
+          secret:
+            secretName: {{ $configMapEtc | quote }}
+            defaultMode: 0444
+{{- end -}}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/manifests/_job-db-init-mysql.tpl b/charts/nova/charts/helm-toolkit/templates/manifests/_job-db-init-mysql.tpl
new file mode 100644
index 0000000..745e8da
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/manifests/_job-db-init-mysql.tpl
@@ -0,0 +1,169 @@
+{{/*
+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 function creates a manifest for db creation and user management.
+# It can be used in charts dict created similar to the following:
+# {- $dbToInitJob := dict "envAll" . "serviceName" "senlin" -}
+# { $dbToInitJob | include "helm-toolkit.manifests.job_db_init_mysql" }
+#
+# If the service does not use oslo then the db can be managed with:
+# {- $dbToInit := dict "inputType" "secret" "adminSecret" .Values.secrets.oslo_db.admin "userSecret" .Values.secrets.oslo_db.horizon -}
+# {- $dbToInitJob := dict "envAll" . "serviceName" "horizon" "dbToInit" $dbToInit -}
+# { $dbToInitJob | include "helm-toolkit.manifests.job_db_init_mysql" }
+
+{{- define "helm-toolkit.manifests.job_db_init_mysql" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $serviceName := index . "serviceName" -}}
+{{- $jobAnnotations := index . "jobAnnotations" -}}
+{{- $jobLabels := index . "jobLabels" -}}
+{{- $nodeSelector := index . "nodeSelector" | default ( dict $envAll.Values.labels.job.node_selector_key $envAll.Values.labels.job.node_selector_value ) -}}
+{{- $tolerationsEnabled := index . "tolerationsEnabled" | default false -}}
+{{- $configMapBin := index . "configMapBin" | default (printf "%s-%s" $serviceName "bin" ) -}}
+{{- $configMapEtc := index . "configMapEtc" | default (printf "%s-%s" $serviceName "etc" ) -}}
+{{- $dbToInit := index . "dbToInit" | default ( dict "adminSecret" $envAll.Values.secrets.oslo_db.admin "configFile" (printf "/etc/%s/%s.conf" $serviceName $serviceName ) "logConfigFile" (printf "/etc/%s/logging.conf" $serviceName ) "configDbSection" "database" "configDbKey" "connection" ) -}}
+{{- $dbsToInit := default (list $dbToInit) (index . "dbsToInit") }}
+{{- $secretBin := index . "secretBin" -}}
+{{- $backoffLimit := index . "backoffLimit" | default "1000" -}}
+{{- $activeDeadlineSeconds := index . "activeDeadlineSeconds" -}}
+{{- $serviceNamePretty := $serviceName | replace "_" "-" -}}
+{{- $dbAdminTlsSecret := index . "dbAdminTlsSecret" | default "" -}}
+
+{{- $serviceAccountName := printf "%s-%s" $serviceNamePretty "db-init" }}
+{{ tuple $envAll "db_init" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: {{ printf "%s-%s" $serviceNamePretty "db-init" | quote }}
+  labels:
+{{ tuple $envAll $serviceName "db-init" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 4 }}
+{{- end }}
+  annotations:
+{{- if $jobAnnotations }}
+{{ toYaml $jobAnnotations | indent 4 }}
+{{- end }}
+spec:
+  backoffLimit: {{ $backoffLimit }}
+{{- if $activeDeadlineSeconds }}
+  activeDeadlineSeconds: {{ $activeDeadlineSeconds }}
+{{- end }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll $serviceName "db-init" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 8 }}
+{{- end }}
+      annotations:
+{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName }}
+      restartPolicy: OnFailure
+      {{ tuple $envAll "db_init" | include "helm-toolkit.snippets.kubernetes_image_pull_secrets" | indent 6 }}
+      nodeSelector:
+{{ toYaml $nodeSelector | indent 8 }}
+{{- if $tolerationsEnabled }}
+{{ tuple $envAll $serviceName | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }}
+{{- end}}
+      initContainers:
+{{ tuple $envAll "db_init" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+      containers:
+{{- range $key1, $dbToInit := $dbsToInit }}
+{{ $dbToInitType := default "oslo" $dbToInit.inputType }}
+        - name: {{ printf "%s-%s-%d" $serviceNamePretty "db-init" $key1 | quote }}
+          image: {{ $envAll.Values.images.tags.db_init }}
+          imagePullPolicy: {{ $envAll.Values.images.pull_policy }}
+{{ tuple $envAll $envAll.Values.pod.resources.jobs.db_init | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+          env:
+            - name: ROOT_DB_CONNECTION
+              valueFrom:
+                secretKeyRef:
+                  name: {{ $dbToInit.adminSecret | quote }}
+                  key: DB_CONNECTION
+{{- if eq $dbToInitType "oslo" }}
+            - name: OPENSTACK_CONFIG_FILE
+              value: {{ $dbToInit.configFile | quote }}
+            - name: OPENSTACK_CONFIG_DB_SECTION
+              value: {{ $dbToInit.configDbSection | quote }}
+            - name: OPENSTACK_CONFIG_DB_KEY
+              value: {{ $dbToInit.configDbKey | quote }}
+{{- end }}
+{{- if eq $dbToInitType "secret" }}
+            - name: DB_CONNECTION
+              valueFrom:
+                secretKeyRef:
+                  name: {{ $dbToInit.userSecret | quote }}
+                  key: DB_CONNECTION
+{{- end }}
+{{- if $envAll.Values.manifests.certificates }}
+            - name: MARIADB_X509
+              value: "REQUIRE X509"
+{{- end }}
+          command:
+            - /tmp/db-init.py
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: db-init-sh
+              mountPath: /tmp/db-init.py
+              subPath: db-init.py
+              readOnly: true
+{{- if eq $dbToInitType "oslo" }}
+            - name: etc-service
+              mountPath: {{ dir $dbToInit.configFile | quote }}
+            - name: db-init-conf
+              mountPath: {{ $dbToInit.configFile | quote }}
+              subPath: {{ base $dbToInit.configFile | quote }}
+              readOnly: true
+            - name: db-init-conf
+              mountPath: {{ $dbToInit.logConfigFile | quote }}
+              subPath: {{ base $dbToInit.logConfigFile | quote }}
+              readOnly: true
+{{- end }}
+{{- if $envAll.Values.manifests.certificates }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $dbAdminTlsSecret "path" "/etc/mysql/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{- end }}
+{{- end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: db-init-sh
+{{- if $secretBin }}
+          secret:
+            secretName: {{ $secretBin | quote }}
+            defaultMode: 0555
+{{- else }}
+          configMap:
+            name: {{ $configMapBin | quote }}
+            defaultMode: 0555
+{{- end }}
+{{- if $envAll.Values.manifests.certificates }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $dbAdminTlsSecret | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- end }}
+{{- $local := dict "configMapBinFirst" true -}}
+{{- range $key1, $dbToInit := $dbsToInit }}
+{{- $dbToInitType := default "oslo" $dbToInit.inputType }}
+{{- if and (eq $dbToInitType "oslo") $local.configMapBinFirst }}
+{{- $_ := set $local "configMapBinFirst" false }}
+        - name: etc-service
+          emptyDir: {}
+        - name: db-init-conf
+          secret:
+            secretName: {{ $configMapEtc | quote }}
+            defaultMode: 0444
+{{- end -}}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/manifests/_job-db-sync.tpl b/charts/nova/charts/helm-toolkit/templates/manifests/_job-db-sync.tpl
new file mode 100644
index 0000000..24d2496
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/manifests/_job-db-sync.tpl
@@ -0,0 +1,137 @@
+{{/*
+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 function creates a manifest for db migration and management.
+# It can be used in charts dict created similar to the following:
+# {- $dbSyncJob := dict "envAll" . "serviceName" "senlin" -}
+# { $dbSyncJob | include "helm-toolkit.manifests.job_db_sync" }
+
+{{- define "helm-toolkit.manifests.job_db_sync" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $serviceName := index . "serviceName" -}}
+{{- $jobAnnotations := index . "jobAnnotations" -}}
+{{- $jobLabels := index . "jobLabels" -}}
+{{- $nodeSelector := index . "nodeSelector" | default ( dict $envAll.Values.labels.job.node_selector_key $envAll.Values.labels.job.node_selector_value ) -}}
+{{- $tolerationsEnabled := index . "tolerationsEnabled" | default false -}}
+{{- $configMapBin := index . "configMapBin" | default (printf "%s-%s" $serviceName "bin" ) -}}
+{{- $configMapEtc := index . "configMapEtc" | default (printf "%s-%s" $serviceName "etc" ) -}}
+{{- $podVolMounts := index . "podVolMounts" | default false -}}
+{{- $podVols := index . "podVols" | default false -}}
+{{- $podEnvVars := index . "podEnvVars" | default false -}}
+{{- $dbToSync := index . "dbToSync" | default ( dict "configFile" (printf "/etc/%s/%s.conf" $serviceName $serviceName ) "logConfigFile" (printf "/etc/%s/logging.conf" $serviceName ) "image" ( index $envAll.Values.images.tags ( printf "%s_db_sync" $serviceName )) ) -}}
+{{- $secretBin := index . "secretBin" -}}
+{{- $backoffLimit := index . "backoffLimit" | default "1000" -}}
+{{- $activeDeadlineSeconds := index . "activeDeadlineSeconds" -}}
+{{- $serviceNamePretty := $serviceName | replace "_" "-" -}}
+{{- $dbAdminTlsSecret := index . "dbAdminTlsSecret" | default "" -}}
+
+{{- $serviceAccountName := printf "%s-%s" $serviceNamePretty "db-sync" }}
+{{ tuple $envAll "db_sync" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: {{ printf "%s-%s" $serviceNamePretty "db-sync" | quote }}
+  labels:
+{{ tuple $envAll $serviceName "db-sync" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 4 }}
+{{- end }}
+  annotations:
+{{- if $jobAnnotations }}
+{{ toYaml $jobAnnotations | indent 4 }}
+{{- end }}
+spec:
+  backoffLimit: {{ $backoffLimit }}
+{{- if $activeDeadlineSeconds }}
+  activeDeadlineSeconds: {{ $activeDeadlineSeconds }}
+{{- end }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll $serviceName "db-sync" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 8 }}
+{{- end }}
+      annotations:
+{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName }}
+      restartPolicy: OnFailure
+      {{ tuple $envAll "db_sync" | include "helm-toolkit.snippets.kubernetes_image_pull_secrets" | indent 6 }}
+      nodeSelector:
+{{ toYaml $nodeSelector | indent 8 }}
+{{- if $tolerationsEnabled }}
+{{ tuple $envAll $serviceName | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }}
+{{- end}}
+      initContainers:
+{{ tuple $envAll "db_sync" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+      containers:
+        - name: {{ printf "%s-%s" $serviceNamePretty "db-sync" | quote }}
+          image: {{ $dbToSync.image | quote }}
+          imagePullPolicy: {{ $envAll.Values.images.pull_policy | quote }}
+{{ tuple $envAll $envAll.Values.pod.resources.jobs.db_sync | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{- if $podEnvVars }}
+          env:
+{{ $podEnvVars | toYaml | indent 12 }}
+{{- end }}
+          command:
+            - /bin/bash
+            - -c
+            - /tmp/db-sync.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: db-sync-sh
+              mountPath: /tmp/db-sync.sh
+              subPath: db-sync.sh
+              readOnly: true
+            - name: etc-service
+              mountPath: {{ dir $dbToSync.configFile | quote }}
+            - name: db-sync-conf
+              mountPath: {{ $dbToSync.configFile | quote }}
+              subPath: {{ base $dbToSync.configFile | quote }}
+              readOnly: true
+            - name: db-sync-conf
+              mountPath: {{ $dbToSync.logConfigFile | quote }}
+              subPath: {{ base $dbToSync.logConfigFile | quote }}
+              readOnly: true
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $dbAdminTlsSecret "path" "/etc/mysql/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{- if $podVolMounts }}
+{{ $podVolMounts | toYaml | indent 12 }}
+{{- end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: db-sync-sh
+{{- if $secretBin }}
+          secret:
+            secretName: {{ $secretBin | quote }}
+            defaultMode: 0555
+{{- else }}
+          configMap:
+            name: {{ $configMapBin | quote }}
+            defaultMode: 0555
+{{- end }}
+        - name: etc-service
+          emptyDir: {}
+        - name: db-sync-conf
+          secret:
+            secretName: {{ $configMapEtc | quote }}
+            defaultMode: 0444
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $dbAdminTlsSecret | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- if $podVols }}
+{{ $podVols | toYaml | indent 8 }}
+{{- end }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/manifests/_job-ks-endpoints.tpl b/charts/nova/charts/helm-toolkit/templates/manifests/_job-ks-endpoints.tpl
new file mode 100644
index 0000000..3a7df7f
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/manifests/_job-ks-endpoints.tpl
@@ -0,0 +1,130 @@
+{{/*
+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 function creates a manifest for keystone service management.
+# It can be used in charts dict created similar to the following:
+# {- $ksEndpointJob := dict "envAll" . "serviceName" "senlin" "serviceTypes" ( tuple "clustering" ) -}
+# { $ksEndpointJob | include "helm-toolkit.manifests.job_ks_endpoints" }
+
+{{- define "helm-toolkit.manifests.job_ks_endpoints" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $serviceName := index . "serviceName" -}}
+{{- $serviceTypes := index . "serviceTypes" -}}
+{{- $jobAnnotations := index . "jobAnnotations" -}}
+{{- $jobLabels := index . "jobLabels" -}}
+{{- $nodeSelector := index . "nodeSelector" | default ( dict $envAll.Values.labels.job.node_selector_key $envAll.Values.labels.job.node_selector_value ) -}}
+{{- $tolerationsEnabled := index . "tolerationsEnabled" | default false -}}
+{{- $configMapBin := index . "configMapBin" | default (printf "%s-%s" $serviceName "bin" ) -}}
+{{- $secretBin := index . "secretBin" -}}
+{{- $tlsSecret := index . "tlsSecret" | default "" -}}
+{{- $backoffLimit := index . "backoffLimit" | default "1000" -}}
+{{- $activeDeadlineSeconds := index . "activeDeadlineSeconds" -}}
+{{- $serviceNamePretty := $serviceName | replace "_" "-" -}}
+{{- $restartPolicy_ := "OnFailure" -}}
+{{- if hasKey $envAll.Values "jobs" -}}
+{{- if hasKey $envAll.Values.jobs "ks_endpoints" -}}
+{{- $restartPolicy_ = $envAll.Values.jobs.ks_endpoints.restartPolicy | default $restartPolicy_ }}
+{{- end }}
+{{- end }}
+{{- $restartPolicy := index . "restartPolicy" | default $restartPolicy_ -}}
+
+{{- $serviceAccountName := printf "%s-%s" $serviceNamePretty "ks-endpoints" }}
+{{ tuple $envAll "ks_endpoints" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: {{ printf "%s-%s" $serviceNamePretty "ks-endpoints" | quote }}
+  labels:
+{{ tuple $envAll $serviceName "ks-endpoints" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 4 }}
+{{- end }}
+  annotations:
+{{- if $jobAnnotations }}
+{{ toYaml $jobAnnotations | indent 4 }}
+{{- end }}
+spec:
+  backoffLimit: {{ $backoffLimit }}
+{{- if $activeDeadlineSeconds }}
+  activeDeadlineSeconds: {{ $activeDeadlineSeconds }}
+{{- end }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll $serviceName "ks-endpoints" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 8 }}
+{{- end }}
+      annotations:
+{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName }}
+      restartPolicy: {{ $restartPolicy }}
+      {{ tuple $envAll "ks_endpoints" | include "helm-toolkit.snippets.kubernetes_image_pull_secrets" | indent 6 }}
+      nodeSelector:
+{{ toYaml $nodeSelector | indent 8 }}
+{{- if $tolerationsEnabled }}
+{{ tuple $envAll $serviceName | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }}
+{{- end}}
+      initContainers:
+{{ tuple $envAll "ks_endpoints" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+      containers:
+{{- range $key1, $osServiceType := $serviceTypes }}
+{{- range $key2, $osServiceEndPoint := tuple "admin" "internal" "public" }}
+        - name: {{ printf "%s-%s-%s" $osServiceType "ks-endpoints" $osServiceEndPoint | quote }}
+          image: {{ $envAll.Values.images.tags.ks_endpoints }}
+          imagePullPolicy: {{ $envAll.Values.images.pull_policy }}
+{{ tuple $envAll $envAll.Values.pod.resources.jobs.ks_endpoints | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+          command:
+            - /bin/bash
+            - -c
+            - /tmp/ks-endpoints.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: ks-endpoints-sh
+              mountPath: /tmp/ks-endpoints.sh
+              subPath: ks-endpoints.sh
+              readOnly: true
+{{ dict "enabled" true "name" $tlsSecret "ca" true | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+          env:
+{{- with $env := dict "ksUserSecret" $envAll.Values.secrets.identity.admin "useCA" (ne $tlsSecret "") }}
+{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 12 }}
+{{- end }}
+            - name: OS_SVC_ENDPOINT
+              value: {{ $osServiceEndPoint | quote }}
+            - name: OS_SERVICE_NAME
+              value: {{ tuple $osServiceType $envAll | include "helm-toolkit.endpoints.keystone_endpoint_name_lookup" }}
+            - name: OS_SERVICE_TYPE
+              value: {{ $osServiceType | quote }}
+            - name: OS_SERVICE_ENDPOINT
+              value: {{ tuple $osServiceType $osServiceEndPoint "api" $envAll | include "helm-toolkit.endpoints.keystone_endpoint_uri_lookup" | quote }}
+{{- end }}
+{{- end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: ks-endpoints-sh
+{{- if $secretBin }}
+          secret:
+            secretName: {{ $secretBin | quote }}
+            defaultMode: 0555
+{{- else }}
+          configMap:
+            name: {{ $configMapBin | quote }}
+            defaultMode: 0555
+{{- end }}
+{{- dict "enabled" true "name" $tlsSecret | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/manifests/_job-ks-service.tpl b/charts/nova/charts/helm-toolkit/templates/manifests/_job-ks-service.tpl
new file mode 100644
index 0000000..a109e3c
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/manifests/_job-ks-service.tpl
@@ -0,0 +1,124 @@
+{{/*
+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 function creates a manifest for keystone service management.
+# It can be used in charts dict created similar to the following:
+# {- $ksServiceJob := dict "envAll" . "serviceName" "senlin" "serviceTypes" ( tuple "clustering" ) -}
+# { $ksServiceJob | include "helm-toolkit.manifests.job_ks_service" }
+
+{{- define "helm-toolkit.manifests.job_ks_service" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $serviceName := index . "serviceName" -}}
+{{- $serviceTypes := index . "serviceTypes" -}}
+{{- $jobAnnotations := index . "jobAnnotations" -}}
+{{- $jobLabels := index . "jobLabels" -}}
+{{- $nodeSelector := index . "nodeSelector" | default ( dict $envAll.Values.labels.job.node_selector_key $envAll.Values.labels.job.node_selector_value ) -}}
+{{- $tolerationsEnabled := index . "tolerationsEnabled" | default false -}}
+{{- $configMapBin := index . "configMapBin" | default (printf "%s-%s" $serviceName "bin" ) -}}
+{{- $secretBin := index . "secretBin" -}}
+{{- $tlsSecret := index . "tlsSecret" | default "" -}}
+{{- $backoffLimit := index . "backoffLimit" | default "1000" -}}
+{{- $activeDeadlineSeconds := index . "activeDeadlineSeconds" -}}
+{{- $serviceNamePretty := $serviceName | replace "_" "-" -}}
+{{- $restartPolicy_ := "OnFailure" -}}
+{{- if hasKey $envAll.Values "jobs" -}}
+{{- if hasKey $envAll.Values.jobs "ks_service" -}}
+{{- $restartPolicy_ = $envAll.Values.jobs.ks_service.restartPolicy | default $restartPolicy_ }}
+{{- end }}
+{{- end }}
+{{- $restartPolicy := index . "restartPolicy" | default $restartPolicy_ -}}
+
+{{- $serviceAccountName := printf "%s-%s" $serviceNamePretty "ks-service" }}
+{{ tuple $envAll "ks_service" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: {{ printf "%s-%s" $serviceNamePretty "ks-service" | quote }}
+  labels:
+{{ tuple $envAll $serviceName "ks-service" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 4 }}
+{{- end }}
+  annotations:
+{{- if $jobAnnotations }}
+{{ toYaml $jobAnnotations | indent 4 }}
+{{- end }}
+spec:
+  backoffLimit: {{ $backoffLimit }}
+{{- if $activeDeadlineSeconds }}
+  activeDeadlineSeconds: {{ $activeDeadlineSeconds }}
+{{- end }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll $serviceName "ks-service" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 8 }}
+{{- end }}
+      annotations:
+{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName }}
+      restartPolicy: {{ $restartPolicy }}
+      {{ tuple $envAll "ks_service" | include "helm-toolkit.snippets.kubernetes_image_pull_secrets" | indent 6 }}
+      nodeSelector:
+{{ toYaml $nodeSelector | indent 8 }}
+{{- if $tolerationsEnabled }}
+{{ tuple $envAll $serviceName | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }}
+{{- end}}
+      initContainers:
+{{ tuple $envAll "ks_service" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+      containers:
+{{- range $key1, $osServiceType := $serviceTypes }}
+        - name: {{ printf "%s-%s" $osServiceType "ks-service-registration" | quote }}
+          image: {{ $envAll.Values.images.tags.ks_service }}
+          imagePullPolicy: {{ $envAll.Values.images.pull_policy }}
+{{ tuple $envAll $envAll.Values.pod.resources.jobs.ks_service | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+          command:
+            - /bin/bash
+            - -c
+            - /tmp/ks-service.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: ks-service-sh
+              mountPath: /tmp/ks-service.sh
+              subPath: ks-service.sh
+              readOnly: true
+{{ dict "enabled" true "name" $tlsSecret "ca" true | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+          env:
+{{- with $env := dict "ksUserSecret" $envAll.Values.secrets.identity.admin "useCA" (ne $tlsSecret "") }}
+{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 12 }}
+{{- end }}
+            - name: OS_SERVICE_NAME
+              value: {{ tuple $osServiceType $envAll | include "helm-toolkit.endpoints.keystone_endpoint_name_lookup" }}
+            - name: OS_SERVICE_TYPE
+              value: {{ $osServiceType | quote }}
+{{- end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: ks-service-sh
+{{- if $secretBin }}
+          secret:
+            secretName: {{ $secretBin | quote }}
+            defaultMode: 0555
+{{- else }}
+          configMap:
+            name: {{ $configMapBin | quote }}
+            defaultMode: 0555
+{{- end }}
+{{- dict "enabled" true "name" $tlsSecret | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/manifests/_job-ks-user.yaml.tpl b/charts/nova/charts/helm-toolkit/templates/manifests/_job-ks-user.yaml.tpl
new file mode 100644
index 0000000..905eb71
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/manifests/_job-ks-user.yaml.tpl
@@ -0,0 +1,154 @@
+{{/*
+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 function creates a manifest for keystone user management.
+# It can be used in charts dict created similar to the following:
+# {- $ksUserJob := dict "envAll" . "serviceName" "senlin" }
+# { $ksUserJob | include "helm-toolkit.manifests.job_ks_user" }
+
+{{/*
+  # To enable PodSecuritycontext (PodSecurityContext/v1) define the below in values.yaml:
+  # example:
+  #  values: |
+  #    pod:
+  #      security_context:
+  #        ks_user:
+  #          pod:
+  #            runAsUser: 65534
+  # To enable Container SecurityContext(SecurityContext/v1) for ks-user container define the values:
+  # example:
+  #   values: |
+  #     pod:
+  #       security_context:
+  #         ks_user:
+  #           container:
+  #             ks-user:
+  #               runAsUser: 65534
+  #               readOnlyRootFilesystem: true
+  #               allowPrivilegeEscalation: false
+*/}}
+
+{{- define "helm-toolkit.manifests.job_ks_user" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $serviceName := index . "serviceName" -}}
+{{- $jobAnnotations := index . "jobAnnotations" -}}
+{{- $jobLabels := index . "jobLabels" -}}
+{{- $nodeSelector := index . "nodeSelector" | default ( dict $envAll.Values.labels.job.node_selector_key $envAll.Values.labels.job.node_selector_value ) -}}
+{{- $tolerationsEnabled := index . "tolerationsEnabled" | default false -}}
+{{- $configMapBin := index . "configMapBin" | default (printf "%s-%s" $serviceName "bin" ) -}}
+{{- $serviceUser := index . "serviceUser" | default $serviceName -}}
+{{- $secretBin := index . "secretBin" -}}
+{{- $tlsSecret := index . "tlsSecret" | default "" -}}
+{{- $backoffLimit := index . "backoffLimit" | default "1000" -}}
+{{- $activeDeadlineSeconds := index . "activeDeadlineSeconds" -}}
+{{- $serviceUserPretty := $serviceUser | replace "_" "-" -}}
+{{- $restartPolicy_ := "OnFailure" -}}
+{{- if hasKey $envAll.Values "jobs" -}}
+{{- if hasKey $envAll.Values.jobs "ks_user" -}}
+{{- $restartPolicy_ = $envAll.Values.jobs.ks_user.restartPolicy | default $restartPolicy_ }}
+{{- end }}
+{{- end }}
+{{- $restartPolicy := index . "restartPolicy" | default $restartPolicy_ -}}
+
+{{- $serviceAccountName := printf "%s-%s" $serviceUserPretty "ks-user" }}
+{{ tuple $envAll "ks_user" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: {{ printf "%s-%s" $serviceUserPretty "ks-user" | quote }}
+  labels:
+{{ tuple $envAll $serviceName "ks-user" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 4 }}
+{{- end }}
+  annotations:
+{{- if $jobAnnotations }}
+{{ toYaml $jobAnnotations | indent 4 }}
+{{- end }}
+spec:
+  backoffLimit: {{ $backoffLimit }}
+{{- if $activeDeadlineSeconds }}
+  activeDeadlineSeconds: {{ $activeDeadlineSeconds }}
+{{- end }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll $serviceName "ks-user" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 8 }}
+{{- end }}
+      annotations:
+{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName | quote }}
+{{ dict "envAll" $envAll "application" "ks_user" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
+      restartPolicy: {{ $restartPolicy }}
+      {{ tuple $envAll "ks_user" | include "helm-toolkit.snippets.kubernetes_image_pull_secrets" | indent 6 }}
+      nodeSelector:
+{{ toYaml $nodeSelector | indent 8 }}
+{{- if $tolerationsEnabled }}
+{{ tuple $envAll $serviceName | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }}
+{{- end}}
+      initContainers:
+{{ tuple $envAll "ks_user" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+      containers:
+        - name: ks-user
+          image: {{ $envAll.Values.images.tags.ks_user }}
+          imagePullPolicy: {{ $envAll.Values.images.pull_policy }}
+{{ tuple $envAll $envAll.Values.pod.resources.jobs.ks_user | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "ks_user" "container" "ks_user" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          command:
+            - /bin/bash
+            - -c
+            - /tmp/ks-user.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: ks-user-sh
+              mountPath: /tmp/ks-user.sh
+              subPath: ks-user.sh
+              readOnly: true
+{{ dict "enabled" true "name" $tlsSecret "ca" true | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+          env:
+{{- with $env := dict "ksUserSecret" $envAll.Values.secrets.identity.admin "useCA" (ne $tlsSecret "") }}
+{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 12 }}
+{{- end }}
+            - name: SERVICE_OS_SERVICE_NAME
+              value: {{ $serviceName | quote }}
+{{- with $env := dict "ksUserSecret" (index $envAll.Values.secrets.identity $serviceUser ) }}
+{{- include "helm-toolkit.snippets.keystone_user_create_env_vars" $env | indent 12 }}
+{{- end }}
+            - name: SERVICE_OS_ROLES
+            {{- $serviceOsRoles := index $envAll.Values.endpoints.identity.auth $serviceUser "role" }}
+            {{- if kindIs "slice" $serviceOsRoles }}
+              value: {{ include "helm-toolkit.utils.joinListWithComma" $serviceOsRoles | quote }}
+            {{- else }}
+              value: {{ $serviceOsRoles | quote }}
+            {{- end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: ks-user-sh
+{{- if $secretBin }}
+          secret:
+            secretName: {{ $secretBin | quote }}
+            defaultMode: 0555
+{{- else }}
+          configMap:
+            name: {{ $configMapBin | quote }}
+            defaultMode: 0555
+{{- end }}
+{{- dict "enabled" true "name" $tlsSecret | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/manifests/_job-rabbit-init.yaml.tpl b/charts/nova/charts/helm-toolkit/templates/manifests/_job-rabbit-init.yaml.tpl
new file mode 100644
index 0000000..6982064
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/manifests/_job-rabbit-init.yaml.tpl
@@ -0,0 +1,129 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.manifests.job_rabbit_init" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $serviceName := index . "serviceName" -}}
+{{- $jobAnnotations := index . "jobAnnotations" -}}
+{{- $jobLabels := index . "jobLabels" -}}
+{{- $nodeSelector := index . "nodeSelector" | default ( dict $envAll.Values.labels.job.node_selector_key $envAll.Values.labels.job.node_selector_value ) -}}
+{{- $tolerationsEnabled := index . "tolerationsEnabled" | default false -}}
+{{- $configMapBin := index . "configMapBin" | default (printf "%s-%s" $serviceName "bin" ) -}}
+{{- $serviceUser := index . "serviceUser" | default $serviceName -}}
+{{- $secretBin := index . "secretBin" -}}
+{{- $backoffLimit := index . "backoffLimit" | default "1000" -}}
+{{- $activeDeadlineSeconds := index . "activeDeadlineSeconds" -}}
+{{- $serviceUserPretty := $serviceUser | replace "_" "-" -}}
+{{- $serviceNamePretty := $serviceName | replace "_" "-" -}}
+{{- $tlsPath := index . "tlsPath" | default "/etc/rabbitmq/certs" -}}
+{{- $tlsSecret := index . "tlsSecret" | default "" -}}
+
+{{- $serviceAccountName := printf "%s-%s" $serviceUserPretty "rabbit-init" }}
+{{ tuple $envAll "rabbit_init" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: {{ printf "%s-%s" $serviceUserPretty "rabbit-init" | quote }}
+  labels:
+{{ tuple $envAll $serviceName "rabbit-init" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 4 }}
+{{- end }}
+  annotations:
+{{- if $jobAnnotations }}
+{{ toYaml $jobAnnotations | indent 4 }}
+{{- end }}
+spec:
+  backoffLimit: {{ $backoffLimit }}
+{{- if $activeDeadlineSeconds }}
+  activeDeadlineSeconds: {{ $activeDeadlineSeconds }}
+{{- end }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll $serviceName "rabbit-init" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 8 }}
+{{- end }}
+      annotations:
+{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName | quote }}
+      restartPolicy: OnFailure
+      {{ tuple $envAll "rabbit_init" | include "helm-toolkit.snippets.kubernetes_image_pull_secrets" | indent 6 }}
+      nodeSelector:
+{{ toYaml $nodeSelector | indent 8 }}
+{{- if $tolerationsEnabled }}
+{{ tuple $envAll $serviceName | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }}
+{{- end}}
+      initContainers:
+{{ tuple $envAll "rabbit_init" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+      containers:
+        - name: rabbit-init
+          image: {{ $envAll.Values.images.tags.rabbit_init | quote }}
+          imagePullPolicy: {{ $envAll.Values.images.pull_policy | quote }}
+{{ tuple $envAll $envAll.Values.pod.resources.jobs.rabbit_init | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+          command:
+            - /bin/bash
+            - -c
+            - /tmp/rabbit-init.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: rabbit-init-sh
+              mountPath: /tmp/rabbit-init.sh
+              subPath: rabbit-init.sh
+              readOnly: true
+{{- if $envAll.Values.manifests.certificates }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $tlsSecret "path" $tlsPath | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{- end }}
+          env:
+          - name: RABBITMQ_ADMIN_CONNECTION
+            valueFrom:
+              secretKeyRef:
+                name: {{ $envAll.Values.secrets.oslo_messaging.admin }}
+                key: RABBITMQ_CONNECTION
+          - name: RABBITMQ_USER_CONNECTION
+            valueFrom:
+              secretKeyRef:
+                name: {{ index $envAll.Values.secrets.oslo_messaging $serviceName }}
+                key: RABBITMQ_CONNECTION
+{{- if $envAll.Values.conf.rabbitmq }}
+          - name: RABBITMQ_AUXILIARY_CONFIGURATION
+            value: {{ toJson $envAll.Values.conf.rabbitmq | quote }}
+{{- end }}
+{{- if and $envAll.Values.manifests.certificates (ne $tlsSecret "") }}
+          - name: RABBITMQ_X509
+            value: "REQUIRE X509"
+          - name: USER_CERT_PATH
+            value: {{ $tlsPath | quote }}
+{{- end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: rabbit-init-sh
+{{- if $secretBin }}
+          secret:
+            secretName: {{ $secretBin | quote }}
+            defaultMode: 0555
+{{- else }}
+          configMap:
+            name: {{ $configMapBin | quote }}
+            defaultMode: 0555
+{{- end }}
+{{- if $envAll.Values.manifests.certificates }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $tlsSecret | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- end }}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/manifests/_job-s3-bucket.yaml.tpl b/charts/nova/charts/helm-toolkit/templates/manifests/_job-s3-bucket.yaml.tpl
new file mode 100644
index 0000000..29cb993
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/manifests/_job-s3-bucket.yaml.tpl
@@ -0,0 +1,147 @@
+{{/*
+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 function creates a manifest for linking an s3 bucket to an s3 user.
+# It can be used in charts dict created similar to the following:
+# {- $s3BucketJob := dict "envAll" . "serviceName" "elasticsearch" }
+# { $s3BucketJob | include "helm-toolkit.manifests.job_s3_bucket" }
+
+{{- define "helm-toolkit.manifests.job_s3_bucket" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $serviceName := index . "serviceName" -}}
+{{- $jobAnnotations := index . "jobAnnotations" -}}
+{{- $jobLabels := index . "jobLabels" -}}
+{{- $nodeSelector := index . "nodeSelector" | default ( dict $envAll.Values.labels.job.node_selector_key $envAll.Values.labels.job.node_selector_value ) -}}
+{{- $tolerationsEnabled := index . "tolerationsEnabled" | default false -}}
+{{- $configMapBin := index . "configMapBin" | default (printf "%s-%s" $serviceName "bin" ) -}}
+{{- $configMapCeph := index . "configMapCeph" | default (printf "ceph-etc" ) -}}
+{{- $secretBin := index . "secretBin" -}}
+{{- $backoffLimit := index . "backoffLimit" | default "1000" -}}
+{{- $activeDeadlineSeconds := index . "activeDeadlineSeconds" -}}
+{{- $serviceNamePretty := $serviceName | replace "_" "-" -}}
+{{- $s3UserSecret := index $envAll.Values.secrets.rgw $serviceName -}}
+{{- $s3Bucket := index . "s3Bucket" | default $serviceName }}
+{{- $tlsCertificateSecret := index . "tlsCertificateSecret" -}}
+{{- $tlsCertificatePath := index . "tlsCertificatePath" -}}
+
+{{- $serviceAccountName := printf "%s-%s" $serviceNamePretty "s3-bucket" }}
+{{ tuple $envAll "s3_bucket" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: {{ printf "%s-%s" $serviceNamePretty "s3-bucket" | quote }}
+  labels:
+{{ tuple $envAll $serviceName "s3-bucket" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 4 }}
+{{- end }}
+  annotations:
+    {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
+{{- if $jobAnnotations }}
+{{ toYaml $jobAnnotations | indent 4 }}
+{{- end }}
+spec:
+  backoffLimit: {{ $backoffLimit }}
+{{- if $activeDeadlineSeconds }}
+  activeDeadlineSeconds: {{ $activeDeadlineSeconds }}
+{{- end }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll $serviceName "s3-bucket" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 8 }}
+{{- end }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName | quote }}
+      restartPolicy: OnFailure
+      {{ tuple $envAll "s3_bucket" | include "helm-toolkit.snippets.kubernetes_image_pull_secrets" | indent 6 }}
+      nodeSelector:
+{{ toYaml $nodeSelector | indent 8 }}
+{{- if $tolerationsEnabled }}
+{{ tuple $envAll $serviceName | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }}
+{{- end}}
+      initContainers:
+{{ tuple $envAll "s3_bucket" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+      containers:
+        - name: s3-bucket
+          image: {{ $envAll.Values.images.tags.s3_bucket }}
+          imagePullPolicy: {{ $envAll.Values.images.pull_policy }}
+{{ tuple $envAll $envAll.Values.pod.resources.jobs.s3_bucket | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+          command:
+            - /bin/bash
+            - -c
+            - /tmp/create-s3-bucket.sh
+          env:
+{{- with $env := dict "s3AdminSecret" $envAll.Values.secrets.rgw.admin }}
+{{- include "helm-toolkit.snippets.rgw_s3_admin_env_vars" $env | indent 12 }}
+{{- end }}
+{{- include "helm-toolkit.snippets.rgw_s3_user_env_vars" $envAll | indent 12 }}
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: s3-bucket-sh
+              mountPath: /tmp/create-s3-bucket.sh
+              subPath: create-s3-bucket.sh
+              readOnly: true
+            - name: etcceph
+              mountPath: /etc/ceph
+            - name: ceph-etc
+              mountPath: /etc/ceph/ceph.conf
+              subPath: ceph.conf
+              readOnly: true
+            {{- if empty $envAll.Values.conf.ceph.admin_keyring }}
+            - name: ceph-keyring
+              mountPath: /tmp/client-keyring
+              subPath: key
+              readOnly: true
+            {{ end }}
+{{- if and ($tlsCertificatePath) ($tlsCertificateSecret) }}
+            - name: {{ $tlsCertificateSecret }}
+              mountPath: {{ $tlsCertificatePath }}
+              subPath: ca.crt
+              readOnly: true
+{{- end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: s3-bucket-sh
+{{- if $secretBin }}
+          secret:
+            secretName: {{ $secretBin | quote }}
+            defaultMode: 0555
+{{- else }}
+          configMap:
+            name: {{ $configMapBin | quote }}
+            defaultMode: 0555
+{{- end }}
+        - name: etcceph
+          emptyDir: {}
+        - name: ceph-etc
+          configMap:
+            name: {{ $configMapCeph | quote }}
+            defaultMode: 0444
+        {{- if empty $envAll.Values.conf.ceph.admin_keyring }}
+        - name: ceph-keyring
+          secret:
+            secretName: pvc-ceph-client-key
+        {{ end }}
+{{- if and ($tlsCertificatePath) ($tlsCertificateSecret) }}
+        - name: {{ $tlsCertificateSecret }}
+          secret:
+            secretName: {{ $tlsCertificateSecret }}
+            defaultMode: 292
+{{- end }}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/manifests/_job-s3-user.yaml.tpl b/charts/nova/charts/helm-toolkit/templates/manifests/_job-s3-user.yaml.tpl
new file mode 100644
index 0000000..50d9af5
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/manifests/_job-s3-user.yaml.tpl
@@ -0,0 +1,159 @@
+{{/*
+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 function creates a manifest for s3 user management.
+# It can be used in charts dict created similar to the following:
+# {- $s3UserJob := dict "envAll" . "serviceName" "elasticsearch" }
+# { $s3UserJob | include "helm-toolkit.manifests.job_s3_user" }
+
+{{- define "helm-toolkit.manifests.job_s3_user" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $serviceName := index . "serviceName" -}}
+{{- $jobAnnotations := index . "jobAnnotations" -}}
+{{- $jobLabels := index . "jobLabels" -}}
+{{- $nodeSelector := index . "nodeSelector" | default ( dict $envAll.Values.labels.job.node_selector_key $envAll.Values.labels.job.node_selector_value ) -}}
+{{- $tolerationsEnabled := index . "tolerationsEnabled" | default false -}}
+{{- $configMapBin := index . "configMapBin" | default (printf "%s-%s" $serviceName "bin" ) -}}
+{{- $configMapCeph := index . "configMapCeph" | default (printf "ceph-etc" ) -}}
+{{- $secretBin := index . "secretBin" -}}
+{{- $backoffLimit := index . "backoffLimit" | default "1000" -}}
+{{- $activeDeadlineSeconds := index . "activeDeadlineSeconds" -}}
+{{- $serviceNamePretty := $serviceName | replace "_" "-" -}}
+{{- $s3UserSecret := index $envAll.Values.secrets.rgw $serviceName -}}
+
+{{- $serviceAccountName := printf "%s-%s" $serviceNamePretty "s3-user" }}
+{{ tuple $envAll "s3_user" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: {{ printf "%s-%s" $serviceNamePretty "s3-user" | quote }}
+  labels:
+{{ tuple $envAll $serviceName "s3-user" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 4 }}
+{{- end }}
+  annotations:
+    "helm.sh/hook-delete-policy": before-hook-creation
+    {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
+{{- if $jobAnnotations }}
+{{ toYaml $jobAnnotations | indent 4 }}
+{{- end }}
+spec:
+  backoffLimit: {{ $backoffLimit }}
+{{- if $activeDeadlineSeconds }}
+  activeDeadlineSeconds: {{ $activeDeadlineSeconds }}
+{{- end }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll $serviceName "s3-user" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 8 }}
+{{- end }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName | quote }}
+      restartPolicy: OnFailure
+      {{ tuple $envAll "s3_user" | include "helm-toolkit.snippets.kubernetes_image_pull_secrets" | indent 6 }}
+      nodeSelector:
+{{ toYaml $nodeSelector | indent 8 }}
+{{- if $tolerationsEnabled }}
+{{ tuple $envAll $serviceName | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }}
+{{- end}}
+      initContainers:
+{{ tuple $envAll "s3_user" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+        - name: ceph-keyring-placement
+          image: {{ $envAll.Values.images.tags.ceph_key_placement }}
+          imagePullPolicy: {{ $envAll.Values.images.pull_policy }}
+          command:
+            - /tmp/ceph-admin-keyring.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: etcceph
+              mountPath: /etc/ceph
+            - name: ceph-keyring-sh
+              mountPath: /tmp/ceph-admin-keyring.sh
+              subPath: ceph-admin-keyring.sh
+              readOnly: true
+            {{- if empty $envAll.Values.conf.ceph.admin_keyring }}
+            - name: ceph-keyring
+              mountPath: /tmp/client-keyring
+              subPath: key
+              readOnly: true
+            {{ end }}
+      containers:
+        - name: s3-user
+          image: {{ $envAll.Values.images.tags.s3_user }}
+          imagePullPolicy: {{ $envAll.Values.images.pull_policy }}
+{{ tuple $envAll $envAll.Values.pod.resources.jobs.s3_user | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+          command:
+            - /bin/bash
+            - -c
+            - /tmp/create-s3-user.sh
+          env:
+{{- with $env := dict "s3AdminSecret" $envAll.Values.secrets.rgw.admin }}
+{{- include "helm-toolkit.snippets.rgw_s3_admin_env_vars" $env | indent 12 }}
+{{- end }}
+{{- include "helm-toolkit.snippets.rgw_s3_user_env_vars" $envAll | indent 12 }}
+            - name: RGW_HOST
+              value: {{ tuple "ceph_object_store" "internal" "api" $envAll | include "helm-toolkit.endpoints.host_and_port_endpoint_uri_lookup" }}
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: create-s3-user-sh
+              mountPath: /tmp/create-s3-user.sh
+              subPath: create-s3-user.sh
+              readOnly: true
+            - name: etcceph
+              mountPath: /etc/ceph
+            - name: ceph-etc
+              mountPath: /etc/ceph/ceph.conf
+              subPath: ceph.conf
+              readOnly: true
+            {{- if empty $envAll.Values.conf.ceph.admin_keyring }}
+            - name: ceph-keyring
+              mountPath: /tmp/client-keyring
+              subPath: key
+              readOnly: true
+            {{ end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: create-s3-user-sh
+{{- if $secretBin }}
+          secret:
+            secretName: {{ $secretBin | quote }}
+            defaultMode: 0555
+{{- else }}
+          configMap:
+            name: {{ $configMapBin | quote }}
+            defaultMode: 0555
+{{- end }}
+        - name: ceph-keyring-sh
+          configMap:
+            name: {{ $configMapBin | quote }}
+            defaultMode: 0555
+        - name: etcceph
+          emptyDir: {}
+        - name: ceph-etc
+          configMap:
+            name: {{ $configMapCeph | quote }}
+            defaultMode: 0444
+        {{- if empty $envAll.Values.conf.ceph.admin_keyring }}
+        - name: ceph-keyring
+          secret:
+            secretName: pvc-ceph-client-key
+        {{ end }}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/manifests/_job_image_repo_sync.tpl b/charts/nova/charts/helm-toolkit/templates/manifests/_job_image_repo_sync.tpl
new file mode 100644
index 0000000..0906df4
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/manifests/_job_image_repo_sync.tpl
@@ -0,0 +1,119 @@
+{{/*
+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 function creates a manifest for the image repo sync jobs.
+# It can be used in charts dict created similar to the following:
+# {- $imageRepoSyncJob := dict "envAll" . "serviceName" "prometheus" -}
+# { $imageRepoSyncJob | include "helm-toolkit.manifests.job_image_repo_sync" }
+
+{{- define "helm-toolkit.manifests.job_image_repo_sync" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $serviceName := index . "serviceName" -}}
+{{- $jobAnnotations := index . "jobAnnotations" -}}
+{{- $jobLabels := index . "jobLabels" -}}
+{{- $nodeSelector := index . "nodeSelector" | default ( dict $envAll.Values.labels.job.node_selector_key $envAll.Values.labels.job.node_selector_value ) -}}
+{{- $tolerationsEnabled := index . "tolerationsEnabled" | default false -}}
+{{- $podVolMounts := index . "podVolMounts" | default false -}}
+{{- $podVols := index . "podVols" | default false -}}
+{{- $configMapBin := index . "configMapBin" | default (printf "%s-%s" $serviceName "bin" ) -}}
+{{- $secretBin := index . "secretBin" -}}
+{{- $backoffLimit := index . "backoffLimit" | default "1000" -}}
+{{- $activeDeadlineSeconds := index . "activeDeadlineSeconds" -}}
+{{- $serviceNamePretty := $serviceName | replace "_" "-" -}}
+
+{{- $serviceAccountName := printf "%s-%s" $serviceNamePretty "image-repo-sync" }}
+{{ tuple $envAll "image_repo_sync" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: {{ printf "%s-%s" $serviceNamePretty "image-repo-sync" | quote }}
+  labels:
+{{ tuple $envAll $serviceName "image-repo-sync" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 4 }}
+{{- end }}
+  annotations:
+    "helm.sh/hook-delete-policy": before-hook-creation
+{{- if $jobAnnotations }}
+{{ toYaml $jobAnnotations | indent 4 }}
+{{- end }}
+spec:
+  backoffLimit: {{ $backoffLimit }}
+{{- if $activeDeadlineSeconds }}
+  activeDeadlineSeconds: {{ $activeDeadlineSeconds }}
+{{- end }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll $serviceName "image-repo-sync" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+{{- if $jobLabels }}
+{{ toYaml $jobLabels | indent 8 }}
+{{- end }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName }}
+      restartPolicy: OnFailure
+      {{ tuple $envAll "image_repo_sync" | include "helm-toolkit.snippets.kubernetes_image_pull_secrets" | indent 6 }}
+      nodeSelector:
+{{ toYaml $nodeSelector | indent 8 }}
+{{- if $tolerationsEnabled }}
+{{ tuple $envAll $serviceName | include "helm-toolkit.snippets.kubernetes_tolerations" | indent 6 }}
+{{- end}}
+      initContainers:
+{{ tuple $envAll "image_repo_sync" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container"  | indent 8 }}
+      containers:
+        - name: image-repo-sync
+{{ tuple $envAll "image_repo_sync" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.jobs.image_repo_sync | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+          env:
+            - name: LOCAL_REPO
+              value: "{{ tuple "local_image_registry" "node" $envAll | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }}:{{ tuple "local_image_registry" "node" "registry" $envAll | include "helm-toolkit.endpoints.endpoint_port_lookup" }}"
+            - name: IMAGE_SYNC_LIST
+              value: "{{ include "helm-toolkit.utils.image_sync_list" $envAll }}"
+          command:
+            - /bin/bash
+            - -c
+            - /tmp/image-repo-sync.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: bootstrap-sh
+              mountPath: /tmp/image-repo-sync.sh
+              subPath: image-repo-sync.sh
+              readOnly: true
+            - name: docker-socket
+              mountPath: /var/run/docker.sock
+{{- if $podVolMounts }}
+{{ $podVolMounts | toYaml | indent 12 }}
+{{- end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: bootstrap-sh
+{{- if $secretBin }}
+          secret:
+            secretName: {{ $secretBin | quote }}
+            defaultMode: 0555
+{{- else }}
+          configMap:
+            name: {{ $configMapBin | quote }}
+            defaultMode: 0555
+{{- end }}
+        - name: docker-socket
+          hostPath:
+            path: /var/run/docker.sock
+{{- if $podVols }}
+{{ $podVols | toYaml | indent 8 }}
+{{- end }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/manifests/_network_policy.tpl b/charts/nova/charts/helm-toolkit/templates/manifests/_network_policy.tpl
new file mode 100644
index 0000000..405197a
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/manifests/_network_policy.tpl
@@ -0,0 +1,238 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Creates a network policy manifest for services.
+values: |
+  endpoints:
+    kube_dns:
+      namespace: kube-system
+      name: kubernetes-dns
+      hosts:
+        default: kube-dns
+      host_fqdn_override:
+        default: null
+      path:
+        default: null
+      scheme: http
+      port:
+        dns_tcp:
+          default: 53
+        dns:
+          default: 53
+          protocol: UDP
+  network_policy:
+    myLabel:
+      podSelector:
+        matchLabels:
+          component: api
+      ingress:
+      - from:
+        - podSelector:
+            matchLabels:
+              application: keystone
+        ports:
+        - protocol: TCP
+          port: 80
+      egress:
+      - to:
+        - namespaceSelector:
+            matchLabels:
+              name: default
+        - namespaceSelector:
+            matchLabels:
+              name: kube-public
+        ports:
+        - protocol: TCP
+          port: 53
+        - protocol: UDP
+          port: 53
+usage: |
+  {{ dict "envAll" . "name" "application" "label" "myLabel" | include "helm-toolkit.manifests.kubernetes_network_policy" }}
+  {{ dict "envAll" . "key" "myLabel" "labels" (dict "application" "myApp" "component" "myComp")}}
+return: |
+  ---
+  apiVersion: networking.k8s.io/v1
+  kind: NetworkPolicy
+  metadata:
+    name: RELEASE-NAME
+    namespace: NAMESPACE
+  spec:
+    policyTypes:
+      - Ingress
+      - Egress
+    podSelector:
+      matchLabels:
+        application: myLabel
+        component: api
+    ingress:
+    - from:
+      - podSelector:
+          matchLabels:
+            application: keystone
+      ports:
+      - protocol: TCP
+        port: 80
+    egress:
+      - to:
+        - podSelector:
+            matchLabels:
+              name: default
+        - namespaceSelector:
+            matchLabels:
+              name: kube-public
+        ports:
+        - protocol: TCP
+          port: 53
+        - protocol: UDP
+          port: 53
+  ---
+  apiVersion: networking.k8s.io/v1
+  kind: NetworkPolicy
+  metadata:
+    name: RELEASE-NAME
+    namespace: NAMESPACE
+  spec:
+    policyTypes:
+      - Ingress
+      - Egress
+    podSelector:
+      matchLabels:
+        application: myApp
+        component: myComp
+    ingress:
+    - from:
+      - podSelector:
+          matchLabels:
+            application: keystone
+      ports:
+      - protocol: TCP
+        port: 80
+    egress:
+      - to:
+        - podSelector:
+            matchLabels:
+              name: default
+        - namespaceSelector:
+            matchLabels:
+              name: kube-public
+        ports:
+        - protocol: TCP
+          port: 53
+        - protocol: UDP
+          port: 53
+*/}}
+
+{{- define "helm-toolkit.manifests.kubernetes_network_policy" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $name := index . "name" -}}
+{{- $labels := index . "labels" | default nil -}}
+{{- $label := index . "key" | default (index . "label") -}}
+---
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: {{ $label | replace "_" "-" }}-netpol
+  namespace: {{ $envAll.Release.Namespace }}
+spec:
+{{- if hasKey (index $envAll.Values "network_policy") $label }}
+  policyTypes:
+{{- $is_egress := false -}}
+{{- if hasKey (index $envAll.Values.network_policy $label) "policyTypes" -}}
+{{- if has "Egress" (index $envAll.Values.network_policy $label "policyTypes") -}}
+{{- $is_egress = true -}}
+{{- end -}}
+{{- end -}}
+{{- if or $is_egress (index $envAll.Values.network_policy $label "egress") }}
+    - Egress
+{{ end -}}
+{{- $is_ingress := false -}}
+{{- if hasKey (index $envAll.Values.network_policy $label) "policyTypes" -}}
+{{- if has "Ingress" (index $envAll.Values.network_policy $label "policyTypes") -}}
+{{- $is_ingress = true -}}
+{{- end -}}
+{{- end -}}
+{{- if or $is_ingress (index $envAll.Values.network_policy $label "ingress") }}
+    - Ingress
+{{ end -}}
+{{- end }}
+  podSelector:
+    matchLabels:
+{{- if empty $labels }}
+      {{ $name }}: {{ $label }}
+{{- else }}
+{{ range $k, $v := $labels }}
+      {{ $k }}: {{ $v }}
+{{- end }}
+{{- end }}
+{{- if hasKey (index $envAll.Values "network_policy") $label }}
+{{- if hasKey (index $envAll.Values.network_policy $label) "podSelector" }}
+{{- if index $envAll.Values.network_policy $label "podSelector" "matchLabels" }}
+{{ index $envAll.Values.network_policy $label "podSelector" "matchLabels" | toYaml | indent 6 }}
+{{ end }}
+{{ end }}
+{{ end }}
+{{- if hasKey (index $envAll.Values "network_policy") $label }}
+  egress:
+{{- range $key, $value := $envAll.Values.endpoints }}
+{{- if kindIs "map" $value }}
+{{- if or (hasKey $value "namespace") (hasKey $value "hosts") }}
+    - to:
+{{- if index $value "namespace" }}
+      - namespaceSelector:
+          matchLabels:
+            name: {{ index $value "namespace" }}
+{{- else if index $value "hosts" }}
+{{- $defaultValue := index $value "hosts" "internal" }}
+{{- if hasKey (index $value "hosts") "internal" }}
+{{- $a := split "-" $defaultValue }}
+      - podSelector:
+          matchLabels:
+            application: {{ printf "%s" (index $a._0) | default $defaultValue }}
+{{- else }}
+{{- $defaultValue := index $value "hosts" "default" }}
+{{- $a := split "-" $defaultValue }}
+      - podSelector:
+          matchLabels:
+            application: {{ printf "%s" (index $a._0) | default $defaultValue }}
+{{- end }}
+{{- end }}
+{{- if index $value "port" }}
+      ports:
+{{- range $k, $v := index $value "port" }}
+{{- if $k }}
+{{- range $pk, $pv := $v }}
+{{- if and $pv (ne $pk "protocol") }}
+      - port: {{ $pv }}
+        protocol: {{ $v.protocol | default "TCP" }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- if index $envAll.Values.network_policy $label "egress" }}
+{{ index $envAll.Values.network_policy $label "egress" | toYaml | indent 4 }}
+{{- end }}
+{{- end }}
+{{- if hasKey (index $envAll.Values "network_policy") $label }}
+{{- if index $envAll.Values.network_policy $label "ingress" }}
+  ingress:
+{{ index $envAll.Values.network_policy $label "ingress" | toYaml | indent 4 }}
+{{- end }}
+{{- end }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/manifests/_secret-tls.yaml.tpl b/charts/nova/charts/helm-toolkit/templates/manifests/_secret-tls.yaml.tpl
new file mode 100644
index 0000000..24a7045
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/manifests/_secret-tls.yaml.tpl
@@ -0,0 +1,108 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Creates a manifest for a services public tls secret
+examples:
+  - values: |
+      secrets:
+        tls:
+          key_manager:
+            api:
+              public: barbican-tls-public
+      endpoints:
+        key_manager:
+          host_fqdn_override:
+            public:
+              tls:
+                crt: |
+                  FOO-CRT
+                key: |
+                  FOO-KEY
+                ca: |
+                  FOO-CA_CRT
+  usage: |
+    {{- include "helm-toolkit.manifests.secret_ingress_tls" ( dict "envAll" . "backendServiceType" "key-manager" ) -}}
+  return: |
+    ---
+    apiVersion: v1
+    kind: Secret
+    metadata:
+      name: barbican-tls-public
+    type: kubernetes.io/tls
+    data:
+      tls.key: Rk9PLUtFWQo=
+      tls.crt: Rk9PLUNSVAoKRk9PLUNBX0NSVAo=
+
+  - values: |
+      secrets:
+        tls:
+          key_manager:
+            api:
+              public: barbican-tls-public
+      endpoints:
+        key_manager:
+          host_fqdn_override:
+            public:
+              tls:
+                crt: |
+                  FOO-CRT
+                  FOO-INTERMEDIATE_CRT
+                  FOO-CA_CRT
+                key: |
+                  FOO-KEY
+  usage: |
+    {{- include "helm-toolkit.manifests.secret_ingress_tls" ( dict "envAll" . "backendServiceType" "key-manager" ) -}}
+  return: |
+    ---
+    apiVersion: v1
+    kind: Secret
+    metadata:
+      name: barbican-tls-public
+    type: kubernetes.io/tls
+    data:
+      tls.key: Rk9PLUtFWQo=
+      tls.crt: Rk9PLUNSVApGT08tSU5URVJNRURJQVRFX0NSVApGT08tQ0FfQ1JUCg==
+*/}}
+
+{{- define "helm-toolkit.manifests.secret_ingress_tls" }}
+{{- $envAll := index . "envAll" }}
+{{- $endpoint := index . "endpoint" | default "public" }}
+{{- $backendServiceType := index . "backendServiceType" }}
+{{- $backendService := index . "backendService" | default "api" }}
+{{- $host := index $envAll.Values.endpoints ( $backendServiceType | replace "-" "_" ) "host_fqdn_override" }}
+{{- if hasKey $host $endpoint }}
+{{- $endpointHost := index $host $endpoint }}
+{{- if kindIs "map" $endpointHost }}
+{{- if hasKey $endpointHost "tls" }}
+{{- if and $endpointHost.tls.key $endpointHost.tls.crt }}
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ index $envAll.Values.secrets.tls ( $backendServiceType | replace "-" "_" ) $backendService $endpoint }}
+type: kubernetes.io/tls
+data:
+  tls.key: {{ $endpointHost.tls.key | b64enc }}
+{{- if $endpointHost.tls.ca }}
+  tls.crt: {{ list $endpointHost.tls.crt $endpointHost.tls.ca | join "\n" | b64enc }}
+{{- else }}
+  tls.crt: {{ $endpointHost.tls.crt | b64enc }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/manifests/_service-ingress.tpl b/charts/nova/charts/helm-toolkit/templates/manifests/_service-ingress.tpl
new file mode 100644
index 0000000..d2e7c0e
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/manifests/_service-ingress.tpl
@@ -0,0 +1,43 @@
+{{/*
+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 function creates a manifest for a services ingress rules.
+# It can be used in charts dict created similar to the following:
+# {- $serviceIngressOpts := dict "envAll" . "backendServiceType" "key-manager" -}
+# { $serviceIngressOpts | include "helm-toolkit.manifests.service_ingress" }
+
+{{- define "helm-toolkit.manifests.service_ingress" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $backendServiceType := index . "backendServiceType" -}}
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ tuple $backendServiceType "public" $envAll | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }}
+spec:
+  ports:
+    - name: http
+      port: 80
+    - name: https
+      port: 443
+  selector:
+    app: ingress-api
+{{- if index $envAll.Values.endpoints $backendServiceType }}
+{{- if index $envAll.Values.endpoints $backendServiceType "ip" }}
+{{- if index $envAll.Values.endpoints $backendServiceType "ip" "ingress" }}
+  clusterIP: {{ (index $envAll.Values.endpoints $backendServiceType "ip" "ingress") }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/scripts/_create-s3-bucket.sh.tpl b/charts/nova/charts/helm-toolkit/templates/scripts/_create-s3-bucket.sh.tpl
new file mode 100644
index 0000000..bf1465b
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/scripts/_create-s3-bucket.sh.tpl
@@ -0,0 +1,35 @@
+{{/*
+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.
+*/}}
+{{- define "helm-toolkit.scripts.create_s3_bucket" }}
+#!/bin/bash
+set -e
+CONNECTION_ARGS="--host=$RGW_HOST --host-bucket=$RGW_HOST"
+if [ "$RGW_PROTO" = "http" ]; then
+  CONNECTION_ARGS+=" --no-ssl"
+else
+  CONNECTION_ARGS+=" --no-check-certificate"
+fi
+ADMIN_AUTH_ARGS=" --access_key=$S3_ADMIN_ACCESS_KEY --secret_key=$S3_ADMIN_SECRET_KEY"
+USER_AUTH_ARGS=" --access_key=$S3_ACCESS_KEY --secret_key=$S3_SECRET_KEY"
+function check_rgw_s3_bucket () {
+  s3cmd $CONNECTION_ARGS $USER_AUTH_ARGS ls s3://$S3_BUCKET
+}
+function create_rgw_s3_bucket () {
+  s3cmd $CONNECTION_ARGS $ADMIN_AUTH_ARGS mb s3://$S3_BUCKET
+}
+function modify_bucket_acl () {
+  s3cmd $CONNECTION_ARGS $ADMIN_AUTH_ARGS setacl s3://$S3_BUCKET --acl-grant=read:$S3_USERNAME --acl-grant=write:$S3_USERNAME
+}
+check_rgw_s3_bucket || ( create_rgw_s3_bucket && modify_bucket_acl )
+{{- end }}
\ No newline at end of file
diff --git a/charts/nova/charts/helm-toolkit/templates/scripts/_create-s3-user.sh.tpl b/charts/nova/charts/helm-toolkit/templates/scripts/_create-s3-user.sh.tpl
new file mode 100644
index 0000000..08796d2
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/scripts/_create-s3-user.sh.tpl
@@ -0,0 +1,65 @@
+{{/*
+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.
+*/}}
+{{- define "helm-toolkit.scripts.create_s3_user" }}
+#!/bin/bash
+set -e
+function create_s3_user () {
+  echo "Creating s3 user and key pair"
+  radosgw-admin user create \
+    --uid=${S3_USERNAME} \
+    --display-name=${S3_USERNAME} \
+    --key-type=s3 \
+    --access-key ${S3_ACCESS_KEY} \
+    --secret-key ${S3_SECRET_KEY}
+}
+function update_s3_user () {
+  # Retrieve old access keys, if they exist
+  old_access_keys=$(radosgw-admin user info --uid=${S3_USERNAME} \
+    | jq -r '.keys[].access_key' || true)
+
+  if [[ ! -z ${old_access_keys} ]]; then
+    for access_key in $old_access_keys; do
+      # If current access key is the same as the key supplied, do nothing.
+      if [ "$access_key" == "${S3_ACCESS_KEY}" ]; then
+        echo "Current user and key pair exists."
+        continue
+      else
+        # If keys differ, remove previous key
+        radosgw-admin key rm --uid=${S3_USERNAME} --key-type=s3 --access-key=$access_key
+      fi
+    done
+  fi
+
+  # Perform one more additional check to account for scenarios where multiple
+  # key pairs existed previously, but one existing key was the supplied key
+  current_access_key=$(radosgw-admin user info --uid=${S3_USERNAME} \
+    | jq -r '.keys[].access_key' || true)
+
+  # If the supplied key does not exist, modify the user
+  if [[ -z ${current_access_key} ]]; then
+    # Modify user with new access and secret keys
+    echo "Updating existing user's key pair"
+    radosgw-admin user modify \
+      --uid=${S3_USERNAME}\
+      --access-key ${S3_ACCESS_KEY} \
+      --secret-key ${S3_SECRET_KEY}
+  fi
+}
+user_exists=$(radosgw-admin user info --uid=${S3_USERNAME} || true)
+if [[ -z ${user_exists} ]]; then
+  create_s3_user
+else
+  update_s3_user
+fi
+{{- end }}
\ No newline at end of file
diff --git a/charts/nova/charts/helm-toolkit/templates/scripts/_db-drop.py.tpl b/charts/nova/charts/helm-toolkit/templates/scripts/_db-drop.py.tpl
new file mode 100644
index 0000000..03884fa
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/scripts/_db-drop.py.tpl
@@ -0,0 +1,142 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.scripts.db_drop" }}
+#!/usr/bin/env python
+
+# Drops db and user for an OpenStack Service:
+# Set ROOT_DB_CONNECTION and DB_CONNECTION environment variables to contain
+# SQLAlchemy strings for the root connection to the database and the one you
+# wish the service to use. Alternatively, you can use an ini formatted config
+# at the location specified by OPENSTACK_CONFIG_FILE, and extract the string
+# from the key OPENSTACK_CONFIG_DB_KEY, in the section specified by
+# OPENSTACK_CONFIG_DB_SECTION.
+
+import os
+import sys
+try:
+    import ConfigParser
+    PARSER_OPTS = {}
+except ImportError:
+    import configparser as ConfigParser
+    PARSER_OPTS = {"strict": False}
+import logging
+from sqlalchemy import create_engine
+
+# Create logger, console handler and formatter
+logger = logging.getLogger('OpenStack-Helm DB Drop')
+logger.setLevel(logging.DEBUG)
+ch = logging.StreamHandler()
+ch.setLevel(logging.DEBUG)
+formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+
+# Set the formatter and add the handler
+ch.setFormatter(formatter)
+logger.addHandler(ch)
+
+
+# Get the connection string for the service db root user
+if "ROOT_DB_CONNECTION" in os.environ:
+    db_connection = os.environ['ROOT_DB_CONNECTION']
+    logger.info('Got DB root connection')
+else:
+    logger.critical('environment variable ROOT_DB_CONNECTION not set')
+    sys.exit(1)
+
+mysql_x509 = os.getenv('MARIADB_X509', "")
+ssl_args = {}
+if mysql_x509:
+    ssl_args = {'ssl': {'ca': '/etc/mysql/certs/ca.crt',
+                        'key': '/etc/mysql/certs/tls.key',
+                        'cert': '/etc/mysql/certs/tls.crt'}}
+
+# Get the connection string for the service db
+if "OPENSTACK_CONFIG_FILE" in os.environ:
+    os_conf = os.environ['OPENSTACK_CONFIG_FILE']
+    if "OPENSTACK_CONFIG_DB_SECTION" in os.environ:
+        os_conf_section = os.environ['OPENSTACK_CONFIG_DB_SECTION']
+    else:
+        logger.critical('environment variable OPENSTACK_CONFIG_DB_SECTION not set')
+        sys.exit(1)
+    if "OPENSTACK_CONFIG_DB_KEY" in os.environ:
+        os_conf_key = os.environ['OPENSTACK_CONFIG_DB_KEY']
+    else:
+        logger.critical('environment variable OPENSTACK_CONFIG_DB_KEY not set')
+        sys.exit(1)
+    try:
+        config = ConfigParser.RawConfigParser(**PARSER_OPTS)
+        logger.info("Using {0} as db config source".format(os_conf))
+        config.read(os_conf)
+        logger.info("Trying to load db config from {0}:{1}".format(
+            os_conf_section, os_conf_key))
+        user_db_conn = config.get(os_conf_section, os_conf_key)
+        logger.info("Got config from {0}".format(os_conf))
+    except:
+        logger.critical("Tried to load config from {0} but failed.".format(os_conf))
+        raise
+elif "DB_CONNECTION" in os.environ:
+    user_db_conn = os.environ['DB_CONNECTION']
+    logger.info('Got config from DB_CONNECTION env var')
+else:
+    logger.critical('Could not get db config, either from config file or env var')
+    sys.exit(1)
+
+# Root DB engine
+try:
+    root_engine_full = create_engine(db_connection)
+    root_user = root_engine_full.url.username
+    root_password = root_engine_full.url.password
+    drivername = root_engine_full.url.drivername
+    host = root_engine_full.url.host
+    port = root_engine_full.url.port
+    root_engine_url = ''.join([drivername, '://', root_user, ':', root_password, '@', host, ':', str (port)])
+    root_engine = create_engine(root_engine_url, connect_args=ssl_args)
+    connection = root_engine.connect()
+    connection.close()
+    logger.info("Tested connection to DB @ {0}:{1} as {2}".format(
+        host, port, root_user))
+except:
+    logger.critical('Could not connect to database as root user')
+    raise
+
+# User DB engine
+try:
+    user_engine = create_engine(user_db_conn, connect_args=ssl_args)
+    # Get our user data out of the user_engine
+    database = user_engine.url.database
+    user = user_engine.url.username
+    password = user_engine.url.password
+    logger.info('Got user db config')
+except:
+    logger.critical('Could not get user database config')
+    raise
+
+# Delete DB
+try:
+    root_engine.execute("DROP DATABASE IF EXISTS {0}".format(database))
+    logger.info("Deleted database {0}".format(database))
+except:
+    logger.critical("Could not drop database {0}".format(database))
+    raise
+
+# Delete DB User
+try:
+    root_engine.execute("DROP USER IF EXISTS {0}".format(user))
+    logger.info("Deleted user {0}".format(user))
+except:
+    logger.critical("Could not delete user {0}".format(user))
+    raise
+
+logger.info('Finished DB Management')
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/scripts/_db-init.py.tpl b/charts/nova/charts/helm-toolkit/templates/scripts/_db-init.py.tpl
new file mode 100644
index 0000000..4294d40
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/scripts/_db-init.py.tpl
@@ -0,0 +1,154 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.scripts.db_init" }}
+#!/usr/bin/env python
+
+# Creates db and user for an OpenStack Service:
+# Set ROOT_DB_CONNECTION and DB_CONNECTION environment variables to contain
+# SQLAlchemy strings for the root connection to the database and the one you
+# wish the service to use. Alternatively, you can use an ini formatted config
+# at the location specified by OPENSTACK_CONFIG_FILE, and extract the string
+# from the key OPENSTACK_CONFIG_DB_KEY, in the section specified by
+# OPENSTACK_CONFIG_DB_SECTION.
+
+import os
+import sys
+try:
+    import ConfigParser
+    PARSER_OPTS = {}
+except ImportError:
+    import configparser as ConfigParser
+    PARSER_OPTS = {"strict": False}
+import logging
+from sqlalchemy import create_engine
+
+# Create logger, console handler and formatter
+logger = logging.getLogger('OpenStack-Helm DB Init')
+logger.setLevel(logging.DEBUG)
+ch = logging.StreamHandler()
+ch.setLevel(logging.DEBUG)
+formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+
+# Set the formatter and add the handler
+ch.setFormatter(formatter)
+logger.addHandler(ch)
+
+
+# Get the connection string for the service db root user
+if "ROOT_DB_CONNECTION" in os.environ:
+    db_connection = os.environ['ROOT_DB_CONNECTION']
+    logger.info('Got DB root connection')
+else:
+    logger.critical('environment variable ROOT_DB_CONNECTION not set')
+    sys.exit(1)
+
+mysql_x509 = os.getenv('MARIADB_X509', "")
+ssl_args = {}
+if mysql_x509:
+    ssl_args = {'ssl': {'ca': '/etc/mysql/certs/ca.crt',
+                'key': '/etc/mysql/certs/tls.key',
+                'cert': '/etc/mysql/certs/tls.crt'}}
+
+# Get the connection string for the service db
+if "OPENSTACK_CONFIG_FILE" in os.environ:
+    os_conf = os.environ['OPENSTACK_CONFIG_FILE']
+    if "OPENSTACK_CONFIG_DB_SECTION" in os.environ:
+        os_conf_section = os.environ['OPENSTACK_CONFIG_DB_SECTION']
+    else:
+        logger.critical('environment variable OPENSTACK_CONFIG_DB_SECTION not set')
+        sys.exit(1)
+    if "OPENSTACK_CONFIG_DB_KEY" in os.environ:
+        os_conf_key = os.environ['OPENSTACK_CONFIG_DB_KEY']
+    else:
+        logger.critical('environment variable OPENSTACK_CONFIG_DB_KEY not set')
+        sys.exit(1)
+    try:
+        config = ConfigParser.RawConfigParser(**PARSER_OPTS)
+        logger.info("Using {0} as db config source".format(os_conf))
+        config.read(os_conf)
+        logger.info("Trying to load db config from {0}:{1}".format(
+            os_conf_section, os_conf_key))
+        user_db_conn = config.get(os_conf_section, os_conf_key)
+        logger.info("Got config from {0}".format(os_conf))
+    except:
+        logger.critical("Tried to load config from {0} but failed.".format(os_conf))
+        raise
+elif "DB_CONNECTION" in os.environ:
+    user_db_conn = os.environ['DB_CONNECTION']
+    logger.info('Got config from DB_CONNECTION env var')
+else:
+    logger.critical('Could not get db config, either from config file or env var')
+    sys.exit(1)
+
+# Root DB engine
+try:
+    root_engine_full = create_engine(db_connection)
+    root_user = root_engine_full.url.username
+    root_password = root_engine_full.url.password
+    drivername = root_engine_full.url.drivername
+    host = root_engine_full.url.host
+    port = root_engine_full.url.port
+    root_engine_url = ''.join([drivername, '://', root_user, ':', root_password, '@', host, ':', str (port)])
+    root_engine = create_engine(root_engine_url, connect_args=ssl_args)
+    connection = root_engine.connect()
+    connection.close()
+    logger.info("Tested connection to DB @ {0}:{1} as {2}".format(
+        host, port, root_user))
+except:
+    logger.critical('Could not connect to database as root user')
+    raise
+
+# User DB engine
+try:
+    user_engine = create_engine(user_db_conn, connect_args=ssl_args)
+    # Get our user data out of the user_engine
+    database = user_engine.url.database
+    user = user_engine.url.username
+    password = user_engine.url.password
+    logger.info('Got user db config')
+except:
+    logger.critical('Could not get user database config')
+    raise
+
+# Create DB
+try:
+    root_engine.execute("CREATE DATABASE IF NOT EXISTS {0}".format(database))
+    logger.info("Created database {0}".format(database))
+except:
+    logger.critical("Could not create database {0}".format(database))
+    raise
+
+# Create DB User
+try:
+    root_engine.execute(
+        "GRANT ALL ON `{0}`.* TO \'{1}\'@\'%%\' IDENTIFIED BY \'{2}\' {3}".format(
+            database, user, password, mysql_x509))
+    logger.info("Created user {0} for {1}".format(user, database))
+except:
+    logger.critical("Could not create user {0} for {1}".format(user, database))
+    raise
+
+# Test connection
+try:
+    connection = user_engine.connect()
+    connection.close()
+    logger.info("Tested connection to DB @ {0}:{1}/{2} as {3}".format(
+        host, port, database, user))
+except:
+    logger.critical('Could not connect to database as user')
+    raise
+
+logger.info('Finished DB Management')
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/scripts/_db-pg-init.sh.tpl b/charts/nova/charts/helm-toolkit/templates/scripts/_db-pg-init.sh.tpl
new file mode 100644
index 0000000..4d7dfaa
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/scripts/_db-pg-init.sh.tpl
@@ -0,0 +1,69 @@
+# 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.
+
+{{- define "helm-toolkit.scripts.pg_db_init" }}
+#!/bin/bash
+set -ex
+
+if [[ ! -v DB_HOST ]]; then
+    echo "environment variable DB_HOST not set"
+    exit 1
+elif [[ ! -v DB_ADMIN_USER ]]; then
+    echo "environment variable DB_ADMIN_USER not set"
+    exit 1
+elif [[ ! -v PGPASSWORD ]]; then
+    echo "environment variable PGPASSWORD not set"
+    exit 1
+elif [[ ! -v DB_PORT ]]; then
+    echo "environment variable DB_PORT not set"
+    exit 1
+elif [[ ! -v USER_DB_USER ]]; then
+    echo "environment variable USER_DB_USER not set"
+    exit 1
+elif [[ ! -v USER_DB_PASS ]]; then
+    echo "environment variable USER_DB_PASS not set"
+    exit 1
+elif [[ ! -v USER_DB_NAME ]]; then
+    echo "environment variable USER_DB_NAME not set"
+    exit 1
+else
+    echo "Got DB connection info"
+fi
+
+pgsql_superuser_cmd () {
+  DB_COMMAND="$1"
+  if [[ ! -z $2 ]]; then
+      EXPORT PGDATABASE=$2
+  fi
+  /usr/bin/psql \
+  -h ${DB_HOST} \
+  -p ${DB_PORT} \
+  -U ${DB_ADMIN_USER} \
+  --command="${DB_COMMAND}"
+}
+
+#create db
+pgsql_superuser_cmd "SELECT 1 FROM pg_database WHERE datname = '$USER_DB_NAME'" | grep -q "(1 row)" || pgsql_superuser_cmd "CREATE DATABASE $USER_DB_NAME"
+
+#create db user
+pgsql_superuser_cmd "SELECT * FROM pg_roles WHERE rolname = '$USER_DB_USER';" | grep -q "(1 row)" || \
+    pgsql_superuser_cmd "CREATE ROLE ${USER_DB_USER} LOGIN PASSWORD '$USER_DB_PASS';"
+
+#Set password everytime. This is required for cases when we would want password rotation to take effect and set the updated password for a user.
+pgsql_superuser_cmd "SELECT * FROM pg_roles WHERE rolname = '$USER_DB_USER';" && pgsql_superuser_cmd "ALTER USER ${USER_DB_USER} with password '$USER_DB_PASS'"
+
+#give permissions to user
+pgsql_superuser_cmd "GRANT ALL PRIVILEGES ON DATABASE $USER_DB_NAME to $USER_DB_USER;"
+
+#revoke all privileges from PUBLIC role
+pgsql_superuser_cmd "REVOKE ALL ON DATABASE $USER_DB_NAME FROM PUBLIC;"
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/scripts/_image-repo-sync.sh.tpl b/charts/nova/charts/helm-toolkit/templates/scripts/_image-repo-sync.sh.tpl
new file mode 100644
index 0000000..e41abe3
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/scripts/_image-repo-sync.sh.tpl
@@ -0,0 +1,24 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.scripts.image_repo_sync" }}
+#!/bin/sh
+set -ex
+
+IFS=','; for IMAGE in ${IMAGE_SYNC_LIST}; do
+  docker pull ${IMAGE}
+  docker tag ${IMAGE} ${LOCAL_REPO}/${IMAGE}
+  docker push ${LOCAL_REPO}/${IMAGE}
+done
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/scripts/_ks-domain-user.sh.tpl b/charts/nova/charts/helm-toolkit/templates/scripts/_ks-domain-user.sh.tpl
new file mode 100644
index 0000000..8755cd5
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/scripts/_ks-domain-user.sh.tpl
@@ -0,0 +1,72 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.scripts.keystone_domain_user" }}
+#!/bin/bash
+
+# Copyright 2017 Pete Birley
+#
+# 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 -ex
+
+# Manage domain
+SERVICE_OS_DOMAIN_ID=$(openstack domain create --or-show --enable -f value -c id \
+    --description="Service Domain for ${SERVICE_OS_REGION_NAME}/${SERVICE_OS_DOMAIN_NAME}" \
+    "${SERVICE_OS_DOMAIN_NAME}")
+
+# Display domain
+openstack domain show "${SERVICE_OS_DOMAIN_ID}"
+
+# Manage user
+SERVICE_OS_USERID=$(openstack user create --or-show --enable -f value -c id \
+    --domain="${SERVICE_OS_DOMAIN_ID}" \
+    --description "Service User for ${SERVICE_OS_REGION_NAME}/${SERVICE_OS_DOMAIN_NAME}" \
+    --password="${SERVICE_OS_PASSWORD}" \
+    "${SERVICE_OS_USERNAME}")
+
+# Manage user password (we do this to ensure the password is updated if required)
+openstack user set --password="${SERVICE_OS_PASSWORD}" "${SERVICE_OS_USERID}"
+
+# Display user
+openstack user show "${SERVICE_OS_USERID}"
+
+# Manage role
+SERVICE_OS_ROLE_ID=$(openstack role show -f value -c id \
+    "${SERVICE_OS_ROLE}" || openstack role create -f value -c id \
+    "${SERVICE_OS_ROLE}" )
+
+# Manage user role assignment
+openstack role add \
+          --domain="${SERVICE_OS_DOMAIN_ID}" \
+          --user="${SERVICE_OS_USERID}" \
+          --user-domain="${SERVICE_OS_DOMAIN_ID}" \
+          "${SERVICE_OS_ROLE_ID}"
+
+# Display user role assignment
+openstack role assignment list \
+          --role="${SERVICE_OS_ROLE_ID}" \
+          --user-domain="${SERVICE_OS_DOMAIN_ID}" \
+          --user="${SERVICE_OS_USERID}"
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/scripts/_ks-endpoints.sh.tpl b/charts/nova/charts/helm-toolkit/templates/scripts/_ks-endpoints.sh.tpl
new file mode 100644
index 0000000..e400bcd
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/scripts/_ks-endpoints.sh.tpl
@@ -0,0 +1,79 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.scripts.keystone_endpoints" }}
+#!/bin/bash
+
+# Copyright 2017 Pete Birley
+#
+# 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 -ex
+
+# Get Service ID
+OS_SERVICE_ID=$( openstack service list -f csv --quote none | \
+                  grep ",${OS_SERVICE_NAME},${OS_SERVICE_TYPE}$" | \
+                    sed -e "s/,${OS_SERVICE_NAME},${OS_SERVICE_TYPE}//g" )
+
+# Get Endpoint ID if it exists
+OS_ENDPOINT_ID=$( openstack endpoint list  -f csv --quote none | \
+                  grep "^[a-z0-9]*,${OS_REGION_NAME},${OS_SERVICE_NAME},${OS_SERVICE_TYPE},True,${OS_SVC_ENDPOINT}," | \
+                  awk -F ',' '{ print $1 }' )
+
+# Making sure only a single endpoint exists for a service within a region
+if [ "$(echo $OS_ENDPOINT_ID | wc -w)" -gt "1" ]; then
+  echo "More than one endpoint found, cleaning up"
+  for ENDPOINT_ID in $OS_ENDPOINT_ID; do
+    openstack endpoint delete ${ENDPOINT_ID}
+  done
+  unset OS_ENDPOINT_ID
+fi
+
+# Determine if Endpoint needs updated
+if [[ ${OS_ENDPOINT_ID} ]]; then
+  OS_ENDPOINT_URL_CURRENT=$(openstack endpoint show ${OS_ENDPOINT_ID} -f value -c url)
+  if [ "${OS_ENDPOINT_URL_CURRENT}" == "${OS_SERVICE_ENDPOINT}" ]; then
+    echo "Endpoints Match: no action required"
+    OS_ENDPOINT_UPDATE="False"
+  else
+    echo "Endpoints Dont Match: removing existing entries"
+    openstack endpoint delete ${OS_ENDPOINT_ID}
+    OS_ENDPOINT_UPDATE="True"
+  fi
+else
+  OS_ENDPOINT_UPDATE="True"
+fi
+
+# Update Endpoint if required
+if [[ "${OS_ENDPOINT_UPDATE}" == "True" ]]; then
+  OS_ENDPOINT_ID=$( openstack endpoint create -f value -c id \
+    --region="${OS_REGION_NAME}" \
+    "${OS_SERVICE_ID}" \
+    ${OS_SVC_ENDPOINT} \
+    "${OS_SERVICE_ENDPOINT}" )
+fi
+
+# Display the Endpoint
+openstack endpoint show ${OS_ENDPOINT_ID}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/scripts/_ks-service.sh.tpl b/charts/nova/charts/helm-toolkit/templates/scripts/_ks-service.sh.tpl
new file mode 100644
index 0000000..8356b36
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/scripts/_ks-service.sh.tpl
@@ -0,0 +1,76 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.scripts.keystone_service" }}
+#!/bin/bash
+
+# Copyright 2017 Pete Birley
+#
+# 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 -ex
+
+# Service boilerplate description
+OS_SERVICE_DESC="${OS_REGION_NAME}: ${OS_SERVICE_NAME} (${OS_SERVICE_TYPE}) service"
+
+# Get Service ID if it exists
+unset OS_SERVICE_ID
+
+# FIXME - There seems to be an issue once in a while where the
+# openstack service list fails and encounters an error message such as:
+#   Unable to establish connection to
+#   https://keystone-api.openstack.svc.cluster.local:5000/v3/auth/tokens:
+#   ('Connection aborted.', OSError("(104, 'ECONNRESET')",))
+# During an upgrade scenario, this would cause the OS_SERVICE_ID to be blank
+# and it would attempt to create a new service when it was not needed.
+# This duplciate service would sometimes be used by other services such as
+# Horizon and would give an 'Invalid Service Catalog' error.
+# This loop allows for a 'retry' of the openstack service list in an
+# attempt to get the service list as expected if it does ecounter an error.
+# This loop and recheck can be reverted once the underlying issue is addressed.
+
+# If OS_SERVICE_ID is blank then wait a few seconds to give it
+# additional time and try again
+for i in $(seq 3)
+do
+  OS_SERVICE_ID=$( openstack service list -f csv --quote none | \
+                   grep ",${OS_SERVICE_NAME},${OS_SERVICE_TYPE}$" | \
+                   sed -e "s/,${OS_SERVICE_NAME},${OS_SERVICE_TYPE}//g" )
+
+  # If the service was found, go ahead and exit successfully.
+  if [[ -n "${OS_SERVICE_ID}" ]]; then
+    exit 0
+  fi
+
+  sleep 2
+done
+
+# If we've reached this point and a Service ID was not found,
+# then create the service
+OS_SERVICE_ID=$(openstack service create -f value -c id \
+                --name="${OS_SERVICE_NAME}" \
+                --description "${OS_SERVICE_DESC}" \
+                --enable \
+                "${OS_SERVICE_TYPE}")
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/scripts/_ks-user.sh.tpl b/charts/nova/charts/helm-toolkit/templates/scripts/_ks-user.sh.tpl
new file mode 100644
index 0000000..b45f798
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/scripts/_ks-user.sh.tpl
@@ -0,0 +1,108 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.scripts.keystone_user" }}
+#!/bin/bash
+
+# Copyright 2017 Pete Birley
+#
+# 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 -ex
+
+shopt -s nocasematch
+
+if [[ "${SERVICE_OS_PROJECT_DOMAIN_NAME}" == "Default" ]]
+then
+  PROJECT_DOMAIN_ID="default"
+else
+  # Manage project domain
+  PROJECT_DOMAIN_ID=$(openstack domain create --or-show --enable -f value -c id \
+    --description="Domain for ${SERVICE_OS_REGION_NAME}/${SERVICE_OS_PROJECT_DOMAIN_NAME}" \
+    "${SERVICE_OS_PROJECT_DOMAIN_NAME}")
+fi
+
+if [[ "${SERVICE_OS_USER_DOMAIN_NAME}" == "Default" ]]
+then
+  USER_DOMAIN_ID="default"
+else
+  # Manage user domain
+  USER_DOMAIN_ID=$(openstack domain create --or-show --enable -f value -c id \
+    --description="Domain for ${SERVICE_OS_REGION_NAME}/${SERVICE_OS_USER_DOMAIN_NAME}" \
+    "${SERVICE_OS_USER_DOMAIN_NAME}")
+fi
+
+shopt -u nocasematch
+
+# Manage user project
+USER_PROJECT_DESC="Service Project for ${SERVICE_OS_REGION_NAME}/${SERVICE_OS_PROJECT_DOMAIN_NAME}"
+USER_PROJECT_ID=$(openstack project create --or-show --enable -f value -c id \
+    --domain="${PROJECT_DOMAIN_ID}" \
+    --description="${USER_PROJECT_DESC}" \
+    "${SERVICE_OS_PROJECT_NAME}");
+
+# Manage user
+USER_DESC="Service User for ${SERVICE_OS_REGION_NAME}/${SERVICE_OS_USER_DOMAIN_NAME}/${SERVICE_OS_SERVICE_NAME}"
+USER_ID=$(openstack user create --or-show --enable -f value -c id \
+    --domain="${USER_DOMAIN_ID}" \
+    --project-domain="${PROJECT_DOMAIN_ID}" \
+    --project="${USER_PROJECT_ID}" \
+    --description="${USER_DESC}" \
+    "${SERVICE_OS_USERNAME}");
+
+# Manage user password (we do this in a seperate step to ensure the password is updated if required)
+set +x
+echo "Setting user password via: openstack user set --password=xxxxxxx ${USER_ID}"
+openstack user set --password="${SERVICE_OS_PASSWORD}" "${USER_ID}"
+set -x
+
+function ks_assign_user_role () {
+  if [[ "$SERVICE_OS_ROLE" == "admin" ]]
+  then
+    USER_ROLE_ID="$SERVICE_OS_ROLE"
+  else
+    USER_ROLE_ID=$(openstack role create --or-show -f value -c id "${SERVICE_OS_ROLE}");
+  fi
+
+  # Manage user role assignment
+  openstack role add \
+      --user="${USER_ID}" \
+      --user-domain="${USER_DOMAIN_ID}" \
+      --project-domain="${PROJECT_DOMAIN_ID}" \
+      --project="${USER_PROJECT_ID}" \
+      "${USER_ROLE_ID}"
+}
+
+# Manage user service role
+IFS=','
+for SERVICE_OS_ROLE in ${SERVICE_OS_ROLES}; do
+  ks_assign_user_role
+done
+
+# Manage user member role
+: ${MEMBER_OS_ROLE:="member"}
+export USER_ROLE_ID=$(openstack role create --or-show -f value -c id \
+    "${MEMBER_OS_ROLE}");
+ks_assign_user_role
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/scripts/_rabbit-init.sh.tpl b/charts/nova/charts/helm-toolkit/templates/scripts/_rabbit-init.sh.tpl
new file mode 100644
index 0000000..87872d6
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/scripts/_rabbit-init.sh.tpl
@@ -0,0 +1,106 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.scripts.rabbit_init" }}
+#!/bin/bash
+set -e
+# Extract connection details
+RABBIT_HOSTNAME=$(echo "${RABBITMQ_ADMIN_CONNECTION}" | \
+  awk -F'[@]' '{print $2}' | \
+  awk -F'[:/]' '{print $1}')
+RABBIT_PORT=$(echo "${RABBITMQ_ADMIN_CONNECTION}" | \
+  awk -F'[@]' '{print $2}' | \
+  awk -F'[:/]' '{print $2}')
+
+# Extract Admin User creadential
+RABBITMQ_ADMIN_USERNAME=$(echo "${RABBITMQ_ADMIN_CONNECTION}" | \
+  awk -F'[@]' '{print $1}' | \
+  awk -F'[//:]' '{print $4}')
+RABBITMQ_ADMIN_PASSWORD=$(echo "${RABBITMQ_ADMIN_CONNECTION}" | \
+  awk -F'[@]' '{print $1}' | \
+  awk -F'[//:]' '{print $5}')
+
+# Extract User creadential
+RABBITMQ_USERNAME=$(echo "${RABBITMQ_USER_CONNECTION}" | \
+  awk -F'[@]' '{print $1}' | \
+  awk -F'[//:]' '{print $4}')
+RABBITMQ_PASSWORD=$(echo "${RABBITMQ_USER_CONNECTION}" | \
+  awk -F'[@]' '{print $1}' | \
+  awk -F'[//:]' '{print $5}')
+
+# Extract User vHost
+RABBITMQ_VHOST=$(echo "${RABBITMQ_USER_CONNECTION}" | \
+  awk -F'[@]' '{print $2}' | \
+  awk -F'[:/]' '{print $3}')
+# Resolve vHost to / if no value is set
+RABBITMQ_VHOST="${RABBITMQ_VHOST:-/}"
+
+function rabbitmqadmin_cli () {
+  if [ -n "$RABBITMQ_X509" ]
+  then
+    rabbitmqadmin \
+      --ssl \
+      --ssl-disable-hostname-verification \
+      --ssl-ca-cert-file="${USER_CERT_PATH}/ca.crt" \
+      --ssl-cert-file="${USER_CERT_PATH}/tls.crt" \
+      --ssl-key-file="${USER_CERT_PATH}/tls.key" \
+      --host="${RABBIT_HOSTNAME}" \
+      --port="${RABBIT_PORT}" \
+      --username="${RABBITMQ_ADMIN_USERNAME}" \
+      --password="${RABBITMQ_ADMIN_PASSWORD}" \
+      ${@}
+  else
+    rabbitmqadmin \
+      --host="${RABBIT_HOSTNAME}" \
+      --port="${RABBIT_PORT}" \
+      --username="${RABBITMQ_ADMIN_USERNAME}" \
+      --password="${RABBITMQ_ADMIN_PASSWORD}" \
+      ${@}
+  fi
+}
+
+echo "Managing: User: ${RABBITMQ_USERNAME}"
+rabbitmqadmin_cli \
+  declare user \
+  name="${RABBITMQ_USERNAME}" \
+  password="${RABBITMQ_PASSWORD}" \
+  tags="user"
+
+if [ "${RABBITMQ_VHOST}" != "/" ]
+then
+  echo "Managing: vHost: ${RABBITMQ_VHOST}"
+  rabbitmqadmin_cli \
+    declare vhost \
+    name="${RABBITMQ_VHOST}"
+else
+  echo "Skipping root vHost declaration: vHost: ${RABBITMQ_VHOST}"
+fi
+
+echo "Managing: Permissions: ${RABBITMQ_USERNAME} on ${RABBITMQ_VHOST}"
+rabbitmqadmin_cli \
+  declare permission \
+  vhost="${RABBITMQ_VHOST}" \
+  user="${RABBITMQ_USERNAME}" \
+  configure=".*" \
+  write=".*" \
+  read=".*"
+
+if [ ! -z "$RABBITMQ_AUXILIARY_CONFIGURATION" ]
+then
+  echo "Applying additional configuration"
+  echo "${RABBITMQ_AUXILIARY_CONFIGURATION}" > /tmp/rmq_definitions.json
+  rabbitmqadmin_cli import /tmp/rmq_definitions.json
+fi
+
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/scripts/_rally_test.sh.tpl b/charts/nova/charts/helm-toolkit/templates/scripts/_rally_test.sh.tpl
new file mode 100644
index 0000000..c08d320
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/scripts/_rally_test.sh.tpl
@@ -0,0 +1,88 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.scripts.rally_test" -}}
+#!/bin/bash
+set -ex
+{{- $rallyTests := index . 0 }}
+
+: "${RALLY_ENV_NAME:="openstack-helm"}"
+: "${OS_INTERFACE:="public"}"
+: "${RALLY_CLEANUP:="true"}"
+
+if [ "x$RALLY_CLEANUP" == "xtrue" ]; then
+  function rally_cleanup {
+    openstack user delete \
+        --domain="${SERVICE_OS_USER_DOMAIN_NAME}" \
+        "${SERVICE_OS_USERNAME}"
+{{ $rallyTests.clean_up | default "" | indent 4 }}
+  }
+  trap rally_cleanup EXIT
+fi
+
+function create_or_update_db () {
+  revisionResults=$(rally db revision)
+  if [ $revisionResults = "None"  ]
+  then
+    rally db create
+  else
+    rally db upgrade
+  fi
+}
+
+create_or_update_db
+
+cat > /tmp/rally-config.json << EOF
+{
+    "openstack": {
+        "auth_url": "${OS_AUTH_URL}",
+        "region_name": "${OS_REGION_NAME}",
+        "endpoint_type": "${OS_INTERFACE}",
+        "admin": {
+            "username": "${OS_USERNAME}",
+            "password": "${OS_PASSWORD}",
+            "user_domain_name": "${OS_USER_DOMAIN_NAME}",
+            "project_name": "${OS_PROJECT_NAME}",
+            "project_domain_name": "${OS_PROJECT_DOMAIN_NAME}"
+        },
+        "users": [
+            {
+                "username": "${SERVICE_OS_USERNAME}",
+                "password": "${SERVICE_OS_PASSWORD}",
+                "project_name": "${SERVICE_OS_PROJECT_NAME}",
+                "user_domain_name": "${SERVICE_OS_USER_DOMAIN_NAME}",
+                "project_domain_name": "${SERVICE_OS_PROJECT_DOMAIN_NAME}"
+            }
+        ],
+        "https_insecure": false,
+        "https_cacert": "${OS_CACERT}"
+    }
+}
+EOF
+rally deployment create --file /tmp/rally-config.json --name "${RALLY_ENV_NAME}"
+rm -f /tmp/rally-config.json
+rally deployment use "${RALLY_ENV_NAME}"
+rally deployment check
+{{- if $rallyTests.run_tempest }}
+rally verify create-verifier --name "${RALLY_ENV_NAME}-tempest" --type tempest
+SERVICE_TYPE="$(rally deployment check | grep "${RALLY_ENV_NAME}" | awk -F \| '{print $3}' | tr -d ' ' | tr -d '\n')"
+rally verify start --pattern "tempest.api.${SERVICE_TYPE}*"
+rally verify delete-verifier --id "${RALLY_ENV_NAME}-tempest" --force
+{{- end }}
+rally task validate /etc/rally/rally_tests.yaml
+rally task start /etc/rally/rally_tests.yaml
+rally task sla-check
+rally env cleanup
+rally deployment destroy --deployment "${RALLY_ENV_NAME}"
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/scripts/db-backup-restore/_backup_main.sh.tpl b/charts/nova/charts/helm-toolkit/templates/scripts/db-backup-restore/_backup_main.sh.tpl
new file mode 100644
index 0000000..db12915
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/scripts/db-backup-restore/_backup_main.sh.tpl
@@ -0,0 +1,540 @@
+{{- define "helm-toolkit.scripts.db-backup-restore.backup_main" }}
+#!/bin/bash
+
+# This file contains a database backup framework which database scripts
+# can use to perform a backup. The idea here is that the database-specific
+# functions will be implemented by the various databases using this script
+# (like mariadb, postgresql or etcd for example). The database-specific
+# script will need to first "source" this file like this:
+#   source /tmp/backup_main.sh
+#
+# Then the script should call the main backup function (backup_databases):
+#   backup_databases [scope]
+#       [scope] is an optional parameter, defaulted to "all". If only one specific
+#               database is required to be backed up then this parameter will
+#               contain the name of the database; otherwise all are backed up.
+#
+#       The framework will require the following variables to be exported:
+#
+#         export DB_NAMESPACE          Namespace where the database(s) reside
+#         export DB_NAME               Name of the database system
+#         export LOCAL_DAYS_TO_KEEP    Number of days to keep the local backups
+#         export REMOTE_DAYS_TO_KEEP   Number of days to keep the remote backups
+#         export ARCHIVE_DIR           Local location where the backup tarballs should
+#                                      be stored. (full directory path)
+#         export BACK_UP_MODE          Determines the mode of backup taken.
+#         export REMOTE_BACKUP_ENABLED "true" if remote backup enabled; false
+#                                      otherwise
+#         export CONTAINER_NAME        Name of the container on the RGW to store
+#                                      the backup tarball.
+#         export STORAGE_POLICY        Name of the storage policy defined on the
+#                                      RGW which is intended to store backups.
+#         RGW access variables:
+#           export OS_REGION_NAME          Name of the region the RGW resides in
+#           export OS_AUTH_URL             Keystone URL associated with the RGW
+#           export OS_PROJECT_NAME         Name of the project associated with the
+#                                          keystone user
+#           export OS_USERNAME             Name of the keystone user
+#           export OS_PASSWORD             Password of the keystone user
+#           export OS_USER_DOMAIN_NAME     Keystone domain the project belongs to
+#           export OS_PROJECT_DOMAIN_NAME  Keystone domain the user belongs to
+#           export OS_IDENTITY_API_VERSION Keystone API version to use
+#
+#           export REMOTE_BACKUP_RETRIES   Number of retries to send backup to remote
+#                                          in case of any temporary failures.
+#           export MIN_DELAY_SEND_REMOTE   Minimum seconds to delay before sending backup
+#                                          to remote to stagger backups being sent to RGW
+#           export MAX_DELAY_SEND_REMOTE   Maximum seconds to delay before sending backup
+#                                          to remote to stagger backups being sent to RGW.
+#                                          A random number between min and max delay is generated
+#                                          to set the delay.
+#
+# The database-specific functions that need to be implemented are:
+#   dump_databases_to_directory <directory> <err_logfile> [scope]
+#       where:
+#         <directory>   is the full directory path to dump the database files
+#                       into. This is a temporary directory for this backup only.
+#         <err_logfile> is the full directory path where error logs are to be
+#                       written by the application.
+#         [scope]       set to "all" if all databases are to be backed up; or
+#                       set to the name of a specific database to be backed up.
+#                       This optional parameter is defaulted to "all".
+#       returns: 0 if no errors; 1 if any errors occurred
+#
+#       This function is expected to dump the database file(s) to the specified
+#       directory path. If this function completes successfully (returns 0), the
+#       framework will automatically tar/zip the files in that directory and
+#       name the tarball appropriately according to the proper conventions.
+#
+# The functions in this file will take care of:
+#   1) Calling "dump_databases_to_directory" and then compressing the files,
+#      naming the tarball properly, and then storing it locally at the specified
+#      local directory.
+#   2) Sending the tarball built to the remote gateway, to be stored in the
+#      container configured to store database backups.
+#   3) Removing local backup tarballs which are older than the number of days
+#      specified by the "LOCAL_DAYS_TO_KEEP" variable.
+#   4) Removing remote backup tarballs (from the remote gateway) which are older
+#      than the number of days specified by the "REMOTE_DAYS_TO_KEEP" variable.
+#
+
+# Note: not using set -e in this script because more elaborate error handling
+# is needed.
+
+log_backup_error_exit() {
+  MSG=$1
+  ERRCODE=${2:-0}
+  log ERROR "${DB_NAME}_backup" "${DB_NAMESPACE} namespace: ${MSG}"
+  rm -f $ERR_LOG_FILE
+  rm -rf $TMP_DIR
+  exit $ERRCODE
+}
+
+log() {
+  #Log message to a file or stdout
+  #TODO: This can be convert into mail alert of alert send to a monitoring system
+  #Params: $1 log level
+  #Params: $2 service
+  #Params: $3 message
+  #Params: $4 Destination
+  LEVEL=$1
+  SERVICE=$2
+  MSG=$3
+  DEST=$4
+  DATE=$(date +"%m-%d-%y %H:%M:%S")
+  if [[ -z "$DEST" ]]; then
+    echo "${DATE} ${LEVEL}: $(hostname) ${SERVICE}: ${MSG}"
+  else
+    echo "${DATE} ${LEVEL}: $(hostname) ${SERVICE}: ${MSG}" >>$DEST
+  fi
+}
+
+# Generate a random number between MIN_DELAY_SEND_REMOTE and
+# MAX_DELAY_SEND_REMOTE
+random_number() {
+  diff=$((${MAX_DELAY_SEND_REMOTE} - ${MIN_DELAY_SEND_REMOTE} + 1))
+  echo $(($(( ${RANDOM} % ${diff} )) + ${MIN_DELAY_SEND_REMOTE} ))
+}
+
+#Get the day delta since the archive file backup
+seconds_difference() {
+  ARCHIVE_DATE=$( date --date="$1" +%s )
+  if [[ $? -ne 0 ]]; then
+    SECOND_DELTA=0
+  fi
+  CURRENT_DATE=$( date +%s )
+  SECOND_DELTA=$(($CURRENT_DATE-$ARCHIVE_DATE))
+  if [[ "$SECOND_DELTA" -lt 0 ]]; then
+    SECOND_DELTA=0
+  fi
+  echo $SECOND_DELTA
+}
+
+# Send the specified tarball file at the specified filepath to the
+# remote gateway.
+send_to_remote_server() {
+  FILEPATH=$1
+  FILE=$2
+
+  # Grab the list of containers on the remote site
+  RESULT=$(openstack container list 2>&1)
+
+  if [[ $? -eq 0 ]]; then
+    echo $RESULT | grep $CONTAINER_NAME
+    if [[ $? -ne 0 ]]; then
+      # Find the swift URL from the keystone endpoint list
+      SWIFT_URL=$(openstack catalog show object-store -c endpoints | grep public | awk '{print $4}')
+      if [[ $? -ne 0 ]]; then
+        log WARN "${DB_NAME}_backup" "Unable to get object-store enpoints from keystone catalog."
+        return 2
+      fi
+
+      # Get a token from keystone
+      TOKEN=$(openstack token issue -f value -c id)
+      if [[ $? -ne 0 ]]; then
+        log WARN "${DB_NAME}_backup" "Unable to get  keystone token."
+        return 2
+      fi
+
+      # Create the container
+      RES_FILE=$(mktemp -p /tmp)
+      curl -g -i -X PUT ${SWIFT_URL}/${CONTAINER_NAME} \
+           -H "X-Auth-Token: ${TOKEN}" \
+           -H "X-Storage-Policy: ${STORAGE_POLICY}" 2>&1 > $RES_FILE
+
+      if [[ $? -ne 0 || $(grep "HTTP" $RES_FILE | awk '{print $2}') -ge 400 ]]; then
+        log WARN "${DB_NAME}_backup" "Unable to create container ${CONTAINER_NAME}"
+        cat $RES_FILE
+        rm -f $RES_FILE
+        return 2
+      fi
+      rm -f $RES_FILE
+
+      swift stat $CONTAINER_NAME
+      if [[ $? -ne 0 ]]; then
+        log WARN "${DB_NAME}_backup" "Unable to retrieve container ${CONTAINER_NAME} details after creation."
+        return 2
+      fi
+    fi
+  else
+    echo $RESULT | grep -E "HTTP 401|HTTP 403"
+    if [[ $? -eq 0 ]]; then
+      log ERROR "${DB_NAME}_backup" "Access denied by keystone: ${RESULT}"
+      return 1
+    else
+      echo $RESULT | grep -E "ConnectionError|Failed to discover available identity versions|Service Unavailable|HTTP 50"
+      if [[ $? -eq 0 ]]; then
+        log WARN "${DB_NAME}_backup" "Could not reach the RGW: ${RESULT}"
+        # In this case, keystone or the site/node may be temporarily down.
+        # Return slightly different error code so the calling code can retry
+        return 2
+      else
+        log ERROR "${DB_NAME}_backup" "Could not get container list: ${RESULT}"
+        return 1
+      fi
+    fi
+  fi
+
+  # Create an object to store the file
+  openstack object create --name $FILE $CONTAINER_NAME $FILEPATH/$FILE
+  if [[ $? -ne 0 ]]; then
+    log WARN "${DB_NAME}_backup" "Cannot create container object ${FILE}!"
+    return 2
+  fi
+  openstack object show $CONTAINER_NAME $FILE
+  if [[ $? -ne 0 ]]; then
+    log WARN "${DB_NAME}_backup" "Unable to retrieve container object $FILE after creation."
+    return 2
+  fi
+
+  log INFO "${DB_NAME}_backup" "Created file $FILE in container $CONTAINER_NAME successfully."
+  return 0
+}
+
+# This function attempts to store the built tarball to the remote gateway,
+# with built-in logic to handle error cases like:
+#   1) Network connectivity issues - retries for a specific amount of time
+#   2) Authorization errors - immediately logs an ERROR and returns
+store_backup_remotely() {
+  FILEPATH=$1
+  FILE=$2
+
+  count=1
+  while [[ ${count} -le ${REMOTE_BACKUP_RETRIES} ]]; do
+    # Store the new archive to the remote backup storage facility.
+    send_to_remote_server $FILEPATH $FILE
+    SEND_RESULT="$?"
+
+    # Check if successful
+    if [[ $SEND_RESULT -eq 0 ]]; then
+      log INFO "${DB_NAME}_backup" "Backup file ${FILE} successfully sent to RGW."
+      return 0
+    elif [[ $SEND_RESULT -eq 2 ]]; then
+      if [[ ${count} -ge ${REMOTE_BACKUP_RETRIES} ]]; then
+        log ERROR "${DB_NAME}_backup" "Backup file ${FILE} could not be sent to the RGW in " \
+        "${REMOTE_BACKUP_RETRIES} retries. Errors encountered. Exiting."
+        break
+      fi
+      # Temporary failure occurred. We need to retry
+      log WARN "${DB_NAME}_backup" "Backup file ${FILE} could not be sent to RGW due to connection issue."
+      sleep_time=$(random_number)
+      log INFO "${DB_NAME}_backup" "Sleeping ${sleep_time} seconds waiting for RGW to become available..."
+      sleep ${sleep_time}
+      log INFO "${DB_NAME}_backup" "Retrying..."
+    else
+      log ERROR "${DB_NAME}_backup" "Backup file ${FILE} could not be sent to the RGW. Errors encountered. Exiting."
+      break
+    fi
+
+    # Increment the counter
+    count=$((count+1))
+  done
+
+  return 1
+}
+
+# This function takes a list of archives' names as an input
+# and creates a hash table where keys are number of seconds
+# between current date and archive date (see seconds_difference),
+# and values are space separated archives' names
+#
+# +------------+---------------------------------------------------------------------------------------------------------+
+# | 1265342678 | "tmp/mysql.backup.auto.2022-02-14T10:13:13Z.tar.gz"                                                     |
+# +------------+---------------------------------------------------------------------------------------------------------+
+# | 2346254257 | "tmp/mysql.backup.auto.2022-02-11T10:13:13Z.tar.gz tmp/mysql.backup.manual.2022-02-11T10:13:13Z.tar.gz" |
+# +------------+---------------------------------------------------------------------------------------------------------+
+# <...>
+# +------------+---------------------------------------------------------------------------------------------------------+
+# | 6253434567 | "tmp/mysql.backup.manual.2022-02-01T10:13:13Z.tar.gz"                                                   |
+# +------------+---------------------------------------------------------------------------------------------------------+
+# We will use the explained above data stracture to cover rare, but still
+# possible case, when we have several backups of the same date. E.g.
+# one manual, and one automatic.
+
+function get_archive_date(){
+# get_archive_date function returns correct archive date
+# for different formats of archives' names
+# the old one: <database name>.<namespace>.<table name | all>.<date-time>.tar.gz
+# the new one: <database name>.<namespace>.<table name | all>.<backup mode>.<date-time>.tar.gz
+local A_FILE="$1"
+local A_DATE=""
+if [[ -z ${BACK_UP_MODE} ]]; then
+  A_DATE=$( awk -F/ '{print $NF}' <<< ${ARCHIVE_FILE} | cut -d'.' -f 4 | tr -d "Z")
+else
+  A_DATE=$( awk -F/ '{print $NF}' <<< ${ARCHIVE_FILE} | cut -d'.' -f 5 | tr -d "Z")
+fi
+echo ${A_DATE}
+}
+
+declare -A fileTable
+create_hash_table() {
+unset fileTable
+fileList=$@
+  for ARCHIVE_FILE in ${fileList}; do
+    # Creating index, we will round given ARCHIVE_DATE to the midnight (00:00:00)
+    # to take in account a possibility, that we can have more than one scheduled
+    # backup per day.
+    ARCHIVE_DATE=$(get_archive_date ${ARCHIVE_FILE})
+    ARCHIVE_DATE=$(date --date=${ARCHIVE_DATE} +%D)
+    log INFO "${DB_NAME}_backup" "Archive date to build index: ${ARCHIVE_DATE}"
+    INDEX=$(seconds_difference ${ARCHIVE_DATE})
+    if [[ -z fileTable[${INDEX}] ]]; then
+      fileTable[${INDEX}]=${ARCHIVE_FILE}
+    else
+      fileTable[${INDEX}]="${fileTable[${INDEX}]} ${ARCHIVE_FILE}"
+    fi
+    echo "INDEX: ${INDEX} VALUE:  ${fileTable[${INDEX}]}"
+ done
+}
+
+function get_backup_prefix() {
+# Create list of all possible prefixes in a format:
+# <db_name>.<namespace> to cover a possible situation
+# when different backups of different databases and/or
+# namespaces share the same local or remote storage.
+  ALL_FILES=($@)
+  PREFIXES=()
+  for fname in ${ALL_FILES[@]}; do
+    prefix=$(basename ${fname} | cut -d'.' -f1,2 )
+    for ((i=0; i<${#PREFIXES[@]}; i++)) do
+      if [[ ${PREFIXES[${i}]} == ${prefix} ]]; then
+        prefix=""
+        break
+      fi
+    done
+    if [[ ! -z ${prefix} ]]; then
+        PREFIXES+=(${prefix})
+    fi
+  done
+}
+
+remove_old_local_archives() {
+  if [[ -d $ARCHIVE_DIR ]]; then
+    count=0
+    SECONDS_TO_KEEP=$((${LOCAL_DAYS_TO_KEEP}*86400))
+    log INFO "${DB_NAME}_backup" "Deleting backups older than ${LOCAL_DAYS_TO_KEEP} days"
+    # We iterate over the hash table, checking the delta in seconds (hash keys),
+    # and minimum number of backups we must have in place. List of keys has to be sorted.
+    for INDEX in $(tr " " "\n" <<< ${!FILETABLE[@]} | sort -n -); do
+      ARCHIVE_FILE=${FILETABLE[${INDEX}]}
+      if [[ ${INDEX} -le ${SECONDS_TO_KEEP} || ${count} -lt ${LOCAL_DAYS_TO_KEEP} ]]; then
+        ((count++))
+        log INFO "${DB_NAME}_backup" "Keeping file(s) ${ARCHIVE_FILE}."
+      else
+        log INFO "${DB_NAME}_backup" "Deleting file(s) ${ARCHIVE_FILE}."
+          rm -rf $ARCHIVE_FILE
+          if [[ $? -ne 0 ]]; then
+            # Log error but don't exit so we can finish the script
+            # because at this point we haven't sent backup to RGW yet
+            log ERROR "${DB_NAME}_backup" "Failed to cleanup local backup. Cannot remove some of ${ARCHIVE_FILE}"
+          fi
+      fi
+    done
+  else
+    log WARN "${DB_NAME}_backup" "The local backup directory ${$ARCHIVE_DIR} does not exist."
+  fi
+}
+
+remove_old_local_archives() {
+  SECONDS_TO_KEEP=$(( $((${LOCAL_DAYS_TO_KEEP}))*86400))
+  log INFO "${DB_NAME}_backup" "Deleting backups older than ${LOCAL_DAYS_TO_KEEP} days (${SECONDS_TO_KEEP} seconds)"
+  if [[ -d $ARCHIVE_DIR ]]; then
+    count=0
+    # We iterate over the hash table, checking the delta in seconds (hash keys),
+    # and minimum number of backups we must have in place. List of keys has to be sorted.
+    for INDEX in $(tr " " "\n" <<< ${!fileTable[@]} | sort -n -); do
+      ARCHIVE_FILE=${fileTable[${INDEX}]}
+      if [[ ${INDEX} -lt ${SECONDS_TO_KEEP} || ${count} -lt ${LOCAL_DAYS_TO_KEEP} ]]; then
+        ((count++))
+        log INFO "${DB_NAME}_backup" "Keeping file(s) ${ARCHIVE_FILE}."
+      else
+        log INFO "${DB_NAME}_backup" "Deleting file(s) ${ARCHIVE_FILE}."
+          rm -f ${ARCHIVE_FILE}
+          if [[ $? -ne 0 ]]; then
+            # Log error but don't exit so we can finish the script
+            # because at this point we haven't sent backup to RGW yet
+            log ERROR "${DB_NAME}_backup" "Failed to cleanup local backup. Cannot remove some of ${ARCHIVE_FILE}"
+          fi
+      fi
+    done
+  else
+    log WARN "${DB_NAME}_backup" "The local backup directory ${$ARCHIVE_DIR} does not exist."
+  fi
+}
+
+prepare_list_of_remote_backups() {
+  BACKUP_FILES=$(mktemp -p /tmp)
+  DB_BACKUP_FILES=$(mktemp -p /tmp)
+  openstack object list $CONTAINER_NAME > $BACKUP_FILES
+  if [[ $? -ne 0 ]]; then
+    log_backup_error_exit \
+      "Failed to cleanup remote backup. Could not obtain a list of current backup files in the RGW"
+  fi
+  # Filter out other types of backup files
+  cat $BACKUP_FILES | grep $DB_NAME | grep $DB_NAMESPACE | awk '{print $2}' > $DB_BACKUP_FILES
+}
+
+# The logic implemented with this function is absolutely similar
+# to the function remove_old_local_archives (see above)
+remove_old_remote_archives() {
+  count=0
+  SECONDS_TO_KEEP=$((${REMOTE_DAYS_TO_KEEP}*86400))
+  log INFO "${DB_NAME}_backup" "Deleting backups older than ${REMOTE_DAYS_TO_KEEP} days (${SECONDS_TO_KEEP} seconds)"
+  for INDEX in $(tr " " "\n" <<< ${!FILETABLE[@]} | sort -n -); do
+    ARCHIVE_FILE=${FILETABLE[${INDEX}]}
+    if [[ ${INDEX} -lt ${SECONDS_TO_KEEP} || ${count} -lt ${REMOTE_DAYS_TO_KEEP} ]]; then
+      ((count++))
+      log INFO "${DB_NAME}_backup" "Keeping remote backup(s) ${ARCHIVE_FILE}."
+    else
+      log INFO "${DB_NAME}_backup" "Deleting remote backup(s) ${ARCHIVE_FILE} from the RGW"
+      openstack object delete ${CONTAINER_NAME} ${ARCHIVE_FILE} ||  log WARN "${DB_NAME}_backup" \
+        "Failed to cleanup remote backup. Cannot delete container object ${ARCHIVE_FILE}"
+    fi
+  done
+
+  # Cleanup now that we're done.
+  for fd in ${BACKUP_FILES} ${DB_BACKUP_FILES}; do
+  if [[ -f fd ]]; then
+    rm -f fd
+  else
+    log WARN "${DB_NAME}_backup" "Can not delete a temporary file ${fd}"
+}
+
+# Main function to backup the databases. Calling functions need to supply:
+#  1) The directory where the final backup will be kept after it is compressed.
+#  2) A temporary directory to use for placing database files to be compressed.
+#     Note: this temp directory will be deleted after backup is done.
+#  3) Optional "scope" parameter indicating what database to back up. Defaults
+#     to "all".
+backup_databases() {
+  SCOPE=${1:-"all"}
+
+  # Create necessary directories if they do not exist.
+  mkdir -p $ARCHIVE_DIR || log_backup_error_exit \
+    "Backup of the ${DB_NAME} database failed. Cannot create directory ${ARCHIVE_DIR}!"
+  export TMP_DIR=$(mktemp -d) || log_backup_error_exit \
+    "Backup of the ${DB_NAME} database failed. Cannot create temp directory!"
+
+  # Create temporary log file
+  export ERR_LOG_FILE=$(mktemp -p /tmp) || log_backup_error_exit \
+    "Backup of the ${DB_NAME} database failed. Cannot create log file!"
+
+  # It is expected that this function will dump the database files to the $TMP_DIR
+  dump_databases_to_directory $TMP_DIR $ERR_LOG_FILE $SCOPE
+
+  # If successful, there should be at least one file in the TMP_DIR
+  if [[ $? -ne 0 || $(ls $TMP_DIR | wc -w) -eq 0 ]]; then
+    cat $ERR_LOG_FILE
+    log_backup_error_exit "Backup of the ${DB_NAME} database failed and needs attention."
+  fi
+
+  log INFO "${DB_NAME}_backup" "Databases dumped successfully. Creating tarball..."
+
+  NOW=$(date +"%Y-%m-%dT%H:%M:%SZ")
+  if [[ -z "${BACK_UP_MODE}" ]]; then
+    TARBALL_FILE="${DB_NAME}.${DB_NAMESPACE}.${SCOPE}.${NOW}.tar.gz"
+  else
+    TARBALL_FILE="${DB_NAME}.${DB_NAMESPACE}.${SCOPE}.${BACK_UP_MODE}.${NOW}.tar.gz"
+  fi
+
+  cd $TMP_DIR || log_backup_error_exit \
+    "Backup of the ${DB_NAME} database failed. Cannot change to directory $TMP_DIR"
+
+  #Archive the current database files
+  tar zcvf $ARCHIVE_DIR/$TARBALL_FILE *
+  if [[ $? -ne 0 ]]; then
+    log_backup_error_exit \
+      "Backup ${DB_NAME} to local file system failed. Backup tarball could not be created."
+  fi
+
+  # Get the size of the file
+  ARCHIVE_SIZE=$(ls -l $ARCHIVE_DIR/$TARBALL_FILE | awk '{print $5}')
+
+  log INFO "${DB_NAME}_backup" "Tarball $TARBALL_FILE created successfully."
+
+  cd $ARCHIVE_DIR
+
+  # Remove the temporary directory and files as they are no longer needed.
+  rm -rf $TMP_DIR
+  rm -f $ERR_LOG_FILE
+
+  #Only delete the old archive after a successful archive
+  export LOCAL_DAYS_TO_KEEP=$(echo $LOCAL_DAYS_TO_KEEP | sed 's/"//g')
+  if [[ "$LOCAL_DAYS_TO_KEEP" -gt 0 ]]; then
+    get_backup_prefix $(ls -1 ${ARCHIVE_DIR}/*.gz)
+    for ((i=0; i<${#PREFIXES[@]}; i++)); do
+      echo "Working with prefix: ${PREFIXES[i]}"
+      create_hash_table $(ls -1 ${ARCHIVE_DIR}/${PREFIXES[i]}*.gz)
+      remove_old_local_archives
+    done
+  fi
+
+  REMOTE_BACKUP=$(echo $REMOTE_BACKUP_ENABLED | sed 's/"//g')
+  if $REMOTE_BACKUP; then
+    # Remove Quotes from the constants which were added due to reading
+    # from secret.
+    export REMOTE_BACKUP_RETRIES=$(echo $REMOTE_BACKUP_RETRIES | sed 's/"//g')
+    export MIN_DELAY_SEND_REMOTE=$(echo $MIN_DELAY_SEND_REMOTE | sed 's/"//g')
+    export MAX_DELAY_SEND_REMOTE=$(echo $MAX_DELAY_SEND_REMOTE | sed 's/"//g')
+    export REMOTE_DAYS_TO_KEEP=$(echo $REMOTE_DAYS_TO_KEEP | sed 's/"//g')
+
+    store_backup_remotely $ARCHIVE_DIR $TARBALL_FILE
+    if [[ $? -ne 0 ]]; then
+      # This error should print first, then print the summary as the last
+      # thing that the user sees in the output.
+      log ERROR "${DB_NAME}_backup" "Backup ${TARBALL_FILE} could not be sent to remote RGW."
+      echo "=================================================================="
+      echo "Local backup successful, but could not send to remote RGW."
+      echo "Backup archive name: $TARBALL_FILE"
+      echo "Backup archive size: $ARCHIVE_SIZE"
+      echo "=================================================================="
+      # Because the local backup was successful, exit with 0 so the pod will not
+      # continue to restart and fill the disk with more backups. The ERRORs are
+      # logged and alerting system should catch those errors and flag the operator.
+      exit 0
+    fi
+
+    #Only delete the old archive after a successful archive
+    if [[ "$REMOTE_DAYS_TO_KEEP" -gt 0 ]]; then
+      prepare_list_of_remote_backups
+      create_hash_table $(cat $DB_BACKUP_FILES)
+      remove_old_remote_archives
+    fi
+
+    echo "=================================================================="
+    echo "Local backup and backup to remote RGW successful!"
+    echo "Backup archive name: $TARBALL_FILE"
+    echo "Backup archive size: $ARCHIVE_SIZE"
+    echo "=================================================================="
+  else
+    # Remote backup is not enabled. This is ok; at least we have a local backup.
+    log INFO "${DB_NAME}_backup" "Skipping remote backup, as it is not enabled."
+
+    echo "=================================================================="
+    echo "Local backup successful!"
+    echo "Backup archive name: $TARBALL_FILE"
+    echo "Backup archive size: $ARCHIVE_SIZE"
+    echo "=================================================================="
+  fi
+}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/scripts/db-backup-restore/_restore_main.sh.tpl b/charts/nova/charts/helm-toolkit/templates/scripts/db-backup-restore/_restore_main.sh.tpl
new file mode 100644
index 0000000..093dd2c
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/scripts/db-backup-restore/_restore_main.sh.tpl
@@ -0,0 +1,616 @@
+{{- define "helm-toolkit.scripts.db-backup-restore.restore_main" }}
+#!/bin/bash
+
+# This file contains a database restore framework which database scripts
+# can use to perform a backup. The idea here is that the database-specific
+# functions will be implemented by the various databases using this script
+# (like mariadb, postgresql or etcd for example). The database-specific
+# script will need to first "source" this file like this:
+#   source /tmp/restore_main.sh
+#
+# Then the script should call the main CLI function (cli_main):
+#   cli_main <arg_list>
+#       where:
+#         <arg_list>    is the list of arguments given by the user
+#
+#       The framework will require the following variables to be exported:
+#
+#         export DB_NAMESPACE        Namespace where the database(s) reside
+#         export DB_NAME             Name of the database system
+#         export ARCHIVE_DIR         Location where the backup tarballs should
+#                                    be stored. (full directory path which
+#                                    should already exist)
+#         export CONTAINER_NAME      Name of the container on the RGW where
+#                                    the backups are stored.
+#         RGW access variables:
+#           export OS_REGION_NAME          Name of the region the RGW resides in
+#           export OS_AUTH_URL             Keystone URL associated with the RGW
+#           export OS_PROJECT_NAME         Name of the project associated with the
+#                                          keystone user
+#           export OS_USERNAME             Name of the keystone user
+#           export OS_PASSWORD             Password of the keystone user
+#           export OS_USER_DOMAIN_NAME     Keystone domain the project belongs to
+#           export OS_PROJECT_DOMAIN_NAME  Keystone domain the user belongs to
+#           export OS_IDENTITY_API_VERSION Keystone API version to use
+#
+# The database-specific functions that need to be implemented are:
+#   get_databases
+#       where:
+#         <tmp_dir>     is the full directory path where the decompressed
+#                       database files reside
+#         <db_file>     is the full path of the file to write the database
+#                       names into, one database per line
+#       returns: 0 if no errors; 1 if any errors occurred
+#
+#       This function is expected to extract the database names from the
+#       uncompressed database files found in the given "tmp_dir", which is
+#       the staging directory for database restore. The database names
+#       should be written to the given "db_file", one database name per
+#       line.
+#
+#   get_tables
+#         <db_name>     is the name of the database to get the tables from
+#         <tmp_dir>     is the full directory path where the decompressed
+#                       database files reside
+#         <table_file>  is the full path of the file to write the table
+#                       names into, one table per line
+#       returns: 0 if no errors; 1 if any errors occurred
+#
+#       This function is expected to extract the table names from the given
+#       database, found in the uncompressed database files located in the
+#       given "tmp_dir", which is the staging directory for database restore.
+#       The table names should be written to the given "table_file", one
+#       table name per line.
+#
+#   get_rows
+#         <table_name>  is the name of the table to get the rows from
+#         <db_name>     is the name of the database the table resides in
+#         <tmp_dir>     is the full directory path where the decompressed
+#                       database files reside
+#         <rows_file>   is the full path of the file to write the table
+#                       row data into, one row (INSERT statement) per line
+#       returns: 0 if no errors; 1 if any errors occurred
+#
+#       This function is expected to extract the rows from the given table
+#       in the given database, found in the uncompressed database files
+#       located in the given "tmp_dir", which is the staging directory for
+#       database restore. The table rows should be written to the given
+#       "rows_file", one row (INSERT statement) per line.
+#
+#   get_schema
+#         <table_name>  is the name of the table to get the schema from
+#         <db_name>     is the name of the database the table resides in
+#         <tmp_dir>     is the full directory path where the decompressed
+#                       database files reside
+#         <schema_file> is the full path of the file to write the table
+#                       schema data into
+#       returns: 0 if no errors; 1 if any errors occurred
+#
+#       This function is expected to extract the schema from the given table
+#       in the given database, found in the uncompressed database files
+#       located in the given "tmp_dir", which is the staging directory for
+#       database restore. The table schema and related alterations and
+#       grant information should be written to the given "schema_file".
+#
+#   restore_single_db
+#       where:
+#         <db_name>     is the name of the database to be restored
+#         <tmp_dir>     is the full directory path where the decompressed
+#                       database files reside
+#       returns: 0 if no errors; 1 if any errors occurred
+#
+#       This function is expected to restore the database given as "db_name"
+#       using the database files located in the "tmp_dir". The framework
+#       will delete the "tmp_dir" and the files in it after the restore is
+#       complete.
+#
+#   restore_all_dbs
+#       where:
+#         <tmp_dir>     is the full directory path where the decompressed
+#                       database files reside
+#       returns: 0 if no errors; 1 if any errors occurred
+#
+#       This function is expected to restore all of the databases which
+#       are backed up in the database files located in the "tmp_dir". The
+#       framework will delete the "tmp_dir" and the files in it after the
+#       restore is complete.
+#
+# The functions in this file will take care of:
+#   1) The CLI parameter parsing for the arguments passed in by the user.
+#   2) The listing of either local or remote archive files at the request
+#      of the user.
+#   3) The retrieval/download of an archive file located either in the local
+#      file system or remotely stored on an RGW.
+#   4) Calling either "restore_single_db" or "restore_all_dbs" when the user
+#      chooses to restore a database or all databases.
+#   5) The framework will call "get_databases" when it needs a list of
+#      databases when the user requests a database list or when the user
+#      requests to restore a single database (to ensure it exists in the
+#      archive). Similarly, the framework will call "get_tables", "get_rows",
+#      or "get_schema" when it needs that data requested by the user.
+#
+
+usage() {
+  ret_val=$1
+  echo "Usage:"
+  echo "Restore command options"
+  echo "============================="
+  echo "help"
+  echo "list_archives [remote]"
+  echo "list_databases <archive_filename> [remote]"
+  echo "list_tables <archive_filename> <dbname> [remote]"
+  echo "list_rows <archive_filename> <dbname> <table_name> [remote]"
+  echo "list_schema <archive_filename> <dbname> <table_name> [remote]"
+  echo "restore <archive_filename> <db_specifier> [remote]"
+  echo "        where <db_specifier> = <dbname> | ALL"
+  echo "delete_archive <archive_filename> [remote]"
+  clean_and_exit $ret_val ""
+}
+
+#Exit cleanly with some message and return code
+clean_and_exit() {
+  RETCODE=$1
+  MSG=$2
+
+  # Clean/remove temporary directories/files
+  rm -rf $TMP_DIR
+  rm -f $RESULT_FILE
+
+  if [[ "x${MSG}" != "x" ]]; then
+    echo $MSG
+  fi
+  exit $RETCODE
+}
+
+determine_resulting_error_code() {
+  RESULT="$1"
+
+  echo ${RESULT} | grep "HTTP 404"
+  if [[ $? -eq 0 ]]; then
+    echo "Could not find the archive: ${RESULT}"
+    return 1
+  else
+    echo ${RESULT} | grep "HTTP 401"
+    if [[ $? -eq 0 ]]; then
+      echo "Could not access the archive: ${RESULT}"
+      return 1
+    else
+      echo ${RESULT} | grep "HTTP 503"
+      if [[ $? -eq 0 ]]; then
+        echo "RGW service is unavailable. ${RESULT}"
+        # In this case, the RGW may be temporarily down.
+        # Return slightly different error code so the calling code can retry
+        return 2
+      else
+        echo ${RESULT} | grep "ConnectionError"
+        if [[ $? -eq 0 ]]; then
+          echo "Could not reach the RGW: ${RESULT}"
+          # In this case, keystone or the site/node may be temporarily down.
+          # Return slightly different error code so the calling code can retry
+          return 2
+        else
+          echo "Archive ${ARCHIVE} could not be retrieved: ${RESULT}"
+          return 1
+        fi
+      fi
+    fi
+  fi
+  return 0
+}
+
+# Retrieve a list of archives from the RGW.
+retrieve_remote_listing() {
+  RESULT=$(openstack container show $CONTAINER_NAME 2>&1)
+  if [[ $? -eq 0 ]]; then
+    # Get the list, ensureing that we only pick up the right kind of backups from the
+    # requested namespace
+    openstack object list $CONTAINER_NAME | grep $DB_NAME | grep $DB_NAMESPACE | awk '{print $2}' > $TMP_DIR/archive_list
+    if [[ $? -ne 0 ]]; then
+      echo "Container object listing could not be obtained."
+      return 1
+    else
+      echo "Archive listing successfully retrieved."
+    fi
+  else
+    determine_resulting_error_code "${RESULT}"
+    return $?
+  fi
+  return 0
+}
+
+# Retrieve a single archive from the RGW.
+retrieve_remote_archive() {
+  ARCHIVE=$1
+
+  RESULT=$(openstack object save --file $TMP_DIR/$ARCHIVE $CONTAINER_NAME $ARCHIVE 2>&1)
+  if [[ $? -ne 0 ]]; then
+    determine_resulting_error_code "${RESULT}"
+    return $?
+  else
+    echo "Archive $ARCHIVE successfully retrieved."
+  fi
+  return 0
+}
+
+# Delete an archive from the RGW.
+delete_remote_archive() {
+  ARCHIVE=$1
+
+  RESULT=$(openstack object delete ${CONTAINER_NAME} ${ARCHIVE} 2>&1)
+  if [[ $? -ne 0 ]]; then
+    determine_resulting_error_code "${RESULT}"
+    return $?
+  else
+    echo "Archive ${ARCHIVE} successfully deleted."
+  fi
+  return 0
+}
+
+# Display all archives
+list_archives() {
+  REMOTE=$1
+
+  if [[ "x${REMOTE^^}" == "xREMOTE" ]]; then
+    retrieve_remote_listing
+    if [[ $? -eq 0 && -e $TMP_DIR/archive_list ]]; then
+      echo
+      echo "All Archives from RGW Data Store"
+      echo "=============================================="
+      cat $TMP_DIR/archive_list | sort
+      clean_and_exit 0 ""
+    else
+      clean_and_exit 1 "ERROR: Archives could not be retrieved from the RGW."
+    fi
+  elif [[ "x${REMOTE}" == "x" ]]; then
+    if [[ -d $ARCHIVE_DIR ]]; then
+      archives=$(find $ARCHIVE_DIR/ -iname "*.gz" -print | sort)
+      echo
+      echo "All Local Archives"
+      echo "=============================================="
+      for archive in $archives
+      do
+        echo $archive | cut -d '/' -f8-
+      done
+      clean_and_exit 0 ""
+    else
+      clean_and_exit 1 "ERROR: Local archive directory is not available."
+    fi
+  else
+    usage 1
+  fi
+}
+
+# Retrieve the archive from the desired location and decompress it into
+# the restore directory
+get_archive() {
+  ARCHIVE_FILE=$1
+  REMOTE=$2
+
+  if [[ "x$REMOTE" == "xremote" ]]; then
+    echo "Retrieving archive ${ARCHIVE_FILE} from the remote RGW..."
+    retrieve_remote_archive $ARCHIVE_FILE
+    if [[ $? -ne 0 ]]; then
+      clean_and_exit 1 "ERROR: Could not retrieve remote archive: $ARCHIVE_FILE"
+    fi
+  elif [[ "x$REMOTE" == "x" ]]; then
+    if [[ -e $ARCHIVE_DIR/$ARCHIVE_FILE ]]; then
+      cp $ARCHIVE_DIR/$ARCHIVE_FILE $TMP_DIR/$ARCHIVE_FILE
+      if [[ $? -ne 0 ]]; then
+        clean_and_exit 1 "ERROR: Could not copy local archive to restore directory."
+      fi
+    else
+      clean_and_exit 1 "ERROR: Local archive file could not be found."
+    fi
+  else
+    usage 1
+  fi
+
+  echo "Decompressing archive $ARCHIVE_FILE..."
+  cd $TMP_DIR
+  tar zxvf - < $TMP_DIR/$ARCHIVE_FILE 1>/dev/null
+  if [[ $? -ne 0 ]]; then
+    clean_and_exit 1 "ERROR: Archive decompression failed."
+  fi
+}
+
+# Display all databases from an archive
+list_databases() {
+  ARCHIVE_FILE=$1
+  REMOTE=$2
+  WHERE="local"
+
+  if [[ -n ${REMOTE} ]]; then
+    WHERE="remote"
+  fi
+
+  # Get the archive from the source location (local/remote)
+  get_archive $ARCHIVE_FILE $REMOTE
+
+  # Expectation is that the database listing will be put into
+  # the given file one database per line
+  get_databases $TMP_DIR $RESULT_FILE
+  if [[ "$?" -ne 0 ]]; then
+    clean_and_exit 1 "ERROR: Could not retrieve databases from $WHERE archive $ARCHIVE_FILE."
+  fi
+
+  if [[ -f "$RESULT_FILE" ]]; then
+    echo " "
+    echo "Databases in the $WHERE archive $ARCHIVE_FILE"
+    echo "================================================================================"
+    cat $RESULT_FILE
+  else
+    clean_and_exit 1 "ERROR: Databases file missing. Could not list databases from $WHERE archive $ARCHIVE_FILE."
+  fi
+}
+
+# Display all tables of a database from an archive
+list_tables() {
+  ARCHIVE_FILE=$1
+  DATABASE=$2
+  REMOTE=$3
+  WHERE="local"
+
+  if [[ -n ${REMOTE} ]]; then
+    WHERE="remote"
+  fi
+
+  # Get the archive from the source location (local/remote)
+  get_archive $ARCHIVE_FILE $REMOTE
+
+  # Expectation is that the database listing will be put into
+  # the given file one table per line
+  get_tables $DATABASE $TMP_DIR $RESULT_FILE
+  if [[ "$?" -ne 0 ]]; then
+    clean_and_exit 1 "ERROR: Could not retrieve tables for database ${DATABASE} from $WHERE archive $ARCHIVE_FILE."
+  fi
+
+  if [[ -f "$RESULT_FILE" ]]; then
+    echo " "
+    echo "Tables in database $DATABASE from $WHERE archive $ARCHIVE_FILE"
+    echo "================================================================================"
+    cat $RESULT_FILE
+  else
+    clean_and_exit 1 "ERROR: Tables file missing. Could not list tables of database ${DATABASE} from $WHERE archive $ARCHIVE_FILE."
+  fi
+}
+
+# Display all rows of the given database table from an archive
+list_rows() {
+  ARCHIVE_FILE=$1
+  DATABASE=$2
+  TABLE=$3
+  REMOTE=$4
+  WHERE="local"
+
+  if [[ -n ${REMOTE} ]]; then
+    WHERE="remote"
+  fi
+
+  # Get the archive from the source location (local/remote)
+  get_archive $ARCHIVE_FILE $REMOTE
+
+  # Expectation is that the database listing will be put into
+  # the given file one table per line
+  get_rows $DATABASE $TABLE $TMP_DIR $RESULT_FILE
+  if [[ "$?" -ne 0 ]]; then
+    clean_and_exit 1 "ERROR: Could not retrieve rows in table ${TABLE} of database ${DATABASE} from $WHERE archive $ARCHIVE_FILE."
+  fi
+
+  if [[ -f "$RESULT_FILE" ]]; then
+    echo " "
+    echo "Rows in table $TABLE of database $DATABASE from $WHERE archive $ARCHIVE_FILE"
+    echo "================================================================================"
+    cat $RESULT_FILE
+  else
+    clean_and_exit 1 "ERROR: Rows file missing. Could not list rows in table ${TABLE} of database ${DATABASE} from $WHERE archive $ARCHIVE_FILE."
+  fi
+}
+
+# Display the schema information of the given database table from an archive
+list_schema() {
+  ARCHIVE_FILE=$1
+  DATABASE=$2
+  TABLE=$3
+  REMOTE=$4
+  WHERE="local"
+
+  if [[ -n ${REMOTE} ]]; then
+    WHERE="remote"
+  fi
+
+  # Get the archive from the source location (local/remote)
+  get_archive $ARCHIVE_FILE $REMOTE
+
+  # Expectation is that the schema information will be placed into
+  # the given schema file.
+  get_schema $DATABASE $TABLE $TMP_DIR $RESULT_FILE
+  if [[ "$?" -ne 0 ]]; then
+    clean_and_exit 1 "ERROR: Could not retrieve schema for table ${TABLE} of database ${DATABASE} from $WHERE archive $ARCHIVE_FILE."
+  fi
+
+  if [[ -f "$RESULT_FILE" ]]; then
+    echo " "
+    echo "Schema for table $TABLE of database $DATABASE from $WHERE archive $ARCHIVE_FILE"
+    echo "================================================================================"
+    cat $RESULT_FILE
+  else
+    clean_and_exit 1 "ERROR: Schema file missing. Could not list schema for table ${TABLE} of database ${DATABASE} from $WHERE archive $ARCHIVE_FILE."
+  fi
+}
+
+# Delete an archive
+delete_archive() {
+  ARCHIVE_FILE=$1
+  REMOTE=$2
+  WHERE="local"
+
+  if [[ -n ${REMOTE} ]]; then
+    WHERE="remote"
+  fi
+
+  if [[ "${WHERE}" == "remote" ]]; then
+    delete_remote_archive ${ARCHIVE_FILE}
+    if [[ $? -ne 0 ]]; then
+      clean_and_exit 1 "ERROR: Could not delete remote archive: ${ARCHIVE_FILE}"
+    fi
+  else # Local
+    if [[ -e ${ARCHIVE_DIR}/${ARCHIVE_FILE} ]]; then
+      rm -f ${ARCHIVE_DIR}/${ARCHIVE_FILE}
+      if [[ $? -ne 0 ]]; then
+        clean_and_exit 1 "ERROR: Could not delete local archive."
+      fi
+    else
+      clean_and_exit 1 "ERROR: Local archive file could not be found."
+    fi
+  fi
+
+  echo "Successfully deleted archive ${ARCHIVE_FILE} from ${WHERE} storage."
+}
+
+
+# Return 1 if the given database exists in the database file. 0 otherwise.
+database_exists() {
+  DB=$1
+
+  grep "${DB}" ${RESULT_FILE}
+  if [[ $? -eq 0 ]]; then
+    return 1
+  fi
+  return 0
+}
+
+# This is the main CLI interpreter function
+cli_main() {
+  ARGS=("$@")
+
+  # Create the ARCHIVE DIR if it's not already there.
+  mkdir -p $ARCHIVE_DIR
+
+  # Create temp directory for a staging area to decompress files into
+  export TMP_DIR=$(mktemp -d)
+
+  # Create a temp file for storing list of databases (if needed)
+  export RESULT_FILE=$(mktemp -p /tmp)
+
+  case "${ARGS[0]}" in
+    "help")
+      usage 0
+      ;;
+
+    "list_archives")
+      if [[ ${#ARGS[@]} -gt 2 ]]; then
+        usage 1
+      elif [[ ${#ARGS[@]} -eq 1 ]]; then
+        list_archives
+      else
+        list_archives ${ARGS[1]}
+      fi
+      clean_and_exit 0
+      ;;
+
+    "list_databases")
+      if [[ ${#ARGS[@]} -lt 2 || ${#ARGS[@]} -gt 3 ]]; then
+        usage 1
+      elif [[ ${#ARGS[@]} -eq 2 ]]; then
+        list_databases ${ARGS[1]}
+      else
+        list_databases ${ARGS[1]} ${ARGS[2]}
+      fi
+      ;;
+
+    "list_tables")
+      if [[ ${#ARGS[@]} -lt 3 || ${#ARGS[@]} -gt 4 ]]; then
+        usage 1
+      elif [[ ${#ARGS[@]} -eq 3 ]]; then
+        list_tables ${ARGS[1]} ${ARGS[2]}
+      else
+        list_tables ${ARGS[1]} ${ARGS[2]} ${ARGS[3]}
+      fi
+      ;;
+
+    "list_rows")
+      if [[ ${#ARGS[@]} -lt 4 || ${#ARGS[@]} -gt 5 ]]; then
+        usage 1
+      elif [[ ${#ARGS[@]} -eq 4 ]]; then
+        list_rows ${ARGS[1]} ${ARGS[2]} ${ARGS[3]}
+      else
+        list_rows ${ARGS[1]} ${ARGS[2]} ${ARGS[3]} ${ARGS[4]}
+      fi
+      ;;
+
+    "list_schema")
+      if [[ ${#ARGS[@]} -lt 4 || ${#ARGS[@]} -gt 5 ]]; then
+        usage 1
+      elif [[ ${#ARGS[@]} -eq 4 ]]; then
+        list_schema ${ARGS[1]} ${ARGS[2]} ${ARGS[3]}
+      else
+        list_schema ${ARGS[1]} ${ARGS[2]} ${ARGS[3]} ${ARGS[4]}
+      fi
+      ;;
+
+    "restore")
+      REMOTE=""
+      if [[ ${#ARGS[@]} -lt 3 || ${#ARGS[@]} -gt 4 ]]; then
+        usage 1
+      elif [[ ${#ARGS[@]} -eq 4 ]]; then
+        REMOTE=${ARGS[3]}
+      fi
+
+      ARCHIVE=${ARGS[1]}
+      DB_SPEC=${ARGS[2]}
+
+      #Get all the databases in that archive
+      get_archive $ARCHIVE $REMOTE
+
+      if [[ "$( echo $DB_SPEC | tr '[a-z]' '[A-Z]')" != "ALL" ]]; then
+        # Expectation is that the database listing will be put into
+        # the given file one database per line
+        get_databases $TMP_DIR $RESULT_FILE
+        if [[ "$?" -ne 0 ]]; then
+          clean_and_exit 1 "ERROR: Could not get the list of databases to restore."
+        fi
+
+        if [[ ! $DB_NAMESPACE == "kube-system" ]]; then
+          #check if the requested database is available in the archive
+          database_exists $DB_SPEC
+          if [[ $? -ne 1 ]]; then
+            clean_and_exit 1 "ERROR: Database ${DB_SPEC} does not exist."
+          fi
+        fi
+
+        echo "Restoring Database $DB_SPEC And Grants"
+        restore_single_db $DB_SPEC $TMP_DIR
+        if [[ "$?" -eq 0 ]]; then
+          echo "Single database restored successfully."
+        else
+          clean_and_exit 1 "ERROR: Single database restore failed."
+        fi
+        clean_and_exit 0 ""
+      else
+        echo "Restoring All The Databases. This could take a few minutes..."
+        restore_all_dbs $TMP_DIR
+        if [[ "$?" -eq 0 ]]; then
+          echo "All databases restored successfully."
+        else
+          clean_and_exit 1 "ERROR: Database restore failed."
+        fi
+        clean_and_exit 0 ""
+      fi
+      ;;
+    "delete_archive")
+      if [[ ${#ARGS[@]} -lt 2 || ${#ARGS[@]} -gt 3 ]]; then
+        usage 1
+      elif [[ ${#ARGS[@]} -eq 2 ]]; then
+        delete_archive ${ARGS[1]}
+      else
+        delete_archive ${ARGS[1]} ${ARGS[2]}
+      fi
+      ;;
+    *)
+      usage 1
+      ;;
+  esac
+
+  clean_and_exit 0 ""
+}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_image.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_image.tpl
new file mode 100644
index 0000000..029c93d
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_image.tpl
@@ -0,0 +1,60 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Resolves an image reference to a string, and its pull policy
+values: |
+  images:
+    tags:
+      test_image: docker.io/port/test:version-foo
+      image_foo: quay.io/airshipit/kubernetes-entrypoint:v1.0.0
+    pull_policy: IfNotPresent
+    local_registry:
+      active: true
+      exclude:
+        - image_foo
+  endpoints:
+    cluster_domain_suffix: cluster.local
+    local_image_registry:
+      name: docker-registry
+      namespace: docker-registry
+      hosts:
+        default: localhost
+        internal: docker-registry
+        node: localhost
+      host_fqdn_override:
+        default: null
+      port:
+        registry:
+          node: 5000
+usage: |
+  {{ tuple . "test_image" | include "helm-toolkit.snippets.image" }}
+return: |
+  image: "localhost:5000/docker.io/port/test:version-foo"
+  imagePullPolicy: IfNotPresent
+*/}}
+
+{{- define "helm-toolkit.snippets.image" -}}
+{{- $envAll := index . 0 -}}
+{{- $image := index . 1 -}}
+{{- $imageTag := index $envAll.Values.images.tags $image -}}
+{{- if and ($envAll.Values.images.local_registry.active) (not (has $image $envAll.Values.images.local_registry.exclude )) -}}
+{{- $registryPrefix := printf "%s:%s" (tuple "local_image_registry" "node" $envAll | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup") (tuple "local_image_registry" "node" "registry" $envAll | include "helm-toolkit.endpoints.endpoint_port_lookup") -}}
+image: {{ printf "%s/%s" $registryPrefix $imageTag | quote }}
+{{- else -}}
+image: {{ $imageTag | quote }}
+{{- end }}
+imagePullPolicy: {{ $envAll.Values.images.pull_policy }}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_keystone_openrc_env_vars.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_keystone_openrc_env_vars.tpl
new file mode 100644
index 0000000..2f209fe
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_keystone_openrc_env_vars.tpl
@@ -0,0 +1,142 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Returns a set of container enviorment variables, equivlant to an openrc for
+  use with keystone based command line clients.
+values: |
+  secrets:
+    identity:
+      admin: example-keystone-admin
+usage: |
+  {{ include "helm-toolkit.snippets.keystone_openrc_env_vars" ( dict "ksUserSecret" .Values.secrets.identity.admin ) }}
+return: |
+  - name: OS_IDENTITY_API_VERSION
+    value: "3"
+  - name: OS_AUTH_URL
+    valueFrom:
+      secretKeyRef:
+        name: example-keystone-admin
+        key: OS_AUTH_URL
+  - name: OS_REGION_NAME
+    valueFrom:
+      secretKeyRef:
+        name: example-keystone-admin
+        key: OS_REGION_NAME
+  - name: OS_INTERFACE
+    valueFrom:
+      secretKeyRef:
+        name: example-keystone-admin
+        key: OS_INTERFACE
+  - name: OS_ENDPOINT_TYPE
+    valueFrom:
+      secretKeyRef:
+        name: example-keystone-admin
+        key: OS_INTERFACE
+  - name: OS_PROJECT_DOMAIN_NAME
+    valueFrom:
+      secretKeyRef:
+        name: example-keystone-admin
+        key: OS_PROJECT_DOMAIN_NAME
+  - name: OS_PROJECT_NAME
+    valueFrom:
+      secretKeyRef:
+        name: example-keystone-admin
+        key: OS_PROJECT_NAME
+  - name: OS_USER_DOMAIN_NAME
+    valueFrom:
+      secretKeyRef:
+        name: example-keystone-admin
+        key: OS_USER_DOMAIN_NAME
+  - name: OS_USERNAME
+    valueFrom:
+      secretKeyRef:
+        name: example-keystone-admin
+        key: OS_USERNAME
+  - name: OS_PASSWORD
+    valueFrom:
+      secretKeyRef:
+        name: example-keystone-admin
+        key: OS_PASSWORD
+  - name: OS_CACERT
+    valueFrom:
+      secretKeyRef:
+        name: example-keystone-admin
+        key: OS_CACERT
+*/}}
+
+{{- define "helm-toolkit.snippets.keystone_openrc_env_vars" }}
+{{- $useCA := .useCA -}}
+{{- $ksUserSecret := .ksUserSecret }}
+- name: OS_IDENTITY_API_VERSION
+  value: "3"
+- name: OS_AUTH_URL
+  valueFrom:
+    secretKeyRef:
+      name: {{ $ksUserSecret }}
+      key: OS_AUTH_URL
+- name: OS_REGION_NAME
+  valueFrom:
+    secretKeyRef:
+      name: {{ $ksUserSecret }}
+      key: OS_REGION_NAME
+- name: OS_INTERFACE
+  valueFrom:
+    secretKeyRef:
+      name: {{ $ksUserSecret }}
+      key: OS_INTERFACE
+- name: OS_ENDPOINT_TYPE
+  valueFrom:
+    secretKeyRef:
+      name: {{ $ksUserSecret }}
+      key: OS_INTERFACE
+- name: OS_PROJECT_DOMAIN_NAME
+  valueFrom:
+    secretKeyRef:
+      name: {{ $ksUserSecret }}
+      key: OS_PROJECT_DOMAIN_NAME
+- name: OS_PROJECT_NAME
+  valueFrom:
+    secretKeyRef:
+      name: {{ $ksUserSecret }}
+      key: OS_PROJECT_NAME
+- name: OS_USER_DOMAIN_NAME
+  valueFrom:
+    secretKeyRef:
+      name: {{ $ksUserSecret }}
+      key: OS_USER_DOMAIN_NAME
+- name: OS_USERNAME
+  valueFrom:
+    secretKeyRef:
+      name: {{ $ksUserSecret }}
+      key: OS_USERNAME
+- name: OS_PASSWORD
+  valueFrom:
+    secretKeyRef:
+      name: {{ $ksUserSecret }}
+      key: OS_PASSWORD
+- name: OS_DEFAULT_DOMAIN
+  valueFrom:
+    secretKeyRef:
+      name: {{ $ksUserSecret }}
+      key: OS_DEFAULT_DOMAIN
+{{- if $useCA }}
+- name: OS_CACERT
+  valueFrom:
+    secretKeyRef:
+      name: {{ $ksUserSecret }}
+      key: OS_CACERT
+{{- end }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_keystone_secret_openrc.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_keystone_secret_openrc.tpl
new file mode 100644
index 0000000..f627657
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_keystone_secret_openrc.tpl
@@ -0,0 +1,32 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.snippets.keystone_secret_openrc" }}
+{{- $userClass := index . 0 -}}
+{{- $identityEndpoint := index . 1 -}}
+{{- $context := index . 2 -}}
+{{- $userContext := index $context.Values.endpoints.identity.auth $userClass }}
+OS_AUTH_URL: {{ tuple "identity" $identityEndpoint "api" $context | include "helm-toolkit.endpoints.keystone_endpoint_uri_lookup" | b64enc }}
+OS_REGION_NAME: {{ $userContext.region_name | b64enc }}
+OS_INTERFACE: {{ $userContext.interface | default "internal" | b64enc }}
+OS_PROJECT_DOMAIN_NAME: {{ $userContext.project_domain_name | b64enc }}
+OS_PROJECT_NAME: {{ $userContext.project_name | b64enc }}
+OS_USER_DOMAIN_NAME: {{ $userContext.user_domain_name | b64enc }}
+OS_USERNAME: {{ $userContext.username | b64enc }}
+OS_PASSWORD: {{ $userContext.password | b64enc }}
+OS_DEFAULT_DOMAIN: {{ $userContext.default_domain_id | default "default" | b64enc }}
+{{- if $userContext.cacert }}
+OS_CACERT: {{ $userContext.cacert | b64enc }}
+{{- end }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_keystone_user_create_env_vars.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_keystone_user_create_env_vars.tpl
new file mode 100644
index 0000000..648711b
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_keystone_user_create_env_vars.tpl
@@ -0,0 +1,90 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Returns a set of container enviorment variables, for use with the keystone
+  user management jobs.
+values: |
+  secrets:
+    identity:
+      service_user: example-keystone-user
+usage: |
+  {{ include "helm-toolkit.snippets.keystone_user_create_env_vars" ( dict "ksUserSecret" .Values.secrets.identity.service_user "useCA" true ) }}
+return: |
+  - name: SERVICE_OS_REGION_NAME
+    valueFrom:
+      secretKeyRef:
+        name: example-keystone-user
+        key: OS_REGION_NAME
+  - name: SERVICE_OS_PROJECT_DOMAIN_NAME
+    valueFrom:
+      secretKeyRef:
+        name: example-keystone-user
+        key: OS_PROJECT_DOMAIN_NAME
+  - name: SERVICE_OS_PROJECT_NAME
+    valueFrom:
+      secretKeyRef:
+        name: example-keystone-user
+        key: OS_PROJECT_NAME
+  - name: SERVICE_OS_USER_DOMAIN_NAME
+    valueFrom:
+      secretKeyRef:
+        name: example-keystone-user
+        key: OS_USER_DOMAIN_NAME
+  - name: SERVICE_OS_USERNAME
+    valueFrom:
+      secretKeyRef:
+        name: example-keystone-user
+        key: OS_USERNAME
+  - name: SERVICE_OS_PASSWORD
+    valueFrom:
+      secretKeyRef:
+        name: example-keystone-user
+        key: OS_PASSWORD
+*/}}
+
+{{- define "helm-toolkit.snippets.keystone_user_create_env_vars" }}
+{{- $ksUserSecret := .ksUserSecret }}
+- name: SERVICE_OS_REGION_NAME
+  valueFrom:
+    secretKeyRef:
+      name: {{ $ksUserSecret }}
+      key: OS_REGION_NAME
+- name: SERVICE_OS_PROJECT_DOMAIN_NAME
+  valueFrom:
+    secretKeyRef:
+      name: {{ $ksUserSecret }}
+      key: OS_PROJECT_DOMAIN_NAME
+- name: SERVICE_OS_PROJECT_NAME
+  valueFrom:
+    secretKeyRef:
+      name: {{ $ksUserSecret }}
+      key: OS_PROJECT_NAME
+- name: SERVICE_OS_USER_DOMAIN_NAME
+  valueFrom:
+    secretKeyRef:
+      name: {{ $ksUserSecret }}
+      key: OS_USER_DOMAIN_NAME
+- name: SERVICE_OS_USERNAME
+  valueFrom:
+    secretKeyRef:
+      name: {{ $ksUserSecret }}
+      key: OS_USERNAME
+- name: SERVICE_OS_PASSWORD
+  valueFrom:
+    secretKeyRef:
+      name: {{ $ksUserSecret }}
+      key: OS_PASSWORD
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_apparmor_configmap.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_apparmor_configmap.tpl
new file mode 100644
index 0000000..aa656c1
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_apparmor_configmap.tpl
@@ -0,0 +1,68 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Renders a configmap used for loading custom AppArmor profiles.
+values: |
+  pod:
+    mandatory_access_control:
+      type: apparmor
+      configmap_apparmor: true
+      apparmor_profiles: |-
+        my_apparmor-v1.profile: |-
+          #include <tunables/global>
+          profile my-apparmor-v1 flags=(attach_disconnected,mediate_deleted) {
+            <profile_data>
+          }
+usage: |
+  {{ dict "envAll" . "component" "myComponent" | include "helm-toolkit.snippets.kubernetes_apparmor_configmap" }}
+return: |
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: releaseName-myComponent-apparmor
+  namespace: myNamespace
+data:
+  my_apparmor-v1.profile: |-
+    #include <tunables/global>
+    profile my-apparmor-v1 flags=(attach_disconnected,mediate_deleted) {
+      <profile_data>
+    }
+*/}}
+{{- define "helm-toolkit.snippets.kubernetes_apparmor_configmap" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $component := index . "component" -}}
+{{- if hasKey $envAll.Values.pod "mandatory_access_control" -}}
+{{- if hasKey $envAll.Values.pod.mandatory_access_control "type" -}}
+{{- if eq $envAll.Values.pod.mandatory_access_control.type "apparmor" -}}
+{{- if hasKey $envAll.Values.pod.mandatory_access_control "configmap_apparmor" -}}
+{{- if $envAll.Values.pod.mandatory_access_control.configmap_apparmor }}
+{{- $mapName := printf "%s-%s-%s" $envAll.Chart.Name $component "apparmor" -}}
+{{- if $envAll.Values.conf.apparmor_profiles }}
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ $mapName }}
+  namespace: {{ $envAll.Release.Namespace }}
+data:
+{{ $envAll.Values.conf.apparmor_profiles | toYaml | indent 2 }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_apparmor_loader_init_container.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_apparmor_loader_init_container.tpl
new file mode 100644
index 0000000..f231fe6
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_apparmor_loader_init_container.tpl
@@ -0,0 +1,75 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Renders the init container used for apparmor loading.
+values: |
+  images:
+    tags:
+      apparmor_loader: my-repo.io/apparmor-loader:1.0.0
+  pod:
+    mandatory_access_control:
+      type: apparmor
+      configmap_apparmor: true
+      apparmor-loader: unconfined
+usage: |
+  {{ dict "envAll" . | include "helm-toolkit.snippets.kubernetes_apparmor_loader_init_container" }}
+return: |
+  - name: apparmor-loader
+    image: my-repo.io/apparmor-loader:1.0.0
+    args:
+      - /profiles
+    securityContext:
+      privileged: true
+    volumeMounts:
+      - name: sys
+        mountPath: /sys
+        readOnly: true
+      - name: includes
+        mountPath: /etc/apparmor.d
+        readOnly: true
+      - name: profiles
+        mountPath: /profiles
+        readOnly: true
+*/}}
+{{- define "helm-toolkit.snippets.kubernetes_apparmor_loader_init_container" -}}
+{{- $envAll := index . "envAll" -}}
+{{- if hasKey $envAll.Values.pod "mandatory_access_control" -}}
+{{- if hasKey $envAll.Values.pod.mandatory_access_control "type" -}}
+{{- if hasKey $envAll.Values.pod.mandatory_access_control "configmap_apparmor" -}}
+{{- if eq $envAll.Values.pod.mandatory_access_control.type "apparmor" -}}
+{{- if $envAll.Values.pod.mandatory_access_control.configmap_apparmor }}
+- name: apparmor-loader
+  image: {{ $envAll.Values.images.tags.apparmor_loader }}
+  args:
+    - /profiles
+  securityContext:
+    privileged: true
+  volumeMounts:
+    - name: sys
+      mountPath: /sys
+      readOnly: true
+    - name: includes
+      mountPath: /etc/apparmor.d
+      readOnly: true
+    - name: profiles
+      mountPath: /profiles
+      readOnly: true
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_apparmor_volumes.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_apparmor_volumes.tpl
new file mode 100644
index 0000000..c5e07ee
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_apparmor_volumes.tpl
@@ -0,0 +1,68 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Renders the volumes used by the apparmor loader.
+values: |
+  pod:
+    mandatory_access_control:
+      type: apparmor
+      configmap_apparmor: true
+inputs: |
+  envAll: "Environment or Context."
+  component: "Name of the component used for the name of configMap."
+  requireSys: "Boolean. True if it needs the hostpath /sys in volumes."
+usage: |
+  {{ dict "envAll" . "component" "keystone" "requireSys" true | include "helm-toolkit.snippets.kubernetes_apparmor_volumes" }}
+return: |
+- name: sys
+  hostPath:
+    path: /sys
+- name: includes
+  hostPath:
+    path: /etc/apparmor.d
+- name: profiles
+  configMap:
+    name: RELEASENAME-keystone-apparmor
+    defaultMode: 0555
+*/}}
+{{- define "helm-toolkit.snippets.kubernetes_apparmor_volumes" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $component := index . "component" -}}
+{{- $requireSys := index . "requireSys" | default false -}}
+{{- $configName := printf "%s-%s-%s" $envAll.Chart.Name $component "apparmor" -}}
+{{- if hasKey $envAll.Values.pod "mandatory_access_control" -}}
+{{- if hasKey $envAll.Values.pod.mandatory_access_control "type" -}}
+{{- if hasKey $envAll.Values.pod.mandatory_access_control "configmap_apparmor" -}}
+{{- if eq $envAll.Values.pod.mandatory_access_control.type "apparmor" -}}
+{{- if $envAll.Values.pod.mandatory_access_control.configmap_apparmor }}
+{{- if $requireSys }}
+- name: sys
+  hostPath:
+    path: /sys
+{{- end }}
+- name: includes
+  hostPath:
+    path: /etc/apparmor.d
+- name: profiles
+  configMap:
+    name: {{ $configName | quote }}
+    defaultMode: 0555
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_container_security_context.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_container_security_context.tpl
new file mode 100644
index 0000000..4741497
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_container_security_context.tpl
@@ -0,0 +1,48 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Renders securityContext for a Kubernetes container.
+  For container level, see here: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.13/#securitycontext-v1-core
+examples:
+  - values: |
+      pod:
+        security_context:
+          myApp:
+            container:
+              foo:
+                runAsUser: 34356
+                readOnlyRootFilesystem: true
+    usage: |
+      {{ dict "envAll" . "application" "myApp" "container" "foo" | include "helm-toolkit.snippets.kubernetes_container_security_context" }}
+    return: |
+      securityContext:
+        readOnlyRootFilesystem: true
+        runAsUser: 34356
+*/}}
+
+{{- define "helm-toolkit.snippets.kubernetes_container_security_context" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $application := index . "application" -}}
+{{- $container := index . "container" -}}
+{{- if hasKey $envAll.Values.pod "security_context" }}
+{{- if hasKey ( index $envAll.Values.pod.security_context ) $application }}
+{{- if hasKey ( index $envAll.Values.pod.security_context $application "container" ) $container }}
+securityContext:
+{{ toYaml ( index $envAll.Values.pod.security_context $application "container" $container ) | indent 2 }}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_entrypoint_init_container.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_entrypoint_init_container.tpl
new file mode 100644
index 0000000..bed712e
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_entrypoint_init_container.tpl
@@ -0,0 +1,209 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Returns a container definition for use with the kubernetes-entrypoint image
+  from stackanetes.
+values: |
+  images:
+    tags:
+      dep_check: quay.io/airshipit/kubernetes-entrypoint:v1.0.0
+    pull_policy: IfNotPresent
+    local_registry:
+      active: true
+      exclude:
+        - dep_check
+  dependencies:
+    dynamic:
+      common:
+        local_image_registry:
+          jobs:
+            - calico-image-repo-sync
+          services:
+            - endpoint: node
+              service: local_image_registry
+    static:
+      calico_node:
+        services:
+          - endpoint: internal
+            service: etcd
+        custom_resources:
+          - apiVersion: argoproj.io/v1alpha1
+            kind: Workflow
+            name: wf-example
+            fields:
+              - key: "status.phase"
+                value: "Succeeded"
+  endpoints:
+    local_image_registry:
+      namespace: docker-registry
+      hosts:
+        default: localhost
+        node: localhost
+    etcd:
+      hosts:
+        default: etcd
+  # NOTE (portdirect): if the stanza, or a portion of it, under `pod` is not
+  # specififed then the following will be used as defaults:
+  #  pod:
+  #    security_context:
+  #      kubernetes_entrypoint:
+  #        container:
+  #          kubernetes_entrypoint:
+  #            runAsUser: 65534
+  #            readOnlyRootFilesystem: true
+  #            allowPrivilegeEscalation: false
+  pod:
+    security_context:
+      kubernetes_entrypoint:
+        container:
+          kubernetes_entrypoint:
+            runAsUser: 0
+            readOnlyRootFilesystem: false
+usage: |
+  {{ tuple . "calico_node" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" }}
+return: |
+  - name: init
+    image: "quay.io/airshipit/kubernetes-entrypoint:v1.0.0"
+    imagePullPolicy: IfNotPresent
+    securityContext:
+      allowPrivilegeEscalation: false
+      readOnlyRootFilesystem: false
+      runAsUser: 0
+
+    env:
+      - name: POD_NAME
+        valueFrom:
+          fieldRef:
+            apiVersion: v1
+            fieldPath: metadata.name
+      - name: NAMESPACE
+        valueFrom:
+          fieldRef:
+            apiVersion: v1
+            fieldPath: metadata.namespace
+      - name: INTERFACE_NAME
+        value: eth0
+      - name: PATH
+        value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/
+      - name: DEPENDENCY_SERVICE
+        value: "default:etcd,docker-registry:localhost"
+      - name: DEPENDENCY_JOBS
+        value: "calico-image-repo-sync"
+      - name: DEPENDENCY_DAEMONSET
+        value: ""
+      - name: DEPENDENCY_CONTAINER
+        value: ""
+      - name: DEPENDENCY_POD_JSON
+        value: ""
+      - name: DEPENDENCY_CUSTOM_RESOURCE
+        value: "[{\"apiVersion\":\"argoproj.io/v1alpha1\",\"kind\":\"Workflow\",\"namespace\":\"default\",\"name\":\"wf-example\",\"fields\":[{\"key\":\"status.phase\",\"value\":\"Succeeded\"}]}]"
+    command:
+      - kubernetes-entrypoint
+    volumeMounts:
+      []
+*/}}
+
+{{- define "helm-toolkit.snippets.kubernetes_entrypoint_init_container._default_security_context" -}}
+Values:
+  pod:
+    security_context:
+      kubernetes_entrypoint:
+        container:
+          kubernetes_entrypoint:
+            runAsUser: 65534
+            readOnlyRootFilesystem: true
+            allowPrivilegeEscalation: false
+{{- end -}}
+
+{{- define "helm-toolkit.snippets.kubernetes_entrypoint_init_container" -}}
+{{- $envAll := index . 0 -}}
+{{- $component := index . 1 -}}
+{{- $mounts := index . 2 -}}
+
+{{- $_ := set $envAll.Values "__kubernetes_entrypoint_init_container" dict -}}
+{{- $_ := set $envAll.Values.__kubernetes_entrypoint_init_container "deps" dict -}}
+{{- if and ($envAll.Values.images.local_registry.active) (ne $component "image_repo_sync") -}}
+{{- if eq $component "pod_dependency" -}}
+{{- $_ := include "helm-toolkit.utils.merge" ( tuple $envAll.Values.__kubernetes_entrypoint_init_container.deps ( index $envAll.Values.pod_dependency ) $envAll.Values.dependencies.dynamic.common.local_image_registry ) -}}
+{{- else -}}
+{{- $_ := include "helm-toolkit.utils.merge" ( tuple $envAll.Values.__kubernetes_entrypoint_init_container.deps ( index $envAll.Values.dependencies.static $component ) $envAll.Values.dependencies.dynamic.common.local_image_registry ) -}}
+{{- end -}}
+{{- else -}}
+{{- if eq $component "pod_dependency" -}}
+{{- $_ := set $envAll.Values.__kubernetes_entrypoint_init_container "deps" ( index $envAll.Values.pod_dependency ) -}}
+{{- else -}}
+{{- $_ := set $envAll.Values.__kubernetes_entrypoint_init_container "deps" ( index $envAll.Values.dependencies.static $component ) -}}
+{{- end -}}
+{{- end -}}
+
+{{- if and ($envAll.Values.manifests.job_rabbit_init) (hasKey $envAll.Values.dependencies "dynamic") -}}
+{{- if $envAll.Values.dependencies.dynamic.job_rabbit_init -}}
+{{- if eq $component "pod_dependency" -}}
+{{- $_ := include "helm-toolkit.utils.merge" ( tuple $envAll.Values.__kubernetes_entrypoint_init_container.deps ( index $envAll.Values.pod_dependency ) (index $envAll.Values.dependencies.dynamic.job_rabbit_init $component) ) -}}
+{{- else -}}
+{{- $_ := include "helm-toolkit.utils.merge" ( tuple $envAll.Values.__kubernetes_entrypoint_init_container.deps ( index $envAll.Values.dependencies.static $component ) (index $envAll.Values.dependencies.dynamic.job_rabbit_init $component)) -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{- $deps := $envAll.Values.__kubernetes_entrypoint_init_container.deps }}
+{{- range $deps.custom_resources }}
+{{- $_ := set . "namespace" $envAll.Release.Namespace -}}
+{{- end -}}
+{{- $default_security_context := include "helm-toolkit.snippets.kubernetes_entrypoint_init_container._default_security_context" . | fromYaml }}
+{{- $patchedEnvAll := mergeOverwrite $default_security_context $envAll }}
+- name: init
+{{ tuple $envAll "dep_check" | include "helm-toolkit.snippets.image" | indent 2 }}
+{{- dict "envAll" $patchedEnvAll "application" "kubernetes_entrypoint" "container" "kubernetes_entrypoint" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 2 }}
+  env:
+    - name: POD_NAME
+      valueFrom:
+        fieldRef:
+          apiVersion: v1
+          fieldPath: metadata.name
+    - name: NAMESPACE
+      valueFrom:
+        fieldRef:
+          apiVersion: v1
+          fieldPath: metadata.namespace
+    - name: INTERFACE_NAME
+      value: eth0
+    - name: PATH
+      value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/
+    - name: DEPENDENCY_SERVICE
+      value: "{{ tuple $deps.services $envAll | include "helm-toolkit.utils.comma_joined_service_list" }}"
+{{- if $deps.jobs -}}
+  {{- if kindIs "string" (index $deps.jobs 0) }}
+    - name: DEPENDENCY_JOBS
+      value: "{{ include "helm-toolkit.utils.joinListWithComma" $deps.jobs }}"
+  {{- else }}
+    - name: DEPENDENCY_JOBS_JSON
+      value: {{- toJson $deps.jobs | quote -}}
+  {{- end -}}
+{{- end }}
+    - name: DEPENDENCY_DAEMONSET
+      value: "{{ include "helm-toolkit.utils.joinListWithComma" $deps.daemonset }}"
+    - name: DEPENDENCY_CONTAINER
+      value: "{{ include "helm-toolkit.utils.joinListWithComma" $deps.container }}"
+    - name: DEPENDENCY_POD_JSON
+      value: {{ if $deps.pod }}{{ toJson $deps.pod | quote }}{{ else }}""{{ end }}
+    - name: DEPENDENCY_CUSTOM_RESOURCE
+      value: {{ if $deps.custom_resources }}{{ toJson $deps.custom_resources | quote }}{{ else }}""{{ end }}
+  command:
+    - kubernetes-entrypoint
+  volumeMounts:
+{{ toYaml $mounts | indent 4 }}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_kubectl_params.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_kubectl_params.tpl
new file mode 100644
index 0000000..34a7da3
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_kubectl_params.tpl
@@ -0,0 +1,20 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.snippets.kubernetes_kubectl_params" -}}
+{{- $envAll := index . 0 -}}
+{{- $application := index . 1 -}}
+{{- $component := index . 2 -}}
+{{ print "-l application=" $application " -l component=" $component }}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_mandatory_access_control_annotation.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_mandatory_access_control_annotation.tpl
new file mode 100644
index 0000000..92d3ea5
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_mandatory_access_control_annotation.tpl
@@ -0,0 +1,60 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Renders mandatory access control annotations for a list of containers
+  driven by values.yaml. As of now, it can only generate an apparmor
+  annotation, but in the future could generate others.
+values: |
+  pod:
+    mandatory_access_control:
+      type: apparmor
+      myPodName:
+        myContainerName: localhost/myAppArmor
+        mySecondContainerName: localhost/secondProfile # optional
+        myThirdContainerName: localhost/thirdProfile # optional
+usage: |
+  {{ dict "envAll" . "podName" "myPodName" "containerNames" (list "myContainerName" "mySecondContainerName" "myThirdContainerName") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" }}
+return: |
+  container.apparmor.security.beta.kubernetes.io/myContainerName: localhost/myAppArmor
+  container.apparmor.security.beta.kubernetes.io/mySecondContainerName: localhost/secondProfile
+  container.apparmor.security.beta.kubernetes.io/myThirdContainerName: localhost/thirdProfile
+note: |
+  The number of container underneath is a variable arguments. It loops through
+  all the container names specified.
+*/}}
+{{- define "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $podName := index . "podName" -}}
+{{- $containerNames := index . "containerNames" -}}
+{{- if hasKey $envAll.Values.pod "mandatory_access_control" -}}
+{{- if hasKey $envAll.Values.pod.mandatory_access_control "type" -}}
+{{- $macType := $envAll.Values.pod.mandatory_access_control.type -}}
+{{- if $macType -}}
+{{- if eq $macType "apparmor" -}}
+{{- if hasKey $envAll.Values.pod.mandatory_access_control $podName -}}
+{{- range $name := $containerNames -}}
+{{- $apparmorProfile := index $envAll.Values.pod.mandatory_access_control $podName $name -}}
+{{- if $apparmorProfile }}
+container.apparmor.security.beta.kubernetes.io/{{ $name }}: {{ $apparmorProfile }}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_metadata_labels.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_metadata_labels.tpl
new file mode 100644
index 0000000..b8493b3
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_metadata_labels.tpl
@@ -0,0 +1,51 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Renders a set of standardised labels
+values: |
+  release_group: null
+  pod:
+    labels:
+      default:
+        label1.example.com: value
+      bar:
+        label2.example.com: bar
+usage: |
+  {{ tuple . "foo" "bar" | include "helm-toolkit.snippets.kubernetes_metadata_labels" }}
+return: |
+  release_group: RELEASE-NAME
+  application: foo
+  component: bar
+  label1.example.com: value
+  label2.example.com: bar
+*/}}
+
+{{- define "helm-toolkit.snippets.kubernetes_metadata_labels" -}}
+{{- $envAll := index . 0 -}}
+{{- $application := index . 1 -}}
+{{- $component := index . 2 -}}
+release_group: {{ $envAll.Values.release_group | default $envAll.Chart.Name }}
+application: {{ $application }}
+component: {{ $component }}
+{{- if ($envAll.Values.pod).labels }}
+{{- if hasKey $envAll.Values.pod.labels $component }}
+{{ index $envAll.Values.pod "labels" $component | toYaml }}
+{{- end -}}
+{{- if hasKey $envAll.Values.pod.labels "default" }}
+{{ $envAll.Values.pod.labels.default | toYaml }}
+{{- end -}}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_pod_anti_affinity.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_pod_anti_affinity.tpl
new file mode 100644
index 0000000..f1ad580
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_pod_anti_affinity.tpl
@@ -0,0 +1,89 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Renders kubernetes anti affinity rules, this function supports both hard
+  'requiredDuringSchedulingIgnoredDuringExecution' and soft
+  'preferredDuringSchedulingIgnoredDuringExecution' types.
+values: |
+  pod:
+    affinity:
+      anti:
+        topologyKey:
+          default: kubernetes.io/hostname
+        type:
+          default: requiredDuringSchedulingIgnoredDuringExecution
+        weight:
+          default: 10
+usage: |
+  {{ tuple . "appliction_x" "component_y" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" }}
+return: |
+  podAntiAffinity:
+    requiredDuringSchedulingIgnoredDuringExecution:
+    - labelSelector:
+        matchExpressions:
+          - key: release_group
+            operator: In
+            values:
+            - RELEASE-NAME
+          - key: application
+            operator: In
+            values:
+            - appliction_x
+          - key: component
+            operator: In
+            values:
+            - component_y
+          topologyKey: kubernetes.io/hostname
+*/}}
+
+{{- define "helm-toolkit.snippets.kubernetes_pod_anti_affinity._match_expressions" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $application := index . "application" -}}
+{{- $component := index . "component" -}}
+{{- $expressionRelease := dict "key" "release_group" "operator" "In"  "values" ( list ( $envAll.Values.release_group | default $envAll.Chart.Name ) ) -}}
+{{- $expressionApplication := dict "key" "application" "operator" "In"  "values" ( list $application ) -}}
+{{- $expressionComponent := dict "key" "component" "operator" "In"  "values" ( list $component ) -}}
+{{- list $expressionRelease $expressionApplication $expressionComponent | toYaml }}
+{{- end -}}
+
+{{- define "helm-toolkit.snippets.kubernetes_pod_anti_affinity" -}}
+{{- $envAll := index . 0 -}}
+{{- $application := index . 1 -}}
+{{- $component := index . 2 -}}
+{{- $antiAffinityType := index $envAll.Values.pod.affinity.anti.type $component | default $envAll.Values.pod.affinity.anti.type.default }}
+{{- $antiAffinityKey := index $envAll.Values.pod.affinity.anti.topologyKey $component | default $envAll.Values.pod.affinity.anti.topologyKey.default }}
+podAntiAffinity:
+{{- $matchExpressions := include "helm-toolkit.snippets.kubernetes_pod_anti_affinity._match_expressions" ( dict "envAll" $envAll "application" $application "component" $component ) -}}
+{{- if eq $antiAffinityType "preferredDuringSchedulingIgnoredDuringExecution" }}
+  {{ $antiAffinityType }}:
+  - podAffinityTerm:
+      labelSelector:
+        matchExpressions:
+{{ $matchExpressions | indent 10 }}
+      topologyKey: {{ $antiAffinityKey }}
+{{- if  $envAll.Values.pod.affinity.anti.weight }}
+    weight: {{ index $envAll.Values.pod.affinity.anti.weight $component | default $envAll.Values.pod.affinity.anti.weight.default }}
+{{- else }}
+    weight: 10
+{{- end -}}
+{{- else if eq $antiAffinityType "requiredDuringSchedulingIgnoredDuringExecution" }}
+  {{ $antiAffinityType }}:
+  - labelSelector:
+      matchExpressions:
+{{ $matchExpressions | indent 8 }}
+    topologyKey: {{ $antiAffinityKey }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_pod_image_pull_secret.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_pod_image_pull_secret.tpl
new file mode 100644
index 0000000..74173dc
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_pod_image_pull_secret.tpl
@@ -0,0 +1,45 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Renders image pull secrets for a pod
+values: |
+  pod:
+    image_pull_secrets:
+      default:
+        - name: some-pull-secret
+      bar:
+        - name: another-pull-secret
+usage: |
+  {{ tuple . "bar" | include "helm-toolkit.snippets.kubernetes_image_pull_secrets" }}
+return: |
+  imagePullSecrets:
+    - name: some-pull-secret
+    - name: another-pull-secret
+*/}}
+
+{{- define "helm-toolkit.snippets.kubernetes_image_pull_secrets" -}}
+{{- $envAll := index . 0 -}}
+{{- $application := index . 1 -}}
+{{- if ($envAll.Values.pod).image_pull_secrets }}
+imagePullSecrets:
+{{- if hasKey $envAll.Values.pod.image_pull_secrets $application }}
+{{ index $envAll.Values.pod "image_pull_secrets" $application | toYaml | indent 2 }}
+{{- end -}}
+{{- if hasKey $envAll.Values.pod.image_pull_secrets "default" }}
+{{ $envAll.Values.pod.image_pull_secrets.default | toYaml | indent 2 }}
+{{- end -}}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_pod_rbac_roles.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_pod_rbac_roles.tpl
new file mode 100644
index 0000000..c2576d5
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_pod_rbac_roles.tpl
@@ -0,0 +1,69 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.snippets.kubernetes_pod_rbac_roles" -}}
+{{- $envAll := index . 0 -}}
+{{- $deps := index . 1 -}}
+{{- $saName := index . 2 | replace "_" "-" }}
+{{- $saNamespace := index . 3 -}}
+{{- $releaseName := $envAll.Chart.Name }}
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: {{ $releaseName }}-{{ $saName }}
+  namespace: {{ $saNamespace }}
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: Role
+  name: {{ $releaseName }}-{{ $saNamespace }}-{{ $saName }}
+subjects:
+  - kind: ServiceAccount
+    name: {{ $saName }}
+    namespace: {{ $saNamespace }}
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+  name: {{ $releaseName }}-{{ $saNamespace }}-{{ $saName }}
+  namespace: {{ $saNamespace }}
+rules:
+  - apiGroups:
+      - ""
+      - extensions
+      - batch
+      - apps
+    verbs:
+      - get
+      - list
+    resources:
+      {{- range $k, $v := $deps -}}
+      {{ if eq $v "daemonsets" }}
+      - daemonsets
+      {{- end -}}
+      {{ if eq $v "jobs" }}
+      - jobs
+      {{- end -}}
+      {{ if or (eq $v "pods") (eq $v "daemonsets") (eq $v "jobs") }}
+      - pods
+      {{- end -}}
+      {{ if eq $v "services" }}
+      - services
+      - endpoints
+      {{- end -}}
+      {{ if eq $v "secrets" }}
+      - secrets
+      {{- end -}}
+      {{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_pod_rbac_serviceaccount.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_pod_rbac_serviceaccount.tpl
new file mode 100644
index 0000000..4cc898d
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_pod_rbac_serviceaccount.tpl
@@ -0,0 +1,69 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" -}}
+{{- $envAll := index . 0 -}}
+{{- $component := index . 1 -}}
+{{- $saName := index . 2 -}}
+{{- $saNamespace := $envAll.Release.Namespace }}
+{{- $randomKey := randAlphaNum 32 }}
+{{- $allNamespace := dict $randomKey "" }}
+
+{{- $_ := set $envAll.Values "__kubernetes_entrypoint_init_container" dict -}}
+{{- $_ := set $envAll.Values.__kubernetes_entrypoint_init_container "deps" dict -}}
+{{- if and ($envAll.Values.images.local_registry.active) (ne $component "image_repo_sync") -}}
+{{- if eq $component "pod_dependency" -}}
+{{- $_ := include "helm-toolkit.utils.merge" ( tuple $envAll.Values.__kubernetes_entrypoint_init_container.deps ( index $envAll.Values.pod_dependency ) $envAll.Values.dependencies.dynamic.common.local_image_registry ) -}}
+{{- else -}}
+{{- $_ := include "helm-toolkit.utils.merge" ( tuple $envAll.Values.__kubernetes_entrypoint_init_container.deps ( index $envAll.Values.dependencies.static $component ) $envAll.Values.dependencies.dynamic.common.local_image_registry ) -}}
+{{- end -}}
+{{- else -}}
+{{- if eq $component "pod_dependency" -}}
+{{- $_ := set $envAll.Values.__kubernetes_entrypoint_init_container "deps" ( index $envAll.Values.pod_dependency ) -}}
+{{- else -}}
+{{- $_ := set $envAll.Values.__kubernetes_entrypoint_init_container "deps" ( index $envAll.Values.dependencies.static $component ) -}}
+{{- end -}}
+{{- end -}}
+{{- $deps := $envAll.Values.__kubernetes_entrypoint_init_container.deps }}
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: {{ $saName }}
+  namespace: {{ $saNamespace }}
+{{- range $k, $v := $deps -}}
+{{- if eq $k "services" }}
+{{- range $serv := $v }}
+{{- $endpointMap := index $envAll.Values.endpoints $serv.service }}
+{{- $endpointNS := $endpointMap.namespace | default $saNamespace }}
+{{- if not (contains "services" ((index $allNamespace $endpointNS) | default "")) }}
+{{- $_ := set $allNamespace $endpointNS (printf "%s%s" "services," ((index $allNamespace $endpointNS) | default "")) }}
+{{- end -}}
+{{- end -}}
+{{- else if and (eq $k "jobs") $v }}
+{{- $_ := set $allNamespace $saNamespace  (printf "%s%s" "jobs," ((index $allNamespace $saNamespace) | default "")) }}
+{{- else if and (eq $k "daemonset") $v }}
+{{- $_ := set $allNamespace $saNamespace  (printf "%s%s" "daemonsets," ((index $allNamespace $saNamespace) | default "")) }}
+{{- else if and (eq $k "pod") $v }}
+{{- $_ := set $allNamespace $saNamespace  (printf "%s%s" "pods," ((index $allNamespace $saNamespace) | default "")) }}
+{{- else if and (eq $k "secret") $v }}
+{{- $_ := set $allNamespace $saNamespace  (printf "%s%s" "secrets," ((index $allNamespace $saNamespace) | default "")) }}
+{{- end -}}
+{{- end -}}
+{{- $_ := unset $allNamespace $randomKey }}
+{{- range $ns, $vv := $allNamespace }}
+{{- $resourceList := (splitList "," (trimSuffix "," $vv)) }}
+{{- tuple $envAll $resourceList $saName $ns | include "helm-toolkit.snippets.kubernetes_pod_rbac_roles" }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_pod_security_context.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_pod_security_context.tpl
new file mode 100644
index 0000000..3a4fbaa
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_pod_security_context.tpl
@@ -0,0 +1,67 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Renders securityContext for a Kubernetes pod.
+  For pod level, seurity context see here: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.13/#podsecuritycontext-v1-core
+examples:
+  - values: |
+      pod:
+        # NOTE: The 'user' key is deprecated, and will be removed shortly.
+        user:
+          myApp:
+            uid: 34356
+        security_context:
+          myApp:
+            pod:
+              runAsNonRoot: true
+    usage: |
+      {{ dict "envAll" . "application" "myApp" | include "helm-toolkit.snippets.kubernetes_pod_security_context" }}
+    return: |
+      securityContext:
+        runAsUser: 34356
+        runAsNonRoot: true
+  - values: |
+      pod:
+        security_context:
+          myApp:
+            pod:
+              runAsUser: 34356
+              runAsNonRoot: true
+    usage: |
+      {{ dict "envAll" . "application" "myApp" | include "helm-toolkit.snippets.kubernetes_pod_security_context" }}
+    return: |
+      securityContext:
+        runAsNonRoot: true
+        runAsUser: 34356
+*/}}
+
+{{- define "helm-toolkit.snippets.kubernetes_pod_security_context" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $application := index . "application" -}}
+securityContext:
+{{- if hasKey $envAll.Values.pod "user" }}
+{{- if hasKey $envAll.Values.pod.user $application }}
+{{- if hasKey ( index $envAll.Values.pod.user $application ) "uid" }}
+  runAsUser: {{ index $envAll.Values.pod.user $application "uid" }}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+{{- if hasKey $envAll.Values.pod "security_context" }}
+{{- if hasKey ( index $envAll.Values.pod.security_context ) $application }}
+{{ toYaml ( index $envAll.Values.pod.security_context $application "pod" ) | indent 2 }}
+{{- end -}}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_probes.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_probes.tpl
new file mode 100644
index 0000000..7470760
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_probes.tpl
@@ -0,0 +1,55 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Renders kubernetes liveness and readiness probes for containers
+values: |
+  pod:
+    probes:
+      api:
+        default:
+          readiness:
+            enabled: true
+            params:
+              initialDelaySeconds: 30
+              timeoutSeconds: 30
+usage: |
+  {{- define "probeTemplate" }}
+  httpGet:
+    path: /status
+    port: 9090
+  {{- end }}
+  {{ dict "envAll" . "component" "api" "container" "default" "type" "readiness" "probeTemplate" (include "probeTemplate" . | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" }}
+return: |
+  readinessProbe:
+    httpGet:
+      path: /status
+      port: 9090
+    initialDelaySeconds: 30
+    timeoutSeconds: 30
+*/}}
+
+{{- define "helm-toolkit.snippets.kubernetes_probe" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $component := index . "component" -}}
+{{- $container := index . "container" -}}
+{{- $type := index . "type" -}}
+{{- $probeTemplate := index . "probeTemplate" -}}
+{{- $probeOpts := index $envAll.Values.pod.probes $component $container $type -}}
+{{- if $probeOpts.enabled -}}
+{{- $probeOverides := index $probeOpts "params" | default dict -}}
+{{ dict ( printf "%sProbe" $type ) (mergeOverwrite $probeTemplate $probeOverides ) | toYaml }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_resources.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_resources.tpl
new file mode 100644
index 0000000..24d30cf
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_resources.tpl
@@ -0,0 +1,53 @@
+{{/*
+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.
+*/}}
+
+{{/*
+Note: This function is deprecated and will be removed in the future.
+
+abstract: |
+  Renders kubernetes resource limits for pods
+values: |
+  pod:
+    resources:
+      enabled: true
+      api:
+        requests:
+          memory: "128Mi"
+          cpu: "100m"
+        limits:
+          memory: "1024Mi"
+          cpu: "2000m"
+          hugepages-1Gi: "1Gi"
+
+usage: |
+  {{ include "helm-toolkit.snippets.kubernetes_resources" ( tuple . .Values.pod.resources.api ) }}
+return: |
+  resources:
+    limits:
+      cpu: "2000m"
+      memory: "1024Mi"
+      hugepages-1Gi: "1Gi"
+    requests:
+      cpu: "100m"
+      memory: "128Mi
+*/}}
+
+{{- define "helm-toolkit.snippets.kubernetes_resources" -}}
+{{- $envAll := index . 0 -}}
+{{- $component := index . 1 -}}
+{{- if $envAll.Values.pod.resources.enabled -}}
+resources:
+{{ toYaml $component | trim | indent 2 }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_seccomp_annotation.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_seccomp_annotation.tpl
new file mode 100644
index 0000000..555ffb0
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_seccomp_annotation.tpl
@@ -0,0 +1,47 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Renders seccomp annotations for a list of containers driven by values.yaml.
+values: |
+  pod:
+    seccomp:
+      myPodName:
+        myContainerName: localhost/mySeccomp
+        mySecondContainerName: localhost/secondProfile # optional
+        myThirdContainerName: localhost/thirdProfile # optional
+usage: |
+  {{ dict "envAll" . "podName" "myPodName" "containerNames" (list "myContainerName" "mySecondContainerName" "myThirdContainerName") | include "helm-toolkit.snippets.kubernetes_seccomp_annotation" }}
+return: |
+  container.seccomp.security.alpha.kubernetes.io/myContainerName: localhost/mySeccomp
+  container.seccomp.security.alpha.kubernetes.io/mySecondContainerName: localhost/secondProfile
+  container.seccomp.security.alpha.kubernetes.io/myThirdContainerName: localhost/thirdProfile
+note: |
+  The number of container underneath is a variable arguments. It loops through
+  all the container names specified.
+*/}}
+{{- define "helm-toolkit.snippets.kubernetes_seccomp_annotation" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $podName := index . "podName" -}}
+{{- $containerNames := index . "containerNames" -}}
+{{- if hasKey (index $envAll.Values.pod "seccomp") $podName -}}
+{{- range $name := $containerNames -}}
+{{- $seccompProfile := index $envAll.Values.pod.seccomp $podName $name -}}
+{{- if $seccompProfile }}
+container.seccomp.security.alpha.kubernetes.io/{{ $name }}: {{ $seccompProfile }}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_tolerations.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_tolerations.tpl
new file mode 100644
index 0000000..e4af6a6
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_tolerations.tpl
@@ -0,0 +1,45 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Renders kubernetes tolerations for pods
+values: |
+  pod:
+    tolerations:
+      api:
+        enabled: true
+        tolerations:
+        - key: node-role.kubernetes.io/master
+          operator: Exists
+        - key: node-role.kubernetes.io/node
+          operator: Exists
+
+usage: |
+  {{ include "helm-toolkit.snippets.kubernetes_tolerations" ( tuple . .Values.pod.tolerations.api ) }}
+return: |
+  tolerations:
+  - key: node-role.kubernetes.io/master
+    operator: Exists
+  - key: node-role.kubernetes.io/node
+    operator: Exists
+*/}}
+
+{{- define "helm-toolkit.snippets.kubernetes_tolerations" -}}
+{{- $envAll := index . 0 -}}
+{{- $component := index . 1 -}}
+{{- $pod := index $envAll.Values.pod.tolerations $component }}
+tolerations:
+{{ toYaml $pod.tolerations }}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_upgrades_daemonset.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_upgrades_daemonset.tpl
new file mode 100644
index 0000000..69cee47
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_upgrades_daemonset.tpl
@@ -0,0 +1,33 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.snippets.kubernetes_upgrades_daemonset" -}}
+{{- $envAll := index . 0 -}}
+{{- $component := index . 1 -}}
+{{- $upgradeMap := index $envAll.Values.pod.lifecycle.upgrades.daemonsets $component -}}
+{{- $pod_replacement_strategy := $envAll.Values.pod.lifecycle.upgrades.daemonsets.pod_replacement_strategy -}}
+{{- with $upgradeMap -}}
+{{- if .enabled }}
+minReadySeconds: {{ .min_ready_seconds }}
+updateStrategy:
+  type: {{ $pod_replacement_strategy }}
+  {{- if $pod_replacement_strategy }}
+  {{- if eq $pod_replacement_strategy "RollingUpdate" }}
+  rollingUpdate:
+    maxUnavailable: {{ .max_unavailable }}
+  {{- end }}
+  {{- end }}
+{{- end }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_upgrades_deployment.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_upgrades_deployment.tpl
new file mode 100644
index 0000000..be28cdb
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_upgrades_deployment.tpl
@@ -0,0 +1,27 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.snippets.kubernetes_upgrades_deployment" -}}
+{{- $envAll := index . 0 -}}
+{{- with $envAll.Values.pod.lifecycle.upgrades.deployments -}}
+revisionHistoryLimit: {{ .revision_history }}
+strategy:
+  type: {{ .pod_replacement_strategy }}
+  {{- if eq .pod_replacement_strategy "RollingUpdate" }}
+  rollingUpdate:
+    maxUnavailable: {{ .rolling_update.max_unavailable }}
+    maxSurge: {{ .rolling_update.max_surge }}
+  {{- end }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_upgrades_statefulset.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_upgrades_statefulset.tpl
new file mode 100644
index 0000000..f897023
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_kubernetes_upgrades_statefulset.tpl
@@ -0,0 +1,51 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Renders upgradeStrategy configuration for Kubernetes statefulsets.
+  See: https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/#updating-statefulsets
+  Types:
+    - RollingUpdate (default)
+    - OnDelete
+  Partitions:
+    - Stage updates to a statefulset by keeping pods at current version while
+      allowing mutations to statefulset's .spec.template
+values: |
+  pod:
+    lifecycle:
+      upgrades:
+        statefulsets:
+          pod_replacement_strategy: RollingUpdate
+          partition: 2
+usage: |
+  {{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_statefulset" | indent 2 }}
+return: |
+  updateStrategy:
+    type: RollingUpdate
+    rollingUpdate:
+      partition: 2
+*/}}
+
+{{- define "helm-toolkit.snippets.kubernetes_upgrades_statefulset" -}}
+{{- $envAll := index . 0 -}}
+{{- with $envAll.Values.pod.lifecycle.upgrades.statefulsets -}}
+updateStrategy:
+  type: {{ .pod_replacement_strategy }}
+  {{ if .partition -}}
+  rollingUpdate:
+    partition: {{ .partition }}
+  {{- end -}}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_mon_host_from_k8s_ep.sh.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_mon_host_from_k8s_ep.sh.tpl
new file mode 100644
index 0000000..fc74c6f
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_mon_host_from_k8s_ep.sh.tpl
@@ -0,0 +1,68 @@
+{{- define "helm-toolkit.snippets.mon_host_from_k8s_ep" -}}
+{{/*
+
+Inserts a bash function definition mon_host_from_k8s_ep() which can be used
+to construct a mon_hosts value from the given namespaced endpoint.
+
+Usage (e.g. in _script.sh.tpl):
+    #!/bin/bash
+
+    : "${NS:=ceph}"
+    : "${EP:=ceph-mon-discovery}"
+
+    {{ include "helm-toolkit.snippets.mon_host_from_k8s_ep" . }}
+
+    MON_HOST=$(mon_host_from_k8s_ep "$NS" "$EP")
+
+    if [ -z "$MON_HOST" ]; then
+        # deal with failure
+    else
+        sed -i -e "s/^mon_host = /mon_host = $MON_HOST/" /etc/ceph/ceph.conf
+    fi
+*/}}
+{{`
+# Construct a mon_hosts value from the given namespaced endpoint
+# IP x.x.x.x with port p named "mon-msgr2" will appear as [v2:x.x.x.x/p/0]
+# IP x.x.x.x with port q named "mon" will appear as [v1:x.x.x.x/q/0]
+# IP x.x.x.x with ports p and q will appear as [v2:x.x.x.x/p/0,v1:x.x.x.x/q/0]
+# The entries for all IPs will be joined with commas
+mon_host_from_k8s_ep() {
+  local ns=$1
+  local ep=$2
+
+  if [ -z "$ns" ] || [ -z "$ep" ]; then
+    return 1
+  fi
+
+  # We don't want shell expansion for the go-template expression
+  # shellcheck disable=SC2016
+  kubectl get endpoints -n "$ns" "$ep" -o go-template='
+    {{- $sep := "" }}
+    {{- range $_,$s := .subsets }}
+      {{- $v2port := 0 }}
+      {{- $v1port := 0 }}
+      {{- range $_,$port := index $s "ports" }}
+        {{- if (eq $port.name "mon-msgr2") }}
+          {{- $v2port = $port.port }}
+        {{- else if (eq $port.name "mon") }}
+          {{- $v1port = $port.port }}
+        {{- end }}
+      {{- end }}
+      {{- range $_,$address := index $s "addresses" }}
+        {{- $v2endpoint := printf "v2:%s:%d/0" $address.ip $v2port }}
+        {{- $v1endpoint := printf "v1:%s:%d/0" $address.ip $v1port }}
+        {{- if (and $v2port $v1port) }}
+          {{- printf "%s[%s,%s]" $sep $v2endpoint $v1endpoint }}
+          {{- $sep = "," }}
+        {{- else if $v2port }}
+          {{- printf "%s[%s]" $sep $v2endpoint }}
+          {{- $sep = "," }}
+        {{- else if $v1port }}
+          {{- printf "%s[%s]" $sep $v1endpoint }}
+          {{- $sep = "," }}
+        {{- end }}
+      {{- end }}
+    {{- end }}'
+}
+`}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_prometheus_pod_annotations.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_prometheus_pod_annotations.tpl
new file mode 100644
index 0000000..fec41f8
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_prometheus_pod_annotations.tpl
@@ -0,0 +1,33 @@
+{{/*
+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.
+*/}}
+
+# Appends annotations for configuring prometheus scrape jobs via pod
+# annotations. The required annotations are:
+# * `prometheus.io/scrape`: Only scrape pods that have a value of `true`
+# * `prometheus.io/path`: If the metrics path is not `/metrics` override this.
+# * `prometheus.io/port`: Scrape the pod on the indicated port instead of the
+# pod's declared ports (default is a port-free target if none are declared).
+
+{{- define "helm-toolkit.snippets.prometheus_pod_annotations" -}}
+{{- $config := index . 0 -}}
+{{- if $config.scrape }}
+prometheus.io/scrape: {{ $config.scrape | quote }}
+{{- end }}
+{{- if $config.path }}
+prometheus.io/path: {{ $config.path | quote }}
+{{- end }}
+{{- if $config.port }}
+prometheus.io/port: {{ $config.port | quote }}
+{{- end }}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_prometheus_service_annotations.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_prometheus_service_annotations.tpl
new file mode 100644
index 0000000..a827c4b
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_prometheus_service_annotations.tpl
@@ -0,0 +1,35 @@
+{{/*
+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.
+*/}}
+
+# Appends annotations for configuring prometheus scrape endpoints via
+# annotations. The required annotations are:
+# * `prometheus.io/scrape`: Only scrape services that have a value of `true`
+# * `prometheus.io/scheme`: If the metrics endpoint is secured then you will need
+# to set this to `https` & most likely set the `tls_config` of the scrape config.
+# * `prometheus.io/path`: If the metrics path is not `/metrics` override this.
+# * `prometheus.io/port`: If the metrics are exposed on a different port to the
+# service then set this appropriately.
+
+{{- define "helm-toolkit.snippets.prometheus_service_annotations" -}}
+{{- $config := index . 0 -}}
+{{- if $config.scrape }}
+prometheus.io/scrape: {{ $config.scrape | quote }}
+{{- end }}
+{{- if $config.scheme }}
+prometheus.io/scheme: {{ $config.scheme | quote }}
+{{- end }}
+{{- if $config.path }}
+prometheus.io/path: {{ $config.path | quote }}
+{{- end }}
+{{- if $config.port }}
+prometheus.io/port: {{ $config.port | quote }}
+{{- end }}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_release_uuid.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_release_uuid.tpl
new file mode 100644
index 0000000..253920b
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_release_uuid.tpl
@@ -0,0 +1,29 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Reneders an attonation key and value for a release
+values: |
+  release_uuid: null
+usage: |
+  {{ tuple . | include "helm-toolkit.snippets.release_uuid" }}
+return: |
+  "openstackhelm.openstack.org/release_uuid": ""
+*/}}
+
+{{- define "helm-toolkit.snippets.release_uuid" -}}
+{{- $envAll := index . 0 -}}
+"openstackhelm.openstack.org/release_uuid": {{ $envAll.Values.release_uuid | default "" | quote }}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_rgw_s3_admin_env_vars.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_rgw_s3_admin_env_vars.tpl
new file mode 100644
index 0000000..a3169ce
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_rgw_s3_admin_env_vars.tpl
@@ -0,0 +1,32 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.snippets.rgw_s3_admin_env_vars" }}
+{{- $s3AdminSecret := .s3AdminSecret }}
+- name: S3_ADMIN_USERNAME
+  valueFrom:
+    secretKeyRef:
+      name: {{ $s3AdminSecret }}
+      key: S3_ADMIN_USERNAME
+- name: S3_ADMIN_ACCESS_KEY
+  valueFrom:
+    secretKeyRef:
+      name: {{ $s3AdminSecret }}
+      key: S3_ADMIN_ACCESS_KEY
+- name: S3_ADMIN_SECRET_KEY
+  valueFrom:
+    secretKeyRef:
+      name: {{ $s3AdminSecret }}
+      key: S3_ADMIN_SECRET_KEY
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_rgw_s3_secret_creds.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_rgw_s3_secret_creds.tpl
new file mode 100644
index 0000000..a611a5e
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_rgw_s3_secret_creds.tpl
@@ -0,0 +1,29 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.snippets.rgw_s3_secret_creds" }}
+{{- range $client, $config := .Values.storage.s3.clients -}}
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ printf "%s-s3-user-secret" ( $client | replace "_" "-" | lower ) }}
+type: Opaque
+data:
+{{- range $key, $value := $config.auth }}
+  {{ $key | upper }}: {{ $value | toString | b64enc}}
+{{- end }}
+
+{{ end }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_rgw_s3_user_env_vars.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_rgw_s3_user_env_vars.tpl
new file mode 100644
index 0000000..a3dd431
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_rgw_s3_user_env_vars.tpl
@@ -0,0 +1,34 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.snippets.rgw_s3_user_env_vars" }}
+{{- range $client, $user := .Values.storage.s3.clients }}
+{{- $s3secret := printf "%s-s3-user-secret" ( $client | replace "_" "-" | lower ) }}
+- name: {{ printf "%s_S3_USERNAME" ($client | replace "-" "_" | upper) }}
+  valueFrom:
+    secretKeyRef:
+      name: {{ $s3secret }}
+      key: USERNAME
+- name: {{ printf "%s_S3_ACCESS_KEY" ($client | replace "-" "_" | upper) }}
+  valueFrom:
+    secretKeyRef:
+      name: {{ $s3secret }}
+      key: ACCESS_KEY
+- name: {{ printf "%s_S3_SECRET_KEY" ($client | replace "-" "_" | upper) }}
+  valueFrom:
+    secretKeyRef:
+      name: {{ $s3secret }}
+      key: SECRET_KEY
+{{- end }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_tls_volume.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_tls_volume.tpl
new file mode 100644
index 0000000..41fe3d9
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_tls_volume.tpl
@@ -0,0 +1,47 @@
+{{/*
+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.
+*/}}
+{{/*
+abstract: |
+  Renders a secret volume for tls.
+
+  Dictionary Parameters:
+    enabled: boolean check if you want to conditional disable this snippet (optional)
+    name: name of the volume (required)
+    secretName: name of a kuberentes/tls secret, if not specified, use the volume name (optional)
+
+values: |
+  manifests:
+    certificates: true
+
+usage: |
+  {{- $opts := dict "enabled" "true" "name" "glance-tls-api" -}}
+  {{- $opts | include "helm-toolkit.snippets.tls_volume" -}}
+
+return: |
+  - name: glance-tls-api
+    secret:
+      secretName: glance-tls-api
+      defaultMode: 292
+*/}}
+{{- define "helm-toolkit.snippets.tls_volume" }}
+{{- $enabled := index . "enabled" -}}
+{{- $name := index . "name" -}}
+{{- $secretName := index . "secretName" | default $name -}}
+{{- if and $enabled (ne $name "") }}
+- name: {{ $name }}
+  secret:
+    secretName: {{ $secretName }}
+    defaultMode: 292
+{{- end }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_tls_volume_mount.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_tls_volume_mount.tpl
new file mode 100644
index 0000000..9cfa819
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_tls_volume_mount.tpl
@@ -0,0 +1,82 @@
+{{/*
+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.
+*/}}
+{{/*
+abstract: |
+  Renders a volume mount for TLS key, cert and CA.
+
+  Dictionary Parameters:
+    enabled: boolean check if you want to conditional disable this snippet (optional)
+    name: name that of the volume and should match the volume name (required)
+    path: path to place tls.crt tls.key ca.crt, do not suffix with '/' (required)
+    certs: a tuple containing a nonempty subset of {tls.crt, tls.key, ca.crt}.
+          the default is the full set. (optional)
+
+values: |
+  manifests:
+    certificates: true
+
+usage: |
+  {{- $opts := dict "enabled" .Values.manifests.certificates "name" "glance-tls-api" "path" "/etc/glance/certs" -}}
+  {{- $opts | include "helm-toolkit.snippets.tls_volume_mount" -}}
+
+return: |
+  - name: glance-tls-api
+    mountPath: /etc/glance/certs/tls.crt
+    subPath: tls.crt
+    readOnly: true
+  - name: glance-tls-api
+    mountPath: /etc/glance/certs/tls.key
+    subPath: tls.key
+    readOnly: true
+  - name: glance-tls-api
+    mountPath: /etc/glance/certs/ca.crt
+    subPath: ca.crt
+    readOnly: true
+
+abstract: |
+  This mounts a specific issuing CA only for service validation
+
+usage: |
+  {{- $opts := dict "enabled" .Values.manifests.certificates "name" "glance-tls-api" "ca" true -}}
+  {{- $opts | include "helm-toolkit.snippets.tls_volume_mount" -}}
+
+return: |
+  - name: glance-tls-api
+    mountPath: /etc/ssl/certs/openstack-helm.crt
+    subPath: ca.crt
+    readOnly: true
+*/}}
+{{- define "helm-toolkit.snippets.tls_volume_mount" }}
+{{- $enabled := index . "enabled" -}}
+{{- $name := index . "name" -}}
+{{- $path := index . "path" | default "" -}}
+{{- $certs := index . "certs" | default ( tuple "tls.crt" "tls.key" "ca.crt" ) }}
+{{- if $enabled }}
+{{- if and (eq $path "") (ne $name "") }}
+- name: {{ $name }}
+  mountPath: "/etc/ssl/certs/openstack-helm.crt"
+  subPath: ca.crt
+  readOnly: true
+{{- else }}
+{{- if ne $name "" }}
+{{- range $key, $value := $certs }}
+- name: {{ $name }}
+  mountPath: {{ printf "%s/%s" $path $value }}
+  subPath: {{ $value }}
+  readOnly: true
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/snippets/_values_template_renderer.tpl b/charts/nova/charts/helm-toolkit/templates/snippets/_values_template_renderer.tpl
new file mode 100644
index 0000000..7fa180a
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/snippets/_values_template_renderer.tpl
@@ -0,0 +1,87 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Renders out configuration sections into a format suitable for incorporation
+  into a config-map. Allowing various forms of input to be rendered out as
+  appropriate.
+values: |
+  conf:
+    inputs:
+      - foo
+      - bar
+    some:
+      config_to_render: |
+        #We can use all of gotpl here: eg macros, ranges etc.
+        {{ include "helm-toolkit.utils.joinListWithComma" .Values.conf.inputs }}
+      config_to_complete:
+        #here we can fill out params, but things need to be valid yaml as input
+        '{{ .Chart.Name }}': '{{ printf "%s-%s" .Release.Namespace "namespace" }}'
+      static_config:
+        #this is just passed though as yaml to the configmap
+        foo: bar
+usage: |
+  {{- $envAll := . }}
+  ---
+  apiVersion: v1
+  kind: ConfigMap
+  metadata:
+    name: application-etc
+  data:
+  {{- include "helm-toolkit.snippets.values_template_renderer" (dict "envAll" $envAll "template" .Values.conf.some.config_to_render "key" "config_to_render.conf") | indent 2 }}
+  {{- include "helm-toolkit.snippets.values_template_renderer" (dict "envAll" $envAll "template" .Values.conf.some.config_to_complete "key" "config_to_complete.yaml") | indent 2 }}
+  {{- include "helm-toolkit.snippets.values_template_renderer" (dict "envAll" $envAll "template" .Values.conf.some.static_config "key" "static_config.yaml") | indent 2 }}
+return: |
+  ---
+  apiVersion: v1
+  kind: ConfigMap
+  metadata:
+    name: application-etc
+  data:
+    config_to_render.conf: |
+      #We can use all of gotpl here: eg macros, ranges etc.
+      foo,bar
+
+    config_to_complete.yaml: |
+      'RELEASE-NAME': 'default-namespace'
+
+    static_config.yaml: |
+      foo: bar
+*/}}
+
+{{- define "helm-toolkit.snippets.values_template_renderer" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $template := index . "template" -}}
+{{- $key := index . "key" -}}
+{{- $format := index . "format" | default "configMap" -}}
+{{- with $envAll -}}
+{{- $templateRendered := tpl ( $template | toYaml ) . }}
+{{- if eq $format "Secret" }}
+{{- if hasPrefix "|\n" $templateRendered }}
+{{ $key }}: {{ regexReplaceAllLiteral "\n  " ( $templateRendered | trimPrefix "|\n" | trimPrefix "  " ) "\n" | b64enc }}
+{{- else }}
+{{ $key }}: {{ $templateRendered | b64enc }}
+{{- end -}}
+{{- else }}
+{{- if hasPrefix "|\n" $templateRendered }}
+{{ $key }}: |
+{{ regexReplaceAllLiteral "\n  " ( $templateRendered | trimPrefix "|\n" | trimPrefix "  " ) "\n" | indent 2 }}
+{{- else }}
+{{ $key }}: |
+{{ $templateRendered | indent 2 }}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/tls/_tls_generate_certs.tpl b/charts/nova/charts/helm-toolkit/templates/tls/_tls_generate_certs.tpl
new file mode 100644
index 0000000..6d617a1
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/tls/_tls_generate_certs.tpl
@@ -0,0 +1,94 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Produces a certificate from a certificate authority. If the "encode" parameter
+  is true, base64 encode the values for inclusion in a Kubernetes secret.
+values: |
+  test:
+    hosts:
+      names:
+        - barbican.openstackhelm.example
+        - barbican.openstack.svc.cluster.local
+      ips:
+        - 127.0.0.1
+        - 192.168.0.1
+    life: 3
+    # Use ca.crt and ca.key to build a customized ca, if they are provided.
+    # Use hosts.names[0] and life to auto-generate a ca, if ca is not provided.
+    ca:
+      crt: |
+        <CA CRT>
+      key: |
+        <CA PRIVATE KEY>
+usage: |
+  {{ include "helm-toolkit.utils.tls_generate_certs" (dict "params" .Values.test) }}
+return: |
+  ca: |
+    <CA CRT>
+  crt: |
+    <CRT>
+  exp: 2018-09-01T10:56:07.895392915-00:00
+  key: |
+    <CRT PRIVATE KEY>
+*/}}
+
+{{- define "helm-toolkit.utils.tls_generate_certs" -}}
+{{- $params := index . "params" -}}
+{{- $encode := index . "encode" | default false -}}
+{{- $local := dict -}}
+
+{{- $_hosts := $params.hosts.names | default list }}
+{{- if kindIs "string" $params.hosts.names }}
+{{- $_ := set $local "certHosts" (list $params.hosts.names) }}
+{{- else }}
+{{- $_ := set $local "certHosts" $_hosts }}
+{{- end }}
+
+{{- $_ips := $params.hosts.ips | default list }}
+{{- if kindIs "string" $params.hosts.ips }}
+{{- $_ := set $local "certIps" (list $params.hosts.ips) }}
+{{- else }}
+{{- $_ := set $local "certIps" $_ips }}
+{{- end }}
+
+{{- if hasKey $params "ca" }}
+{{- if and (hasKey $params.ca "crt") (hasKey $params.ca "key") }}
+{{- $ca := buildCustomCert ($params.ca.crt | b64enc ) ($params.ca.key | b64enc ) }}
+{{- $_ := set $local "ca" $ca }}
+{{- end }}
+{{- else }}
+{{- $ca := genCA (first $local.certHosts) (int $params.life) }}
+{{- $_ := set $local "ca" $ca }}
+{{- end }}
+
+{{- $expDate := date_in_zone "2006-01-02T15:04:05Z07:00" ( date_modify (printf "+%sh" (mul $params.life 24 |toString)) now ) "UTC" }}
+{{- $rawCert := genSignedCert (first $local.certHosts) ($local.certIps) ($local.certHosts) (int $params.life) $local.ca }}
+{{- $certificate := dict -}}
+{{- if $encode -}}
+{{- $_ := b64enc $rawCert.Cert | set $certificate "crt" -}}
+{{- $_ := b64enc $rawCert.Key | set $certificate "key" -}}
+{{- $_ := b64enc $local.ca.Cert | set $certificate "ca" -}}
+{{- $_ := b64enc $local.ca.Key | set $certificate "caKey" -}}
+{{- $_ := b64enc $expDate | set $certificate "exp" -}}
+{{- else -}}
+{{- $_ := set $certificate "crt" $rawCert.Cert -}}
+{{- $_ := set $certificate "key" $rawCert.Key -}}
+{{- $_ := set $certificate "ca" $local.ca.Cert -}}
+{{- $_ := set $certificate "caKey" $local.ca.Key -}}
+{{- $_ := set $certificate "exp" $expDate -}}
+{{- end -}}
+{{- $certificate | toYaml }}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/utils/_comma_joined_service_list.tpl b/charts/nova/charts/helm-toolkit/templates/utils/_comma_joined_service_list.tpl
new file mode 100644
index 0000000..e26501f
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/utils/_comma_joined_service_list.tpl
@@ -0,0 +1,46 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Returns a comma separated list of namespace:service pairs.
+values: |
+  dependencies:
+    static:
+      api:
+        services:
+          - endpoint: internal
+            service: oslo_cache
+          - endpoint: internal
+            service: oslo_db
+  endpoints:
+    oslo_db:
+      namespace: foo
+      hosts:
+        default: mariadb
+    oslo_cache:
+      namespace: bar
+      hosts:
+        default: memcache
+usage: |
+  {{ tuple .Values.dependencies.static.api.services . | include "helm-toolkit.utils.comma_joined_service_list" }}
+return: |
+  bar:memcache,foo:mariadb
+*/}}
+
+{{- define "helm-toolkit.utils.comma_joined_service_list" -}}
+{{- $deps := index . 0 -}}
+{{- $envAll := index . 1 -}}
+{{- range $k, $v := $deps -}}{{- if $k -}},{{- end -}}{{ tuple $v.service $v.endpoint $envAll | include "helm-toolkit.endpoints.service_name_endpoint_with_namespace_lookup" }}{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/utils/_configmap_templater.tpl b/charts/nova/charts/helm-toolkit/templates/utils/_configmap_templater.tpl
new file mode 100644
index 0000000..7095c19
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/utils/_configmap_templater.tpl
@@ -0,0 +1,30 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.utils.configmap_templater" }}
+{{- $keyRoot := index . 0 -}}
+{{- $configTemplate := index . 1 -}}
+{{- $context := index . 2 -}}
+{{ if $keyRoot.override -}}
+{{ $keyRoot.override | indent 4 }}
+{{- else -}}
+{{- if $keyRoot.prefix -}}
+{{ $keyRoot.prefix | indent 4 }}
+{{- end }}
+{{ tuple $configTemplate $context | include "helm-toolkit.utils.template" | indent 4 }}
+{{- end }}
+{{- if $keyRoot.append -}}
+{{ $keyRoot.append | indent 4 }}
+{{- end }}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/utils/_daemonset_overrides.tpl b/charts/nova/charts/helm-toolkit/templates/utils/_daemonset_overrides.tpl
new file mode 100644
index 0000000..40359f0
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/utils/_daemonset_overrides.tpl
@@ -0,0 +1,269 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.utils.daemonset_overrides" }}
+  {{- $daemonset := index . 0 }}
+  {{- $daemonset_yaml := index . 1 }}
+  {{- $configmap_include := index . 2 }}
+  {{- $configmap_name := index . 3 }}
+  {{- $context := index . 4 }}
+  {{- $_ := unset $context ".Files" }}
+  {{- $daemonset_root_name := printf (print $context.Chart.Name "_" $daemonset) }}
+  {{- $_ := set $context.Values "__daemonset_list" list }}
+  {{- $_ := set $context.Values "__default" dict }}
+  {{- if hasKey $context.Values.conf "overrides" }}
+    {{- range $key, $val := $context.Values.conf.overrides }}
+
+      {{- if eq $key $daemonset_root_name }}
+        {{- range $type, $type_data := . }}
+
+          {{- if eq $type "hosts" }}
+            {{- range $host_data := . }}
+              {{/* dictionary that will contain all info needed to generate this
+              iteration of the daemonset */}}
+              {{- $current_dict := dict }}
+
+              {{/* set daemonset name */}}
+              {{/* Note: long hostnames can cause the 63 char name limit to be
+              exceeded. Truncate the hostname if hostname > 20 char */}}
+              {{- if gt (len $host_data.name) 20 }}
+                {{- $_ := set $current_dict "name" (substr 0 20 $host_data.name) }}
+              {{- else }}
+                {{- $_ := set $current_dict "name" $host_data.name }}
+              {{- end }}
+
+              {{/* apply overrides */}}
+              {{- $override_conf_copy := $host_data.conf }}
+              {{/* Deep copy to prevent https://storyboard.openstack.org/#!/story/2005936 */}}
+              {{- $root_conf_copy := omit ($context.Values.conf | toYaml | fromYaml) "overrides" }}
+              {{- $merged_dict := mergeOverwrite $root_conf_copy $override_conf_copy }}
+              {{- $root_conf_copy2 := dict "conf" $merged_dict }}
+              {{- $context_values := omit (omit ($context.Values | toYaml | fromYaml) "conf") "__daemonset_list" }}
+              {{- $root_conf_copy3 := mergeOverwrite $context_values $root_conf_copy2 }}
+              {{- $root_conf_copy4 := dict "Values" $root_conf_copy3 }}
+              {{- $_ := set $current_dict "nodeData" $root_conf_copy4 }}
+
+              {{/* Schedule to this host explicitly. */}}
+              {{- $nodeSelector_dict := dict }}
+
+              {{- $_ := set $nodeSelector_dict "key" "kubernetes.io/hostname" }}
+              {{- $_ := set $nodeSelector_dict "operator" "In" }}
+
+              {{- $values_list := list $host_data.name }}
+              {{- $_ := set $nodeSelector_dict "values" $values_list }}
+
+              {{- $list_aggregate := list $nodeSelector_dict }}
+              {{- $_ := set $current_dict "matchExpressions" $list_aggregate }}
+
+              {{/* store completed daemonset entry/info into global list */}}
+              {{- $list_aggregate := append $context.Values.__daemonset_list $current_dict }}
+              {{- $_ := set $context.Values "__daemonset_list" $list_aggregate }}
+
+            {{- end }}
+          {{- end }}
+
+          {{- if eq $type "labels" }}
+            {{- $_ := set $context.Values "__label_list" . }}
+            {{- range $label_data := . }}
+              {{/* dictionary that will contain all info needed to generate this
+              iteration of the daemonset. */}}
+              {{- $_ := set $context.Values "__current_label" dict }}
+
+              {{/* set daemonset name */}}
+              {{- $_ := set $context.Values.__current_label "name" $label_data.label.key }}
+
+              {{/* apply overrides */}}
+              {{- $override_conf_copy := $label_data.conf }}
+              {{/* Deep copy to prevent https://storyboard.openstack.org/#!/story/2005936 */}}
+              {{- $root_conf_copy := omit ($context.Values.conf | toYaml | fromYaml) "overrides" }}
+              {{- $merged_dict := mergeOverwrite $root_conf_copy $override_conf_copy }}
+              {{- $root_conf_copy2 := dict "conf" $merged_dict }}
+              {{- $context_values := omit (omit ($context.Values | toYaml | fromYaml) "conf") "__daemonset_list" }}
+              {{- $root_conf_copy3 := mergeOverwrite $context_values $root_conf_copy2 }}
+              {{- $root_conf_copy4 := dict "Values" $root_conf_copy3 }}
+              {{- $_ := set $context.Values.__current_label "nodeData" $root_conf_copy4 }}
+
+              {{/* Schedule to the provided label value(s) */}}
+              {{- $label_dict := omit $label_data.label "NULL" }}
+              {{- $_ := set $label_dict "operator" "In" }}
+              {{- $list_aggregate := list $label_dict }}
+              {{- $_ := set $context.Values.__current_label "matchExpressions" $list_aggregate }}
+
+              {{/* Do not schedule to other specified labels, with higher
+              precedence as the list position increases. Last defined label
+              is highest priority. */}}
+              {{- $other_labels := without $context.Values.__label_list $label_data }}
+              {{- range $label_data2 := $other_labels }}
+                {{- $label_dict := omit $label_data2.label "NULL" }}
+
+                {{- $_ := set $label_dict "operator" "NotIn" }}
+
+                {{- $list_aggregate := append $context.Values.__current_label.matchExpressions $label_dict }}
+                {{- $_ := set $context.Values.__current_label "matchExpressions" $list_aggregate }}
+              {{- end }}
+              {{- $_ := set $context.Values "__label_list" $other_labels }}
+
+              {{/* Do not schedule to any other specified hosts */}}
+              {{- range $type, $type_data := $val }}
+                {{- if eq $type "hosts" }}
+                  {{- range $host_data := . }}
+                    {{- $label_dict := dict }}
+
+                    {{- $_ := set $label_dict "key" "kubernetes.io/hostname" }}
+                    {{- $_ := set $label_dict "operator" "NotIn" }}
+
+                    {{- $values_list := list $host_data.name }}
+                    {{- $_ := set $label_dict "values" $values_list }}
+
+                    {{- $list_aggregate := append $context.Values.__current_label.matchExpressions $label_dict }}
+                    {{- $_ := set $context.Values.__current_label "matchExpressions" $list_aggregate }}
+                  {{- end }}
+                {{- end }}
+              {{- end }}
+
+              {{/* store completed daemonset entry/info into global list */}}
+              {{- $list_aggregate := append $context.Values.__daemonset_list $context.Values.__current_label }}
+              {{- $_ := set $context.Values "__daemonset_list" $list_aggregate }}
+              {{- $_ := unset $context.Values "__current_label" }}
+
+            {{- end }}
+          {{- end }}
+        {{- end }}
+
+        {{/* scheduler exceptions for the default daemonset */}}
+        {{- $_ := set $context.Values.__default "matchExpressions" list }}
+
+        {{- range $type, $type_data := . }}
+          {{/* Do not schedule to other specified labels */}}
+          {{- if eq $type "labels" }}
+            {{- range $label_data := . }}
+              {{- $default_dict := omit $label_data.label "NULL" }}
+
+              {{- $_ := set $default_dict "operator" "NotIn" }}
+
+              {{- $list_aggregate := append $context.Values.__default.matchExpressions $default_dict }}
+              {{- $_ := set $context.Values.__default "matchExpressions" $list_aggregate }}
+            {{- end }}
+          {{- end }}
+          {{/* Do not schedule to other specified hosts */}}
+          {{- if eq $type "hosts" }}
+            {{- range $host_data := . }}
+              {{- $default_dict := dict }}
+
+              {{- $_ := set $default_dict "key" "kubernetes.io/hostname" }}
+              {{- $_ := set $default_dict "operator" "NotIn" }}
+
+              {{- $values_list := list $host_data.name }}
+              {{- $_ := set $default_dict "values" $values_list }}
+
+              {{- $list_aggregate := append $context.Values.__default.matchExpressions $default_dict }}
+              {{- $_ := set $context.Values.__default "matchExpressions" $list_aggregate }}
+            {{- end }}
+          {{- end }}
+        {{- end }}
+      {{- end }}
+    {{- end }}
+  {{- end }}
+
+  {{/* generate the default daemonset */}}
+
+  {{/* set name */}}
+  {{- $_ := set $context.Values.__default "name" "default" }}
+
+  {{/* no overrides apply, so copy as-is */}}
+  {{- $root_conf_copy1 := omit $context.Values.conf "overrides" }}
+  {{- $root_conf_copy2 := dict "conf" $root_conf_copy1 }}
+  {{- $context_values := omit $context.Values "conf" }}
+  {{- $root_conf_copy3 := mergeOverwrite $context_values $root_conf_copy2 }}
+  {{- $root_conf_copy4 := dict "Values" $root_conf_copy3 }}
+  {{- $_ := set $context.Values.__default "nodeData" $root_conf_copy4 }}
+
+  {{/* add to global list */}}
+  {{- $list_aggregate := append $context.Values.__daemonset_list $context.Values.__default }}
+  {{- $_ := set $context.Values "__daemonset_list" $list_aggregate }}
+
+  {{- range $current_dict := $context.Values.__daemonset_list }}
+
+    {{- $context_novalues := omit $context "Values" }}
+    {{- $merged_dict := mergeOverwrite $context_novalues $current_dict.nodeData }}
+    {{- $_ := set $current_dict "nodeData" $merged_dict }}
+    {{/* Deep copy original daemonset_yaml */}}
+    {{- $_ := set $context.Values "__daemonset_yaml" ($daemonset_yaml | toYaml | fromYaml) }}
+
+    {{/* name needs to be a DNS-1123 compliant name. Ensure lower case */}}
+    {{- $name_format1 := printf (print $daemonset_root_name "-" $current_dict.name) | lower }}
+    {{/* labels may contain underscores which would be invalid here, so we replace them with dashes
+    there may be other valid label names which would make for an invalid DNS-1123 name
+    but these will be easier to handle in future with sprig regex* functions
+    (not availabile in helm 2.5.1) */}}
+    {{- $name_format2 := $name_format1 | replace "_" "-" }}
+    {{/* To account for the case where the same label is defined multiple times in overrides
+    (but with different label values), we add a sha of the scheduling data to ensure
+    name uniqueness */}}
+    {{- $_ := set $current_dict "dns_1123_name" dict }}
+    {{- if hasKey $current_dict "matchExpressions" }}
+      {{- $_ := set $current_dict "dns_1123_name" (printf (print $name_format2 "-" ($current_dict.matchExpressions | quote | sha256sum | trunc 8))) }}
+    {{- else }}
+      {{- $_ := set $current_dict "dns_1123_name" $name_format2 }}
+    {{- end }}
+
+    {{/* set daemonset metadata name */}}
+    {{- if not $context.Values.__daemonset_yaml.metadata }}{{- $_ := set $context.Values.__daemonset_yaml "metadata" dict }}{{- end }}
+    {{- if not $context.Values.__daemonset_yaml.metadata.name }}{{- $_ := set $context.Values.__daemonset_yaml.metadata "name" dict }}{{- end }}
+    {{- $_ := set $context.Values.__daemonset_yaml.metadata "name" $current_dict.dns_1123_name }}
+
+    {{/* cross-reference configmap name to container volume definitions */}}
+    {{- $_ := set $context.Values "__volume_list" list }}
+    {{- range $current_volume := $context.Values.__daemonset_yaml.spec.template.spec.volumes }}
+      {{- $_ := set $context.Values "__volume" $current_volume }}
+      {{- if hasKey $context.Values.__volume "secret" }}
+        {{- if eq $context.Values.__volume.secret.secretName $configmap_name }}
+          {{- $_ := set $context.Values.__volume.secret "secretName" $current_dict.dns_1123_name }}
+        {{- end }}
+      {{- end }}
+      {{- $updated_list := append $context.Values.__volume_list $context.Values.__volume }}
+      {{- $_ := set $context.Values "__volume_list" $updated_list }}
+    {{- end }}
+    {{- $_ := set $context.Values.__daemonset_yaml.spec.template.spec "volumes" $context.Values.__volume_list }}
+
+
+    {{/* populate scheduling restrictions */}}
+    {{- if hasKey $current_dict "matchExpressions" }}
+      {{- if not $context.Values.__daemonset_yaml.spec.template.spec }}{{- $_ := set $context.Values.__daemonset_yaml.spec.template "spec" dict }}{{- end }}
+      {{- if not $context.Values.__daemonset_yaml.spec.template.spec.affinity }}{{- $_ := set $context.Values.__daemonset_yaml.spec.template.spec "affinity" dict }}{{- end }}
+      {{- if not $context.Values.__daemonset_yaml.spec.template.spec.affinity.nodeAffinity }}{{- $_ := set $context.Values.__daemonset_yaml.spec.template.spec.affinity "nodeAffinity" dict }}{{- end }}
+      {{- if not $context.Values.__daemonset_yaml.spec.template.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution }}{{- $_ := set $context.Values.__daemonset_yaml.spec.template.spec.affinity.nodeAffinity "requiredDuringSchedulingIgnoredDuringExecution" dict }}{{- end }}
+      {{- $match_exprs := dict }}
+      {{- $_ := set $match_exprs "matchExpressions" $current_dict.matchExpressions }}
+      {{- $appended_match_expr := list $match_exprs }}
+      {{- $_ := set $context.Values.__daemonset_yaml.spec.template.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution "nodeSelectorTerms" $appended_match_expr }}
+    {{- end }}
+
+    {{/* input value hash for current set of values overrides */}}
+    {{- if not $context.Values.__daemonset_yaml.spec }}{{- $_ := set $context.Values.__daemonset_yaml "spec" dict }}{{- end }}
+    {{- if not $context.Values.__daemonset_yaml.spec.template }}{{- $_ := set $context.Values.__daemonset_yaml.spec "template" dict }}{{- end }}
+    {{- if not $context.Values.__daemonset_yaml.spec.template.metadata }}{{- $_ := set $context.Values.__daemonset_yaml.spec.template "metadata" dict }}{{- end }}
+    {{- if not $context.Values.__daemonset_yaml.spec.template.metadata.annotations }}{{- $_ := set $context.Values.__daemonset_yaml.spec.template.metadata "annotations" dict }}{{- end }}
+    {{- $cmap := list $current_dict.dns_1123_name $current_dict.nodeData | include $configmap_include }}
+    {{- $values_hash := $cmap | quote | sha256sum }}
+    {{- $_ := set $context.Values.__daemonset_yaml.spec.template.metadata.annotations "configmap-etc-hash" $values_hash }}
+
+    {{/* generate configmap */}}
+---
+{{ $cmap }}
+    {{/* generate daemonset yaml */}}
+---
+{{ $context.Values.__daemonset_yaml | toYaml }}
+  {{- end }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/utils/_dependency_resolver.tpl b/charts/nova/charts/helm-toolkit/templates/utils/_dependency_resolver.tpl
new file mode 100644
index 0000000..b99c00d
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/utils/_dependency_resolver.tpl
@@ -0,0 +1,38 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.utils.dependency_resolver" }}
+{{- $envAll := index . "envAll" -}}
+{{- $dependencyMixinParam := index . "dependencyMixinParam" -}}
+{{- $dependencyKey := index . "dependencyKey" -}}
+{{- if $dependencyMixinParam -}}
+{{- $_ := set $envAll.Values "pod_dependency" dict -}}
+{{- if kindIs "string" $dependencyMixinParam }}
+{{- if ( index $envAll.Values.dependencies.dynamic.targeted $dependencyMixinParam ) }}
+{{- $_ := include "helm-toolkit.utils.merge" (tuple $envAll.Values.pod_dependency ( index $envAll.Values.dependencies.static $dependencyKey ) ( index $envAll.Values.dependencies.dynamic.targeted $dependencyMixinParam $dependencyKey ) ) -}}
+{{- else }}
+{{- $_ := set $envAll.Values "pod_dependency" ( index $envAll.Values.dependencies.static $dependencyKey ) }}
+{{- end }}
+{{- else if kindIs "slice" $dependencyMixinParam }}
+{{- $_ := set $envAll.Values "__deps" ( index $envAll.Values.dependencies.static $dependencyKey ) }}
+{{- range $k, $v := $dependencyMixinParam -}}
+{{- $_ := include "helm-toolkit.utils.merge" (tuple $envAll.Values.pod_dependency $envAll.Values.__deps ( index $envAll.Values.dependencies.dynamic.targeted $v $dependencyKey ) ) -}}
+{{- $_ := set $envAll.Values "__deps" $envAll.Values.pod_dependency -}}
+{{- end }}
+{{- end }}
+{{- else -}}
+{{- $_ := set $envAll.Values "pod_dependency" ( index $envAll.Values.dependencies.static $dependencyKey ) -}}
+{{- end -}}
+{{ $envAll.Values.pod_dependency | toYaml }}
+{{- end }}
diff --git a/charts/nova/charts/helm-toolkit/templates/utils/_hash.tpl b/charts/nova/charts/helm-toolkit/templates/utils/_hash.tpl
new file mode 100644
index 0000000..d871b62
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/utils/_hash.tpl
@@ -0,0 +1,21 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.utils.hash" -}}
+{{- $name := index . 0 -}}
+{{- $context := index . 1 -}}
+{{- $last := base $context.Template.Name }}
+{{- $wtf := $context.Template.Name | replace $last $name -}}
+{{- include $wtf $context | sha256sum | quote -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/utils/_host_list.tpl b/charts/nova/charts/helm-toolkit/templates/utils/_host_list.tpl
new file mode 100644
index 0000000..0c32136
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/utils/_host_list.tpl
@@ -0,0 +1,44 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Returns a list of unique hosts for an endpoint, in yaml.
+values: |
+  endpoints:
+    cluster_domain_suffix: cluster.local
+    oslo_db:
+      hosts:
+        default: mariadb
+      host_fqdn_override:
+        default: mariadb
+usage: |
+  {{ tuple "oslo_db" "internal" . | include "helm-toolkit.utils.host_list" }}
+return: |
+  hosts:
+  - mariadb
+  - mariadb.default
+*/}}
+
+{{- define "helm-toolkit.utils.host_list" -}}
+{{- $type := index . 0 -}}
+{{- $endpoint := index . 1 -}}
+{{- $context := index . 2 -}}
+{{- $host_fqdn := tuple $type $endpoint $context | include "helm-toolkit.endpoints.hostname_fqdn_endpoint_lookup" }}
+{{- $host_namespaced := tuple $type $endpoint $context | include "helm-toolkit.endpoints.hostname_namespaced_endpoint_lookup" }}
+{{- $host_short := tuple $type $endpoint $context | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }}
+{{/* It is important that the FQDN host is 1st in this list, to ensure other function can use the 1st element for cert gen CN etc */}}
+{{- $host_list := list $host_fqdn $host_namespaced $host_short | uniq }}
+{{- dict "hosts" $host_list | toYaml }}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/utils/_image_sync_list.tpl b/charts/nova/charts/helm-toolkit/templates/utils/_image_sync_list.tpl
new file mode 100644
index 0000000..51923b6
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/utils/_image_sync_list.tpl
@@ -0,0 +1,25 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.utils.image_sync_list" -}}
+{{- $imageExcludeList := .Values.images.local_registry.exclude -}}
+{{- $imageDict := .Values.images.tags -}}
+{{- $local := dict "first" true -}}
+{{- range $k, $v := $imageDict -}}
+{{- if not $local.first -}},{{- end -}}
+{{- if (not (has $k $imageExcludeList )) -}}
+{{- index $imageDict $k -}}
+{{- $_ := set $local "first" false -}}
+{{- end -}}{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/utils/_joinListWithComma.tpl b/charts/nova/charts/helm-toolkit/templates/utils/_joinListWithComma.tpl
new file mode 100644
index 0000000..5eb5785
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/utils/_joinListWithComma.tpl
@@ -0,0 +1,31 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Joins a list of values into a comma separated string
+values: |
+  test:
+    - foo
+    - bar
+usage: |
+  {{ include "helm-toolkit.utils.joinListWithComma" .Values.test }}
+return: |
+  foo,bar
+*/}}
+
+{{- define "helm-toolkit.utils.joinListWithComma" -}}
+{{- $local := dict "first" true -}}
+{{- range $k, $v := . -}}{{- if not $local.first -}},{{- end -}}{{- $v -}}{{- $_ := set $local "first" false -}}{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/utils/_joinListWithCommaAndSingleQuotes.tpl b/charts/nova/charts/helm-toolkit/templates/utils/_joinListWithCommaAndSingleQuotes.tpl
new file mode 100644
index 0000000..3bc6819
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/utils/_joinListWithCommaAndSingleQuotes.tpl
@@ -0,0 +1,32 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Joins a list of values into a comma seperated string with single quotes
+  around each value.
+values: |
+  test:
+    - foo
+    - bar
+usage: |
+  {{ include "helm-toolkit.utils.joinListWithCommaAndSingleQuotes" .Values.test }}
+return: |
+  'foo','bar'
+*/}}
+
+{{- define "helm-toolkit.utils.joinListWithCommaAndSingleQuotes" -}}
+{{- $local := dict "first" true -}}
+{{- range $k, $v := . -}}{{- if not $local.first -}},{{- end -}}'{{- $v -}}'{{- $_ := set $local "first" false -}}{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/utils/_joinListWithPrefix.tpl b/charts/nova/charts/helm-toolkit/templates/utils/_joinListWithPrefix.tpl
new file mode 100644
index 0000000..40ebb15
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/utils/_joinListWithPrefix.tpl
@@ -0,0 +1,32 @@
+{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Joins a list of prefixed values into a space separated string
+values: |
+  test:
+    - foo
+    - bar
+usage: |
+  {{ tuple "prefix" .Values.test | include "helm-toolkit.utils.joinListWithPrefix" }}
+return: |
+  prefixfoo prefixbar
+*/}}
+
+{{- define "helm-toolkit.utils.joinListWithPrefix" -}}
+{{- $prefix := index . 0 -}}
+{{- $local := dict "first" true -}}
+{{- range $k, $v := index . 1 -}}{{- if not $local.first -}}{{- " " -}}{{- end -}}{{- $prefix -}}{{- $v -}}{{- $_ := set $local "first" false -}}{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/utils/_joinListWithSpace.tpl b/charts/nova/charts/helm-toolkit/templates/utils/_joinListWithSpace.tpl
new file mode 100644
index 0000000..5912280
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/utils/_joinListWithSpace.tpl
@@ -0,0 +1,31 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Joins a list of values into a space separated string
+values: |
+  test:
+    - foo
+    - bar
+usage: |
+  {{ include "helm-toolkit.utils.joinListWithSpace" .Values.test }}
+return: |
+  foo bar
+*/}}
+
+{{- define "helm-toolkit.utils.joinListWithSpace" -}}
+{{- $local := dict "first" true -}}
+{{- range $k, $v := . -}}{{- if not $local.first -}}{{- " " -}}{{- end -}}{{- $v -}}{{- $_ := set $local "first" false -}}{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/utils/_merge.tpl b/charts/nova/charts/helm-toolkit/templates/utils/_merge.tpl
new file mode 100644
index 0000000..ea80546
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/utils/_merge.tpl
@@ -0,0 +1,135 @@
+{{/*
+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.
+*/}}
+
+{{/*
+Takes a tuple of values and merges into the first (target) one each subsequent
+(source) one in order. If all values to merge are maps, then the tuple can be
+passed as is and the target will be the result, otherwise pass a map with a
+"values" key containing the tuple of values to merge, and the merge result will
+be assigned to the "result" key of the passed map.
+
+When merging maps, for each key in the source, if the target does not define
+that key, the source value is assigned. If both define the key, then the key
+values are merged using this algorithm (recursively) and the result is assigned
+to the target key. Slices are merged by appending them and removing any
+duplicates, and when passing a map to this function and including a
+"merge_same_named" key set to true, then map items from the slices with the same
+value for the "name" key will be merged with each other. Any other values are
+merged by simply keeping the source, and throwing away the target.
+*/}}
+
+{{- define "helm-toolkit.utils.merge" -}}
+  {{- $local := dict -}}
+  {{- $_ := set $local "merge_same_named" false -}}
+  {{- if kindIs "map" $ -}}
+    {{- $_ := set $local "values" $.values -}}
+    {{- if hasKey $ "merge_same_named" -}}
+      {{- $_ := set $local "merge_same_named" $.merge_same_named -}}
+    {{- end -}}
+  {{- else -}}
+    {{- $_ := set $local "values" $ -}}
+  {{- end -}}
+
+  {{- $target := first $local.values -}}
+  {{- range $item := rest $local.values -}}
+    {{- $call := dict "target" $target "source" . "merge_same_named" $local.merge_same_named -}}
+    {{- $_ := include "helm-toolkit.utils._merge" $call -}}
+    {{- $_ := set $local "result" $call.result -}}
+  {{- end -}}
+
+  {{- if kindIs "map" $ -}}
+    {{- $_ := set $ "result" $local.result -}}
+  {{- end -}}
+{{- end -}}
+
+{{- define "helm-toolkit.utils._merge" -}}
+  {{- $local := dict -}}
+
+  {{- $_ := set $ "result" $.source -}}
+
+  {{/*
+  TODO: Should we `fail` when trying to merge a collection (map or slice) with
+  either a different kind of collection or a scalar?
+  */}}
+
+  {{- if and (kindIs "map" $.target) (kindIs "map" $.source) -}}
+    {{- range $key, $sourceValue := $.source -}}
+      {{- if not (hasKey $.target $key) -}}
+        {{- $_ := set $local "newTargetValue" $sourceValue -}}
+        {{- if kindIs "map" $sourceValue -}}
+          {{- $copy := dict -}}
+          {{- $call := dict "target" $copy "source" $sourceValue -}}
+          {{- $_ := include "helm-toolkit.utils._merge.shallow" $call -}}
+          {{- $_ := set $local "newTargetValue" $copy -}}
+        {{- end -}}
+      {{- else -}}
+        {{- $targetValue := index $.target $key -}}
+        {{- $call := dict "target" $targetValue "source" $sourceValue "merge_same_named" $.merge_same_named -}}
+        {{- $_ := include "helm-toolkit.utils._merge" $call -}}
+        {{- $_ := set $local "newTargetValue" $call.result -}}
+      {{- end -}}
+      {{- $_ := set $.target $key $local.newTargetValue -}}
+    {{- end -}}
+    {{- $_ := set $ "result" $.target -}}
+  {{- else if and (kindIs "slice" $.target) (kindIs "slice" $.source) -}}
+    {{- $call := dict "target" $.target "source" $.source -}}
+    {{- $_ := include "helm-toolkit.utils._merge.append_slice" $call -}}
+    {{- if $.merge_same_named -}}
+      {{- $_ := set $local "result" list -}}
+      {{- $_ := set $local "named_items" dict -}}
+      {{- range $item := $call.result -}}
+      {{- $_ := set $local "has_name_key" false -}}
+        {{- if kindIs "map" $item -}}
+          {{- if hasKey $item "name" -}}
+            {{- $_ := set $local "has_name_key" true -}}
+          {{- end -}}
+        {{- end -}}
+
+        {{- if $local.has_name_key -}}
+          {{- if hasKey $local.named_items $item.name -}}
+            {{- $named_item := index $local.named_items $item.name -}}
+            {{- $call := dict "target" $named_item "source" $item "merge_same_named" $.merge_same_named -}}
+            {{- $_ := include "helm-toolkit.utils._merge" $call -}}
+          {{- else -}}
+            {{- $copy := dict -}}
+            {{- $copy_call := dict "target" $copy "source" $item -}}
+            {{- $_ := include "helm-toolkit.utils._merge.shallow" $copy_call -}}
+            {{- $_ := set $local.named_items $item.name $copy -}}
+            {{- $_ := set $local "result" (append $local.result $copy) -}}
+          {{- end -}}
+        {{- else -}}
+          {{- $_ := set $local "result" (append $local.result $item) -}}
+        {{- end -}}
+      {{- end -}}
+    {{- else -}}
+      {{- $_ := set $local "result" $call.result -}}
+    {{- end -}}
+    {{- $_ := set $ "result" (uniq $local.result) -}}
+  {{- end -}}
+{{- end -}}
+
+{{- define "helm-toolkit.utils._merge.shallow" -}}
+  {{- range $key, $value := $.source -}}
+    {{- $_ := set $.target $key $value -}}
+  {{- end -}}
+{{- end -}}
+
+{{- define "helm-toolkit.utils._merge.append_slice" -}}
+  {{- $local := dict -}}
+  {{- $_ := set $local "result" $.target -}}
+  {{- range $value := $.source -}}
+    {{- $_ := set $local "result" (append $local.result $value) -}}
+  {{- end -}}
+  {{- $_ := set $ "result" $local.result -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/utils/_template.tpl b/charts/nova/charts/helm-toolkit/templates/utils/_template.tpl
new file mode 100644
index 0000000..da56aa0
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/utils/_template.tpl
@@ -0,0 +1,21 @@
+{{/*
+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.
+*/}}
+
+{{- define "helm-toolkit.utils.template" -}}
+{{- $name := index . 0 -}}
+{{- $context := index . 1 -}}
+{{- $last := base $context.Template.Name }}
+{{- $wtf := $context.Template.Name | replace $last $name -}}
+{{ include $wtf $context }}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/utils/_to_ini.tpl b/charts/nova/charts/helm-toolkit/templates/utils/_to_ini.tpl
new file mode 100644
index 0000000..a159364
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/utils/_to_ini.tpl
@@ -0,0 +1,51 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Returns INI formatted output from yaml input
+values: |
+  conf:
+    paste:
+      filter:debug:
+        use: egg:oslo.middleware#debug
+      filter:request_id:
+        use: egg:oslo.middleware#request_id
+      filter:build_auth_context:
+        use: egg:keystone#build_auth_context
+usage: |
+  {{ include "helm-toolkit.utils.to_ini" .Values.conf.paste }}
+return: |
+  [filter:build_auth_context]
+  use = egg:keystone#build_auth_context
+  [filter:debug]
+  use = egg:oslo.middleware#debug
+  [filter:request_id]
+  use = egg:oslo.middleware#request_id
+*/}}
+
+{{- define "helm-toolkit.utils.to_ini" -}}
+{{- range $section, $values := . -}}
+{{- if kindIs "map" $values -}}
+[{{ $section }}]
+{{range $key, $value := $values -}}
+{{- if kindIs "slice" $value -}}
+{{ $key }} = {{ include "helm-toolkit.utils.joinListWithComma" $value }}
+{{else -}}
+{{ $key }} = {{ $value }}
+{{end -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/utils/_to_k8s_env_secret_vars.tpl b/charts/nova/charts/helm-toolkit/templates/utils/_to_k8s_env_secret_vars.tpl
new file mode 100644
index 0000000..d66663f
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/utils/_to_k8s_env_secret_vars.tpl
@@ -0,0 +1,46 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Returns yaml formatted to be used in k8s templates as container
+  env vars injected via secrets. This requires a secret-<chartname> template to
+  be defined in the chart that can be used to house the desired secret
+  variables. For reference, see the fluentd chart.
+values: |
+  test:
+    secrets:
+      foo: bar
+
+usage: |
+  {{ include "helm-toolkit.utils.to_k8s_env_vars" .Values.test }}
+return: |
+  - name: foo
+    valueFrom:
+      secretKeyRef:
+        name: "my-release-name-env-secret"
+        key: foo
+*/}}
+
+{{- define "helm-toolkit.utils.to_k8s_env_secret_vars" -}}
+{{- $context := index . 0 -}}
+{{- $secrets := index . 1 -}}
+{{ range $key, $config := $secrets -}}
+- name: {{ $key }}
+  valueFrom:
+    secretKeyRef:
+      name: {{ printf "%s-%s" $context.Chart.Name "env-secret" | quote }}
+      key: {{ $key }}
+{{ end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/utils/_to_k8s_env_vars.tpl b/charts/nova/charts/helm-toolkit/templates/utils/_to_k8s_env_vars.tpl
new file mode 100644
index 0000000..829dca6
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/utils/_to_k8s_env_vars.tpl
@@ -0,0 +1,39 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Returns key value pair formatted to be used in k8s templates as container
+  env vars.
+values: |
+  test:
+    foo: bar
+usage: |
+  {{ include "helm-toolkit.utils.to_k8s_env_vars" .Values.test }}
+return: |
+  - name: foo
+    value: "bar"
+*/}}
+
+{{- define "helm-toolkit.utils.to_k8s_env_vars" -}}
+{{range $key, $value := . -}}
+{{- if kindIs "slice" $value -}}
+- name: {{ $key }}
+  value: {{ include "helm-toolkit.utils.joinListWithComma" $value | quote }}
+{{else -}}
+- name: {{ $key }}
+  value: {{ $value | quote }}
+{{ end -}}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/utils/_to_kv_list.tpl b/charts/nova/charts/helm-toolkit/templates/utils/_to_kv_list.tpl
new file mode 100644
index 0000000..91bdeb6
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/utils/_to_kv_list.tpl
@@ -0,0 +1,42 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Returns key value pair in INI format (key = value)
+values: |
+  conf:
+    libvirt:
+      log_level: 3
+usage: |
+  {{ include "helm-toolkit.utils.to_kv_list" .Values.conf.libvirt }}
+return: |
+  log_level = 3
+*/}}
+
+{{- define "helm-toolkit.utils.to_kv_list" -}}
+{{- range $key, $value :=  . -}}
+{{- if kindIs "slice" $value }}
+{{ $key }} = {{ include "helm-toolkit.utils.joinListWithComma" $value | quote }}
+{{- else if kindIs "string" $value }}
+{{- if regexMatch "^[0-9]+$" $value }}
+{{ $key }} = {{ $value }}
+{{- else }}
+{{ $key }} = {{ $value | quote }}
+{{- end }}
+{{- else }}
+{{ $key }} = {{ $value }}
+{{- end }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/templates/utils/_to_oslo_conf.tpl b/charts/nova/charts/helm-toolkit/templates/utils/_to_oslo_conf.tpl
new file mode 100644
index 0000000..622a862
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/templates/utils/_to_oslo_conf.tpl
@@ -0,0 +1,75 @@
+{{/*
+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.
+*/}}
+
+{{/*
+abstract: |
+  Returns OSLO.conf formatted output from yaml input
+values: |
+  conf:
+    keystone:
+      DEFAULT: # Keys at this level are used for section headings
+        max_token_size: 255
+      oslo_messaging_notifications:
+        driver: # An example of a multistring option's syntax
+          type: multistring
+          values:
+            - messagingv2
+            - log
+      oslo_messaging_notifications_stein:
+        driver: # An example of a csv option's syntax
+          type: csv
+          values:
+            - messagingv2
+            - log
+      security_compliance:
+        password_expires_ignore_user_ids:
+        # Values in a list will be converted to a comma separated key
+          - "123"
+          - "456"
+usage: |
+  {{ include "helm-toolkit.utils.to_oslo_conf" .Values.conf.keystone }}
+return: |
+  [DEFAULT]
+  max_token_size = 255
+  [oslo_messaging_notifications]
+  driver = messagingv2
+  driver = log
+  [oslo_messaging_notifications_stein]
+  driver = messagingv2,log
+  [security_compliance]
+  password_expires_ignore_user_ids = 123,456
+*/}}
+
+{{- define "helm-toolkit.utils.to_oslo_conf" -}}
+{{- range $section, $values := . -}}
+{{- if kindIs "map" $values -}}
+[{{ $section }}]
+{{ range $key, $value := $values -}}
+{{- if kindIs "slice" $value -}}
+{{ $key }} = {{ include "helm-toolkit.utils.joinListWithComma" $value }}
+{{ else if kindIs "map" $value -}}
+{{- if eq $value.type "multistring" }}
+{{- range $k, $multistringValue := $value.values -}}
+{{ $key }} = {{ $multistringValue }}
+{{ end -}}
+{{ else if eq $value.type "csv" -}}
+{{ $key }} = {{ include "helm-toolkit.utils.joinListWithComma" $value.values }}
+{{ end -}}
+{{- else -}}
+{{ $key }} = {{ $value }}
+{{ end -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/charts/helm-toolkit/values.yaml b/charts/nova/charts/helm-toolkit/values.yaml
new file mode 100644
index 0000000..681a92b
--- /dev/null
+++ b/charts/nova/charts/helm-toolkit/values.yaml
@@ -0,0 +1,16 @@
+# 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.
+
+# Default values for utils.
+# This is a YAML-formatted file.
+# Declare name/value pairs to be passed into your templates.
+# name: value
diff --git a/charts/nova/requirements.lock b/charts/nova/requirements.lock
new file mode 100644
index 0000000..159c53a
--- /dev/null
+++ b/charts/nova/requirements.lock
@@ -0,0 +1,6 @@
+dependencies:
+- name: helm-toolkit
+  repository: file://../../openstack-helm-infra/helm-toolkit
+  version: 0.2.38
+digest: sha256:5e8c9ccd0834d092abdcf29f1a6d79c906d4aa9f61c375d617f69a342c40747f
+generated: "2022-03-25T19:12:55.919908558Z"
diff --git a/charts/nova/requirements.yaml b/charts/nova/requirements.yaml
new file mode 100644
index 0000000..4124d01
--- /dev/null
+++ b/charts/nova/requirements.yaml
@@ -0,0 +1,16 @@
+# 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"
diff --git a/charts/nova/templates/bin/_bootstrap.sh.tpl b/charts/nova/templates/bin/_bootstrap.sh.tpl
new file mode 100644
index 0000000..9cb48b1
--- /dev/null
+++ b/charts/nova/templates/bin/_bootstrap.sh.tpl
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+{{/*
+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 -ex
+export HOME=/tmp
+
+{{ if .Values.bootstrap.structured.flavors.enabled }}
+{{ range .Values.bootstrap.structured.flavors.options }}
+# NOTE(aostapenko) Since Wallaby with switch of osc to sdk '--id auto' is no
+# longer treated specially. Though the same behavior can be achieved w/o specifying
+#--id flag.
+# https://review.opendev.org/c/openstack/python-openstackclient/+/750151
+{
+  openstack flavor show {{ .name }} || \
+   openstack flavor create {{ .name }} \
+{{ if .id }} \
+   --id {{ .id }} \
+{{ end }} \
+   --ram {{ .ram }} \
+   --disk {{ .disk }} \
+   --vcpus {{ .vcpus }}
+} &
+{{ end }}
+wait
+{{ end }}
+
+{{ if .Values.bootstrap.wait_for_computes.enabled }}
+{{ .Values.bootstrap.wait_for_computes.scripts.wait_script }}
+{{ else }}
+echo 'Wait for Computes script not enabled'
+{{ end }}
+
+{{ .Values.bootstrap.script | default "echo 'No other bootstrap customizations found.'" }}
diff --git a/charts/nova/templates/bin/_cell-setup-init.sh.tpl b/charts/nova/templates/bin/_cell-setup-init.sh.tpl
new file mode 100644
index 0000000..9535085
--- /dev/null
+++ b/charts/nova/templates/bin/_cell-setup-init.sh.tpl
@@ -0,0 +1,71 @@
+#!/bin/bash
+
+{{/*
+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 -ex
+
+{{- if .Values.jobs.cell_setup.extended_wait.enabled }}
+iteration={{ .Values.jobs.cell_setup.extended_wait.iteration }}
+duration={{ .Values.jobs.cell_setup.extended_wait.duration }}
+extra_wait=true
+# Init for case wait_for_computes is not enabled. It'll have
+# the same effect as the original code that checks for at
+# least one compute is registered
+expected_computes=1
+
+if [[ -f /tmp/compute_nodes.txt ]]
+then
+  expected_computes=$(cat /tmp/compute_nodes.txt | wc -w)
+fi
+
+while [[ "$extra_wait" == true ]]
+do
+  nova_computes=$(openstack compute service list --service nova-compute -f value -c State)
+
+  if [[ -z "$(echo $nova_computes | grep down)" ]]
+  then
+    # No more down. Although all present computes are up,
+    # the number of present computes may not be the total
+    # expected number of computes as some of the remaining
+    # computes may take a bit longer to register/join.
+    actual_computes=$(echo $nova_computes | wc -w)
+    if [[ "$actual_computes" -ge "$expected_computes" ]]
+    then
+      # All expected nodes are up
+      extra_wait=false
+    fi
+  fi
+
+  if [[ "$extra_wait" == true ]]
+  then
+    sleep "$duration"
+
+    if [[ "$iteration" -gt 1 ]]
+    then
+      ((iteration=iteration-1))
+    else
+      extra_wait=false
+
+      # List out the info to see whether any nodes is still down
+      openstack compute service list --service nova-compute
+    fi
+  fi
+done
+{{- end }}
+
+until openstack compute service list --service nova-compute -f value -c State | grep -q "^up$" ;do
+  echo "Waiting for Nova Compute processes to register"
+  sleep 10
+done
diff --git a/charts/nova/templates/bin/_cell-setup.sh.tpl b/charts/nova/templates/bin/_cell-setup.sh.tpl
new file mode 100644
index 0000000..45c9771
--- /dev/null
+++ b/charts/nova/templates/bin/_cell-setup.sh.tpl
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+{{/*
+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 -ex
+
+NOVA_VERSION=$(nova-manage --version 2>&1 | grep -Eo '[0-9]+[.][0-9]+[.][0-9]+')
+
+# NOTE(portdirect): check if nova fully supports cells v2, and manage
+# accordingly. Support was complete in ocata (V14.x.x).
+
+if [ "${NOVA_VERSION%%.*}" -gt "14" ]; then
+  nova-manage cell_v2 discover_hosts --verbose
+fi
diff --git a/charts/nova/templates/bin/_ceph-admin-keyring.sh.tpl b/charts/nova/templates/bin/_ceph-admin-keyring.sh.tpl
new file mode 100644
index 0000000..8c36d4b
--- /dev/null
+++ b/charts/nova/templates/bin/_ceph-admin-keyring.sh.tpl
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+{{/*
+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 -ex
+export HOME=/tmp
+
+cat > /etc/ceph/ceph.client.admin.keyring << EOF
+[client.admin]
+{{- if .Values.conf.ceph.admin_keyring }}
+    key = {{ .Values.conf.ceph.admin_keyring }}
+{{- else }}
+    key = $(cat /tmp/client-keyring)
+{{- end }}
+EOF
+
+exit 0
diff --git a/charts/nova/templates/bin/_ceph-keyring.sh.tpl b/charts/nova/templates/bin/_ceph-keyring.sh.tpl
new file mode 100644
index 0000000..b9237e8
--- /dev/null
+++ b/charts/nova/templates/bin/_ceph-keyring.sh.tpl
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+{{/*
+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 -ex
+export HOME=/tmp
+
+cp -vf /etc/ceph/ceph.conf.template /etc/ceph/ceph.conf
+
+KEYRING=/etc/ceph/ceph.client.${CEPH_CINDER_USER}.keyring
+{{- if .Values.conf.ceph.cinder.keyring }}
+cat > ${KEYRING} <<EOF
+[client.{{ .Values.conf.ceph.cinder.user }}]
+    key = {{ .Values.conf.ceph.cinder.keyring }}
+EOF
+{{- else }}
+if ! [ "x${CEPH_CINDER_USER}" == "xadmin" ]; then
+  #
+  # If user is not client.admin, check if it already exists. If not create
+  # the user. If the cephx user does not exist make sure the caps are set
+  # according to best practices
+  #
+  if USERINFO=$(ceph auth get client.${CEPH_CINDER_USER}); then
+    echo "Cephx user client.${CEPH_CINDER_USER} already exist"
+    echo "Update user client.${CEPH_CINDER_USER} caps"
+    ceph auth caps client.${CEPH_CINDER_USER} \
+       mon "profile rbd" \
+       osd "profile rbd"
+    ceph auth get client.${CEPH_CINDER_USER} -o ${KEYRING}
+  else
+    echo "Creating Cephx user client.${CEPH_CINDER_USER}"
+    ceph auth get-or-create client.${CEPH_CINDER_USER} \
+      mon "profile rbd" \
+      osd "profile rbd" \
+      -o ${KEYRING}
+  fi
+  rm -f /etc/ceph/ceph.client.admin.keyring
+fi
+{{- end }}
diff --git a/charts/nova/templates/bin/_db-archive-deleted-row.sh.tpl b/charts/nova/templates/bin/_db-archive-deleted-row.sh.tpl
new file mode 100644
index 0000000..a4b986b
--- /dev/null
+++ b/charts/nova/templates/bin/_db-archive-deleted-row.sh.tpl
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+{{/*
+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 -ex
+
+exec nova-manage db archive_deleted_rows \
+{{- if .Values.conf.archive_deleted_rows.until_completion }}
+   --until-complete \
+{{- end}}
+{{- if .Values.conf.archive_deleted_rows.purge_delete_rows }}
+   --purge \
+{{- end }}
+{{- if .Values.conf.archive_deleted_rows.all_cells }}
+   --all-cells \
+{{- end}}
+{{- if .Values.conf.archive_deleted_rows.max_rows.enabled }}
+   --max_rows {{ .Values.conf.archive_deleted_rows.max_rows.rows }} \
+{{- end }}
+{{- if .Values.conf.archive_deleted_rows.before.enabled }}
+   --before "{{ .Values.conf.archive_deleted_rows.before.date }}" \
+{{- end }}
+   --verbose
diff --git a/charts/nova/templates/bin/_db-sync.sh.tpl b/charts/nova/templates/bin/_db-sync.sh.tpl
new file mode 100644
index 0000000..e688238
--- /dev/null
+++ b/charts/nova/templates/bin/_db-sync.sh.tpl
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+{{/*
+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 -ex
+NOVA_VERSION=$(nova-manage --version 2>&1 | grep -Eo '[0-9]+[.][0-9]+[.][0-9]+')
+
+function manage_cells () {
+  # NOTE(portdirect): check if nova fully supports cells v2, and manage
+  # accordingly. Support was complete in ocata (V14.x.x).
+  if [ "${NOVA_VERSION%%.*}" -gt "14" ]; then
+    nova-manage cell_v2 map_cell0
+    nova-manage cell_v2 list_cells | grep -q " cell1 " || \
+      nova-manage cell_v2 create_cell --name=cell1 --verbose
+
+    CELL0_ID=$(nova-manage cell_v2 list_cells | awk -F '|' '/ cell0 / { print $3 }' | tr -d ' ')
+    CELL1_ID=$(nova-manage cell_v2 list_cells | awk -F '|' '/ cell1 / { print $3 }' | tr -d ' ')
+    set +x
+
+    CELL0_TRANSPORT=$(nova-manage cell_v2 list_cells | awk -F '|' '/ cell0 / { print $4 }' | tr -d ' ')
+    if [ -z "${DB_CONNECTION_CELL0}" ]; then
+      echo "ERROR: missing DB_CONNECTION_CELL0"
+      exit 1
+    fi
+    nova-manage cell_v2 update_cell \
+      --cell_uuid="${CELL0_ID}" \
+      --name="cell0" \
+      --transport-url="${CELL0_TRANSPORT}" \
+      --database_connection="${DB_CONNECTION_CELL0}"
+
+    for VAR in TRANSPORT_URL DB_CONNECTION; do
+      if [ -z "${!VAR}" ]; then
+        echo "ERROR: missing $VAR variable"
+        exit 1
+      fi
+    done
+    nova-manage cell_v2 update_cell \
+      --cell_uuid="${CELL1_ID}" \
+      --name="cell1" \
+      --transport-url="${TRANSPORT_URL}" \
+      --database_connection="${DB_CONNECTION}"
+    set -x
+  fi
+}
+
+# NOTE(aostapenko) Starting Wallaby nova-manage api_db version returns init version for empty database
+# greater than 0 # https://opendev.org/openstack/nova/src/branch/stable/wallaby/nova/db/sqlalchemy/migration.py#L32
+# thus logic prior to this commit does not work. We need to either remove or justify and alter previous logic.
+nova-manage api_db sync
+manage_cells
+
+nova-manage db sync
+
+nova-manage db online_data_migrations
+
+echo 'Finished DB migrations'
diff --git a/charts/nova/templates/bin/_fake-iptables.sh.tpl b/charts/nova/templates/bin/_fake-iptables.sh.tpl
new file mode 100644
index 0000000..78cbd46
--- /dev/null
+++ b/charts/nova/templates/bin/_fake-iptables.sh.tpl
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+{{/*
+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.
+*/}}
+
+exit 0
diff --git a/charts/nova/templates/bin/_health-probe.py.tpl b/charts/nova/templates/bin/_health-probe.py.tpl
new file mode 100644
index 0000000..0185319
--- /dev/null
+++ b/charts/nova/templates/bin/_health-probe.py.tpl
@@ -0,0 +1,259 @@
+#!/usr/bin/env python
+
+# 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.
+
+"""
+Health probe script for OpenStack service that uses RPC/unix domain socket for
+communication. Check's the RPC tcp socket status on the process and send
+message to service through rpc call method and expects a reply.
+Use nova's ping method that is designed just for such simple purpose.
+
+Script returns failure to Kubernetes only when
+  a. TCP socket for the RPC communication are not established.
+  b. service is not reachable or
+  c. service times out sending a reply.
+
+sys.stderr.write() writes to pod's events on failures.
+
+Usage example for Nova Compute:
+# python health-probe.py --config-file /etc/nova/nova.conf \
+#  --service-queue-name compute
+
+"""
+
+import json
+import os
+import psutil
+import signal
+import socket
+import sys
+
+from oslo_config import cfg
+from oslo_context import context
+from oslo_log import log
+import oslo_messaging
+
+rpc_timeout = int(os.getenv('RPC_PROBE_TIMEOUT', '60'))
+rpc_retries = int(os.getenv('RPC_PROBE_RETRIES', '2'))
+
+tcp_established = "ESTABLISHED"
+
+
+def _get_hostname(topic, use_fqdn):
+    if use_fqdn and topic == "compute":
+        return socket.getfqdn()
+    return socket.gethostname()
+
+
+def check_service_status(transport):
+    """Verify service status. Return success if service consumes message"""
+    try:
+        service_queue_name = cfg.CONF.service_queue_name
+        use_fqdn = cfg.CONF.use_fqdn
+        target = oslo_messaging.Target(
+            topic=service_queue_name,
+            server=_get_hostname(service_queue_name, use_fqdn),
+            namespace='baseapi',
+            version="1.1")
+        client = oslo_messaging.RPCClient(transport, target,
+                                          timeout=rpc_timeout,
+                                          retry=rpc_retries)
+        client.call(context.RequestContext(),
+                    'ping',
+                    arg=None)
+    except oslo_messaging.exceptions.MessageDeliveryFailure:
+        # Log to pod events
+        sys.stderr.write("Health probe unable to reach message bus")
+        sys.exit(0)  # return success
+    except oslo_messaging.rpc.client.RemoteError as re:
+        message = getattr(re, "message", str(re))
+        if ("Endpoint does not support RPC method" in message) or \
+                ("Endpoint does not support RPC version" in message):
+            sys.exit(0)  # Call reached the service
+        else:
+            sys.stderr.write("Health probe unable to reach service")
+            sys.exit(1)  # return failure
+    except oslo_messaging.exceptions.MessagingTimeout:
+        sys.stderr.write("Health probe timed out. Agent is down or response "
+                         "timed out")
+        sys.exit(1)  # return failure
+    except Exception as ex:
+        message = getattr(ex, "message", str(ex))
+        sys.stderr.write("Health probe caught exception sending message to "
+                         "service: %s" % message)
+        sys.exit(0)
+    except:
+        sys.stderr.write("Health probe caught exception sending message to"
+                         " service")
+        sys.exit(0)
+
+
+def tcp_socket_status(process, ports):
+    """Check the tcp socket status on a process"""
+    for p in psutil.process_iter():
+        try:
+            with p.oneshot():
+                if process in " ".join(p.cmdline()):
+                    pcon = p.connections()
+                    for con in pcon:
+                        try:
+                            rport = con.raddr[1]
+                            status = con.status
+                        except IndexError:
+                            continue
+                        if rport in ports and status == tcp_established:
+                            return 1
+        except psutil.Error:
+            continue
+    return 0
+
+
+def configured_port_in_conf():
+    """Get the rabbitmq/Database port configured in config file"""
+
+    rabbit_ports = set()
+    database_ports = set()
+
+    try:
+        transport_url = oslo_messaging.TransportURL.parse(cfg.CONF)
+        for host in transport_url.hosts:
+            rabbit_ports.add(host.port)
+    except Exception as ex:
+        message = getattr(ex, "message", str(ex))
+        sys.stderr.write("Health probe caught exception reading "
+                         "RabbitMQ ports: %s" % message)
+        sys.exit(0)  # return success
+
+    try:
+        with open(sys.argv[2]) as conf_file:
+            for line in conf_file:
+                if "connection =" in line:
+                    service = line.split(':', 3)[3].split('/')[1].rstrip('\n')
+                    if service == "nova":
+                        database_ports.add(
+                            int(line.split(':', 3)[3].split('/')[0]))
+    except IOError:
+        sys.stderr.write("Nova Config file not present")
+        sys.exit(1)
+
+    return rabbit_ports, database_ports
+
+
+def test_tcp_socket(service):
+    """Check tcp socket to rabbitmq/db is in Established state"""
+    dict_services = {
+        "compute": "nova-compute",
+        "conductor": "nova-conductor",
+        "consoleauth": "nova-consoleaut",
+        "scheduler": "nova-scheduler"
+    }
+    r_ports, d_ports = configured_port_in_conf()
+
+    if service in dict_services:
+        proc = dict_services[service]
+        transport = oslo_messaging.TransportURL.parse(cfg.CONF)
+        if r_ports and tcp_socket_status(proc, r_ports) == 0:
+            sys.stderr.write("RabbitMQ socket not established for service "
+                             "%s with transport %s" % (proc, transport))
+            # Do not kill the pod if RabbitMQ is not reachable/down
+            if not cfg.CONF.liveness_probe:
+                sys.exit(1)
+
+        # let's do the db check
+        if service != "compute":
+            if d_ports and tcp_socket_status(proc, d_ports) == 0:
+                sys.stderr.write("Database socket not established for service "
+                                 "%s with transport %s" % (proc, transport))
+                # Do not kill the pod if database is not reachable/down
+                # there could be no socket as well as typically connections
+                # get closed after an idle timeout
+                # Just log it to pod events
+                if not cfg.CONF.liveness_probe:
+                    sys.exit(1)
+
+
+def test_rpc_liveness():
+    """Test if service can consume message from queue"""
+    oslo_messaging.set_transport_defaults(control_exchange='nova')
+
+    rabbit_group = cfg.OptGroup(name='oslo_messaging_rabbit',
+                                title='RabbitMQ options')
+    cfg.CONF.register_group(rabbit_group)
+    cfg.CONF.register_cli_opt(cfg.StrOpt('service-queue-name'))
+    cfg.CONF.register_cli_opt(cfg.BoolOpt('liveness-probe', default=False,
+                                          required=False))
+    cfg.CONF.register_cli_opt(cfg.BoolOpt('use-fqdn', default=False,
+                                          required=False))
+
+    cfg.CONF(sys.argv[1:])
+
+    log.logging.basicConfig(level=log.{{ .Values.health_probe.logging.level }})
+
+    try:
+        transport = oslo_messaging.get_notification_transport(cfg.CONF)
+    except Exception as ex:
+        message = getattr(ex, "message", str(ex))
+        sys.stderr.write("Message bus driver load error: %s" % message)
+        sys.exit(0)  # return success
+
+    if not cfg.CONF.transport_url or \
+            not cfg.CONF.service_queue_name:
+        sys.stderr.write("Both message bus URL and service's queue name are "
+                         "required for health probe to work")
+        sys.exit(0)  # return success
+
+    try:
+        cfg.CONF.set_override('rabbit_max_retries', 2,
+                              group=rabbit_group)  # 3 attempts
+    except cfg.NoSuchOptError as ex:
+        cfg.CONF.register_opt(cfg.IntOpt('rabbit_max_retries', default=2),
+                              group=rabbit_group)
+
+    service = cfg.CONF.service_queue_name
+    test_tcp_socket(service)
+
+    check_service_status(transport)
+
+def check_pid_running(pid):
+    if psutil.pid_exists(int(pid)):
+       return True
+    else:
+       return False
+
+if __name__ == "__main__":
+
+    if "liveness-probe" in ','.join(sys.argv):
+        pidfile = "/tmp/liveness.pid"  #nosec
+    else:
+        pidfile = "/tmp/readiness.pid"  #nosec
+    data = {}
+    if os.path.isfile(pidfile):
+        with open(pidfile,'r') as f:
+            data = json.load(f)
+        if check_pid_running(data['pid']):
+            if data['exit_count'] > 1:
+                # Third time in, kill the previous process
+                os.kill(int(data['pid']), signal.SIGTERM)
+            else:
+                data['exit_count'] = data['exit_count'] + 1
+                with open(pidfile, 'w') as f:
+                    json.dump(data, f)
+                sys.exit(0)
+    data['pid'] = os.getpid()
+    data['exit_count'] = 0
+    with open(pidfile, 'w') as f:
+        json.dump(data, f)
+
+    test_rpc_liveness()
+
+    sys.exit(0)  # return success
diff --git a/charts/nova/templates/bin/_iscsiadm.tpl b/charts/nova/templates/bin/_iscsiadm.tpl
new file mode 100644
index 0000000..edb5017
--- /dev/null
+++ b/charts/nova/templates/bin/_iscsiadm.tpl
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+{{/*
+Copyright 2020 The Openstack-Helm Authors.
+
+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.
+*/}}
+
+chroot /mnt/host-rootfs /usr/bin/env -i PATH="/sbin:/bin:/usr/bin" \
+      iscsiadm "${@:1}"
diff --git a/charts/nova/templates/bin/_multipath.tpl b/charts/nova/templates/bin/_multipath.tpl
new file mode 100644
index 0000000..7f84c9c
--- /dev/null
+++ b/charts/nova/templates/bin/_multipath.tpl
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+{{/*
+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.
+*/}}
+
+chroot /mnt/host-rootfs /usr/bin/env -i PATH="/sbin:/bin:/usr/bin" \
+      multipath "${@:1}"
diff --git a/charts/nova/templates/bin/_multipathd.tpl b/charts/nova/templates/bin/_multipathd.tpl
new file mode 100644
index 0000000..a9ff34a
--- /dev/null
+++ b/charts/nova/templates/bin/_multipathd.tpl
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+{{/*
+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.
+*/}}
+
+chroot /mnt/host-rootfs /usr/bin/env -i PATH="/sbin:/bin:/usr/bin" \
+      multipathd "${@:1}"
diff --git a/charts/nova/templates/bin/_nova-api-metadata-init.sh.tpl b/charts/nova/templates/bin/_nova-api-metadata-init.sh.tpl
new file mode 100644
index 0000000..84f1c80
--- /dev/null
+++ b/charts/nova/templates/bin/_nova-api-metadata-init.sh.tpl
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+{{/*
+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 -ex
+
+metadata_ip="{{- .Values.endpoints.compute_metadata.ip.ingress -}}"
+if [ -z "${metadata_ip}" ] ; then
+    metadata_ip=$(getent hosts metadata | awk '{print $1}')
+fi
+
+cat <<EOF>/tmp/pod-shared/nova-api-metadata.ini
+[DEFAULT]
+metadata_host=$metadata_ip
+EOF
diff --git a/charts/nova/templates/bin/_nova-api-metadata.sh.tpl b/charts/nova/templates/bin/_nova-api-metadata.sh.tpl
new file mode 100644
index 0000000..18195f2
--- /dev/null
+++ b/charts/nova/templates/bin/_nova-api-metadata.sh.tpl
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+{{/*
+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 -ex
+COMMAND="${@:-start}"
+
+function start () {
+{{- if .Values.manifests.certificates }}
+  for WSGI_SCRIPT in nova-metadata-wsgi; do
+    cp -a $(type -p ${WSGI_SCRIPT}) /var/www/cgi-bin/nova/
+  done
+
+  if [ -f /etc/apache2/envvars ]; then
+    # Loading Apache2 ENV variables
+    source /etc/apache2/envvars
+    mkdir -p ${APACHE_RUN_DIR}
+  fi
+
+{{- if .Values.conf.software.apache2.a2enmod }}
+  {{- range .Values.conf.software.apache2.a2enmod }}
+  a2enmod {{ . }}
+  {{- end }}
+{{- end }}
+
+{{- if .Values.conf.software.apache2.a2dismod }}
+  {{- range .Values.conf.software.apache2.a2dismod }}
+  a2dismod {{ . }}
+  {{- end }}
+{{- end }}
+
+  if [ -f /var/run/apache2/apache2.pid ]; then
+    # Remove the stale pid for debian/ubuntu images
+    rm -f /var/run/apache2/apache2.pid
+  fi
+  # Starts Apache2
+  exec {{ .Values.conf.software.apache2.binary }} {{ .Values.conf.software.apache2.start_parameters }}
+{{- else }}
+  exec nova-api-metadata \
+        --config-file /etc/nova/nova.conf \
+        --config-file /tmp/pod-shared/nova-api-metadata.ini
+{{- end }}
+}
+
+function stop () {
+{{- if .Values.manifests.certificates }}
+  if [ -f /etc/apache2/envvars ]; then
+    source /etc/apache2/envvars
+  fi
+  {{ .Values.conf.software.apache2.binary }} -k graceful-stop
+{{- else }}
+  kill -TERM 1
+{{- end }}
+}
+
+$COMMAND
diff --git a/charts/nova/templates/bin/_nova-api.sh.tpl b/charts/nova/templates/bin/_nova-api.sh.tpl
new file mode 100644
index 0000000..c62de9a
--- /dev/null
+++ b/charts/nova/templates/bin/_nova-api.sh.tpl
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+{{/*
+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 -ex
+COMMAND="${@:-start}"
+
+function start () {
+{{- if .Values.manifests.certificates }}
+  for WSGI_SCRIPT in nova-api-wsgi; do
+    cp -a $(type -p ${WSGI_SCRIPT}) /var/www/cgi-bin/nova/
+  done
+
+  if [ -f /etc/apache2/envvars ]; then
+    # Loading Apache2 ENV variables
+    source /etc/apache2/envvars
+    mkdir -p ${APACHE_RUN_DIR}
+  fi
+
+{{- if .Values.conf.software.apache2.a2enmod }}
+  {{- range .Values.conf.software.apache2.a2enmod }}
+  a2enmod {{ . }}
+  {{- end }}
+{{- end }}
+
+{{- if .Values.conf.software.apache2.a2dismod }}
+  {{- range .Values.conf.software.apache2.a2dismod }}
+  a2dismod {{ . }}
+  {{- end }}
+{{- end }}
+
+
+  if [ -f /var/run/apache2/apache2.pid ]; then
+    # Remove the stale pid for debian/ubuntu images
+    rm -f /var/run/apache2/apache2.pid
+  fi
+  # Starts Apache2
+  exec {{ .Values.conf.software.apache2.binary }} {{ .Values.conf.software.apache2.start_parameters }}
+{{- else }}
+  exec nova-api-os-compute \
+        --config-file /etc/nova/nova.conf
+{{- end }}
+}
+
+function stop () {
+{{- if .Values.manifests.certificates }}
+  if [ -f /etc/apache2/envvars ]; then
+    source /etc/apache2/envvars
+  fi
+  {{ .Values.conf.software.apache2.binary }} -k graceful-stop
+{{- else }}
+  kill -TERM 1
+{{- end }}
+}
+
+$COMMAND
diff --git a/charts/nova/templates/bin/_nova-compute-init.sh.tpl b/charts/nova/templates/bin/_nova-compute-init.sh.tpl
new file mode 100644
index 0000000..0636b69
--- /dev/null
+++ b/charts/nova/templates/bin/_nova-compute-init.sh.tpl
@@ -0,0 +1,63 @@
+#!/bin/bash
+
+{{/*
+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 -ex
+
+# Make the Nova Instances Dir as this is not autocreated.
+mkdir -p /var/lib/nova/instances
+
+# Set Ownership of nova dirs to the nova user
+chown ${NOVA_USER_UID} /var/lib/nova /var/lib/nova/instances
+
+migration_interface="{{- .Values.conf.libvirt.live_migration_interface -}}"
+if [[ -n $migration_interface ]]; then
+    # determine ip dynamically based on interface provided
+    migration_address=$(ip a s $migration_interface | grep 'inet ' | awk '{print $2}' | awk -F "/" '{print $1}' | head -1)
+fi
+
+touch /tmp/pod-shared/nova-libvirt.conf
+if [[ -n $migration_address ]]; then
+cat <<EOF>/tmp/pod-shared/nova-libvirt.conf
+[libvirt]
+live_migration_inbound_addr = $migration_address
+EOF
+fi
+
+hypervisor_interface="{{- .Values.conf.hypervisor.host_interface -}}"
+if [[ -z $hypervisor_interface ]]; then
+    # search for interface with default routing
+    # If there is not default gateway, exit
+    hypervisor_interface=$(ip -4 route list 0/0 | awk -F 'dev' '{ print $2; exit }' | awk '{ print $1 }') || exit 1
+fi
+
+hypervisor_address=$(ip a s $hypervisor_interface | grep 'inet ' | awk '{print $2}' | awk -F "/" '{print $1}' | head -1)
+
+if [ -z "${hypervisor_address}" ] ; then
+  echo "Var my_ip is empty"
+  exit 1
+fi
+
+tee > /tmp/pod-shared/nova-hypervisor.conf << EOF
+[DEFAULT]
+my_ip  = $hypervisor_address
+EOF
+
+{{- if and ( empty .Values.conf.nova.DEFAULT.host ) ( .Values.pod.use_fqdn.compute ) }}
+tee > /tmp/pod-shared/nova-compute-fqdn.conf << EOF
+[DEFAULT]
+host = $(hostname --fqdn)
+EOF
+{{- end }}
diff --git a/charts/nova/templates/bin/_nova-compute-ironic.sh.tpl b/charts/nova/templates/bin/_nova-compute-ironic.sh.tpl
new file mode 100644
index 0000000..a22cbcf
--- /dev/null
+++ b/charts/nova/templates/bin/_nova-compute-ironic.sh.tpl
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+{{/*
+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 -ex
+
+exec nova-compute \
+      --config-file /etc/nova/nova.conf \
+      --config-file /etc/nova/nova-ironic.conf
diff --git a/charts/nova/templates/bin/_nova-compute.sh.tpl b/charts/nova/templates/bin/_nova-compute.sh.tpl
new file mode 100644
index 0000000..23ce347
--- /dev/null
+++ b/charts/nova/templates/bin/_nova-compute.sh.tpl
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+{{/*
+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 -ex
+
+exec nova-compute \
+      --config-file /etc/nova/nova.conf \
+      --config-file /tmp/pod-shared/nova-console.conf \
+      --config-file /tmp/pod-shared/nova-libvirt.conf \
+{{- if and ( empty .Values.conf.nova.DEFAULT.host ) ( .Values.pod.use_fqdn.compute ) }}
+      --config-file /tmp/pod-shared/nova-compute-fqdn.conf \
+{{- end }}
+      --config-file /tmp/pod-shared/nova-hypervisor.conf
diff --git a/charts/nova/templates/bin/_nova-conductor.sh.tpl b/charts/nova/templates/bin/_nova-conductor.sh.tpl
new file mode 100644
index 0000000..0f7d5b1
--- /dev/null
+++ b/charts/nova/templates/bin/_nova-conductor.sh.tpl
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+{{/*
+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 -x
+exec nova-conductor \
+      --config-file /etc/nova/nova.conf
diff --git a/charts/nova/templates/bin/_nova-console-compute-init.sh.tpl b/charts/nova/templates/bin/_nova-console-compute-init.sh.tpl
new file mode 100644
index 0000000..6718fab
--- /dev/null
+++ b/charts/nova/templates/bin/_nova-console-compute-init.sh.tpl
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+{{/*
+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 -ex
+
+console_kind="{{- .Values.console.console_kind -}}"
+
+if [ "${console_kind}" == "novnc" ] ; then
+    client_address="{{- .Values.conf.nova.vnc.server_proxyclient_address -}}"
+    client_interface="{{- .Values.console.novnc.compute.vncserver_proxyclient_interface -}}"
+    listen_ip="{{- .Values.conf.nova.vnc.server_listen -}}"
+elif [ "${console_kind}" == "spice" ] ; then
+    client_address="{{- .Values.conf.nova.spice.server_proxyclient_address -}}"
+    client_interface="{{- .Values.console.spice.compute.server_proxyclient_interface -}}"
+    listen_ip="{{- .Values.conf.nova.spice.server_listen -}}"
+fi
+
+if [ -z "${client_address}" ] ; then
+    if [ -z "${client_interface}" ] ; then
+        if  [ -x "$(command -v route)" ] ; then
+            # search for interface with default routing, if multiple default routes exist then select the one with the lowest metric.
+            client_interface=$(route -n | awk '/^0.0.0.0/ { print $5 " " $NF }' | sort | awk '{ print $NF; exit }')
+        else
+            client_interface=$(ip r | grep default | awk '{print $5}')
+        fi
+    fi
+
+    # determine client ip dynamically based on interface provided
+    client_address=$(ip a s $client_interface | grep 'inet ' | awk '{print $2}' | awk -F "/" '{print $1}' | head -n 1)
+fi
+
+if [ -z "${listen_ip}" ] ; then
+    # The server component listens on all IP addresses and the proxy component
+    # only listens on the management interface IP address of the compute node.
+    listen_ip=0.0.0.0
+fi
+
+touch /tmp/pod-shared/nova-console.conf
+if [ "${console_kind}" == "novnc" ] ; then
+  cat > /tmp/pod-shared/nova-console.conf <<EOF
+[vnc]
+server_proxyclient_address = $client_address
+vncserver_listen = $listen_ip
+EOF
+elif [ "${console_kind}" == "spice" ] ; then
+  cat > /tmp/pod-shared/nova-console.conf <<EOF
+[spice]
+server_proxyclient_address = $client_address
+server_listen = $listen_ip
+EOF
+fi
diff --git a/charts/nova/templates/bin/_nova-console-proxy-init-assets.sh.tpl b/charts/nova/templates/bin/_nova-console-proxy-init-assets.sh.tpl
new file mode 100644
index 0000000..84652eb
--- /dev/null
+++ b/charts/nova/templates/bin/_nova-console-proxy-init-assets.sh.tpl
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+{{/*
+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 -ex
+
+console_kind="{{- .Values.console.console_kind -}}"
+if [ "${console_kind}" == "novnc" ] ; then
+    cp -vaRf /usr/share/novnc/* /tmp/usr/share/novnc/
+elif [ "${console_kind}" == "spice" ] ; then
+    cp -vaRf /usr/share/spice-html5/* /tmp/usr/share/spice-html5/
+fi
diff --git a/charts/nova/templates/bin/_nova-console-proxy-init.sh.tpl b/charts/nova/templates/bin/_nova-console-proxy-init.sh.tpl
new file mode 100644
index 0000000..6218d29
--- /dev/null
+++ b/charts/nova/templates/bin/_nova-console-proxy-init.sh.tpl
@@ -0,0 +1,61 @@
+#!/bin/bash
+
+{{/*
+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 -ex
+
+console_kind="{{- .Values.console.console_kind -}}"
+
+if [ "${console_kind}" == "novnc" ] ; then
+    client_address="{{- .Values.conf.nova.vnc.vncserver_proxyclient_address -}}"
+    client_interface="{{- .Values.console.novnc.vncproxy.vncserver_proxyclient_interface -}}"
+    listen_ip="{{- .Values.conf.nova.vnc.vncserver_listen -}}"
+elif [ "${console_kind}" == "spice" ] ; then
+    client_address="{{- .Values.conf.nova.spice.server_proxyclient_address -}}"
+    client_interface="{{- .Values.console.spice.proxy.server_proxyclient_interface -}}"
+    listen_ip="{{- .Values.conf.nova.spice.server_listen -}}"
+fi
+
+if [ -z "${client_address}" ] ; then
+    if [ -z "${client_interface}" ] ; then
+        if  [ -x "$(command -v route)" ] ; then
+            # search for interface with default routing, if multiple default routes exist then select the one with the lowest metric.
+            client_interface=$(route -n | awk '/^0.0.0.0/ { print $5 " " $NF }' | sort | awk '{ print $NF; exit }')
+        else
+            client_interface=$(ip r | grep default | awk '{print $5}')
+        fi
+    fi
+
+    # determine client ip dynamically based on interface provided
+    client_address=$(ip a s $client_interface | grep 'inet ' | awk '{print $2}' | awk -F "/" '{print $1}' | head -n 1)
+fi
+
+if [ -z "${listen_ip}" ] ; then
+    listen_ip=$client_address
+fi
+
+if [ "${console_kind}" == "novnc" ] ; then
+cat <<EOF>/tmp/pod-shared/nova-vnc.ini
+[vnc]
+vncserver_proxyclient_address = $client_address
+vncserver_listen = $listen_ip
+EOF
+elif [ "${console_kind}" == "spice" ] ; then
+cat <<EOF>/tmp/pod-shared/nova-spice.ini
+[spice]
+server_proxyclient_address = $client_address
+server_listen = $listen_ip
+EOF
+fi
diff --git a/charts/nova/templates/bin/_nova-console-proxy.sh.tpl b/charts/nova/templates/bin/_nova-console-proxy.sh.tpl
new file mode 100644
index 0000000..253a053
--- /dev/null
+++ b/charts/nova/templates/bin/_nova-console-proxy.sh.tpl
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+{{/*
+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 -x
+
+console_kind="{{- .Values.console.console_kind -}}"
+if [ "${console_kind}" == "novnc" ] ; then
+    exec nova-novncproxy \
+        --config-file /etc/nova/nova.conf \
+        --config-file /tmp/pod-shared/nova-vnc.ini
+elif [ "${console_kind}" == "spice" ] ; then
+    exec nova-spicehtml5proxy\
+        --config-file /etc/nova/nova.conf \
+        --config-file /tmp/pod-shared/nova-spice.ini
+fi
\ No newline at end of file
diff --git a/charts/nova/templates/bin/_nova-consoleauth.sh.tpl b/charts/nova/templates/bin/_nova-consoleauth.sh.tpl
new file mode 100644
index 0000000..97c4195
--- /dev/null
+++ b/charts/nova/templates/bin/_nova-consoleauth.sh.tpl
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+{{/*
+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 -x
+exec nova-consoleauth \
+      --config-file /etc/nova/nova.conf
diff --git a/charts/nova/templates/bin/_nova-placement-api.sh.tpl b/charts/nova/templates/bin/_nova-placement-api.sh.tpl
new file mode 100644
index 0000000..762af44
--- /dev/null
+++ b/charts/nova/templates/bin/_nova-placement-api.sh.tpl
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+{{/*
+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 -ex
+COMMAND="${@:-start}"
+
+function start () {
+
+  cp -a $(type -p nova-placement-api) /var/www/cgi-bin/nova/
+
+  if [ -f /etc/apache2/envvars ]; then
+    # Loading Apache2 ENV variables
+    source /etc/apache2/envvars
+    # The directory below has to be created due to the fact that
+    # libapache2-mod-wsgi-py3 doesn't create it in contrary by libapache2-mod-wsgi
+    if [ ! -d ${APACHE_RUN_DIR} ]; then
+      mkdir -p ${APACHE_RUN_DIR}
+    fi
+  fi
+
+  # Start Apache2
+  {{- if .Values.conf.software.apache2.a2enmod }}
+    {{- range .Values.conf.software.apache2.a2enmod }}
+  a2enmod {{ . }}
+    {{- end }}
+  {{- end }}
+  {{- if .Values.conf.software.apache2.a2dismod }}
+    {{- range .Values.conf.software.apache2.a2dismod }}
+  a2dismod {{ . }}
+    {{- end }}
+  {{- end }}
+  exec {{ .Values.conf.software.apache2.binary }} {{ .Values.conf.software.apache2.start_parameters }}
+}
+
+function stop () {
+  if [ -f /etc/apache2/envvars ]; then
+    source /etc/apache2/envvars
+  fi
+  {{ .Values.conf.software.apache2.binary }} -k graceful-stop
+}
+
+$COMMAND
diff --git a/charts/nova/templates/bin/_nova-scheduler.sh.tpl b/charts/nova/templates/bin/_nova-scheduler.sh.tpl
new file mode 100644
index 0000000..dc00037
--- /dev/null
+++ b/charts/nova/templates/bin/_nova-scheduler.sh.tpl
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+{{/*
+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
+
+exec nova-scheduler \
+      --config-file /etc/nova/nova.conf
diff --git a/charts/nova/templates/bin/_nova-service-cleaner.sh.tpl b/charts/nova/templates/bin/_nova-service-cleaner.sh.tpl
new file mode 100644
index 0000000..2242757
--- /dev/null
+++ b/charts/nova/templates/bin/_nova-service-cleaner.sh.tpl
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+{{/*
+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
+
+# If any non-compute service is down, then sleep for 2 times the report_interval
+# to confirm service is still down.
+DISABLED_SVC="$(openstack compute service list -f value | grep -v 'nova-compute' | grep 'down' || true)"
+if [ ! -z "${DISABLED_SVC}" ]; then
+  sleep {{ .Values.jobs.service_cleaner.sleep_time }}
+fi
+
+NOVA_SERVICES_TO_CLEAN="$(openstack compute service list -f value -c Binary | sort | uniq | grep -v '^nova-compute$')"
+for NOVA_SERVICE in ${NOVA_SERVICES_TO_CLEAN}; do
+  DEAD_SERVICE_IDS=$(openstack compute service list --service ${NOVA_SERVICE} -f json | jq -r '.[] | select(.State == "down") | .ID')
+  for SERVICE_ID in ${DEAD_SERVICE_IDS}; do
+    openstack compute service delete "${SERVICE_ID}"
+  done
+done
diff --git a/charts/nova/templates/bin/_ssh-init.sh.tpl b/charts/nova/templates/bin/_ssh-init.sh.tpl
new file mode 100644
index 0000000..9032933
--- /dev/null
+++ b/charts/nova/templates/bin/_ssh-init.sh.tpl
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+{{/*
+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 -ex
+
+export NOVA_USERNAME=$(id -u ${NOVA_USER_UID} -n)
+export NOVA_USER_HOME=$(eval echo ~${NOVA_USERNAME})
+
+mkdir -p ${NOVA_USER_HOME}/.ssh
+chown -R ${NOVA_USERNAME}:${NOVA_USERNAME} ${NOVA_USER_HOME}/.ssh
+
+cat > ${NOVA_USER_HOME}/.ssh/config <<EOF
+Host *
+  StrictHostKeyChecking no
+  UserKnownHostsFile /dev/null
+  port $SSH_PORT
+  IdentitiesOnly yes
+EOF
+
+cp /tmp/nova-ssh/* ${NOVA_USER_HOME}/.ssh/
+chmod 600 ${NOVA_USER_HOME}/.ssh/id_rsa
diff --git a/charts/nova/templates/bin/_ssh-start.sh.tpl b/charts/nova/templates/bin/_ssh-start.sh.tpl
new file mode 100644
index 0000000..abbf9f0
--- /dev/null
+++ b/charts/nova/templates/bin/_ssh-start.sh.tpl
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+{{/*
+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 -ex
+
+IFS=','
+for KEY_TYPE in $KEY_TYPES; do
+    KEY_PATH=/etc/ssh/ssh_host_${KEY_TYPE}_key
+    if [[ ! -f "${KEY_PATH}" ]]; then
+        ssh-keygen -q -t ${KEY_TYPE} -f ${KEY_PATH} -N ""
+    fi
+done
+IFS=''
+
+subnet_address="{{- .Values.network.ssh.from_subnet -}}"
+cat > /tmp/sshd_config_extend <<EOF
+PasswordAuthentication no
+Match Address $subnet_address
+    PermitRootLogin without-password
+EOF
+cat /tmp/sshd_config_extend >> /etc/ssh/sshd_config
+
+rm /tmp/sshd_config_extend
+
+exec /usr/sbin/sshd -D -e -o Port=$SSH_PORT
diff --git a/charts/nova/templates/bin/_wait-for-computes-init.sh.tpl b/charts/nova/templates/bin/_wait-for-computes-init.sh.tpl
new file mode 100644
index 0000000..ef60bf6
--- /dev/null
+++ b/charts/nova/templates/bin/_wait-for-computes-init.sh.tpl
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+{{/*
+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 -ex
+
+{{ .Values.bootstrap.wait_for_computes.scripts.init_script | default "echo 'No wait-for-compute script configured'" }}
diff --git a/charts/nova/templates/certificates.yaml b/charts/nova/templates/certificates.yaml
new file mode 100644
index 0000000..3bf6c8d
--- /dev/null
+++ b/charts/nova/templates/certificates.yaml
@@ -0,0 +1,27 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.certificates -}}
+{{ dict "envAll" . "service" "compute" "type" "internal" | include "helm-toolkit.manifests.certificates" }}
+{{- if .Values.manifests.deployment_novncproxy }}
+{{ dict "envAll" . "service" "compute_novnc_proxy" "type" "internal" | include "helm-toolkit.manifests.certificates" }}
+{{- end }}
+{{- if .Values.manifests.deployment_placement }}
+{{ dict "envAll" . "service" "placement" "type" "internal" | include "helm-toolkit.manifests.certificates" }}
+{{- end }}
+{{  dict "envAll" . "service" "compute_metadata" "type" "internal" | include "helm-toolkit.manifests.certificates" }}
+{{- if .Values.manifests.deployment_spiceproxy }}
+{{ dict "envAll" . "service" "compute_spice_proxy" "type" "internal" | include "helm-toolkit.manifests.certificates" }}
+{{- end }}
+{{- end -}}
diff --git a/charts/nova/templates/configmap-bin.yaml b/charts/nova/templates/configmap-bin.yaml
new file mode 100644
index 0000000..141130a
--- /dev/null
+++ b/charts/nova/templates/configmap-bin.yaml
@@ -0,0 +1,114 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.configmap_bin }}
+{{- $envAll := . }}
+{{- $rallyTests := .Values.conf.rally_tests }}
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: nova-bin
+data:
+{{- if .Values.conf.enable_iscsi }}
+  iscsiadm: |
+{{ tuple "bin/_iscsiadm.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  multipath: |
+{{ tuple "bin/_multipath.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  multipathd: |
+{{ tuple "bin/_multipathd.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+{{- end }}
+{{- if .Values.images.local_registry.active }}
+  image-repo-sync.sh: |
+{{- include "helm-toolkit.scripts.image_repo_sync" . | indent 4 }}
+{{- end }}
+{{- if .Values.bootstrap.enabled }}
+  bootstrap.sh: |
+{{ tuple "bin/_bootstrap.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+{{- end }}
+  rally-test.sh: |
+{{ tuple $rallyTests | include "helm-toolkit.scripts.rally_test" | indent 4 }}
+  db-init.py: |
+{{- include "helm-toolkit.scripts.db_init" . | indent 4 }}
+  db-sync.sh: |
+{{ tuple "bin/_db-sync.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  db-drop.py: |
+{{- include "helm-toolkit.scripts.db_drop" . | indent 4 }}
+  ks-service.sh: |
+{{- include "helm-toolkit.scripts.keystone_service" . | indent 4 }}
+  ks-endpoints.sh: |
+{{- include "helm-toolkit.scripts.keystone_endpoints" . | indent 4 }}
+  ks-user.sh: |
+{{- include "helm-toolkit.scripts.keystone_user" . | indent 4 }}
+{{- if .Values.conf.ceph.enabled }}
+  ceph-keyring.sh: |
+{{ tuple "bin/_ceph-keyring.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  ceph-admin-keyring.sh: |
+{{ tuple "bin/_ceph-admin-keyring.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+{{- end }}
+{{- if .Values.manifests.cron_job_archive_deleted_rows }}
+  archive-deleted-rows.sh: |
+{{ tuple "bin/_db-archive-deleted-row.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+{{- end }}
+  health-probe.py: |
+{{ tuple "bin/_health-probe.py.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  nova-api.sh: |
+{{ tuple "bin/_nova-api.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  nova-api-metadata.sh: |
+{{ tuple "bin/_nova-api-metadata.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  nova-api-metadata-init.sh: |
+{{ tuple "bin/_nova-api-metadata-init.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  nova-placement-api.sh: |
+{{ tuple "bin/_nova-placement-api.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  nova-compute.sh: |
+{{ tuple "bin/_nova-compute.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  nova-compute-init.sh: |
+{{ tuple "bin/_nova-compute-init.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  nova-compute-ironic.sh: |
+{{ tuple "bin/_nova-compute-ironic.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  nova-conductor.sh: |
+{{ tuple "bin/_nova-conductor.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  nova-consoleauth.sh: |
+{{ tuple "bin/_nova-consoleauth.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  nova-scheduler.sh: |
+{{ tuple "bin/_nova-scheduler.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  fake-iptables.sh: |
+{{ tuple "bin/_fake-iptables.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  nova-console-compute-init.sh: |
+{{ tuple "bin/_nova-console-compute-init.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  nova-console-proxy.sh: |
+{{ tuple "bin/_nova-console-proxy.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  nova-console-proxy-init.sh: |
+{{ tuple "bin/_nova-console-proxy-init.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  nova-console-proxy-init-assets.sh: |
+{{ tuple "bin/_nova-console-proxy-init-assets.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  ssh-init.sh: |
+{{ tuple "bin/_ssh-init.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  ssh-start.sh: |
+{{ tuple "bin/_ssh-start.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  cell-setup.sh: |
+{{ tuple "bin/_cell-setup.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  cell-setup-init.sh: |
+{{ tuple "bin/_cell-setup-init.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  nova-service-cleaner.sh: |
+{{ tuple "bin/_nova-service-cleaner.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+  rabbit-init.sh: |
+{{- include "helm-toolkit.scripts.rabbit_init" . | indent 4 }}
+  wait-for-computes-init.sh: |
+{{ tuple "bin/_wait-for-computes-init.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }}
+{{- if ( has "tungstenfabric" .Values.network.backend ) }}
+  tf-plugin.pth: |
+    /opt/plugin/site-packages
+{{- end }}
+{{- end }}
diff --git a/charts/nova/templates/configmap-etc.yaml b/charts/nova/templates/configmap-etc.yaml
new file mode 100644
index 0000000..c92fd93
--- /dev/null
+++ b/charts/nova/templates/configmap-etc.yaml
@@ -0,0 +1,294 @@
+{{/*
+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.
+*/}}
+
+{{- define "nova.configmap.etc" }}
+{{- $configMapName := index . 0 }}
+{{- $envAll := index . 1 }}
+{{- with $envAll }}
+
+{{- if empty .Values.conf.nova.keystone_authtoken.auth_uri -}}
+{{- $_ := tuple "identity" "internal" "api" . | include "helm-toolkit.endpoints.keystone_endpoint_uri_lookup" | set .Values.conf.nova.keystone_authtoken "auth_uri" -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.keystone_authtoken.auth_url -}}
+{{- $_ := tuple "identity" "internal" "api" . | include "helm-toolkit.endpoints.keystone_endpoint_uri_lookup" | set .Values.conf.nova.keystone_authtoken "auth_url" -}}
+{{- end -}}
+
+{{- if empty .Values.conf.nova.keystone_authtoken.region_name -}}
+{{- $_ := set .Values.conf.nova.keystone_authtoken "region_name" .Values.endpoints.identity.auth.nova.region_name -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.keystone_authtoken.project_name -}}
+{{- $_ := set .Values.conf.nova.keystone_authtoken "project_name" .Values.endpoints.identity.auth.nova.project_name -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.keystone_authtoken.project_domain_name -}}
+{{- $_ := set .Values.conf.nova.keystone_authtoken "project_domain_name" .Values.endpoints.identity.auth.nova.project_domain_name -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.keystone_authtoken.user_domain_name -}}
+{{- $_ := set .Values.conf.nova.keystone_authtoken "user_domain_name" .Values.endpoints.identity.auth.nova.user_domain_name -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.keystone_authtoken.username -}}
+{{- $_ := set .Values.conf.nova.keystone_authtoken "username" .Values.endpoints.identity.auth.nova.username -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.keystone_authtoken.password -}}
+{{- $_ := set .Values.conf.nova.keystone_authtoken "password" .Values.endpoints.identity.auth.nova.password -}}
+{{- end -}}
+
+{{- if empty .Values.conf.nova.keystone_authtoken.memcached_servers -}}
+{{- $_ := tuple "oslo_cache" "internal" "memcache" . | include "helm-toolkit.endpoints.host_and_port_endpoint_uri_lookup" | set .Values.conf.nova.keystone_authtoken "memcached_servers" -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.keystone_authtoken.memcache_secret_key -}}
+{{- $_ := set .Values.conf.nova.keystone_authtoken "memcache_secret_key" ( default ( randAlphaNum 64 ) .Values.endpoints.oslo_cache.auth.memcache_secret_key ) -}}
+{{- end -}}
+
+{{- if .Values.conf.nova.service_user.send_service_user_token -}}
+
+{{- if empty .Values.conf.nova.service_user.auth_url -}}
+{{- $_ := tuple "identity" "internal" "api" . | include "helm-toolkit.endpoints.keystone_endpoint_uri_lookup" | set .Values.conf.nova.service_user "auth_url" -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.service_user.region_name -}}
+{{- $_ := set .Values.conf.nova.service_user "region_name" .Values.endpoints.identity.auth.nova.region_name -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.service_user.project_name -}}
+{{- $_ := set .Values.conf.nova.service_user "project_name" .Values.endpoints.identity.auth.nova.project_name -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.service_user.project_domain_name -}}
+{{- $_ := set .Values.conf.nova.service_user "project_domain_name" .Values.endpoints.identity.auth.nova.project_domain_name -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.service_user.user_domain_name -}}
+{{- $_ := set .Values.conf.nova.service_user "user_domain_name" .Values.endpoints.identity.auth.nova.user_domain_name -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.service_user.username -}}
+{{- $_ := set .Values.conf.nova.service_user "username" .Values.endpoints.identity.auth.nova.username -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.service_user.password -}}
+{{- $_ := set .Values.conf.nova.service_user "password" .Values.endpoints.identity.auth.nova.password -}}
+{{- end -}}
+
+{{- end -}}
+
+{{- if empty .Values.conf.nova.database.connection -}}
+{{- $connection := tuple "oslo_db" "internal" "nova" "mysql" . | include "helm-toolkit.endpoints.authenticated_endpoint_uri_lookup" -}}
+{{- if .Values.manifests.certificates -}}
+{{- $_ := (printf "%s?charset=utf8&ssl_ca=/etc/mysql/certs/ca.crt&ssl_key=/etc/mysql/certs/tls.key&ssl_cert=/etc/mysql/certs/tls.crt&ssl_verify_cert" $connection ) | set .Values.conf.nova.database "connection" -}}
+{{- else -}}
+{{- $_ := set .Values.conf.nova.database "connection" $connection -}}
+{{- end -}}
+{{- end -}}
+
+{{- if empty .Values.conf.nova.api_database.connection -}}
+{{- $connection := tuple "oslo_db_api" "internal" "nova" "mysql" . | include "helm-toolkit.endpoints.authenticated_endpoint_uri_lookup" -}}
+{{- if .Values.manifests.certificates -}}
+{{- $_ := (printf "%s?charset=utf8&ssl_ca=/etc/mysql/certs/ca.crt&ssl_key=/etc/mysql/certs/tls.key&ssl_cert=/etc/mysql/certs/tls.crt&ssl_verify_cert" $connection ) | set .Values.conf.nova.api_database "connection" -}}
+{{- else -}}
+{{- $_ := set .Values.conf.nova.api_database "connection" $connection -}}
+{{- end -}}
+{{- end -}}
+
+{{- if empty .Values.conf.nova.cell0_database.connection -}}
+{{- $connection := tuple "oslo_db_cell0" "internal" "nova" "mysql" . | include "helm-toolkit.endpoints.authenticated_endpoint_uri_lookup" -}}
+{{- if .Values.manifests.certificates -}}
+{{- $_ := (printf "%s?charset=utf8&ssl_ca=/etc/mysql/certs/ca.crt&ssl_key=/etc/mysql/certs/tls.key&ssl_cert=/etc/mysql/certs/tls.crt&ssl_verify_cert" $connection ) | set .Values.conf.nova.cell0_database "connection" -}}
+{{- else -}}
+{{- $_ := set .Values.conf.nova.cell0_database "connection" $connection -}}
+{{- end -}}
+{{- end -}}
+
+{{- if empty .Values.conf.nova.DEFAULT.transport_url -}}
+{{- $_ := tuple "oslo_messaging" "internal" "nova" "amqp" . | include "helm-toolkit.endpoints.authenticated_transport_endpoint_uri_lookup" | set .Values.conf.nova.DEFAULT "transport_url" -}}
+{{- end -}}
+
+{{- if empty .Values.conf.nova.glance.api_servers -}}
+{{- $_ := tuple "image" "internal" "api" . | include "helm-toolkit.endpoints.keystone_endpoint_uri_lookup" | set .Values.conf.nova.glance "api_servers" -}}
+{{- end -}}
+
+{{- if empty .Values.conf.nova.neutron.url -}}
+{{- $_ := tuple "network" "internal" "api" . | include "helm-toolkit.endpoints.keystone_endpoint_uri_lookup" | set .Values.conf.nova.neutron "url" -}}
+{{- end -}}
+
+{{- if empty .Values.conf.nova.neutron.auth_url -}}
+{{- $_ := tuple "identity" "internal" "api" . | include "helm-toolkit.endpoints.keystone_endpoint_uri_lookup" | set .Values.conf.nova.neutron "auth_url" -}}
+{{- end -}}
+
+{{- if empty .Values.conf.nova.neutron.region_name -}}
+{{- $_ := set .Values.conf.nova.neutron "region_name" .Values.endpoints.identity.auth.neutron.region_name -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.neutron.project_name -}}
+{{- $_ := set .Values.conf.nova.neutron "project_name" .Values.endpoints.identity.auth.neutron.project_name -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.neutron.project_domain_name -}}
+{{- $_ := set .Values.conf.nova.neutron "project_domain_name" .Values.endpoints.identity.auth.neutron.project_domain_name -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.neutron.user_domain_name -}}
+{{- $_ := set .Values.conf.nova.neutron "user_domain_name" .Values.endpoints.identity.auth.neutron.user_domain_name -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.neutron.username -}}
+{{- $_ := set .Values.conf.nova.neutron "username" .Values.endpoints.identity.auth.neutron.username -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.neutron.password -}}
+{{- $_ := set .Values.conf.nova.neutron "password" .Values.endpoints.identity.auth.neutron.password -}}
+{{- end -}}
+
+{{- if empty .Values.conf.nova.cache.memcache_servers -}}
+{{- $_ := tuple "oslo_cache" "internal" "memcache" . | include "helm-toolkit.endpoints.host_and_port_endpoint_uri_lookup" | set .Values.conf.nova.cache "memcache_servers" -}}
+{{- end -}}
+
+{{- if and (empty .Values.conf.nova.DEFAULT.metadata_host) .Values.endpoints.compute_metadata.ip.ingress -}}
+{{- $_ := set .Values.conf.nova.DEFAULT "metadata_host" .Values.endpoints.compute_metadata.ip.ingress -}}
+{{- end -}}
+
+{{- if empty .Values.conf.nova.DEFAULT.metadata_port -}}
+{{- $_ := tuple "compute_metadata" "public" "metadata" . | include "helm-toolkit.endpoints.endpoint_port_lookup" | set .Values.conf.nova.DEFAULT "metadata_port" -}}
+{{- end -}}
+
+{{- if empty .Values.conf.nova.placement.auth_url -}}
+{{- $_ := tuple "identity" "internal" "api" . | include "helm-toolkit.endpoints.keystone_endpoint_uri_lookup"| set .Values.conf.nova.placement "auth_url" -}}
+{{- end -}}
+
+{{- if empty .Values.conf.nova.placement.region_name -}}
+{{- $_ := set .Values.conf.nova.placement "region_name" .Values.endpoints.identity.auth.placement.region_name -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.placement.project_name -}}
+{{- $_ := set .Values.conf.nova.placement "project_name" .Values.endpoints.identity.auth.placement.project_name -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.placement.project_domain_name -}}
+{{- $_ := set .Values.conf.nova.placement "project_domain_name" .Values.endpoints.identity.auth.placement.project_domain_name -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.placement.user_domain_name -}}
+{{- $_ := set .Values.conf.nova.placement "user_domain_name" .Values.endpoints.identity.auth.placement.user_domain_name -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.placement.username -}}
+{{- $_ := set .Values.conf.nova.placement "username" .Values.endpoints.identity.auth.placement.username -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.placement.password -}}
+{{- $_ := set .Values.conf.nova.placement "password" .Values.endpoints.identity.auth.placement.password -}}
+{{- end -}}
+
+{{- if eq .Values.console.console_kind "novnc"}}
+{{- $_ := "true" | set .Values.conf.nova.vnc "enabled" -}}
+{{- if empty .Values.conf.nova.vnc.novncproxy_base_url -}}
+{{- $_ := tuple "compute_novnc_proxy" "public" "novnc_proxy" . | include "helm-toolkit.endpoints.keystone_endpoint_uri_lookup" | set .Values.conf.nova.vnc "novncproxy_base_url" -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.vnc.novncproxy_port -}}
+{{- $_ := tuple "compute_novnc_proxy" "internal" "novnc_proxy" . | include "helm-toolkit.endpoints.endpoint_port_lookup" | set .Values.conf.nova.vnc "novncproxy_port" -}}
+{{- end -}}
+{{- end -}}
+
+{{- if eq .Values.console.console_kind "spice"}}
+{{- $_ := "false" | set .Values.conf.nova.vnc "enabled" -}}
+{{- $_ := "true" | set .Values.conf.nova.spice "enabled" -}}
+{{- if empty .Values.conf.nova.spice.html5proxy_base_url -}}
+{{- $_ := tuple "compute_spice_proxy" "public" "spice_proxy" . | include "helm-toolkit.endpoints.keystone_endpoint_uri_lookup" | set .Values.conf.nova.spice "html5proxy_base_url" -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.spice.html5proxy_port -}}
+{{- $_ := tuple "compute_spice_proxy" "internal" "spice_proxy" . | include "helm-toolkit.endpoints.endpoint_port_lookup" | set .Values.conf.nova.spice "html5proxy_port" -}}
+{{- end -}}
+{{- end -}}
+
+{{- if empty .Values.conf.nova.ironic.api_endpoint -}}
+{{- $_ := tuple "baremetal" "internal" "api" . | include "helm-toolkit.endpoints.keystone_endpoint_uri_lookup" | set .Values.conf.nova.ironic "api_endpoint" -}}
+{{- end -}}
+
+{{- if empty .Values.conf.nova.ironic.auth_url -}}
+{{- $_ := tuple "identity" "internal" "api" . | include "helm-toolkit.endpoints.keystone_endpoint_uri_lookup" | set .Values.conf.nova.ironic "auth_url" -}}
+{{- end -}}
+
+{{- if empty .Values.conf.nova.ironic.region_name -}}
+{{- $_ := set .Values.conf.nova.ironic "region_name" .Values.endpoints.identity.auth.ironic.region_name -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.ironic.project_name -}}
+{{- $_ := set .Values.conf.nova.ironic "project_name" .Values.endpoints.identity.auth.ironic.project_name -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.ironic.project_domain_name -}}
+{{- $_ := set .Values.conf.nova.ironic "project_domain_name" .Values.endpoints.identity.auth.ironic.project_domain_name -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.ironic.user_domain_name -}}
+{{- $_ := set .Values.conf.nova.ironic "user_domain_name" .Values.endpoints.identity.auth.ironic.user_domain_name -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.ironic.username -}}
+{{- $_ := set .Values.conf.nova.ironic "username" .Values.endpoints.identity.auth.ironic.username -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.ironic.password -}}
+{{- $_ := set .Values.conf.nova.ironic "password" .Values.endpoints.identity.auth.ironic.password -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.ironic.auth_type -}}
+{{- $_ := set .Values.conf.nova.ironic "auth_type" .Values.endpoints.identity.auth.ironic.auth_type -}}
+{{- end -}}
+{{- if empty .Values.conf.nova.ironic.auth_version -}}
+{{- $_ := set .Values.conf.nova.ironic "auth_version" .Values.endpoints.identity.auth.ironic.auth_version -}}
+{{- end -}}
+
+{{- if empty .Values.conf.nova.ironic.memcache_secret_key -}}
+{{- $_ := (default (randAlphaNum 64) .Values.endpoints.oslo_cache.auth.memcache_secret_key) | set .Values.conf.nova.ironic "memcache_secret_key" -}}
+{{- end -}}
+
+{{- if empty .Values.conf.nova.ironic.memcache_servers -}}
+{{- $_ := tuple "oslo_cache" "internal" "memcache" . | include "helm-toolkit.endpoints.host_and_port_endpoint_uri_lookup" | set .Values.conf.nova.ironic "memcache_servers" -}}
+{{- end -}}
+
+{{- if empty .Values.conf.nova.DEFAULT.osapi_compute_listen_port -}}
+{{- $_ := tuple "compute" "internal" "api" . | include "helm-toolkit.endpoints.endpoint_port_lookup" | set .Values.conf.nova.DEFAULT "osapi_compute_listen_port" -}}
+{{- end -}}
+
+{{- if and (empty .Values.conf.logging.handler_fluent) (has "fluent" .Values.conf.logging.handlers.keys) -}}
+{{- $fluentd_host := tuple "fluentd" "internal" $envAll | include "helm-toolkit.endpoints.hostname_namespaced_endpoint_lookup" }}
+{{- $fluentd_port := tuple "fluentd" "internal" "service" $envAll | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+{{- $fluent_args := printf "('%s.%s', '%s', %s)" .Release.Namespace .Release.Name $fluentd_host $fluentd_port }}
+{{- $handler_fluent := dict "class" "fluent.handler.FluentHandler" "formatter" "fluent" "args" $fluent_args -}}
+{{- $_ := set .Values.conf.logging "handler_fluent" $handler_fluent -}}
+{{- end -}}
+
+{{- if and (empty .Values.conf.logging.formatter_fluent) (has "fluent" .Values.conf.logging.formatters.keys) -}}
+{{- $formatter_fluent := dict "class" "oslo_log.formatters.FluentFormatter" -}}
+{{- $_ := set .Values.conf.logging "formatter_fluent" $formatter_fluent -}}
+{{- end -}}
+
+{{ $__nova_compute := dict }}
+{{ $_ := set $__nova_compute "config" .Values.conf.nova  }}
+{{ range .Values.conf.nova_compute_redactions }}
+{{   $_ := set $__nova_compute "config" (omit $__nova_compute.config .) }}
+{{ end }}
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ $configMapName }}
+type: Opaque
+data:
+  rally_tests.yaml: {{ toYaml .Values.conf.rally_tests.tests | b64enc }}
+  api-paste.ini: {{ include "helm-toolkit.utils.to_oslo_conf" .Values.conf.paste | b64enc }}
+  policy.yaml: {{ toYaml .Values.conf.policy | b64enc }}
+  nova_sudoers: {{ $envAll.Values.conf.nova_sudoers | b64enc }}
+  rootwrap.conf: {{ .Values.conf.rootwrap | b64enc }}
+{{- range $key, $value := $envAll.Values.conf.rootwrap_filters }}
+{{- $filePrefix := replace "_" "-"  $key }}
+  {{ printf "%s.filters" $filePrefix }}: {{ $value.content | b64enc }}
+{{- end }}
+  nova.conf: {{ include "helm-toolkit.utils.to_oslo_conf" .Values.conf.nova | b64enc }}
+  nova-compute.conf: {{ include "helm-toolkit.utils.to_oslo_conf" $__nova_compute.config | b64enc }}
+  logging.conf: {{ include "helm-toolkit.utils.to_oslo_conf" .Values.conf.logging | b64enc }}
+  api_audit_map.conf: {{ include "helm-toolkit.utils.to_oslo_conf" .Values.conf.api_audit_map | b64enc }}
+  nova-ironic.conf: {{ include "helm-toolkit.utils.to_oslo_conf" .Values.conf.nova_ironic | b64enc }}
+{{- include "helm-toolkit.snippets.values_template_renderer" (dict "envAll" $envAll "template" .Values.conf.wsgi_placement "key" "wsgi-nova-placement.conf" "format" "Secret" ) | indent 2 }}
+{{- if .Values.manifests.certificates }}
+{{- include "helm-toolkit.snippets.values_template_renderer" (dict "envAll" $envAll "template" .Values.conf.mpm_event "key" "mpm_event.conf" "format" "Secret" ) | indent 2 }}
+{{- include "helm-toolkit.snippets.values_template_renderer" (dict "envAll" $envAll "template" .Values.conf.wsgi_nova_api "key" "wsgi-api.conf" "format" "Secret" ) | indent 2 }}
+{{- include "helm-toolkit.snippets.values_template_renderer" (dict "envAll" $envAll "template" .Values.conf.wsgi_nova_metadata "key" "wsgi-metadata.conf" "format" "Secret" ) | indent 2 }}
+{{- end }}
+{{- if .Values.conf.security }}
+{{- include "helm-toolkit.snippets.values_template_renderer" (dict "envAll" $envAll "template" .Values.conf.security "key" "security.conf" "format" "Secret" ) | indent 2 }}
+{{- end }}
+{{- end }}
+{{- end }}
+{{- if .Values.manifests.configmap_etc }}
+{{- list "nova-etc" . | include "nova.configmap.etc" }}
+{{- end }}
diff --git a/charts/nova/templates/cron-job-archive-deleted-rows.yaml b/charts/nova/templates/cron-job-archive-deleted-rows.yaml
new file mode 100644
index 0000000..7baa330
--- /dev/null
+++ b/charts/nova/templates/cron-job-archive-deleted-rows.yaml
@@ -0,0 +1,85 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.cron_job_archive_deleted_rows }}
+{{- $envAll := . }}
+
+{{- $serviceAccountName := "nova-archive-deleted-rows-cron" }}
+{{ tuple $envAll "archive_deleted_rows" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: batch/v1beta1
+kind: CronJob
+metadata:
+  name: nova-archive-deleted-rows
+  annotations:
+    {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
+spec:
+  schedule: {{ .Values.jobs.archive_deleted_rows.cron | quote }}
+  successfulJobsHistoryLimit: {{ .Values.jobs.archive_deleted_rows.history.success }}
+  failedJobsHistoryLimit: {{ .Values.jobs.archive_deleted_rows.history.failed }}
+  {{- if .Values.jobs.archive_deleted_rows.starting_deadline }}
+  startingDeadlineSeconds: {{ .Values.jobs.archive_deleted_rows.starting_deadline }}
+  {{- end }}
+  concurrencyPolicy: Forbid
+  jobTemplate:
+    metadata:
+      labels:
+{{ tuple $envAll "nova" "archive-deleted-rows" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+    spec:
+      template:
+        metadata:
+          labels:
+{{ tuple $envAll "nova" "archive-deleted-rows" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 12 }}
+        spec:
+          serviceAccountName: {{ $serviceAccountName }}
+{{ dict "envAll" $envAll "application" "archive_deleted_rows" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 10 }}
+          restartPolicy: OnFailure
+          nodeSelector:
+            {{ .Values.labels.job.node_selector_key }}: {{ .Values.labels.job.node_selector_value }}
+          initContainers:
+{{ tuple $envAll "archive-deleted-rows" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 12 }}
+          containers:
+            - name: nova-archive-deleted-rows
+{{ tuple $envAll "nova_archive_deleted_rows" | include "helm-toolkit.snippets.image" | indent 14 }}
+{{ tuple $envAll $envAll.Values.pod.resources.jobs.archive_deleted_rows | include "helm-toolkit.snippets.kubernetes_resources" | indent 14 }}
+{{ dict "envAll" $envAll "application" "archive_deleted_rows" "container" "nova_archive_deleted_rows" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 14 }}
+              command:
+                - /tmp/archive-deleted-rows.sh
+              volumeMounts:
+                - name: pod-tmp
+                  mountPath: /tmp
+                - name: archive-deleted-rows-conf
+                  mountPath: /etc/nova/nova.conf
+                  subPath: nova.conf
+                  readOnly: true
+                - name: archive-deleted-rows-conf
+                  mountPath: /etc/nova/logging.conf
+                  subPath: logging.conf
+                  readOnly: true
+                - name: archive-deleted-rows
+                  mountPath: /tmp/archive-deleted-rows.sh
+                  readOnly: true
+                  subPath: archive-deleted-rows.sh
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal "path" "/etc/mysql/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 16 }}
+          volumes:
+            - name: pod-tmp
+              emptyDir: {}
+            - name: archive-deleted-rows
+              configMap:
+                name: nova-bin
+                defaultMode: 0555
+            - name: archive-deleted-rows-conf
+              secret:
+                secretName: nova-etc
+{{- end }}
diff --git a/charts/nova/templates/cron-job-cell-setup.yaml b/charts/nova/templates/cron-job-cell-setup.yaml
new file mode 100644
index 0000000..18b661a
--- /dev/null
+++ b/charts/nova/templates/cron-job-cell-setup.yaml
@@ -0,0 +1,97 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.cron_job_cell_setup }}
+{{- $envAll := . }}
+
+{{- $serviceAccountName := "nova-cell-setup-cron" }}
+{{ tuple $envAll "cell_setup" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: batch/v1beta1
+kind: CronJob
+metadata:
+  name: nova-cell-setup
+  annotations:
+    {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
+spec:
+  schedule: {{ .Values.jobs.cell_setup.cron | quote }}
+  successfulJobsHistoryLimit: {{ .Values.jobs.cell_setup.history.success }}
+  failedJobsHistoryLimit: {{ .Values.jobs.cell_setup.history.failed }}
+  {{- if .Values.jobs.cell_setup.starting_deadline }}
+  startingDeadlineSeconds: {{ .Values.jobs.cell_setup.starting_deadline }}
+  {{- end }}
+  concurrencyPolicy: Forbid
+  jobTemplate:
+    metadata:
+      labels:
+{{ tuple $envAll "nova" "cell-setup" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+    spec:
+      template:
+        metadata:
+          labels:
+{{ tuple $envAll "nova" "cell-setup" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 12 }}
+        spec:
+          serviceAccountName: {{ $serviceAccountName }}
+{{ dict "envAll" $envAll "application" "cell_setup" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 10 }}
+          restartPolicy: OnFailure
+          nodeSelector:
+            {{ .Values.labels.job.node_selector_key }}: {{ .Values.labels.job.node_selector_value }}
+          initContainers:
+{{ tuple $envAll "cell_setup" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 12 }}
+          containers:
+            - name: nova-cell-setup
+{{ tuple $envAll "nova_cell_setup" | include "helm-toolkit.snippets.image" | indent 14 }}
+{{ tuple $envAll $envAll.Values.pod.resources.jobs.cell_setup | include "helm-toolkit.snippets.kubernetes_resources" | indent 14 }}
+{{ dict "envAll" $envAll "application" "cell_setup" "container" "nova_cell_setup" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 14 }}
+              command:
+                - /tmp/cell-setup.sh
+              volumeMounts:
+                - name: pod-tmp
+                  mountPath: /tmp
+                - name: nova-bin
+                  mountPath: /tmp/cell-setup.sh
+                  subPath: cell-setup.sh
+                  readOnly: true
+                - name: etcnova
+                  mountPath: /etc/nova
+                - name: nova-etc
+                  mountPath: /etc/nova/nova.conf
+                  subPath: nova.conf
+                  readOnly: true
+                {{- if .Values.conf.nova.DEFAULT.log_config_append }}
+                - name: nova-etc
+                  mountPath: {{ .Values.conf.nova.DEFAULT.log_config_append }}
+                  subPath: {{ base .Values.conf.nova.DEFAULT.log_config_append }}
+                  readOnly: true
+                {{- end }}
+                - name: nova-etc
+                  mountPath: /etc/nova/policy.yaml
+                  subPath: policy.yaml
+                  readOnly: true
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal "path" "/etc/mysql/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 16 }}
+          volumes:
+            - name: pod-tmp
+              emptyDir: {}
+            - name: etcnova
+              emptyDir: {}
+            - name: nova-etc
+              secret:
+                secretName: nova-etc
+                defaultMode: 0444
+            - name: nova-bin
+              configMap:
+                name: nova-bin
+                defaultMode: 0555
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 12 }}
+{{- end }}
diff --git a/charts/nova/templates/cron-job-service-cleaner.yaml b/charts/nova/templates/cron-job-service-cleaner.yaml
new file mode 100644
index 0000000..bbe3fab
--- /dev/null
+++ b/charts/nova/templates/cron-job-service-cleaner.yaml
@@ -0,0 +1,87 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.cron_job_service_cleaner }}
+{{- $envAll := . }}
+
+{{- $serviceAccountName := "nova-service-cleaner" }}
+{{ tuple $envAll "service_cleaner" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: batch/v1beta1
+kind: CronJob
+metadata:
+  name: nova-service-cleaner
+  annotations:
+    {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
+spec:
+  schedule: {{ .Values.jobs.service_cleaner.cron | quote }}
+  successfulJobsHistoryLimit: {{ .Values.jobs.service_cleaner.history.success }}
+  failedJobsHistoryLimit: {{ .Values.jobs.service_cleaner.history.failed }}
+  {{- if .Values.jobs.service_cleaner.starting_deadline }}
+  startingDeadlineSeconds: {{ .Values.jobs.service_cleaner.starting_deadline }}
+  {{- end }}
+  concurrencyPolicy: Forbid
+  jobTemplate:
+    metadata:
+      labels:
+{{ tuple $envAll "nova" "service-cleaner" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+    spec:
+      template:
+        metadata:
+          labels:
+{{ tuple $envAll "nova" "service-cleaner" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 12 }}
+        spec:
+          serviceAccountName: {{ $serviceAccountName }}
+{{ dict "envAll" $envAll "application" "service_cleaner" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 10 }}
+          restartPolicy: OnFailure
+          nodeSelector:
+            {{ .Values.labels.job.node_selector_key }}: {{ .Values.labels.job.node_selector_value }}
+          initContainers:
+{{ tuple $envAll "service_cleaner" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 12 }}
+          containers:
+            - name: nova-service-cleaner
+{{ tuple $envAll "nova_service_cleaner" | include "helm-toolkit.snippets.image" | indent 14 }}
+{{ tuple $envAll $envAll.Values.pod.resources.jobs.service_cleaner | include "helm-toolkit.snippets.kubernetes_resources" | indent 14 }}
+{{ dict "envAll" $envAll "application" "service_cleaner" "container" "nova_service_cleaner" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 14 }}
+              env:
+{{- with $env := dict "ksUserSecret" $envAll.Values.secrets.identity.nova "useCA" .Values.manifests.certificates}}
+{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 14 }}
+{{- end }}
+              command:
+                - /tmp/nova-service-cleaner.sh
+              volumeMounts:
+                - name: pod-tmp
+                  mountPath: /tmp
+                - name: nova-bin
+                  mountPath: /tmp/nova-service-cleaner.sh
+                  subPath: nova-service-cleaner.sh
+                  readOnly: true
+                - name: etcnova
+                  mountPath: /etc/nova
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute.osapi.internal | include "helm-toolkit.snippets.tls_volume_mount" | indent 16 }}
+          volumes:
+            - name: pod-tmp
+              emptyDir: {}
+            - name: etcnova
+              emptyDir: {}
+            - name: nova-etc
+              secret:
+                secretName: nova-etc
+                defaultMode: 0444
+            - name: nova-bin
+              configMap:
+                name: nova-bin
+                defaultMode: 0555
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute.osapi.internal | include "helm-toolkit.snippets.tls_volume" | indent 12 }}
+{{- end }}
diff --git a/charts/nova/templates/daemonset-compute.yaml b/charts/nova/templates/daemonset-compute.yaml
new file mode 100644
index 0000000..e600e58
--- /dev/null
+++ b/charts/nova/templates/daemonset-compute.yaml
@@ -0,0 +1,565 @@
+{{/*
+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.
+*/}}
+
+{{- define "novaComputeLivenessProbeTemplate" }}
+exec:
+  command:
+    - python
+    - /tmp/health-probe.py
+    - --config-file
+    - /etc/nova/nova.conf
+    - --service-queue-name
+    - compute
+    - --liveness-probe
+    {{- if .Values.pod.use_fqdn.compute }}
+    - --use-fqdn
+    {{- end }}
+{{- end }}
+
+{{- define "novaComputeReadinessProbeTemplate" }}
+exec:
+  command:
+    - python
+    - /tmp/health-probe.py
+    - --config-file
+    - /etc/nova/nova.conf
+    - --service-queue-name
+    - compute
+    {{- if .Values.pod.use_fqdn.compute }}
+    - --use-fqdn
+    {{- end }}
+{{- end }}
+
+{{- define "nova.compute.daemonset" }}
+{{- $daemonset := index . 0 }}
+{{- $configMapName := index . 1 }}
+{{- $serviceAccountName := index . 2 }}
+{{- $envAll := index . 3 }}
+{{- with $envAll }}
+
+{{- $mounts_nova_compute := .Values.pod.mounts.nova_compute.nova_compute }}
+{{- $mounts_nova_compute_init := .Values.pod.mounts.nova_compute.init_container }}
+
+---
+apiVersion: apps/v1
+kind: DaemonSet
+metadata:
+  name: nova-compute
+  annotations:
+    {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
+  labels:
+{{ tuple $envAll .Chart.Name $daemonset | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+spec:
+  selector:
+    matchLabels:
+{{ tuple $envAll .Chart.Name $daemonset | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }}
+{{ tuple $envAll $daemonset | include "helm-toolkit.snippets.kubernetes_upgrades_daemonset" | indent 2 }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll .Chart.Name $daemonset | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+      annotations:
+{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+        configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ dict "envAll" $envAll "podName" "nova-compute-default" "containerNames" (list "nova-compute" "init" "nova-compute-init" "nova-compute-vnc-init") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName }}
+{{ dict "envAll" $envAll "application" "nova" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
+      nodeSelector:
+        {{ .Values.labels.agent.compute.node_selector_key }}: {{ .Values.labels.agent.compute.node_selector_value }}
+      hostNetwork: true
+      hostPID: true
+      hostIPC: true
+      dnsPolicy: ClusterFirstWithHostNet
+      initContainers:
+{{ tuple $envAll "pod_dependency" $mounts_nova_compute_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+        - name: nova-compute-init
+{{ tuple $envAll "nova_compute" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_compute_init" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          env:
+            - name: NOVA_USER_UID
+              value: "{{ .Values.pod.security_context.nova.pod.runAsUser }}"
+          command:
+            - /tmp/nova-compute-init.sh
+          terminationMessagePath: /var/log/termination-log
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/nova-compute-init.sh
+              subPath: nova-compute-init.sh
+              readOnly: true
+            - name: varlibnova
+              mountPath: /var/lib/nova
+            - name: pod-shared
+              mountPath: /tmp/pod-shared
+{{ if $mounts_nova_compute.volumeMounts }}{{ toYaml $mounts_nova_compute.volumeMounts | indent 12 }}{{ end }}
+        {{- if .Values.conf.ceph.enabled }}
+        - name: ceph-perms
+{{ tuple $envAll "nova_compute" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "ceph_perms" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          command:
+            - chown
+            - -R
+            - "nova:"
+            - /etc/ceph
+          terminationMessagePath: /var/log/termination-log
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: etcceph
+              mountPath: /etc/ceph
+{{ if $mounts_nova_compute.volumeMounts }}{{ toYaml $mounts_nova_compute.volumeMounts | indent 12 }}{{ end }}
+        {{- if empty .Values.conf.ceph.cinder.keyring }}
+        - name: ceph-admin-keyring-placement
+{{ tuple $envAll "nova_compute" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "ceph_admin_keyring_placement" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          command:
+            - /tmp/ceph-admin-keyring.sh
+          terminationMessagePath: /var/log/termination-log
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: etcceph
+              mountPath: /etc/ceph
+            - name: nova-bin
+              mountPath: /tmp/ceph-admin-keyring.sh
+              subPath: ceph-admin-keyring.sh
+              readOnly: true
+            {{- if empty .Values.conf.ceph.admin_keyring }}
+            - name: ceph-keyring
+              mountPath: /tmp/client-keyring
+              subPath: key
+              readOnly: true
+            {{ end }}
+{{ if $mounts_nova_compute.volumeMounts }}{{ toYaml $mounts_nova_compute.volumeMounts | indent 12 }}{{ end }}
+        {{ end }}
+        - name: ceph-keyring-placement
+{{ tuple $envAll "nova_compute" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "ceph_keyring_placement" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          env:
+            - name: CEPH_CINDER_USER
+              value: "{{ .Values.conf.ceph.cinder.user }}"
+            {{- if .Values.conf.ceph.cinder.keyring }}
+            - name: CEPH_CINDER_KEYRING
+              value: "{{ .Values.conf.ceph.cinder.keyring }}"
+            {{ end }}
+            - name: LIBVIRT_CEPH_SECRET_UUID
+              value: "{{ .Values.conf.ceph.secret_uuid }}"
+          command:
+            - /tmp/ceph-keyring.sh
+          terminationMessagePath: /var/log/termination-log
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: etcceph
+              mountPath: /etc/ceph
+            - name: nova-bin
+              mountPath: /tmp/ceph-keyring.sh
+              subPath: ceph-keyring.sh
+            - name: ceph-etc
+              mountPath: /etc/ceph/ceph.conf.template
+              subPath: ceph.conf
+              readOnly: true
+{{ if $mounts_nova_compute.volumeMounts }}{{ toYaml $mounts_nova_compute.volumeMounts | indent 12 }}{{ end }}
+        {{ end }}
+        {{- if eq .Values.console.console_kind "novnc"}}
+        - name: nova-compute-vnc-init
+{{ tuple $envAll "nova_compute" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.compute | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_compute_vnc_init" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          command:
+            - /tmp/nova-console-compute-init.sh
+          terminationMessagePath: /var/log/termination-log
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/nova-console-compute-init.sh
+              subPath: nova-console-compute-init.sh
+              readOnly: true
+            - name: pod-shared
+              mountPath: /tmp/pod-shared
+{{ if $mounts_nova_compute.volumeMounts }}{{ toYaml $mounts_nova_compute.volumeMounts | indent 12 }}{{ end }}
+        {{ end }}
+        {{- if eq .Values.console.console_kind "spice"}}
+        - name: nova-compute-spice-init
+{{ tuple $envAll "nova_compute" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.compute | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_compute_spice_init" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          command:
+            - /tmp/nova-console-compute-init.sh
+          terminationMessagePath: /var/log/termination-log
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/nova-console-compute-init.sh
+              subPath: nova-console-compute-init.sh
+              readOnly: true
+            - name: pod-shared
+              mountPath: /tmp/pod-shared
+{{ if $mounts_nova_compute.volumeMounts }}{{ toYaml $mounts_nova_compute.volumeMounts | indent 12 }}{{ end }}
+        {{ end }}
+        {{- if ( has "tungstenfabric" .Values.network.backend ) }}
+        - name: tungstenfabric-compute-init
+          image: {{ .Values.images.tags.tf_compute_init }}
+          imagePullPolicy: {{ .Values.images.pull_policy }}
+{{ tuple $envAll $envAll.Values.pod.resources.compute | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "tungstenfabric_compute_init" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          volumeMounts:
+            - name: tf-plugin-shared
+              mountPath: /opt/plugin
+            - name: tf-plugin-bin
+              mountPath: /opt/plugin/bin
+{{ if $mounts_nova_compute.volumeMounts }}{{ toYaml $mounts_nova_compute.volumeMounts | indent 12 }}{{ end }}
+        {{- end }}
+        {{- if .Values.network.ssh.enabled }}
+        - name: nova-compute-ssh-init
+{{ tuple $envAll "nova_compute_ssh" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.ssh | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_compute_ssh_init" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          terminationMessagePath: /var/log/termination-log
+          env:
+            - name: SSH_PORT
+              value: {{ .Values.network.ssh.port | quote }}
+            - name: NOVA_USER_UID
+              value: "{{ .Values.pod.security_context.nova.pod.runAsUser }}"
+          command:
+            - /tmp/ssh-init.sh
+          volumeMounts:
+            - name: varlibnova
+              mountPath: /var/lib/nova
+            - name: nova-ssh
+              mountPath: /tmp/nova-ssh/authorized_keys
+              subPath: public-key
+            - name: nova-ssh
+              mountPath: /tmp/nova-ssh/id_rsa
+              subPath: private-key
+            - name: nova-bin
+              mountPath: /tmp/ssh-init.sh
+              subPath: ssh-init.sh
+              readOnly: true
+{{ if $mounts_nova_compute.volumeMounts }}{{ toYaml $mounts_nova_compute.volumeMounts | indent 12 }}{{ end }}
+        {{- end }}
+      containers:
+        - name: nova-compute
+{{ tuple $envAll "nova_compute" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.compute | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_compute" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          env:
+          {{- if .Values.conf.ceph.enabled }}
+            - name: CEPH_CINDER_USER
+              value: "{{ .Values.conf.ceph.cinder.user }}"
+            {{- if .Values.conf.ceph.cinder.keyring }}
+            - name: CEPH_CINDER_KEYRING
+              value: "{{ .Values.conf.ceph.cinder.keyring }}"
+            {{ end }}
+            - name: LIBVIRT_CEPH_SECRET_UUID
+              value: "{{ .Values.conf.ceph.secret_uuid }}"
+          {{ end }}
+            - name: RPC_PROBE_TIMEOUT
+              value: "{{ .Values.pod.probes.rpc_timeout }}"
+            - name: RPC_PROBE_RETRIES
+              value: "{{ .Values.pod.probes.rpc_retries }}"
+{{- if .Values.manifests.certificates }}
+            - name: REQUESTS_CA_BUNDLE
+              value: "/etc/nova/certs/ca.crt"
+{{- end }}
+{{ dict "envAll" $envAll "component" "compute" "container" "default" "type" "liveness" "probeTemplate" (include "novaComputeLivenessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+{{ dict "envAll" $envAll "component" "compute" "container" "default" "type" "readiness" "probeTemplate" (include "novaComputeReadinessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+          command:
+            - /tmp/nova-compute.sh
+          terminationMessagePath: /var/log/termination-log
+          volumeMounts:
+            - name: dev-pts
+              mountPath: /dev/pts
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/nova-compute.sh
+              subPath: nova-compute.sh
+              readOnly: true
+            - name: nova-bin
+              mountPath: /tmp/health-probe.py
+              subPath: health-probe.py
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/nova.conf
+              subPath: nova-compute.conf
+              readOnly: true
+            {{- if .Values.conf.nova.DEFAULT.log_config_append }}
+            - name: nova-etc
+              mountPath: {{ .Values.conf.nova.DEFAULT.log_config_append }}
+              subPath: {{ base .Values.conf.nova.DEFAULT.log_config_append }}
+              readOnly: true
+            {{- end }}
+            - name: nova-etc
+              mountPath: /etc/nova/api-paste.ini
+              subPath: api-paste.ini
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/policy.yaml
+              subPath: policy.yaml
+              readOnly: true
+            - name: nova-etc
+              # NOTE (Portdirect): We mount here to override Kollas
+              # custom sudoers file when using Kolla images, this
+              # location will also work fine for other images.
+              mountPath: /etc/sudoers.d/kolla_nova_sudoers
+              subPath: nova_sudoers
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/rootwrap.conf
+              subPath: rootwrap.conf
+              readOnly: true
+            {{- range $key, $value := $envAll.Values.conf.rootwrap_filters }}
+            {{- if ( has "compute" $value.pods ) }}
+            {{- $filePrefix := replace "_" "-"  $key }}
+            {{- $rootwrapFile := printf "/etc/nova/rootwrap.d/%s.filters" $filePrefix }}
+            - name: nova-etc
+              mountPath: {{ $rootwrapFile }}
+              subPath: {{ base $rootwrapFile }}
+              readOnly: true
+            {{- end }}
+            {{- end }}
+            {{- if .Values.conf.ceph.enabled }}
+            - name: etcceph
+              mountPath: /etc/ceph
+              {{- if or ( gt .Capabilities.KubeVersion.Major "1" ) ( ge .Capabilities.KubeVersion.Minor "10" ) }}
+              mountPropagation: Bidirectional
+              {{- end }}
+            {{- if and ( empty .Values.conf.ceph.cinder.keyring ) ( empty .Values.conf.ceph.admin_keyring )}}
+            - name: ceph-keyring
+              mountPath: /tmp/client-keyring
+              subPath: key
+              readOnly: true
+            {{ end }}
+            {{ end }}
+            - mountPath: /lib/modules
+              name: libmodules
+              readOnly: true
+            - name: varlibnova
+              mountPath: /var/lib/nova
+              {{- if or ( gt .Capabilities.KubeVersion.Major "1" ) ( ge .Capabilities.KubeVersion.Minor "10" ) }}
+              mountPropagation: Bidirectional
+              {{- end }}
+            - name: varliblibvirt
+              mountPath: /var/lib/libvirt
+              {{- if or ( gt .Capabilities.KubeVersion.Major "1" ) ( ge .Capabilities.KubeVersion.Minor "10" ) }}
+              mountPropagation: Bidirectional
+              {{- end }}
+            - name: run
+              mountPath: /run
+            - name: cgroup
+              mountPath: /sys/fs/cgroup
+              readOnly: true
+            - name: pod-shared
+              mountPath: /tmp/pod-shared
+            - name: machine-id
+              mountPath: /etc/machine-id
+              readOnly: true
+            {{- if .Values.conf.enable_iscsi }}
+            - name: host-rootfs
+              mountPath: /mnt/host-rootfs
+              mountPropagation: HostToContainer
+            - name: usrlocalsbin
+              mountPath: /usr/local/sbin
+            - name: etciscsi
+              mountPath: /etc/iscsi
+              {{- if or ( gt .Capabilities.KubeVersion.Major "1" ) ( ge .Capabilities.KubeVersion.Minor "10" ) }}
+              mountPropagation: HostToContainer
+              {{- end }}
+            - name: dev
+              mountPath: /dev
+              {{- if or ( gt .Capabilities.KubeVersion.Major "1" ) ( ge .Capabilities.KubeVersion.Minor "10" ) }}
+              mountPropagation: HostToContainer
+              {{- end }}
+            - name: nova-bin
+              mountPath: /usr/local/sbin/iscsiadm
+              subPath: iscsiadm
+            - name: runlock
+              mountPath: /run/lock
+            - name: nova-bin
+              mountPath: /usr/local/sbin/multipath
+              subPath: multipath
+            - name: nova-bin
+              mountPath: /usr/local/sbin/multipathd
+              subPath: multipathd
+            - name: etcmultipath
+              mountPath: /etc/multipath
+              {{- if or ( gt .Capabilities.KubeVersion.Major "1" ) ( ge .Capabilities.KubeVersion.Minor "10" ) }}
+              mountPropagation: Bidirectional
+              {{- end }}
+            - name: sysblock
+              mountPath: /sys/block
+              {{- if or ( gt .Capabilities.KubeVersion.Major "1" ) ( ge .Capabilities.KubeVersion.Minor "10" ) }}
+              mountPropagation: HostToContainer
+              {{- end }}
+            {{- end }}
+            {{- if ( has "tungstenfabric" .Values.network.backend ) }}
+            - name: tf-plugin-shared
+              mountPath: /opt/plugin
+              readOnly: true
+            - name: tf-plugin-bin
+              mountPath: /usr/sbin
+              readOnly: true
+            - name: nova-bin
+              mountPath: /usr/local/lib/python2.7/site-packages/tf-plugin.pth
+              subPath: tf-plugin.pth
+              readOnly: true
+            - name: nova-bin
+              mountPath: /var/lib/openstack/lib/python2.7/site-packages/tf-plugin.pth
+              subPath: tf-plugin.pth
+              readOnly: true
+            - name: nova-bin
+              mountPath: /var/lib/openstack/lib/python3.6/site-packages/tf-plugin.pth
+              subPath: tf-plugin.pth
+              readOnly: true
+            {{- end }}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute.osapi.internal "path" "/etc/nova/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal "path" "/etc/rabbitmq/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{ if $mounts_nova_compute.volumeMounts }}{{ toYaml $mounts_nova_compute.volumeMounts | indent 12 }}{{ end }}
+        {{- if .Values.network.ssh.enabled }}
+        - name: nova-compute-ssh
+{{ tuple $envAll "nova_compute_ssh" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.ssh | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_compute_ssh" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          env:
+            - name: KEY_TYPES
+              value: {{ include "helm-toolkit.utils.joinListWithComma" .Values.network.ssh.key_types | quote }}
+            - name: SSH_PORT
+              value: {{ .Values.network.ssh.port | quote }}
+{{- if .Values.manifests.certificates }}
+            - name: REQUESTS_CA_BUNDLE
+              value: "/etc/nova/certs/ca.crt"
+{{- end }}
+          ports:
+            - containerPort: {{ .Values.network.ssh.port }}
+          command:
+            - /tmp/ssh-start.sh
+          terminationMessagePath: /var/log/termination-log
+          volumeMounts:
+            - name: varlibnova
+              mountPath: /var/lib/nova
+            - name: nova-bin
+              mountPath: /tmp/ssh-start.sh
+              subPath: ssh-start.sh
+              readOnly: true
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute.osapi.internal "path" "/etc/nova/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{ if $mounts_nova_compute.volumeMounts }}{{ toYaml $mounts_nova_compute.volumeMounts | indent 12 }}{{ end }}
+        {{ end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: nova-bin
+          configMap:
+            name: nova-bin
+            defaultMode: 0555
+        - name: nova-etc
+          secret:
+            secretName: {{ $configMapName }}
+            defaultMode: 0444
+        {{- if .Values.network.ssh.enabled }}
+        - name: nova-ssh
+          secret:
+            secretName: nova-ssh
+            defaultMode: 0644
+        {{ end }}
+        {{- if .Values.conf.ceph.enabled }}
+        - name: etcceph
+          hostPath:
+            path: /var/lib/openstack-helm/compute/nova
+        - name: ceph-etc
+          configMap:
+            name: {{ .Values.ceph_client.configmap }}
+            defaultMode: 0444
+        {{- if and ( empty .Values.conf.ceph.cinder.keyring ) ( empty .Values.conf.ceph.admin_keyring ) }}
+        - name: ceph-keyring
+          secret:
+            secretName: {{ .Values.ceph_client.user_secret_name }}
+        {{ end }}
+        {{ end }}
+        - name: dev-pts
+          hostPath:
+            path: /dev/pts
+        - name: libmodules
+          hostPath:
+            path: /lib/modules
+        - name: varlibnova
+          hostPath:
+            path: /var/lib/nova
+        - name: varliblibvirt
+          hostPath:
+            path: /var/lib/libvirt
+        - name: run
+          hostPath:
+            path: /run
+        - name: cgroup
+          hostPath:
+            path: /sys/fs/cgroup
+        - name: pod-shared
+          emptyDir: {}
+        - name: machine-id
+          hostPath:
+            path: /etc/machine-id
+        {{- if .Values.conf.enable_iscsi }}
+        - name: host-rootfs
+          hostPath:
+            path: /
+        - name: runlock
+          hostPath:
+            path: /run/lock
+        - name: etciscsi
+          hostPath:
+            path: /etc/iscsi
+        - name: dev
+          hostPath:
+            path: /dev
+        - name: usrlocalsbin
+          emptyDir: {}
+        - name: etcmultipath
+          hostPath:
+            path: /etc/multipath
+        - name: sysblock
+          hostPath:
+            path: /sys/block
+
+        {{- end }}
+        {{- if ( has "tungstenfabric" .Values.network.backend ) }}
+        - name: tf-plugin-shared
+          emptyDir: {}
+        - name: tf-plugin-bin
+          emptyDir: {}
+        {{- end }}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute.osapi.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{ if $mounts_nova_compute.volumes }}{{ toYaml $mounts_nova_compute.volumes | indent 8 }}{{ end }}
+{{- end }}
+{{- end }}
+
+{{- if .Values.manifests.daemonset_compute }}
+{{- $envAll := . }}
+{{- $daemonset := "compute" }}
+{{- $configMapName := "nova-etc" }}
+{{- $serviceAccountName := "nova-compute" }}
+
+{{- $dependencyOpts := dict "envAll" $envAll "dependencyMixinParam" $envAll.Values.network.backend "dependencyKey" "compute" -}}
+{{- $_ := include "helm-toolkit.utils.dependency_resolver" $dependencyOpts | toString | fromYaml }}
+
+{{ tuple $envAll "pod_dependency" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+{{- $daemonset_yaml := list $daemonset $configMapName $serviceAccountName . | include "nova.compute.daemonset" | toString | fromYaml }}
+{{- $configmap_yaml := "nova.configmap.etc" }}
+{{- list $daemonset $daemonset_yaml $configmap_yaml $configMapName . | include "helm-toolkit.utils.daemonset_overrides" }}
+{{- end }}
diff --git a/charts/nova/templates/deployment-api-metadata.yaml b/charts/nova/templates/deployment-api-metadata.yaml
new file mode 100644
index 0000000..c663a23
--- /dev/null
+++ b/charts/nova/templates/deployment-api-metadata.yaml
@@ -0,0 +1,204 @@
+{{/*
+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.
+*/}}
+
+{{- define "novaApiMetadataLivenessProbeTemplate" }}
+tcpSocket:
+  port: {{ .Values.network.metadata.port }}
+{{- end }}
+
+{{- define "novaApiMetadataReadinessProbeTemplate" }}
+tcpSocket:
+  port: {{ .Values.network.metadata.port }}
+{{- end }}
+
+{{- if .Values.manifests.deployment_api_metadata }}
+{{- $envAll := . }}
+
+{{- $mounts_nova_api_metadata := .Values.pod.mounts.nova_api_metadata.nova_api_metadata }}
+{{- $mounts_nova_api_metadata_init := .Values.pod.mounts.nova_api_metadata.init_container }}
+
+{{- $serviceAccountName := "nova-api-metadata" }}
+{{ tuple $envAll "api_metadata" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: nova-api-metadata
+  annotations:
+    {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
+  labels:
+{{ tuple $envAll "nova" "metadata" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+spec:
+  replicas: {{ .Values.pod.replicas.api_metadata }}
+  selector:
+    matchLabels:
+{{ tuple $envAll "nova" "metadata" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }}
+{{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_deployment" | indent 2 }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll "nova" "metadata" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+      annotations:
+{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+        configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
+        configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ dict "envAll" $envAll "podName" "nova-api-metadata" "containerNames" (list "nova-api-metadata-init" "nova-api" "init") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName }}
+{{ dict "envAll" $envAll "application" "nova" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
+      affinity:
+{{ tuple $envAll "nova" "metadata" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }}
+      nodeSelector:
+        {{ .Values.labels.api_metadata.node_selector_key }}: {{ .Values.labels.api_metadata.node_selector_value }}
+      terminationGracePeriodSeconds: {{ .Values.pod.lifecycle.termination_grace_period.metadata.timeout | default "30" }}
+      initContainers:
+{{ tuple $envAll "api_metadata" $mounts_nova_api_metadata_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+        - name: nova-api-metadata-init
+{{ tuple $envAll "nova_api" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.api_metadata | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_api_metadata_init" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          command:
+            - /tmp/nova-api-metadata-init.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/nova-api-metadata-init.sh
+              subPath: nova-api-metadata-init.sh
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/nova.conf
+              subPath: nova.conf
+              readOnly: true
+            - name: pod-shared
+              mountPath: /tmp/pod-shared
+      containers:
+        - name: nova-api
+{{ tuple $envAll "nova_api" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.api_metadata | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_api" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          command:
+            - /tmp/nova-api-metadata.sh
+            - start
+          lifecycle:
+            preStop:
+              exec:
+                command:
+                  - /tmp/nova-api-metadata.sh
+                  - stop
+          ports:
+            - containerPort: {{ .Values.network.metadata.port }}
+{{ dict "envAll" $envAll "component" "api-metadata" "container" "default" "type" "liveness" "probeTemplate" (include "novaApiMetadataLivenessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+{{ dict "envAll" $envAll "component" "api-metadata" "container" "default" "type" "readiness" "probeTemplate" (include "novaApiMetadataReadinessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/nova-api-metadata.sh
+              subPath: nova-api-metadata.sh
+              readOnly: true
+            - name: nova-bin
+              mountPath: /sbin/iptables
+              subPath: fake-iptables.sh
+              readOnly: true
+            - name: nova-bin
+              mountPath: /sbin/iptables-restore
+              subPath: fake-iptables.sh
+              readOnly: true
+            - name: nova-bin
+              mountPath: /sbin/iptables-save
+              subPath: fake-iptables.sh
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/nova.conf
+              subPath: nova.conf
+              readOnly: true
+            {{- if .Values.conf.nova.DEFAULT.log_config_append }}
+            - name: nova-etc
+              mountPath: {{ .Values.conf.nova.DEFAULT.log_config_append }}
+              subPath: {{ base .Values.conf.nova.DEFAULT.log_config_append }}
+              readOnly: true
+            {{- end }}
+            - name: nova-etc
+              mountPath: /etc/nova/api-paste.ini
+              subPath: api-paste.ini
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/policy.yaml
+              subPath: policy.yaml
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/api_audit_map.conf
+              subPath: api_audit_map.conf
+              readOnly: true
+            - name: nova-etc
+              # NOTE (Portdirect): We mount here to override Kollas
+              # custom sudoers file when using Kolla images, this
+              # location will also work fine for other images.
+              mountPath: /etc/sudoers.d/kolla_nova_sudoers
+              subPath: nova_sudoers
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/rootwrap.conf
+              subPath: rootwrap.conf
+              readOnly: true
+            {{- range $key, $value := $envAll.Values.conf.rootwrap_filters }}
+            {{- if ( has "metadata" $value.pods ) }}
+            {{- $filePrefix := replace "_" "-"  $key }}
+            {{- $rootwrapFile := printf "/etc/nova/rootwrap.d/%s.filters" $filePrefix }}
+            - name: nova-etc
+              mountPath: {{ $rootwrapFile }}
+              subPath: {{ base $rootwrapFile }}
+              readOnly: true
+            {{- end }}
+            {{- end }}
+            - name: pod-shared
+              mountPath: /tmp/pod-shared
+              readOnly: true
+            {{- if .Values.manifests.certificates }}
+            - name: wsgi-nova
+              mountPath: /var/www/cgi-bin/nova
+            - name: nova-etc
+              mountPath: {{ .Values.conf.software.apache2.conf_dir }}/wsgi-metadata.conf
+              subPath: wsgi-metadata.conf
+              readOnly: true
+            - name: nova-etc
+              mountPath: {{ .Values.conf.software.apache2.mods_dir }}/mpm_event.conf
+              subPath: mpm_event.conf
+              readOnly: true
+            {{- end }}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal "path" "/etc/mysql/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute_metadata.metadata.internal "path" "/etc/nova/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{ if $mounts_nova_api_metadata.volumeMounts }}{{ toYaml $mounts_nova_api_metadata.volumeMounts | indent 12 }}{{ end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        {{- if .Values.manifests.certificates }}
+        - name: wsgi-nova
+          emptyDir: {}
+        {{- end }}
+        - name: nova-bin
+          configMap:
+            name: nova-bin
+            defaultMode: 0555
+        - name: nova-etc
+          secret:
+            secretName: nova-etc
+            defaultMode: 0444
+        - name: pod-shared
+          emptyDir: {}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute_metadata.metadata.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{ if $mounts_nova_api_metadata.volumes }}{{ toYaml $mounts_nova_api_metadata.volumes | indent 8 }}{{ end }}
+{{- end }}
diff --git a/charts/nova/templates/deployment-api-osapi.yaml b/charts/nova/templates/deployment-api-osapi.yaml
new file mode 100644
index 0000000..41c1faf
--- /dev/null
+++ b/charts/nova/templates/deployment-api-osapi.yaml
@@ -0,0 +1,154 @@
+{{/*
+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.
+*/}}
+
+{{- define "novaApiOsapiLivenessProbeTemplate" }}
+tcpSocket:
+  port: {{ tuple "compute" "internal" "api" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+{{- end }}
+
+{{- define "novaApiOsapiReadinessProbeTemplate" }}
+tcpSocket:
+  port: {{ tuple "compute" "internal" "api" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+{{- end }}
+
+{{- if .Values.manifests.deployment_api_osapi }}
+{{- $envAll := . }}
+
+{{- $mounts_nova_api_osapi := .Values.pod.mounts.nova_api_osapi.nova_api_osapi }}
+{{- $mounts_nova_api_osapi_init := .Values.pod.mounts.nova_api_osapi.init_container }}
+
+{{- $serviceAccountName := "nova-api-osapi" }}
+{{ tuple $envAll "api" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: nova-api-osapi
+  annotations:
+    {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
+  labels:
+{{ tuple $envAll "nova" "os-api" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+spec:
+  replicas: {{ .Values.pod.replicas.osapi }}
+  selector:
+    matchLabels:
+{{ tuple $envAll "nova" "os-api" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }}
+{{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_deployment" | indent 2 }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll "nova" "os-api" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+      annotations:
+{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+        configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
+        configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ dict "envAll" $envAll "podName" "nova-api-osapi" "containerNames" (list "nova-osapi" "init") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName }}
+{{ dict "envAll" $envAll "application" "nova" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
+      affinity:
+{{ tuple $envAll "nova" "os-api" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }}
+      nodeSelector:
+        {{ .Values.labels.osapi.node_selector_key }}: {{ .Values.labels.osapi.node_selector_value }}
+      terminationGracePeriodSeconds: {{ .Values.pod.lifecycle.termination_grace_period.osapi.timeout | default "30" }}
+      initContainers:
+{{ tuple $envAll "api" $mounts_nova_api_osapi_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+      containers:
+        - name: nova-osapi
+{{ tuple $envAll "nova_api" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.api | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_osapi" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          command:
+            - /tmp/nova-api.sh
+            - start
+          lifecycle:
+            preStop:
+              exec:
+                command:
+                  - /tmp/nova-api.sh
+                  - stop
+          ports:
+            - name: n-api
+              containerPort: {{ tuple "compute" "internal" "api" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+{{ dict "envAll" $envAll "component" "api-osapi" "container" "default" "type" "liveness" "probeTemplate" (include "novaApiOsapiLivenessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+{{ dict "envAll" $envAll "component" "api-osapi" "container" "default" "type" "readiness" "probeTemplate" (include "novaApiOsapiReadinessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: pod-var-nova
+              mountPath: /var/lib/nova
+            - name: nova-bin
+              mountPath: /tmp/nova-api.sh
+              subPath: nova-api.sh
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/nova.conf
+              subPath: nova.conf
+              readOnly: true
+            {{- if .Values.conf.nova.DEFAULT.log_config_append }}
+            - name: nova-etc
+              mountPath: {{ .Values.conf.nova.DEFAULT.log_config_append }}
+              subPath: {{ base .Values.conf.nova.DEFAULT.log_config_append }}
+              readOnly: true
+            {{- end }}
+            - name: nova-etc
+              mountPath: /etc/nova/api-paste.ini
+              subPath: api-paste.ini
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/policy.yaml
+              subPath: policy.yaml
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/api_audit_map.conf
+              subPath: api_audit_map.conf
+              readOnly: true
+            {{- if .Values.manifests.certificates }}
+            - name: wsgi-nova
+              mountPath: /var/www/cgi-bin/nova
+            - name: nova-etc
+              mountPath: {{ .Values.conf.software.apache2.conf_dir }}/wsgi-api.conf
+              subPath: wsgi-api.conf
+              readOnly: true
+            - name: nova-etc
+              mountPath: {{ .Values.conf.software.apache2.mods_dir }}/mpm_event.conf
+              subPath: mpm_event.conf
+              readOnly: true
+            {{- end }}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal "path" "/etc/mysql/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute.osapi.internal "path" "/etc/nova/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal "path" "/etc/rabbitmq/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{ if $mounts_nova_api_osapi.volumeMounts }}{{ toYaml $mounts_nova_api_osapi.volumeMounts | indent 12 }}{{ end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        {{- if .Values.manifests.certificates }}
+        - name: wsgi-nova
+          emptyDir: {}
+        {{- end }}
+        - name: pod-var-nova
+          emptyDir: {}
+        - name: nova-bin
+          configMap:
+            name: nova-bin
+            defaultMode: 0555
+        - name: nova-etc
+          secret:
+            secretName: nova-etc
+            defaultMode: 0444
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute.osapi.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{ if $mounts_nova_api_osapi.volumes}}{{ toYaml $mounts_nova_api_osapi.volumes | indent 8 }}{{ end }}
+{{- end }}
diff --git a/charts/nova/templates/deployment-conductor.yaml b/charts/nova/templates/deployment-conductor.yaml
new file mode 100644
index 0000000..5335a4c
--- /dev/null
+++ b/charts/nova/templates/deployment-conductor.yaml
@@ -0,0 +1,141 @@
+{{/*
+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.
+*/}}
+
+{{- define "novaConductorLivenessProbeTemplate" }}
+exec:
+  command:
+    - python
+    - /tmp/health-probe.py
+    - --config-file
+    - /etc/nova/nova.conf
+    - --service-queue-name
+    - conductor
+    - --liveness-probe
+{{- end }}
+
+{{- define "novaConductorReadinessProbeTemplate" }}
+exec:
+  command:
+    - python
+    - /tmp/health-probe.py
+    - --config-file
+    - /etc/nova/nova.conf
+    - --service-queue-name
+    - conductor
+{{- end }}
+
+{{- if .Values.manifests.deployment_conductor }}
+{{- $envAll := . }}
+
+{{- $mounts_nova_conductor := .Values.pod.mounts.nova_conductor.nova_conductor }}
+{{- $mounts_nova_conductor_init := .Values.pod.mounts.nova_conductor.init_container }}
+
+{{- $serviceAccountName := "nova-conductor" }}
+{{ tuple $envAll "conductor" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: nova-conductor
+  annotations:
+    {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
+  labels:
+{{ tuple $envAll "nova" "conductor" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+spec:
+  replicas: {{ .Values.pod.replicas.conductor }}
+  selector:
+    matchLabels:
+{{ tuple $envAll "nova" "conductor" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }}
+{{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_deployment" | indent 2 }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll "nova" "conductor" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+      annotations:
+{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+        configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
+        configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ dict "envAll" $envAll "podName" "nova-conductor" "containerNames" (list "nova-conductor" "init") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName }}
+{{ dict "envAll" $envAll "application" "nova" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
+      affinity:
+{{ tuple $envAll "nova" "conductor" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }}
+      nodeSelector:
+        {{ .Values.labels.conductor.node_selector_key }}: {{ .Values.labels.conductor.node_selector_value }}
+      initContainers:
+{{ tuple $envAll "conductor" $mounts_nova_conductor_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+      containers:
+        - name: nova-conductor
+{{ tuple $envAll "nova_conductor" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.conductor | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_conductor" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+{{ dict "envAll" $envAll "component" "conductor" "container" "default" "type" "liveness" "probeTemplate" (include "novaConductorLivenessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+{{ dict "envAll" $envAll "component" "conductor" "container" "default" "type" "readiness" "probeTemplate" (include "novaConductorReadinessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+          env:
+            - name: RPC_PROBE_TIMEOUT
+              value: "{{ .Values.pod.probes.rpc_timeout }}"
+            - name: RPC_PROBE_RETRIES
+              value: "{{ .Values.pod.probes.rpc_retries }}"
+{{- if .Values.manifests.certificates }}
+            - name: REQUESTS_CA_BUNDLE
+              value: "/etc/nova/certs/ca.crt"
+{{- end }}
+          command:
+            - /tmp/nova-conductor.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/nova-conductor.sh
+              subPath: nova-conductor.sh
+              readOnly: true
+            - name: nova-bin
+              mountPath: /tmp/health-probe.py
+              subPath: health-probe.py
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/nova.conf
+              subPath: nova.conf
+              readOnly: true
+            {{- if .Values.conf.nova.DEFAULT.log_config_append }}
+            - name: nova-etc
+              mountPath: {{ .Values.conf.nova.DEFAULT.log_config_append }}
+              subPath: {{ base .Values.conf.nova.DEFAULT.log_config_append }}
+              readOnly: true
+            {{- end }}
+            - name: nova-etc
+              mountPath: /etc/nova/policy.yaml
+              subPath: policy.yaml
+              readOnly: true
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute.osapi.internal "path" "/etc/nova/certs" "certs" (tuple "ca.crt") | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_db.auth.admin.secret.tls.internal "path" "/etc/mysql/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal "path" "/etc/rabbitmq/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{ if $mounts_nova_conductor.volumeMounts }}{{ toYaml $mounts_nova_conductor.volumeMounts | indent 12 }}{{ end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: nova-bin
+          configMap:
+            name: nova-bin
+            defaultMode: 0555
+        - name: nova-etc
+          secret:
+            secretName: nova-etc
+            defaultMode: 0444
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute.osapi.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_db.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{ if $mounts_nova_conductor.volumes }}{{ toYaml $mounts_nova_conductor.volumes | indent 8 }}{{ end }}
+{{- end }}
diff --git a/charts/nova/templates/deployment-consoleauth.yaml b/charts/nova/templates/deployment-consoleauth.yaml
new file mode 100644
index 0000000..c4a781f
--- /dev/null
+++ b/charts/nova/templates/deployment-consoleauth.yaml
@@ -0,0 +1,133 @@
+{{/*
+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.
+*/}}
+
+{{- define "novaConsoleauthLivenessProbeTemplate" }}
+exec:
+  command:
+    - python
+    - /tmp/health-probe.py
+    - --config-file
+    - /etc/nova/nova.conf
+    - --service-queue-name
+    - consoleauth
+    - --liveness-probe
+{{- end }}
+
+{{- define "novaConsoleauthReadinessProbeTemplate" }}
+exec:
+  command:
+    - python
+    - /tmp/health-probe.py
+    - --config-file
+    - /etc/nova/nova.conf
+    - --service-queue-name
+    - consoleauth
+{{- end }}
+
+{{- if .Values.manifests.deployment_consoleauth }}
+{{- $envAll := . }}
+
+{{- $mounts_nova_consoleauth := .Values.pod.mounts.nova_consoleauth.nova_consoleauth }}
+{{- $mounts_nova_consoleauth_init := .Values.pod.mounts.nova_consoleauth.init_container }}
+
+{{- $serviceAccountName := "nova-consoleauth" }}
+{{ tuple $envAll "consoleauth" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: nova-consoleauth
+  annotations:
+    {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
+  labels:
+{{ tuple $envAll "nova" "consoleauth" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+spec:
+  replicas: {{ .Values.pod.replicas.consoleauth }}
+  selector:
+    matchLabels:
+{{ tuple $envAll "nova" "consoleauth" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }}
+{{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_deployment" | indent 2 }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll "nova" "consoleauth" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+      annotations:
+{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+        configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
+        configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ dict "envAll" $envAll "podName" "nova-consoleauth" "containerNames" (list "nova-consoleauth" "init") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName }}
+{{ dict "envAll" $envAll "application" "nova" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
+      affinity:
+{{ tuple $envAll "nova" "consoleauth" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }}
+      nodeSelector:
+        {{ .Values.labels.consoleauth.node_selector_key }}: {{ .Values.labels.consoleauth.node_selector_value }}
+      initContainers:
+{{ tuple $envAll "consoleauth" $mounts_nova_consoleauth_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+      containers:
+        - name: nova-consoleauth
+{{ tuple $envAll "nova_consoleauth" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.consoleauth | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_consoleauth" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+{{ dict "envAll" $envAll "component" "consoleauth" "container" "default" "type" "liveness" "probeTemplate" (include "novaConsoleauthLivenessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+{{ dict "envAll" $envAll "component" "consoleauth" "container" "default" "type" "readiness" "probeTemplate" (include "novaConsoleauthReadinessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+          env:
+            - name: RPC_PROBE_TIMEOUT
+              value: "{{ .Values.pod.probes.rpc_timeout }}"
+            - name: RPC_PROBE_RETRIES
+              value: "{{ .Values.pod.probes.rpc_retries }}"
+          command:
+            - /tmp/nova-consoleauth.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/nova-consoleauth.sh
+              subPath: nova-consoleauth.sh
+              readOnly: true
+            - name: nova-bin
+              mountPath: /tmp/health-probe.py
+              subPath: health-probe.py
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/nova.conf
+              subPath: nova.conf
+              readOnly: true
+            {{- if .Values.conf.nova.DEFAULT.log_config_append }}
+            - name: nova-etc
+              mountPath: {{ .Values.conf.nova.DEFAULT.log_config_append }}
+              subPath: {{ base .Values.conf.nova.DEFAULT.log_config_append }}
+              readOnly: true
+            {{- end }}
+            - name: nova-etc
+              mountPath: /etc/nova/policy.yaml
+              subPath: policy.yaml
+              readOnly: true
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_db.auth.admin.secret.tls.internal "path" "/etc/mysql/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{ if $mounts_nova_consoleauth.volumeMounts }}{{ toYaml $mounts_nova_consoleauth.volumeMounts | indent 12 }}{{ end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: nova-bin
+          configMap:
+            name: nova-bin
+            defaultMode: 0555
+        - name: nova-etc
+          secret:
+            secretName: nova-etc
+            defaultMode: 0444
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_db.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{ if $mounts_nova_consoleauth.volumes }}{{ toYaml $mounts_nova_consoleauth.volumes | indent 8 }}{{ end }}
+{{- end }}
diff --git a/charts/nova/templates/deployment-novncproxy.yaml b/charts/nova/templates/deployment-novncproxy.yaml
new file mode 100644
index 0000000..68db32a
--- /dev/null
+++ b/charts/nova/templates/deployment-novncproxy.yaml
@@ -0,0 +1,165 @@
+{{/*
+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.
+*/}}
+
+{{- define "novaNovncproxyLivenessProbeTemplate" }}
+tcpSocket:
+  port: {{ tuple "compute_novnc_proxy" "internal" "novnc_proxy" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+{{- end }}
+
+{{- define "novaNovncproxyReadinessProbeTemplate" }}
+tcpSocket:
+  port: {{ tuple "compute_novnc_proxy" "internal" "novnc_proxy" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+{{- end }}
+
+{{- if and .Values.manifests.deployment_novncproxy ( eq .Values.console.console_kind "novnc" )}}
+{{- $envAll := . }}
+
+{{- $mounts_nova_novncproxy := .Values.pod.mounts.nova_novncproxy.nova_novncproxy }}
+{{- $mounts_nova_novncproxy_init := .Values.pod.mounts.nova_novncproxy.init_novncproxy }}
+
+{{- $serviceAccountName := "nova-novncproxy" }}
+{{ tuple $envAll "novncproxy" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: nova-novncproxy
+  annotations:
+    {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
+  labels:
+{{ tuple $envAll "nova" "novnc-proxy" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+spec:
+  replicas: {{ .Values.pod.replicas.novncproxy }}
+  selector:
+    matchLabels:
+{{ tuple $envAll "nova" "novnc-proxy" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }}
+{{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_deployment" | indent 2 }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll "nova" "novnc-proxy" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+      annotations:
+{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+        configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
+        configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ dict "envAll" $envAll "podName" "nova-novncproxy" "containerNames" (list "nova-novncproxy" "nova-novncproxy-init-assets" "nova-novncproxy-init" "init") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName }}
+{{ dict "envAll" $envAll "application" "nova" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
+      affinity:
+{{ tuple $envAll "nova" "novnc-proxy" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }}
+      nodeSelector:
+        {{ .Values.labels.novncproxy.node_selector_key }}: {{ .Values.labels.novncproxy.node_selector_value }}
+{{- if .Values.pod.useHostNetwork.novncproxy }}
+      hostNetwork: true
+      dnsPolicy: ClusterFirstWithHostNet
+{{- end }}
+      initContainers:
+{{ tuple $envAll "novncproxy" $mounts_nova_novncproxy_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+        - name: nova-novncproxy-init
+{{ tuple $envAll "nova_novncproxy" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.novncproxy | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_novncproxy_init" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          command:
+            - /tmp/nova-console-proxy-init.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/nova-console-proxy-init.sh
+              subPath: nova-console-proxy-init.sh
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/nova.conf
+              subPath: nova.conf
+              readOnly: true
+            {{- if .Values.conf.nova.DEFAULT.log_config_append }}
+            - name: nova-etc
+              mountPath: {{ .Values.conf.nova.DEFAULT.log_config_append }}
+              subPath: {{ base .Values.conf.nova.DEFAULT.log_config_append }}
+              readOnly: true
+            {{- end }}
+            - name: pod-shared
+              mountPath: /tmp/pod-shared
+        - name: nova-novncproxy-init-assets
+{{ tuple $envAll "nova_novncproxy_assets" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.novncproxy | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_novncproxy_init_assests" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          command:
+            - /tmp/nova-console-proxy-init-assets.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/nova-console-proxy-init-assets.sh
+              subPath: nova-console-proxy-init-assets.sh
+              readOnly: true
+            - name: pod-usr-share-novnc
+              mountPath: /tmp/usr/share/novnc
+      containers:
+        - name: nova-novncproxy
+{{ tuple $envAll "nova_novncproxy" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.novncproxy | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_novncproxy" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+{{ dict "envAll" $envAll "component" "novncproxy" "container" "default" "type" "liveness" "probeTemplate" (include "novaNovncproxyLivenessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+{{ dict "envAll" $envAll "component" "novncproxy" "container" "default" "type" "readiness" "probeTemplate" (include "novaNovncproxyReadinessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+          command:
+            - /tmp/nova-console-proxy.sh
+          ports:
+            - name: n-novnc
+              containerPort: {{ tuple "compute_novnc_proxy" "internal" "novnc_proxy" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/nova-console-proxy.sh
+              subPath: nova-console-proxy.sh
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/nova.conf
+              subPath: nova.conf
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/logging.conf
+              subPath: logging.conf
+              readOnly: true
+            - name: pod-usr-share-novnc
+              mountPath: /usr/share/novnc
+              readOnly: true
+            - name: pod-shared
+              mountPath: /tmp/pod-shared
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal "path" "/etc/mysql/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute_novnc_proxy.novncproxy.internal "path" "/etc/nova/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal "path" "/etc/rabbitmq/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{ if $mounts_nova_novncproxy.volumeMounts }}{{ toYaml $mounts_nova_novncproxy.volumeMounts | indent 12 }}{{ end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: nova-bin
+          configMap:
+            name: nova-bin
+            defaultMode: 0555
+        - name: nova-etc
+          secret:
+            secretName: nova-etc
+            defaultMode: 0444
+        - name: pod-usr-share-novnc
+          emptyDir: {}
+        - name: pod-shared
+          emptyDir: {}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute_novnc_proxy.novncproxy.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{ if $mounts_nova_novncproxy.volumes }}{{ toYaml $mounts_nova_novncproxy.volumes | indent 8 }}{{ end }}
+{{- end }}
diff --git a/charts/nova/templates/deployment-placement.yaml b/charts/nova/templates/deployment-placement.yaml
new file mode 100644
index 0000000..1391cd9
--- /dev/null
+++ b/charts/nova/templates/deployment-placement.yaml
@@ -0,0 +1,142 @@
+{{/*
+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.
+*/}}
+
+{{- define "novaPlacementLivenessProbeTemplate" }}
+tcpSocket:
+  port: {{ tuple "placement" "internal" "api" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+{{- end }}
+
+{{- define "novaPlacementReadinessProbeTemplate" }}
+#NOTE(portdirect): use tcpSocket check as HTTP will return 401
+tcpSocket:
+  port: {{ tuple "placement" "internal" "api" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+{{- end }}
+
+{{- if .Values.manifests.deployment_placement }}
+{{- $envAll := . }}
+
+{{- $mounts_nova_placement := .Values.pod.mounts.nova_placement.nova_placement }}
+{{- $mounts_nova_placement_init := .Values.pod.mounts.nova_placement.init_container }}
+
+{{- $serviceAccountName := "nova-placement-api" }}
+{{ tuple $envAll "api" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: nova-placement-api
+  annotations:
+    {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
+  labels:
+{{ tuple $envAll "nova" "placement" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+spec:
+  replicas: {{ .Values.pod.replicas.placement }}
+  selector:
+    matchLabels:
+{{ tuple $envAll "nova" "placement" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }}
+{{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_deployment" | indent 2 }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll "nova" "placement" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+      annotations:
+{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+        configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
+        configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ dict "envAll" $envAll "podName" "nova-placement" "containerNames" (list "nova-placement-api" "init") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName }}
+      affinity:
+{{ tuple $envAll "nova" "placement" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }}
+      nodeSelector:
+        {{ .Values.labels.placement.node_selector_key }}: {{ .Values.labels.placement.node_selector_value }}
+      terminationGracePeriodSeconds: {{ .Values.pod.lifecycle.termination_grace_period.placement.timeout | default "30" }}
+      initContainers:
+{{ tuple $envAll "api" $mounts_nova_placement_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+      containers:
+        - name: nova-placement-api
+{{ tuple $envAll "nova_placement" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.placement | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_placement_api" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          command:
+            - /tmp/nova-placement-api.sh
+            - start
+          lifecycle:
+            preStop:
+              exec:
+                command:
+                  - /tmp/nova-placement-api.sh
+                  - stop
+          ports:
+            - name: p-api
+              containerPort: {{ tuple "placement" "internal" "api" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+{{ dict "envAll" $envAll "component" "placement" "container" "default" "type" "liveness" "probeTemplate" (include "novaPlacementLivenessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+{{ dict "envAll" $envAll "component" "placement" "container" "default" "type" "readiness" "probeTemplate" (include "novaPlacementReadinessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: wsgi-nova
+              mountPath: /var/www/cgi-bin/nova
+            - name: nova-bin
+              mountPath: /tmp/nova-placement-api.sh
+              subPath: nova-placement-api.sh
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/nova.conf
+              subPath: nova.conf
+              readOnly: true
+            {{- if .Values.conf.nova.DEFAULT.log_config_append }}
+            - name: nova-etc
+              mountPath: {{ .Values.conf.nova.DEFAULT.log_config_append }}
+              subPath: {{ base .Values.conf.nova.DEFAULT.log_config_append }}
+              readOnly: true
+            {{- end }}
+            - name: nova-etc
+              mountPath: /etc/nova/api-paste.ini
+              subPath: api-paste.ini
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/policy.yaml
+              subPath: policy.yaml
+              readOnly: true
+            - name: nova-etc
+              mountPath: {{ .Values.conf.software.apache2.conf_dir }}/wsgi-nova-placement.conf
+              subPath: wsgi-nova-placement.conf
+              readOnly: true
+{{- if .Values.conf.security }}
+            - name: nova-etc
+              mountPath: {{ .Values.conf.software.apache2.conf_dir }}/security.conf
+              subPath: security.conf
+              readOnly: true
+{{- end }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_db.auth.admin.secret.tls.internal "path" "/etc/mysql/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.placement.placement.internal "path" "/etc/nova/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{ if $mounts_nova_placement.volumeMounts }}{{ toYaml $mounts_nova_placement.volumeMounts | indent 12 }}{{ end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: wsgi-nova
+          emptyDir: {}
+        - name: nova-bin
+          configMap:
+            name: nova-bin
+            defaultMode: 0555
+        - name: nova-etc
+          secret:
+            secretName: nova-etc
+            defaultMode: 0444
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_db.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.placement.placement.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{ if $mounts_nova_placement.volumes }}{{ toYaml $mounts_nova_placement.volumes | indent 8 }}{{ end }}
+{{- end }}
diff --git a/charts/nova/templates/deployment-scheduler.yaml b/charts/nova/templates/deployment-scheduler.yaml
new file mode 100644
index 0000000..b8a465e
--- /dev/null
+++ b/charts/nova/templates/deployment-scheduler.yaml
@@ -0,0 +1,141 @@
+{{/*
+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.
+*/}}
+
+{{- define "novaSchedulerLivenessProbeTemplate" }}
+exec:
+  command:
+    - python
+    - /tmp/health-probe.py
+    - --config-file
+    - /etc/nova/nova.conf
+    - --service-queue-name
+    - scheduler
+    - --liveness-probe
+{{- end }}
+
+{{- define "novaSchedulerReadinessProbeTemplate" }}
+exec:
+  command:
+    - python
+    - /tmp/health-probe.py
+    - --config-file
+    - /etc/nova/nova.conf
+    - --service-queue-name
+    - scheduler
+{{- end }}
+
+{{- if .Values.manifests.deployment_scheduler }}
+{{- $envAll := . }}
+
+{{- $mounts_nova_scheduler := .Values.pod.mounts.nova_scheduler.nova_scheduler }}
+{{- $mounts_nova_scheduler_init := .Values.pod.mounts.nova_scheduler.init_container }}
+
+{{- $serviceAccountName := "nova-scheduler" }}
+{{ tuple $envAll "scheduler" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: nova-scheduler
+  annotations:
+    {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
+  labels:
+{{ tuple $envAll "nova" "scheduler" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+spec:
+  replicas: {{ .Values.pod.replicas.scheduler }}
+  selector:
+    matchLabels:
+{{ tuple $envAll "nova" "scheduler" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }}
+{{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_deployment" | indent 2 }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll "nova" "scheduler" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+      annotations:
+{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+        configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
+        configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ dict "envAll" $envAll "podName" "nova-scheduler" "containerNames" (list "nova-scheduler" "init") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName }}
+{{ dict "envAll" $envAll "application" "nova" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
+      affinity:
+{{ tuple $envAll "nova" "scheduler" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }}
+      nodeSelector:
+        {{ .Values.labels.scheduler.node_selector_key }}: {{ .Values.labels.scheduler.node_selector_value }}
+      initContainers:
+{{ tuple $envAll "scheduler" $mounts_nova_scheduler_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+      containers:
+        - name: nova-scheduler
+{{ tuple $envAll "nova_scheduler" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.scheduler | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_scheduler" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+{{ dict "envAll" $envAll "component" "scheduler" "container" "default" "type" "liveness" "probeTemplate" (include "novaSchedulerLivenessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+{{ dict "envAll" $envAll "component" "scheduler" "container" "default" "type" "readiness" "probeTemplate" (include "novaSchedulerReadinessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+          env:
+            - name: RPC_PROBE_TIMEOUT
+              value: "{{ .Values.pod.probes.rpc_timeout }}"
+            - name: RPC_PROBE_RETRIES
+              value: "{{ .Values.pod.probes.rpc_retries }}"
+{{- if .Values.manifests.certificates }}
+            - name: REQUESTS_CA_BUNDLE
+              value: "/etc/nova/certs/ca.crt"
+{{- end }}
+          command:
+            - /tmp/nova-scheduler.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/nova-scheduler.sh
+              subPath: nova-scheduler.sh
+              readOnly: true
+            - name: nova-bin
+              mountPath: /tmp/health-probe.py
+              subPath: health-probe.py
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/nova.conf
+              subPath: nova.conf
+              readOnly: true
+            {{- if .Values.conf.nova.DEFAULT.log_config_append }}
+            - name: nova-etc
+              mountPath: {{ .Values.conf.nova.DEFAULT.log_config_append }}
+              subPath: {{ base .Values.conf.nova.DEFAULT.log_config_append }}
+              readOnly: true
+            {{- end }}
+            - name: nova-etc
+              mountPath: /etc/nova/policy.yaml
+              subPath: policy.yaml
+              readOnly: true
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal "path" "/etc/mysql/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute.osapi.internal "path" "/etc/nova/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal "path" "/etc/rabbitmq/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{ if $mounts_nova_scheduler.volumeMounts }}{{ toYaml $mounts_nova_scheduler.volumeMounts | indent 12 }}{{ end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: nova-bin
+          configMap:
+            name: nova-bin
+            defaultMode: 0555
+        - name: nova-etc
+          secret:
+            secretName: nova-etc
+            defaultMode: 0444
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute.osapi.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- dict "enabled" $envAll.Values.manifests.certificates "name" $envAll.Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{ if $mounts_nova_scheduler.volumes }}{{ toYaml $mounts_nova_scheduler.volumes | indent 8 }}{{ end }}
+{{- end }}
diff --git a/charts/nova/templates/deployment-spiceproxy.yaml b/charts/nova/templates/deployment-spiceproxy.yaml
new file mode 100644
index 0000000..98046a0
--- /dev/null
+++ b/charts/nova/templates/deployment-spiceproxy.yaml
@@ -0,0 +1,160 @@
+{{/*
+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.
+*/}}
+
+{{- define "novaSpiceproxyLivenessProbeTemplate" }}
+tcpSocket:
+  port: {{ tuple "compute_spice_proxy" "internal" "spice_proxy" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+{{- end }}
+
+{{- define "novaSpiceproxyReadynessProbeTemplate" }}
+tcpSocket:
+  port: {{ tuple "compute_spice_proxy" "internal" "spice_proxy" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+{{- end }}
+
+{{- if and .Values.manifests.deployment_spiceproxy ( eq .Values.console.console_kind "spice" )}}
+{{- $envAll := . }}
+
+{{- $mounts_nova_spiceproxy := .Values.pod.mounts.nova_spiceproxy.nova_spiceproxy }}
+{{- $mounts_nova_spiceproxy_init := .Values.pod.mounts.nova_spiceproxy.init_spiceproxy }}
+
+{{- $serviceAccountName := "nova-spiceproxy" }}
+{{ tuple $envAll "spiceproxy" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: nova-spiceproxy
+  annotations:
+    {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
+  labels:
+{{ tuple $envAll "nova" "spice-proxy" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+spec:
+  replicas: {{ .Values.pod.replicas.spiceproxy }}
+  selector:
+    matchLabels:
+{{ tuple $envAll "nova" "spice-proxy" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }}
+{{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_deployment" | indent 2 }}
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll "nova" "spice-proxy" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+      annotations:
+{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+        configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
+        configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName }}
+{{ dict "envAll" $envAll "application" "nova" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
+      affinity:
+{{ tuple $envAll "nova" "spice-proxy" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }}
+      nodeSelector:
+        {{ .Values.labels.spiceproxy.node_selector_key }}: {{ .Values.labels.spiceproxy.node_selector_value }}
+      hostNetwork: true
+      dnsPolicy: ClusterFirstWithHostNet
+      initContainers:
+{{ tuple $envAll "spiceproxy" $mounts_nova_spiceproxy_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+        - name: nova-spiceproxy-init
+{{ tuple $envAll "nova_spiceproxy" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.spiceproxy | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_spiceproxy_init" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          command:
+            - /tmp/nova-console-proxy-init.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/nova-console-proxy-init.sh
+              subPath: nova-console-proxy-init.sh
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/nova.conf
+              subPath: nova.conf
+              readOnly: true
+            {{- if .Values.conf.nova.DEFAULT.log_config_append }}
+            - name: nova-etc
+              mountPath: {{ .Values.conf.nova.DEFAULT.log_config_append }}
+              subPath: {{ base .Values.conf.nova.DEFAULT.log_config_append }}
+              readOnly: true
+            {{- end }}
+            - name: pod-shared
+              mountPath: /tmp/pod-shared
+        - name: nova-spiceproxy-init-assets
+{{ tuple $envAll "nova_spiceproxy_assets" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.spiceproxy | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_spiceproxy_init_assets" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          command:
+            - /tmp/nova-console-proxy-init-assets.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/nova-console-proxy-init-assets.sh
+              subPath: nova-console-proxy-init-assets.sh
+              readOnly: true
+            - name: pod-usr-share-spice-html5
+              mountPath: /tmp/usr/share/spice-html5
+      containers:
+        - name: nova-spiceproxy
+{{ tuple $envAll "nova_spiceproxy" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.spiceproxy | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova" "container" "nova_spiceproxy" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+{{ dict "envAll" $envAll "component" "compute-spice-proxy" "container" "default" "type" "liveness" "probeTemplate" (include "novaSpiceproxyLivenessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+{{ dict "envAll" $envAll "component" "compute-spice-proxy" "container" "default" "type" "readiness" "probeTemplate" (include "novaSpiceproxyReadinessProbeTemplate" $envAll | fromYaml) | include "helm-toolkit.snippets.kubernetes_probe" | indent 10 }}
+          command:
+            - /tmp/nova-console-proxy.sh
+          ports:
+            - name: n-spice
+              containerPort: {{ tuple "compute_spice_proxy" "internal" "spice_proxy" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/nova-console-proxy.sh
+              subPath: nova-console-proxy.sh
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/nova.conf
+              subPath: nova.conf
+              readOnly: true
+            {{- if .Values.conf.nova.DEFAULT.log_config_append }}
+            - name: nova-etc
+              mountPath: {{ .Values.conf.nova.DEFAULT.log_config_append }}
+              subPath: {{ base .Values.conf.nova.DEFAULT.log_config_append }}
+              readOnly: true
+            {{- end }}
+            - name: pod-usr-share-spice-html5
+              mountPath: /usr/share/spice-html5
+              readOnly: true
+            - name: pod-shared
+              mountPath: /tmp/pod-shared
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute_spice_proxy.spiceproxy.internal "path" "/etc/nova/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+{{ if $mounts_nova_spiceproxy.volumeMounts }}{{ toYaml $mounts_nova_spiceproxy.volumeMounts | indent 12 }}{{ end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: nova-bin
+          configMap:
+            name: nova-bin
+            defaultMode: 0555
+        - name: nova-etc
+          secret:
+            secretName: nova-etc
+            defaultMode: 0444
+        - name: pod-usr-share-spice-html5
+          emptyDir: {}
+        - name: pod-shared
+          emptyDir: {}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute_spice_proxy.spiceproxy.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{ if $mounts_nova_spiceproxy.volumes }}{{ toYaml $mounts_nova_spiceproxy.volumes | indent 8 }}{{ end }}
+{{- end }}
diff --git a/charts/nova/templates/ingress-metadata.yaml b/charts/nova/templates/ingress-metadata.yaml
new file mode 100644
index 0000000..36eb864
--- /dev/null
+++ b/charts/nova/templates/ingress-metadata.yaml
@@ -0,0 +1,23 @@
+{{/*
+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.
+*/}}
+
+{{- if and .Values.manifests.ingress_metadata .Values.network.metadata.ingress.public }}
+{{- $envAll := . -}}
+{{- $ingressOpts := dict "envAll" $envAll "backendService" "metadata" "backendServiceType" "compute_metadata" "backendPort" "n-meta" -}}
+{{- $secretName := $envAll.Values.secrets.tls.compute_metadata.metadata.internal -}}
+{{- if and .Values.manifests.certificates $secretName }}
+{{- $_ := set $ingressOpts "certIssuer" .Values.endpoints.compute_metadata.host_fqdn_override.default.tls.issuerRef.name -}}
+{{- end -}}
+{{ $ingressOpts | include "helm-toolkit.manifests.ingress" }}
+{{- end }}
diff --git a/charts/nova/templates/ingress-novncproxy.yaml b/charts/nova/templates/ingress-novncproxy.yaml
new file mode 100644
index 0000000..cad53cf
--- /dev/null
+++ b/charts/nova/templates/ingress-novncproxy.yaml
@@ -0,0 +1,23 @@
+{{/*
+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.
+*/}}
+
+{{- if and .Values.manifests.ingress_novncproxy .Values.network.novncproxy.ingress.public }}
+{{- $envAll := . }}
+{{- $ingressOpts := dict "envAll" $envAll "backendService" "novncproxy" "backendServiceType" "compute_novnc_proxy" "backendPort" "n-novnc" -}}
+{{- $secretName := $envAll.Values.secrets.tls.compute_novnc_proxy.novncproxy.internal -}}
+{{- if and .Values.manifests.certificates $secretName }}
+{{- $_ := set $ingressOpts "certIssuer" .Values.endpoints.compute_novnc_proxy.host_fqdn_override.default.tls.issuerRef.name -}}
+{{- end }}
+{{ $ingressOpts | include "helm-toolkit.manifests.ingress" }}
+{{- end }}
diff --git a/charts/nova/templates/ingress-osapi.yaml b/charts/nova/templates/ingress-osapi.yaml
new file mode 100644
index 0000000..b78f80f
--- /dev/null
+++ b/charts/nova/templates/ingress-osapi.yaml
@@ -0,0 +1,23 @@
+{{/*
+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.
+*/}}
+
+{{- if and .Values.manifests.ingress_osapi .Values.network.osapi.ingress.public }}
+{{- $envAll := . -}}
+{{- $ingressOpts := dict "envAll" $envAll "backendService" "osapi" "backendServiceType" "compute" "backendPort" "n-api" -}}
+{{- $secretName := $envAll.Values.secrets.tls.compute.osapi.internal -}}
+{{- if and .Values.manifests.certificates $secretName }}
+{{- $_ := set $ingressOpts "certIssuer" .Values.endpoints.compute.host_fqdn_override.default.tls.issuerRef.name -}}
+{{- end }}
+{{ $ingressOpts | include "helm-toolkit.manifests.ingress" }}
+{{- end }}
diff --git a/charts/nova/templates/ingress-placement.yaml b/charts/nova/templates/ingress-placement.yaml
new file mode 100644
index 0000000..28b0f0d
--- /dev/null
+++ b/charts/nova/templates/ingress-placement.yaml
@@ -0,0 +1,23 @@
+{{/*
+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.
+*/}}
+
+{{- if and .Values.manifests.ingress_placement .Values.network.placement.ingress.public }}
+{{- $envAll := . -}}
+{{- $ingressOpts := dict "envAll" $envAll "backendService" "placement" "backendServiceType" "placement" "backendPort" "p-api" -}}
+{{- $secretName := $envAll.Values.secrets.tls.placement.placement.internal -}}
+{{- if and .Values.manifests.certificates $secretName }}
+{{- $_ := set $ingressOpts "certIssuer" .Values.endpoints.placement.host_fqdn_override.default.tls.issuerRef.name -}}
+{{- end }}
+{{ $ingressOpts | include "helm-toolkit.manifests.ingress" }}
+{{- end }}
diff --git a/charts/nova/templates/job-bootstrap.yaml b/charts/nova/templates/job-bootstrap.yaml
new file mode 100644
index 0000000..c105f56
--- /dev/null
+++ b/charts/nova/templates/job-bootstrap.yaml
@@ -0,0 +1,140 @@
+{{/*
+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.
+*/}}
+
+{{- $envAll := . }}
+{{- if and $envAll.Values.manifests.job_bootstrap $envAll.Values.bootstrap.enabled }}
+{{- $serviceName := "nova" -}}
+{{- $keystoneUser := $envAll.Values.bootstrap.ks_user -}}
+{{- $configMapBin := printf "%s-%s" $serviceName "bin" -}}
+{{- $configMapEtc := printf "%s-%s" $serviceName "etc" -}}
+{{- $configFile := printf "/etc/%s/%s.conf" $serviceName $serviceName -}}
+{{- $logConfigFile := $envAll.Values.conf.nova.DEFAULT.log_config_append -}}
+{{- $nodeSelector := index . "nodeSelector" | default ( dict $envAll.Values.labels.job.node_selector_key $envAll.Values.labels.job.node_selector_value ) -}}
+{{- $serviceAccountName := printf "%s-%s" $serviceName "bootstrap" -}}
+{{ tuple $envAll "bootstrap" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: {{ $serviceAccountName | quote }}
+  labels:
+{{ tuple $envAll "nova" "bootstrap" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+spec:
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll "nova" "bootstrap" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+      annotations:
+{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+    spec:
+{{ dict "envAll" $envAll "application" "bootstrap" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
+      serviceAccountName: {{ $serviceAccountName }}
+      restartPolicy: OnFailure
+      nodeSelector:
+{{ toYaml $nodeSelector | indent 8 }}
+      initContainers:
+{{ tuple $envAll "bootstrap" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container"  | indent 8 }}
+{{- if $envAll.Values.bootstrap.wait_for_computes.enabled }}
+        - name: nova-wait-for-computes-init
+{{ tuple $envAll "nova_wait_for_computes_init" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ dict "envAll" $envAll "application" "bootstrap" "container" "nova_wait_for_computes_init" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          command:
+            - /bin/bash
+            - -c
+            - /tmp/wait-for-computes-init.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: bootstrap-sh
+              mountPath: /tmp/wait-for-computes-init.sh
+              subPath: wait-for-computes-init.sh
+              readOnly: true
+{{- end }}
+      containers:
+        - name: bootstrap
+          image: {{ $envAll.Values.images.tags.bootstrap }}
+          imagePullPolicy: {{ $envAll.Values.images.pull_policy }}
+{{ tuple $envAll $envAll.Values.pod.resources.jobs.bootstrap | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "bootstrap" "container" "bootstrap" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          env:
+{{- with $env := dict "ksUserSecret" ( index $envAll.Values.secrets.identity $keystoneUser ) "useCA" .Values.manifests.certificates }}
+{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 12 }}
+{{- end }}
+            - name: WAIT_PERCENTAGE
+              value: "{{ .Values.bootstrap.wait_for_computes.wait_percentage }}"
+            - name: REMAINING_WAIT
+              value: "{{ .Values.bootstrap.wait_for_computes.remaining_wait }}"
+          command:
+            - /bin/bash
+            - -c
+            - /tmp/bootstrap.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: bootstrap-sh
+              mountPath: /tmp/bootstrap.sh
+              subPath: bootstrap.sh
+              readOnly: true
+            - name: etc-service
+              mountPath: {{ dir $configFile | quote }}
+            - name: bootstrap-conf
+              mountPath: {{ $configFile | quote }}
+              subPath: {{ base $configFile | quote }}
+              readOnly: true
+            - name: bootstrap-conf
+              mountPath: {{ $logConfigFile | quote }}
+              subPath: {{ base $logConfigFile | quote }}
+              readOnly: true
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute.osapi.internal | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: bootstrap-sh
+          configMap:
+            name: {{ $configMapBin | quote }}
+            defaultMode: 0555
+        - name: etc-service
+          emptyDir: {}
+        - name: bootstrap-conf
+          secret:
+            secretName: {{ $configMapEtc | quote }}
+            defaultMode: 0444
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute.osapi.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+---
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: {{ $serviceAccountName }}
+rules:
+  - apiGroups:
+      - ''
+    resources:
+      - nodes
+    verbs:
+      - get
+      - list
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: {{ $serviceAccountName }}
+subjects:
+  - kind: ServiceAccount
+    name: {{ $serviceAccountName }}
+    namespace: {{ $envAll.Release.Namespace }}
+roleRef:
+  kind: ClusterRole
+  name: {{ $serviceAccountName }}
+  apiGroup: rbac.authorization.k8s.io
+{{- end }}
diff --git a/charts/nova/templates/job-cell-setup.yaml b/charts/nova/templates/job-cell-setup.yaml
new file mode 100644
index 0000000..cdcdf25
--- /dev/null
+++ b/charts/nova/templates/job-cell-setup.yaml
@@ -0,0 +1,149 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.job_cell_setup }}
+{{- $envAll := . }}
+
+{{- $serviceAccountName := "nova-cell-setup" }}
+{{ tuple $envAll "cell_setup" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: nova-cell-setup
+  labels:
+{{ tuple $envAll "nova" "cell-setup" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+  annotations:
+    {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
+spec:
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll "nova" "cell-setup" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+      annotations:
+{{ dict "envAll" $envAll "podName" "nova-cell-setup" "containerNames" (list "nova-cell-setup-init" "nova-cell-setup" "init") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName }}
+      restartPolicy: OnFailure
+      nodeSelector:
+        {{ .Values.labels.job.node_selector_key }}: {{ .Values.labels.job.node_selector_value }}
+      initContainers:
+{{ tuple $envAll "cell_setup" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+{{- if $envAll.Values.bootstrap.wait_for_computes.enabled }}
+        - name: nova-wait-for-computes-init
+{{ tuple $envAll "nova_wait_for_computes_init" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ dict "envAll" $envAll "application" "bootstrap" "container" "nova_wait_for_computes_init" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          command:
+            - /bin/bash
+            - -c
+            - /tmp/wait-for-computes-init.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/wait-for-computes-init.sh
+              subPath: wait-for-computes-init.sh
+              readOnly: true
+{{- end }}
+        - name: nova-cell-setup-init
+{{ tuple $envAll "nova_cell_setup_init" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.jobs.cell_setup | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova_cell_setup" "container" "nova_cell_setup_init" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          env:
+{{- with $env := dict "ksUserSecret" $envAll.Values.secrets.identity.admin "useCA" .Values.manifests.certificates }}
+{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 12 }}
+{{- end }}
+          command:
+            - /tmp/cell-setup-init.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/cell-setup-init.sh
+              subPath: cell-setup-init.sh
+              readOnly: true
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute.osapi.internal (tuple "ca.crt") | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+      containers:
+        - name: nova-cell-setup
+{{ tuple $envAll "nova_cell_setup" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.jobs.cell_setup | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+{{ dict "envAll" $envAll "application" "nova_cell_setup" "container" "nova_cell_setup" | include "helm-toolkit.snippets.kubernetes_container_security_context" | indent 10 }}
+          command:
+            - /tmp/cell-setup.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/cell-setup.sh
+              subPath: cell-setup.sh
+              readOnly: true
+            - name: etcnova
+              mountPath: /etc/nova
+            - name: nova-etc
+              mountPath: /etc/nova/nova.conf
+              subPath: nova.conf
+              readOnly: true
+            {{- if .Values.conf.nova.DEFAULT.log_config_append }}
+            - name: nova-etc
+              mountPath: {{ .Values.conf.nova.DEFAULT.log_config_append }}
+              subPath: {{ base .Values.conf.nova.DEFAULT.log_config_append }}
+              readOnly: true
+            {{- end }}
+            - name: nova-etc
+              mountPath: /etc/nova/policy.yaml
+              subPath: policy.yaml
+              readOnly: true
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal "path" "/etc/mysql/certs" | include "helm-toolkit.snippets.tls_volume_mount" | indent 12 }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: etcnova
+          emptyDir: {}
+        - name: nova-etc
+          secret:
+            secretName: nova-etc
+            defaultMode: 0444
+        - name: nova-bin
+          configMap:
+            name: nova-bin
+            defaultMode: 0555
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+{{- dict "enabled" .Values.manifests.certificates "name" .Values.secrets.tls.compute.osapi.internal | include "helm-toolkit.snippets.tls_volume" | indent 8 }}
+---
+kind: ClusterRole
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: {{ $serviceAccountName }}
+rules:
+  - apiGroups:
+      - ''
+    resources:
+      - nodes
+    verbs:
+      - get
+      - list
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: {{ $serviceAccountName }}
+subjects:
+  - kind: ServiceAccount
+    name: {{ $serviceAccountName }}
+    namespace: {{ $envAll.Release.Namespace }}
+roleRef:
+  kind: ClusterRole
+  name: {{ $serviceAccountName }}
+  apiGroup: rbac.authorization.k8s.io
+{{- end }}
diff --git a/charts/nova/templates/job-db-drop.yaml b/charts/nova/templates/job-db-drop.yaml
new file mode 100644
index 0000000..9a6b1a0
--- /dev/null
+++ b/charts/nova/templates/job-db-drop.yaml
@@ -0,0 +1,26 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.job_db_drop }}
+{{- $serviceName := "nova" -}}
+{{- $dbSvc := dict "adminSecret" .Values.secrets.oslo_db.admin "configFile" (printf "/etc/%s/%s.conf" $serviceName $serviceName ) "logConfigFile" (printf "/etc/%s/logging.conf" $serviceName ) "configDbSection" "database" "configDbKey" "connection" -}}
+{{- $dbApi := dict "adminSecret" .Values.secrets.oslo_db.admin "configFile" (printf "/etc/%s/%s.conf" $serviceName $serviceName ) "logConfigFile" (printf "/etc/%s/logging.conf" $serviceName ) "configDbSection" "api_database" "configDbKey" "connection" -}}
+{{- $dbCell := dict "adminSecret" .Values.secrets.oslo_db.admin "configFile" (printf "/etc/%s/%s.conf" $serviceName $serviceName ) "logConfigFile" (printf "/etc/%s/logging.conf" $serviceName ) "configDbSection" "cell0_database" "configDbKey" "connection" -}}
+{{- $dbsToDrop := list $dbSvc $dbApi $dbCell }}
+{{- $dbDropJob := dict "envAll" . "serviceName" $serviceName "dbsToDrop" $dbsToDrop -}}
+{{- if .Values.manifests.certificates -}}
+{{- $_ := set $dbDropJob "dbAdminTlsSecret" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal -}}
+{{- end -}}
+{{ $dbDropJob | include "helm-toolkit.manifests.job_db_drop_mysql" }}
+{{- end }}
diff --git a/charts/nova/templates/job-db-init.yaml b/charts/nova/templates/job-db-init.yaml
new file mode 100644
index 0000000..b1ca870
--- /dev/null
+++ b/charts/nova/templates/job-db-init.yaml
@@ -0,0 +1,34 @@
+{{/*
+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.
+*/}}
+
+{{- define "metadata.annotations.job.db_init" }}
+helm.sh/hook: post-install,post-upgrade
+helm.sh/hook-weight: "-5"
+{{- end }}
+
+{{- if .Values.manifests.job_db_init }}
+{{- $serviceName := "nova" -}}
+{{- $dbSvc := dict "adminSecret" .Values.secrets.oslo_db.admin "configFile" (printf "/etc/%s/%s.conf" $serviceName $serviceName ) "logConfigFile" (printf "/etc/%s/logging.conf" $serviceName ) "configDbSection" "database" "configDbKey" "connection" -}}
+{{- $dbApi := dict "adminSecret" .Values.secrets.oslo_db.admin "configFile" (printf "/etc/%s/%s.conf" $serviceName $serviceName ) "logConfigFile" (printf "/etc/%s/logging.conf" $serviceName ) "configDbSection" "api_database" "configDbKey" "connection" -}}
+{{- $dbCell := dict "adminSecret" .Values.secrets.oslo_db.admin "configFile" (printf "/etc/%s/%s.conf" $serviceName $serviceName ) "logConfigFile" (printf "/etc/%s/logging.conf" $serviceName ) "configDbSection" "cell0_database" "configDbKey" "connection" -}}
+{{- $dbsToInit := list $dbSvc $dbApi $dbCell }}
+{{- $dbInitJob := dict "envAll" . "serviceName" $serviceName "dbsToInit" $dbsToInit -}}
+{{- if .Values.manifests.certificates -}}
+{{- $_ := set $dbInitJob "dbAdminTlsSecret" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal -}}
+{{- end -}}
+{{- if .Values.helm3_hook }}
+{{- $_ := set $dbInitJob "jobAnnotations" (include "metadata.annotations.job.db_init" . | fromYaml) }}
+{{- end }}
+{{ $dbInitJob | include "helm-toolkit.manifests.job_db_init_mysql" }}
+{{- end }}
diff --git a/charts/nova/templates/job-db-sync.yaml b/charts/nova/templates/job-db-sync.yaml
new file mode 100644
index 0000000..3cd8cac
--- /dev/null
+++ b/charts/nova/templates/job-db-sync.yaml
@@ -0,0 +1,50 @@
+{{/*
+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.
+*/}}
+
+{{- define "metadata.annotations.job.db_sync" }}
+helm.sh/hook: post-install,post-upgrade
+helm.sh/hook-weight: "-4"
+{{- end }}
+
+{{- define "nova.templates._job_db_sync.env_vars" -}}
+{{- $envAll := index . 0 }}
+env:
+  - name: TRANSPORT_URL
+    valueFrom:
+      secretKeyRef:
+        name: {{ $envAll.Values.secrets.oslo_messaging.nova }}
+        key: TRANSPORT_URL
+  - name: DB_CONNECTION
+    valueFrom:
+      secretKeyRef:
+        name: {{ $envAll.Values.secrets.oslo_db.nova }}
+        key: DB_CONNECTION
+  - name: DB_CONNECTION_CELL0
+    valueFrom:
+      secretKeyRef:
+        name: {{ $envAll.Values.secrets.oslo_db_cell0.nova }}
+        key: DB_CONNECTION
+{{- end }}
+
+{{- if .Values.manifests.job_db_sync }}
+{{- $podEnvVars := include "nova.templates._job_db_sync.env_vars" (tuple .) | toString | fromYaml }}
+{{- $dbSyncJob := dict "envAll" . "serviceName" "nova" "podVolMounts" .Values.pod.mounts.nova_db_sync.nova_db_sync.volumeMounts "podVols" .Values.pod.mounts.nova_db_sync.nova_db_sync.volumes "podEnvVars" $podEnvVars.env -}}
+{{- if .Values.manifests.certificates -}}
+{{- $_ := set $dbSyncJob "dbAdminTlsSecret" .Values.endpoints.oslo_db.auth.admin.secret.tls.internal -}}
+{{- end -}}
+{{- if .Values.helm3_hook }}
+{{- $_ := set $dbSyncJob "jobAnnotations" (include "metadata.annotations.job.db_sync" . | fromYaml) }}
+{{- end }}
+{{ $dbSyncJob | include "helm-toolkit.manifests.job_db_sync" }}
+{{- end }}
diff --git a/charts/nova/templates/job-image-repo-sync.yaml b/charts/nova/templates/job-image-repo-sync.yaml
new file mode 100644
index 0000000..fe488dd
--- /dev/null
+++ b/charts/nova/templates/job-image-repo-sync.yaml
@@ -0,0 +1,25 @@
+{{/*
+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.
+*/}}
+
+{{- define "metadata.annotations.job.repo_sync" }}
+helm.sh/hook: post-install,post-upgrade
+{{- end }}
+
+{{- if and .Values.manifests.job_image_repo_sync .Values.images.local_registry.active }}
+{{- $imageRepoSyncJob := dict "envAll" . "serviceName" "nova" -}}
+{{- if .Values.helm3_hook }}
+{{- $_ := set $imageRepoSyncJob "jobAnnotations" (include "metadata.annotations.job.repo_sync" . | fromYaml) }}
+{{- end }}
+{{ $imageRepoSyncJob | include "helm-toolkit.manifests.job_image_repo_sync" }}
+{{- end }}
diff --git a/charts/nova/templates/job-ks-endpoints.yaml b/charts/nova/templates/job-ks-endpoints.yaml
new file mode 100644
index 0000000..5057ebc
--- /dev/null
+++ b/charts/nova/templates/job-ks-endpoints.yaml
@@ -0,0 +1,29 @@
+{{/*
+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.
+*/}}
+
+{{- define "metadata.annotations.job.ks_endpoints" }}
+helm.sh/hook: post-install,post-upgrade
+helm.sh/hook-weight: "-2"
+{{- end }}
+
+{{- if .Values.manifests.job_ks_endpoints }}
+{{- $ksServiceJob := dict "envAll" . "serviceName" "nova" "serviceTypes" ( tuple "compute" ) -}}
+{{- if .Values.manifests.certificates -}}
+{{- $_ := set $ksServiceJob "tlsSecret" .Values.secrets.tls.compute.osapi.internal -}}
+{{- end -}}
+{{- if .Values.helm3_hook }}
+{{- $_ := set $ksServiceJob "jobAnnotations" (include "metadata.annotations.job.ks_endpoints" . | fromYaml) }}
+{{- end }}
+{{ $ksServiceJob | include "helm-toolkit.manifests.job_ks_endpoints" }}
+{{- end }}
diff --git a/charts/nova/templates/job-ks-placement-endpoints.yaml b/charts/nova/templates/job-ks-placement-endpoints.yaml
new file mode 100644
index 0000000..2147f3c
--- /dev/null
+++ b/charts/nova/templates/job-ks-placement-endpoints.yaml
@@ -0,0 +1,21 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.job_ks_placement_endpoints }}
+{{- $ksServiceJob := dict "envAll" . "serviceName" "placement" "configMapBin" "nova-bin" "serviceTypes" ( tuple "placement" ) -}}
+{{- if .Values.manifests.certificates -}}
+{{- $_ := set $ksServiceJob "tlsSecret" .Values.secrets.tls.placement.placement.internal -}}
+{{- end -}}
+{{ $ksServiceJob | include "helm-toolkit.manifests.job_ks_endpoints" }}
+{{- end }}
diff --git a/charts/nova/templates/job-ks-placement-service.yaml b/charts/nova/templates/job-ks-placement-service.yaml
new file mode 100644
index 0000000..c2c8865
--- /dev/null
+++ b/charts/nova/templates/job-ks-placement-service.yaml
@@ -0,0 +1,21 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.job_ks_placement_service }}
+{{- $ksServiceJob := dict "envAll" . "serviceName" "placement" "configMapBin" "nova-bin" "serviceTypes" ( tuple "placement" ) -}}
+{{- if .Values.manifests.certificates -}}
+{{- $_ := set $ksServiceJob "tlsSecret" .Values.secrets.tls.placement.placement.internal -}}
+{{- end -}}
+{{ $ksServiceJob | include "helm-toolkit.manifests.job_ks_service" }}
+{{- end }}
diff --git a/charts/nova/templates/job-ks-placement-user.yaml b/charts/nova/templates/job-ks-placement-user.yaml
new file mode 100644
index 0000000..035c2f0
--- /dev/null
+++ b/charts/nova/templates/job-ks-placement-user.yaml
@@ -0,0 +1,21 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.job_ks_placement_user }}
+{{- $ksUserJob := dict "envAll" . "serviceName" "placement" "serviceUser" "placement" "configMapBin" "nova-bin" -}}
+{{- if .Values.manifests.certificates -}}
+{{- $_ := set $ksUserJob "tlsSecret" .Values.secrets.tls.placement.placement.internal -}}
+{{- end -}}
+{{ $ksUserJob | include "helm-toolkit.manifests.job_ks_user" }}
+{{- end }}
diff --git a/charts/nova/templates/job-ks-service.yaml b/charts/nova/templates/job-ks-service.yaml
new file mode 100644
index 0000000..d9eb3b5
--- /dev/null
+++ b/charts/nova/templates/job-ks-service.yaml
@@ -0,0 +1,29 @@
+{{/*
+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.
+*/}}
+
+{{- define "metadata.annotations.job.ks_service" }}
+helm.sh/hook: post-install,post-upgrade
+helm.sh/hook-weight: "-3"
+{{- end }}
+
+{{- if .Values.manifests.job_ks_service }}
+{{- $ksServiceJob := dict "envAll" . "serviceName" "nova" "serviceTypes" ( tuple "compute" ) -}}
+{{- if .Values.manifests.certificates -}}
+{{- $_ := set $ksServiceJob "tlsSecret" .Values.secrets.tls.compute.osapi.internal -}}
+{{- end -}}
+{{- if .Values.helm3_hook }}
+{{- $_ := set $ksServiceJob "jobAnnotations" (include "metadata.annotations.job.ks_service" . | fromYaml) }}
+{{- end }}
+{{ $ksServiceJob | include "helm-toolkit.manifests.job_ks_service" }}
+{{- end }}
diff --git a/charts/nova/templates/job-ks-user.yaml b/charts/nova/templates/job-ks-user.yaml
new file mode 100644
index 0000000..e5613cc
--- /dev/null
+++ b/charts/nova/templates/job-ks-user.yaml
@@ -0,0 +1,29 @@
+{{/*
+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.
+*/}}
+
+{{- define "metadata.annotations.job.ks_user" }}
+helm.sh/hook: post-install,post-upgrade
+helm.sh/hook-weight: "-1"
+{{- end }}
+
+{{- if .Values.manifests.job_ks_user }}
+{{- $ksUserJob := dict "envAll" . "serviceName" "nova" -}}
+{{- if .Values.manifests.certificates -}}
+{{- $_ := set $ksUserJob "tlsSecret" .Values.secrets.tls.compute.osapi.internal -}}
+{{- end -}}
+{{- if .Values.helm3_hook }}
+{{- $_ := set $ksUserJob "jobAnnotations" (include "metadata.annotations.job.ks_user" . | fromYaml) -}}
+{{- end }}
+{{ $ksUserJob | include "helm-toolkit.manifests.job_ks_user" }}
+{{- end }}
diff --git a/charts/nova/templates/job-rabbit-init.yaml b/charts/nova/templates/job-rabbit-init.yaml
new file mode 100644
index 0000000..ffbb270
--- /dev/null
+++ b/charts/nova/templates/job-rabbit-init.yaml
@@ -0,0 +1,29 @@
+{{/*
+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.
+*/}}
+
+{{- define "metadata.annotations.job.rabbit_init" }}
+helm.sh/hook: post-install,post-upgrade
+helm.sh/hook-weight: "-4"
+{{- end }}
+
+{{- if .Values.manifests.job_rabbit_init }}
+{{- $rmqUserJob := dict "envAll" . "serviceName" "nova" -}}
+{{- if .Values.manifests.certificates -}}
+{{- $_ := set $rmqUserJob "tlsSecret" .Values.endpoints.oslo_messaging.auth.admin.secret.tls.internal -}}
+{{- end -}}
+{{- if .Values.helm3_hook }}
+{{- $_ := set $rmqUserJob "jobAnnotations" (include "metadata.annotations.job.rabbit_init" . | fromYaml) }}
+{{- end }}
+{{ $rmqUserJob | include "helm-toolkit.manifests.job_rabbit_init" }}
+{{- end }}
diff --git a/charts/nova/templates/netpol-nova.yaml b/charts/nova/templates/netpol-nova.yaml
new file mode 100644
index 0000000..4939aca
--- /dev/null
+++ b/charts/nova/templates/netpol-nova.yaml
@@ -0,0 +1,20 @@
+{{/*
+Copyright 2017-2018 The Openstack-Helm Authors.
+
+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.
+*/}}
+
+{{- if .Values.manifests.network_policy -}}
+{{- $netpol_opts := dict "envAll" . "name" "application" "label" "nova" }}
+{{ $netpol_opts | include "helm-toolkit.manifests.kubernetes_network_policy" }}
+{{- end -}}
diff --git a/charts/nova/templates/netpol-placement.yaml b/charts/nova/templates/netpol-placement.yaml
new file mode 100644
index 0000000..18feb04
--- /dev/null
+++ b/charts/nova/templates/netpol-placement.yaml
@@ -0,0 +1,20 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.network_policy -}}
+{{- if .Values.manifests.deployment_placement -}}
+{{- $netpol_opts := dict "envAll" . "name" "application" "label" "placement" }}
+{{ $netpol_opts | include "helm-toolkit.manifests.kubernetes_network_policy" }}
+{{- end -}}
+{{- end -}}
diff --git a/charts/nova/templates/pdb-metadata.yaml b/charts/nova/templates/pdb-metadata.yaml
new file mode 100644
index 0000000..6fba271
--- /dev/null
+++ b/charts/nova/templates/pdb-metadata.yaml
@@ -0,0 +1,27 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.pdb_metadata }}
+{{- $envAll := . }}
+---
+apiVersion: policy/v1beta1
+kind: PodDisruptionBudget
+metadata:
+  name: nova-api-metadata
+spec:
+  minAvailable: {{ .Values.pod.lifecycle.disruption_budget.metadata.min_available }}
+  selector:
+    matchLabels:
+{{ tuple $envAll "nova" "metadata" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }}
+{{- end }}
diff --git a/charts/nova/templates/pdb-osapi.yaml b/charts/nova/templates/pdb-osapi.yaml
new file mode 100644
index 0000000..81971d1
--- /dev/null
+++ b/charts/nova/templates/pdb-osapi.yaml
@@ -0,0 +1,27 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.pdb_osapi }}
+{{- $envAll := . }}
+---
+apiVersion: policy/v1beta1
+kind: PodDisruptionBudget
+metadata:
+  name: nova-api-osapi
+spec:
+  minAvailable: {{ .Values.pod.lifecycle.disruption_budget.osapi.min_available }}
+  selector:
+    matchLabels:
+{{ tuple $envAll "nova" "os-api" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }}
+{{- end }}
diff --git a/charts/nova/templates/pdb-placement.yaml b/charts/nova/templates/pdb-placement.yaml
new file mode 100644
index 0000000..db7e1c7
--- /dev/null
+++ b/charts/nova/templates/pdb-placement.yaml
@@ -0,0 +1,27 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.pdb_placement }}
+{{- $envAll := . }}
+---
+apiVersion: policy/v1beta1
+kind: PodDisruptionBudget
+metadata:
+  name: nova-placement-api
+spec:
+  minAvailable: {{ .Values.pod.lifecycle.disruption_budget.placement.min_available }}
+  selector:
+    matchLabels:
+{{ tuple $envAll "nova" "placement" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }}
+{{- end }}
diff --git a/charts/nova/templates/pod-rally-test.yaml b/charts/nova/templates/pod-rally-test.yaml
new file mode 100644
index 0000000..eabe8b6
--- /dev/null
+++ b/charts/nova/templates/pod-rally-test.yaml
@@ -0,0 +1,110 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.pod_rally_test }}
+{{- $envAll := . }}
+
+{{- $mounts_tests := .Values.pod.mounts.nova_tests.nova_tests }}
+{{- $mounts_tests_init := .Values.pod.mounts.nova_tests.init_container }}
+
+{{- $serviceAccountName := print $envAll.Release.Name "-test" }}
+{{ tuple $envAll "tests" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: v1
+kind: Pod
+metadata:
+  name: {{ print $envAll.Release.Name "-test" }}
+  labels:
+{{ tuple $envAll "nova" "test" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+  annotations:
+    "helm.sh/hook": test-success
+    {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
+{{ dict "envAll" $envAll "podName" "nova-test" "containerNames" (list "init" "nova-test" "nova-test-ks-user") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 4 }}
+spec:
+  nodeSelector:
+    {{ .Values.labels.test.node_selector_key }}: {{ .Values.labels.test.node_selector_value }}
+  restartPolicy: Never
+  serviceAccountName: {{ $serviceAccountName }}
+  initContainers:
+{{ tuple $envAll "tests" $mounts_tests_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 4 }}
+    - name: nova-test-ks-user
+{{ tuple $envAll "ks_user" | include "helm-toolkit.snippets.image" | indent 6 }}
+{{ tuple $envAll $envAll.Values.pod.resources.jobs.ks_user | include "helm-toolkit.snippets.kubernetes_resources" | indent 6 }}
+      command:
+        - /tmp/ks-user.sh
+      volumeMounts:
+        - name: pod-tmp
+          mountPath: /tmp
+        - name: nova-bin
+          mountPath: /tmp/ks-user.sh
+          subPath: ks-user.sh
+          readOnly: true
+{{ dict "enabled" .Values.manifests.certificates "name"  .Values.secrets.tls.compute.osapi.internal | include "helm-toolkit.snippets.tls_volume_mount" | indent 8 }}
+      env:
+{{- with $env := dict "ksUserSecret" .Values.secrets.identity.admin "useCA" .Values.manifests.certificates }}
+{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 8 }}
+{{- end }}
+        - name: SERVICE_OS_SERVICE_NAME
+          value: "test"
+{{- with $env := dict "ksUserSecret" .Values.secrets.identity.test }}
+{{- include "helm-toolkit.snippets.keystone_user_create_env_vars" $env | indent 8 }}
+{{- end }}
+        - name: SERVICE_OS_ROLE
+          value: {{ .Values.endpoints.identity.auth.test.role | quote }}
+  containers:
+    - name: nova-test
+{{ tuple $envAll "test" | include "helm-toolkit.snippets.image" | indent 6 }}
+{{ tuple $envAll $envAll.Values.pod.resources.jobs.tests | include "helm-toolkit.snippets.kubernetes_resources" | indent 6 }}
+      env:
+{{- with $env := dict "ksUserSecret" .Values.secrets.identity.admin "useCA" .Values.manifests.certificates}}
+{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 8 }}
+{{- end }}
+{{- with $env := dict "ksUserSecret" .Values.secrets.identity.test }}
+{{- include "helm-toolkit.snippets.keystone_user_create_env_vars" $env | indent 8 }}
+{{- end }}
+        - name: RALLY_ENV_NAME
+          value: {{.Release.Name}}
+      command:
+        - /tmp/rally-test.sh
+      volumeMounts:
+        - name: pod-tmp
+          mountPath: /tmp
+        - name: nova-etc
+          mountPath: /etc/rally/rally_tests.yaml
+          subPath: rally_tests.yaml
+          readOnly: true
+        - name: nova-bin
+          mountPath: /tmp/rally-test.sh
+          subPath: rally-test.sh
+          readOnly: true
+        - name: rally-db
+          mountPath: /var/lib/rally
+{{ dict "enabled" .Values.manifests.certificates "name"  .Values.secrets.tls.compute.osapi.internal | include "helm-toolkit.snippets.tls_volume_mount" | indent 8 }}
+{{ if $mounts_tests.volumeMounts }}{{ toYaml $mounts_tests.volumeMounts | indent 8 }}{{ end }}
+  volumes:
+    - name: pod-tmp
+      emptyDir: {}
+    - name: nova-etc
+      secret:
+        secretName: nova-etc
+        defaultMode: 0444
+    - name: nova-bin
+      configMap:
+        name: nova-bin
+        defaultMode: 0555
+    - name: rally-db
+      emptyDir: {}
+{{- dict "enabled" .Values.manifests.certificates "name"  .Values.secrets.tls.compute.osapi.internal | include "helm-toolkit.snippets.tls_volume" | indent 4 }}
+{{ if $mounts_tests.volumes }}{{ toYaml $mounts_tests.volumes | indent 4 }}{{ end }}
+{{- end }}
diff --git a/charts/nova/templates/secret-db-api.yaml b/charts/nova/templates/secret-db-api.yaml
new file mode 100644
index 0000000..baf75b1
--- /dev/null
+++ b/charts/nova/templates/secret-db-api.yaml
@@ -0,0 +1,33 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.secret_db_api }}
+{{- $envAll := . }}
+{{- range $key1, $userClass := tuple "admin" "nova" }}
+{{- $secretName := index $envAll.Values.secrets.oslo_db_api $userClass }}
+{{- $connection := tuple "oslo_db_api" "internal" $userClass "mysql" $envAll | include "helm-toolkit.endpoints.authenticated_endpoint_uri_lookup" }}
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ $secretName }}
+type: Opaque
+data:
+{{- if $envAll.Values.manifests.certificates }}
+  DB_CONNECTION: {{ (printf "%s?charset=utf8&ssl_ca=/etc/mysql/certs/ca.crt&ssl_key=/etc/mysql/certs/tls.key&ssl_cert=/etc/mysql/certs/tls.crt&ssl_verify_cert" $connection ) | b64enc -}}
+{{- else }}
+  DB_CONNECTION: {{ $connection | b64enc -}}
+{{- end }}
+{{- end }}
+{{- end }}
diff --git a/charts/nova/templates/secret-db-cell0.yaml b/charts/nova/templates/secret-db-cell0.yaml
new file mode 100644
index 0000000..100b57f
--- /dev/null
+++ b/charts/nova/templates/secret-db-cell0.yaml
@@ -0,0 +1,33 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.secret_db_cell0 }}
+{{- $envAll := . }}
+{{- range $key1, $userClass := tuple "admin" "nova" }}
+{{- $secretName := index $envAll.Values.secrets.oslo_db_cell0 $userClass }}
+{{- $connection := tuple "oslo_db_cell0" "internal" $userClass "mysql" $envAll | include "helm-toolkit.endpoints.authenticated_endpoint_uri_lookup" }}
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ $secretName }}
+type: Opaque
+data:
+{{- if $envAll.Values.manifests.certificates }}
+  DB_CONNECTION: {{ (printf "%s?charset=utf8&ssl_ca=/etc/mysql/certs/ca.crt&ssl_key=/etc/mysql/certs/tls.key&ssl_cert=/etc/mysql/certs/tls.crt&ssl_verify_cert" $connection ) | b64enc -}}
+{{- else }}
+  DB_CONNECTION: {{ $connection | b64enc -}}
+{{- end }}
+{{- end }}
+{{- end }}
diff --git a/charts/nova/templates/secret-db.yaml b/charts/nova/templates/secret-db.yaml
new file mode 100644
index 0000000..d9cbf8f
--- /dev/null
+++ b/charts/nova/templates/secret-db.yaml
@@ -0,0 +1,33 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.secret_db }}
+{{- $envAll := . }}
+{{- range $key1, $userClass := tuple "admin" "nova" }}
+{{- $secretName := index $envAll.Values.secrets.oslo_db $userClass }}
+{{- $connection := tuple "oslo_db" "internal" $userClass "mysql" $envAll | include "helm-toolkit.endpoints.authenticated_endpoint_uri_lookup" }}
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ $secretName }}
+type: Opaque
+data:
+{{- if $envAll.Values.manifests.certificates }}
+  DB_CONNECTION: {{ (printf "%s?charset=utf8&ssl_ca=/etc/mysql/certs/ca.crt&ssl_key=/etc/mysql/certs/tls.key&ssl_cert=/etc/mysql/certs/tls.crt&ssl_verify_cert" $connection ) | b64enc -}}
+{{- else }}
+  DB_CONNECTION: {{  $connection | b64enc -}}
+{{- end }}
+{{- end }}
+{{- end }}
diff --git a/charts/nova/templates/secret-ingress-tls.yaml b/charts/nova/templates/secret-ingress-tls.yaml
new file mode 100644
index 0000000..91ec9fa
--- /dev/null
+++ b/charts/nova/templates/secret-ingress-tls.yaml
@@ -0,0 +1,21 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.secret_ingress_tls }}
+{{ include "helm-toolkit.manifests.secret_ingress_tls" ( dict "envAll" . "backendService" "osapi" "backendServiceType" "compute" ) }}
+{{ include "helm-toolkit.manifests.secret_ingress_tls" ( dict "envAll" . "backendService" "novncproxy" "backendServiceType" "compute_novnc_proxy" ) }}
+{{- if .Values.manifests.ingress_placement }}
+{{ include "helm-toolkit.manifests.secret_ingress_tls" ( dict "envAll" . "backendService" "placement" "backendServiceType" "placement" ) }}
+{{- end }}
+{{- end }}
diff --git a/charts/nova/templates/secret-keystone-placement.yaml b/charts/nova/templates/secret-keystone-placement.yaml
new file mode 100644
index 0000000..bdce9b5
--- /dev/null
+++ b/charts/nova/templates/secret-keystone-placement.yaml
@@ -0,0 +1,28 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.secret_keystone_placement }}
+{{- $envAll := . }}
+{{- range $key1, $userClass := tuple "placement" }}
+{{- $secretName := index $envAll.Values.secrets.identity $userClass }}
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ $secretName }}
+type: Opaque
+data:
+{{- tuple $userClass "internal" $envAll | include "helm-toolkit.snippets.keystone_secret_openrc" | indent 2 -}}
+{{- end }}
+{{- end }}
diff --git a/charts/nova/templates/secret-keystone.yaml b/charts/nova/templates/secret-keystone.yaml
new file mode 100644
index 0000000..beddb30
--- /dev/null
+++ b/charts/nova/templates/secret-keystone.yaml
@@ -0,0 +1,28 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.secret_keystone }}
+{{- $envAll := . }}
+{{- range $key1, $userClass := tuple "admin" "nova" "test" }}
+{{- $secretName := index $envAll.Values.secrets.identity $userClass }}
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ $secretName }}
+type: Opaque
+data:
+{{- tuple $userClass "internal" $envAll | include "helm-toolkit.snippets.keystone_secret_openrc" | indent 2 -}}
+{{- end }}
+{{- end }}
diff --git a/charts/nova/templates/secret-ssh.yaml b/charts/nova/templates/secret-ssh.yaml
new file mode 100644
index 0000000..4811b2e
--- /dev/null
+++ b/charts/nova/templates/secret-ssh.yaml
@@ -0,0 +1,33 @@
+{{/*
+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.
+*/}}
+
+{{- define "nova.configmap.ssh" }}
+{{- $envAll := index . 1 }}
+{{- with $envAll }}
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: nova-ssh
+type: Opaque
+data:
+  private-key: {{ .Values.network.ssh.private_key | b64enc }}
+{{- include "helm-toolkit.snippets.values_template_renderer" (dict "envAll" $envAll "template" .Values.network.ssh.public_key "key" "public-key" "format" "Secret" ) | indent 2 }}
+
+{{- end }}
+{{- end }}
+
+{{- if .Values.manifests.configmap_etc }}
+{{- list "nova-ssh" . | include "nova.configmap.ssh" }}
+{{- end }}
diff --git a/charts/nova/templates/secret_rabbitmq.yaml b/charts/nova/templates/secret_rabbitmq.yaml
new file mode 100644
index 0000000..b49f84e
--- /dev/null
+++ b/charts/nova/templates/secret_rabbitmq.yaml
@@ -0,0 +1,33 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.secret_rabbitmq }}
+{{- $envAll := . }}
+{{- $rabbitmqProtocol := "http" }}
+{{- if $envAll.Values.manifests.certificates }}
+{{- $rabbitmqProtocol = "https" }}
+{{- end }}
+{{- range $key1, $userClass := tuple "admin" "nova" }}
+{{- $secretName := index $envAll.Values.secrets.oslo_messaging $userClass }}
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ $secretName }}
+type: Opaque
+data:
+  RABBITMQ_CONNECTION: {{ tuple "oslo_messaging" "internal" $userClass $rabbitmqProtocol $envAll | include "helm-toolkit.endpoints.authenticated_endpoint_uri_lookup" | b64enc }}
+  TRANSPORT_URL: {{ tuple "oslo_messaging" "internal" $userClass "amqp" $envAll | include "helm-toolkit.endpoints.authenticated_transport_endpoint_uri_lookup" | b64enc }}
+{{- end }}
+{{- end }}
diff --git a/charts/nova/templates/service-ingress-metadata.yaml b/charts/nova/templates/service-ingress-metadata.yaml
new file mode 100644
index 0000000..187987d
--- /dev/null
+++ b/charts/nova/templates/service-ingress-metadata.yaml
@@ -0,0 +1,18 @@
+{{/*
+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.
+*/}}
+
+{{- if and .Values.manifests.service_ingress_metadata .Values.network.metadata.ingress.public }}
+{{- $serviceIngressOpts := dict "envAll" . "backendServiceType" "compute_metadata" -}}
+{{ $serviceIngressOpts | include "helm-toolkit.manifests.service_ingress" }}
+{{- end }}
diff --git a/charts/nova/templates/service-ingress-novncproxy.yaml b/charts/nova/templates/service-ingress-novncproxy.yaml
new file mode 100644
index 0000000..caae913
--- /dev/null
+++ b/charts/nova/templates/service-ingress-novncproxy.yaml
@@ -0,0 +1,18 @@
+{{/*
+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.
+*/}}
+
+{{- if and .Values.manifests.service_ingress_novncproxy .Values.network.novncproxy.ingress.public }}
+{{- $serviceIngressOpts := dict "envAll" . "backendServiceType" "compute_novnc_proxy" -}}
+{{ $serviceIngressOpts | include "helm-toolkit.manifests.service_ingress" }}
+{{- end }}
diff --git a/charts/nova/templates/service-ingress-osapi.yaml b/charts/nova/templates/service-ingress-osapi.yaml
new file mode 100644
index 0000000..44633e3
--- /dev/null
+++ b/charts/nova/templates/service-ingress-osapi.yaml
@@ -0,0 +1,18 @@
+{{/*
+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.
+*/}}
+
+{{- if and .Values.manifests.service_ingress_osapi .Values.network.osapi.ingress.public }}
+{{- $serviceIngressOpts := dict "envAll" . "backendServiceType" "compute" -}}
+{{ $serviceIngressOpts | include "helm-toolkit.manifests.service_ingress" }}
+{{- end }}
diff --git a/charts/nova/templates/service-ingress-placement.yaml b/charts/nova/templates/service-ingress-placement.yaml
new file mode 100644
index 0000000..5d9e6a6
--- /dev/null
+++ b/charts/nova/templates/service-ingress-placement.yaml
@@ -0,0 +1,18 @@
+{{/*
+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.
+*/}}
+
+{{- if and .Values.manifests.service_ingress_placement .Values.network.placement.ingress.public }}
+{{- $serviceIngressOpts := dict "envAll" . "backendServiceType" "placement" -}}
+{{ $serviceIngressOpts | include "helm-toolkit.manifests.service_ingress" }}
+{{- end }}
diff --git a/charts/nova/templates/service-metadata.yaml b/charts/nova/templates/service-metadata.yaml
new file mode 100644
index 0000000..26eed99
--- /dev/null
+++ b/charts/nova/templates/service-metadata.yaml
@@ -0,0 +1,37 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.service_metadata }}
+{{- $envAll := . }}
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ tuple "compute_metadata" "internal" . | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }}
+spec:
+  ports:
+  - name: n-meta
+    port: {{ .Values.network.metadata.port }}
+    {{ if .Values.network.metadata.node_port.enabled }}
+    nodePort: {{ .Values.network.metadata.node_port.port }}
+    {{ end }}
+  selector:
+{{ tuple $envAll "nova" "metadata" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+  {{ if .Values.network.metadata.node_port.enabled }}
+  type: NodePort
+  {{ if .Values.network.metadata.external_policy_local }}
+  externalTrafficPolicy: Local
+  {{ end }}
+  {{ end }}
+{{- end }}
diff --git a/charts/nova/templates/service-novncproxy.yaml b/charts/nova/templates/service-novncproxy.yaml
new file mode 100644
index 0000000..9e7eebe
--- /dev/null
+++ b/charts/nova/templates/service-novncproxy.yaml
@@ -0,0 +1,34 @@
+{{/*
+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.
+*/}}
+
+{{- if and .Values.manifests.service_novncproxy ( eq .Values.console.console_kind "novnc" ) }}
+{{- $envAll := . }}
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ tuple "compute_novnc_proxy" "internal" . | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }}
+spec:
+  ports:
+  - name: n-novnc
+    port: {{ tuple "compute_novnc_proxy" "internal" "novnc_proxy" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+    {{ if .Values.network.novncproxy.node_port.enabled }}
+    nodePort: {{ .Values.network.novncproxy.node_port.port }}
+    {{ end }}
+  selector:
+{{ tuple $envAll "nova" "novnc-proxy" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+  {{ if .Values.network.novncproxy.node_port.enabled }}
+  type: NodePort
+  {{ end }}
+{{- end }}
diff --git a/charts/nova/templates/service-osapi.yaml b/charts/nova/templates/service-osapi.yaml
new file mode 100644
index 0000000..91ab52c
--- /dev/null
+++ b/charts/nova/templates/service-osapi.yaml
@@ -0,0 +1,37 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.service_osapi }}
+{{- $envAll := . }}
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ tuple "compute" "internal" . | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }}
+spec:
+  ports:
+  - name: n-api
+    port: {{ tuple "compute" "internal" "api" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+    {{ if .Values.network.osapi.node_port.enabled }}
+    nodePort: {{ .Values.network.osapi.node_port.port }}
+    {{ end }}
+  selector:
+{{ tuple $envAll "nova" "os-api" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+  {{ if .Values.network.osapi.node_port.enabled }}
+  type: NodePort
+  {{ if .Values.network.osapi.external_policy_local }}
+  externalTrafficPolicy: Local
+  {{ end }}
+  {{ end }}
+{{- end }}
diff --git a/charts/nova/templates/service-placement.yaml b/charts/nova/templates/service-placement.yaml
new file mode 100644
index 0000000..8e1f3d5
--- /dev/null
+++ b/charts/nova/templates/service-placement.yaml
@@ -0,0 +1,34 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.service_placement }}
+{{- $envAll := . }}
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ tuple "placement" "internal" . | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }}
+spec:
+  ports:
+  - name: p-api
+    port: {{ tuple "placement" "internal" "api" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+    {{ if .Values.network.placement.node_port.enabled }}
+    nodePort: {{ .Values.network.placement.node_port.port }}
+    {{ end }}
+  selector:
+{{ tuple $envAll "nova" "placement" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+  {{ if .Values.network.placement.node_port.enabled }}
+  type: NodePort
+  {{ end }}
+{{- end }}
diff --git a/charts/nova/templates/service-spiceproxy.yaml b/charts/nova/templates/service-spiceproxy.yaml
new file mode 100644
index 0000000..3507a05
--- /dev/null
+++ b/charts/nova/templates/service-spiceproxy.yaml
@@ -0,0 +1,34 @@
+{{/*
+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.
+*/}}
+
+{{- if and .Values.manifests.service_spiceproxy (eq .Values.console.console_kind "spice") }}
+{{- $envAll := . }}
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ tuple "compute_spice_proxy" "internal" . | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }}
+spec:
+  ports:
+  - name: n-spice
+    port: {{ tuple "compute_spice_proxy" "internal" "spice_proxy" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+    {{ if .Values.network.spiceproxy.node_port.enabled }}
+    nodePort: {{ .Values.network.spiceproxy.node_port.port }}
+    {{ end }}
+  selector:
+{{ tuple $envAll "nova" "spice-proxy" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+  {{ if .Values.network.spiceproxy.node_port.enabled }}
+  type: NodePort
+  {{ end }}
+{{- end }}
diff --git a/charts/nova/templates/statefulset-compute-ironic.yaml b/charts/nova/templates/statefulset-compute-ironic.yaml
new file mode 100644
index 0000000..377555d
--- /dev/null
+++ b/charts/nova/templates/statefulset-compute-ironic.yaml
@@ -0,0 +1,113 @@
+{{/*
+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.
+*/}}
+
+{{- if .Values.manifests.statefulset_compute_ironic }}
+{{- $envAll := . }}
+
+{{- $mounts_nova_compute_ironic := .Values.pod.mounts.nova_compute_ironic.nova_compute_ironic }}
+{{- $mounts_nova_compute_ironic_init := .Values.pod.mounts.nova_compute_ironic.init_container }}
+
+{{- $serviceAccountName := "nova-compute-ironic" }}
+{{ tuple $envAll "compute_ironic" $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: nova-compute-ironic
+  annotations:
+    {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }}
+  labels:
+{{ tuple $envAll "nova" "compute-ironic" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }}
+spec:
+  replicas: {{ .Values.pod.replicas.compute_ironic }}
+  selector:
+    matchLabels:
+{{ tuple $envAll "nova" "compute-ironic" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }}
+  serviceName: "{{ tuple "baremetal" "internal" . | include "helm-toolkit.endpoints.hostname_short_endpoint_lookup" }}-compute"
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll "nova" "compute-ironic" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+      annotations:
+{{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" | indent 8 }}
+        configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }}
+        configmap-etc-hash: {{ tuple "configmap-etc.yaml" . | include "helm-toolkit.utils.hash" }}
+{{ dict "envAll" $envAll "podName" "nova-compute-default" "containerNames" (list "nova-compute") | include "helm-toolkit.snippets.kubernetes_mandatory_access_control_annotation" | indent 8 }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName }}
+{{ dict "envAll" $envAll "application" "nova" | include "helm-toolkit.snippets.kubernetes_pod_security_context" | indent 6 }}
+      affinity:
+{{ tuple $envAll "nova" "compute-ironic" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }}
+      nodeSelector:
+        {{ .Values.labels.agent.compute_ironic.node_selector_key }}: {{ .Values.labels.agent.compute_ironic.node_selector_value }}
+      securityContext:
+        runAsUser: 0
+      hostPID: true
+      dnsPolicy: ClusterFirstWithHostNet
+      initContainers:
+{{ tuple $envAll "compute_ironic" $mounts_nova_compute_ironic_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
+      containers:
+        - name: nova-compute-ironic
+{{ tuple $envAll "nova_compute_ironic" | include "helm-toolkit.snippets.image" | indent 10 }}
+{{ tuple $envAll $envAll.Values.pod.resources.compute_ironic | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
+          command:
+            - /tmp/nova-compute-ironic.sh
+          volumeMounts:
+            - name: pod-tmp
+              mountPath: /tmp
+            - name: nova-bin
+              mountPath: /tmp/nova-compute-ironic.sh
+              subPath: nova-compute-ironic.sh
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/nova.conf
+              subPath: nova.conf
+              readOnly: true
+            {{- if .Values.conf.nova.DEFAULT.log_config_append }}
+            - name: nova-etc
+              mountPath: {{ .Values.conf.nova.DEFAULT.log_config_append }}
+              subPath: {{ base .Values.conf.nova.DEFAULT.log_config_append }}
+              readOnly: true
+            {{- end }}
+            - name: nova-etc
+              mountPath: /etc/nova/nova-ironic.conf
+              subPath: nova-ironic.conf
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/api-paste.ini
+              subPath: api-paste.ini
+              readOnly: true
+            - name: nova-etc
+              mountPath: /etc/nova/policy.yaml
+              subPath: policy.yaml
+              readOnly: true
+            - name: varlibironic
+              mountPath: /var/lib/ironic
+{{ if $mounts_nova_compute_ironic.volumeMounts }}{{ toYaml $mounts_nova_compute_ironic.volumeMounts | indent 12 }}{{ end }}
+      volumes:
+        - name: pod-tmp
+          emptyDir: {}
+        - name: nova-bin
+          configMap:
+            name: nova-bin
+            defaultMode: 0555
+        - name: nova-etc
+          secret:
+            secretName: nova-etc
+            defaultMode: 0444
+        - name: varlibironic
+          hostPath:
+            path: /var/lib/ironic
+{{ if $mounts_nova_compute_ironic.volumes }}{{ toYaml $mounts_nova_compute_ironic.volumes | indent 8 }}{{ end }}
+{{- end }}
diff --git a/charts/nova/values.yaml b/charts/nova/values.yaml
new file mode 100644
index 0000000..7d4c1e5
--- /dev/null
+++ b/charts/nova/values.yaml
@@ -0,0 +1,2619 @@
+# 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.
+
+# Default values for nova.
+# This is a YAML-formatted file.
+# Declare name/value pairs to be passed into your templates.
+# name: value
+
+---
+release_group: null
+
+labels:
+  agent:
+    compute:
+      node_selector_key: openstack-compute-node
+      node_selector_value: enabled
+    compute_ironic:
+      node_selector_key: openstack-compute-node
+      node_selector_value: enabled
+  api_metadata:
+    node_selector_key: openstack-control-plane
+    node_selector_value: enabled
+  conductor:
+    node_selector_key: openstack-control-plane
+    node_selector_value: enabled
+  consoleauth:
+    node_selector_key: openstack-control-plane
+    node_selector_value: enabled
+  job:
+    node_selector_key: openstack-control-plane
+    node_selector_value: enabled
+  novncproxy:
+    node_selector_key: openstack-control-plane
+    node_selector_value: enabled
+  osapi:
+    node_selector_key: openstack-control-plane
+    node_selector_value: enabled
+  placement:
+    node_selector_key: openstack-control-plane
+    node_selector_value: enabled
+  scheduler:
+    node_selector_key: openstack-control-plane
+    node_selector_value: enabled
+  spiceproxy:
+    node_selector_key: openstack-control-plane
+    node_selector_value: enabled
+  test:
+    node_selector_key: openstack-control-plane
+    node_selector_value: enabled
+
+images:
+  pull_policy: IfNotPresent
+  tags:
+    bootstrap: docker.io/openstackhelm/heat:stein-ubuntu_bionic
+    db_drop: docker.io/openstackhelm/heat:stein-ubuntu_bionic
+    db_init: docker.io/openstackhelm/heat:stein-ubuntu_bionic
+    dep_check: 'quay.io/airshipit/kubernetes-entrypoint:v1.0.0'
+    rabbit_init: docker.io/rabbitmq:3.7-management
+    ks_user: docker.io/openstackhelm/heat:stein-ubuntu_bionic
+    ks_service: docker.io/openstackhelm/heat:stein-ubuntu_bionic
+    nova_archive_deleted_rows: docker.io/openstackhelm/nova:stein-ubuntu_bionic
+    ks_endpoints: docker.io/openstackhelm/heat:stein-ubuntu_bionic
+    nova_api: docker.io/openstackhelm/nova:stein-ubuntu_bionic
+    nova_cell_setup: docker.io/openstackhelm/nova:stein-ubuntu_bionic
+    nova_cell_setup_init: docker.io/openstackhelm/heat:stein-ubuntu_bionic
+    nova_compute: docker.io/openstackhelm/nova:stein-ubuntu_bionic
+    nova_compute_ironic: 'docker.io/kolla/ubuntu-source-nova-compute-ironic:ocata'
+    nova_compute_ssh: docker.io/openstackhelm/nova:stein-ubuntu_bionic
+    nova_conductor: docker.io/openstackhelm/nova:stein-ubuntu_bionic
+    nova_consoleauth: docker.io/openstackhelm/nova:stein-ubuntu_bionic
+    nova_db_sync: docker.io/openstackhelm/nova:stein-ubuntu_bionic
+    nova_novncproxy: docker.io/openstackhelm/nova:stein-ubuntu_bionic
+    nova_novncproxy_assets: 'docker.io/kolla/ubuntu-source-nova-novncproxy:ocata'
+    nova_placement: docker.io/openstackhelm/nova:stein-ubuntu_bionic
+    nova_scheduler: docker.io/openstackhelm/nova:stein-ubuntu_bionic
+    # NOTE(portdirect): we simply use the ceph config helper here,
+    # as it has both oscli and jq.
+    nova_service_cleaner: 'docker.io/openstackhelm/ceph-config-helper:latest-ubuntu_xenial'
+    nova_spiceproxy: docker.io/openstackhelm/nova:stein-ubuntu_bionic
+    nova_spiceproxy_assets: docker.io/openstackhelm/nova:stein-ubuntu_bionic
+    test: docker.io/xrally/xrally-openstack:2.0.0
+    image_repo_sync: docker.io/docker:17.07.0
+    nova_wait_for_computes_init: gcr.io/google_containers/hyperkube-amd64:v1.11.6
+  local_registry:
+    active: false
+    exclude:
+      - dep_check
+      - image_repo_sync
+
+jobs:
+  # NOTE(portdirect): When using cells new nodes will be added to the cell on the hour by default.
+  # TODO(portdirect): Add a post-start action to nova compute pods that registers themselves.
+  cell_setup:
+    cron: "0 */1 * * *"
+    starting_deadline: 600
+    history:
+      success: 3
+      failed: 1
+    extended_wait:
+      enabled: false
+      iteration: 3
+      duration: 5
+  service_cleaner:
+    cron: "0 */1 * * *"
+    starting_deadline: 600
+    history:
+      success: 3
+      failed: 1
+    sleep_time: 60
+  archive_deleted_rows:
+    cron: "0 */1 * * *"
+    starting_deadline: 600
+    history:
+      success: 3
+      failed: 1
+
+bootstrap:
+  enabled: true
+  ks_user: admin
+  script: null
+  structured:
+    flavors:
+      enabled: true
+      options:
+        m1_tiny:
+          name: "m1.tiny"
+          ram: 512
+          disk: 1
+          vcpus: 1
+        m1_small:
+          name: "m1.small"
+          ram: 2048
+          disk: 20
+          vcpus: 1
+        m1_medium:
+          name: "m1.medium"
+          ram: 4096
+          disk: 40
+          vcpus: 2
+        m1_large:
+          name: "m1.large"
+          ram: 8192
+          disk: 80
+          vcpus: 4
+        m1_xlarge:
+          name: "m1.xlarge"
+          ram: 16384
+          disk: 160
+          vcpus: 8
+  wait_for_computes:
+    enabled: false
+    # Wait percentage is the minimum percentage of compute hypervisors which
+    # must be available before the remainder of the bootstrap script can be run.
+    wait_percentage: 70
+    # Once the wait_percentage above is achieved, the remaining_wait is the
+    # amount of time in seconds to wait before executing the remainder of the
+    # boostrap script.
+    remaining_wait: 300
+    scripts:
+      init_script: |
+        # This runs in a bootstrap init container. It counts the number of compute nodes.
+        COMPUTE_NODES=$(kubectl get nodes -o custom-columns=NAME:.metadata.name -l openstack-compute-node=enabled --no-headers | sort)
+        /bin/echo $COMPUTE_NODES > /tmp/compute_nodes.txt
+      wait_script: |
+        # This script runs in the main bootstrap container just before the
+        # bootstrap.script is called.
+        COMPUTE_HOSTS=`cat /tmp/compute_nodes.txt | wc -w`
+        if [[ $COMPUTE_HOSTS == 0 ]]; then
+          echo "There are no compute hosts found!"
+          exit 1
+        fi
+
+        # Wait for all hypervisors to come up before moving on with the deployment
+        HYPERVISOR_WAIT=true
+        WAIT_AFTER_READY=0
+        SLEEP=5
+        while [[ $HYPERVISOR_WAIT == true ]]; do
+          # Its possible that openstack command may fail due to not being able to
+          # reach the compute service
+          set +e
+          HYPERVISORS=$(openstack hypervisor list -f value -c 'Hypervisor Hostname' | wc -w)
+          set -e
+
+          PERCENT_READY=$(( $HYPERVISORS * 100 / $COMPUTE_HOSTS ))
+          if [[ $PERCENT_READY -ge $WAIT_PERCENTAGE ]]; then
+            echo "Hypervisor ready percentage is $PERCENT_READY"
+            if [[ $PERCENT_READY == 100 ]]; then
+              HYPERVISOR_WAIT=false
+              echo "All hypervisors are ready."
+            elif [[ WAIT_AFTER_READY -ge $REMAINING_WAIT ]]; then
+              HYPERVISOR_WAIT=false
+              echo "Waited the configured time -- $HYPERVISORS out of $COMPUTE_HOSTS hypervisor(s) ready -- proceeding with the bootstrap."
+            else
+              sleep $SLEEP
+              WAIT_AFTER_READY=$(( $WAIT_AFTER_READY + $SLEEP ))
+            fi
+          else
+            echo "Waiting $SLEEP seconds for enough hypervisors to be discovered..."
+            sleep $SLEEP
+          fi
+        done
+
+network:
+  # provide what type of network wiring will be used
+  # possible options: openvswitch, linuxbridge, sriov
+  backend:
+    - openvswitch
+  osapi:
+    port: 8774
+    ingress:
+      public: true
+      classes:
+        namespace: "nginx"
+        cluster: "nginx-cluster"
+      annotations:
+        nginx.ingress.kubernetes.io/rewrite-target: /
+    external_policy_local: false
+    node_port:
+      enabled: false
+      port: 30774
+  metadata:
+    port: 8775
+    ingress:
+      public: true
+      classes:
+        namespace: "nginx"
+        cluster: "nginx-cluster"
+      annotations:
+        nginx.ingress.kubernetes.io/rewrite-target: /
+    external_policy_local: false
+    node_port:
+      enabled: false
+      port: 30775
+  placement:
+    port: 8778
+    ingress:
+      public: true
+      classes:
+        namespace: "nginx"
+        cluster: "nginx-cluster"
+      annotations:
+        nginx.ingress.kubernetes.io/rewrite-target: /
+    node_port:
+      enabled: false
+      port: 30778
+  novncproxy:
+    ingress:
+      public: true
+      classes:
+        namespace: "nginx"
+        cluster: "nginx-cluster"
+      annotations:
+        nginx.ingress.kubernetes.io/rewrite-target: /
+    node_port:
+      enabled: false
+      port: 30680
+  spiceproxy:
+    node_port:
+      enabled: false
+      port: 30682
+  ssh:
+    enabled: false
+    port: 8022
+    from_subnet: 0.0.0.0/0
+    key_types:
+      - rsa
+      - dsa
+      - ecdsa
+      - ed25519
+    private_key: 'null'
+    public_key: 'null'
+
+dependencies:
+  dynamic:
+    common:
+      local_image_registry:
+        jobs:
+          - nova-image-repo-sync
+        services:
+          - endpoint: node
+            service: local_image_registry
+    targeted:
+      openvswitch:
+        compute:
+          pod:
+            - requireSameNode: true
+              labels:
+                application: neutron
+                component: neutron-ovs-agent
+      linuxbridge:
+        compute:
+          pod:
+            - requireSameNode: true
+              labels:
+                application: neutron
+                component: neutron-lb-agent
+      sriov:
+        compute:
+          pod:
+            - requireSameNode: true
+              labels:
+                application: neutron
+                component: neutron-sriov-agent
+  static:
+    api:
+      jobs:
+        - nova-db-sync
+        - nova-ks-user
+        - nova-ks-endpoints
+        - nova-rabbit-init
+      services:
+        - endpoint: internal
+          service: oslo_messaging
+        - endpoint: internal
+          service: oslo_db
+        - endpoint: internal
+          service: identity
+    api_metadata:
+      jobs:
+        - nova-db-sync
+        - nova-ks-user
+        - nova-ks-endpoints
+        - nova-rabbit-init
+      services:
+        - endpoint: internal
+          service: oslo_messaging
+        - endpoint: internal
+          service: oslo_db
+        - endpoint: internal
+          service: identity
+    bootstrap:
+      services:
+        - endpoint: internal
+          service: identity
+        - endpoint: internal
+          service: compute
+    cell_setup:
+      jobs:
+        - nova-db-sync
+        - nova-rabbit-init
+      services:
+        - endpoint: internal
+          service: oslo_messaging
+        - endpoint: internal
+          service: oslo_db
+        - endpoint: internal
+          service: identity
+        - endpoint: internal
+          service: compute
+      pod:
+        - requireSameNode: false
+          labels:
+            application: nova
+            component: compute
+    service_cleaner:
+      jobs:
+        - nova-db-sync
+        - nova-rabbit-init
+      services:
+        - endpoint: internal
+          service: oslo_messaging
+        - endpoint: internal
+          service: oslo_db
+        - endpoint: internal
+          service: identity
+        - endpoint: internal
+          service: compute
+    compute:
+      pod:
+        - requireSameNode: true
+          labels:
+            application: libvirt
+            component: libvirt
+      jobs:
+        - nova-db-sync
+        - nova-rabbit-init
+        - placement-ks-endpoints
+      services:
+        - endpoint: internal
+          service: oslo_messaging
+        - endpoint: internal
+          service: image
+        - endpoint: internal
+          service: compute
+        - endpoint: internal
+          service: network
+        - endpoint: internal
+          service: compute_metadata
+    compute_ironic:
+      jobs:
+        - nova-db-sync
+        - nova-rabbit-init
+      services:
+        - endpoint: internal
+          service: oslo_messaging
+        - endpoint: internal
+          service: image
+        - endpoint: internal
+          service: compute
+        - endpoint: internal
+          service: network
+        - endpoint: internal
+          service: baremetal
+    conductor:
+      jobs:
+        - nova-db-sync
+        - nova-rabbit-init
+        - placement-ks-endpoints
+      services:
+        - endpoint: internal
+          service: oslo_messaging
+        - endpoint: internal
+          service: oslo_db
+        - endpoint: internal
+          service: identity
+        - endpoint: internal
+          service: compute
+    consoleauth:
+      jobs:
+        - nova-db-sync
+        - nova-rabbit-init
+      services:
+        - endpoint: internal
+          service: oslo_messaging
+        - endpoint: internal
+          service: oslo_db
+        - endpoint: internal
+          service: identity
+        - endpoint: internal
+          service: compute
+    db_drop:
+      services:
+        - endpoint: internal
+          service: oslo_db
+    archive_deleted_rows:
+      jobs:
+        - nova-db-init
+        - nova-db-sync
+    db_init:
+      services:
+        - endpoint: internal
+          service: oslo_db
+    db_sync:
+      jobs:
+        - nova-db-init
+      services:
+        - endpoint: internal
+          service: oslo_db
+    ks_endpoints:
+      jobs:
+        - nova-ks-service
+      services:
+        - endpoint: internal
+          service: identity
+    ks_service:
+      services:
+        - endpoint: internal
+          service: identity
+    ks_user:
+      services:
+        - endpoint: internal
+          service: identity
+    rabbit_init:
+      services:
+        - service: oslo_messaging
+          endpoint: internal
+    novncproxy:
+      jobs:
+        - nova-db-sync
+      services:
+        - endpoint: internal
+          service: oslo_db
+    spiceproxy:
+      jobs:
+        - nova-db-sync
+      services:
+        - endpoint: internal
+          service: oslo_db
+    scheduler:
+      jobs:
+        - nova-db-sync
+        - nova-rabbit-init
+        - placement-ks-endpoints
+      services:
+        - endpoint: internal
+          service: oslo_messaging
+        - endpoint: internal
+          service: oslo_db
+        - endpoint: internal
+          service: identity
+        - endpoint: internal
+          service: compute
+    tests:
+      services:
+        - endpoint: internal
+          service: image
+        - endpoint: internal
+          service: compute
+        - endpoint: internal
+          service: network
+        - endpoint: internal
+          service: compute_metadata
+    image_repo_sync:
+      services:
+        - endpoint: internal
+          service: local_image_registry
+
+console:
+  # serial | spice | novnc | none
+  console_kind: novnc
+  serial:
+  spice:
+    compute:
+      # IF blank, search default routing interface
+      server_proxyclient_interface:
+    proxy:
+      # IF blank, search default routing interface
+      server_proxyclient_interface:
+  novnc:
+    compute:
+      # IF blank, search default routing interface
+      vncserver_proxyclient_interface:
+    vncproxy:
+      # IF blank, search default routing interface
+      vncserver_proxyclient_interface:
+
+ceph_client:
+  configmap: ceph-etc
+  user_secret_name: pvc-ceph-client-key
+
+conf:
+  security: |
+    #
+    # Disable access to the entire file system except for the directories that
+    # are explicitly allowed later.
+    #
+    # This currently breaks the configurations that come with some web application
+    # Debian packages.
+    #
+    #<Directory />
+    #   AllowOverride None
+    #   Require all denied
+    #</Directory>
+
+    # Changing the following options will not really affect the security of the
+    # server, but might make attacks slightly more difficult in some cases.
+
+    #
+    # ServerTokens
+    # This directive configures what you return as the Server HTTP response
+    # Header. The default is 'Full' which sends information about the OS-Type
+    # and compiled in modules.
+    # Set to one of:  Full | OS | Minimal | Minor | Major | Prod
+    # where Full conveys the most information, and Prod the least.
+    ServerTokens Prod
+
+    #
+    # Optionally add a line containing the server version and virtual host
+    # name to server-generated pages (internal error documents, FTP directory
+    # listings, mod_status and mod_info output etc., but not CGI generated
+    # documents or custom error documents).
+    # Set to "EMail" to also include a mailto: link to the ServerAdmin.
+    # Set to one of:  On | Off | EMail
+    ServerSignature Off
+
+    #
+    # Allow TRACE method
+    #
+    # Set to "extended" to also reflect the request body (only for testing and
+    # diagnostic purposes).
+    #
+    # Set to one of:  On | Off | extended
+    TraceEnable Off
+
+    #
+    # Forbid access to version control directories
+    #
+    # If you use version control systems in your document root, you should
+    # probably deny access to their directories. For example, for subversion:
+    #
+    #<DirectoryMatch "/\.svn">
+    #   Require all denied
+    #</DirectoryMatch>
+
+    #
+    # Setting this header will prevent MSIE from interpreting files as something
+    # else than declared by the content type in the HTTP headers.
+    # Requires mod_headers to be enabled.
+    #
+    #Header set X-Content-Type-Options: "nosniff"
+
+    #
+    # Setting this header will prevent other sites from embedding pages from this
+    # site as frames. This defends against clickjacking attacks.
+    # Requires mod_headers to be enabled.
+    #
+    #Header set X-Frame-Options: "sameorigin"
+  software:
+    apache2:
+      binary: apache2
+      start_parameters: -DFOREGROUND
+      conf_dir: /etc/apache2/conf-enabled
+      site_dir: /etc/apache2/sites-enable
+      mods_dir: /etc/apache2/mods-available
+      a2enmod: null
+      a2dismod: null
+  ceph:
+    enabled: true
+    admin_keyring: null
+    cinder:
+      user: "cinder"
+      keyring: null
+      secret_uuid: 457eb676-33da-42ec-9a8c-9293d545c337
+  rally_tests:
+    run_tempest: false
+    clean_up: |
+      FLAVORS=$(openstack flavor list -f value --all | awk '$2 ~ /^s_rally_/ { print $1 }')
+      if [ -n "$FLAVORS" ]; then
+        echo $FLAVORS | xargs openstack flavor delete
+      fi
+      SERVERS=$(openstack server list -f value --all | awk '$2 ~ /^s_rally_/ { print $1 }')
+      if [ -n "$SERVERS" ]; then
+        echo $SERVERS | xargs openstack server delete
+      fi
+      IMAGES=$(openstack image list -f value | awk '$2 ~ /^c_rally_/ { print $1 }')
+      if [ -n "$IMAGES" ]; then
+        echo $IMAGES | xargs openstack image delete
+      fi
+    tests:
+      NovaAgents.list_agents:
+        - runner:
+            concurrency: 1
+            times: 1
+            type: constant
+          sla:
+            failure_rate:
+              max: 0
+      NovaAggregates.create_and_get_aggregate_details:
+        - args:
+            availability_zone: nova
+          runner:
+            concurrency: 1
+            times: 1
+            type: constant
+          sla:
+            failure_rate:
+              max: 0
+      NovaAggregates.create_and_update_aggregate:
+        - args:
+            availability_zone: nova
+          runner:
+            concurrency: 1
+            times: 1
+            type: constant
+          sla:
+            failure_rate:
+              max: 0
+      NovaAggregates.list_aggregates:
+        - runner:
+            concurrency: 1
+            times: 1
+            type: constant
+          sla:
+            failure_rate:
+              max: 0
+      NovaAvailabilityZones.list_availability_zones:
+        - args:
+            detailed: true
+          runner:
+            concurrency: 1
+            times: 1
+            type: constant
+          sla:
+            failure_rate:
+              max: 0
+      NovaFlavors.create_and_delete_flavor:
+        - args:
+            disk: 1
+            ram: 500
+            vcpus: 1
+          runner:
+            concurrency: 1
+            times: 1
+            type: constant
+          sla:
+            failure_rate:
+              max: 0
+      NovaFlavors.create_and_list_flavor_access:
+        - args:
+            disk: 1
+            ram: 500
+            vcpus: 1
+          runner:
+            concurrency: 1
+            times: 1
+            type: constant
+          sla:
+            failure_rate:
+              max: 0
+      NovaFlavors.create_flavor:
+        - args:
+            disk: 1
+            ram: 500
+            vcpus: 1
+          runner:
+            concurrency: 1
+            times: 1
+            type: constant
+          sla:
+            failure_rate:
+              max: 0
+      NovaFlavors.create_flavor_and_add_tenant_access:
+        - args:
+            disk: 1
+            ram: 500
+            vcpus: 1
+          runner:
+            concurrency: 1
+            times: 1
+            type: constant
+          sla:
+            failure_rate:
+              max: 0
+      NovaFlavors.create_flavor_and_set_keys:
+        - args:
+            disk: 1
+            extra_specs:
+              'quota:disk_read_bytes_sec': 10240
+            ram: 500
+            vcpus: 1
+          runner:
+            concurrency: 1
+            times: 1
+            type: constant
+          sla:
+            failure_rate:
+              max: 0
+      NovaFlavors.list_flavors:
+        - args:
+            detailed: true
+          runner:
+            concurrency: 1
+            times: 1
+            type: constant
+          sla:
+            failure_rate:
+              max: 0
+      NovaHypervisors.list_and_get_hypervisors:
+        - args:
+            detailed: true
+          runner:
+            concurrency: 1
+            times: 1
+            type: constant
+          sla:
+            failure_rate:
+              max: 0
+      NovaHypervisors.list_and_get_uptime_hypervisors:
+        - args:
+            detailed: true
+          runner:
+            concurrency: 1
+            times: 1
+            type: constant
+          sla:
+            failure_rate:
+              max: 0
+      NovaHypervisors.list_and_search_hypervisors:
+        - args:
+            detailed: true
+          runner:
+            concurrency: 1
+            times: 1
+            type: constant
+          sla:
+            failure_rate:
+              max: 0
+      NovaHypervisors.list_hypervisors:
+        - args:
+            detailed: true
+          runner:
+            concurrency: 1
+            times: 1
+            type: constant
+          sla:
+            failure_rate:
+              max: 0
+      NovaHypervisors.statistics_hypervisors:
+        - args: {}
+          runner:
+            concurrency: 1
+            times: 1
+            type: constant
+          sla:
+            failure_rate:
+              max: 0
+      NovaKeypair.create_and_delete_keypair:
+        - runner:
+            concurrency: 1
+            times: 1
+            type: constant
+          sla:
+            failure_rate:
+              max: 0
+      NovaKeypair.create_and_list_keypairs:
+        - runner:
+            concurrency: 1
+            times: 1
+            type: constant
+          sla:
+            failure_rate:
+              max: 0
+      NovaServerGroups.create_and_list_server_groups:
+        - args:
+            all_projects: false
+            kwargs:
+              policies:
+                - affinity
+          runner:
+            concurrency: 1
+            times: 1
+            type: constant
+          sla:
+            failure_rate:
+              max: 0
+      NovaServices.list_services:
+        - runner:
+            concurrency: 1
+            times: 1
+            type: constant
+          sla:
+            failure_rate:
+              max: 0
+  paste:
+    composite:metadata:
+      use: egg:Paste#urlmap
+      /: meta
+    pipeline:meta:
+      pipeline: cors metaapp
+    app:metaapp:
+      paste.app_factory: nova.api.metadata.handler:MetadataRequestHandler.factory
+    composite:osapi_compute:
+      use: call:nova.api.openstack.urlmap:urlmap_factory
+      /: oscomputeversions
+      /v2: openstack_compute_api_v21_legacy_v2_compatible
+      /v2.1: openstack_compute_api_v21
+    composite:openstack_compute_api_v21:
+      use: call:nova.api.auth:pipeline_factory_v21
+      noauth2: cors http_proxy_to_wsgi compute_req_id faultwrap sizelimit noauth2 osapi_compute_app_v21
+      keystone: cors http_proxy_to_wsgi compute_req_id faultwrap sizelimit authtoken audit keystonecontext osapi_compute_app_v21
+    composite:openstack_compute_api_v21_legacy_v2_compatible:
+      use: call:nova.api.auth:pipeline_factory_v21
+      noauth2: cors http_proxy_to_wsgi compute_req_id faultwrap sizelimit noauth2 legacy_v2_compatible osapi_compute_app_v21
+      keystone: cors http_proxy_to_wsgi compute_req_id faultwrap sizelimit authtoken audit keystonecontext legacy_v2_compatible osapi_compute_app_v21
+    filter:request_id:
+      paste.filter_factory: oslo_middleware:RequestId.factory
+    filter:compute_req_id:
+      paste.filter_factory: nova.api.compute_req_id:ComputeReqIdMiddleware.factory
+    filter:faultwrap:
+      paste.filter_factory: nova.api.openstack:FaultWrapper.factory
+    filter:noauth2:
+      paste.filter_factory: nova.api.openstack.auth:NoAuthMiddleware.factory
+    filter:sizelimit:
+      paste.filter_factory: oslo_middleware:RequestBodySizeLimiter.factory
+    filter:http_proxy_to_wsgi:
+      paste.filter_factory: oslo_middleware.http_proxy_to_wsgi:HTTPProxyToWSGI.factory
+    filter:legacy_v2_compatible:
+      paste.filter_factory: nova.api.openstack:LegacyV2CompatibleWrapper.factory
+    app:osapi_compute_app_v21:
+      paste.app_factory: nova.api.openstack.compute:APIRouterV21.factory
+    pipeline:oscomputeversions:
+      pipeline: faultwrap http_proxy_to_wsgi oscomputeversionapp
+    app:oscomputeversionapp:
+      paste.app_factory: nova.api.openstack.compute.versions:Versions.factory
+    filter:cors:
+      paste.filter_factory: oslo_middleware.cors:filter_factory
+      oslo_config_project: nova
+    filter:keystonecontext:
+      paste.filter_factory: nova.api.auth:NovaKeystoneContext.factory
+    filter:authtoken:
+      paste.filter_factory: keystonemiddleware.auth_token:filter_factory
+    filter:audit:
+      paste.filter_factory: keystonemiddleware.audit:filter_factory
+      audit_map_file: /etc/nova/api_audit_map.conf
+  policy: {}
+  nova_sudoers: |
+    # This sudoers file supports rootwrap for both Kolla and LOCI Images.
+    Defaults !requiretty
+    Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin:/var/lib/openstack/bin:/var/lib/kolla/venv/bin"
+    nova ALL = (root) NOPASSWD: /var/lib/kolla/venv/bin/nova-rootwrap /etc/nova/rootwrap.conf *, /var/lib/openstack/bin/nova-rootwrap /etc/nova/rootwrap.conf *
+  api_audit_map:
+    DEFAULT:
+      target_endpoint_type: None
+    custom_actions:
+      enable: enable
+      disable: disable
+      delete: delete
+      startup: start/startup
+      shutdown: stop/shutdown
+      reboot: start/reboot
+      os-migrations/get: read
+      os-server-password/post: update
+    path_keywords:
+      add: None
+      action: None
+      enable: None
+      disable: None
+      configure-project: None
+      defaults: None
+      delete: None
+      detail: None
+      diagnostics: None
+      entries: entry
+      extensions: alias
+      flavors: flavor
+      images: image
+      ips: label
+      limits: None
+      metadata: key
+      os-agents: os-agent
+      os-aggregates: os-aggregate
+      os-availability-zone: None
+      os-certificates: None
+      os-cloudpipe: None
+      os-fixed-ips: ip
+      os-extra_specs: key
+      os-flavor-access: None
+      os-floating-ip-dns: domain
+      os-floating-ips-bulk: host
+      os-floating-ip-pools: None
+      os-floating-ips: floating-ip
+      os-hosts: host
+      os-hypervisors: hypervisor
+      os-instance-actions: instance-action
+      os-keypairs: keypair
+      os-migrations: None
+      os-networks: network
+      os-quota-sets: tenant
+      os-security-groups: security_group
+      os-security-group-rules: rule
+      os-server-password: None
+      os-services: None
+      os-simple-tenant-usage: tenant
+      os-virtual-interfaces: None
+      os-volume_attachments: attachment
+      os-volumes_boot: None
+      os-volumes: volume
+      os-volume-types: volume-type
+      os-snapshots: snapshot
+      reboot: None
+      servers: server
+      shutdown: None
+      startup: None
+      statistics: None
+    service_endpoints:
+      compute: service/compute
+  rootwrap: |
+    # Configuration for nova-rootwrap
+    # This file should be owned by (and only-writeable by) the root user
+
+    [DEFAULT]
+    # List of directories to load filter definitions from (separated by ',').
+    # These directories MUST all be only writeable by root !
+    filters_path=/etc/nova/rootwrap.d,/usr/share/nova/rootwrap
+
+    # List of directories to search executables in, in case filters do not
+    # explicitely specify a full path (separated by ',')
+    # If not specified, defaults to system PATH environment variable.
+    # These directories MUST all be only writeable by root !
+    exec_dirs=/sbin,/usr/sbin,/bin,/usr/bin,/usr/local/bin,/usr/local/sbin,/var/lib/openstack/bin,/var/lib/kolla/venv/bin
+
+    # Enable logging to syslog
+    # Default value is False
+    use_syslog=False
+
+    # Which syslog facility to use.
+    # Valid values include auth, authpriv, syslog, local0, local1...
+    # Default value is 'syslog'
+    syslog_log_facility=syslog
+
+    # Which messages to log.
+    # INFO means log all usage
+    # ERROR means only log unsuccessful attempts
+    syslog_log_level=ERROR
+  wsgi_placement: |
+    Listen 0.0.0.0:{{ tuple "placement" "internal" "api" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}
+
+    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+    LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" proxy
+
+    SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded
+    CustomLog /dev/stdout combined env=!forwarded
+    CustomLog /dev/stdout proxy env=forwarded
+
+    <VirtualHost *:{{ tuple "placement" "internal" "api" . | include "helm-toolkit.endpoints.endpoint_port_lookup" }}>
+        WSGIDaemonProcess placement-api processes=4 threads=1 user=nova group=nova display-name=%{GROUP}
+        WSGIProcessGroup placement-api
+        WSGIScriptAlias / /var/www/cgi-bin/nova/nova-placement-api
+        WSGIApplicationGroup %{GLOBAL}
+        WSGIPassAuthorization On
+        <IfVersion >= 2.4>
+          ErrorLogFormat "%{cu}t %M"
+        </IfVersion>
+        ErrorLog /dev/stdout
+
+        SetEnvIf X-Forwarded-For "^.*\..*\..*\..*" forwarded
+        CustomLog /dev/stdout combined env=!forwarded
+        CustomLog /dev/stdout proxy env=forwarded
+    </VirtualHost>
+
+    Alias /placement /var/www/cgi-bin/nova/nova-placement-api
+    <Location /placement>
+        SetHandler wsgi-script
+        Options +ExecCGI
+
+        WSGIProcessGroup placement-api
+        WSGIApplicationGroup %{GLOBAL}
+        WSGIPassAuthorization On
+    </Location>
+  rootwrap_filters:
+    api_metadata:
+      pods:
+        - metadata
+      content: |
+        # nova-rootwrap command filters for api-metadata nodes
+        # This is needed on nova-api hosts running with "metadata" in enabled_apis
+        # or when running nova-api-metadata
+        # This file should be owned by (and only-writeable by) the root user
+
+        [Filters]
+        # nova/network/linux_net.py: 'ip[6]tables-save' % (cmd, '-t', ...
+        iptables-save: CommandFilter, iptables-save, root
+        ip6tables-save: CommandFilter, ip6tables-save, root
+
+        # nova/network/linux_net.py: 'ip[6]tables-restore' % (cmd,)
+        iptables-restore: CommandFilter, iptables-restore, root
+        ip6tables-restore: CommandFilter, ip6tables-restore, root
+    compute:
+      pods:
+        - compute
+      content: |
+        # nova-rootwrap command filters for compute nodes
+        # This file should be owned by (and only-writeable by) the root user
+
+        [Filters]
+        # nova/virt/disk/mount/api.py: 'kpartx', '-a', device
+        # nova/virt/disk/mount/api.py: 'kpartx', '-d', device
+        kpartx: CommandFilter, kpartx, root
+
+        # nova/virt/xenapi/vm_utils.py: tune2fs, -O ^has_journal, part_path
+        # nova/virt/xenapi/vm_utils.py: tune2fs, -j, partition_path
+        tune2fs: CommandFilter, tune2fs, root
+
+        # nova/virt/disk/mount/api.py: 'mount', mapped_device
+        # nova/virt/disk/api.py: 'mount', '-o', 'bind', src, target
+        # nova/virt/xenapi/vm_utils.py: 'mount', '-t', 'ext2,ext3,ext4,reiserfs'..
+        # nova/virt/configdrive.py: 'mount', device, mountdir
+        # nova/virt/libvirt/volume.py: 'mount', '-t', 'sofs' ...
+        mount: CommandFilter, mount, root
+
+        # nova/virt/disk/mount/api.py: 'umount', mapped_device
+        # nova/virt/disk/api.py: 'umount' target
+        # nova/virt/xenapi/vm_utils.py: 'umount', dev_path
+        # nova/virt/configdrive.py: 'umount', mountdir
+        umount: CommandFilter, umount, root
+
+        # nova/virt/disk/mount/nbd.py: 'qemu-nbd', '-c', device, image
+        # nova/virt/disk/mount/nbd.py: 'qemu-nbd', '-d', device
+        qemu-nbd: CommandFilter, qemu-nbd, root
+
+        # nova/virt/disk/mount/loop.py: 'losetup', '--find', '--show', image
+        # nova/virt/disk/mount/loop.py: 'losetup', '--detach', device
+        losetup: CommandFilter, losetup, root
+
+        # nova/virt/disk/vfs/localfs.py: 'blkid', '-o', 'value', '-s', 'TYPE', device
+        blkid: CommandFilter, blkid, root
+
+        # nova/virt/libvirt/utils.py: 'blockdev', '--getsize64', path
+        # nova/virt/disk/mount/nbd.py: 'blockdev', '--flushbufs', device
+        blockdev: RegExpFilter, blockdev, root, blockdev, (--getsize64|--flushbufs), /dev/.*
+
+        # nova/virt/disk/vfs/localfs.py: 'tee', canonpath
+        tee: CommandFilter, tee, root
+
+        # nova/virt/disk/vfs/localfs.py: 'mkdir', canonpath
+        mkdir: CommandFilter, mkdir, root
+
+        # nova/virt/disk/vfs/localfs.py: 'chown'
+        # nova/virt/libvirt/connection.py: 'chown', os.getuid( console_log
+        # nova/virt/libvirt/connection.py: 'chown', os.getuid( console_log
+        # nova/virt/libvirt/connection.py: 'chown', 'root', basepath('disk')
+        chown: CommandFilter, chown, root
+
+        # nova/virt/disk/vfs/localfs.py: 'chmod'
+        chmod: CommandFilter, chmod, root
+
+        # nova/virt/libvirt/vif.py: 'ip', 'tuntap', 'add', dev, 'mode', 'tap'
+        # nova/virt/libvirt/vif.py: 'ip', 'link', 'set', dev, 'up'
+        # nova/virt/libvirt/vif.py: 'ip', 'link', 'delete', dev
+        # nova/network/linux_net.py: 'ip', 'addr', 'add', str(floating_ip)+'/32'i..
+        # nova/network/linux_net.py: 'ip', 'addr', 'del', str(floating_ip)+'/32'..
+        # nova/network/linux_net.py: 'ip', 'addr', 'add', '169.254.169.254/32',..
+        # nova/network/linux_net.py: 'ip', 'addr', 'show', 'dev', dev, 'scope',..
+        # nova/network/linux_net.py: 'ip', 'addr', 'del/add', ip_params, dev)
+        # nova/network/linux_net.py: 'ip', 'addr', 'del', params, fields[-1]
+        # nova/network/linux_net.py: 'ip', 'addr', 'add', params, bridge
+        # nova/network/linux_net.py: 'ip', '-f', 'inet6', 'addr', 'change', ..
+        # nova/network/linux_net.py: 'ip', 'link', 'set', 'dev', dev, 'promisc',..
+        # nova/network/linux_net.py: 'ip', 'link', 'add', 'link', bridge_if ...
+        # nova/network/linux_net.py: 'ip', 'link', 'set', interface, address,..
+        # nova/network/linux_net.py: 'ip', 'link', 'set', interface, 'up'
+        # nova/network/linux_net.py: 'ip', 'link', 'set', bridge, 'up'
+        # nova/network/linux_net.py: 'ip', 'addr', 'show', 'dev', interface, ..
+        # nova/network/linux_net.py: 'ip', 'link', 'set', dev, address, ..
+        # nova/network/linux_net.py: 'ip', 'link', 'set', dev, 'up'
+        # nova/network/linux_net.py: 'ip', 'route', 'add', ..
+        # nova/network/linux_net.py: 'ip', 'route', 'del', .
+        # nova/network/linux_net.py: 'ip', 'route', 'show', 'dev', dev
+        ip: CommandFilter, ip, root
+
+        # nova/virt/libvirt/vif.py: 'tunctl', '-b', '-t', dev
+        # nova/network/linux_net.py: 'tunctl', '-b', '-t', dev
+        tunctl: CommandFilter, tunctl, root
+
+        # nova/virt/libvirt/vif.py: 'ovs-vsctl', ...
+        # nova/virt/libvirt/vif.py: 'ovs-vsctl', 'del-port', ...
+        # nova/network/linux_net.py: 'ovs-vsctl', ....
+        ovs-vsctl: CommandFilter, ovs-vsctl, root
+
+        # nova/virt/libvirt/vif.py: 'vrouter-port-control', ...
+        vrouter-port-control: CommandFilter, vrouter-port-control, root
+
+        # nova/virt/libvirt/vif.py: 'ebrctl', ...
+        ebrctl: CommandFilter, ebrctl, root
+
+        # nova/virt/libvirt/vif.py: 'mm-ctl', ...
+        mm-ctl: CommandFilter, mm-ctl, root
+
+        # nova/network/linux_net.py: 'ovs-ofctl', ....
+        ovs-ofctl: CommandFilter, ovs-ofctl, root
+
+        # nova/virt/libvirt/connection.py: 'dd', if=%s % virsh_output, ...
+        dd: CommandFilter, dd, root
+
+        # nova/virt/xenapi/volume_utils.py: 'iscsiadm', '-m', ...
+        iscsiadm: CommandFilter, iscsiadm, root
+
+        # nova/virt/libvirt/volume/aoe.py: 'aoe-revalidate', aoedev
+        # nova/virt/libvirt/volume/aoe.py: 'aoe-discover'
+        aoe-revalidate: CommandFilter, aoe-revalidate, root
+        aoe-discover: CommandFilter, aoe-discover, root
+
+        # nova/virt/xenapi/vm_utils.py: parted, --script, ...
+        # nova/virt/xenapi/vm_utils.py: 'parted', '--script', dev_path, ..*.
+        parted: CommandFilter, parted, root
+
+        # nova/virt/xenapi/vm_utils.py: 'pygrub', '-qn', dev_path
+        pygrub: CommandFilter, pygrub, root
+
+        # nova/virt/xenapi/vm_utils.py: fdisk %(dev_path)s
+        fdisk: CommandFilter, fdisk, root
+
+        # nova/virt/xenapi/vm_utils.py: e2fsck, -f, -p, partition_path
+        # nova/virt/disk/api.py: e2fsck, -f, -p, image
+        e2fsck: CommandFilter, e2fsck, root
+
+        # nova/virt/xenapi/vm_utils.py: resize2fs, partition_path
+        # nova/virt/disk/api.py: resize2fs, image
+        resize2fs: CommandFilter, resize2fs, root
+
+        # nova/network/linux_net.py: 'ip[6]tables-save' % (cmd, '-t', ...
+        iptables-save: CommandFilter, iptables-save, root
+        ip6tables-save: CommandFilter, ip6tables-save, root
+
+        # nova/network/linux_net.py: 'ip[6]tables-restore' % (cmd,)
+        iptables-restore: CommandFilter, iptables-restore, root
+        ip6tables-restore: CommandFilter, ip6tables-restore, root
+
+        # nova/network/linux_net.py: 'arping', '-U', floating_ip, '-A', '-I', ...
+        # nova/network/linux_net.py: 'arping', '-U', network_ref['dhcp_server'],..
+        arping: CommandFilter, arping, root
+
+        # nova/network/linux_net.py: 'dhcp_release', dev, address, mac_address
+        dhcp_release: CommandFilter, dhcp_release, root
+
+        # nova/network/linux_net.py: 'kill', '-9', pid
+        # nova/network/linux_net.py: 'kill', '-HUP', pid
+        kill_dnsmasq: KillFilter, root, /usr/sbin/dnsmasq, -9, -HUP
+
+        # nova/network/linux_net.py: 'kill', pid
+        kill_radvd: KillFilter, root, /usr/sbin/radvd
+
+        # nova/network/linux_net.py: dnsmasq call
+        dnsmasq: EnvFilter, env, root, CONFIG_FILE=, NETWORK_ID=, dnsmasq
+
+        # nova/network/linux_net.py: 'radvd', '-C', '%s' % _ra_file(dev, 'conf'..
+        radvd: CommandFilter, radvd, root
+
+        # nova/network/linux_net.py: 'brctl', 'addbr', bridge
+        # nova/network/linux_net.py: 'brctl', 'setfd', bridge, 0
+        # nova/network/linux_net.py: 'brctl', 'stp', bridge, 'off'
+        # nova/network/linux_net.py: 'brctl', 'addif', bridge, interface
+        brctl: CommandFilter, brctl, root
+
+        # nova/virt/libvirt/utils.py: 'mkswap'
+        # nova/virt/xenapi/vm_utils.py: 'mkswap'
+        mkswap: CommandFilter, mkswap, root
+
+        # nova/virt/libvirt/utils.py: 'nova-idmapshift'
+        nova-idmapshift: CommandFilter, nova-idmapshift, root
+
+        # nova/virt/xenapi/vm_utils.py: 'mkfs'
+        # nova/utils.py: 'mkfs', fs, path, label
+        mkfs: CommandFilter, mkfs, root
+
+        # nova/virt/libvirt/utils.py: 'qemu-img'
+        qemu-img: CommandFilter, qemu-img, root
+
+        # nova/virt/disk/vfs/localfs.py: 'readlink', '-e'
+        readlink: CommandFilter, readlink, root
+
+        # nova/virt/disk/api.py:
+        mkfs.ext3: CommandFilter, mkfs.ext3, root
+        mkfs.ext4: CommandFilter, mkfs.ext4, root
+        mkfs.ntfs: CommandFilter, mkfs.ntfs, root
+
+        # nova/virt/libvirt/connection.py:
+        lvremove: CommandFilter, lvremove, root
+
+        # nova/virt/libvirt/utils.py:
+        lvcreate: CommandFilter, lvcreate, root
+
+        # nova/virt/libvirt/utils.py:
+        lvs: CommandFilter, lvs, root
+
+        # nova/virt/libvirt/utils.py:
+        vgs: CommandFilter, vgs, root
+
+        # nova/utils.py:read_file_as_root: 'cat', file_path
+        # (called from nova/virt/disk/vfs/localfs.py:VFSLocalFS.read_file)
+        read_passwd: RegExpFilter, cat, root, cat, (/var|/usr)?/tmp/openstack-vfs-localfs[^/]+/etc/passwd
+        read_shadow: RegExpFilter, cat, root, cat, (/var|/usr)?/tmp/openstack-vfs-localfs[^/]+/etc/shadow
+
+        # os-brick needed commands
+        read_initiator: ReadFileFilter, /etc/iscsi/initiatorname.iscsi
+        multipath: CommandFilter, multipath, root
+        # multipathd show status
+        multipathd: CommandFilter, multipathd, root
+        systool: CommandFilter, systool, root
+        vgc-cluster: CommandFilter, vgc-cluster, root
+        # os_brick/initiator/connector.py
+        drv_cfg: CommandFilter, /opt/emc/scaleio/sdc/bin/drv_cfg, root, /opt/emc/scaleio/sdc/bin/drv_cfg, --query_guid
+
+        # TODO(smcginnis) Temporary fix.
+        # Need to pull in os-brick os-brick.filters file instead and clean
+        # out stale brick values from this file.
+        scsi_id: CommandFilter, /lib/udev/scsi_id, root
+        # os_brick.privileged.default oslo.privsep context
+        # This line ties the superuser privs with the config files, context name,
+        # and (implicitly) the actual python code invoked.
+        privsep-rootwrap: RegExpFilter, privsep-helper, root, privsep-helper, --config-file, /etc/(?!\.\.).*, --privsep_context, os_brick.privileged.default, --privsep_sock_path, /tmp/.*
+
+        # nova/storage/linuxscsi.py: sg_scan device
+        sg_scan: CommandFilter, sg_scan, root
+
+        # nova/volume/encryptors/cryptsetup.py:
+        # nova/volume/encryptors/luks.py:
+        ln: RegExpFilter, ln, root, ln, --symbolic, --force, /dev/mapper/crypt-.+, .+
+
+        # nova/volume/encryptors.py:
+        # nova/virt/libvirt/dmcrypt.py:
+        cryptsetup: CommandFilter, cryptsetup, root
+
+        # nova/virt/xenapi/vm_utils.py:
+        xenstore-read: CommandFilter, xenstore-read, root
+
+        # nova/virt/libvirt/utils.py:
+        rbd: CommandFilter, rbd, root
+
+        # nova/virt/libvirt/utils.py: 'shred', '-n3', '-s%d' % volume_size, path
+        shred: CommandFilter, shred, root
+
+        # nova/virt/libvirt/volume.py: 'cp', '/dev/stdin', delete_control..
+        cp: CommandFilter, cp, root
+
+        # nova/virt/xenapi/vm_utils.py:
+        sync: CommandFilter, sync, root
+
+        # nova/virt/libvirt/imagebackend.py:
+        ploop: RegExpFilter, ploop, root, ploop, restore-descriptor, .*
+        prl_disk_tool: RegExpFilter, prl_disk_tool, root, prl_disk_tool, resize, --size, .*M$, --resize_partition, --hdd, .*
+
+        # nova/virt/libvirt/utils.py: 'xend', 'status'
+        xend: CommandFilter, xend, root
+
+        # nova/virt/libvirt/utils.py:
+        touch: CommandFilter, touch, root
+
+        # nova/virt/libvirt/volume/vzstorage.py
+        pstorage-mount: CommandFilter, pstorage-mount, root
+    network:
+      pods:
+        - compute
+      content: |
+        # nova-rootwrap command filters for network nodes
+        # This file should be owned by (and only-writeable by) the root user
+
+        [Filters]
+        # nova/virt/libvirt/vif.py: 'ip', 'tuntap', 'add', dev, 'mode', 'tap'
+        # nova/virt/libvirt/vif.py: 'ip', 'link', 'set', dev, 'up'
+        # nova/virt/libvirt/vif.py: 'ip', 'link', 'delete', dev
+        # nova/network/linux_net.py: 'ip', 'addr', 'add', str(floating_ip)+'/32'i..
+        # nova/network/linux_net.py: 'ip', 'addr', 'del', str(floating_ip)+'/32'..
+        # nova/network/linux_net.py: 'ip', 'addr', 'add', '169.254.169.254/32',..
+        # nova/network/linux_net.py: 'ip', 'addr', 'show', 'dev', dev, 'scope',..
+        # nova/network/linux_net.py: 'ip', 'addr', 'del/add', ip_params, dev)
+        # nova/network/linux_net.py: 'ip', 'addr', 'del', params, fields[-1]
+        # nova/network/linux_net.py: 'ip', 'addr', 'add', params, bridge
+        # nova/network/linux_net.py: 'ip', '-f', 'inet6', 'addr', 'change', ..
+        # nova/network/linux_net.py: 'ip', 'link', 'set', 'dev', dev, 'promisc',..
+        # nova/network/linux_net.py: 'ip', 'link', 'add', 'link', bridge_if ...
+        # nova/network/linux_net.py: 'ip', 'link', 'set', interface, address,..
+        # nova/network/linux_net.py: 'ip', 'link', 'set', interface, 'up'
+        # nova/network/linux_net.py: 'ip', 'link', 'set', bridge, 'up'
+        # nova/network/linux_net.py: 'ip', 'addr', 'show', 'dev', interface, ..
+        # nova/network/linux_net.py: 'ip', 'link', 'set', dev, address, ..
+        # nova/network/linux_net.py: 'ip', 'link', 'set', dev, 'up'
+        # nova/network/linux_net.py: 'ip', 'route', 'add', ..
+        # nova/network/linux_net.py: 'ip', 'route', 'del', .
+        # nova/network/linux_net.py: 'ip', 'route', 'show', 'dev', dev
+        ip: CommandFilter, ip, root
+
+        # nova/virt/libvirt/vif.py: 'ovs-vsctl', ...
+        # nova/virt/libvirt/vif.py: 'ovs-vsctl', 'del-port', ...
+        # nova/network/linux_net.py: 'ovs-vsctl', ....
+        ovs-vsctl: CommandFilter, ovs-vsctl, root
+
+        # nova/network/linux_net.py: 'ovs-ofctl', ....
+        ovs-ofctl: CommandFilter, ovs-ofctl, root
+
+        # nova/virt/libvirt/vif.py: 'ivs-ctl', ...
+        # nova/virt/libvirt/vif.py: 'ivs-ctl', 'del-port', ...
+        # nova/network/linux_net.py: 'ivs-ctl', ....
+        ivs-ctl: CommandFilter, ivs-ctl, root
+
+        # nova/virt/libvirt/vif.py: 'ifc_ctl', ...
+        ifc_ctl: CommandFilter, /opt/pg/bin/ifc_ctl, root
+
+        # nova/network/linux_net.py: 'ebtables', '-D' ...
+        # nova/network/linux_net.py: 'ebtables', '-I' ...
+        ebtables: CommandFilter, ebtables, root
+        ebtables_usr: CommandFilter, ebtables, root
+
+        # nova/network/linux_net.py: 'ip[6]tables-save' % (cmd, '-t', ...
+        iptables-save: CommandFilter, iptables-save, root
+        ip6tables-save: CommandFilter, ip6tables-save, root
+
+        # nova/network/linux_net.py: 'ip[6]tables-restore' % (cmd,)
+        iptables-restore: CommandFilter, iptables-restore, root
+        ip6tables-restore: CommandFilter, ip6tables-restore, root
+
+        # nova/network/linux_net.py: 'arping', '-U', floating_ip, '-A', '-I', ...
+        # nova/network/linux_net.py: 'arping', '-U', network_ref['dhcp_server'],..
+        arping: CommandFilter, arping, root
+
+        # nova/network/linux_net.py: 'dhcp_release', dev, address, mac_address
+        dhcp_release: CommandFilter, dhcp_release, root
+
+        # nova/network/linux_net.py: 'kill', '-9', pid
+        # nova/network/linux_net.py: 'kill', '-HUP', pid
+        kill_dnsmasq: KillFilter, root, /usr/sbin/dnsmasq, -9, -HUP
+
+        # nova/network/linux_net.py: 'kill', pid
+        kill_radvd: KillFilter, root, /usr/sbin/radvd
+
+        # nova/network/linux_net.py: dnsmasq call
+        dnsmasq: EnvFilter, env, root, CONFIG_FILE=, NETWORK_ID=, dnsmasq
+
+        # nova/network/linux_net.py: 'radvd', '-C', '%s' % _ra_file(dev, 'conf'..
+        radvd: CommandFilter, radvd, root
+
+        # nova/network/linux_net.py: 'brctl', 'addbr', bridge
+        # nova/network/linux_net.py: 'brctl', 'setfd', bridge, 0
+        # nova/network/linux_net.py: 'brctl', 'stp', bridge, 'off'
+        # nova/network/linux_net.py: 'brctl', 'addif', bridge, interface
+        brctl: CommandFilter, brctl, root
+
+        # nova/network/linux_net.py: 'sysctl', ....
+        sysctl: CommandFilter, sysctl, root
+
+        # nova/network/linux_net.py: 'conntrack'
+        conntrack: CommandFilter, conntrack, root
+
+        # nova/network/linux_net.py: 'fp-vdev'
+        fp-vdev: CommandFilter, fp-vdev, root
+  nova_ironic:
+    DEFAULT:
+      scheduler_host_manager: ironic_host_manager
+      compute_driver: ironic.IronicDriver
+      ram_allocation_ratio: 1.0
+      cpu_allocation_ratio: 1.0
+      reserved_host_memory_mb: 0
+  libvirt:
+    # Get the IP address to be used as the target for live migration traffic using interface name.
+    # If this option is set to None, the hostname of the migration target compute node will be used.
+    live_migration_interface:
+  hypervisor:
+    # my_ip can be set automatically through this interface name.
+    host_interface:
+  # This list is the keys to exclude from the config file ingested by nova-compute
+  nova_compute_redactions:
+    - database
+    - api_database
+    - cell0_database
+  nova:
+    DEFAULT:
+      log_config_append: /etc/nova/logging.conf
+      default_ephemeral_format: ext4
+      ram_allocation_ratio: 1.0
+      disk_allocation_ratio: 1.0
+      cpu_allocation_ratio: 3.0
+      state_path: /var/lib/nova
+      osapi_compute_listen: 0.0.0.0
+      # NOTE(portdirect): the bind port should not be defined, and is manipulated
+      # via the endpoints section.
+      osapi_compute_listen_port: null
+      osapi_compute_workers: 1
+      metadata_workers: 1
+      use_neutron: true
+      firewall_driver: nova.virt.firewall.NoopFirewallDriver
+      linuxnet_interface_driver: openvswitch
+      compute_driver: libvirt.LibvirtDriver
+      my_ip: 0.0.0.0
+      instance_usage_audit: True
+      instance_usage_audit_period: hour
+      notify_on_state_change: vm_and_task_state
+      resume_guests_state_on_host_boot: True
+    vnc:
+      novncproxy_host: 0.0.0.0
+      vncserver_listen: 0.0.0.0
+      # This would be set by each compute nodes's ip
+      # server_proxyclient_address: 127.0.0.1
+    spice:
+      html5proxy_host: 0.0.0.0
+      server_listen: 0.0.0.0
+      # This would be set by each compute nodes's ip
+      # server_proxyclient_address: 127.0.0.1
+    conductor:
+      workers: 1
+    oslo_policy:
+      policy_file: /etc/nova/policy.yaml
+    oslo_concurrency:
+      lock_path: /var/lib/nova/tmp
+    oslo_middleware:
+      enable_proxy_headers_parsing: true
+    glance:
+      num_retries: 3
+    ironic:
+      api_endpoint: null
+      auth_url: null
+    neutron:
+      metadata_proxy_shared_secret: "password"
+      service_metadata_proxy: True
+      auth_type: password
+      auth_version: v3
+    database:
+      max_retries: -1
+    api_database:
+      max_retries: -1
+    cell0_database:
+      max_retries: -1
+    keystone_authtoken:
+      auth_type: password
+      auth_version: v3
+      memcache_security_strategy: ENCRYPT
+    service_user:
+      auth_type: password
+      send_service_user_token: false
+    libvirt:
+      connection_uri: "qemu+unix:///system?socket=/run/libvirt/libvirt-sock"
+      images_type: qcow2
+      images_rbd_pool: vms
+      images_rbd_ceph_conf: /etc/ceph/ceph.conf
+      rbd_user: cinder
+      rbd_secret_uuid: 457eb676-33da-42ec-9a8c-9293d545c337
+      disk_cachemodes: "network=writeback"
+      hw_disk_discard: unmap
+    upgrade_levels:
+      compute: auto
+    cache:
+      enabled: true
+      backend: dogpile.cache.memcached
+    wsgi:
+      api_paste_config: /etc/nova/api-paste.ini
+    oslo_messaging_notifications:
+      driver: messagingv2
+    oslo_messaging_rabbit:
+      rabbit_ha_queues: true
+    placement:
+      auth_type: password
+      auth_version: v3
+  logging:
+    loggers:
+      keys:
+        - root
+        - nova
+        - os.brick
+    handlers:
+      keys:
+        - stdout
+        - stderr
+        - "null"
+    formatters:
+      keys:
+        - context
+        - default
+    logger_root:
+      level: WARNING
+      handlers: 'null'
+    logger_nova:
+      level: INFO
+      handlers:
+        - stdout
+      qualname: nova
+    logger_os.brick:
+      level: INFO
+      handlers:
+        - stdout
+      qualname: os.brick
+    logger_amqp:
+      level: WARNING
+      handlers: stderr
+      qualname: amqp
+    logger_amqplib:
+      level: WARNING
+      handlers: stderr
+      qualname: amqplib
+    logger_eventletwsgi:
+      level: WARNING
+      handlers: stderr
+      qualname: eventlet.wsgi.server
+    logger_sqlalchemy:
+      level: WARNING
+      handlers: stderr
+      qualname: sqlalchemy
+    logger_boto:
+      level: WARNING
+      handlers: stderr
+      qualname: boto
+    handler_null:
+      class: logging.NullHandler
+      formatter: default
+      args: ()
+    handler_stdout:
+      class: StreamHandler
+      args: (sys.stdout,)
+      formatter: context
+    handler_stderr:
+      class: StreamHandler
+      args: (sys.stderr,)
+      formatter: context
+    formatter_context:
+      class: oslo_log.formatters.ContextFormatter
+      datefmt: "%Y-%m-%d %H:%M:%S"
+    formatter_default:
+      format: "%(message)s"
+      datefmt: "%Y-%m-%d %H:%M:%S"
+  rabbitmq:
+    # NOTE(rk760n): adding rmq policy to mirror messages from notification queues and set expiration time for the ones
+    policies:
+      - vhost: "nova"
+        name: "ha_ttl_nova"
+        definition:
+          # mirror messges to other nodes in rmq cluster
+          ha-mode: "all"
+          ha-sync-mode: "automatic"
+          # 70s
+          message-ttl: 70000
+        priority: 0
+        apply-to: all
+        pattern: '^(?!(amq\.|reply_)).*'
+  enable_iscsi: false
+  archive_deleted_rows:
+    purge_deleted_rows: false
+    until_completion: true
+    all_cells: false
+    max_rows:
+      enabled: False
+      rows: 1000
+    before:
+      enabled: false
+      date: 'nil'
+
+# Names of secrets used by bootstrap and environmental checks
+secrets:
+  identity:
+    admin: nova-keystone-admin
+    nova: nova-keystone-user
+    placement: nova-keystone-placement
+    test: nova-keystone-test
+  oslo_db:
+    admin: nova-db-admin
+    nova: nova-db-user
+  oslo_db_api:
+    admin: nova-db-api-admin
+    nova: nova-db-api-user
+  oslo_db_cell0:
+    admin: nova-db-cell0-admin
+    nova: nova-db-cell0-user
+  oslo_messaging:
+    admin: nova-rabbitmq-admin
+    nova: nova-rabbitmq-user
+  tls:
+    compute:
+      osapi:
+        public: nova-tls-public
+        internal: nova-tls-api
+    compute_novnc_proxy:
+      novncproxy:
+        public: nova-novncproxy-tls-public
+        internal: nova-novncproxy-tls-proxy
+    placement:
+      placement:
+        public: placement-tls-public
+        internal: placement-tls-api
+    compute_metadata:
+      metadata:
+        public: metadata-tls-public
+        internal: metadata-tls-metadata
+    compute_spice_proxy:
+      spiceproxy:
+        internal: nova-tls-spiceproxy
+
+# typically overridden by environmental
+# values, but should include all endpoints
+# required by this chart
+endpoints:
+  cluster_domain_suffix: cluster.local
+  local_image_registry:
+    name: docker-registry
+    namespace: docker-registry
+    hosts:
+      default: localhost
+      internal: docker-registry
+      node: localhost
+    host_fqdn_override:
+      default: null
+    port:
+      registry:
+        node: 5000
+  oslo_db:
+    auth:
+      admin:
+        username: root
+        password: password
+        secret:
+          tls:
+            internal: mariadb-tls-direct
+      nova:
+        username: nova
+        password: password
+    hosts:
+      default: mariadb
+    host_fqdn_override:
+      default: null
+    path: /nova
+    scheme: mysql+pymysql
+    port:
+      mysql:
+        default: 3306
+  oslo_db_api:
+    auth:
+      admin:
+        username: root
+        password: password
+      nova:
+        username: nova
+        password: password
+    hosts:
+      default: mariadb
+    host_fqdn_override:
+      default: null
+    path: /nova_api
+    scheme: mysql+pymysql
+    port:
+      mysql:
+        default: 3306
+  oslo_db_cell0:
+    auth:
+      admin:
+        username: root
+        password: password
+      nova:
+        username: nova
+        password: password
+    hosts:
+      default: mariadb
+    host_fqdn_override:
+      default: null
+    path: /nova_cell0
+    scheme: mysql+pymysql
+    port:
+      mysql:
+        default: 3306
+  oslo_messaging:
+    auth:
+      admin:
+        username: rabbitmq
+        password: password
+        secret:
+          tls:
+            internal: rabbitmq-tls-direct
+      nova:
+        username: nova
+        password: password
+    statefulset:
+      replicas: 2
+      name: rabbitmq-rabbitmq
+    hosts:
+      default: rabbitmq
+    host_fqdn_override:
+      default: null
+    path: /nova
+    scheme: rabbit
+    port:
+      amqp:
+        default: 5672
+      http:
+        default: 15672
+  oslo_cache:
+    auth:
+      # NOTE(portdirect): this is used to define the value for keystone
+      # authtoken cache encryption key, if not set it will be populated
+      # automatically with a random value, but to take advantage of
+      # this feature all services should be set to use the same key,
+      # and memcache service.
+      memcache_secret_key: null
+    hosts:
+      default: memcached
+    host_fqdn_override:
+      default: null
+    port:
+      memcache:
+        default: 11211
+  identity:
+    name: keystone
+    auth:
+      admin:
+        region_name: RegionOne
+        username: admin
+        password: password
+        project_name: admin
+        user_domain_name: default
+        project_domain_name: default
+      nova:
+        role: admin
+        region_name: RegionOne
+        username: nova
+        password: password
+        project_name: service
+        user_domain_name: service
+        project_domain_name: service
+      # NOTE(portdirect): the neutron user is not managed by the nova chart
+      # these values should match those set in the neutron chart.
+      neutron:
+        region_name: RegionOne
+        project_name: service
+        user_domain_name: service
+        project_domain_name: service
+        username: neutron
+        password: password
+      # NOTE(portdirect): the ironic user is not managed by the nova chart
+      # these values should match those set in the ironic chart.
+      ironic:
+        auth_type: password
+        auth_version: v3
+        region_name: RegionOne
+        project_name: service
+        user_domain_name: service
+        project_domain_name: service
+        username: ironic
+        password: password
+      placement:
+        role: admin
+        region_name: RegionOne
+        username: placement
+        password: password
+        project_name: service
+        user_domain_name: service
+        project_domain_name: service
+      test:
+        role: admin
+        region_name: RegionOne
+        username: nova-test
+        password: password
+        project_name: test
+        user_domain_name: service
+        project_domain_name: service
+    hosts:
+      default: keystone
+      internal: keystone-api
+    host_fqdn_override:
+      default: null
+    path:
+      default: /v3
+    scheme:
+      default: http
+    port:
+      api:
+        default: 80
+        internal: 5000
+  image:
+    name: glance
+    hosts:
+      default: glance-api
+      public: glance
+    host_fqdn_override:
+      default: null
+    path:
+      default: null
+    scheme:
+      default: http
+    port:
+      api:
+        default: 9292
+        public: 80
+  compute:
+    name: nova
+    hosts:
+      default: nova-api
+      public: nova
+    host_fqdn_override:
+      default: null
+      # NOTE(portdirect): this chart supports TLS for fqdn over-ridden public
+      # endpoints using the following format:
+      # public:
+      #   host: null
+      #   tls:
+      #     crt: null
+      #     key: null
+    path:
+      default: "/v2.1/%(tenant_id)s"
+    scheme:
+      default: 'http'
+    port:
+      api:
+        default: 8774
+        public: 80
+      novncproxy:
+        default: 6080
+  compute_metadata:
+    name: nova
+    ip:
+      # IF blank, set clusterIP and metadata_host dynamically
+      ingress: null
+    hosts:
+      default: nova-metadata
+      public: metadata
+    host_fqdn_override:
+      default: null
+    path:
+      default: /
+    scheme:
+      default: 'http'
+    port:
+      metadata:
+        default: 8775
+        public: 80
+  compute_novnc_proxy:
+    name: nova
+    hosts:
+      default: nova-novncproxy
+      public: novncproxy
+    host_fqdn_override:
+      default: null
+      # NOTE(portdirect): this chart supports TLS for fqdn over-ridden public
+      # endpoints using the following format:
+      # public:
+      #   host: null
+      #   tls:
+      #     crt: null
+      #     key: null
+    path:
+      default: /vnc_auto.html
+    scheme:
+      default: 'http'
+    port:
+      novnc_proxy:
+        default: 6080
+        public: 80
+  compute_spice_proxy:
+    name: nova
+    hosts:
+      default: nova-spiceproxy
+      public: placement
+    host_fqdn_override:
+      default: null
+    path:
+      default: /spice_auto.html
+    scheme:
+      default: 'http'
+    port:
+      spice_proxy:
+        default: 6082
+  placement:
+    name: placement
+    hosts:
+      default: placement-api
+      public: placement
+    host_fqdn_override:
+      default: null
+    path:
+      default: /
+    scheme:
+      default: 'http'
+    port:
+      api:
+        default: 8778
+        public: 80
+  network:
+    name: neutron
+    hosts:
+      default: neutron-server
+      public: neutron
+    host_fqdn_override:
+      default: null
+    path:
+      default: null
+    scheme:
+      default: 'http'
+    port:
+      api:
+        default: 9696
+        public: 80
+  baremetal:
+    name: ironic
+    hosts:
+      default: ironic-api
+      public: ironic
+    host_fqdn_override:
+      default: null
+    path:
+      default: null
+    scheme:
+      default: http
+    port:
+      api:
+        default: 6385
+        public: 80
+  fluentd:
+    namespace: null
+    name: fluentd
+    hosts:
+      default: fluentd-logging
+    host_fqdn_override:
+      default: null
+    path:
+      default: null
+    scheme: 'http'
+    port:
+      service:
+        default: 24224
+      metrics:
+        default: 24220
+  # NOTE(tp6510): these endpoints allow for things like DNS lookups and ingress
+  # They are using to enable the Egress K8s network policy.
+  kube_dns:
+    namespace: kube-system
+    name: kubernetes-dns
+    hosts:
+      default: kube-dns
+    host_fqdn_override:
+      default: null
+    path:
+      default: null
+    scheme: http
+    port:
+      dns:
+        default: 53
+        protocol: UDP
+  ingress:
+    namespace: null
+    name: ingress
+    hosts:
+      default: ingress
+    port:
+      ingress:
+        default: 80
+
+pod:
+  probes:
+    rpc_timeout: 60
+    rpc_retries: 2
+    compute:
+      default:
+        liveness:
+          enabled: True
+          params:
+            initialDelaySeconds: 120
+            periodSeconds: 90
+            timeoutSeconds: 70
+        readiness:
+          enabled: True
+          params:
+            initialDelaySeconds: 80
+            periodSeconds: 90
+            timeoutSeconds: 70
+    api-metadata:
+      default:
+        liveness:
+          enabled: True
+          params:
+            initialDelaySeconds: 30
+            periodSeconds: 60
+            timeoutSeconds: 15
+        readiness:
+          enabled: True
+          params:
+            initialDelaySeconds: 30
+            periodSeconds: 60
+            timeoutSeconds: 15
+    api-osapi:
+      default:
+        liveness:
+          enabled: True
+          params:
+            initialDelaySeconds: 30
+            periodSeconds: 60
+            timeoutSeconds: 15
+        readiness:
+          enabled: True
+          params:
+            initialDelaySeconds: 30
+            periodSeconds: 60
+            timeoutSeconds: 15
+    conductor:
+      default:
+        liveness:
+          enabled: True
+          params:
+            initialDelaySeconds: 120
+            periodSeconds: 90
+            timeoutSeconds: 70
+        readiness:
+          enabled: True
+          params:
+            initialDelaySeconds: 80
+            periodSeconds: 90
+            timeoutSeconds: 70
+    consoleauth:
+      default:
+        liveness:
+          enabled: True
+          params:
+            initialDelaySeconds: 120
+            periodSeconds: 90
+            timeoutSeconds: 70
+        readiness:
+          enabled: True
+          params:
+            initialDelaySeconds: 80
+            periodSeconds: 90
+            timeoutSeconds: 70
+    novncproxy:
+      default:
+        liveness:
+          enabled: True
+          params:
+            initialDelaySeconds: 30
+            periodSeconds: 60
+            timeoutSeconds: 15
+        readiness:
+          enabled: True
+          params:
+            initialDelaySeconds: 30
+            periodSeconds: 60
+            timeoutSeconds: 15
+    placement:
+      default:
+        liveness:
+          enabled: True
+          params:
+            initialDelaySeconds: 50
+            periodSeconds: 30
+            timeoutSeconds: 10
+        readiness:
+          enabled: True
+          params:
+            initialDelaySeconds: 15
+            periodSeconds: 30
+            timeoutSeconds: 10
+    scheduler:
+      default:
+        liveness:
+          enabled: True
+          params:
+            initialDelaySeconds: 120
+            periodSeconds: 90
+            timeoutSeconds: 70
+        readiness:
+          enabled: True
+          params:
+            initialDelaySeconds: 80
+            periodSeconds: 90
+            timeoutSeconds: 70
+    compute-spice-proxy:
+      default:
+        liveness:
+          enabled: True
+          params:
+            initialDelaySeconds: 30
+            periodSeconds: 60
+            timeoutSeconds: 15
+        readiness:
+          enabled: True
+          params:
+            initialDelaySeconds: 30
+            periodSeconds: 60
+            timeoutSeconds: 15
+  security_context:
+    nova:
+      pod:
+        runAsUser: 42424
+      container:
+        nova_compute_init:
+          readOnlyRootFilesystem: true
+          runAsUser: 0
+        tungstenfabric_compute_init:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+        ceph_perms:
+          readOnlyRootFilesystem: true
+          runAsUser: 0
+        ceph_admin_keyring_placement:
+          readOnlyRootFilesystem: true
+        ceph_keyring_placement:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+        nova_compute_vnc_init:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+        nova_compute_spice_init:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+        nova_compute:
+          readOnlyRootFilesystem: true
+          privileged: true
+        nova_compute_ssh:
+          privileged: true
+          runAsUser: 0
+        nova_compute_ssh_init:
+          runAsUser: 0
+        nova_api_metadata_init:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+        nova_api:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+        nova_osapi:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+        nova_conductor:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+        nova_consoleauth:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+        nova_novncproxy_init:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+        nova_novncproxy_init_assests:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+        nova_novncproxy:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+        nova_placement_api:
+          readOnlyRootFilesystem: false
+          allowPrivilegeEscalation: false
+        nova_scheduler:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+        nova_spiceproxy_init:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+        nova_spiceproxy_init_assets:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+        nova_spiceproxy:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+    bootstrap:
+      pod:
+        runAsUser: 42424
+      container:
+        nova_wait_for_computes_init:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+        bootstrap:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+    nova_cell_setup:
+      pod:
+        runAsUser: 42424
+      container:
+        nova_wait_for_computes_init:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+        nova_cell_setup_init:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+        nova_cell_setup:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+    archive_deleted_rows:
+      pod:
+        runAsUser: 42424
+      container:
+        nova_archive_deleted_rows_init:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+        nova_archive_deleted_rows:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+    cell_setup:
+      pod:
+        runAsUser: 42424
+      container:
+        nova_cell_setup:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+    service_cleaner:
+      pod:
+        runAsUser: 42424
+      container:
+        nova_service_cleaner:
+          readOnlyRootFilesystem: true
+          allowPrivilegeEscalation: false
+  use_fqdn:
+    # NOTE: If the option "host" is not specified in nova.conf, the host name
+    # shown in the hypervisor host is defaulted to the short name of the host.
+    # Setting the option here to true will cause use $(hostname --fqdn) as the
+    # host name by default. If the short name is desired $(hostname --short),
+    # set the option to false. Specifying a host in the nova.conf via the conf:
+    # section will supersede the value of this option.
+    compute: true
+  affinity:
+    anti:
+      type:
+        default: preferredDuringSchedulingIgnoredDuringExecution
+      topologyKey:
+        default: kubernetes.io/hostname
+      weight:
+        default: 10
+  mounts:
+    nova_compute:
+      init_container: null
+      nova_compute:
+        volumeMounts:
+        volumes:
+    nova_compute_ironic:
+      init_container: null
+      nova_compute_ironic:
+        volumeMounts:
+        volumes:
+    nova_api_metadata:
+      init_container: null
+      nova_api_metadata:
+        volumeMounts:
+        volumes:
+    nova_placement:
+      init_container: null
+      nova_placement:
+        volumeMounts:
+        volumes:
+    nova_api_osapi:
+      init_container: null
+      nova_api_osapi:
+        volumeMounts:
+        volumes:
+    nova_consoleauth:
+      init_container: null
+      nova_consoleauth:
+        volumeMounts:
+        volumes:
+    nova_conductor:
+      init_container: null
+      nova_conductor:
+        volumeMounts:
+        volumes:
+    nova_scheduler:
+      init_container: null
+      nova_scheduler:
+        volumeMounts:
+        volumes:
+    nova_bootstrap:
+      init_container: null
+      nova_bootstrap:
+        volumeMounts:
+        volumes:
+    nova_tests:
+      init_container: null
+      nova_tests:
+        volumeMounts:
+        volumes:
+    nova_novncproxy:
+      init_novncproxy: null
+      nova_novncproxy:
+        volumeMounts:
+        volumes:
+    nova_spiceproxy:
+      init_spiceproxy: null
+      nova_spiceproxy:
+        volumeMounts:
+        volumes:
+    nova_db_sync:
+      nova_db_sync:
+        volumeMounts:
+        volumes:
+  useHostNetwork:
+    novncproxy: true
+  replicas:
+    api_metadata: 1
+    compute_ironic: 1
+    placement: 1
+    osapi: 1
+    conductor: 1
+    consoleauth: 1
+    scheduler: 1
+    novncproxy: 1
+    spiceproxy: 1
+  lifecycle:
+    upgrades:
+      deployments:
+        revision_history: 3
+        pod_replacement_strategy: RollingUpdate
+        rolling_update:
+          max_unavailable: 1
+          max_surge: 3
+      daemonsets:
+        pod_replacement_strategy: RollingUpdate
+        compute:
+          enabled: true
+          min_ready_seconds: 0
+          max_unavailable: 1
+    disruption_budget:
+      metadata:
+        min_available: 0
+      placement:
+        min_available: 0
+      osapi:
+        min_available: 0
+    termination_grace_period:
+      metadata:
+        timeout: 30
+      placement:
+        timeout: 30
+      osapi:
+        timeout: 30
+  resources:
+    enabled: false
+    compute:
+      requests:
+        memory: "128Mi"
+        cpu: "100m"
+      limits:
+        memory: "1024Mi"
+        cpu: "2000m"
+    compute_ironic:
+      requests:
+        memory: "128Mi"
+        cpu: "100m"
+      limits:
+        memory: "1024Mi"
+        cpu: "2000m"
+    api_metadata:
+      requests:
+        memory: "128Mi"
+        cpu: "100m"
+      limits:
+        memory: "1024Mi"
+        cpu: "2000m"
+    placement:
+      requests:
+        memory: "128Mi"
+        cpu: "100m"
+      limits:
+        memory: "1024Mi"
+        cpu: "2000m"
+    api:
+      requests:
+        memory: "128Mi"
+        cpu: "100m"
+      limits:
+        memory: "1024Mi"
+        cpu: "2000m"
+    conductor:
+      requests:
+        memory: "128Mi"
+        cpu: "100m"
+      limits:
+        memory: "1024Mi"
+        cpu: "2000m"
+    consoleauth:
+      requests:
+        memory: "128Mi"
+        cpu: "100m"
+      limits:
+        memory: "1024Mi"
+        cpu: "2000m"
+    scheduler:
+      requests:
+        memory: "128Mi"
+        cpu: "100m"
+      limits:
+        memory: "1024Mi"
+        cpu: "2000m"
+    ssh:
+      requests:
+        memory: "128Mi"
+        cpu: "100m"
+      limits:
+        memory: "1024Mi"
+        cpu: "2000m"
+    novncproxy:
+      requests:
+        memory: "128Mi"
+        cpu: "100m"
+      limits:
+        memory: "1024Mi"
+        cpu: "2000m"
+    spiceproxy:
+      requests:
+        memory: "128Mi"
+        cpu: "100m"
+      limits:
+        memory: "1024Mi"
+        cpu: "2000m"
+    jobs:
+      bootstrap:
+        requests:
+          memory: "128Mi"
+          cpu: "100m"
+        limits:
+          memory: "1024Mi"
+          cpu: "2000m"
+      db_init:
+        requests:
+          memory: "128Mi"
+          cpu: "100m"
+        limits:
+          memory: "1024Mi"
+          cpu: "2000m"
+      rabbit_init:
+        requests:
+          memory: "128Mi"
+          cpu: "100m"
+        limits:
+          memory: "1024Mi"
+          cpu: "2000m"
+      db_sync:
+        requests:
+          memory: "128Mi"
+          cpu: "100m"
+        limits:
+          memory: "1024Mi"
+          cpu: "2000m"
+      archive_deleted_rows:
+        requests:
+          memory: "128Mi"
+          cpu: "100m"
+        limits:
+          memory: "1024Mi"
+          cpu: "2000m"
+      db_drop:
+        requests:
+          memory: "128Mi"
+          cpu: "100m"
+        limits:
+          memory: "1024Mi"
+          cpu: "2000m"
+      ks_endpoints:
+        requests:
+          memory: "128Mi"
+          cpu: "100m"
+        limits:
+          memory: "1024Mi"
+          cpu: "2000m"
+      ks_service:
+        requests:
+          memory: "128Mi"
+          cpu: "100m"
+        limits:
+          memory: "1024Mi"
+          cpu: "2000m"
+      ks_user:
+        requests:
+          memory: "128Mi"
+          cpu: "100m"
+        limits:
+          memory: "1024Mi"
+          cpu: "2000m"
+      tests:
+        requests:
+          memory: "128Mi"
+          cpu: "100m"
+        limits:
+          memory: "1024Mi"
+          cpu: "2000m"
+      cell_setup:
+        requests:
+          memory: "128Mi"
+          cpu: "100m"
+        limits:
+          memory: "1024Mi"
+          cpu: "2000m"
+      service_cleaner:
+        requests:
+          memory: "128Mi"
+          cpu: "100m"
+        limits:
+          memory: "1024Mi"
+          cpu: "2000m"
+      image_repo_sync:
+        requests:
+          memory: "128Mi"
+          cpu: "100m"
+        limits:
+          memory: "1024Mi"
+          cpu: "2000m"
+
+network_policy:
+  nova:
+    # TODO(lamt): Need to tighten this ingress for security.
+    ingress:
+      - {}
+    egress:
+      - {}
+  placement:
+    # TODO(lamt): Need to tighten this ingress for security.
+    ingress:
+      - {}
+    egress:
+      - {}
+
+# NOTE(helm_hook): helm_hook might break for helm2 binary.
+# set helm3_hook: false when using the helm2 binary.
+helm3_hook: true
+
+health_probe:
+  logging:
+    level: ERROR
+
+manifests:
+  certificates: false
+  configmap_bin: true
+  configmap_etc: true
+  cron_job_cell_setup: true
+  cron_job_service_cleaner: true
+  cron_job_archive_deleted_rows: false
+  daemonset_compute: true
+  deployment_api_metadata: true
+  deployment_api_osapi: true
+  deployment_placement: true
+  deployment_conductor: true
+  deployment_consoleauth: true
+  deployment_novncproxy: true
+  deployment_spiceproxy: true
+  deployment_scheduler: true
+  ingress_metadata: true
+  ingress_novncproxy: true
+  ingress_placement: true
+  ingress_osapi: true
+  job_bootstrap: true
+  job_db_init: true
+  job_db_init_placement: true
+  job_db_sync: true
+  job_db_drop: false
+  job_image_repo_sync: true
+  job_rabbit_init: true
+  job_ks_endpoints: true
+  job_ks_service: true
+  job_ks_user: true
+  job_ks_placement_endpoints: true
+  job_ks_placement_service: true
+  job_ks_placement_user: true
+  job_cell_setup: true
+  pdb_metadata: true
+  pdb_placement: true
+  pdb_osapi: true
+  pod_rally_test: true
+  network_policy: false
+  secret_db_api: true
+  secret_db_cell0: true
+  secret_db: true
+  secret_ingress_tls: true
+  secret_keystone: true
+  secret_keystone_placement: true
+  secret_rabbitmq: true
+  service_ingress_metadata: true
+  service_ingress_novncproxy: true
+  service_ingress_placement: true
+  service_ingress_osapi: true
+  service_metadata: true
+  service_placement: true
+  service_novncproxy: true
+  service_spiceproxy: true
+  service_osapi: true
+  statefulset_compute_ironic: false
+...