diff --git a/library/common-test/Chart.yaml b/library/common-test/Chart.yaml index ae4eb68a..fb0d6786 100644 --- a/library/common-test/Chart.yaml +++ b/library/common-test/Chart.yaml @@ -3,7 +3,7 @@ appVersion: "" dependencies: - name: common repository: file://../common - version: ~14.5.0 + version: ~15.0.0 deprecated: false description: Helper chart to test different use cases of the common library home: https://github.com/truecharts/apps/tree/master/charts/library/common-test diff --git a/library/common-test/ci/statefulset-values.yaml b/library/common-test/ci/statefulset-values.yaml index e0d884cc..9801d6ff 100644 --- a/library/common-test/ci/statefulset-values.yaml +++ b/library/common-test/ci/statefulset-values.yaml @@ -36,9 +36,10 @@ workload: type: http port: "{{ .Values.service.main.ports.main.port }}" -volumeClaimTemplates: +persistence: data: mountPath: /data + type: vct accessMode: "ReadWriteOnce" size: 1Gi diff --git a/library/common-test/tests/container/volumeMounts_test.yaml b/library/common-test/tests/container/volumeMounts_test.yaml index 8c8c8399..3edfdc91 100644 --- a/library/common-test/tests/container/volumeMounts_test.yaml +++ b/library/common-test/tests/container/volumeMounts_test.yaml @@ -637,9 +637,10 @@ tests: primary: true imageSelector: image probes: *probes - volumeClaimTemplates: + persistence: vct-vol: enabled: true + type: vct size: 50Gi targetSelector: workload-name: diff --git a/library/common-test/tests/persistence/pv_data_test.yaml b/library/common-test/tests/persistence/pv_data_test.yaml new file mode 100644 index 00000000..28659b3d --- /dev/null +++ b/library/common-test/tests/persistence/pv_data_test.yaml @@ -0,0 +1,335 @@ +suite: pv data test +templates: + - common.yaml +release: + name: test-release-name + namespace: test-release-namespace +tests: + - it: should create nfs pv with csi + set: + version: 4.1 + persistence: + my-volume1: + enabled: true + type: pvc + static: + mode: nfs + share: /my-path + server: my-server + my-volume2: + enabled: true + type: pvc + static: + mode: nfs + share: /my-path2 + server: my-server2 + size: 2Gi + mountOptions: + - key: hard + - key: nfsvers + value: "{{ .Values.version }}" + my-volume3: + enabled: true + type: pvc + static: + mode: nfs + share: /my-path3 + server: my-server3 + size: 3Gi + mountOptions: + - key: hard + - key: nfsvers + value: "{{ .Values.version }}" + asserts: + - documentIndex: &pvDoc 0 + isKind: + of: PersistentVolume + - documentIndex: *pvDoc + equal: + path: spec + value: + capacity: + storage: 100Gi + persistentVolumeReclaimPolicy: Delete + storageClassName: test-release-name-common-test-my-volume1-1599277109 + accessModes: + - ReadWriteOnce + csi: + driver: nfs.csi.k8s.io + volumeHandle: my-server/my-path#test-release-name-common-test-my-volume1-1599277109 + volumeAttributes: + server: my-server + share: /my-path + - documentIndex: &pvcDoc 1 + isKind: + of: PersistentVolumeClaim + - documentIndex: *pvcDoc + equal: + path: spec + value: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Gi + storageClassName: test-release-name-common-test-my-volume1-1599277109 + volumeName: test-release-name-common-test-my-volume1-1599277109 + - documentIndex: &otherPvDoc 2 + isKind: + of: PersistentVolume + - documentIndex: *otherPvDoc + equal: + path: spec + value: + capacity: + storage: 2Gi + persistentVolumeReclaimPolicy: Delete + storageClassName: test-release-name-common-test-my-volume2-1702692922 + accessModes: + - ReadWriteOnce + mountOptions: + - hard + - nfsvers=4.1 + csi: + driver: nfs.csi.k8s.io + volumeHandle: my-server2/my-path2#test-release-name-common-test-my-volume2-1702692922 + volumeAttributes: + server: my-server2 + share: /my-path2 + - documentIndex: &otherPvcDoc 3 + isKind: + of: PersistentVolumeClaim + - documentIndex: *otherPvcDoc + equal: + path: spec + value: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + storageClassName: test-release-name-common-test-my-volume2-1702692922 + volumeName: test-release-name-common-test-my-volume2-1702692922 + - documentIndex: &thirdPvDoc 4 + isKind: + of: PersistentVolume + - documentIndex: *thirdPvDoc + equal: + path: spec + value: + capacity: + storage: 3Gi + persistentVolumeReclaimPolicy: Delete + storageClassName: test-release-name-common-test-my-volume3-1705052221 + accessModes: + - ReadWriteOnce + mountOptions: + - hard + - nfsvers=4.1 + csi: + driver: nfs.csi.k8s.io + volumeHandle: my-server3/my-path3#test-release-name-common-test-my-volume3-1705052221 + volumeAttributes: + server: my-server3 + share: /my-path3 + - documentIndex: &thirdPvcDoc 5 + isKind: + of: PersistentVolumeClaim + - documentIndex: *thirdPvcDoc + equal: + path: spec + value: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 3Gi + storageClassName: test-release-name-common-test-my-volume3-1705052221 + volumeName: test-release-name-common-test-my-volume3-1705052221 + + - it: should create smb pv with csi + set: + version: "3.0" + persistence: + my-volume1: + enabled: true + type: pvc + static: + mode: smb + share: my-share + server: my-server + username: my-user + password: my-password + my-volume2: + enabled: true + type: pvc + static: + mode: smb + share: my-share2 + server: my-server2 + username: my-user2 + password: my-password2 + size: 2Gi + mountOptions: + - key: hard + - key: uid + value: 99999999999 + - key: vers + value: "{{ .Values.version }}" + my-volume3: + enabled: true + type: pvc + static: + mode: smb + share: my-share3 + server: my-server3 + username: my-user3 + password: my-password3 + size: 3Gi + mountOptions: + - key: hard + - key: uid + value: 99999999999 + - key: vers + value: "{{ .Values.version }}" + asserts: + - documentIndex: &secretDoc 0 + isKind: + of: Secret + - documentIndex: *secretDoc + equal: + path: stringData + value: + username: my-user + password: my-password + - documentIndex: &pvDoc 1 + isKind: + of: PersistentVolume + - documentIndex: *pvDoc + equal: + path: spec + value: + capacity: + storage: 100Gi + persistentVolumeReclaimPolicy: Delete + storageClassName: test-release-name-common-test-my-volume1-1627785324 + accessModes: + - ReadWriteOnce + csi: + driver: smb.csi.k8s.io + volumeHandle: my-server/my-share#test-release-name-common-test-my-volume1-1627785324 + volumeAttributes: + source: //my-server/my-share + nodeStageSecretRef: + name: test-release-name-common-test-my-volume1-1627785324 + namespace: test-release-namespace + - documentIndex: &pvcDoc 2 + isKind: + of: PersistentVolumeClaim + - documentIndex: *pvcDoc + equal: + path: spec + value: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Gi + storageClassName: test-release-name-common-test-my-volume1-1627785324 + volumeName: test-release-name-common-test-my-volume1-1627785324 + - documentIndex: &otherSecretDoc 3 + isKind: + of: Secret + - documentIndex: *otherSecretDoc + equal: + path: stringData + value: + username: my-user2 + password: my-password2 + - documentIndex: &otherPvDoc 4 + isKind: + of: PersistentVolume + - documentIndex: *otherPvDoc + equal: + path: spec + value: + capacity: + storage: 2Gi + persistentVolumeReclaimPolicy: Delete + storageClassName: test-release-name-common-test-my-volume2-1734805617 + accessModes: + - ReadWriteOnce + mountOptions: + - hard + - uid=99999999999 + - vers=3.0 + csi: + driver: smb.csi.k8s.io + volumeHandle: my-server2/my-share2#test-release-name-common-test-my-volume2-1734805617 + volumeAttributes: + source: //my-server2/my-share2 + nodeStageSecretRef: + name: test-release-name-common-test-my-volume2-1734805617 + namespace: test-release-namespace + - documentIndex: &otherPvcDoc 5 + isKind: + of: PersistentVolumeClaim + - documentIndex: *otherPvcDoc + equal: + path: spec + value: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + storageClassName: test-release-name-common-test-my-volume2-1734805617 + volumeName: test-release-name-common-test-my-volume2-1734805617 + - documentIndex: &thirdSecretDoc 6 + isKind: + of: Secret + - documentIndex: *thirdSecretDoc + equal: + path: stringData + value: + username: my-user3 + password: my-password3 + - documentIndex: &thirdPvDoc 7 + isKind: + of: PersistentVolume + - documentIndex: *thirdPvDoc + equal: + path: spec + value: + capacity: + storage: 3Gi + persistentVolumeReclaimPolicy: Delete + storageClassName: test-release-name-common-test-my-volume3-1737164916 + accessModes: + - ReadWriteOnce + mountOptions: + - hard + - uid=99999999999 + - vers=3.0 + csi: + driver: smb.csi.k8s.io + volumeHandle: my-server3/my-share3#test-release-name-common-test-my-volume3-1737164916 + volumeAttributes: + source: //my-server3/my-share3 + nodeStageSecretRef: + name: test-release-name-common-test-my-volume3-1737164916 + namespace: test-release-namespace + - documentIndex: &thirdPvcDoc 8 + isKind: + of: PersistentVolumeClaim + - documentIndex: *thirdPvcDoc + equal: + path: spec + value: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 3Gi + storageClassName: test-release-name-common-test-my-volume3-1737164916 + volumeName: test-release-name-common-test-my-volume3-1737164916 diff --git a/library/common-test/tests/persistence/pv_metadata_test.yaml b/library/common-test/tests/persistence/pv_metadata_test.yaml new file mode 100644 index 00000000..a1e08e02 --- /dev/null +++ b/library/common-test/tests/persistence/pv_metadata_test.yaml @@ -0,0 +1,239 @@ +suite: pv 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 pv created with labels and annotations (nfs-pv-pvc) + 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 }}" + persistence: + my-volume1: + enabled: true + type: pvc + static: + mode: nfs + share: /someshare + server: someserver + labels: + label1: "{{ .Values.label1 }}" + label2: label2 + annotations: + annotation1: "{{ .Values.annotation1 }}" + annotation2: annotation2 + asserts: + - documentIndex: &pvDoc 0 + isKind: + of: PersistentVolume + - documentIndex: *pvDoc + isAPIVersion: + of: v1 + - documentIndex: *pvDoc + equal: + path: metadata.annotations + value: + annotation1: annotation1 + annotation2: annotation2 + g_annotation1: global_annotation1 + g_annotation2: global_annotation2 + pv.kubernetes.io/provisioned-by: nfs.csi.k8s.io + - documentIndex: *pvDoc + 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/instance: test-release-name + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/version: *appVer + app.kubernetes.io/name: common-test + g_label1: global_label1 + g_label2: global_label2 + label1: label1 + label2: label2 + + - it: should pass with pvc created with retain set to true (nfs-pv-pvc) + set: + persistence: + my-volume1: + enabled: true + type: pvc + static: + mode: nfs + share: /someshare + server: someserver + retain: true + asserts: + - documentIndex: *pvDoc + isKind: + of: PersistentVolume + - documentIndex: *pvDoc + equal: + path: metadata.annotations + value: + "helm.sh/resource-policy": keep + pv.kubernetes.io/provisioned-by: nfs.csi.k8s.io + - documentIndex: *pvDoc + 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/instance: test-release-name + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/version: *appVer + app.kubernetes.io/name: common-test + + - it: should pass with pv created with labels and annotations (smb-pv-pvc) + 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 }}" + persistence: + my-volume1: + enabled: true + type: pvc + static: + mode: smb + share: someshare + server: someserver + username: someuser + password: someuserpoassword + labels: + label1: "{{ .Values.label1 }}" + label2: label2 + annotations: + annotation1: "{{ .Values.annotation1 }}" + annotation2: annotation2 + asserts: + - documentIndex: &secretDoc 0 + isKind: + of: Secret + - documentIndex: *secretDoc + isAPIVersion: + of: v1 + - documentIndex: *secretDoc + equal: + path: metadata.annotations + value: + annotation1: annotation1 + annotation2: annotation2 + g_annotation1: global_annotation1 + g_annotation2: global_annotation2 + - documentIndex: *secretDoc + 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/instance: test-release-name + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/version: *appVer + app.kubernetes.io/name: common-test + g_label1: global_label1 + g_label2: global_label2 + label1: label1 + label2: label2 + - documentIndex: &pvDoc 1 + isKind: + of: PersistentVolume + - documentIndex: *pvDoc + isAPIVersion: + of: v1 + - documentIndex: *pvDoc + equal: + path: metadata.annotations + value: + annotation1: annotation1 + annotation2: annotation2 + g_annotation1: global_annotation1 + g_annotation2: global_annotation2 + pv.kubernetes.io/provisioned-by: smb.csi.k8s.io + - documentIndex: *pvDoc + 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/instance: test-release-name + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/version: *appVer + app.kubernetes.io/name: common-test + g_label1: global_label1 + g_label2: global_label2 + label1: label1 + label2: label2 + + - it: should pass with pvc created with retain set to true (smb-pv-pvc) + set: + persistence: + my-volume1: + enabled: true + type: pvc + static: + mode: smb + share: someshare + server: someserver + username: someuser + password: someuserpoassword + retain: true + asserts: + - documentIndex: *secretDoc + isKind: + of: Secret + - documentIndex: *secretDoc + isAPIVersion: + of: v1 + - documentIndex: *secretDoc + isNull: + path: metadata.annotations + - documentIndex: *pvDoc + isKind: + of: PersistentVolume + - documentIndex: *pvDoc + equal: + path: metadata.annotations + value: + "helm.sh/resource-policy": keep + pv.kubernetes.io/provisioned-by: smb.csi.k8s.io + - documentIndex: *pvDoc + 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/instance: test-release-name + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/version: *appVer + app.kubernetes.io/name: common-test diff --git a/library/common-test/tests/persistence/pv_name_test.yaml b/library/common-test/tests/persistence/pv_name_test.yaml new file mode 100644 index 00000000..a9dd0717 --- /dev/null +++ b/library/common-test/tests/persistence/pv_name_test.yaml @@ -0,0 +1,77 @@ +suite: pv name test +templates: + - common.yaml +release: + name: test-release-name + namespace: test-release-namespace +tests: + - it: should generate correct name + set: + persistence: + my-volume1: + enabled: true + type: pvc + static: + mode: nfs + share: /someshare + server: someserver + my-volume2: + enabled: true + type: pvc + static: + mode: smb + share: someshare + server: someserver + username: someuser + password: someuserpoassword + asserts: + - documentIndex: &pvDoc 0 + isKind: + of: PersistentVolume + - documentIndex: *pvDoc + isAPIVersion: + of: v1 + - documentIndex: *pvDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-volume1-2156988893 + - documentIndex: &pvcDoc 1 + isKind: + of: PersistentVolumeClaim + - documentIndex: *pvcDoc + isAPIVersion: + of: v1 + - documentIndex: *pvcDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-volume1-2156988893 + - documentIndex: &secretDoc 2 + isKind: + of: Secret + - documentIndex: *secretDoc + isAPIVersion: + of: v1 + - documentIndex: *secretDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-volume2-2027162030 + - documentIndex: &pvDoc 3 + isKind: + of: PersistentVolume + - documentIndex: *pvDoc + isAPIVersion: + of: v1 + - documentIndex: *pvDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-volume2-2027162030 + - documentIndex: &otherPvcDoc 4 + isKind: + of: PersistentVolumeClaim + - documentIndex: *otherPvcDoc + isAPIVersion: + of: v1 + - documentIndex: *otherPvcDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-volume2-2027162030 diff --git a/library/common-test/tests/persistence/metadata_test.yaml b/library/common-test/tests/persistence/pvc_metadata_test.yaml similarity index 100% rename from library/common-test/tests/persistence/metadata_test.yaml rename to library/common-test/tests/persistence/pvc_metadata_test.yaml diff --git a/library/common-test/tests/persistence/names_test.yaml b/library/common-test/tests/persistence/pvc_names_test.yaml similarity index 100% rename from library/common-test/tests/persistence/names_test.yaml rename to library/common-test/tests/persistence/pvc_names_test.yaml diff --git a/library/common-test/tests/persistence/validation_test.yaml b/library/common-test/tests/persistence/validation_test.yaml index 8563dca4..a13000e7 100644 --- a/library/common-test/tests/persistence/validation_test.yaml +++ b/library/common-test/tests/persistence/validation_test.yaml @@ -43,7 +43,7 @@ tests: type: not-a-type asserts: - failedTemplate: - errorMessage: Persistence - Expected to be one of [pvc, emptyDir, nfs, hostPath, ixVolume, secret, configmap, device], but got [not-a-type] + errorMessage: Persistence - Expected to be one of [pvc, vct, emptyDir, nfs, hostPath, ixVolume, secret, configmap, device], but got [not-a-type] - it: should fail with invalid accessMode set: @@ -157,3 +157,279 @@ tests: asserts: - failedTemplate: errorMessage: Persistent Volume Claim - Namespace [my-namespace] expected to have [ix-] prefix when installed in TrueNAS SCALE + + - it: should fail without server on pvc static nfs + set: + persistence: + volume1: + enabled: true + type: pvc + static: + mode: nfs + share: /someshare + asserts: + - failedTemplate: + errorMessage: NFS CSI - Expected to be non-empty + + - it: should fail without share on pvc static nfs + set: + persistence: + volume1: + enabled: true + type: pvc + static: + mode: nfs + server: someserver + asserts: + - failedTemplate: + errorMessage: NFS CSI - Expected to be non-empty + + - it: should fail without server on pvc static smb + set: + persistence: + volume1: + enabled: true + type: pvc + static: + mode: smb + share: someshare + asserts: + - failedTemplate: + errorMessage: SMB CSI - Expected to be non-empty + + - it: should fail without share on pvc static smb + set: + persistence: + volume1: + enabled: true + type: pvc + static: + mode: smb + server: someserver + asserts: + - failedTemplate: + errorMessage: SMB CSI - Expected to be non-empty + + - it: should fail without CSI when in ixChartContext on pvc static smb + set: + global: + ixChartContext: {} + persistence: + volume1: + enabled: true + type: pvc + static: + mode: smb + share: someshare + server: someserver + asserts: + - failedTemplate: + errorMessage: SMB CSI - Not supported CSI + + - it: should fail without CSI when in ixChartContext on pvc static nfs + set: + global: + ixChartContext: {} + persistence: + volume1: + enabled: true + type: pvc + static: + mode: nfs + share: /someshare + server: someserver + asserts: + - failedTemplate: + errorMessage: NFS CSI - Not supported CSI + + - it: should fail without username pvc static smb + set: + persistence: + volume1: + enabled: true + type: pvc + static: + mode: smb + share: someshare + server: someserver + asserts: + - failedTemplate: + errorMessage: SMB CSI - Expected to be non-empty + + - it: should fail without password on pvc static smb + set: + persistence: + volume1: + enabled: true + type: pvc + static: + mode: smb + share: someshare + server: someserver + username: someuser + asserts: + - failedTemplate: + errorMessage: SMB CSI - Expected to be non-empty + + - it: should fail with server starting with // on pvc static smb + set: + persistence: + volume1: + enabled: true + type: pvc + static: + mode: smb + share: someshare + server: //someserver + username: someuser + password: someuserpoassword + asserts: + - failedTemplate: + errorMessage: SMB CSI - Did not expect to start with [//] + + - it: should fail with share starting with / on pvc static smb + set: + persistence: + volume1: + enabled: true + type: pvc + static: + mode: smb + share: /someshare + server: someserver + username: someuser + password: someuserpoassword + asserts: + - failedTemplate: + errorMessage: SMB CSI - Did not expect to start with [/] + + - it: should fail without share starting with / on pvc static nfs + set: + persistence: + volume1: + enabled: true + type: pvc + static: + mode: nfs + share: someshare + server: someserver + asserts: + - failedTemplate: + errorMessage: NFS CSI - Expected to start with [/] + + - it: should fail with empty key on mountOptions in pvc static nfs + set: + persistence: + volume1: + enabled: true + type: pvc + static: + mode: nfs + share: /someshare + server: someserver + mountOptions: + - key: "" + asserts: + - failedTemplate: + errorMessage: NFS CSI - Expected key in to be non-empty + + - it: should fail with empty key on mountOptions in pvc static smb + set: + persistence: + volume1: + enabled: true + type: pvc + static: + mode: smb + share: someshare + server: someserver + username: someuser + password: someuserpoassword + mountOptions: + - key: "" + asserts: + - failedTemplate: + errorMessage: SMB CSI - Expected key in to be non-empty + + - it: should fail with item in mountOptions not a map in pvc static smb + set: + persistence: + volume1: + enabled: true + type: pvc + static: + mode: smb + share: someshare + server: someserver + username: someuser + password: someuserpoassword + mountOptions: + - not-a-map + asserts: + - failedTemplate: + errorMessage: SMB CSI - Expected item to be a dict, but got [string] + + - it: should fail with item in mountOptions not a map in pvc static nfs + set: + persistence: + volume1: + enabled: true + type: pvc + static: + mode: nfs + share: /someshare + server: someserver + mountOptions: + - not-a-map + asserts: + - failedTemplate: + errorMessage: NFS CSI - Expected item to be a dict, but got [string] + + - it: should fail with invalid static mode + set: + persistence: + volume1: + enabled: true + type: pvc + static: + mode: not-a-mode + asserts: + - failedTemplate: + errorMessage: Persistence - Expected [static.mode] to be one of [disabled, smb, nfs, custom], but got [not-a-mode] + + - it: should fail with missing name in dataSource + set: + persistence: + volume1: + enabled: true + type: pvc + dataSource: + kind: PersistentVolumeClaim + asserts: + - failedTemplate: + errorMessage: Persistence - Expected [dataSource.name] to be non-empty + + - it: should fail with missing kind in dataSource + set: + persistence: + volume1: + enabled: true + type: pvc + dataSource: + name: some name + asserts: + - failedTemplate: + errorMessage: Persistence - Expected [dataSource.kind] to be non-empty + + - it: should fail with invalid kind in dataSource + set: + persistence: + volume1: + enabled: true + type: pvc + dataSource: + name: some name + kind: invalid + asserts: + - failedTemplate: + errorMessage: Persistence - Expected [dataSource.kind] to be one of [VolumeSnapshot, PersistentVolumeClaim], but got [invalid] diff --git a/library/common-test/tests/pod/volumeMounts_test.yaml b/library/common-test/tests/pod/volumeMounts_test.yaml new file mode 100644 index 00000000..5a197506 --- /dev/null +++ b/library/common-test/tests/pod/volumeMounts_test.yaml @@ -0,0 +1,831 @@ +suite: container volumeMounts test +templates: + - common.yaml +release: + name: test-release-name + namespace: test-release-namespace +tests: + - it: should pass with shared volume on multiple workloads and containers with targetSelectAll + set: + some_path: /some/path + image: &image + repository: nginx + tag: 1.19.0 + pullPolicy: IfNotPresent + workload: + workload-name: + enabled: true + primary: true + type: Deployment + podSpec: + containers: + container-name1: + enabled: true + primary: true + imageSelector: image + probes: &probes + liveness: + enabled: false + readiness: + enabled: false + startup: + enabled: false + container-name2: + enabled: true + primary: false + imageSelector: image + probes: *probes + workload-name2: + enabled: true + primary: false + type: Job + podSpec: + restartPolicy: Never + containers: + container-name1: + enabled: true + primary: true + imageSelector: image + probes: *probes + container-name2: + enabled: true + primary: false + imageSelector: image + probes: *probes + persistence: + shared-vol: + enabled: true + type: emptyDir + mountPath: "{{ .Values.some_path }}" + targetSelectAll: true + nfs-vol-pvc: + enabled: true + type: pvc + static: + mode: nfs + share: /someshare + server: someserver + mountPath: /nfs-mount + targetSelectAll: true + smb-vol-pvc: + enabled: true + type: pvc + static: + mode: smb + share: someshare + server: someserver + username: someuser + password: someuserpoassword + mountPath: /smb-mount + targetSelectAll: true + asserts: + - documentIndex: &deploymentDoc 0 + isKind: + of: Deployment + - documentIndex: *deploymentDoc + isAPIVersion: + of: apps/v1 + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: shared-vol + mountPath: /some/path + readOnly: false + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: nfs-vol-pvc + mountPath: /nfs-mount + readOnly: false + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: smb-vol-pvc + mountPath: /smb-mount + readOnly: false + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.containers[1].volumeMounts + content: + name: shared-vol + mountPath: /some/path + readOnly: false + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.containers[1].volumeMounts + content: + name: nfs-vol-pvc + mountPath: /nfs-mount + readOnly: false + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.containers[1].volumeMounts + content: + name: smb-vol-pvc + mountPath: /smb-mount + readOnly: false + - documentIndex: &jobDoc 1 + isKind: + of: Job + - documentIndex: *jobDoc + isAPIVersion: + of: batch/v1 + - documentIndex: *jobDoc + contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: shared-vol + mountPath: /some/path + readOnly: false + - documentIndex: *jobDoc + contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: nfs-vol-pvc + mountPath: /nfs-mount + readOnly: false + - documentIndex: *jobDoc + contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: smb-vol-pvc + mountPath: /smb-mount + readOnly: false + - documentIndex: *jobDoc + contains: + path: spec.template.spec.containers[1].volumeMounts + content: + name: shared-vol + mountPath: /some/path + readOnly: false + - documentIndex: *jobDoc + contains: + path: spec.template.spec.containers[1].volumeMounts + content: + name: nfs-vol-pvc + mountPath: /nfs-mount + readOnly: false + - documentIndex: *jobDoc + contains: + path: spec.template.spec.containers[1].volumeMounts + content: + name: smb-vol-pvc + mountPath: /smb-mount + readOnly: false + + - it: should pass with volume on primary workload and container + set: + image: *image + workload: + workload-name: + enabled: true + primary: true + type: Deployment + podSpec: + containers: + container-name1: + enabled: true + primary: true + imageSelector: image + probes: *probes + container-name2: + enabled: true + primary: false + imageSelector: image + probes: *probes + workload-name2: + enabled: true + primary: false + type: Job + podSpec: + restartPolicy: Never + containers: + container-name1: + enabled: true + primary: true + imageSelector: image + probes: *probes + container-name2: + enabled: true + primary: false + imageSelector: image + probes: *probes + persistence: + some-vol: + enabled: true + type: emptyDir + mountPath: /some/path + readOnly: true + asserts: + - documentIndex: &deploymentDoc 0 + isKind: + of: Deployment + - documentIndex: *deploymentDoc + isAPIVersion: + of: apps/v1 + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: some-vol + mountPath: /some/path + readOnly: true + - documentIndex: *deploymentDoc + notContains: + path: spec.template.spec.containers[1].volumeMounts + content: + name: some-vol + mountPath: /some/path + readOnly: true + - documentIndex: &jobDoc 1 + isKind: + of: Job + - documentIndex: *jobDoc + isAPIVersion: + of: batch/v1 + - documentIndex: *jobDoc + notContains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: some-vol + mountPath: /some/path + readOnly: true + - documentIndex: *jobDoc + notContains: + path: spec.template.spec.containers[1].volumeMounts + content: + name: some-vol + mountPath: /some/path + readOnly: true + + - it: should pass with volume with selected pod and container + set: + image: *image + workload: + workload-name: + enabled: true + primary: true + type: Deployment + podSpec: + containers: + container-name1: + enabled: true + primary: true + imageSelector: image + probes: *probes + container-name2: + enabled: true + primary: false + imageSelector: image + probes: *probes + workload-name2: + enabled: true + primary: false + type: Job + podSpec: + restartPolicy: Never + containers: + container-name1: + enabled: true + primary: true + imageSelector: image + probes: *probes + container-name2: + enabled: true + primary: false + imageSelector: image + probes: *probes + persistence: + some-vol: + enabled: true + type: emptyDir + mountPath: /some/path + readOnly: true + targetSelector: + workload-name: + container-name2: {} + workload-name2: + container-name1: {} + asserts: + - documentIndex: &deploymentDoc 0 + isKind: + of: Deployment + - documentIndex: *deploymentDoc + isAPIVersion: + of: apps/v1 + - documentIndex: *deploymentDoc + notContains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: some-vol + mountPath: /some/path + readOnly: true + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.containers[1].volumeMounts + content: + name: some-vol + mountPath: /some/path + readOnly: true + - documentIndex: &jobDoc 1 + isKind: + of: Job + - documentIndex: *jobDoc + isAPIVersion: + of: batch/v1 + - documentIndex: *jobDoc + contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: some-vol + mountPath: /some/path + readOnly: true + - documentIndex: *jobDoc + notContains: + path: spec.template.spec.containers[1].volumeMounts + content: + name: some-vol + mountPath: /some/path + readOnly: true + + - it: should pass with volume with selected pod and multiple containers + set: + image: *image + workload: + workload-name: + enabled: true + primary: true + type: Deployment + podSpec: + containers: + container-name1: + enabled: true + primary: true + imageSelector: image + probes: *probes + container-name2: + enabled: true + primary: false + imageSelector: image + probes: *probes + workload-name2: + enabled: true + primary: false + type: Job + podSpec: + restartPolicy: Never + containers: + container-name1: + enabled: true + primary: true + imageSelector: image + probes: *probes + container-name2: + enabled: true + primary: false + imageSelector: image + probes: *probes + persistence: + some-vol: + enabled: true + type: emptyDir + mountPath: /some/path + readOnly: true + targetSelector: + workload-name: + container-name1: {} + container-name2: {} + asserts: + - documentIndex: &deploymentDoc 0 + isKind: + of: Deployment + - documentIndex: *deploymentDoc + isAPIVersion: + of: apps/v1 + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: some-vol + mountPath: /some/path + readOnly: true + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.containers[1].volumeMounts + content: + name: some-vol + mountPath: /some/path + readOnly: true + - documentIndex: &jobDoc 1 + isKind: + of: Job + - documentIndex: *jobDoc + isAPIVersion: + of: batch/v1 + - documentIndex: *jobDoc + notContains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: some-vol + mountPath: /some/path + readOnly: true + - documentIndex: *jobDoc + notContains: + path: spec.template.spec.containers[1].volumeMounts + content: + name: some-vol + mountPath: /some/path + readOnly: true + + - it: should pass with volume with selected pod and containers and specific values + set: + image: *image + workload: + workload-name: + enabled: true + primary: true + type: Deployment + podSpec: + containers: + container-name1: + enabled: true + primary: true + imageSelector: image + probes: *probes + container-name2: + enabled: true + primary: false + imageSelector: image + probes: *probes + workload-name2: + enabled: true + primary: false + type: Job + podSpec: + restartPolicy: Never + containers: + container-name1: + enabled: true + primary: true + imageSelector: image + probes: *probes + container-name2: + enabled: true + primary: false + imageSelector: image + probes: *probes + persistence: + some-vol: + enabled: true + type: emptyDir + mountPath: /some/path + readOnly: true + targetSelector: + workload-name: + container-name1: + mountPath: /some/other/path + readOnly: false + mountPropagation: None + subPath: /some/sub/path + container-name2: {} + asserts: + - documentIndex: &deploymentDoc 0 + isKind: + of: Deployment + - documentIndex: *deploymentDoc + isAPIVersion: + of: apps/v1 + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: some-vol + mountPath: /some/other/path + readOnly: false + mountPropagation: None + subPath: /some/sub/path + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.containers[1].volumeMounts + content: + name: some-vol + mountPath: /some/path + readOnly: true + - documentIndex: &jobDoc 1 + isKind: + of: Job + - documentIndex: *jobDoc + isAPIVersion: + of: batch/v1 + - documentIndex: *jobDoc + notContains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: some-vol + mountPath: /some/other/path + readOnly: false + mountPropagation: None + subPath: /some/sub/path + - documentIndex: *jobDoc + notContains: + path: spec.template.spec.containers[1].volumeMounts + content: + name: some-vol + mountPath: /some/path + readOnly: true + + - it: should pass with volume with selected pod and containers and specific values from tpl + set: + some_path: /some/other/path + some_propagation: None + some_sub_path: /some/sub/path + image: *image + workload: + workload-name: + enabled: true + primary: true + type: Deployment + podSpec: + containers: + container-name1: + enabled: true + primary: true + imageSelector: image + probes: *probes + container-name2: + enabled: true + primary: false + imageSelector: image + probes: *probes + persistence: + some-vol: + enabled: true + type: emptyDir + mountPath: /some/path + readOnly: true + targetSelector: + workload-name: + container-name1: + mountPath: "{{ .Values.some_path }}" + readOnly: false + mountPropagation: "{{ .Values.some_propagation }}" + subPath: "{{ .Values.some_sub_path }}" + container-name2: {} + asserts: + - documentIndex: &deploymentDoc 0 + isKind: + of: Deployment + - documentIndex: *deploymentDoc + isAPIVersion: + of: apps/v1 + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: some-vol + mountPath: /some/other/path + readOnly: false + mountPropagation: None + subPath: /some/sub/path + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.containers[1].volumeMounts + content: + name: some-vol + mountPath: /some/path + readOnly: true + + - it: should pass with cert mounted as volume with subPath + set: + image: *image + ixCertificates: + "1": + certificate: some_cert + key: some_key + scaleCertificate: + cert-name: + enabled: false + id: 1 + workload: + workload-name: + enabled: true + primary: true + type: Deployment + podSpec: + containers: + container-name1: + enabled: true + primary: true + imageSelector: image + probes: *probes + persistence: + cert-vol: + enabled: true + type: secret + objectName: cert-name + readOnly: true + targetSelector: + workload-name: + container-name1: + mountPath: /some/path/cert.crt + readOnly: true + subPath: cert.crt + asserts: + - documentIndex: &deploymentDoc 0 + isKind: + of: Deployment + - documentIndex: *deploymentDoc + isAPIVersion: + of: apps/v1 + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: cert-vol + mountPath: /some/path/cert.crt + readOnly: true + subPath: cert.crt + + - it: should pass with cert mounted as volume with subPath + set: + image: *image + ixCertificates: + "1": + certificate: some_cert + key: some_key + scaleCertificate: + cert-name: + enabled: false + id: 1 + workload: + workload-name: + enabled: true + primary: true + type: Deployment + podSpec: + containers: + container-name1: + enabled: true + primary: true + imageSelector: image + probes: *probes + persistence: + cert-vol: + enabled: true + type: secret + objectName: cert-name + readOnly: true + items: + - key: tls.crt + path: cert.crt + targetSelector: + workload-name: + container-name1: + mountPath: /some/path + readOnly: true + asserts: + - documentIndex: &deploymentDoc 0 + isKind: + of: Deployment + - documentIndex: *deploymentDoc + isAPIVersion: + of: apps/v1 + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.containers[0].volumeMounts + content: + name: cert-vol + mountPath: /some/path + readOnly: true + + # Failures + - it: should fail with invalid mountPropagation + set: + image: *image + workload: + workload-name: &workload + enabled: true + primary: true + type: Deployment + podSpec: + containers: + container-name1: + enabled: true + primary: true + imageSelector: image + persistence: + vol-name: + enabled: true + type: emptyDir + mountPath: /some/path + mountPropagation: HostToContainer + targetSelector: + workload-name: + container-name1: + mountPropagation: invalid + asserts: + - failedTemplate: + errorMessage: Persistence - Expected to be one of [None, HostToContainer, Bidirectional], but got [invalid] + + - it: should fail with non-boolean readOnly + set: + image: *image + workload: + workload-name: *workload + persistence: + vol-name: + enabled: true + type: emptyDir + mountPath: /some/path + targetSelector: + workload-name: + container-name1: + readOnly: invalid + asserts: + - failedTemplate: + errorMessage: Persistence - Expected to be [boolean], but got [string] + + - it: should fail with empty readOnly + set: + image: *image + workload: + workload-name: *workload + persistence: + vol-name: + enabled: true + type: emptyDir + mountPath: /some/path + targetSelector: + workload-name: + container-name1: + readOnly: + asserts: + - failedTemplate: + errorMessage: Persistence - Expected to be [boolean], but got [invalid] + + - it: should fail with empty mountPath + set: + image: *image + workload: + workload-name: *workload + persistence: + vol-name: + enabled: true + type: emptyDir + mountPath: "" + targetSelector: + workload-name: + container-name1: {} + asserts: + - failedTemplate: + errorMessage: Persistence - Expected non-empty + + - it: should fail with mountPath not starting with / + set: + image: *image + workload: + workload-name: *workload + persistence: + vol-name: + enabled: true + type: emptyDir + targetSelector: + workload-name: + container-name1: + mountPath: some/path + asserts: + - failedTemplate: + errorMessage: Persistence - Expected to start with a forward slash [/] + + - it: should fail with non-dict targetSelect.workloadName + set: + image: *image + workload: + workload-name: *workload + persistence: + vol-name: + enabled: true + type: emptyDir + targetSelector: + workload-name: string + asserts: + - failedTemplate: + errorMessage: Persistence - Expected to be a [dict], but got [string] + + - it: should fail with empty targetSelect.workloadName + set: + image: *image + workload: + workload-name: *workload + persistence: + vol-name: + enabled: true + type: emptyDir + targetSelector: + workload-name: {} + asserts: + - failedTemplate: + errorMessage: Persistence - Expected non-empty diff --git a/library/common-test/tests/pod/volume_nfs-pv-pvc_test.yaml b/library/common-test/tests/pod/volume_nfs-pv-pvc_test.yaml new file mode 100644 index 00000000..beac6803 --- /dev/null +++ b/library/common-test/tests/pod/volume_nfs-pv-pvc_test.yaml @@ -0,0 +1,85 @@ +suite: pod nfs-pv-pvc volume test +templates: + - common.yaml +release: + name: test-release-name + namespace: test-release-namespace +tests: + - it: should pass with nfs-pv-pvc volume + set: + workload: + workload-name1: + enabled: true + primary: true + type: Deployment + podSpec: {} + persistence: + my-volume1: + enabled: true + type: pvc + static: + mode: nfs + server: my-server + share: /my-path + my-volume2: + enabled: true + type: pvc + static: + mode: nfs + server: my-server2 + share: /my-path2 + size: 2Gi + my-volume3: + enabled: true + type: pvc + static: + mode: nfs + server: my-server3 + share: /my-path3 + size: 3Gi + asserts: + - documentIndex: &pvDoc 1 + isKind: + of: PersistentVolume + - documentIndex: *pvDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-volume1-1599277109 + - documentIndex: &otherPvDoc 3 + isKind: + of: PersistentVolume + - documentIndex: *otherPvDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-volume2-1702692922 + - documentIndex: &thirdPvDoc 5 + isKind: + of: PersistentVolume + - documentIndex: *thirdPvDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-volume3-1705052221 + - documentIndex: &deploymentDoc 0 + isKind: + of: Deployment + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.volumes + content: + name: my-volume1 + persistentVolumeClaim: + claimName: test-release-name-common-test-my-volume1-1599277109 + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.volumes + content: + name: my-volume2 + persistentVolumeClaim: + claimName: test-release-name-common-test-my-volume2-1702692922 + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.volumes + content: + name: my-volume3 + persistentVolumeClaim: + claimName: test-release-name-common-test-my-volume3-1705052221 diff --git a/library/common-test/tests/pod/volume_smb-pv-pvc_test.yaml b/library/common-test/tests/pod/volume_smb-pv-pvc_test.yaml new file mode 100644 index 00000000..0fcf4380 --- /dev/null +++ b/library/common-test/tests/pod/volume_smb-pv-pvc_test.yaml @@ -0,0 +1,91 @@ +suite: pod smb-pv-pvc volume test +templates: + - common.yaml +release: + name: test-release-name + namespace: test-release-namespace +tests: + - it: should pass with smb-pv-pvc volume + set: + workload: + workload-name1: + enabled: true + primary: true + type: Deployment + podSpec: {} + persistence: + my-volume1: + enabled: true + type: pvc + static: + mode: smb + server: my-server + share: my-share + username: my-user + password: my-pass + my-volume2: + enabled: true + type: pvc + static: + mode: smb + server: my-server2 + share: my-share2 + username: my-user2 + password: my-pass2 + size: 2Gi + my-volume3: + enabled: true + type: pvc + static: + mode: smb + server: my-server3 + share: my-share3 + username: my-user3 + password: my-pass3 + size: 3Gi + asserts: + - documentIndex: &pvDoc 2 + isKind: + of: PersistentVolume + - documentIndex: *pvDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-volume1-1627785324 + - documentIndex: &otherPvDoc 5 + isKind: + of: PersistentVolume + - documentIndex: *otherPvDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-volume2-1734805617 + - documentIndex: &thirdPvDoc 8 + isKind: + of: PersistentVolume + - documentIndex: *thirdPvDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-volume3-1737164916 + - documentIndex: &deploymentDoc 0 + isKind: + of: Deployment + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.volumes + content: + name: my-volume1 + persistentVolumeClaim: + claimName: test-release-name-common-test-my-volume1-1627785324 + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.volumes + content: + name: my-volume2 + persistentVolumeClaim: + claimName: test-release-name-common-test-my-volume2-1734805617 + - documentIndex: *deploymentDoc + contains: + path: spec.template.spec.volumes + content: + name: my-volume3 + persistentVolumeClaim: + claimName: test-release-name-common-test-my-volume3-1737164916 diff --git a/library/common-test/tests/volumeClaimTemplate/metadata_test.yaml b/library/common-test/tests/volumeClaimTemplate/metadata_test.yaml index a7b4fa3b..5ad44ed1 100644 --- a/library/common-test/tests/volumeClaimTemplate/metadata_test.yaml +++ b/library/common-test/tests/volumeClaimTemplate/metadata_test.yaml @@ -1,4 +1,4 @@ -suite: volumeClaimTemplates metadata test +suite: volumeClaimTemplate metadata test templates: - common.yaml chart: @@ -16,9 +16,10 @@ tests: g_label1: global_label1 annotations: g_annotation1: global_annotation1 - volumeClaimTemplates: + persistence: my-volume1: enabled: true + type: vct labels: label1: "{{ .Values.label1 }}" label2: label2 diff --git a/library/common-test/tests/volumeClaimTemplate/names_test.yaml b/library/common-test/tests/volumeClaimTemplate/names_test.yaml index 0a28e53f..4029aad3 100644 --- a/library/common-test/tests/volumeClaimTemplate/names_test.yaml +++ b/library/common-test/tests/volumeClaimTemplate/names_test.yaml @@ -1,4 +1,4 @@ -suite: volumeClaimTemplates name test +suite: volumeClaimTemplate name test templates: - common.yaml release: @@ -7,11 +7,13 @@ release: tests: - it: should generate correct name set: - volumeClaimTemplates: + persistence: my-volume1: enabled: true + type: vct my-volume2: enabled: true + type: vct workload: main: enabled: true @@ -28,8 +30,8 @@ tests: - documentIndex: *statefulSetDoc equal: path: spec.volumeClaimTemplates[0].metadata.name - value: my-volume1 + value: test-release-name-common-test-my-volume1 - documentIndex: *statefulSetDoc equal: path: spec.volumeClaimTemplates[1].metadata.name - value: my-volume2 + value: test-release-name-common-test-my-volume2 diff --git a/library/common-test/tests/volumeClaimTemplate/validation_test.yaml b/library/common-test/tests/volumeClaimTemplate/validation_test.yaml index a837c53f..a869963c 100644 --- a/library/common-test/tests/volumeClaimTemplate/validation_test.yaml +++ b/library/common-test/tests/volumeClaimTemplate/validation_test.yaml @@ -7,9 +7,10 @@ release: tests: - it: should fail with annotations not a dict set: - volumeClaimTemplates: + persistence: volume1: enabled: true + type: vct annotations: not-a-dict workload: main: @@ -23,9 +24,10 @@ tests: - it: should fail with labels not a dict set: - volumeClaimTemplates: + persistence: volume1: enabled: true + type: vct labels: not-a-dict workload: main: @@ -39,9 +41,10 @@ tests: - it: should fail with pod targetSelector not a map set: - volumeClaimTemplates: + persistence: volume1: enabled: true + type: vct targetSelector: not-a-map workload: main: @@ -51,7 +54,7 @@ tests: podSpec: {} asserts: - failedTemplate: - errorMessage: Volume Claim Templates - Expected to be [dict], but got [string] + errorMessage: Persistence - Expected [targetSelector] to be [dict], but got [string] - it: should fail without storageClassName in ixChartContext set: @@ -59,9 +62,10 @@ tests: namespace: ix-namespace ixChartContext: storageClassName: "" - volumeClaimTemplates: + persistence: volume1: enabled: true + type: vct workload: main: enabled: true @@ -70,7 +74,7 @@ tests: podSpec: {} asserts: - failedTemplate: - errorMessage: Volume Claim Templates - Expected non-empty + errorMessage: PVC - Expected non-empty - it: should fail without storageClassName in ixChartContext with SCALE-ZFS explicitly set set: @@ -78,9 +82,10 @@ tests: namespace: ix-namespace ixChartContext: storageClassName: "" - volumeClaimTemplates: + persistence: volume1: enabled: true + type: vct storageClass: SCALE-ZFS workload: main: @@ -90,13 +95,14 @@ tests: podSpec: {} asserts: - failedTemplate: - errorMessage: Volume Claim Templates - Expected non-empty on [SCALE-ZFS] storageClass + errorMessage: PVC - Expected non-empty on [SCALE-ZFS] storageClass - it: should fail with invalid accessMode set: - volumeClaimTemplates: + persistence: volume1: enabled: true + type: vct accessModes: - not-an-access-mode workload: @@ -107,4 +113,4 @@ tests: podSpec: {} asserts: - failedTemplate: - errorMessage: Volume Claim Templates - Expected entry to be one of [ReadWriteOnce, ReadOnlyMany, ReadWriteMany, ReadWriteOncePod], but got [not-an-access-mode] + errorMessage: PVC - 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 index 89cf37d4..b6f44428 100644 --- a/library/common-test/tests/volumeClaimTemplate/vct_data_test.yaml +++ b/library/common-test/tests/volumeClaimTemplate/vct_data_test.yaml @@ -1,4 +1,4 @@ -suite: volumeClaimTemplates data test +suite: volumeClaimTemplate data test templates: - common.yaml release: @@ -7,9 +7,10 @@ release: tests: - it: should create vct set: - volumeClaimTemplates: + persistence: my-volume1: enabled: true + type: vct mountPath: /some/path workload: main: @@ -27,7 +28,7 @@ tests: - documentIndex: *statefulSetDoc equal: path: spec.volumeClaimTemplates[0].metadata.name - value: my-volume1 + value: test-release-name-common-test-my-volume1 - documentIndex: *statefulSetDoc equal: path: spec.volumeClaimTemplates[0].spec.accessModes @@ -44,9 +45,10 @@ tests: - it: should create vct with accessModes set as string set: some_mode: ReadWriteMany - volumeClaimTemplates: + persistence: my-volume1: enabled: true + type: vct mountPath: /some/path accessModes: "{{ .Values.some_mode }}" workload: @@ -68,9 +70,10 @@ tests: - it: should create pvc with accessModes set as list set: some_mode: ReadWriteMany - volumeClaimTemplates: + persistence: my-volume1: enabled: true + type: vct mountPath: /some/path accessModes: - "{{ .Values.some_mode }}" @@ -94,9 +97,10 @@ tests: - it: should create pvc with size set set: - volumeClaimTemplates: + persistence: my-volume1: enabled: true + type: vct mountPath: /some/path size: 20Gi workload: @@ -117,9 +121,10 @@ tests: - it: should create vct with storageClass set "-" set: some_storage_class: "-" - volumeClaimTemplates: + persistence: my-volume1: enabled: true + type: vct mountPath: /some/path storageClass: "{{ .Values.some_storage_class }}" workload: @@ -140,9 +145,10 @@ tests: - it: should create vct with storageClass set set: some_storage_class: some-storage-class - volumeClaimTemplates: + persistence: my-volume1: enabled: true + type: vct mountPath: /some/path storageClass: "{{ .Values.some_storage_class }}" workload: @@ -164,9 +170,10 @@ tests: set: fallbackDefaults: storageClass: some-storage-class - volumeClaimTemplates: + persistence: my-volume1: enabled: true + type: vct mountPath: /some/path workload: main: @@ -190,9 +197,10 @@ tests: ixChartContext: storageClassName: ix-storage-class-releasename some_storage_class: "SCALE-ZFS" - volumeClaimTemplates: + persistence: my-volume1: enabled: true + type: vct mountPath: /some/path storageClass: "{{ .Values.some_storage_class }}" workload: @@ -217,9 +225,10 @@ tests: ixChartContext: storageClassName: ix-storage-class-releasename some_storage_class: "SCALE-ZFS" - volumeClaimTemplates: + persistence: my-volume1: enabled: true + type: vct mountPath: /some/path workload: main: diff --git a/library/common/Chart.yaml b/library/common/Chart.yaml index 3460d175..3a3390ee 100644 --- a/library/common/Chart.yaml +++ b/library/common/Chart.yaml @@ -15,4 +15,4 @@ maintainers: name: common sources: null type: library -version: 14.5.0 +version: 15.0.0 diff --git a/library/common/templates/class/_cnpgCluster.tpl b/library/common/templates/class/_cnpgCluster.tpl index 59b65f3d..a89e807f 100644 --- a/library/common/templates/class/_cnpgCluster.tpl +++ b/library/common/templates/class/_cnpgCluster.tpl @@ -45,25 +45,11 @@ spec: storage: pvcTemplate: - {{- with (include "tc.v1.common.lib.storage.storageClassName" ( dict "rootCtx" $ "objectData" $values.storage )) | trim }} - storageClassName: {{ . }} - {{- end }} - accessModes: - - ReadWriteOnce - resources: - requests: - storage: {{ tpl ($values.storage.walsize | default $.Values.fallbackDefaults.vctSize) $ | quote }} + {{- include "tc.v1.common.lib.storage.pvc.spec" (dict "rootCtx" $ "objectData" $values.storage) | trim | nindent 6 }} walStorage: pvcTemplate: - {{- with (include "tc.v1.common.lib.storage.storageClassName" ( dict "rootCtx" $ "objectData" $values.storage )) | trim }} - storageClassName: {{ . }} - {{- end }} - accessModes: - - ReadWriteOnce - resources: - requests: - storage: {{ tpl ($values.storage.walsize | default $.Values.fallbackDefaults.vctSize) $ | quote }} + {{- include "tc.v1.common.lib.storage.pvc.spec" (dict "rootCtx" $ "objectData" $values.walStorage) | trim | nindent 6 }} monitoring: enablePodMonitor: {{ $values.monitoring.enablePodMonitor | default true }} diff --git a/library/common/templates/class/_persistentVolume.tpl b/library/common/templates/class/_persistentVolume.tpl new file mode 100644 index 00000000..7b4de0d9 --- /dev/null +++ b/library/common/templates/class/_persistentVolume.tpl @@ -0,0 +1,75 @@ +{{/* PersistentVolume Class */}} +{{/* Call this template: +{{ include "tc.v1.common.class.pv" (dict "rootCtx" $ "objectData" $objectData) }} + +rootCtx: The root context of the chart. +objectData: + name: The name of the PV. + labels: The labels of the PV. + annotations: The annotations of the PV. + provisioner: The provisioner to use for the PersistentVolume. + driver: The driver to use for the csi + retain: Whether to retain the PV after deletion. (Default: false) + size: The size of the PersistentVolume. (Default: 1Gi) +*/}} + +{{- define "tc.v1.common.class.pv" -}} + + {{- $rootCtx := .rootCtx -}} + {{- $objectData := .objectData -}} + + {{- $retain := $rootCtx.Values.fallbackDefaults.pvcRetain -}} + {{- if not (kindIs "invalid" $objectData.retain) -}} + {{- $retain = $objectData.retain -}} + {{- end -}} + + {{- $reclaimPolicy := ternary "Retain" "Delete" $retain -}} + + {{- $pvcSize := $rootCtx.Values.fallbackDefaults.pvcSize -}} + {{- with $objectData.size -}} + {{- $pvcSize = tpl . $rootCtx -}} + {{- end }} +--- +apiVersion: v1 +kind: PersistentVolume +metadata: + name: {{ $objectData.name }} + {{- $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)) -}} + {{- if $retain -}} + {{- $_ := set $annotations "\"helm.sh/resource-policy\"" "keep" -}} + {{- end -}} + {{- $_ := set $annotations "pv.kubernetes.io/provisioned-by" $objectData.provisioner -}} + {{- with (include "tc.v1.common.lib.metadata.render" (dict "rootCtx" $rootCtx "annotations" $annotations) | trim) }} + annotations: + {{- . | nindent 4 }} + {{- end }} +spec: + capacity: + storage: {{ $pvcSize }} + persistentVolumeReclaimPolicy: {{ $reclaimPolicy }} + storageClassName: {{ $objectData.name }} + accessModes: + {{- include "tc.v1.common.lib.pvc.accessModes" (dict "rootCtx" $rootCtx "objectData" $objectData "caller" "Persistent Volume") | trim | nindent 4 -}} + {{- if $objectData.mountOptions }} + mountOptions: + {{- range $opt := $objectData.mountOptions -}} + {{- if $opt.value }} + - {{ printf "%s=%s" (tpl $opt.key $rootCtx) (tpl (include "tc.v1.common.helper.makeIntOrNoop" $opt.value) $rootCtx) }} + {{- else }} + - {{ tpl $opt.key $rootCtx }} + {{- end -}} + {{- end -}} + {{- end -}} + {{- if $objectData.static -}} + {{- if eq "smb" $objectData.static.mode -}} + {{- include "tc.v1.common.lib.storage.smbCSI" (dict "rootCtx" $rootCtx "objectData" $objectData) | trim | nindent 2 -}} + {{- else if eq "nfs" $objectData.static.mode -}} + {{- include "tc.v1.common.lib.storage.nfsCSI" (dict "rootCtx" $rootCtx "objectData" $objectData) | trim | nindent 2 -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/library/common/templates/class/_pvc.tpl b/library/common/templates/class/_pvc.tpl index b1451018..22d40f94 100644 --- a/library/common/templates/class/_pvc.tpl +++ b/library/common/templates/class/_pvc.tpl @@ -1,4 +1,4 @@ -{{/* PVC Class */}} +{{/* PersistentVolumeClaim Class */}} {{/* Call this template: {{ include "tc.v1.common.class.pvc" (dict "rootCtx" $ "objectData" $objectData) }} @@ -7,6 +7,10 @@ objectData: name: The name of the PVC. labels: The labels of the PVC. annotations: The annotations of the PVC. + size: The size of the PVC. (Default: 1Gi) + volumeName: The name of the volume to bind to. (Default: "") + retain: Whether to retain the PVC after deletion. (Default: false) + storageClass: The storage class to use. (Absent) */}} {{- define "tc.v1.common.class.pvc" -}} @@ -43,15 +47,5 @@ metadata: {{- . | nindent 4 }} {{- end }} spec: - accessModes: - {{- include "tc.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 "tc.v1.common.lib.storage.storageClassName" (dict "rootCtx" $rootCtx "objectData" $objectData "caller" "PVC") | trim) }} - storageClassName: {{ . }} - {{- end -}} + {{- include "tc.v1.common.lib.storage.pvc.spec" (dict "rootCtx" $rootCtx "objectData" $objectData) | trim | nindent 2 }} {{- end -}} diff --git a/library/common/templates/lib/container/_volumeMounts.tpl b/library/common/templates/lib/container/_volumeMounts.tpl index 027cdc4f..1008625f 100644 --- a/library/common/templates/lib/container/_volumeMounts.tpl +++ b/library/common/templates/lib/container/_volumeMounts.tpl @@ -10,21 +10,16 @@ objectData: The object data to be used to render the container. {{- $volMounts := list -}} - {{- $codeServerIgnoredTypes := (list "configmap" "secret") -}} - {{- $keys := (list "persistence") -}} - {{- if eq $objectData.podType "StatefulSet" -}} - {{- $keys = mustAppend $keys "volumeClaimTemplates" -}} - {{- end -}} + {{- $codeServerIgnoredTypes := (list "configmap" "secret" "vct") -}} - {{- range $key := $keys -}} - {{- range $persistenceName, $persistenceValues := (get $rootCtx.Values $key) -}} - {{- if $persistenceValues.enabled -}} - {{/* Dont try to mount configmap/sercet to codeserver */}} - {{- if not (and (eq $objectData.shortName "codeserver") (mustHas $persistenceValues.type $codeServerIgnoredTypes)) -}} - {{- $volMount := (fromJson (include "tc.v1.common.lib.container.volumeMount.isSelected" (dict "persistenceName" $persistenceName "persistenceValues" $persistenceValues "objectData" $objectData "key" $key))) -}} - {{- if $volMount -}} - {{- $volMounts = mustAppend $volMounts $volMount -}} - {{- end -}} + {{- range $persistenceName, $persistenceValues := $rootCtx.Values.persistence -}} + {{/* TLDR: Enabled + Not VCT without STS */}} + {{- if and $persistenceValues.enabled (not (and (eq $persistenceValues.type "vct") (ne $objectData.podType "StatefulSet"))) -}} + {{/* Dont try to mount configmap/sercet/vct to codeserver */}} + {{- if not (and (eq $objectData.shortName "codeserver") (mustHas $persistenceValues.type $codeServerIgnoredTypes)) -}} + {{- $volMount := (fromJson (include "tc.v1.common.lib.container.volumeMount.isSelected" (dict "persistenceName" $persistenceName "persistenceValues" $persistenceValues "objectData" $objectData))) -}} + {{- if $volMount -}} + {{- $volMounts = mustAppend $volMounts $volMount -}} {{- end -}} {{- end -}} {{- end -}} @@ -37,20 +32,20 @@ objectData: The object data to be used to render the container. {{- $_ := set $volMount "mountPropagation" (tpl $volMount.mountPropagation $rootCtx) -}} {{- if not $volMount.mountPath -}} - {{- fail (printf "%s - Expected non-empty " (camelcase $volMount.key)) -}} + {{- fail (printf "Persistence - Expected non-empty ") -}} {{- end -}} {{- if not (hasPrefix "/" $volMount.mountPath) -}} - {{- fail (printf "%s - Expected to start with a forward slash [/]" (camelcase $volMount.key)) -}} + {{- fail (printf "Persistence - Expected to start with a forward slash [/]") -}} {{- end -}} {{- $propagationTypes := (list "None" "HostToContainer" "Bidirectional") -}} {{- if and $volMount.mountPropagation (not (mustHas $volMount.mountPropagation $propagationTypes)) -}} - {{- fail (printf "%s - Expected to be one of [%s], but got [%s]" (camelcase $volMount.key) (join ", " $propagationTypes) $volMount.mountPropagation) -}} + {{- fail (printf "Persistence - Expected to be one of [%s], but got [%s]" (join ", " $propagationTypes) $volMount.mountPropagation) -}} {{- end -}} {{- if not (kindIs "bool" $volMount.readOnly) -}} - {{- fail (printf "%s - Expected to be [boolean], but got [%s]" (camelcase $volMount.key) (kindOf $volMount.readOnly)) -}} + {{- fail (printf "Persistence - Expected to be [boolean], but got [%s]" (kindOf $volMount.readOnly)) -}} {{- end }} - name: {{ $volMount.name }} mountPath: {{ $volMount.mountPath }} @@ -69,12 +64,10 @@ objectData: The object data to be used to render the container. {{- $persistenceName := .persistenceName -}} {{- $persistenceValues := .persistenceValues -}} {{- $objectData := .objectData -}} - {{- $key := .key -}} {{/* Initialize from the default values */}} {{- $volMount := dict -}} {{- $_ := set $volMount "name" $persistenceName -}} - {{- $_ := set $volMount "key" $key -}} {{- if eq $persistenceValues.type "device" -}} {{/* On devices use the hostPath as default if mountpath is not defined */}} {{- $_ := set $volMount "mountPath" ($persistenceValues.mountPath | default $persistenceValues.hostPath | default "") -}} {{- else -}} @@ -86,7 +79,7 @@ objectData: The object data to be used to render the container. {{- $return := false -}} {{/* If targetSelectAll is set, means all pods/containers */}} {{/* targetSelectAll does not make sense for vct */}} - {{- if and $persistenceValues.targetSelectAll (ne $key "volumeClaimTemplates") -}} + {{- if and $persistenceValues.targetSelectAll (ne $persistenceValues.type "vct") -}} {{- $return = true -}} {{/* Set custom path on autopermissions container */}} {{- if and (eq $objectData.shortName "autopermissions") $persistenceValues.autoPermissions -}} @@ -107,15 +100,19 @@ objectData: The object data to be used to render the container. {{/* Else if selector is defined */}} {{- else if $persistenceValues.targetSelector -}} + {{- if not (kindIs "map" $persistenceValues.targetSelector) -}} + {{- fail (printf "Persistence - Expected [targetSelector] to be a [dict] but got [%s]" (kindOf $persistenceValues.targetSelector)) -}} + {{- end -}} + {{/* 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)) -}} + {{- fail (printf "Persistence - Expected to be a [dict], but got [%s]" $objectData.podShortName (kindOf $selectorValues)) -}} {{- end -}} {{- if not $selectorValues -}} - {{- fail (printf "%s - Expected non-empty " (camelcase $key) $objectData.podShortName) -}} + {{- fail (printf "Persistence - Expected non-empty " $objectData.podShortName) -}} {{- end -}} {{/* If container is selected */}} diff --git a/library/common/templates/lib/pod/_volumes.tpl b/library/common/templates/lib/pod/_volumes.tpl index d054c2d0..73844e66 100644 --- a/library/common/templates/lib/pod/_volumes.tpl +++ b/library/common/templates/lib/pod/_volumes.tpl @@ -29,6 +29,10 @@ objectData: The object data to be used to render the Pod. {{/* If targetSelector is set, check if pod is selected */}} {{- else if $persistence.targetSelector -}} + {{- if not (kindIs "map" $persistence.targetSelector) -}} + {{- fail (printf "Persistence - Expected [targetSelector] to be [dict], but got [%s]" (kindOf $persistence.targetSelector)) -}} + {{- end -}} + {{- if (mustHas $objectData.shortName (keys $persistence.targetSelector)) -}} {{- $selected = true -}} {{- end -}} diff --git a/library/common/templates/lib/pod/volumes/_pvc.tpl b/library/common/templates/lib/pod/volumes/_pvc.tpl index b0a2fe20..1f93e965 100644 --- a/library/common/templates/lib/pod/volumes/_pvc.tpl +++ b/library/common/templates/lib/pod/volumes/_pvc.tpl @@ -8,7 +8,7 @@ objectData: The object data to be used to render the volume. {{- $rootCtx := .rootCtx -}} {{- $objectData := .objectData -}} - {{- $pvcName := (printf "%s-%s" (include "tc.v1.common.lib.chart.names.fullname" $rootCtx) $objectData.shortName) -}} + {{- $pvcName := include "tc.v1.common.lib.storage.pvc.name" (dict "rootCtx" $rootCtx "objectName" $objectData.shortName "objectData" $objectData) -}} {{- with $objectData.existingClaim -}} {{- $pvcName = tpl . $rootCtx -}} {{- end }} diff --git a/library/common/templates/lib/storage/_nfsCSI.tpl b/library/common/templates/lib/storage/_nfsCSI.tpl new file mode 100644 index 00000000..f3f9c015 --- /dev/null +++ b/library/common/templates/lib/storage/_nfsCSI.tpl @@ -0,0 +1,21 @@ +{{/* NFS CSI */}} +{{/* Call this template: +{{ include "tc.v1.common.lib.storage.nfsCSI" (dict "rootCtx" $ "objectData" $objectData) }} + +rootCtx: The root context of the chart. +objectData: + driver: The name of the driver. + server: The server address. + share: The share to the NFS share. +*/}} +{{- define "tc.v1.common.lib.storage.nfsCSI" -}} + {{- $rootCtx := .rootCtx -}} + {{- $objectData := .objectData }} +csi: + driver: {{ $objectData.static.driver }} + {{- /* Create a unique handle, server/share#release-app-volumeName */}} + volumeHandle: {{ printf "%s%s#%s" $objectData.static.server $objectData.static.share $objectData.name }} + volumeAttributes: + server: {{ tpl $objectData.static.server $rootCtx }} + share: {{ tpl $objectData.static.share $rootCtx }} +{{- end -}} diff --git a/library/common/templates/lib/storage/_smbCSI.tpl b/library/common/templates/lib/storage/_smbCSI.tpl new file mode 100644 index 00000000..522ead36 --- /dev/null +++ b/library/common/templates/lib/storage/_smbCSI.tpl @@ -0,0 +1,23 @@ +{{/* SMB CSI */}} +{{/* Call this template: +{{ include "tc.v1.common.lib.storage.smbCSI" (dict "rootCtx" $ "objectData" $objectData) }} + +rootCtx: The root context of the chart. +objectData: + driver: The name of the driver. + server: The server address. + share: The share to the SMB share. +*/}} +{{- define "tc.v1.common.lib.storage.smbCSI" -}} + {{- $rootCtx := .rootCtx -}} + {{- $objectData := .objectData }} +csi: + driver: {{ $objectData.static.driver }} + {{- /* Create a unique handle, server/share#release-app-volumeName */}} + volumeHandle: {{ printf "%s/%s#%s" $objectData.static.server $objectData.static.share $objectData.name }} + volumeAttributes: + source: {{ printf "//%v/%v" (tpl $objectData.static.server $rootCtx) (tpl $objectData.static.share $rootCtx) }} + nodeStageSecretRef: + name: {{ $objectData.name }} + namespace: {{ $rootCtx.Release.Namespace }} +{{- end -}} diff --git a/library/common/templates/lib/storage/_storageClassName.tpl b/library/common/templates/lib/storage/_storageClassName.tpl index a4f4f6d8..059f5abc 100644 --- a/library/common/templates/lib/storage/_storageClassName.tpl +++ b/library/common/templates/lib/storage/_storageClassName.tpl @@ -13,7 +13,6 @@ objectData: The object data of the pvc If storageClass is defined on the objectData: * "-" returns "", which means requesting a PV without class * "SCALE-ZFS" returns the value set on Values.global.ixChartContext.storageClassName - (*) "SCALE-SMB" returns the value set on Values.global.ixChartContext.smbStorageClassName (Example for the future) * Else return the original defined storageClass Else if we are in an ixChartContext, always return the storageClassName defined on the ixChartContext diff --git a/library/common/templates/lib/storage/_validation.tpl b/library/common/templates/lib/storage/_validation.tpl index 3c71a7b0..f8bc4d6e 100644 --- a/library/common/templates/lib/storage/_validation.tpl +++ b/library/common/templates/lib/storage/_validation.tpl @@ -1,39 +1,44 @@ -{{/* PVC Validation */}} +{{/* Persistence Validation */}} {{/* Call this template: {{ include "tc.v1.common.lib.persistence.validation" (dict "objectData" $objectData) -}} objectData: rootCtx: The root context of the chart. - objectData: The pvc object. + objectData: The persistence object. */}} {{- define "tc.v1.common.lib.persistence.validation" -}} {{- $rootCtx := .rootCtx -}} {{- $objectData := .objectData -}} - {{- $types := (list "pvc" "emptyDir" "nfs" "hostPath" "ixVolume" "secret" "configmap" "device") -}} + {{- $types := (list "pvc" "vct" "emptyDir" "nfs" "hostPath" "ixVolume" "secret" "configmap" "device") -}} {{- if not (mustHas $objectData.type $types) -}} {{- fail (printf "Persistence - Expected to be one of [%s], but got [%s]" (join ", " $types) $objectData.type) -}} {{- end -}} + {{- if and $objectData.static $objectData.static.mode -}} + {{- $validModes := (list "disabled" "smb" "nfs" "custom") -}} + {{- if not (mustHas $objectData.static.mode $validModes) -}} + {{- fail (printf "Persistence - Expected [static.mode] to be one of [%s], but got [%s]" (join ", " $validModes) $objectData.static.mode) -}} + {{- end -}} + {{- end -}} + + {{- if $objectData.dataSource -}} + {{- if not $objectData.dataSource.name -}} + {{- fail "Persistence - Expected [dataSource.name] to be non-empty" -}} + {{- end -}} + + {{- if not $objectData.dataSource.kind -}} + {{- fail "Persistence - Expected [dataSource.kind] to be non-empty" -}} + {{- end -}} + + {{- $validKinds := (list "VolumeSnapshot" "PersistentVolumeClaim") -}} + {{- if not (mustHas $objectData.dataSource.kind $validKinds) -}} + {{- fail (printf "Persistence - Expected [dataSource.kind] to be one of [%s], but got [%s]" (join ", " $validKinds) $objectData.dataSource.kind) -}} + {{- end -}} + {{- end -}} + {{- if and $objectData.targetSelector (not (kindIs "map" $objectData.targetSelector)) -}} {{- fail (printf "Persistence - Expected to be [dict], but got [%s]" (kindOf $objectData.targetSelector)) -}} {{- end -}} {{- end -}} - -{{/* VCT Validation */}} -{{/* Call this template: -{{ include "tc.v1.common.lib.vct.validation" (dict "objectData" $objectData) -}} -objectData: - rootCtx: The root context of the chart. - objectData: The vct object. -*/}} - -{{- define "tc.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/templates/lib/storage/_validationCsiNFS.tpl b/library/common/templates/lib/storage/_validationCsiNFS.tpl new file mode 100644 index 00000000..6f516828 --- /dev/null +++ b/library/common/templates/lib/storage/_validationCsiNFS.tpl @@ -0,0 +1,50 @@ +{{/* Validate NFS CSI */}} +{{/* Call this template: +{{ include "tc.v1.common.lib.storage.nfsCSI.validation" (dict "rootCtx" $ "objectData" $objectData) }} + +rootCtx: The root context of the chart. +objectData: + driver: The name of the driver. + mountOptions: The mount options. + server: The server address. + share: The share to the NFS share. +*/}} +{{- define "tc.v1.common.lib.storage.nfsCSI.validation" -}} + {{- $rootCtx := .rootCtx -}} + {{- $objectData := .objectData -}} + + {{- if hasKey $rootCtx.Values.global "ixChartContext" -}} + {{- if not $rootCtx.Values.global.ixChartContext.hasNFSCSI -}} + {{- fail "NFS CSI - Not supported CSI" -}} + {{- end -}} + {{- end -}} + + {{- $required := (list "server" "share") -}} + {{- range $item := $required -}} + {{- if not (get $objectData.static $item) -}} + {{- fail (printf "NFS CSI - Expected <%v> to be non-empty" $item) -}} + {{- end -}} + {{- end -}} + + {{- if not (hasPrefix "/" $objectData.static.share) -}} + {{- fail "NFS CSI - Expected to start with [/]" -}} + {{- end -}} + + {{/* TODO: Allow only specific opts / set specific opts by default? + {{- $validOpts := list -}} */}} + {{- range $opt := $objectData.mountOptions -}} + {{- if not (kindIs "map" $opt) -}} + {{- fail (printf "NFS CSI - Expected item to be a dict, but got [%s]" (kindOf $opt)) -}} + {{- end -}} + {{- if not $opt.key -}} + {{- fail "NFS CSI - Expected key in to be non-empty" -}} + {{- end -}} + + {{/* + {{- $key := tpl $opt.key $rootCtx -}} + {{- if not (mustHas $key $validOpts) -}} + {{- fail (printf "NFS CSI - Expected to be one of [%v], but got [%v]" (join ", " $validOpts) $opt) -}} + {{- end -}} + */}} + {{- end -}} +{{- end -}} diff --git a/library/common/templates/lib/storage/_validationCsiSMB.tpl b/library/common/templates/lib/storage/_validationCsiSMB.tpl new file mode 100644 index 00000000..af8e21db --- /dev/null +++ b/library/common/templates/lib/storage/_validationCsiSMB.tpl @@ -0,0 +1,54 @@ +{{/* Validate SMB CSI */}} +{{/* Call this template: +{{ include "tc.v1.common.lib.storage.smbCSI.validation" (dict "rootCtx" $ "objectData" $objectData) }} + +rootCtx: The root context of the chart. +objectData: + driver: The name of the driver. + mountOptions: The mount options. + server: The server address. + share: The share to the SMB share. +*/}} +{{- define "tc.v1.common.lib.storage.smbCSI.validation" -}} + {{- $rootCtx := .rootCtx -}} + {{- $objectData := .objectData -}} + + {{- if hasKey $rootCtx.Values.global "ixChartContext" -}} + {{- if not $rootCtx.Values.global.ixChartContext.hasSMBCSI -}} + {{- fail "SMB CSI - Not supported CSI" -}} + {{- end -}} + {{- end -}} + + {{- $required := (list "server" "share" "username" "password") -}} + {{- range $item := $required -}} + {{- if not (get $objectData.static $item) -}} + {{- fail (printf "SMB CSI - Expected <%v> to be non-empty" $item) -}} + {{- end -}} + {{- end -}} + + {{- if hasPrefix "//" $objectData.static.server -}} + {{- fail "SMB CSI - Did not expect to start with [//]" -}} + {{- end -}} + + {{- if hasPrefix "/" $objectData.static.share -}} + {{- fail "SMB CSI - Did not expect to start with [/]" -}} + {{- end -}} + + {{/* TODO: Allow only specific opts? / set specific opts by default? + {{- $validOpts := list -}} */}} + {{- range $opt := $objectData.mountOptions -}} + {{- if not (kindIs "map" $opt) -}} + {{- fail (printf "SMB CSI - Expected item to be a dict, but got [%s]" (kindOf $opt)) -}} + {{- end -}} + {{- if not $opt.key -}} + {{- fail "SMB CSI - Expected key in to be non-empty" -}} + {{- end -}} + + {{/* + {{- $key := tpl $opt.key $rootCtx -}} + {{- if not (mustHas $key $validOpts) -}} + {{- fail (printf "SMB CSI - Expected to be one of [%v], but got [%v]" (join ", " $validOpts) $opt) -}} + {{- end -}} + */}} + {{- end -}} +{{- end -}} diff --git a/library/common/templates/lib/storage/_volumeClaimTemplates.tpl b/library/common/templates/lib/storage/_volumeClaimTemplates.tpl index 37e55e02..eb5e77bc 100644 --- a/library/common/templates/lib/storage/_volumeClaimTemplates.tpl +++ b/library/common/templates/lib/storage/_volumeClaimTemplates.tpl @@ -8,15 +8,15 @@ objectData: The object data to be used to render the Pod. {{- $rootCtx := .rootCtx -}} {{- $objectData := .objectData -}} - {{- range $name, $vctValues := $rootCtx.Values.volumeClaimTemplates -}} + {{- range $name, $vctValues := $rootCtx.Values.persistence -}} - {{- if $vctValues.enabled -}} + {{- if and $vctValues.enabled (eq $vctValues.type "vct") -}} {{- $vct := (mustDeepCopy $vctValues) -}} {{- $selected := false -}} {{- $_ := set $vct "shortName" $name -}} - {{- include "tc.v1.common.lib.vct.validation" (dict "objectData" $vct) -}} + {{- include "tc.v1.common.lib.persistence.validation" (dict "objectData" $vct) -}} {{- include "tc.v1.common.lib.chart.names.validation" (dict "name" $vct.shortName) -}} {{- include "tc.v1.common.lib.metadata.validation" (dict "objectData" $vct "caller" "Volume Claim Templates") -}} @@ -40,7 +40,7 @@ objectData: The object data to be used to render the Pod. {{- $vctSize = tpl . $rootCtx -}} {{- end }} - metadata: - name: {{ $vct.shortName }} + name: {{ include "tc.v1.common.lib.storage.pvc.name" (dict "rootCtx" $rootCtx "objectName" $vct.shortName "objectData" $vctValues) }} {{- $labels := $vct.labels | default dict -}} {{- with (include "tc.v1.common.lib.metadata.render" (dict "rootCtx" $rootCtx "labels" $labels) | trim) }} labels: @@ -52,14 +52,7 @@ objectData: The object data to be used to render the Pod. {{- . | nindent 6 }} {{- end }} spec: - {{- with (include "tc.v1.common.lib.storage.storageClassName" (dict "rootCtx" $rootCtx "objectData" $vct "caller" "Volume Claim Templates") | trim) }} - storageClassName: {{ . }} - {{- end }} - accessModes: - {{- include "tc.v1.common.lib.pvc.accessModes" (dict "rootCtx" $rootCtx "objectData" $vct "caller" "Volume Claim Templates") | trim | nindent 6 }} - resources: - requests: - storage: {{ $vctSize }} + {{- include "tc.v1.common.lib.storage.pvc.spec" (dict "rootCtx" $rootCtx "objectData" $vctValues) | trim | nindent 4 }} {{- end -}} {{- end -}} {{- end -}} diff --git a/library/common/templates/lib/storage/pvc/_name.tpl b/library/common/templates/lib/storage/pvc/_name.tpl new file mode 100644 index 00000000..44c39b80 --- /dev/null +++ b/library/common/templates/lib/storage/pvc/_name.tpl @@ -0,0 +1,51 @@ +{{/* Returns Persitent Volume Claim name*/}} +{{/* Call this template: +{{ include "tc.v1.common.lib.storage.pvc.name" (dict "rootCtx" $ "objectName" $objectName "objectData" $objectData) }} +objectName: the base name of the object without any alteration or sanitation +rootCtx: The root context of the chart. +objectData: The object data to be used to render the Pod. +*/}} +{{- define "tc.v1.common.lib.storage.pvc.name" -}} +{{- $rootCtx := .rootCtx -}} +{{- $objectName := .objectName -}} +{{- $objectData := .objectData -}} +{{- $hashValues := "" -}} + + {{- $renderedName := (printf "%s-%s" (include "tc.v1.common.lib.chart.names.fullname" $rootCtx) $objectName) -}} + {{/* Perform validations */}} + {{- include "tc.v1.common.lib.chart.names.validation" (dict "name" $renderedName) -}} + + {{- $modes := (list "smb" "nfs") -}} + {{- if $objectData.static -}} + {{- if and $objectData.static.mode (mustHas $objectData.static.mode $modes) -}} + + {{- $size := $objectData.size | default $rootCtx.Values.fallbackDefaults.pvcSize -}} + + {{/* Create a unique name taking into account server and share, + without this, changing one of those values is not possible */}} + + {{- $hashValues = (printf "%s-%s-%s" $size $objectData.static.server $objectData.static.share) -}} + {{- if $objectData.domain -}} + {{- $hashValues = (printf "%s-%s" $hashValues $objectData.domain) -}} + {{- end -}} + + {{- else if eq $objectData.static.mode "custom" -}} + {{- $hashValues = (printf "%s-%v" $size $objectData.csi) -}} + {{- end -}} + {{- end -}} + + {{/* Create a hash from the dataSource settings to ensure a new PVC is created when a dataSource is set*/}} + {{- if $objectData.dataSource -}} + {{- $hashValues = (printf "%s-%s-%s" $hashValues $objectData.dataSource.kind $objectData.dataSource.name) -}} + {{- end -}} + + {{- $objectName = $renderedName -}} + {{- if $hashValues -}} + {{- $hash := adler32sum $hashValues -}} + {{- $objectName = (printf "%s-%v" $renderedName $hash) -}} + {{- end -}} + + {{/* Return the new objectName */}} + {{- $objectName -}} + +{{- end -}} diff --git a/library/common/templates/lib/storage/pvc/_spec.tpl b/library/common/templates/lib/storage/pvc/_spec.tpl new file mode 100644 index 00000000..bd29103a --- /dev/null +++ b/library/common/templates/lib/storage/pvc/_spec.tpl @@ -0,0 +1,38 @@ +{{/* Returns Persitant Volume Claim Spec*/}} +{{/* Call this template: +{{ include "tc.v1.common.lib.storage.pvc.spec" (dict "rootCtx" $ "objectData" $objectData) }} +rootCtx: The root context of the chart. +objectData: The object data to be used to render the Pod. +*/}} +{{- define "tc.v1.common.lib.storage.pvc.spec" -}} +{{- $rootCtx := .rootCtx -}} +{{- $objectData := .objectData -}} + +{{- $size := $rootCtx.Values.fallbackDefaults.pvcSize -}} +{{- with $objectData.size -}} + {{- $size = tpl . $rootCtx -}} +{{- end }} + +accessModes: + {{- include "tc.v1.common.lib.pvc.accessModes" (dict "rootCtx" $rootCtx "objectData" $objectData "caller" "PVC") | trim | nindent 2 }} +resources: + requests: + storage: {{ $size }} + {{- with $objectData.volumeName }} +volumeName: {{ tpl . $rootCtx }} + {{- end -}} + {{- with (include "tc.v1.common.lib.storage.storageClassName" (dict "rootCtx" $rootCtx "objectData" $objectData "caller" "PVC") | trim) }} +storageClassName: {{ . }} + {{- end -}} + {{- with $objectData.dataSource -}} + {{- $sourceName := .name -}} + {{- if eq .kind "PersistentVolumeClaim" -}} + {{- with get $rootCtx.persistence $sourceName -}} + {{- $sourceName := (include "tc.v1.common.lib.storage.pvc.name" (dict "rootCtx" $rootCtx "objectName" $sourceName "objectData" .)) -}} + {{- end -}} + {{- end }} +dataSource: + kind: {{ .kind }} + name: {{ $sourceName }} + {{- end -}} +{{- end -}} diff --git a/library/common/templates/spawner/_pvc.tpl b/library/common/templates/spawner/_pvc.tpl index 14b11976..d6402f79 100644 --- a/library/common/templates/spawner/_pvc.tpl +++ b/library/common/templates/spawner/_pvc.tpl @@ -4,7 +4,6 @@ */}} {{- define "tc.v1.common.spawner.pvc" -}} - {{- $fullname := include "tc.v1.common.lib.chart.names.fullname" $ -}} {{- range $name, $persistence := .Values.persistence -}} @@ -19,23 +18,63 @@ {{- include "tc.v1.common.lib.persistence.validation" (dict "rootCtx" $ "objectData" $objectData) -}} {{- include "tc.v1.common.lib.metadata.validation" (dict "objectData" $objectData "caller" "Persistence") -}} - {{/* Only spawn PVC if its enabled and type of "pvc" */}} - {{- if and (eq "pvc" $objectData.type) (not $objectData.existingClaim) -}} + {{/* Only spawn PVC if its enabled and any type of "pvc" */}} + {{- $types := (list "pvc") -}} + {{- if and (mustHas $objectData.type $types) (not $objectData.existingClaim) -}} - {{- $objectName := (printf "%s-%s" $fullname $name) -}} - {{/* Perform validations */}} - {{- include "tc.v1.common.lib.chart.names.validation" (dict "name" $objectName) -}} - - {{/* Set the name of the secret */}} - {{- $_ := set $objectData "name" $objectName -}} + {{/* Set the name of the PVC */}} + {{- $_ := set $objectData "name" (include "tc.v1.common.lib.storage.pvc.name" (dict "rootCtx" $ "objectName" $name "objectData" $objectData)) -}} {{- $_ := set $objectData "shortName" $name -}} + {{- if and $objectData.static $objectData.static.mode (ne $objectData.static.mode "disabled") -}} + {{- $_ := set $objectData "storageClass" ($objectData.storageClass | default $objectData.name) -}} + {{- $_ := set $objectData "volumeName" $objectData.name -}} + + {{- if eq $objectData.static.mode "smb" -}} + {{/* Validate SMB CSI */}} + {{- include "tc.v1.common.lib.storage.smbCSI.validation" (dict "rootCtx" $ "objectData" $objectData) -}} + + {{- $_ := set $objectData "provisioner" "smb.csi.k8s.io" -}} + {{- $_ := set $objectData.static "driver" "smb.csi.k8s.io" -}} + + {{/* Create secret with creds */}} + {{- $secretData := (dict + "name" $objectData.name + "labels" ($objectData.labels | default dict) + "annotations" ($objectData.annotations | default dict) + "data" (dict "username" $objectData.static.username "password" $objectData.static.password) + ) -}} + {{- with $objectData.domain -}} + {{- $_ := set $secretData.data "domain" . -}} + {{- end -}} + {{- include "tc.v1.common.class.secret" (dict "rootCtx" $ "objectData" $secretData) -}} + + {{- else if eq $objectData.static.mode "nfs" -}} + {{/* Validate NFS CSI */}} + {{- include "tc.v1.common.lib.storage.nfsCSI.validation" (dict "rootCtx" $ "objectData" $objectData) -}} + + {{- $_ := set $objectData "provisioner" "nfs.csi.k8s.io" -}} + {{- $_ := set $objectData.static "driver" "nfs.csi.k8s.io" -}} + + {{- else if eq $objectData.static.mode "custom" -}} + + {{- $_ := set $objectData "provisioner" $objectData.static.provisioner -}} + {{- $_ := set $objectData.static "driver" $objectData.static.driver -}} + + {{- end -}} + + {{/* Create the PV */}} + {{- include "tc.v1.common.class.pv" (dict "rootCtx" $ "objectData" $objectData) -}} + + {{- else if $objectData.volumeName -}} + + {{- $_ := set $objectData "storageClass" ($objectData.storageClass | default $objectData.name) -}} + + {{- end -}} + {{/* Call class to create the object */}} {{- include "tc.v1.common.class.pvc" (dict "rootCtx" $ "objectData" $objectData) -}} - {{- end -}} {{- end -}} - {{- end -}} - {{- end -}} diff --git a/library/common/values.yaml b/library/common/values.yaml index aeebe4dc..b4f04063 100644 --- a/library/common/values.yaml +++ b/library/common/values.yaml @@ -222,6 +222,67 @@ persistence: mountPath: /dev/shm medium: Memory targetSelectAll: true +# vct: +# enabled: true +# type: vct +# mountPath: /shared +# dynamic-pvc: +# enabled: true +# type: pvc +# mountPath: /shared +# targetSelectAll: true +# dynamic-pvc-dataSource: +# enabled: true +# type: pvc +# mountPath: /shared +# targetSelectAll: true +# dataSource: +# kind: "PersistentVolumeClaim" +# name: "existingPVC" +# existing-claim: +# enabled: true +# type: pvc +# existingClaim: "someclaim" +# mountPath: /shared +# targetSelectAll: true +# existingpv-pvc: +# enabled: true +# type: pvc +# mountPath: /shared +# targetSelectAll: true +# volumeName: "somePV" +# static-nfs-pvc: +# enabled: true +# type: pvc +# mountPath: /shared +# targetSelectAll: true +# static: +# mode: nfs +# server: "/someserver" +# share: "someshare" +# static-smb-pvc: +# enabled: true +# type: pvc +# mountPath: /shared +# targetSelectAll: true +# static: +# mode: smb +# server: "/someserver" +# share: "someshare" +# domain: "somedomain" +# user: "someuser" +# password: "somepass" +# static-custom-pvc: +# enabled: true +# type: pvc +# mountPath: /shared +# targetSelectAll: true +# static: +# mode: custom +# provisioner: "some.provisioner" +# driver: "somedriver" +# # Custom CSI definition here +# csi: {} persistenceList: [] @@ -255,9 +316,6 @@ serviceAccount: {} # -- (docs/rbac.md) rbac: {} -# -- (docs/volumeClaimTemplates) (StatefulSet only) -volumeClaimTemplates: {} - # -- (docs/scaleExternalInterface.md) scaleExternalInterface: [] @@ -807,10 +865,14 @@ cnpg: primaryUpdateStrategy: unsupervised # -- enable to create extra pgbouncer for readonly access acceptRO: false - # -- storage size for the two pvc's per instance - storage: - size: "256Gi" - walsize: "256Gi" + # # -- storage size for the data pvc's + # # Follows the same spec as .Values.Persistence type=PVC + # storage: + # size: "256Gi" + # # -- storage size for the wal pvc's + # # Follows the same spec as .Values.Persistence type=PVC + # walStorage: + # size: "256Gi" # -- Gets scaled to 0 if hibernation is true pooler: instances: 2