From c7e2eb9e255e720c94b8302196e384eb60a80b6c Mon Sep 17 00:00:00 2001
From: portdirect <pete@port.direct>
Date: Sun, 18 Feb 2018 16:19:02 -0500
Subject: [PATCH] Bootstrap jobs: move template to helm toolkit

This PS moves the templates for bootstrap jobs to helm-toolkit.

Change-Id: I0fc0f7722cfc87b00e26510dee7ba79d2139a171
---
 barbican/templates/job-bootstrap.yaml         | 54 +----------
 barbican/values.yaml                          |  1 +
 ceilometer/templates/job-bootstrap.yaml       | 20 ++++
 ceilometer/values.yaml                        |  7 ++
 cinder/templates/job-bootstrap.yaml           | 57 +----------
 cinder/values.yaml                            |  1 +
 congress/templates/job-bootstrap.yaml         | 20 ++++
 congress/values.yaml                          | 17 +++-
 glance/templates/bin/_bootstrap.sh.tpl        |  6 +-
 glance/templates/job-bootstrap.yaml           | 68 +++-----------
 glance/values.yaml                            | 31 +++---
 gnocchi/templates/job-bootstrap.yaml          | 20 ++++
 gnocchi/values.yaml                           |  7 ++
 heat/templates/job-bootstrap.yaml             | 54 +----------
 heat/values.yaml                              |  1 +
 .../templates/manifests/_job-bootstrap.yaml   | 94 +++++++++++++++++++
 ironic/templates/job-bootstrap.yaml           | 50 +---------
 ironic/values.yaml                            |  3 +-
 keystone/templates/job-bootstrap.yaml         | 90 +-----------------
 keystone/values.yaml                          |  1 +
 magnum/templates/job-bootstrap.yaml           | 54 +----------
 magnum/values.yaml                            |  1 +
 mistral/templates/job-bootstrap.yaml          | 53 +----------
 mistral/values.yaml                           |  1 +
 neutron/templates/job-bootstrap.yaml          | 53 +----------
 neutron/values.yaml                           |  3 +-
 nova/templates/bin/_bootstrap.sh.tpl          |  5 +-
 nova/templates/job-bootstrap.yaml             | 62 +-----------
 nova/values.yaml                              | 68 +++++++-------
 senlin/templates/job-bootstrap.yaml           | 53 +----------
 senlin/values.yaml                            |  1 +
 tools/overrides/releases/newton/kolla.yaml    |  2 -
 32 files changed, 289 insertions(+), 669 deletions(-)
 create mode 100644 ceilometer/templates/job-bootstrap.yaml
 create mode 100644 congress/templates/job-bootstrap.yaml
 create mode 100644 gnocchi/templates/job-bootstrap.yaml
 create mode 100644 helm-toolkit/templates/manifests/_job-bootstrap.yaml

diff --git a/barbican/templates/job-bootstrap.yaml b/barbican/templates/job-bootstrap.yaml
index 537ba80d72..ba1d10ab9e 100644
--- a/barbican/templates/job-bootstrap.yaml
+++ b/barbican/templates/job-bootstrap.yaml
@@ -14,55 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */}}
 
