diff --git a/library/common-test/tests/persistence/pvc_with_snapshot.yaml b/library/common-test/tests/persistence/pvc_with_snapshot.yaml new file mode 100644 index 00000000..ba9cb7fc --- /dev/null +++ b/library/common-test/tests/persistence/pvc_with_snapshot.yaml @@ -0,0 +1,79 @@ +suite: persistence pvc with snapshots test +templates: + - common.yaml +release: + name: test-release-name + namespace: test-release-namespace +tests: + - it: should generate correct pvc and snapshot + set: + persistence: + my-volume1: + enabled: true + type: pvc + volumeSnapshots: + - name: example1 + enabled: true + volumeSnapshotClassName: some-name + my-volume2: + enabled: true + type: pvc + volumeSnapshots: + - name: example1 + enabled: true + volumeSnapshotClassName: some-name + asserts: + - documentIndex: &pvcDoc 0 + isKind: + of: PersistentVolumeClaim + - documentIndex: *pvcDoc + isAPIVersion: + of: v1 + - documentIndex: *pvcDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-volume1 + - documentIndex: &volumeSnapshotDoc 1 + isKind: + of: VolumeSnapshot + - documentIndex: *volumeSnapshotDoc + isAPIVersion: + of: snapshot.storage.k8s.io/v1 + - documentIndex: *volumeSnapshotDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-volume1-example1 + - documentIndex: *volumeSnapshotDoc + equal: + path: spec + value: + volumeSnapshotClassName: some-name + source: + persistentVolumeClaimName: test-release-name-common-test-my-volume1 + - documentIndex: &otherPvcDoc 2 + isKind: + of: PersistentVolumeClaim + - documentIndex: *otherPvcDoc + isAPIVersion: + of: v1 + - documentIndex: *otherPvcDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-volume2 + - documentIndex: &otherVolumeSnapshotDoc 3 + isKind: + of: VolumeSnapshot + - documentIndex: *otherVolumeSnapshotDoc + isAPIVersion: + of: snapshot.storage.k8s.io/v1 + - documentIndex: *otherVolumeSnapshotDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-volume2-example1 + - documentIndex: *otherVolumeSnapshotDoc + equal: + path: spec + value: + volumeSnapshotClassName: some-name + source: + persistentVolumeClaimName: test-release-name-common-test-my-volume2 diff --git a/library/common-test/tests/priorityClass/metadata_test.yaml b/library/common-test/tests/priorityClass/metadata_test.yaml index 326606bd..717593b0 100644 --- a/library/common-test/tests/priorityClass/metadata_test.yaml +++ b/library/common-test/tests/priorityClass/metadata_test.yaml @@ -30,10 +30,13 @@ tests: annotation1: "{{ .Values.annotation1 }}" annotation2: annotation2 asserts: - - documentIndex: &storageClassDoc 0 + - documentIndex: &priorityClassDoc 0 isKind: of: PriorityClass - - documentIndex: *storageClassDoc + - documentIndex: &priorityClassDoc 0 + isAPIVersion: + of: scheduling.k8s.io/v1 + - documentIndex: *priorityClassDoc equal: path: metadata.annotations value: @@ -41,7 +44,7 @@ tests: annotation2: annotation2 g_annotation1: global_annotation1 g_annotation2: global_annotation2 - - documentIndex: *storageClassDoc + - documentIndex: *priorityClassDoc equal: path: metadata.labels value: diff --git a/library/common-test/tests/priorityClass/spec_test.yaml b/library/common-test/tests/priorityClass/spec_test.yaml index faa1e8e3..d5a78352 100644 --- a/library/common-test/tests/priorityClass/spec_test.yaml +++ b/library/common-test/tests/priorityClass/spec_test.yaml @@ -1,4 +1,4 @@ -suite: priorityClass name test +suite: priorityClass spec test templates: - common.yaml release: diff --git a/library/common-test/tests/storageClass/metadata_test.yaml b/library/common-test/tests/storageClass/metadata_test.yaml index fdfb1fdf..0a486051 100644 --- a/library/common-test/tests/storageClass/metadata_test.yaml +++ b/library/common-test/tests/storageClass/metadata_test.yaml @@ -34,6 +34,9 @@ tests: - documentIndex: &storageClassDoc 0 isKind: of: StorageClass + - documentIndex: *storageClassDoc + isAPIVersion: + of: storage.k8s.io/v1 - documentIndex: *storageClassDoc equal: path: metadata.annotations diff --git a/library/common-test/tests/storageClass/spec_test.yaml b/library/common-test/tests/storageClass/spec_test.yaml index fd897236..d55436a2 100644 --- a/library/common-test/tests/storageClass/spec_test.yaml +++ b/library/common-test/tests/storageClass/spec_test.yaml @@ -1,4 +1,4 @@ -suite: storageClass name test +suite: storageClass spec test templates: - common.yaml release: diff --git a/library/common-test/tests/volumeSnapshot/metadata_test.yaml b/library/common-test/tests/volumeSnapshot/metadata_test.yaml new file mode 100644 index 00000000..3b453380 --- /dev/null +++ b/library/common-test/tests/volumeSnapshot/metadata_test.yaml @@ -0,0 +1,64 @@ +suite: volumeSnapshot metadata test +templates: + - common.yaml +chart: + appVersion: &appVer v9.9.9 +release: + name: test-release-name + namespace: test-release-namespace +tests: + - it: should pass with volumeSnapshot 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 }}" + volumeSnapshots: + - name: example1 + enabled: true + source: + volumeSnapshotContentName: some-name + labels: + label1: "{{ .Values.label1 }}" + label2: label2 + annotations: + annotation1: "{{ .Values.annotation1 }}" + annotation2: annotation2 + asserts: + - documentIndex: &volumeSnapshotDoc 0 + isKind: + of: VolumeSnapshot + - documentIndex: &volumeSnapshotDoc 0 + isAPIVersion: + of: snapshot.storage.k8s.io/v1 + - documentIndex: *volumeSnapshotDoc + equal: + path: metadata.annotations + value: + annotation1: annotation1 + annotation2: annotation2 + g_annotation1: global_annotation1 + g_annotation2: global_annotation2 + - documentIndex: *volumeSnapshotDoc + equal: + path: metadata.labels + value: + app: common-test-1.0.0 + release: test-release-name + helm-revision: "0" + helm.sh/chart: common-test-1.0.0 + app.kubernetes.io/name: common-test + app.kubernetes.io/instance: test-release-name + 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/volumeSnapshot/names_test.yaml b/library/common-test/tests/volumeSnapshot/names_test.yaml new file mode 100644 index 00000000..cb5a4752 --- /dev/null +++ b/library/common-test/tests/volumeSnapshot/names_test.yaml @@ -0,0 +1,39 @@ +suite: volumeSnapshot name test +templates: + - common.yaml +release: + name: test-release-name + namespace: test-release-namespace +tests: + - it: should generate correct name + set: + volumeSnapshots: + - name: example1 + enabled: true + source: + volumeSnapshotContentName: some-name + - name: example2 + enabled: true + source: + volumeSnapshotContentName: some-name + asserts: + - documentIndex: &volumeSnapshotDoc 0 + isKind: + of: VolumeSnapshot + - documentIndex: *volumeSnapshotDoc + isAPIVersion: + of: snapshot.storage.k8s.io/v1 + - documentIndex: *volumeSnapshotDoc + equal: + path: metadata.name + value: test-release-name-common-test-example1 + - documentIndex: &otherVolumeSnapshotDoc 1 + isKind: + of: VolumeSnapshot + - documentIndex: *otherVolumeSnapshotDoc + isAPIVersion: + of: snapshot.storage.k8s.io/v1 + - documentIndex: *otherVolumeSnapshotDoc + equal: + path: metadata.name + value: test-release-name-common-test-example2 diff --git a/library/common-test/tests/volumeSnapshot/spec_test.yaml b/library/common-test/tests/volumeSnapshot/spec_test.yaml new file mode 100644 index 00000000..c8d7a18d --- /dev/null +++ b/library/common-test/tests/volumeSnapshot/spec_test.yaml @@ -0,0 +1,106 @@ +suite: volumeSnapshot spec test +templates: + - common.yaml +release: + name: test-release-name + namespace: test-release-namespace +tests: + - it: should generate correct spec + set: + volumeSnapshots: + - name: example1 + enabled: true + source: + volumeSnapshotContentName: some-name + - name: example2 + enabled: true + source: + persistentVolumeClaimName: some-pvc-name + asserts: + - documentIndex: &volumeSnapshotDoc 0 + isKind: + of: VolumeSnapshot + - documentIndex: *volumeSnapshotDoc + isAPIVersion: + of: snapshot.storage.k8s.io/v1 + - documentIndex: *volumeSnapshotDoc + equal: + path: spec + value: + source: + volumeSnapshotContentName: some-name + - documentIndex: &otherVolumeSnapshotDoc 1 + isKind: + of: VolumeSnapshot + - documentIndex: *otherVolumeSnapshotDoc + isAPIVersion: + of: snapshot.storage.k8s.io/v1 + - documentIndex: *otherVolumeSnapshotDoc + equal: + path: spec + value: + source: + persistentVolumeClaimName: some-pvc-name + + - it: should generate correct spec with volumeSnapshotClass + set: + volumeSnapshots: + - name: example1 + enabled: true + volumeSnapshotClassName: some-class + source: + volumeSnapshotContentName: some-name + asserts: + - documentIndex: &volumeSnapshotDoc 0 + isKind: + of: VolumeSnapshot + - documentIndex: *volumeSnapshotDoc + equal: + path: spec + value: + volumeSnapshotClassName: some-class + source: + volumeSnapshotContentName: some-name + + # Failures + - it: should fail without name + set: + volumeSnapshots: + - enabled: true + source: + volumeSnapshotContentName: some-name + asserts: + - failedTemplate: + errorMessage: VolumeSnapshot - Expected non empty [name] + + - it: should fail without source object + set: + volumeSnapshots: + - name: example1 + enabled: true + asserts: + - failedTemplate: + errorMessage: VolumeSnapshot - Expected non empty [source] + + - it: should fail without a valid source + set: + volumeSnapshots: + - name: example1 + enabled: true + source: + invalid: invalid + asserts: + - failedTemplate: + errorMessage: VolumeSnapshot - Expected exactly one of the valid source types [volumeSnapshotContentName, persistentVolumeClaimName]. Found [0] + + - it: should fail with more than one valid source + set: + volumeSnapshots: + - name: example1 + enabled: true + source: + volumeSnapshotContentName: some-name + persistentVolumeClaimName: some-pvc-name + asserts: + - failedTemplate: + errorMessage: VolumeSnapshot - Expected exactly one of the valid source types [volumeSnapshotContentName, persistentVolumeClaimName]. Found [2] diff --git a/library/common/templates/class/_volumeSnapshot.tpl b/library/common/templates/class/_volumeSnapshot.tpl new file mode 100644 index 00000000..21d4c33b --- /dev/null +++ b/library/common/templates/class/_volumeSnapshot.tpl @@ -0,0 +1,46 @@ +{{/* volumesnapshot Class */}} +{{/* Call this template: +{{ include "tc.v1.common.class.volumesnapshot" (dict "rootCtx" $ "objectData" $objectData) }} + +rootCtx: The root context of the chart. +objectData: + name: The name of the volumesnapshot. + labels: The labels of the volumesnapshot. + annotations: The annotations of the volumesnapshot. + namespace: The namespace of the volumesnapshot. (Optional) +*/}} + +{{- define "tc.v1.common.class.volumesnapshot" -}} + + {{- $rootCtx := .rootCtx -}} + {{- $objectData := .objectData }} +--- +apiVersion: snapshot.storage.k8s.io/v1 +kind: VolumeSnapshot +metadata: + name: {{ $objectData.name }} + namespace: {{ include "tc.v1.common.lib.metadata.namespace" (dict "rootCtx" $rootCtx "objectData" $objectData "caller" "volumesnapshot") }} + {{- $labels := (mustMerge ($objectData.labels | default dict) (include "tc.v1.common.lib.metadata.allLabels" $rootCtx | fromYaml)) -}} + {{- with (include "tc.v1.common.lib.metadata.render" (dict "rootCtx" $rootCtx "labels" $labels) | trim) }} + labels: + {{- . | nindent 4 }} + {{- end -}} + {{- $annotations := (mustMerge ($objectData.annotations | default dict) (include "tc.v1.common.lib.metadata.allAnnotations" $rootCtx | fromYaml)) -}} + {{- with (include "tc.v1.common.lib.metadata.render" (dict "rootCtx" $rootCtx "annotations" $annotations) | trim) }} + annotations: + {{- . | nindent 4 }} + {{- end }} +spec: + {{- with $objectData.volumeSnapshotClassName }} + volumeSnapshotClassName: {{ . }} + {{- end -}} + {{- if $objectData.source }} + source: + {{- with $objectData.source.persistentVolumeClaimName }} + persistentVolumeClaimName: {{ . }} + {{- end -}} + {{- with $objectData.source.volumeSnapshotContentName }} + volumeSnapshotContentName: {{ . }} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/library/common/templates/lib/storage/_validationVolumeSnapshot.tpl b/library/common/templates/lib/storage/_validationVolumeSnapshot.tpl new file mode 100644 index 00000000..be368e7f --- /dev/null +++ b/library/common/templates/lib/storage/_validationVolumeSnapshot.tpl @@ -0,0 +1,29 @@ +{{/* volumeSnapshot Validation */}} +{{/* Call this template: +{{ include "tc.v1.common.lib.volumesnapshot.validation" (dict "objectData" $objectData) -}} +objectData: + rootCtx: The root context of the chart. + objectData: The volumesnapshot object. +*/}} + +{{- define "tc.v1.common.lib.volumesnapshot.validation" -}} + {{- $rootCtx := .rootCtx -}} + {{- $objectData := .objectData -}} + + {{- if not $objectData.source -}} + {{- fail "VolumeSnapshot - Expected non empty [source]" -}} + {{- end -}} + + {{- $sourceTypes := (list "volumeSnapshotContentName" "persistentVolumeClaimName") -}} + {{- $sourceCount := 0 -}} + {{- range $t := $sourceTypes -}} + {{- if (get $objectData.source $t) -}} + {{- $sourceCount = add1 $sourceCount -}} + {{- end -}} + {{- end -}} + + {{- if ne $sourceCount 1 -}} + {{- fail (printf "VolumeSnapshot - Expected exactly one of the valid source types [%s]. Found [%d]" (join ", " $sourceTypes) $sourceCount) -}} + {{- end -}} + +{{- end -}} diff --git a/library/common/templates/loader/_apply.tpl b/library/common/templates/loader/_apply.tpl index cdc93921..89876ee8 100644 --- a/library/common/templates/loader/_apply.tpl +++ b/library/common/templates/loader/_apply.tpl @@ -46,6 +46,9 @@ {{/* Render PVC(s) */}} {{- include "tc.v1.common.spawner.pvc" . | nindent 0 -}} + {{/* Render volumeSnapshot(s) */}} + {{- include "tc.v1.common.spawner.volumesnapshot" . | nindent 0 -}} + {{/* Render ingress(s) */}} {{- include "tc.v1.common.spawner.ingress" . | nindent 0 -}} diff --git a/library/common/templates/spawner/_pvc.tpl b/library/common/templates/spawner/_pvc.tpl index 019b704c..47b21cd3 100644 --- a/library/common/templates/spawner/_pvc.tpl +++ b/library/common/templates/spawner/_pvc.tpl @@ -74,6 +74,29 @@ {{/* Call class to create the object */}} {{- include "tc.v1.common.class.pvc" (dict "rootCtx" $ "objectData" $objectData) -}} + + {{/* Create VolumeSnapshots */}} + {{- range $volSnap := $objectData.volumeSnapshots -}} + + {{/* Create a copy of the volumesnapshot */}} + {{- $volSnapData := (mustDeepCopy $volSnap) -}} + {{/* PVC FullName - Snapshot Name*/}} + {{- $snapshotName := printf "%s-%s" $objectData.name $volSnap.name -}} + + {{/* Perform validations */}} {{/* volumesnapshots have a max name length of 253 */}} + {{- include "tc.v1.common.lib.chart.names.validation" (dict "name" $snapshotName "length" 253) -}} + {{- include "tc.v1.common.lib.metadata.validation" (dict "objectData" $volSnapData "caller" "PVC - VolumeSnapshot") -}} + + {{/* Set the name of the volumesnapshot */}} + {{- $_ := set $volSnapData "name" $snapshotName -}} + {{- $_ := set $volSnapData "shortName" $volSnap.name -}} + {{- $_ := set $volSnapData "source" (dict "persistentVolumeClaimName" $objectData.name) -}} + + {{- include "tc.v1.common.lib.volumesnapshot.validation" (dict "objectData" $volSnapData) -}} + + {{/* Call class to create the object */}} + {{- include "tc.v1.common.class.volumesnapshot" (dict "rootCtx" $ "objectData" $volSnapData) -}} + {{- end -}} {{- end -}} {{- if eq $objectData.type "iscsi" -}} diff --git a/library/common/templates/spawner/_volumeSnapshot.tpl b/library/common/templates/spawner/_volumeSnapshot.tpl new file mode 100644 index 00000000..4a8d6a90 --- /dev/null +++ b/library/common/templates/spawner/_volumeSnapshot.tpl @@ -0,0 +1,38 @@ +{{/* volumesnapshot Spawwner */}} +{{/* Call this template: +{{ include "tc.v1.common.spawner.volumesnapshot" $ -}} +*/}} + +{{- define "tc.v1.common.spawner.volumesnapshot" -}} + {{- $fullname := include "tc.v1.common.lib.chart.names.fullname" $ -}} + + {{- range $volumesnapshot := .Values.volumeSnapshots -}} + {{/* Create a copy of the volumesnapshot */}} + {{- $objectData := (mustDeepCopy $volumesnapshot) -}} + + {{- if not $objectData.name -}} + {{- fail "VolumeSnapshot - Expected non empty [name]" -}} + {{- end -}} + + {{- $objectName := (printf "%s-%s" $fullname $volumesnapshot.name) -}} + {{- if hasKey $objectData "expandObjectName" -}} + {{- if not $objectData.expandObjectName -}} + {{- $objectName = $volumesnapshot.name -}} + {{- end -}} + {{- end -}} + + {{/* Perform validations */}} {{/* volumesnapshots have a max name length of 253 */}} + {{- include "tc.v1.common.lib.chart.names.validation" (dict "name" $objectName "length" 253) -}} + {{- include "tc.v1.common.lib.volumesnapshot.validation" (dict "objectData" $objectData) -}} + {{- include "tc.v1.common.lib.metadata.validation" (dict "objectData" $objectData "caller" "VolumeSnapshot") -}} + + {{/* Set the name of the volumesnapshot */}} + {{- $_ := set $objectData "name" $objectName -}} + {{- $_ := set $objectData "shortName" $volumesnapshot.name -}} + + {{/* Call class to create the object */}} + {{- include "tc.v1.common.class.volumesnapshot" (dict "rootCtx" $ "objectData" $objectData) -}} + + {{- end -}} + +{{- end -}} diff --git a/library/common/values.yaml b/library/common/values.yaml index c838d5ca..3f932947 100644 --- a/library/common/values.yaml +++ b/library/common/values.yaml @@ -307,11 +307,28 @@ persistence: # driver: "somedriver" # # Custom CSI definition here # csi: {} +# example-volumesnapshot: +# enabled: true +# type: pvc +# mountPath: /shared +# targetSelectAll: true +# volumeSnapshots: +# - name: "mysnapshot" +# volumeSnapshotClassName: "mysnapshotclass" (optional) persistenceList: [] deviceList: [] +volumeSnapshots: [] +# volumeSnapshots: +# - name: "mycustomsnapshot" +# volumeSnapshotClassName: "mycustomsnapshot" (optional) +# source: +# # pick one +# persistentVolumeClaimName: "mypvcname" (does not get altered) +# volumeSnapshotContentName: "mysnapshotname" + # -- Injected from SCALE middleware # Only for reference here ixExternalInterfacesConfiguration: []