From 8e7e50c2d096f1f1986cd4753ff958fcd1bad6de Mon Sep 17 00:00:00 2001 From: Stavros kois Date: Sun, 12 Feb 2023 13:15:53 +0200 Subject: [PATCH] vct --- .../tests/container/volumeMounts_test.yaml | 56 +++++ .../tests/persistence/validation_test.yaml | 11 + .../volumeClaimTemplate/metadata_test.yaml | 63 +++++ .../tests/volumeClaimTemplate/names_test.yaml | 32 +++ .../volumeClaimTemplate/validation_test.yaml | 105 ++++++++ .../volumeClaimTemplate/vct_data_test.yaml | 232 ++++++++++++++++++ .../common/1.0.0/docs/persistence/README.md | 4 +- .../common/1.0.0/docs/volumeClaimTemplates.md | 82 +++++++ library/common/1.0.0/templates/class/_pvc.tpl | 4 +- .../1.0.0/templates/class/_statefulset.tpl | 4 + .../templates/lib/container/_volumeMounts.tpl | 84 ++++--- .../templates/lib/storage/_accessModes.tpl | 5 +- .../lib/storage/_storageClassName.tpl | 5 +- .../templates/lib/storage/_validation.tpl | 19 +- .../lib/storage/_volumeClaimTemplates.tpl | 66 +++++ .../1.0.0/templates/lib/workload/_pod.tpl | 1 + library/common/1.0.0/values.yaml | 42 +--- 17 files changed, 734 insertions(+), 81 deletions(-) create mode 100644 library/common-test/tests/volumeClaimTemplate/metadata_test.yaml create mode 100644 library/common-test/tests/volumeClaimTemplate/names_test.yaml create mode 100644 library/common-test/tests/volumeClaimTemplate/validation_test.yaml create mode 100644 library/common-test/tests/volumeClaimTemplate/vct_data_test.yaml create mode 100644 library/common/1.0.0/docs/volumeClaimTemplates.md create mode 100644 library/common/1.0.0/templates/lib/storage/_volumeClaimTemplates.tpl diff --git a/library/common-test/tests/container/volumeMounts_test.yaml b/library/common-test/tests/container/volumeMounts_test.yaml index 12d24b0c57..63ee7ab6f9 100644 --- a/library/common-test/tests/container/volumeMounts_test.yaml +++ b/library/common-test/tests/container/volumeMounts_test.yaml @@ -549,6 +549,62 @@ tests: mountPath: /some/path readOnly: true + - it: should pass with vct mounted + set: + image: *image + workload: + workload-name: + enabled: true + primary: true + type: StatefulSet + podSpec: + containers: + container-name1: + enabled: true + primary: true + imageSelector: image + workload-name2: + enabled: true + primary: false + type: StatefulSet + podSpec: + containers: + container-name1: + enabled: true + primary: true + imageSelector: image + volumeClaimTemplates: + vct-vol: + enabled: true + size: 50Gi + targetSelector: + workload-name: + container-name1: + mountPath: /some/path + asserts: + - documentIndex: &statefulSetDoc 0 + isKind: + of: StatefulSet + - documentIndex: *statefulSetDoc + isAPIVersion: + of: apps/v1 + - documentIndex: *statefulSetDoc + contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: vct-vol + mountPath: /some/path + readOnly: false + - documentIndex: &otherStatefulSetDoc 1 + isKind: + of: StatefulSet + - documentIndex: *otherStatefulSetDoc + isAPIVersion: + of: apps/v1 + - documentIndex: *otherStatefulSetDoc + isNull: + path: spec.template.spec.containers[0].volumeMounts + # Failures - it: should fail with invalid mountPropagation set: diff --git a/library/common-test/tests/persistence/validation_test.yaml b/library/common-test/tests/persistence/validation_test.yaml index ea921d7b16..bd0dc0a60a 100644 --- a/library/common-test/tests/persistence/validation_test.yaml +++ b/library/common-test/tests/persistence/validation_test.yaml @@ -42,6 +42,17 @@ tests: - failedTemplate: errorMessage: Persistence - Expected to be one of [pvc, emptyDir, nfs, hostPath, ixVolume, secret, configmap, device], but got [not-a-type] + - it: should fail with invalid accessMode + set: + persistence: + volume1: + enabled: true + accessModes: + - not-an-access-mode + asserts: + - failedTemplate: + errorMessage: PVC - Expected entry to be one of [ReadWriteOnce, ReadOnlyMany, ReadWriteMany, ReadWriteOncePod], but got [not-an-access-mode] + - it: should fail without storageClassName in ixChartContext set: global: diff --git a/library/common-test/tests/volumeClaimTemplate/metadata_test.yaml b/library/common-test/tests/volumeClaimTemplate/metadata_test.yaml new file mode 100644 index 0000000000..ded66d47ec --- /dev/null +++ b/library/common-test/tests/volumeClaimTemplate/metadata_test.yaml @@ -0,0 +1,63 @@ +suite: volumeClaimTemplates metadata test +templates: + - common.yaml +chart: + appVersion: &appVer v9.9.9 +tests: + - it: should pass with vct created with labels and annotations + set: + label1: label1 + label2: global_label2 + annotation1: annotation1 + annotation2: global_annotation2 + global: + labels: + g_label1: global_label1 + g_label2: "{{ .Values.label2 }}" + annotations: + g_annotation1: global_annotation1 + g_annotation2: "{{ .Values.annotation2 }}" + volumeClaimTemplates: + my-volume1: + enabled: true + labels: + label1: "{{ .Values.label1 }}" + label2: label2 + annotations: + annotation1: "{{ .Values.annotation1 }}" + annotation2: annotation2 + workload: + main: + enabled: true + primary: true + type: StatefulSet + podSpec: {} + asserts: + - documentIndex: &statefulSetDoc 0 + isKind: + of: StatefulSet + - documentIndex: *statefulSetDoc + isAPIVersion: + of: apps/v1 + - documentIndex: *statefulSetDoc + equal: + path: spec.volumeClaimTemplates[0].metadata.annotations + value: + annotation1: annotation1 + annotation2: annotation2 + g_annotation1: global_annotation1 + g_annotation2: global_annotation2 + - documentIndex: *statefulSetDoc + equal: + path: spec.volumeClaimTemplates[0].metadata.labels + value: + app: common-test-1.0.0 + release: RELEASE-NAME + helm-revision: 0 + helm.sh/chart: common-test-1.0.0 + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/version: *appVer + g_label1: global_label1 + g_label2: global_label2 + label1: label1 + label2: label2 diff --git a/library/common-test/tests/volumeClaimTemplate/names_test.yaml b/library/common-test/tests/volumeClaimTemplate/names_test.yaml new file mode 100644 index 0000000000..fd541c7291 --- /dev/null +++ b/library/common-test/tests/volumeClaimTemplate/names_test.yaml @@ -0,0 +1,32 @@ +suite: volumeClaimTemplates name test +templates: + - common.yaml +tests: + - it: should generate correct name + set: + volumeClaimTemplates: + my-volume1: + enabled: true + my-volume2: + enabled: true + workload: + main: + enabled: true + primary: true + type: StatefulSet + podSpec: {} + asserts: + - documentIndex: &statefulSetDoc 0 + isKind: + of: StatefulSet + - documentIndex: *statefulSetDoc + isAPIVersion: + of: apps/v1 + - documentIndex: *statefulSetDoc + equal: + path: spec.volumeClaimTemplates[0].metadata.name + value: my-volume1 + - documentIndex: *statefulSetDoc + equal: + path: spec.volumeClaimTemplates[1].metadata.name + value: my-volume2 diff --git a/library/common-test/tests/volumeClaimTemplate/validation_test.yaml b/library/common-test/tests/volumeClaimTemplate/validation_test.yaml new file mode 100644 index 0000000000..4af14ba0df --- /dev/null +++ b/library/common-test/tests/volumeClaimTemplate/validation_test.yaml @@ -0,0 +1,105 @@ +suite: volumeClaimTemplates validation test +templates: + - common.yaml +tests: + - it: should fail with annotations not a dict + set: + volumeClaimTemplates: + volume1: + enabled: true + annotations: not-a-dict + workload: + main: + enabled: true + primary: true + type: StatefulSet + podSpec: {} + asserts: + - failedTemplate: + errorMessage: Volume Claim Templates - Expected to be a dictionary, but got [string] + + - it: should fail with labels not a dict + set: + volumeClaimTemplates: + volume1: + enabled: true + labels: not-a-dict + workload: + main: + enabled: true + primary: true + type: StatefulSet + podSpec: {} + asserts: + - failedTemplate: + errorMessage: Volume Claim Templates - Expected to be a dictionary, but got [string] + + - it: should fail with pod targetSelector not a map + set: + volumeClaimTemplates: + volume1: + enabled: true + targetSelector: not-a-map + workload: + main: + enabled: true + primary: true + type: StatefulSet + podSpec: {} + asserts: + - failedTemplate: + errorMessage: Volume Claim Templates - Expected to be [dict], but got [string] + + - it: should fail without storageClassName in ixChartContext + set: + global: + ixChartContext: + storageClassName: "" + volumeClaimTemplates: + volume1: + enabled: true + workload: + main: + enabled: true + primary: true + type: StatefulSet + podSpec: {} + asserts: + - failedTemplate: + errorMessage: Volume Claim Templates - Expected non-empty + + - it: should fail without storageClassName in ixChartContext with SCALE-ZFS explicitly set + set: + global: + ixChartContext: + storageClassName: "" + volumeClaimTemplates: + volume1: + enabled: true + storageClass: SCALE-ZFS + workload: + main: + enabled: true + primary: true + type: StatefulSet + podSpec: {} + asserts: + - failedTemplate: + errorMessage: Volume Claim Templates - Expected non-empty on [SCALE-ZFS] storageClass + + - it: should fail with invalid accessMode + set: + volumeClaimTemplates: + volume1: + enabled: true + accessModes: + - not-an-access-mode + workload: + main: + enabled: true + primary: true + type: StatefulSet + podSpec: {} + asserts: + - failedTemplate: + errorMessage: Volume Claim Templates - Expected entry to be one of [ReadWriteOnce, ReadOnlyMany, ReadWriteMany, ReadWriteOncePod], but got [not-an-access-mode] diff --git a/library/common-test/tests/volumeClaimTemplate/vct_data_test.yaml b/library/common-test/tests/volumeClaimTemplate/vct_data_test.yaml new file mode 100644 index 0000000000..2b2d8473d7 --- /dev/null +++ b/library/common-test/tests/volumeClaimTemplate/vct_data_test.yaml @@ -0,0 +1,232 @@ +suite: volumeClaimTemplates data name test +templates: + - common.yaml +tests: + - it: should create vct + set: + volumeClaimTemplates: + my-volume1: + enabled: true + mountPath: /some/path + workload: + main: + enabled: true + primary: true + type: StatefulSet + podSpec: {} + asserts: + - documentIndex: &statefulSetDoc 0 + isKind: + of: StatefulSet + - documentIndex: *statefulSetDoc + isAPIVersion: + of: apps/v1 + - documentIndex: *statefulSetDoc + equal: + path: spec.volumeClaimTemplates[0].metadata.name + value: my-volume1 + - documentIndex: *statefulSetDoc + equal: + path: spec.volumeClaimTemplates[0].spec.accessModes + value: + - ReadWriteOnce + - documentIndex: *statefulSetDoc + equal: + path: spec.volumeClaimTemplates[0].spec.resources.requests.storage + value: 100Gi + - documentIndex: *statefulSetDoc + isNull: + path: spec.volumeClaimTemplates[0].spec.storageClassName + + - it: should create vct with accessModes set as string + set: + some_mode: ReadWriteMany + volumeClaimTemplates: + my-volume1: + enabled: true + mountPath: /some/path + accessModes: "{{ .Values.some_mode }}" + workload: + main: + enabled: true + primary: true + type: StatefulSet + podSpec: {} + asserts: + - documentIndex: *statefulSetDoc + isKind: + of: StatefulSet + - documentIndex: *statefulSetDoc + equal: + path: spec.volumeClaimTemplates[0].spec.accessModes + value: + - ReadWriteMany + + - it: should create pvc with accessModes set as list + set: + some_mode: ReadWriteMany + volumeClaimTemplates: + my-volume1: + enabled: true + mountPath: /some/path + accessModes: + - "{{ .Values.some_mode }}" + - ReadWriteOnce + workload: + main: + enabled: true + primary: true + type: StatefulSet + podSpec: {} + asserts: + - documentIndex: *statefulSetDoc + isKind: + of: StatefulSet + - documentIndex: *statefulSetDoc + equal: + path: spec.volumeClaimTemplates[0].spec.accessModes + value: + - ReadWriteMany + - ReadWriteOnce + + - it: should create pvc with size set + set: + volumeClaimTemplates: + my-volume1: + enabled: true + mountPath: /some/path + size: 20Gi + workload: + main: + enabled: true + primary: true + type: StatefulSet + podSpec: {} + asserts: + - documentIndex: *statefulSetDoc + isKind: + of: StatefulSet + - documentIndex: *statefulSetDoc + equal: + path: spec.volumeClaimTemplates[0].spec.resources.requests.storage + value: 20Gi + + - it: should create vct with storageClass set "-" + set: + some_storage_class: "-" + volumeClaimTemplates: + my-volume1: + enabled: true + mountPath: /some/path + storageClass: "{{ .Values.some_storage_class }}" + workload: + main: + enabled: true + primary: true + type: StatefulSet + podSpec: {} + asserts: + - documentIndex: *statefulSetDoc + isKind: + of: StatefulSet + - documentIndex: *statefulSetDoc + equal: + path: spec.volumeClaimTemplates[0].spec.storageClassName + value: "" + + - it: should create vct with storageClass set + set: + some_storage_class: some-storage-class + volumeClaimTemplates: + my-volume1: + enabled: true + mountPath: /some/path + storageClass: "{{ .Values.some_storage_class }}" + workload: + main: + enabled: true + primary: true + type: StatefulSet + podSpec: {} + asserts: + - documentIndex: *statefulSetDoc + isKind: + of: StatefulSet + - documentIndex: *statefulSetDoc + equal: + path: spec.volumeClaimTemplates[0].spec.storageClassName + value: some-storage-class + + - it: should create vct with storageClass not set, but have fallbackDefaults set + set: + fallbackDefaults: + storageClass: some-storage-class + volumeClaimTemplates: + my-volume1: + enabled: true + mountPath: /some/path + workload: + main: + enabled: true + primary: true + type: StatefulSet + podSpec: {} + asserts: + - documentIndex: *statefulSetDoc + isKind: + of: StatefulSet + - documentIndex: *statefulSetDoc + equal: + path: spec.volumeClaimTemplates[0].spec.storageClassName + value: some-storage-class + + - it: should create vct with storageClass set "SCALE-ZFS" and within ixChartContext + set: + global: + ixChartContext: + storageClassName: ix-storage-class-releasename + some_storage_class: "SCALE-ZFS" + volumeClaimTemplates: + my-volume1: + enabled: true + mountPath: /some/path + storageClass: "{{ .Values.some_storage_class }}" + workload: + main: + enabled: true + primary: true + type: StatefulSet + podSpec: {} + asserts: + - documentIndex: *statefulSetDoc + isKind: + of: StatefulSet + - documentIndex: *statefulSetDoc + equal: + path: spec.volumeClaimTemplates[0].spec.storageClassName + value: ix-storage-class-releasename + + - it: should create pvc with storageClass not set and within ixChartContext + set: + global: + ixChartContext: + storageClassName: ix-storage-class-releasename + some_storage_class: "SCALE-ZFS" + volumeClaimTemplates: + my-volume1: + enabled: true + mountPath: /some/path + workload: + main: + enabled: true + primary: true + type: StatefulSet + podSpec: {} + asserts: + - documentIndex: *statefulSetDoc + isKind: + of: StatefulSet + - documentIndex: *statefulSetDoc + equal: + path: spec.volumeClaimTemplates[0].spec.storageClassName + value: ix-storage-class-releasename diff --git a/library/common/1.0.0/docs/persistence/README.md b/library/common/1.0.0/docs/persistence/README.md index 04b750b6cc..d5602d2a7e 100644 --- a/library/common/1.0.0/docs/persistence/README.md +++ b/library/common/1.0.0/docs/persistence/README.md @@ -6,12 +6,12 @@ | persistence.[volume-name] | `dict` | ✅ | ❌ | `{}` | Holds persistence definition | | persistence.[volume-name].enabled | `boolean` | ✅ | ❌ | `false` | Enables or Disables the persistence | | persistence.[volume-name].type | `string` | ❌ | ❌ | `pvc` | Define the persistence type (pvc, ixVolume, nfs, hostPath, configmap, secret, device) | -| persistence.[volume-name].targetSelectAll | `boolean` | ❌ | ❌ | `false` | Define wether to define this volume to all workloads and mount it on all containers | -| persistence.[volume-name].targetSelector | `dict` | ❌ | ❌ | `{}` | Define a dict with pod and containers to mount | | persistence.[volume-name].mountPath | `string` | ✅ | ✅ | `""` | Default mountPath for all containers that are selected | | persistence.[volume-name].mountPropagation | `string` | ❌ | ✅ | `""` | Default mountPropagation for all containers that are selected | | persistence.[volume-name].subPath | `string` | ❌ | ✅ | `""` | Default subPath for all containers that are selected | | persistence.[volume-name].readOnly | `boolean` | ❌ | ❌ | `false` | Default readOnly for all containers that are selected | +| persistence.[volume-name].targetSelectAll | `boolean` | ❌ | ❌ | `false` | Define wether to define this volume to all workloads and mount it on all containers | +| persistence.[volume-name].targetSelector | `dict` | ❌ | ❌ | `{}` | Define a dict with pod and containers to mount | | persistence.[volume-name].targetSelector.[pod-name] | `dict` | ❌ | ❌ | `{}` | Define a dict named after the pod to define the volume | | persistence.[volume-name].targetSelector.[pod-name].[container-name] | `dict` | ❌ | ❌ | `{}` | Define a dict named after the container to mount the volume | | persistence.[volume-name].targetSelector.[pod-name].[container-name].mountPath | `string` | ❌ | ✅ | `[volume-name].mountPath` | Define the mountPath for the container | diff --git a/library/common/1.0.0/docs/volumeClaimTemplates.md b/library/common/1.0.0/docs/volumeClaimTemplates.md new file mode 100644 index 0000000000..7d8deddfaf --- /dev/null +++ b/library/common/1.0.0/docs/volumeClaimTemplates.md @@ -0,0 +1,82 @@ +# Volume Claim Template + +| Key | Type | Required | Helm Template | Default | Description | +| :------------------------------------------------------------------------------------------ | :-----------: | :------: | :----------------: | :----------------------------------------------------: | :----------------------------------------------------------------------------------------------- | +| volumeClaimTemplates | `dict` | ❌ | ❌ | `{}` | Define the VCT as dicts | +| volumeClaimTemplates.[vct-name] | `dict` | ✅ | ❌ | `{}` | Holds VCT definition | +| volumeClaimTemplates.[vct-name].enabled | `boolean` | ✅ | ❌ | `false` | Enables or Disables the VCT | +| volumeClaimTemplates.[vct-name].labels | `dict` | ❌ | ✅ (On value only) | `{}` | Labels for the VCT | +| volumeClaimTemplates.[vct-name].annotations | `dict` | ❌ | ✅ (On value only) | `{}` | Annotations for the VCT | +| volumeClaimTemplates.[vct-name].size | `string` | ❌ | ✅ | `{{ .Values.global.fallbackDefaults.pvcSize }}` | Define the size of the PVC | +| volumeClaimTemplates.[vct-name].accessModes | `string/list` | ❌ | ✅ | `{{ .Values.global.fallbackDefaults.pvcAccessModes }}` | Define the accessModes of the PVC, if it's single can be defined as a string, multiple as a list | +| volumeClaimTemplates.[vct-name].storageClassName | `string` | ❌ | ✅ | See bellow | Define an existing claim to use | +| volumeClaimTemplates.[vct-name].mountPath | `string` | ✅ | ✅ | `""` | Default mountPath for all containers that are selected | +| volumeClaimTemplates.[vct-name].mountPropagation | `string` | ❌ | ✅ | `""` | Default mountPropagation for all containers that are selected | +| volumeClaimTemplates.[vct-name].subPath | `string` | ❌ | ✅ | `""` | Default subPath for all containers that are selected | +| volumeClaimTemplates.[vct-name].readOnly | `boolean` | ❌ | ❌ | `false` | Default readOnly for all containers that are selected | +| volumeClaimTemplates.[vct-name].targetSelector | `dict` | ❌ | ❌ | `{}` | Define a dict with pod and containers to mount | +| volumeClaimTemplates.[vct-name].targetSelector.[pod-name] | `dict` | ❌ | ❌ | `{}` | Define a dict named after the pod to define the volume | +| volumeClaimTemplates.[vct-name].targetSelector.[pod-name].[container-name] | `dict` | ❌ | ❌ | `{}` | Define a dict named after the container to mount the volume | +| volumeClaimTemplates.[vct-name].targetSelector.[pod-name].[container-name].mountPath | `string` | ❌ | ✅ | `[vct-name].mountPath` | Define the mountPath for the container | +| volumeClaimTemplates.[vct-name].targetSelector.[pod-name].[container-name].mountPropagation | `string` | ❌ | ✅ | `[vct-name].mountPropagation` | Define the mountPropagation for the container | +| volumeClaimTemplates.[vct-name].targetSelector.[pod-name].[container-name].subPath | `string` | ❌ | ✅ | `[vct-name].subPath` | Define the subPath for the container | +| volumeClaimTemplates.[vct-name].targetSelector.[pod-name].[container-name].readOnly | `boolean` | ❌ | ❌ | `[vct-name].readOnly` | Define the readOnly for the container | + +> When `targetSelector` is a empty, it will define the volume to the primary pod and volumeMount to the primary container +> When `targetSelector` is defined, referencing pod(s) and container(s) it will define the volume to those pod(s) and volumeMount to those container(s) + +--- + +Appears in: + +- `.Values.volumeClaimTemplates` + +--- + +Naming scheme: + +- `$FullName-$VolumeClaimTemplateName` (release-name-chart-name-VolumeClaimTemplateName) + +--- + +Examples: + +```yaml +# Example of a shared emptyDir volume +volumeClaimTemplates: + vct-name: + enabled: true + mountPath: /shared + readOnly: false + targetSelectAll: true +``` + +```yaml +# Example of a volume mounted to a specific container with a specific mountPath +volumeClaimTemplates: + db-data: + enabled: true + targetSelector: + my-pod: + my-container: {} + mountPath: /path + readOnly: false + my-other-container: {} + mountPath: /other/path + readOnly: false +``` + +```yaml +# Example of a volume mounted to a specific container using the default mountPath +persistence: + db-data: + enabled: true + mountPath: /path + readOnly: true + targetSelector: + my-pod: + my-container: {} + my-other-container: + mountPath: /other/path + readOnly: false +``` diff --git a/library/common/1.0.0/templates/class/_pvc.tpl b/library/common/1.0.0/templates/class/_pvc.tpl index d89e2dcff9..972f54c0d2 100644 --- a/library/common/1.0.0/templates/class/_pvc.tpl +++ b/library/common/1.0.0/templates/class/_pvc.tpl @@ -43,14 +43,14 @@ metadata: {{- end }} spec: accessModes: - {{- include "ix.v1.common.lib.pvc.accessModes" (dict "rootCtx" $rootCtx "objectData" $objectData) | trim | nindent 4 }} + {{- include "ix.v1.common.lib.pvc.accessModes" (dict "rootCtx" $rootCtx "objectData" $objectData "caller" "PVC") | trim | nindent 4 }} resources: requests: storage: {{ $pvcSize }} {{- with $objectData.volumeName }} volumeName: {{ tpl . $rootCtx }} {{- end -}} - {{- with (include "ix.v1.common.lib.pvc.storageClassName" (dict "rootCtx" $rootCtx "objectData" $objectData) | trim) }} + {{- with (include "ix.v1.common.lib.pvc.storageClassName" (dict "rootCtx" $rootCtx "objectData" $objectData "caller" "PVC") | trim) }} storageClassName: {{ . }} {{- end -}} {{- end -}} diff --git a/library/common/1.0.0/templates/class/_statefulset.tpl b/library/common/1.0.0/templates/class/_statefulset.tpl index 1a3c959f02..72215d4b8d 100644 --- a/library/common/1.0.0/templates/class/_statefulset.tpl +++ b/library/common/1.0.0/templates/class/_statefulset.tpl @@ -51,5 +51,9 @@ spec: {{- end }} spec: {{- include "ix.v1.common.lib.workload.pod" (dict "rootCtx" $rootCtx "objectData" $objectData) | trim | nindent 6 }} + {{- with (include "ix.v1.common.lib.workload.volumeClaimTemplates" (dict "rootCtx" $rootCtx "objectData" $objectData) | trim) }} + volumeClaimTemplates: + {{- . | nindent 4 }} + {{- end }} {{- end -}} {{/* TODO: VCT */}} diff --git a/library/common/1.0.0/templates/lib/container/_volumeMounts.tpl b/library/common/1.0.0/templates/lib/container/_volumeMounts.tpl index 8e072bca91..144b8c954e 100644 --- a/library/common/1.0.0/templates/lib/container/_volumeMounts.tpl +++ b/library/common/1.0.0/templates/lib/container/_volumeMounts.tpl @@ -10,46 +10,54 @@ objectData: The object data to be used to render the container. {{- $volMounts := list -}} - {{- range $persistenceName, $persistenceValues := $rootCtx.Values.persistence -}} + {{- $keys := (list "persistence") -}} + {{- if eq $objectData.podType "StatefulSet" -}} + {{- $keys = mustAppend $keys "volumeClaimTemplates" -}} + {{- end -}} - {{/* Initialize from the default values */}} - {{- $volMount := dict -}} - {{- $_ := set $volMount "name" $persistenceName -}} - {{- $_ := set $volMount "mountPath" ($persistenceValues.mountPath | default "") -}} - {{- $_ := set $volMount "subPath" ($persistenceValues.subPath | default "") -}} - {{- $_ := set $volMount "readOnly" ($persistenceValues.readOnly | default false) -}} - {{- $_ := set $volMount "mountPropagation" ($persistenceValues.mountPropagation | default "") -}} + {{- range $key := $keys -}} + {{- range $persistenceName, $persistenceValues := (get $rootCtx.Values $key) -}} - {{/* If persistence is enabled... */}} - {{- if $persistenceValues.enabled -}} - {{/* If targetSelectAll is set, means all pods/containers */}} - {{- if $persistenceValues.targetSelectAll -}} - {{- $volMounts = mustAppend $volMounts $volMount -}} + {{/* Initialize from the default values */}} + {{- $volMount := dict -}} + {{- $_ := set $volMount "name" $persistenceName -}} + {{- $_ := set $volMount "key" $key -}} + {{- $_ := set $volMount "mountPath" ($persistenceValues.mountPath | default "") -}} + {{- $_ := set $volMount "subPath" ($persistenceValues.subPath | default "") -}} + {{- $_ := set $volMount "readOnly" ($persistenceValues.readOnly | default false) -}} + {{- $_ := set $volMount "mountPropagation" ($persistenceValues.mountPropagation | default "") -}} - {{/* Else if selector is defined */}} - {{- else if $persistenceValues.targetSelector -}} - {{/* If pod is selected */}} - {{- if mustHas $objectData.podShortName ($persistenceValues.targetSelector | keys) -}} - {{- $selectorValues := (get $persistenceValues.targetSelector $objectData.podShortName) -}} - {{- if not (kindIs "map" $selectorValues) -}} - {{- fail (printf "Persistence - Expected to be a [dict], but got [%s]" $objectData.podShortName (kindOf $selectorValues)) -}} + {{/* If persistence is enabled... */}} + {{- if $persistenceValues.enabled -}} + {{/* If targetSelectAll is set, means all pods/containers */}} {{/* targetSelectAll does not make sense for vct */}} + {{- if and $persistenceValues.targetSelectAll (ne $key "volumeClaimTemplates") -}} + {{- $volMounts = mustAppend $volMounts $volMount -}} + + {{/* Else if selector is defined */}} + {{- else if $persistenceValues.targetSelector -}} + {{/* If pod is selected */}} + {{- if mustHas $objectData.podShortName ($persistenceValues.targetSelector | keys) -}} + {{- $selectorValues := (get $persistenceValues.targetSelector $objectData.podShortName) -}} + {{- if not (kindIs "map" $selectorValues) -}} + {{- fail (printf "%s - Expected to be a [dict], but got [%s]" (camelcase $key) $objectData.podShortName (kindOf $selectorValues)) -}} + {{- end -}} + + {{- if not $selectorValues -}} + {{- fail (printf "%s - Expected non-empty " (camelcase $key) $objectData.podShortName) -}} + {{- end -}} + + {{/* If container is selected */}} + {{- if mustHas $objectData.shortName ($selectorValues | keys) -}} + {{/* Merge with values that might be set for the specific container */}} + {{- $volMount = mustMergeOverwrite $volMount (get $selectorValues $objectData.shortName) -}} + {{- $volMounts = mustAppend $volMounts $volMount -}} + {{- end -}} {{- end -}} - {{- if not $selectorValues -}} - {{- fail (printf "Persistence - Expected non-empty " $objectData.podShortName) -}} - {{- end -}} - - {{/* If container is selected */}} - {{- if mustHas $objectData.shortName ($selectorValues | keys) -}} - {{/* Merge with values that might be set for the specific container */}} - {{- $volMount = mustMergeOverwrite $volMount (get $selectorValues $objectData.shortName) -}} - {{- $volMounts = mustAppend $volMounts $volMount -}} - {{- end -}} + {{/* Else if not selector, but pod and container is primary */}} + {{- else if and $objectData.podPrimary $objectData.primary -}} + {{- $volMounts = mustAppend $volMounts $volMount -}} {{- end -}} - - {{/* Else if not selector, but pod and container is primary */}} - {{- else if and $objectData.podPrimary $objectData.primary -}} - {{- $volMounts = mustAppend $volMounts $volMount -}} {{- end -}} {{- end -}} {{- end -}} @@ -61,20 +69,20 @@ objectData: The object data to be used to render the container. {{- $_ := set $volMount "mountPropagation" (tpl $volMount.mountPropagation $rootCtx) -}} {{- if not $volMount.mountPath -}} - {{- fail "Persistence - Expected non-empty " -}} + {{- fail (printf "%s - Expected non-empty " (camelcase $volMount.key)) -}} {{- end -}} {{- if not (hasPrefix "/" $volMount.mountPath) -}} - {{- fail "Persistence - Expected to start with a forward slash [/]" -}} + {{- fail (printf "%s - Expected to start with a forward slash [/]" (camelcase $volMount.key)) -}} {{- end -}} {{- $propagationTypes := (list "None" "HostToContainer" "Bidirectional") -}} {{- if and $volMount.mountPropagation (not (mustHas $volMount.mountPropagation $propagationTypes)) -}} - {{- fail (printf "Persistence - Expected to be one of [%s], but got [%s]" (join ", " $propagationTypes) $volMount.mountPropagation) -}} + {{- fail (printf "%s - Expected to be one of [%s], but got [%s]" (camelcase $volMount.key) (join ", " $propagationTypes) $volMount.mountPropagation) -}} {{- end -}} {{- if not (kindIs "bool" $volMount.readOnly) -}} - {{- fail (printf "Persistence - Expected to be [boolean], but got [%s]" (kindOf $volMount.readOnly)) -}} + {{- fail (printf "%s - Expected to be [boolean], but got [%s]" (camelcase $volMount.key) (kindOf $volMount.readOnly)) -}} {{- end }} - name: {{ $volMount.name }} mountPath: {{ $volMount.mountPath }} diff --git a/library/common/1.0.0/templates/lib/storage/_accessModes.tpl b/library/common/1.0.0/templates/lib/storage/_accessModes.tpl index 2b9d0458a6..0ea1d3f899 100644 --- a/library/common/1.0.0/templates/lib/storage/_accessModes.tpl +++ b/library/common/1.0.0/templates/lib/storage/_accessModes.tpl @@ -8,6 +8,7 @@ objectData: The object data of the pvc {{- define "ix.v1.common.lib.pvc.accessModes" -}} {{- $rootCtx := .rootCtx -}} {{- $objectData := .objectData -}} + {{- $caller := .caller -}} {{- $accessModes := $objectData.accessModes -}} @@ -16,7 +17,7 @@ objectData: The object data of the pvc {{- end -}} {{- if not $accessModes -}} - {{- $accessModes = $rootCtx.Values.fallbackDefaults.pvcAccessModes -}} + {{- $accessModes = $rootCtx.Values.fallbackDefaults.accessModes -}} {{- end -}} {{- $validAccessModes := (list "ReadWriteOnce" "ReadOnlyMany" "ReadWriteMany" "ReadWriteOncePod") -}} @@ -24,7 +25,7 @@ objectData: The object data of the pvc {{- range $accessModes -}} {{- $mode := tpl . $rootCtx -}} {{- if not (mustHas $mode $validAccessModes) -}} - {{- fail (printf "PVC - Expected entry to be one of [%s], but got [%s]" (join ", " $validAccessModes) $mode) -}} + {{- fail (printf "%s - Expected entry to be one of [%s], but got [%s]" $caller (join ", " $validAccessModes) $mode) -}} {{- end }} - {{ $mode }} {{- end -}} diff --git a/library/common/1.0.0/templates/lib/storage/_storageClassName.tpl b/library/common/1.0.0/templates/lib/storage/_storageClassName.tpl index b716536401..f7033a7dc2 100644 --- a/library/common/1.0.0/templates/lib/storage/_storageClassName.tpl +++ b/library/common/1.0.0/templates/lib/storage/_storageClassName.tpl @@ -7,6 +7,7 @@ objectData: The object data of the pvc {{- define "ix.v1.common.lib.pvc.storageClassName" -}} {{- $objectData := .objectData -}} {{- $rootCtx := .rootCtx -}} + {{- $caller := .caller -}} {{/* If storageClass is defined on the objectData: @@ -30,7 +31,7 @@ objectData: The object data of the pvc {{- $className = "\"\"" -}} {{- else if eq "SCALE-ZFS" $storageClass -}} {{- if not $rootCtx.Values.global.ixChartContext.storageClassName -}} - {{- fail "PVC - Expected non-empty on [SCALE-ZFS] storageClass" -}} + {{- fail (printf "%s - Expected non-empty on [SCALE-ZFS] storageClass" $caller) -}} {{- end -}} {{- $className = tpl $rootCtx.Values.global.ixChartContext.storageClassName $rootCtx -}} {{- else -}} @@ -39,7 +40,7 @@ objectData: The object data of the pvc {{- else if $rootCtx.Values.global.ixChartContext -}} {{- if not $rootCtx.Values.global.ixChartContext.storageClassName -}} - {{- fail "PVC - Expected non-empty " -}} + {{- fail (printf "%s - Expected non-empty " $caller) -}} {{- end -}} {{- $className = tpl $rootCtx.Values.global.ixChartContext.storageClassName $rootCtx -}} diff --git a/library/common/1.0.0/templates/lib/storage/_validation.tpl b/library/common/1.0.0/templates/lib/storage/_validation.tpl index 42c3e35071..1d19f7f6e1 100644 --- a/library/common/1.0.0/templates/lib/storage/_validation.tpl +++ b/library/common/1.0.0/templates/lib/storage/_validation.tpl @@ -3,7 +3,7 @@ {{ include "ix.v1.common.lib.persistence.validation" (dict "objectData" $objectData) -}} objectData: rootCtx: The root context of the chart. - objectData: The service object. + objectData: The pvc object. */}} {{- define "ix.v1.common.lib.persistence.validation" -}} @@ -20,3 +20,20 @@ objectData: {{- end -}} {{- end -}} + +{{/* VCT Validation */}} +{{/* Call this template: +{{ include "ix.v1.common.lib.vct.validation" (dict "objectData" $objectData) -}} +objectData: + rootCtx: The root context of the chart. + objectData: The vct object. +*/}} + +{{- define "ix.v1.common.lib.vct.validation" -}} + {{- $objectData := .objectData -}} + + {{- if and $objectData.targetSelector (not (kindIs "map" $objectData.targetSelector)) -}} + {{- fail (printf "Volume Claim Templates - Expected to be [dict], but got [%s]" (kindOf $objectData.targetSelector)) -}} + {{- end -}} + +{{- end -}} diff --git a/library/common/1.0.0/templates/lib/storage/_volumeClaimTemplates.tpl b/library/common/1.0.0/templates/lib/storage/_volumeClaimTemplates.tpl new file mode 100644 index 0000000000..8cda93d0df --- /dev/null +++ b/library/common/1.0.0/templates/lib/storage/_volumeClaimTemplates.tpl @@ -0,0 +1,66 @@ +{{/* Returns Volume Claim Templates */}} +{{/* Call this template: +{{ include "ix.v1.common.lib.workload.volumeClaimTemplates" (dict "rootCtx" $ "objectData" $objectData) }} +rootCtx: The root context of the chart. +objectData: The object data to be used to render the Pod. +*/}} +{{- define "ix.v1.common.lib.workload.volumeClaimTemplates" -}} + {{- $rootCtx := .rootCtx -}} + {{- $objectData := .objectData -}} + + {{- range $name, $vctValues := $rootCtx.Values.volumeClaimTemplates -}} + + {{- if $vctValues.enabled -}} + {{- $vct := (mustDeepCopy $vctValues) -}} + + {{- $selected := false -}} + {{- $_ := set $vct "shortName" $name -}} + + {{- include "ix.v1.common.lib.vct.validation" (dict "objectData" $vct) -}} + {{- include "ix.v1.common.lib.chart.names.validation" (dict "name" $vct.shortName) -}} + {{- include "ix.v1.common.lib.metadata.validation" (dict "objectData" $vct "caller" "Volume Claim Templates") -}} + + {{/* If targetSelector is set, check if pod is selected */}} + {{- if $vct.targetSelector -}} + {{- if (mustHas $objectData.shortName (keys $vct.targetSelector)) -}} + {{- $selected = true -}} + {{- end -}} + + {{/* If no targetSelector is set or targetSelectAll, check if pod is primary */}} + {{- else -}} + {{- if $objectData.primary -}} + {{- $selected = true -}} + {{- end -}} + {{- end -}} + + {{/* If pod selected */}} + {{- if $selected -}} + {{- $vctSize := $rootCtx.Values.fallbackDefaults.vctSize -}} + {{- with $vct.size -}} + {{- $vctSize = tpl . $rootCtx -}} + {{- end }} +- metadata: + name: {{ $vct.shortName }} + {{- $labels := (mustMerge ($vct.labels | default dict) (include "ix.v1.common.lib.metadata.allLabels" $rootCtx | fromYaml)) -}} + {{- with (include "ix.v1.common.lib.metadata.render" (dict "rootCtx" $rootCtx "labels" $labels) | trim) }} + labels: + {{- . | nindent 6 }} + {{- end -}} + {{- $annotations := (mustMerge ($vct.annotations | default dict) (include "ix.v1.common.lib.metadata.allAnnotations" $rootCtx | fromYaml)) -}} + {{- with (include "ix.v1.common.lib.metadata.render" (dict "rootCtx" $rootCtx "annotations" $annotations) | trim) }} + annotations: + {{- . | nindent 6 }} + {{- end }} + spec: + {{- with (include "ix.v1.common.lib.pvc.storageClassName" (dict "rootCtx" $rootCtx "objectData" $vct "caller" "Volume Claim Templates") | trim) }} + storageClassName: {{ . }} + {{- end }} + accessModes: + {{- include "ix.v1.common.lib.pvc.accessModes" (dict "rootCtx" $rootCtx "objectData" $vct "caller" "Volume Claim Templates") | trim | nindent 6 }} + resources: + requests: + storage: {{ $vctSize }} + {{- end -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/library/common/1.0.0/templates/lib/workload/_pod.tpl b/library/common/1.0.0/templates/lib/workload/_pod.tpl index 30baf93ec9..0f11fb60a4 100644 --- a/library/common/1.0.0/templates/lib/workload/_pod.tpl +++ b/library/common/1.0.0/templates/lib/workload/_pod.tpl @@ -59,6 +59,7 @@ containers: {{- $_ := set $container "shortName" $containerName -}} {{- $_ := set $container "podShortName" $objectData.shortName -}} {{- $_ := set $container "podPrimary" $objectData.primary -}} + {{- $_ := set $container "podType" $objectData.type -}} {{- include "ix.v1.common.lib.pod.container" (dict "rootCtx" $rootCtx "objectData" $container) | trim | nindent 2 }} {{- end -}} {{- end -}} diff --git a/library/common/1.0.0/values.yaml b/library/common/1.0.0/values.yaml index 5b7ba2260a..16c4228dd7 100644 --- a/library/common/1.0.0/values.yaml +++ b/library/common/1.0.0/values.yaml @@ -27,8 +27,10 @@ fallbackDefaults: pvcRetain: false # -- Default PVC Size pvcSize: 1Gi - # -- Default PVC Access Modes - pvcAccessModes: + # -- Default VCT Size + vctSize: 100Gi + # -- Default PVC/VCT Access Modes + accessModes: - ReadWriteOnce # TODO: Docs (for the imageName) convention @@ -112,7 +114,7 @@ workload: main: enabled: true primary: true - type: Deployment + type: StatefulSet podSpec: # TODO: Currently implementing containers: @@ -171,37 +173,6 @@ workload: # TODO: portal: {} -# -- VolumeClaimTemplates (StatefulSet only) -volumeClaimTemplates: - # -- VolumeClaimTemplate name - vct-name: - # -- Enables the VolumeClaimTemplate - enabled: true - # -- VolumeClaimTemplate labels - labels: {} - # -- VolumeClaimTemplate annotations - annotations: {} - # -- VolumeClaimTemplate access modes - accessModes: - - ReadWriteOnce - # -- VolumeClaimTemplate storage class - storageClassName: "" - # -- VolumeClaimTemplate size - size: 1Gi - # -- Options that apply to all volumeMounts - # Can be overruled per volumeMount under targetSelector - # -- VolumeClaimTemplate mount path - mountPath: /data - readOnly: false - subPath: "" - mountPropagation: "" - # targetSelector: - # pod-name: - # container-name: - # mountPath: /data - # readOnly: false - # subPath: "" - # mountPropagation: "" # -- SCALE GPU (TODO: Only the resources part is left) scaleGPU: @@ -280,6 +251,9 @@ serviceAccount: {} # -- (docs/rbac.md) rbac: {} +# -- (docs/volumeClaimTemplates) (StatefulSet only) +volumeClaimTemplates: {} + # -- (docs/scaleExternalInterface.md) scaleExternalInterface: []