-{{- if .Values.manifests.job_bootstrap }}
-{{- $envAll := . }}
-{{- if .Values.bootstrap.enabled }}
-{{- $dependencies := .Values.dependencies.bootstrap }}
-
-{{- $mounts_barbican_bootstrap := .Values.pod.mounts.barbican_bootstrap.barbican_bootstrap }}
-{{- $mounts_barbican_bootstrap_init := .Values.pod.mounts.barbican_bootstrap.init_container }}
-
-{{- $serviceAccountName := "barbican-bootstrap" }}
-{{ tuple $envAll $dependencies $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
----
-apiVersion: batch/v1
-kind: Job
-metadata:
-  name: barbican-bootstrap
-spec:
-  template:
-    metadata:
-      labels:
-{{ tuple $envAll "barbican" "bootstrap" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
-    spec:
-      serviceAccountName: {{ $serviceAccountName }}
-      restartPolicy: OnFailure
-      nodeSelector:
-        {{ .Values.labels.job.node_selector_key }}: {{ .Values.labels.job.node_selector_value }}
-      initContainers:
-{{ tuple $envAll $dependencies $mounts_barbican_bootstrap_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container"  | indent 8 }}
-      containers:
-        - name: barbican-bootstrap
-          image: {{ .Values.images.tags.bootstrap }}
-          imagePullPolicy: {{ .Values.images.pull_policy }}
-{{ tuple $envAll $envAll.Values.pod.resources.jobs.bootstrap | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
-          env:
-{{- with $env := dict "ksUserSecret" .Values.secrets.identity.admin }}
-{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 12 }}
-{{- end }}
-          command:
-            - /tmp/bootstrap.sh
-          volumeMounts:
-            - name: barbican-bin
-              mountPath: /tmp/bootstrap.sh
-              subPath: bootstrap.sh
-              readOnly: true
-{{ if $mounts_barbican_bootstrap.volumeMounts }}{{ toYaml $mounts_barbican_bootstrap.volumeMounts | indent 12 }}{{ end }}
-      volumes:
-        - name: barbican-bin
-          configMap:
-            name: barbican-bin
-            defaultMode: 0555
-{{ if $mounts_barbican_bootstrap.volumes }}{{ toYaml $mounts_barbican_bootstrap.volumes | indent 8 }}{{ end }}
-{{- end }}
+{{- if and .Values.manifests.job_bootstrap .Values.bootstrap.enabled }}
+{{- $bootstrapJob := dict "envAll" . "serviceName" "barbican" "keystoneUser" .Values.bootstrap.ks_user -}}
+{{ $bootstrapJob | include "helm-toolkit.manifests.job_bootstrap" }}
 {{- end }}
diff --git a/barbican/values.yaml b/barbican/values.yaml
index fb793ba324..6ebf5c4a27 100644
--- a/barbican/values.yaml
+++ b/barbican/values.yaml
@@ -148,6 +148,7 @@ network:
 
 bootstrap:
   enabled: false
+  ks_user: barbican
   script: |
     openstack token issue
 
diff --git a/ceilometer/templates/job-bootstrap.yaml b/ceilometer/templates/job-bootstrap.yaml
new file mode 100644
index 0000000000..8d56fa00be
--- /dev/null
+++ b/ceilometer/templates/job-bootstrap.yaml
@@ -0,0 +1,20 @@
+{{/*
+Copyright 2017 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 and .Values.manifests.job_bootstrap .Values.bootstrap.enabled }}
+{{- $bootstrapJob := dict "envAll" . "serviceName" "ceilometer" "keystoneUser" .Values.bootstrap.ks_user -}}
+{{ $bootstrapJob | include "helm-toolkit.manifests.job_bootstrap" }}
+{{- end }}
diff --git a/ceilometer/values.yaml b/ceilometer/values.yaml
index 4e9b883dc3..f700377d67 100644
--- a/ceilometer/values.yaml
+++ b/ceilometer/values.yaml
@@ -1609,6 +1609,12 @@ secrets:
     admin: ceilometer-mongodb-admin
     ceilometer: ceilometer-mongodb-user
 
+bootstrap:
+  enabled: false
+  ks_user: ceilometer
+  script: |
+    openstack token issue
+
 # typically overriden by environmental
 # values, but should include all endpoints
 # required by this chart
@@ -1914,6 +1920,7 @@ manifests:
   deployment_compute: true
   deployment_notification: true
   ingress_api: true
+  job_bootstrap: true
   job_db_init: true
   job_db_init_mongodb: true
   job_db_sync: true
diff --git a/cinder/templates/job-bootstrap.yaml b/cinder/templates/job-bootstrap.yaml
index 0893a975ef..4b5d048b66 100644
--- a/cinder/templates/job-bootstrap.yaml
+++ b/cinder/templates/job-bootstrap.yaml
@@ -14,58 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */}}
 
-{{- if .Values.manifests.job_bootstrap }}
-{{- $envAll := . }}
-{{- if .Values.bootstrap.enabled }}
-{{- $dependencies := .Values.dependencies.bootstrap }}
-
-{{- $serviceAccountName := "cinder-bootstrap" }}
-{{ tuple $envAll $dependencies $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
----
-apiVersion: batch/v1
-kind: Job
-metadata:
-  name: cinder-bootstrap
-spec:
-  template:
-    metadata:
-      labels:
-{{ tuple $envAll "cinder" "bootstrap" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
-    spec:
-      serviceAccountName: {{ $serviceAccountName }}
-      restartPolicy: OnFailure
-      nodeSelector:
-        {{ .Values.labels.job.node_selector_key }}: {{ .Values.labels.job.node_selector_value }}
-      initContainers:
-{{ tuple $envAll $dependencies list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
-      containers:
-        - name: cinder-bootstrap
-          image: {{ .Values.images.tags.bootstrap }}
-          imagePullPolicy: {{ .Values.images.pull_policy }}
-{{ tuple $envAll $envAll.Values.pod.resources.jobs.bootstrap | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
-          command:
-            - /tmp/bootstrap.sh
-          env:
-{{- with $env := dict "ksUserSecret" .Values.secrets.identity.admin }}
-{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 12 }}
-{{- end }}
-          volumeMounts:
-            - name: cinder-etc
-              mountPath: /etc/cinder/cinder.conf
-              subPath: cinder.conf
-              readOnly: true
-            - name: cinder-bin
-              mountPath: /tmp/bootstrap.sh
-              subPath: bootstrap.sh
-              readOnly: true
-      volumes:
-        - name: cinder-etc
-          configMap:
-            name: cinder-etc
-            defaultMode: 0444
-        - name: cinder-bin
-          configMap:
-            name: cinder-bin
-            defaultMode: 0555
-{{- end }}
+{{- if and .Values.manifests.job_bootstrap .Values.bootstrap.enabled }}
+{{- $bootstrapJob := dict "envAll" . "serviceName" "cinder" "keystoneUser" .Values.bootstrap.ks_user -}}
+{{ $bootstrapJob | include "helm-toolkit.manifests.job_bootstrap" }}
 {{- end }}
diff --git a/cinder/values.yaml b/cinder/values.yaml
index 0128827635..80b82763e4 100644
--- a/cinder/values.yaml
+++ b/cinder/values.yaml
@@ -224,6 +224,7 @@ pod:
 
 bootstrap:
   enabled: true
+  ks_user: admin
   bootstrap_conf_backends: true
   volume_types:
     name:
diff --git a/congress/templates/job-bootstrap.yaml b/congress/templates/job-bootstrap.yaml
new file mode 100644
index 0000000000..88b80cbaa7
--- /dev/null
+++ b/congress/templates/job-bootstrap.yaml
@@ -0,0 +1,20 @@
+{{/*
+Copyright 2017 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 and .Values.manifests.job_bootstrap .Values.bootstrap.enabled }}
+{{- $bootstrapJob := dict "envAll" . "serviceName" "congress" "keystoneUser" .Values.bootstrap.ks_user -}}
+{{ $bootstrapJob | include "helm-toolkit.manifests.job_bootstrap" }}
+{{- end }}
diff --git a/congress/values.yaml b/congress/values.yaml
index 7ad70f96f0..4f10da2921 100644
--- a/congress/values.yaml
+++ b/congress/values.yaml
@@ -156,6 +156,12 @@ secrets:
     congress: congress-db-user
   rbd: images-rbd-keyring
 
+bootstrap:
+  enabled: false
+  ks_user: congress
+  script: |
+    openstack token issue
+
 endpoints:
   cluster_domain_suffix: cluster.local
   identity:
@@ -433,16 +439,17 @@ manifests:
   configmap_bin: true
   configmap_etc: true
   deployment_api: true
-  deployment_policy_engine: true
   deployment_datasource: true
+  deployment_policy_engine: true
+  ingress_api: true
+  job_bootstrap: true
   job_db_init: true
   job_db_sync: true
-  secret_db: true
-  secret_keystone: true
+  job_ds_create: true
   job_ks_endpoints: true
   job_ks_service: true
   job_ks_user: true
-  job_ds_create: true
+  secret_db: true
+  secret_keystone: true
   service_api: true
-  ingress_api: true
   service_ingress_api: true
diff --git a/glance/templates/bin/_bootstrap.sh.tpl b/glance/templates/bin/_bootstrap.sh.tpl
index 7952084456..ddd6ebe960 100644
--- a/glance/templates/bin/_bootstrap.sh.tpl
+++ b/glance/templates/bin/_bootstrap.sh.tpl
@@ -18,11 +18,10 @@ limitations under the License.
 
 set -ex
 export HOME=/tmp
-{{ if .Values.bootstrap.enabled }}
 
 cd /tmp/images
 
-{{ range .Values.bootstrap.images }}
+{{ range .Values.bootstrap.structured.images }}
 openstack image show {{ .name  | quote }} || \
   { curl -O {{ .source_url }}{{ .image_file }}; \
   openstack image create {{ .name | quote }} \
@@ -39,5 +38,4 @@ openstack image show {{ .name  | quote }} || \
   {{- end -}}; }
 {{ end }}
 
-{{ end }}
-exit 0
+{{ .Values.bootstrap.script | default "echo 'Not Enabled'" }}
diff --git a/glance/templates/job-bootstrap.yaml b/glance/templates/job-bootstrap.yaml
index d161011df2..d26ea7849a 100644
--- a/glance/templates/job-bootstrap.yaml
+++ b/glance/templates/job-bootstrap.yaml
@@ -14,60 +14,18 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */}}
 
-{{- if .Values.manifests.job_bootstrap }}
-{{- $envAll := . }}
-{{- $dependencies := .Values.dependencies.bootstrap }}
+{{- define "glance.templates._job_bootstrap.pod_volumes" -}}
+{{- $envAll := index . 0 -}}
+volumeMounts:
+  - name: imagedir
+    mountPath: /tmp/images
+volumes:
+  - name: imagedir
+    emptyDir: {}
+{{- end }}
 
-{{- $serviceAccountName := "glance-bootstrap" }}
-{{ tuple $envAll $dependencies $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
----
-apiVersion: batch/v1
-kind: Job
-metadata:
-  name: glance-bootstrap
-spec:
-  template:
-    metadata:
-      labels:
-{{ tuple $envAll "glance" "bootstrap" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
-    spec:
-      serviceAccountName: {{ $serviceAccountName }}
-      restartPolicy: OnFailure
-      nodeSelector:
-        {{ .Values.labels.job.node_selector_key }}: {{ .Values.labels.job.node_selector_value }}
-      initContainers:
-{{ tuple $envAll $dependencies list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
-      containers:
-        - name: glance-bootstrap
-          image: {{ .Values.images.tags.glance_bootstrap }}
-          imagePullPolicy: {{ .Values.images.pull_policy }}
-{{ tuple $envAll $envAll.Values.pod.resources.jobs.bootstrap | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
-          env:
-{{- with $env := dict "ksUserSecret" .Values.secrets.identity.admin }}
-{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 12 }}
-{{- end }}
-          command:
-            - /tmp/bootstrap.sh
-          volumeMounts:
-            - name: imagedir
-              mountPath: /tmp/images
-            - name: glance-bin
-              mountPath: /tmp/bootstrap.sh
-              subPath: bootstrap.sh
-              readOnly: true
-            - name: glance-etc
-              mountPath: /etc/glance/glance-api.conf
-              subPath: glance-api.conf
-              readOnly: true
-      volumes:
-        - name: imagedir
-          emptyDir: {}
-        - name: glance-bin
-          configMap:
-            name: glance-bin
-            defaultMode: 0555
-        - name: glance-etc
-          configMap:
-            name: glance-etc
-            defaultMode: 0444
+{{- if and .Values.manifests.job_bootstrap .Values.bootstrap.enabled }}
+{{- $podVolumes := tuple . | include "glance.templates._job_bootstrap.pod_volumes" | toString | fromYaml }}
+{{- $bootstrapJob := dict "envAll" . "serviceName" "glance" "keystoneUser" .Values.bootstrap.ks_user "podVolMounts" $podVolumes.volumeMounts "podVols" $podVolumes.volumes -}}
+{{ $bootstrapJob | include "helm-toolkit.manifests.job_bootstrap" }}
 {{- end }}
diff --git a/glance/values.yaml b/glance/values.yaml
index 2c5d24840c..c2bcf0314b 100644
--- a/glance/values.yaml
+++ b/glance/values.yaml
@@ -46,25 +46,28 @@ images:
     glance_api: docker.io/openstackhelm/glance:newton
     glance_registry: docker.io/openstackhelm/glance:newton
     # Bootstrap image requires curl
-    glance_bootstrap: docker.io/openstackhelm/heat:newton
+    bootstrap: docker.io/openstackhelm/heat:newton
     dep_check: quay.io/stackanetes/kubernetes-entrypoint:v0.2.1
   pull_policy: "IfNotPresent"
 
 bootstrap:
   enabled: true
-  images:
-    cirros:
-      id: null
-      name: "Cirros 0.3.5 64-bit"
-      source_url: "http://download.cirros-cloud.net/0.3.5/"
-      image_file: "cirros-0.3.5-x86_64-disk.img"
-      min_disk: 1
-      image_type: qcow2
-      container_format: bare
-      private: true
-      properties:
-        hypervisor_type: "qemu"
-        os_distro: "cirros"
+  ks_user: admin
+  script: null
+  structured:
+    images:
+      cirros:
+        id: null
+        name: "Cirros 0.3.5 64-bit"
+        source_url: "http://download.cirros-cloud.net/0.3.5/"
+        image_file: "cirros-0.3.5-x86_64-disk.img"
+        min_disk: 1
+        image_type: qcow2
+        container_format: bare
+        private: true
+        properties:
+          hypervisor_type: "qemu"
+          os_distro: "cirros"
 
 conf:
   rally_tests:
diff --git a/gnocchi/templates/job-bootstrap.yaml b/gnocchi/templates/job-bootstrap.yaml
new file mode 100644
index 0000000000..8b58185b90
--- /dev/null
+++ b/gnocchi/templates/job-bootstrap.yaml
@@ -0,0 +1,20 @@
+{{/*
+Copyright 2017 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 and .Values.manifests.job_bootstrap .Values.bootstrap.enabled }}
+{{- $bootstrapJob := dict "envAll" . "serviceName" "gnocchi" "keystoneUser" .Values.bootstrap.ks_user -}}
+{{ $bootstrapJob | include "helm-toolkit.manifests.job_bootstrap" }}
+{{- end }}
diff --git a/gnocchi/values.yaml b/gnocchi/values.yaml
index e97068ecda..dfc3d3ed4f 100644
--- a/gnocchi/values.yaml
+++ b/gnocchi/values.yaml
@@ -361,6 +361,12 @@ secrets:
     gnocchi: gnocchi-db-indexer-user
   rbd: gnocchi-rbd-keyring
 
+bootstrap:
+  enabled: false
+  ks_user: gnocchi
+  script: |
+    openstack token issue
+
 # typically overriden by environmental
 # values, but should include all endpoints
 # required by this chart
@@ -467,6 +473,7 @@ manifests:
   daemonset_statsd: true
   deployment_api: true
   ingress_api: true
+  job_bootstrap: true
   job_clean: true
   job_db_init_indexer: true
   job_db_init: true
diff --git a/heat/templates/job-bootstrap.yaml b/heat/templates/job-bootstrap.yaml
index d6f8abc398..904e2140c8 100644
--- a/heat/templates/job-bootstrap.yaml
+++ b/heat/templates/job-bootstrap.yaml
@@ -14,55 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */}}
 
-{{- if .Values.manifests.job_bootstrap }}
-{{- $envAll := . }}
-{{- if .Values.bootstrap.enabled }}
-{{- $dependencies := .Values.dependencies.bootstrap }}
-
-{{- $mounts_heat_bootstrap := .Values.pod.mounts.heat_bootstrap.heat_bootstrap }}
-{{- $mounts_heat_bootstrap_init := .Values.pod.mounts.heat_bootstrap.init_container }}
-
-{{- $serviceAccountName := "heat-bootstrap" }}
-{{ tuple $envAll $dependencies $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
----
-apiVersion: batch/v1
-kind: Job
-metadata:
-  name: heat-bootstrap
-spec:
-  template:
-    metadata:
-      labels:
-{{ tuple $envAll "heat" "bootstrap" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
-    spec:
-      serviceAccountName: {{ $serviceAccountName }}
-      restartPolicy: OnFailure
-      nodeSelector:
-        {{ .Values.labels.job.node_selector_key }}: {{ .Values.labels.job.node_selector_value }}
-      initContainers:
-{{ tuple $envAll $dependencies $mounts_heat_bootstrap_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container"  | indent 8 }}
-      containers:
-        - name: heat-bootstrap
-          image: {{ .Values.images.tags.bootstrap }}
-          imagePullPolicy: {{ .Values.images.pull_policy }}
-{{ tuple $envAll $envAll.Values.pod.resources.jobs.bootstrap | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
-          env:
-{{- with $env := dict "ksUserSecret" .Values.secrets.identity.admin }}
-{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 12 }}
-{{- end }}
-          command:
-            - /tmp/bootstrap.sh
-          volumeMounts:
-            - name: heat-bin
-              mountPath: /tmp/bootstrap.sh
-              subPath: bootstrap.sh
-              readOnly: true
-{{ if $mounts_heat_bootstrap.volumeMounts }}{{ toYaml $mounts_heat_bootstrap.volumeMounts | indent 12 }}{{ end }}
-      volumes:
-        - name: heat-bin
-          configMap:
-            name: heat-bin
-            defaultMode: 0555
-{{ if $mounts_heat_bootstrap.volumes }}{{ toYaml $mounts_heat_bootstrap.volumes | indent 8 }}{{ end }}
-{{- end }}
+{{- if and .Values.manifests.job_bootstrap .Values.bootstrap.enabled }}
+{{- $bootstrapJob := dict "envAll" . "serviceName" "heat" "keystoneUser" .Values.bootstrap.ks_user -}}
+{{ $bootstrapJob | include "helm-toolkit.manifests.job_bootstrap" }}
 {{- end }}
diff --git a/heat/values.yaml b/heat/values.yaml
index 9210d9cffe..fe042530ab 100644
--- a/heat/values.yaml
+++ b/heat/values.yaml
@@ -263,6 +263,7 @@ network:
 
 bootstrap:
   enabled: false
+  ks_user: heat
   script: |
     openstack token issue
 
diff --git a/helm-toolkit/templates/manifests/_job-bootstrap.yaml b/helm-toolkit/templates/manifests/_job-bootstrap.yaml
new file mode 100644
index 0000000000..086fc2370d
--- /dev/null
+++ b/helm-toolkit/templates/manifests/_job-bootstrap.yaml
@@ -0,0 +1,94 @@
+{{/*
+Copyright 2017 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.
+*/}}
+
+# This function creates a manifest for db creation and user 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_bootstrap" -}}
+{{- $envAll := index . "envAll" -}}
+{{- $serviceName := index . "serviceName" -}}
+{{- $nodeSelector := index . "nodeSelector" | default ( dict $envAll.Values.labels.job.node_selector_key $envAll.Values.labels.job.node_selector_value ) -}}
+{{- $dependencies := index . "dependencies" | default $envAll.Values.dependencies.bootstrap -}}
+{{- $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 ) -}}
+{{- $keystoneUser := index . "keystoneUser" | default $serviceName -}}
+
+{{- $serviceNamePretty := $serviceName | replace "_" "-" -}}
+
+{{- $serviceAccountName := printf "%s-%s" $serviceNamePretty "bootstrap" }}
+{{ tuple $envAll $dependencies $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+  name: {{ printf "%s-%s" $serviceNamePretty "bootstrap" | quote }}
+spec:
+  template:
+    metadata:
+      labels:
+{{ tuple $envAll $serviceName "bootstrap" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
+    spec:
+      serviceAccountName: {{ $serviceAccountName }}
+      restartPolicy: OnFailure
+      nodeSelector:
+{{ toYaml $nodeSelector | indent 8 }}
+      initContainers:
+{{ tuple $envAll $dependencies 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 }}
+          env:
+{{- with $env := dict "ksUserSecret" ( index $envAll.Values.secrets.identity $keystoneUser ) }}
+{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 12 }}
+{{- end }}
+          command:
+            - /tmp/bootstrap.sh
+          volumeMounts:
+            - 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
+{{- if $podVolMounts }}
+{{ $podVolMounts | toYaml | indent 12 }}
+{{- end }}
+      volumes:
+        - name: bootstrap-sh
+          configMap:
+            name: {{ $configMapBin | quote }}
+            defaultMode: 0555
+        - name: etc-service
+          emptyDir: {}
+        - name: bootstrap-conf
+          configMap:
+            name: {{ $configMapEtc | quote }}
+            defaultMode: 0444
+{{- if $podVols }}
+{{ $podVols | toYaml | indent 8 }}
+{{- end }}
+{{- end }}
diff --git a/ironic/templates/job-bootstrap.yaml b/ironic/templates/job-bootstrap.yaml
index e7b932fd9b..c33a17f338 100644
--- a/ironic/templates/job-bootstrap.yaml
+++ b/ironic/templates/job-bootstrap.yaml
@@ -15,52 +15,6 @@ limitations under the License.
 */}}
 
 {{- if and .Values.manifests.job_bootstrap .Values.bootstrap.enabled }}
-{{- $envAll := . }}
-{{- $dependencies := .Values.dependencies.bootstrap }}
-
-{{- $mounts_ironic_bootstrap := .Values.pod.mounts.ironic_bootstrap.ironic_bootstrap }}
-{{- $mounts_ironic_bootstrap_init := .Values.pod.mounts.ironic_bootstrap.init_container }}
-
-{{- $serviceAccountName := "ironic-bootstrap" }}
-{{ tuple $envAll $dependencies $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
----
-apiVersion: batch/v1
-kind: Job
-metadata:
-  name: ironic-bootstrap
-spec:
-  template:
-    metadata:
-      labels:
-{{ tuple $envAll "ironic" "bootstrap" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
-    spec:
-      serviceAccountName: {{ $serviceAccountName }}
-      restartPolicy: OnFailure
-      nodeSelector:
-        {{ .Values.labels.job.node_selector_key }}: {{ .Values.labels.job.node_selector_value }}
-      initContainers:
-{{ tuple $envAll $dependencies $mounts_ironic_bootstrap_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container"  | indent 8 }}
-      containers:
-        - name: ironic-bootstrap
-          image: {{ .Values.images.tags.ironic_bootstrap }}
-          imagePullPolicy: {{ .Values.images.pull_policy }}
-{{ tuple $envAll $envAll.Values.pod.resources.jobs.bootstrap | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
-          env:
-{{- with $env := dict "ksUserSecret" .Values.secrets.identity.ironic }}
-{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 12 }}
-{{- end }}
-          command:
-            - /tmp/bootstrap.sh
-          volumeMounts:
-            - name: ironic-bin
-              mountPath: /tmp/bootstrap.sh
-              subPath: bootstrap.sh
-              readOnly: true
-{{- if $mounts_ironic_bootstrap.volumeMounts }}{{ toYaml $mounts_ironic_bootstrap.volumeMounts | indent 10 }}{{ end }}
-      volumes:
-        - name: ironic-bin
-          configMap:
-            name: ironic-bin
-            defaultMode: 0555
-{{- if $mounts_ironic_bootstrap.volumes }}{{ toYaml $mounts_ironic_bootstrap.volumes | indent 6 }}{{ end }}
+{{- $bootstrapJob := dict "envAll" . "serviceName" "ironic" "keystoneUser" .Values.bootstrap.ks_user -}}
+{{ $bootstrapJob | include "helm-toolkit.manifests.job_bootstrap" }}
 {{- end }}
diff --git a/ironic/values.yaml b/ironic/values.yaml
index 22a418d437..2107002482 100644
--- a/ironic/values.yaml
+++ b/ironic/values.yaml
@@ -33,7 +33,7 @@ images:
     ironic_manage_cleaning_network: docker.io/openstackhelm/heat:newton
     ironic_retrive_cleaning_network: docker.io/openstackhelm/heat:newton
     # Bootstrap image requires curl
-    ironic_bootstrap: docker.io/openstackhelm/heat:newton
+    bootstrap: docker.io/openstackhelm/heat:newton
     db_init: docker.io/openstackhelm/heat:newton
     ironic_db_sync: docker.io/openstackhelm/ironic:newton
     ks_user: docker.io/openstackhelm/heat:newton
@@ -116,6 +116,7 @@ network:
 
 bootstrap:
   enabled: true
+  ks_user: ironic
   script: |
     RELEASE="newton"
     IMAGE_URL_BASE="http://tarballs.openstack.org/ironic-python-agent/tinyipa/files"
diff --git a/keystone/templates/job-bootstrap.yaml b/keystone/templates/job-bootstrap.yaml
index b60bd1d218..c69d1286fa 100644
--- a/keystone/templates/job-bootstrap.yaml
+++ b/keystone/templates/job-bootstrap.yaml
@@ -14,91 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */}}
 
-{{- if .Values.manifests.job_bootstrap }}
-{{- $envAll := . }}
-{{- if .Values.bootstrap.enabled }}
-{{- $dependencies := .Values.dependencies.bootstrap }}
-
-{{- $mounts_keystone_bootstrap := .Values.pod.mounts.keystone_bootstrap.keystone_bootstrap }}
-{{- $mounts_keystone_bootstrap_init := .Values.pod.mounts.keystone_bootstrap.init_container }}
-
-{{- $serviceAccountName := "keystone-bootstrap" }}
-{{ tuple $envAll $dependencies $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
----
-apiVersion: batch/v1
-kind: Job
-metadata:
-  name: keystone-bootstrap
-spec:
-  template:
-    metadata:
-      labels:
-{{ tuple $envAll "keystone" "bootstrap" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
-    spec:
-      serviceAccountName: {{ $serviceAccountName }}
-      restartPolicy: OnFailure
-      nodeSelector:
-        {{ .Values.labels.job.node_selector_key }}: {{ .Values.labels.job.node_selector_value }}
-      initContainers:
-{{ tuple $envAll $dependencies $mounts_keystone_bootstrap_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container"  | indent 8 }}
-      containers:
-        - name: keystone-bootstrap
-          image: {{ .Values.images.tags.bootstrap }}
-          imagePullPolicy: {{ .Values.images.pull_policy }}
-{{ tuple $envAll $envAll.Values.pod.resources.jobs.bootstrap | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
-          env:
-{{- with $env := dict "ksUserSecret" .Values.secrets.identity.admin }}
-{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 12 }}
-{{- end }}
-          command:
-            - /tmp/bootstrap.sh
-          volumeMounts:
-            - name: etckeystonedomains
-              mountPath: {{ .Values.conf.keystone.identity.domain_config_dir | default "/etc/keystonedomains" }}
-            - name: etckeystone
-              mountPath: /etc/keystone
-            - name: keystone-bin
-              mountPath: /tmp/bootstrap.sh
-              subPath: bootstrap.sh
-              readOnly: true
-            - name: keystone-etc
-              mountPath: /etc/keystone/keystone.conf
-              subPath: keystone.conf
-              readOnly: true
-{{- range $k, $v := .Values.conf.ks_domains }}
-            - name: keystone-etc
-              mountPath: {{ $envAll.Values.conf.keystone.identity.domain_config_dir | default "/etc/keystonedomains" }}/keystone.{{ $k }}.conf
-              subPath: keystone.{{ $k }}.conf
-              readOnly: true
-{{- end }}
-{{- if eq .Values.conf.keystone.token.provider "fernet" }}
-            - name: keystone-fernet-keys
-              mountPath: {{ .Values.conf.keystone.fernet_tokens.key_repository }}
-{{- end }}
-            - name: keystone-credential-keys
-              mountPath: {{ .Values.conf.keystone.credential.key_repository }}
-{{ if $mounts_keystone_bootstrap.volumeMounts }}{{ toYaml $mounts_keystone_bootstrap.volumeMounts | indent 12 }}{{ end }}
-      volumes:
-        - name: etckeystone
-          emptyDir: {}
-        - name: etckeystonedomains
-          emptyDir: {}
-        - name: keystone-etc
-          configMap:
-            name: keystone-etc
-            defaultMode: 0444
-        - name: keystone-bin
-          configMap:
-            name: keystone-bin
-            defaultMode: 0555
-{{- if eq .Values.conf.keystone.token.provider "fernet" }}
-        - name: keystone-fernet-keys
-          secret:
-            secretName: keystone-fernet-keys
-{{- end }}
-        - name: keystone-credential-keys
-          secret:
-            secretName: keystone-credential-keys
-{{ if $mounts_keystone_bootstrap.volumes }}{{ toYaml $mounts_keystone_bootstrap.volumes | indent 9 }}{{ end }}
-{{- end }}
+{{- if and .Values.manifests.job_bootstrap .Values.bootstrap.enabled }}
+{{- $bootstrapJob := dict "envAll" . "serviceName" "keystone" "keystoneUser" .Values.bootstrap.ks_user -}}
+{{ $bootstrapJob | include "helm-toolkit.manifests.job_bootstrap" }}
 {{- end }}
diff --git a/keystone/values.yaml b/keystone/values.yaml
index eddd429add..34660bfd08 100644
--- a/keystone/values.yaml
+++ b/keystone/values.yaml
@@ -46,6 +46,7 @@ images:
 
 bootstrap:
   enabled: true
+  ks_user: admin
   script: |
     openstack role add \
           --user="${OS_USERNAME}" \
diff --git a/magnum/templates/job-bootstrap.yaml b/magnum/templates/job-bootstrap.yaml
index d01bafb095..668f46c350 100644
--- a/magnum/templates/job-bootstrap.yaml
+++ b/magnum/templates/job-bootstrap.yaml
@@ -14,55 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */}}
 
-{{- if .Values.manifests.job_bootstrap }}
-{{- $envAll := . }}
-{{- if .Values.bootstrap.enabled }}
-{{- $dependencies := .Values.dependencies.bootstrap }}
-
-{{- $mounts_magnum_bootstrap := .Values.pod.mounts.magnum_bootstrap.magnum_bootstrap }}
-{{- $mounts_magnum_bootstrap_init := .Values.pod.mounts.magnum_bootstrap.init_container }}
-
-{{- $serviceAccountName := "magnum-bootstrap" }}
-{{ tuple $envAll $dependencies $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
----
-apiVersion: batch/v1
-kind: Job
-metadata:
-  name: magnum-bootstrap
-spec:
-  template:
-    metadata:
-      labels:
-{{ tuple $envAll "magnum" "bootstrap" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
-    spec:
-      serviceAccountName: {{ $serviceAccountName }}
-      restartPolicy: OnFailure
-      nodeSelector:
-        {{ .Values.labels.job.node_selector_key }}: {{ .Values.labels.job.node_selector_value }}
-      initContainers:
-{{ tuple $envAll $dependencies $mounts_magnum_bootstrap_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container"  | indent 8 }}
-      containers:
-        - name: magnum-bootstrap
-          image: {{ .Values.images.tags.bootstrap }}
-          imagePullPolicy: {{ .Values.images.pull_policy }}
-{{ tuple $envAll $envAll.Values.pod.resources.jobs.bootstrap | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
-          env:
-{{- with $env := dict "ksUserSecret" .Values.secrets.identity.admin }}
-{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 12 }}
-{{- end }}
-          command:
-            - /tmp/bootstrap.sh
-          volumeMounts:
-            - name: magnum-bin
-              mountPath: /tmp/bootstrap.sh
-              subPath: bootstrap.sh
-              readOnly: true
-{{ if $mounts_magnum_bootstrap.volumeMounts }}{{ toYaml $mounts_magnum_bootstrap.volumeMounts | indent 12 }}{{ end }}
-      volumes:
-        - name: magnum-bin
-          configMap:
-            name: magnum-bin
-            defaultMode: 0555
-{{ if $mounts_magnum_bootstrap.volumes }}{{ toYaml $mounts_magnum_bootstrap.volumes | indent 8 }}{{ end }}
-{{- end }}
+{{- if and .Values.manifests.job_bootstrap .Values.bootstrap.enabled }}
+{{- $bootstrapJob := dict "envAll" . "serviceName" "magnum" "keystoneUser" .Values.bootstrap.ks_user -}}
+{{ $bootstrapJob | include "helm-toolkit.manifests.job_bootstrap" }}
 {{- end }}
diff --git a/magnum/values.yaml b/magnum/values.yaml
index cc5c0b2903..d22f67ba75 100644
--- a/magnum/values.yaml
+++ b/magnum/values.yaml
@@ -132,6 +132,7 @@ network:
 
 bootstrap:
   enabled: false
+  ks_user: magnum
   script: |
     openstack token issue
 
diff --git a/mistral/templates/job-bootstrap.yaml b/mistral/templates/job-bootstrap.yaml
index 15d20da04c..00e463e956 100644
--- a/mistral/templates/job-bootstrap.yaml
+++ b/mistral/templates/job-bootstrap.yaml
@@ -14,54 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */}}
 
-{{- if .Values.manifests.job_bootstrap }}
-{{- $envAll := . }}
-{{- if .Values.bootstrap.enabled }}
-{{- $dependencies := .Values.dependencies.bootstrap }}
-{{- $mounts_mistral_bootstrap := .Values.pod.mounts.mistral_bootstrap.mistral_bootstrap }}
-{{- $mounts_mistral_bootstrap_init := .Values.pod.mounts.mistral_bootstrap.init_container }}
-
-{{- $serviceAccountName := "mistral-bootstrap" }}
-{{ tuple $envAll $dependencies $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
----
-apiVersion: batch/v1
-kind: Job
-metadata:
-  name: mistral-bootstrap
-spec:
-  template:
-    metadata:
-      labels:
-{{ tuple $envAll "mistral" "bootstrap" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
-    spec:
-      serviceAccountName: {{ $serviceAccountName }}
-      restartPolicy: OnFailure
-      nodeSelector:
-        {{ .Values.labels.job.node_selector_key }}: {{ .Values.labels.job.node_selector_value }}
-      initContainers:
-{{ tuple $envAll $dependencies $mounts_mistral_bootstrap_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container"  | indent 8 }}
-      containers:
-        - name: mistral-bootstrap
-          image: {{ .Values.images.tags.bootstrap }}
-          imagePullPolicy: {{ .Values.images.pull_policy }}
-{{ tuple $envAll $envAll.Values.pod.resources.jobs.bootstrap | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
-          env:
-{{- with $env := dict "ksUserSecret" .Values.secrets.identity.admin }}
-{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 12 }}
-{{- end }}
-          command:
-            - /tmp/bootstrap.sh
-          volumeMounts:
-            - name: mistral-bin
-              mountPath: /tmp/bootstrap.sh
-              subPath: bootstrap.sh
-              readOnly: true
-{{ if $mounts_mistral_bootstrap.volumeMounts }}{{ toYaml $mounts_mistral_bootstrap.volumeMounts | indent 12 }}{{ end }}
-      volumes:
-        - name: mistral-bin
-          configMap:
-            name: mistral-bin
-            defaultMode: 0555
-{{ if $mounts_mistral_bootstrap.volumes }}{{ toYaml $mounts_mistral_bootstrap.volumes | indent 8 }}{{ end }}
-{{- end }}
+{{- if and .Values.manifests.job_bootstrap .Values.bootstrap.enabled }}
+{{- $bootstrapJob := dict "envAll" . "serviceName" "mistral" "keystoneUser" .Values.bootstrap.ks_user -}}
+{{ $bootstrapJob | include "helm-toolkit.manifests.job_bootstrap" }}
 {{- end }}
diff --git a/mistral/values.yaml b/mistral/values.yaml
index c6ae5ef26c..9e974b9484 100644
--- a/mistral/values.yaml
+++ b/mistral/values.yaml
@@ -65,6 +65,7 @@ network:
 
 bootstrap:
   enabled: false
+  ks_user: mistral
   script: |
     openstack token issue
 
diff --git a/neutron/templates/job-bootstrap.yaml b/neutron/templates/job-bootstrap.yaml
index 9bbda9d44c..d705809aef 100644
--- a/neutron/templates/job-bootstrap.yaml
+++ b/neutron/templates/job-bootstrap.yaml
@@ -14,54 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */}}
 
-{{- if .Values.manifests.job_bootstrap }}
-{{- $envAll := . }}
-{{- if .Values.bootstrap.enabled }}
-{{- $dependencies := .Values.dependencies.bootstrap }}
-
-{{- $mounts_neutron_bootstrap := .Values.pod.mounts.neutron_bootstrap.neutron_bootstrap }}
-{{- $mounts_neutron_bootstrap_init := .Values.pod.mounts.neutron_bootstrap.init_container }}
-
-{{- $serviceAccountName := "neutron-bootstrap" }}
-{{ tuple $envAll $dependencies $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
----
-apiVersion: batch/v1
-kind: Job
-metadata:
-  name: neutron-bootstrap
-spec:
-  template:
-    metadata:
-      labels:
-{{ tuple $envAll "neutron" "bootstrap" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
-    spec:
-      serviceAccountName: {{ $serviceAccountName }}
-      restartPolicy: OnFailure
-      nodeSelector:
-        {{ .Values.labels.job.node_selector_key }}: {{ .Values.labels.job.node_selector_value }}
-      initContainers:
-{{ tuple $envAll $dependencies $mounts_neutron_bootstrap_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container"  | indent 8 }}
-      containers:
-        - name: neutron-bootstrap
-          image: {{ .Values.images.tags.bootstrap }}
-          imagePullPolicy: {{ .Values.images.pull_policy }}
-{{ tuple $envAll $envAll.Values.pod.resources.jobs.bootstrap | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
-          env:
-{{- with $env := dict "ksUserSecret" .Values.secrets.identity.admin }}
-{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 12 }}
-{{- end }}
-          command:
-            - /tmp/bootstrap.sh
-          volumeMounts:
-            - name: neutron-bin
-              mountPath: /tmp/bootstrap.sh
-              subPath: bootstrap.sh
-{{ if $mounts_neutron_bootstrap.volumeMounts }}{{ toYaml $mounts_neutron_bootstrap.volumeMounts | indent 12 }}{{ end }}
-      volumes:
-        - name: neutron-bin
-          configMap:
-            name: neutron-bin
-            defaultMode: 0555
-{{ if $mounts_neutron_bootstrap.volumes }}{{ toYaml $mounts_neutron_bootstrap.volumes | indent 8 }}{{ end }}
-{{- end }}
+{{- if and .Values.manifests.job_bootstrap .Values.bootstrap.enabled }}
+{{- $bootstrapJob := dict "envAll" . "serviceName" "neutron" "keystoneUser" .Values.bootstrap.ks_user -}}
+{{ $bootstrapJob | include "helm-toolkit.manifests.job_bootstrap" }}
 {{- end }}
diff --git a/neutron/values.yaml b/neutron/values.yaml
index 6089c49bec..f33c57fdd8 100644
--- a/neutron/values.yaml
+++ b/neutron/values.yaml
@@ -104,8 +104,9 @@ network:
 
 bootstrap:
   enabled: false
+  ks_user: neutron
   script: |
-    neutron agent-list
+    openstack token issue
 
 dependencies:
   db_init:
diff --git a/nova/templates/bin/_bootstrap.sh.tpl b/nova/templates/bin/_bootstrap.sh.tpl
index 25eb3280ed..2f1cb41203 100644
--- a/nova/templates/bin/_bootstrap.sh.tpl
+++ b/nova/templates/bin/_bootstrap.sh.tpl
@@ -19,8 +19,8 @@ limitations under the License.
 set -ex
 export HOME=/tmp
 
-{{ if .Values.bootstrap.flavors.enabled }}
-{{ range .Values.bootstrap.flavors.options }}
+{{ if .Values.bootstrap.structured.flavors.enabled }}
+{{ range .Values.bootstrap.structured.flavors.options }}
 openstack flavor show {{ .name }} || \
  openstack flavor create {{ .name }} \
  --id {{ .id }} \
@@ -31,4 +31,3 @@ openstack flavor show {{ .name }} || \
 {{ end }}
 
 {{ .Values.bootstrap.script | default "echo 'Not Enabled'" }}
-exit 0
diff --git a/nova/templates/job-bootstrap.yaml b/nova/templates/job-bootstrap.yaml
index 30ce26d5d5..6620f2d776 100644
--- a/nova/templates/job-bootstrap.yaml
+++ b/nova/templates/job-bootstrap.yaml
@@ -14,63 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */}}
 
-{{- if .Values.manifests.job_bootstrap }}
-{{- $envAll := . }}
-{{- if .Values.bootstrap.enabled }}
-{{- $dependencies := .Values.dependencies.bootstrap }}
-
-{{- $mounts_nova_bootstrap := .Values.pod.mounts.nova_bootstrap.nova_bootstrap }}
-{{- $mounts_nova_bootstrap_init := .Values.pod.mounts.nova_bootstrap.init_container }}
-
-{{- $serviceAccountName := "nova-bootstrap" }}
-{{ tuple $envAll $dependencies $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
----
-apiVersion: batch/v1
-kind: Job
-metadata:
-  name: nova-bootstrap
-spec:
-  template:
-    metadata:
-      labels:
-{{ tuple $envAll "nova" "bootstrap" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
-    spec:
-      serviceAccountName: {{ $serviceAccountName }}
-      restartPolicy: OnFailure
-      nodeSelector:
-        {{ .Values.labels.job.node_selector_key }}: {{ .Values.labels.job.node_selector_value }}
-      initContainers:
-{{ tuple $envAll $dependencies $mounts_nova_bootstrap_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }}
-      containers:
-        - name: nova-bootstrap
-          image: {{ .Values.images.tags.bootstrap }}
-          imagePullPolicy: {{ .Values.images.pull_policy }}
-{{ tuple $envAll $envAll.Values.pod.resources.jobs.bootstrap | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
-          command:
-            - /tmp/bootstrap.sh
-          env:
-{{- with $env := dict "ksUserSecret" .Values.secrets.identity.admin }}
-{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 12 }}
-{{- end }}
-          volumeMounts:
-            - name: nova-bin
-              mountPath: /tmp/bootstrap.sh
-              subPath: bootstrap.sh
-              readOnly: true
-            - name: nova-etc
-              mountPath: /etc/nova/nova.conf
-              subPath: nova.conf
-              readOnly: true
-{{ if $mounts_nova_bootstrap.volumeMounts }}{{ toYaml $mounts_nova_bootstrap.volumeMounts | indent 12 }}{{ end }}
-      volumes:
-        - name: nova-etc
-          configMap:
-            name: nova-etc
-            defaultMode: 0444
-        - name: nova-bin
-          configMap:
-            name: nova-bin
-            defaultMode: 0555
-{{ if $mounts_nova_bootstrap.volumes }}{{ toYaml $mounts_nova_bootstrap.volumes | indent 8 }}{{ end }}
-{{- end }}
+{{- if and .Values.manifests.job_bootstrap .Values.bootstrap.enabled }}
+{{- $bootstrapJob := dict "envAll" . "serviceName" "nova" "keystoneUser" .Values.bootstrap.ks_user -}}
+{{ $bootstrapJob | include "helm-toolkit.manifests.job_bootstrap" }}
 {{- end }}
diff --git a/nova/values.yaml b/nova/values.yaml
index 420c2d49c2..398c4dcc37 100644
--- a/nova/values.yaml
+++ b/nova/values.yaml
@@ -83,40 +83,42 @@ images:
 
 bootstrap:
   enabled: true
+  ks_user: admin
   script: null
-  flavors:
-    enabled: true
-    options:
-      m1_tiny:
-          name: "m1.tiny"
-          id: "auto"
-          ram: 512
-          disk: 1
-          vcpus: 1
-      m1_small:
-          name: "m1.small"
-          id: "auto"
-          ram: 2048
-          disk: 20
-          vcpus: 1
-      m1_medium:
-          name: "m1.medium"
-          id: "auto"
-          ram: 4096
-          disk: 40
-          vcpus: 2
-      m1_large:
-          name: "m1.large"
-          id: "auto"
-          ram: 8192
-          disk: 80
-          vcpus: 4
-      m1_xlarge:
-          name: "m1.xlarge"
-          id: "auto"
-          ram: 16384
-          disk: 160
-          vcpus: 8
+  structured:
+    flavors:
+      enabled: true
+      options:
+        m1_tiny:
+            name: "m1.tiny"
+            id: "auto"
+            ram: 512
+            disk: 1
+            vcpus: 1
+        m1_small:
+            name: "m1.small"
+            id: "auto"
+            ram: 2048
+            disk: 20
+            vcpus: 1
+        m1_medium:
+            name: "m1.medium"
+            id: "auto"
+            ram: 4096
+            disk: 40
+            vcpus: 2
+        m1_large:
+            name: "m1.large"
+            id: "auto"
+            ram: 8192
+            disk: 80
+            vcpus: 4
+        m1_xlarge:
+            name: "m1.xlarge"
+            id: "auto"
+            ram: 16384
+            disk: 160
+            vcpus: 8
 
 network:
   osapi:
diff --git a/senlin/templates/job-bootstrap.yaml b/senlin/templates/job-bootstrap.yaml
index c2e9d28cde..662dfa3138 100644
--- a/senlin/templates/job-bootstrap.yaml
+++ b/senlin/templates/job-bootstrap.yaml
@@ -14,54 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */}}
 
-{{- if .Values.manifests.job_bootstrap }}
-{{- $envAll := . }}
-{{- if .Values.bootstrap.enabled }}
-{{- $dependencies := .Values.dependencies.bootstrap }}
-{{- $mounts_senlin_bootstrap := .Values.pod.mounts.senlin_bootstrap.senlin_bootstrap }}
-{{- $mounts_senlin_bootstrap_init := .Values.pod.mounts.senlin_bootstrap.init_container }}
-
-{{- $serviceAccountName := "senlin-bootstrap" }}
-{{ tuple $envAll $dependencies $serviceAccountName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }}
----
-apiVersion: batch/v1
-kind: Job
-metadata:
-  name: senlin-bootstrap
-spec:
-  template:
-    metadata:
-      labels:
-{{ tuple $envAll "senlin" "bootstrap" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }}
-    spec:
-      serviceAccountName: {{ $serviceAccountName }}
-      restartPolicy: OnFailure
-      nodeSelector:
-        {{ .Values.labels.job.node_selector_key }}: {{ .Values.labels.job.node_selector_value }}
-      initContainers:
-{{ tuple $envAll $dependencies $mounts_senlin_bootstrap_init | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container"  | indent 8 }}
-      containers:
-        - name: senlin-bootstrap
-          image: {{ .Values.images.tags.bootstrap }}
-          imagePullPolicy: {{ .Values.images.pull_policy }}
-{{ tuple $envAll $envAll.Values.pod.resources.jobs.bootstrap | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }}
-          env:
-{{- with $env := dict "ksUserSecret" .Values.secrets.identity.admin }}
-{{- include "helm-toolkit.snippets.keystone_openrc_env_vars" $env | indent 12 }}
-{{- end }}
-          command:
-            - /tmp/bootstrap.sh
-          volumeMounts:
-            - name: senlin-bin
-              mountPath: /tmp/bootstrap.sh
-              subPath: bootstrap.sh
-              readOnly: true
-{{ if $mounts_senlin_bootstrap.volumeMounts }}{{ toYaml $mounts_senlin_bootstrap.volumeMounts | indent 12 }}{{ end }}
-      volumes:
-        - name: senlin-bin
-          configMap:
-            name: senlin-bin
-            defaultMode: 0555
-{{ if $mounts_senlin_bootstrap.volumes }}{{ toYaml $mounts_senlin_bootstrap.volumes | indent 8 }}{{ end }}
-{{- end }}
+{{- if and .Values.manifests.job_bootstrap .Values.bootstrap.enabled }}
+{{- $bootstrapJob := dict "envAll" . "serviceName" "senlin" "keystoneUser" .Values.bootstrap.ks_user -}}
+{{ $bootstrapJob | include "helm-toolkit.manifests.job_bootstrap" }}
 {{- end }}
diff --git a/senlin/values.yaml b/senlin/values.yaml
index 33f475e75f..916d03ff4e 100644
--- a/senlin/values.yaml
+++ b/senlin/values.yaml
@@ -144,6 +144,7 @@ network:
 
 bootstrap:
   enabled: false
+  ks_user: senlin
   script: |
     openstack token issue
 
diff --git a/tools/overrides/releases/newton/kolla.yaml b/tools/overrides/releases/newton/kolla.yaml
index c77f3ca2a4..29f9aec131 100644
--- a/tools/overrides/releases/newton/kolla.yaml
+++ b/tools/overrides/releases/newton/kolla.yaml
@@ -25,7 +25,6 @@ images:
     db_drop: 'docker.io/kolla/ubuntu-source-heat-engine:3.0.3'
     db_init: 'docker.io/kolla/ubuntu-source-heat-engine:3.0.3'
     glance_api: 'docker.io/kolla/ubuntu-source-glance-api:3.0.3'
-    glance_bootstrap: 'docker.io/kolla/ubuntu-source-heat-engine:3.0.3'
     glance_db_sync: 'docker.io/kolla/ubuntu-source-glance-api:3.0.3'
     glance_registry: 'docker.io/kolla/ubuntu-source-glance-registry:3.0.3'
     heat_api: 'docker.io/kolla/ubuntu-source-heat-api:3.0.3'
@@ -36,7 +35,6 @@ images:
     horizon: 'docker.io/kolla/ubuntu-source-horizon:ocata'
     horizon_db_sync: 'docker.io/kolla/ubuntu-source-horizon:ocata'
     ironic_api: 'docker.io/kolla/ubuntu-source-ironic-api:3.0.3'
-    ironic_bootstrap: 'docker.io/kolla/ubuntu-source-heat-engine:3.0.3'
     ironic_conductor: 'docker.io/kolla/ubuntu-source-ironic-conductor:3.0.3'
     ironic_db_sync: 'docker.io/kolla/ubuntu-source-ironic-api:3.0.3'
     ironic_pxe: 'docker.io/kolla/ubuntu-source-ironic-pxe:3.0.3'