From 19ef55470b1f18d2546ea2dc2283db95565a204b Mon Sep 17 00:00:00 2001 From: Stavros Kois <47820033+stavros-k@users.noreply.github.com> Date: Fri, 8 Dec 2023 15:59:55 +0200 Subject: [PATCH 1/9] test --- library/common/templates/lib/ingress/integrations/_traefik.tpl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/common/templates/lib/ingress/integrations/_traefik.tpl b/library/common/templates/lib/ingress/integrations/_traefik.tpl index e61bddbc..5b0301ca 100644 --- a/library/common/templates/lib/ingress/integrations/_traefik.tpl +++ b/library/common/templates/lib/ingress/integrations/_traefik.tpl @@ -109,6 +109,8 @@ {{- end -}} {{- if not $found -}} + {{- fail (printf "%s\n\n%s" (toYaml $parsedMiddlewares) (toYaml $middlewares)) -}} + {{- fail (printf "Ingress - Middleware [%s] is not defined in any namespace. Create the middleware first." $mid.name) -}} {{- end -}} {{- end -}} From 0ddf444b083ec63cfc84a06d87069b71988da9ad Mon Sep 17 00:00:00 2001 From: Stavros Kois <47820033+stavros-k@users.noreply.github.com> Date: Fri, 8 Dec 2023 16:15:41 +0200 Subject: [PATCH 2/9] Update library/common/templates/lib/ingress/integrations/_traefik.tpl --- library/common/templates/lib/ingress/integrations/_traefik.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/common/templates/lib/ingress/integrations/_traefik.tpl b/library/common/templates/lib/ingress/integrations/_traefik.tpl index 5b0301ca..53f08f48 100644 --- a/library/common/templates/lib/ingress/integrations/_traefik.tpl +++ b/library/common/templates/lib/ingress/integrations/_traefik.tpl @@ -109,7 +109,7 @@ {{- end -}} {{- if not $found -}} - {{- fail (printf "%s\n\n%s" (toYaml $parsedMiddlewares) (toYaml $middlewares)) -}} + {{- fail (printf "Parsed:\n%s\n\nMiddlewares:\n%s" (toYaml $parsedMiddlewares) (toYaml $middlewares)) -}} {{- fail (printf "Ingress - Middleware [%s] is not defined in any namespace. Create the middleware first." $mid.name) -}} {{- end -}} From 65c0d33a2bced425fe65bc001f8ca48bf17101ea Mon Sep 17 00:00:00 2001 From: Stavros Kois <47820033+stavros-k@users.noreply.github.com> Date: Fri, 8 Dec 2023 16:25:59 +0200 Subject: [PATCH 3/9] Update library/common/templates/lib/ingress/integrations/_traefik.tpl --- library/common/templates/lib/ingress/integrations/_traefik.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/common/templates/lib/ingress/integrations/_traefik.tpl b/library/common/templates/lib/ingress/integrations/_traefik.tpl index 53f08f48..d2cf197b 100644 --- a/library/common/templates/lib/ingress/integrations/_traefik.tpl +++ b/library/common/templates/lib/ingress/integrations/_traefik.tpl @@ -109,7 +109,7 @@ {{- end -}} {{- if not $found -}} - {{- fail (printf "Parsed:\n%s\n\nMiddlewares:\n%s" (toYaml $parsedMiddlewares) (toYaml $middlewares)) -}} + {{- fail (printf "Parsed:\n%s\n\nMiddlewares:\n%s\n\nmidName:%s\n\npName:%s\n\nfound:%s" (toYaml $parsedMiddlewares) (toYaml $middlewares) $mid.name $p.name $found) -}} {{- fail (printf "Ingress - Middleware [%s] is not defined in any namespace. Create the middleware first." $mid.name) -}} {{- end -}} From 11005073f5ff9ef18d40aefdc5b8d74221a80abb Mon Sep 17 00:00:00 2001 From: Stavros Kois <47820033+stavros-k@users.noreply.github.com> Date: Fri, 8 Dec 2023 16:36:10 +0200 Subject: [PATCH 4/9] ofc, you dummy --- .../templates/lib/ingress/integrations/_traefik.tpl | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/library/common/templates/lib/ingress/integrations/_traefik.tpl b/library/common/templates/lib/ingress/integrations/_traefik.tpl index d2cf197b..e4f043b5 100644 --- a/library/common/templates/lib/ingress/integrations/_traefik.tpl +++ b/library/common/templates/lib/ingress/integrations/_traefik.tpl @@ -107,12 +107,10 @@ {{- $found = true -}} {{- $midNamespace = $p.namespace -}} {{- end -}} + {{- end -}} - {{- if not $found -}} - {{- fail (printf "Parsed:\n%s\n\nMiddlewares:\n%s\n\nmidName:%s\n\npName:%s\n\nfound:%s" (toYaml $parsedMiddlewares) (toYaml $middlewares) $mid.name $p.name $found) -}} - - {{- fail (printf "Ingress - Middleware [%s] is not defined in any namespace. Create the middleware first." $mid.name) -}} - {{- end -}} + {{- if not $found -}} + {{- fail (printf "Ingress - Middleware [%s] is not defined in any namespace. Create the middleware first." $mid.name) -}} {{- end -}} {{- end -}} From 913fd78ae2984b0bf68a613bca1c91bfba46d133 Mon Sep 17 00:00:00 2001 From: Stavros Kois <47820033+stavros-k@users.noreply.github.com> Date: Fri, 8 Dec 2023 16:44:11 +0200 Subject: [PATCH 5/9] feat(ingress) refactor + tests (#621) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Description** ⚒️ Fixes # Partially solves https://github.com/truecharts/charts/issues/11205 Partially solves https://github.com/truecharts/charts/issues/14160 Partially solves https://github.com/truecharts/charts/issues/8080 Partially solves https://github.com/truecharts/charts/issues/9635 All the above are "partially" because changes need to be performed on the chart it self Eg. Set the targetSelector for the "other" ingress to point to the "other" service **⚙️ Type of change** - [x] ⚙️ Feature/App addition - [x] 🪛 Bugfix - [ ] ⚠️ Breaking change (fix or feature that would cause existing functionality to not work as expected) - [x] 🔃 Refactor of current code **🧪 How Has This Been Tested?** **📃 Notes:** **✔️ Checklist:** - [x] ⚖️ My code follows the style guidelines of this project - [x] 👀 I have performed a self-review of my own code - [x] #️⃣ I have commented my code, particularly in hard-to-understand areas - [ ] 📄 I have made corresponding changes to the documentation - [ ] ⚠️ My changes generate no new warnings - [x] 🧪 I have added tests to this description that prove my fix is effective or that my feature works - [x] ⬆️ I increased versions for any altered app according to semantic versioning **➕ App addition** If this PR is an app addition please make sure you have done the following. - [ ] 🪞 I have opened a PR on [truecharts/containers](https://github.com/truecharts/containers) adding the container to TrueCharts mirror repo. - [ ] 🖼️ I have added an icon in the Chart's root directory called `icon.png` --- _Please don't blindly check all the boxes. Read them and only check those that apply. Those checkboxes are there for the reviewer to see what is this all about and the status of this PR with a quick glance._ --- library/common-test/Chart.yaml | 2 +- library/common-test/ci/ingress-values.yaml | 3 - .../tests/ingress/cert_manager_test.yaml | 115 ++++ .../tests/ingress/homepage_test.yaml | 152 +++++ .../tests/ingress/metadata_test.yaml | 274 ++++---- .../common-test/tests/ingress/name_test.yaml | 67 ++ .../tests/ingress/presence_test.yaml | 93 --- .../common-test/tests/ingress/rules_test.yaml | 199 ++++++ .../tests/ingress/service_reference_test.yaml | 79 --- .../common-test/tests/ingress/tls_test.yaml | 260 +++++--- .../tests/ingress/traefik_test.yaml | 466 ++++++++++++++ .../tests/ingress/validation_test.yaml | 607 ++++++++++++++++++ .../tests/ingress/values_test.yaml | 143 ----- .../tests/service/metadata_test.yaml | 8 +- library/common/Chart.yaml | 2 +- library/common/templates/class/_ingress.tpl | 196 ++---- .../common/templates/class/_priorityClass.tpl | 2 +- .../common/templates/class/cnpg/_cluster.tpl | 2 +- .../common/templates/lib/_tc_capabilities.tpl | 5 - .../lib/container/_securityContext.tpl | 2 +- .../templates/lib/ingress/_targetSelector.tpl | 85 +++ .../templates/lib/ingress/_validation.tpl | 172 ++++- .../lib/ingress/integrations/_certManager.tpl | 29 + .../lib/ingress/integrations/_homepage.tpl | 100 ++- .../lib/ingress/integrations/_traefik.tpl | 115 ++++ .../lib/service/_additionalAnnotations.tpl | 12 +- .../templates/lib/util/_primary_service.tpl | 4 +- library/common/templates/loader/_init.tpl | 2 +- library/common/templates/spawner/_ingress.tpl | 121 ++-- .../templates/spawner/_priorityClass.tpl | 2 +- library/common/templates/spawner/_service.tpl | 2 +- library/common/values.yaml | 155 ++--- 32 files changed, 2626 insertions(+), 850 deletions(-) create mode 100644 library/common-test/tests/ingress/cert_manager_test.yaml create mode 100644 library/common-test/tests/ingress/homepage_test.yaml create mode 100644 library/common-test/tests/ingress/name_test.yaml delete mode 100644 library/common-test/tests/ingress/presence_test.yaml create mode 100644 library/common-test/tests/ingress/rules_test.yaml delete mode 100644 library/common-test/tests/ingress/service_reference_test.yaml create mode 100644 library/common-test/tests/ingress/traefik_test.yaml create mode 100644 library/common-test/tests/ingress/validation_test.yaml delete mode 100644 library/common-test/tests/ingress/values_test.yaml create mode 100644 library/common/templates/lib/ingress/_targetSelector.tpl create mode 100644 library/common/templates/lib/ingress/integrations/_certManager.tpl create mode 100644 library/common/templates/lib/ingress/integrations/_traefik.tpl diff --git a/library/common-test/Chart.yaml b/library/common-test/Chart.yaml index 34a2e909..31dc8d5e 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: ~16.0.0 + version: ~16.1.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/ingress-values.yaml b/library/common-test/ci/ingress-values.yaml index ac6f17ef..2cb68375 100644 --- a/library/common-test/ci/ingress-values.yaml +++ b/library/common-test/ci/ingress-values.yaml @@ -53,9 +53,6 @@ ingress: paths: - path: / pathType: Prefix - service: - name: - port: tls: [] scalecert: diff --git a/library/common-test/tests/ingress/cert_manager_test.yaml b/library/common-test/tests/ingress/cert_manager_test.yaml new file mode 100644 index 00000000..62c8b52f --- /dev/null +++ b/library/common-test/tests/ingress/cert_manager_test.yaml @@ -0,0 +1,115 @@ +suite: ingress - cert manager 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 ingress created with annotations from cert manager + set: + operator: &operator + verify: + enabled: false + service: &service + my-service: + enabled: true + primary: true + ports: + main: + enabled: true + primary: true + port: 80 + ingress: + my-ingress: + enabled: true + primary: true + integrations: + traefik: &traefik + enabled: false + certManager: + enabled: true + certificateIssuer: some-issuer + hosts: &hosts + - host: test-host + paths: + - path: /test-path + asserts: + - documentIndex: &ingressDoc 1 + isKind: + of: Ingress + - documentIndex: *ingressDoc + equal: + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc + equal: + path: metadata.annotations + value: + cert-manager.io/cluster-issuer: some-issuer + cert-manager.io/private-key-rotation-policy: Always + - documentIndex: *ingressDoc + equal: + path: metadata.namespace + value: test-release-namespace + + - it: should pass with ingress created without cert manager annotations when cert manager false + set: + operator: *operator + service: *service + ingress: + my-ingress: + enabled: true + primary: true + integrations: + traefik: *traefik + certManager: + enabled: false + hosts: *hosts + asserts: + - documentIndex: *ingressDoc + isKind: + of: Ingress + - documentIndex: *ingressDoc + equal: + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc + isNull: + path: metadata.annotations + + # Failures + - it: should fail with missing certificateIssuer + set: + operator: *operator + service: *service + ingress: + my-ingress1: + enabled: true + primary: true + integrations: + certManager: + enabled: true + hosts: *hosts + asserts: + - failedTemplate: + errorMessage: Ingress - Expected a non-empty [integrations.certManager.certificateIssuer] + + - it: should fail with certificateIssuer not a string + set: + operator: *operator + service: *service + ingress: + my-ingress1: + enabled: true + primary: true + integrations: + certManager: + enabled: true + certificateIssuer: + - some-issuer + hosts: *hosts + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [integrations.certManager.certificateIssuer] to be a [string], but got [slice] diff --git a/library/common-test/tests/ingress/homepage_test.yaml b/library/common-test/tests/ingress/homepage_test.yaml new file mode 100644 index 00000000..1ad45c69 --- /dev/null +++ b/library/common-test/tests/ingress/homepage_test.yaml @@ -0,0 +1,152 @@ +suite: ingress - homepage 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 ingress created with annotations from homepage enabled + set: + k1: some-name + k2: some-desc + k3: some-icon + k4: some-url + k5: some-type + k6: some-group + operator: &operator + verify: + enabled: false + service: &service + my-service: + enabled: true + primary: true + ports: + main: + enabled: true + primary: true + port: 80 + someHost: test-host + somePath: /test-path + ingress: + my-ingress1: + enabled: true + primary: true + integrations: + traefik: &traefik + enabled: false + homepage: + enabled: true + hosts: + - host: "{{ .Values.someHost }}" + paths: + - path: "{{ .Values.somePath }}" + my-ingress2: + enabled: true + integrations: + traefik: *traefik + homepage: + enabled: true + name: "{{ .Values.k1 }}" + description: "{{ .Values.k2 }}" + icon: "{{ .Values.k3 }}" + group: "{{ .Values.k6 }}" + weight: 1 + podSelector: + - main + - other + widget: + url: "{{ .Values.k4 }}" + type: "{{ .Values.k5 }}" + custom: + some-key: some-value + some-other-key: some-other-value + hosts: &hosts + - host: test-host + paths: + - path: /test-path + asserts: + - documentIndex: &ingressDoc 1 + isKind: + of: Ingress + - documentIndex: *ingressDoc + equal: + path: metadata.annotations + value: + gethomepage.dev/enabled: "true" + gethomepage.dev/name: CommonTest + gethomepage.dev/description: Helper chart to test different use cases of the common library + gethomepage.dev/icon: https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png + gethomepage.dev/widget.type: common-test + gethomepage.dev/widget.url: "https://test-host/test-path" + - documentIndex: *ingressDoc + equal: + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc + equal: + path: metadata.namespace + value: test-release-namespace + - documentIndex: &otherIngressDoc 2 + isKind: + of: Ingress + - documentIndex: *otherIngressDoc + equal: + path: metadata.annotations + value: + gethomepage.dev/enabled: "true" + gethomepage.dev/name: some-name + gethomepage.dev/description: some-desc + gethomepage.dev/group: some-group + gethomepage.dev/icon: some-icon + gethomepage.dev/widget.url: some-url + gethomepage.dev/weight: "1" + gethomepage.dev/widget.type: some-type + gethomepage.dev/pod-selector: pod.name in (main,other) + gethomepage.dev/widget.some-key: some-value + gethomepage.dev/widget.some-other-key: some-other-value + - documentIndex: *otherIngressDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-ingress2 + - documentIndex: *otherIngressDoc + equal: + path: metadata.namespace + value: test-release-namespace + + # Failures + - it: should fail with podSelector not a slice + set: + operator: *operator + service: *service + ingress: + my-ingress1: + enabled: true + primary: true + integrations: + homepage: + enabled: true + podSelector: main + hosts: *hosts + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [integrations.homepage.podSelector] to be a [slice], but got [string] + + - it: should fail with custom widget not a map + set: + operator: *operator + service: *service + ingress: + my-ingress1: + enabled: true + primary: true + integrations: + homepage: + enabled: true + widget: + custom: "not a map" + hosts: *hosts + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [integrations.homepage.widget.custom] to be a [map], but got [string] diff --git a/library/common-test/tests/ingress/metadata_test.yaml b/library/common-test/tests/ingress/metadata_test.yaml index 5c4cfeae..ad3fc5f7 100644 --- a/library/common-test/tests/ingress/metadata_test.yaml +++ b/library/common-test/tests/ingress/metadata_test.yaml @@ -1,4 +1,4 @@ -suite: ingress metadata +suite: ingress metadata test templates: - common.yaml chart: @@ -7,135 +7,66 @@ release: name: test-release-name namespace: test-release-namespace tests: - - it: default metadata should pass + - it: should pass with ingress created with labels and annotations set: - operator: + 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 }}" + operator: &operator verify: enabled: false - ingress.main.enabled: true - service: - main: + service: &service + my-service: enabled: true + primary: true ports: main: enabled: true primary: true - port: 12345 - workload: - my-workload: - enabled: true - primary: true - type: Deployment - podSpec: {} - asserts: - - documentIndex: &ingressDocument 2 - isKind: - of: Ingress - - documentIndex: *ingressDocument - equal: - path: metadata.annotations - value: - traefik.ingress.kubernetes.io/router.entrypoints: websecure - traefik.ingress.kubernetes.io/router.middlewares: tc-system-chain-basic@kubernetescrd - - - documentIndex: *ingressDocument - 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 - - - it: cors metadata should pass - set: - operator: - verify: - enabled: false + port: 80 ingress: - main: - enabled: true - allowCors: true - service: - main: - enabled: true - ports: - main: - enabled: true - primary: true - port: 12345 - workload: - my-workload: + my-ingress1: enabled: true primary: true - type: Deployment - podSpec: {} - asserts: - - documentIndex: &ingressDocument 2 - isKind: - of: Ingress - - documentIndex: *ingressDocument - equal: - path: metadata.annotations - value: - traefik.ingress.kubernetes.io/router.entrypoints: websecure - traefik.ingress.kubernetes.io/router.middlewares: tc-system-tc-opencors-chain@kubernetescrd - - - documentIndex: *ingressDocument - 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 - - - it: custom metadata should pass - set: - operator: - verify: - enabled: false - service: - main: - enabled: true - ports: - main: - enabled: true - primary: true - port: 12345 - workload: - my-workload: - enabled: true - primary: true - type: Deployment - podSpec: {} - ingress: - main: - enabled: true - annotations: - test_annotation: test labels: - test_label: test + label1: "{{ .Values.label1 }}" + label2: label2 + annotations: + annotation1: "{{ .Values.annotation1 }}" + annotation2: annotation2 + integrations: &integrations + traefik: + enabled: false + hosts: &hosts + - host: test-host + paths: + - path: /test-path + my-ingress2: + enabled: true + primary: false + integrations: *integrations + hosts: *hosts asserts: - - documentIndex: &ingressDocument 2 + - documentIndex: &ingressDoc 1 isKind: of: Ingress - - documentIndex: *ingressDocument + - documentIndex: *ingressDoc equal: path: metadata.annotations value: - test_annotation: test - traefik.ingress.kubernetes.io/router.entrypoints: websecure - traefik.ingress.kubernetes.io/router.middlewares: tc-system-chain-basic@kubernetescrd - - documentIndex: *ingressDocument + annotation1: annotation1 + annotation2: annotation2 + g_annotation1: global_annotation1 + g_annotation2: global_annotation2 + - documentIndex: *ingressDoc equal: path: metadata.labels value: @@ -143,8 +74,121 @@ tests: 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 - test_label: test + app.kubernetes.io/instance: test-release-name + app.kubernetes.io/name: common-test + g_label1: global_label1 + g_label2: global_label2 + label1: label1 + label2: label2 + - documentIndex: *ingressDoc + equal: + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc + equal: + path: metadata.namespace + value: test-release-namespace + - documentIndex: &otherIngressDoc 2 + isKind: + of: Ingress + - documentIndex: *otherIngressDoc + equal: + path: metadata.labels + value: + app: common-test-1.0.0 + app.kubernetes.io/instance: test-release-name + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: common-test + app.kubernetes.io/version: *appVer + g_label1: global_label1 + g_label2: global_label2 + helm-revision: "0" + helm.sh/chart: common-test-1.0.0 + release: test-release-name + - documentIndex: *otherIngressDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-ingress2 + - documentIndex: *otherIngressDoc + equal: + path: metadata.namespace + value: test-release-namespace + + - it: should pass with ingress created with object namespace from tpl + set: + key: some-namespace + operator: *operator + service: *service + ingress: + my-ingress1: + enabled: true + primary: true + namespace: "{{ .Values.key }}" + integrations: *integrations + hosts: *hosts + asserts: + - documentIndex: *ingressDoc + equal: + path: metadata.namespace + value: some-namespace + + - it: should pass with ingress created with global namespace from tpl + set: + key: global-namespace + global: + namespace: "{{ .Values.key }}" + operator: *operator + service: *service + ingress: + my-ingress1: + enabled: true + primary: true + integrations: *integrations + hosts: *hosts + asserts: + - documentIndex: *ingressDoc + equal: + path: metadata.namespace + value: global-namespace + + - it: should pass with ingress created with root namespace from tpl + set: + key: local-namespace + namespace: "{{ .Values.key }}" + global: + namespace: global-namespace + operator: *operator + service: *service + ingress: + my-ingress1: + enabled: true + primary: true + integrations: *integrations + hosts: *hosts + asserts: + - documentIndex: *ingressDoc + equal: + path: metadata.namespace + value: local-namespace + + - it: should pass with ingress created with namespace in TrueNAS SCALE + set: + global: + ixChartContext: + iAmNotEmpty: true + namespace: ix-namespace + operator: *operator + service: *service + ingress: + my-ingress1: + enabled: true + primary: true + integrations: *integrations + hosts: *hosts + asserts: + - documentIndex: *ingressDoc + equal: + path: metadata.namespace + value: ix-namespace diff --git a/library/common-test/tests/ingress/name_test.yaml b/library/common-test/tests/ingress/name_test.yaml new file mode 100644 index 00000000..6f36ded8 --- /dev/null +++ b/library/common-test/tests/ingress/name_test.yaml @@ -0,0 +1,67 @@ +suite: ingress name test +templates: + - common.yaml +release: + name: test-release-name + namespace: test-release-namespace +tests: + - it: should generate correct name + set: + operator: + verify: + enabled: false + service: + my-service: + enabled: true + primary: true + ports: + main: + enabled: true + primary: true + port: 80 + ingress: + my-ingress1: + enabled: true + primary: true + hosts: &hosts + - host: test-host + paths: + - path: /test-path + my-ingress2: + enabled: true + hosts: *hosts + my-ingress3: + enabled: true + expandObjectName: false + hosts: *hosts + asserts: + - documentIndex: &ingressDoc 1 + isKind: + of: Ingress + - documentIndex: *ingressDoc + isAPIVersion: + of: networking.k8s.io/v1 + - documentIndex: *ingressDoc + equal: + path: metadata.name + value: test-release-name-common-test + - documentIndex: &otherIngressDoc 2 + isKind: + of: Ingress + - documentIndex: *otherIngressDoc + isAPIVersion: + of: networking.k8s.io/v1 + - documentIndex: *otherIngressDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-ingress2 + - documentIndex: &thirdIngressDoc 3 + isKind: + of: Ingress + - documentIndex: *thirdIngressDoc + isAPIVersion: + of: networking.k8s.io/v1 + - documentIndex: *thirdIngressDoc + equal: + path: metadata.name + value: my-ingress3 diff --git a/library/common-test/tests/ingress/presence_test.yaml b/library/common-test/tests/ingress/presence_test.yaml deleted file mode 100644 index 43328c63..00000000 --- a/library/common-test/tests/ingress/presence_test.yaml +++ /dev/null @@ -1,93 +0,0 @@ -suite: ingress presence -templates: - - common.yaml -release: - name: test-release-name - namespace: test-release-namespace -tests: - - it: default should pass - asserts: - - hasDocuments: - count: 0 - - - - it: explicitly disabled should pass - set: - ingress.main.enabled: false - asserts: - - hasDocuments: - count: 0 - - - it: explicitly enabled should pass - set: - operator: - verify: - enabled: false - ingress.main.enabled: true - service: - main: - enabled: true - ports: - main: - enabled: true - primary: true - port: 12345 - workload: - my-workload: - enabled: true - primary: true - type: Deployment - podSpec: {} - asserts: - - hasDocuments: - count: 3 - - documentIndex: 0 - not: true - isKind: - of: Ingress - - documentIndex: 1 - not: true - isKind: - of: Ingress - - documentIndex: 2 - isKind: - of: Ingress - - - it: multiple enabled should pass - set: - operator: - verify: - enabled: false - ingress.main.enabled: true - ingress.test.enabled: true - service: - main: - enabled: true - ports: - main: - enabled: true - primary: true - port: 12345 - workload: - my-workload: - enabled: true - primary: true - type: Deployment - podSpec: {} - asserts: - - hasDocuments: - count: 4 - - documentIndex: 0 - not: true - isKind: - of: Ingress - - documentIndex: 1 - not: true - isKind: - of: Ingress - - documentIndex: 2 - isKind: - of: Ingress - - documentIndex: 3 - isKind: - of: Ingress diff --git a/library/common-test/tests/ingress/rules_test.yaml b/library/common-test/tests/ingress/rules_test.yaml new file mode 100644 index 00000000..eda68c2e --- /dev/null +++ b/library/common-test/tests/ingress/rules_test.yaml @@ -0,0 +1,199 @@ +suite: ingress - rules test +templates: + - common.yaml +chart: + appVersion: &appVer v9.9.9 +release: + name: test-release-name + namespace: test-release-namespace +tests: + - it: should pass with ingress created with ingressClassName + set: + operator: &operator + verify: + enabled: false + service: + my-service: + enabled: true + primary: true + ports: + main: + enabled: true + primary: true + port: 80 + ingress: + my-ingress: + enabled: true + primary: true + ingressClassName: some-class + hosts: + - host: test-host + paths: + - path: /test-path + integrations: &integrations + traefik: + enabled: false + asserts: + - documentIndex: &ingressDoc 1 + isKind: + of: Ingress + - documentIndex: *ingressDoc + equal: + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc + equal: + path: spec.ingressClassName + value: some-class + + - it: should pass with ingress created with rules + set: + operator: &operator + verify: + enabled: false + service: + my-service: + enabled: true + primary: true + ports: + main: + enabled: true + primary: true + port: 80 + someHost: test-host + somePath: /test-path + someType: Exact + ingress: + my-ingress: + enabled: true + primary: true + hosts: &hosts + - host: "{{ .Values.someHost }}" + paths: + - path: "{{ .Values.somePath }}" + pathType: "{{ .Values.someType }}" + - host: test-other-host + paths: + - path: /test-other-path + - path: /test-other-path2 + overrideService: + name: other-service + port: 8080 + integrations: *integrations + asserts: + - documentIndex: &ingressDoc 1 + isKind: + of: Ingress + - documentIndex: *ingressDoc + equal: + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc + equal: + path: spec.rules + value: + - host: test-host + http: + paths: + - path: /test-path + pathType: Exact + backend: + service: + name: test-release-name-common-test + port: + number: 80 + - host: test-other-host + http: + paths: + - path: /test-other-path + pathType: Prefix + backend: + service: + name: test-release-name-common-test + port: + number: 80 + - path: /test-other-path2 + pathType: Prefix + backend: + service: + name: other-service + port: + number: 8080 + + - it: should pass with ingress created with rules with targetSelector + set: + operator: &operator + verify: + enabled: false + service: + my-service: + enabled: true + primary: true + ports: + main: + enabled: true + primary: true + port: 80 + my-service2: + enabled: true + ports: + my-port2: + enabled: true + port: 9000 + ingress: + my-ingress: + enabled: true + primary: true + targetSelector: + my-service2: my-port2 + hosts: &hosts + - host: test-host + paths: + - path: /test-path + - host: test-other-host + paths: + - path: /test-other-path + - path: /test-other-path2 + overrideService: + name: other-service + port: 8080 + integrations: *integrations + asserts: + - documentIndex: &ingressDoc 2 + isKind: + of: Ingress + - documentIndex: *ingressDoc + equal: + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc + equal: + path: spec.rules + value: + - host: test-host + http: + paths: + - path: /test-path + pathType: Prefix + backend: + service: + name: test-release-name-common-test-my-service2 + port: + number: 9000 + - host: test-other-host + http: + paths: + - path: /test-other-path + pathType: Prefix + backend: + service: + name: test-release-name-common-test-my-service2 + port: + number: 9000 + - path: /test-other-path2 + pathType: Prefix + backend: + service: + name: other-service + port: + number: 8080 diff --git a/library/common-test/tests/ingress/service_reference_test.yaml b/library/common-test/tests/ingress/service_reference_test.yaml deleted file mode 100644 index 0fe2042f..00000000 --- a/library/common-test/tests/ingress/service_reference_test.yaml +++ /dev/null @@ -1,79 +0,0 @@ -suite: ingress service reference -templates: - - common.yaml -release: - name: test-release-name - namespace: test-release-namespace -tests: - - it: default should pass - set: - operator: - verify: - enabled: false - ingress.main.enabled: true - service: - main: - enabled: true - ports: - main: - enabled: true - primary: true - port: 12345 - workload: - my-workload: - enabled: true - primary: true - type: Deployment - podSpec: {} - asserts: - - documentIndex: &ingressDocument 2 - isKind: - of: Ingress - - documentIndex: *ingressDocument - equal: - path: spec.rules[0].http.paths[0].backend.service - value: - name: test-release-name-common-test - port: - number: 12345 - - - - it: custom service reference should pass - set: - operator: - verify: - enabled: false - service: - main: - enabled: true - ports: - main: - enabled: true - primary: true - port: 12345 - workload: - my-workload: - enabled: true - primary: true - type: Deployment - podSpec: {} - ingress.main: - enabled: true - hosts: - - host: chart-test.local - paths: - - path: / - service: - name: pathService - port: 1234 - asserts: - - documentIndex: &ingressDocument 2 - isKind: - of: Ingress - - documentIndex: *ingressDocument - equal: - path: spec.rules[0].http.paths[0].backend.service - value: - name: pathService - port: - number: 1234 diff --git a/library/common-test/tests/ingress/tls_test.yaml b/library/common-test/tests/ingress/tls_test.yaml index d07b8bbc..089ef69f 100644 --- a/library/common-test/tests/ingress/tls_test.yaml +++ b/library/common-test/tests/ingress/tls_test.yaml @@ -1,143 +1,195 @@ -suite: ingress tls +suite: ingress - tls test templates: - common.yaml +chart: + appVersion: &appVer v9.9.9 release: name: test-release-name namespace: test-release-namespace tests: - - it: default should pass + - it: should pass with ingress created with certManager integration set: - operator: + operator: &operator verify: enabled: false - service: - main: + service: &service + my-service: enabled: true + primary: true ports: main: enabled: true primary: true - port: 12345 - workload: - my-workload: + port: 80 + ingress: + my-ingress: enabled: true primary: true - type: Deployment - podSpec: {} - ingress.main.enabled: true + hosts: + - host: test-host + paths: + - path: /test-path + - host: other-test-host + paths: + - path: /other-test-path + integrations: &integrations + traefik: + enabled: false + certManager: + enabled: true + certificateIssuer: some-issuer asserts: - - documentIndex: &ingressDocument 2 + - documentIndex: &ingressDoc 1 isKind: of: Ingress - - documentIndex: *ingressDocument - isNull: + - documentIndex: *ingressDoc + equal: + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc + equal: path: spec.tls + value: + - hosts: + - test-host + secretName: test-release-name-common-test-tls-0 + - hosts: + - other-test-host + secretName: test-release-name-common-test-tls-1 - - it: tls enabled should pass + - it: should pass with ingress created with tls with scaleCert set: - operator: - verify: - enabled: false - service: - main: - enabled: true - ports: - main: - enabled: true - primary: true - port: 12345 - workload: - my-workload: + operator: *operator + service: *service + namespace: ix-test-namespace + global: + ixChartContext: + imNotEmpty: true + ixCertificates: + "1": + certificate: some_cert + privatekey: some_key + "2": + certificate: some_other_cert + privatekey: some_other_key + ingress: + my-ingress: enabled: true primary: true - type: Deployment - podSpec: {} - ingress.main: - enabled: true - tls: - - secretName: test - hosts: - - hostname + hosts: + - host: test-host + paths: + - path: /test-path + - host: other-test-host + paths: + - path: /other-test-path + tls: + - hosts: + - test-host + - other-test-host + scaleCert: "1" + - hosts: + - some-other-test-host + scaleCert: "2" + integrations: &integrations + traefik: + enabled: false asserts: - - documentIndex: &ingressDocument 2 + - documentIndex: &secretDoc 2 + isKind: + of: Secret + - documentIndex: *secretDoc + equal: + path: metadata.name + value: test-release-name-common-test-scale-tls-0 + - documentIndex: *secretDoc + equal: + path: data + value: + tls.crt: c29tZV9jZXJ0 + tls.key: c29tZV9rZXk= + - documentIndex: *secretDoc + equal: + path: type + value: kubernetes.io/tls + - documentIndex: &secretDoc 3 + isKind: + of: Secret + - documentIndex: *secretDoc + equal: + path: metadata.name + value: test-release-name-common-test-scale-tls-1 + - documentIndex: *secretDoc + equal: + path: data + value: + tls.crt: c29tZV9vdGhlcl9jZXJ0 + tls.key: c29tZV9vdGhlcl9rZXk= + - documentIndex: *secretDoc + equal: + path: type + value: kubernetes.io/tls + - documentIndex: &ingressDoc 1 isKind: of: Ingress - - documentIndex: *ingressDocument + - documentIndex: *ingressDoc equal: - path: spec.tls[0] + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc + equal: + path: spec.tls value: - secretName: test - hosts: - - hostname + - hosts: + - test-host + - other-test-host + secretName: test-release-name-common-test-scale-tls-0 + - hosts: + - some-other-test-host + secretName: test-release-name-common-test-scale-tls-1 - - it: tls enabled without secret should pass + - it: should pass with ingress created with tls with certificateIssuer set: - operator: - verify: - enabled: false - service: - main: - enabled: true - ports: - main: - enabled: true - primary: true - port: 12345 - workload: - my-workload: + operator: *operator + service: *service + ingress: + my-ingress: enabled: true primary: true - type: Deployment - podSpec: {} - ingress.main: - enabled: true - tls: - - hosts: - - hostname + hosts: + - host: test-host + paths: + - path: /test-path + - host: other-test-host + paths: + - path: /other-test-path + tls: + - hosts: + - test-host + - other-test-host + certificateIssuer: some-issuer + - hosts: + - some-other-test-host + certificateIssuer: some-other-issuer + integrations: &integrations + traefik: + enabled: false asserts: - - documentIndex: &ingressDocument 2 + - documentIndex: &ingressDoc 1 isKind: of: Ingress - - documentIndex: *ingressDocument + - documentIndex: *ingressDoc equal: - path: spec.tls[0] - value: - hosts: - - hostname - - - it: tls enabled with secret template should pass - set: - operator: - verify: - enabled: false - service: - main: - enabled: true - ports: - main: - enabled: true - primary: true - port: 12345 - workload: - my-workload: - enabled: true - primary: true - type: Deployment - podSpec: {} - ingress.main: - enabled: true - tls: - - secretName: "{{ .Release.Name }}-secret" - hosts: - - hostname - asserts: - - documentIndex: &ingressDocument 2 - isKind: - of: Ingress - - documentIndex: *ingressDocument + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc equal: - path: spec.tls[0] + path: spec.tls value: - secretName: test-release-name-secret - hosts: - - hostname + - hosts: + - test-host + - other-test-host + secretName: test-release-name-common-test-tls-0 + - hosts: + - some-other-test-host + secretName: test-release-name-common-test-tls-1 diff --git a/library/common-test/tests/ingress/traefik_test.yaml b/library/common-test/tests/ingress/traefik_test.yaml new file mode 100644 index 00000000..2eb69a5f --- /dev/null +++ b/library/common-test/tests/ingress/traefik_test.yaml @@ -0,0 +1,466 @@ +suite: ingress - traefik 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 ingress created with annotations from traefik + set: + operator: &operator + verify: + enabled: false + service: &service + my-service: + enabled: true + primary: true + ports: + main: + enabled: true + primary: true + port: 80 + ingress: + my-ingress: + enabled: true + primary: true + hosts: &hosts + - host: test-host + paths: + - path: /test-path + asserts: + - documentIndex: &ingressDoc 1 + isKind: + of: Ingress + - documentIndex: *ingressDoc + equal: + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc + equal: + path: metadata.annotations + value: + traefik.ingress.kubernetes.io/router.entrypoints: websecure + traefik.ingress.kubernetes.io/router.middlewares: chain-basic-tc-system@kubernetescrd + - documentIndex: *ingressDoc + equal: + path: metadata.namespace + value: test-release-namespace + + - it: should pass with ingress created without traefik annotations when traefik false + set: + operator: *operator + service: *service + ingress: + my-ingress: + enabled: true + primary: true + integrations: + traefik: + enabled: false + hosts: *hosts + asserts: + - documentIndex: *ingressDoc + isKind: + of: Ingress + - documentIndex: *ingressDoc + equal: + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc + isNull: + path: metadata.annotations + + - it: should replace local fixedMiddlewares when allowCors true + set: + operator: *operator + service: *service + ingress: + my-ingress: + enabled: true + primary: true + integrations: + traefik: + enabled: true + allowCors: true + fixedMiddlewares: + - some-fixed-middleware + hosts: *hosts + asserts: + - documentIndex: *ingressDoc + isKind: + of: Ingress + - documentIndex: *ingressDoc + equal: + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc + equal: + path: metadata.annotations + value: + traefik.ingress.kubernetes.io/router.entrypoints: websecure + traefik.ingress.kubernetes.io/router.middlewares: tc-opencors-chain-tc-system@kubernetescrd + + - it: should replace global fixedMiddlewares when allowCors true + set: + operator: *operator + service: *service + ingress: + my-ingress: + enabled: true + primary: true + integrations: + traefik: + enabled: true + allowCors: true + hosts: *hosts + asserts: + - documentIndex: *ingressDoc + isKind: + of: Ingress + - documentIndex: *ingressDoc + equal: + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc + equal: + path: metadata.annotations + value: + traefik.ingress.kubernetes.io/router.entrypoints: websecure + traefik.ingress.kubernetes.io/router.middlewares: tc-opencors-chain-tc-system@kubernetescrd + + - it: should replace global fixedMiddlewares when local fixedMiddlewares is defined + set: + operator: *operator + service: *service + ingress: + my-ingress: + enabled: true + primary: true + integrations: + traefik: + enabled: true + fixedMiddlewares: + - some-fixed-middleware + hosts: *hosts + asserts: + - documentIndex: *ingressDoc + isKind: + of: Ingress + - documentIndex: *ingressDoc + equal: + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc + equal: + path: metadata.annotations + value: + traefik.ingress.kubernetes.io/router.entrypoints: websecure + traefik.ingress.kubernetes.io/router.middlewares: some-fixed-middleware-tc-system@kubernetescrd + + - it: should override default entrypoint(s) + set: + operator: *operator + service: *service + ingress: + my-ingress: + enabled: true + primary: true + integrations: + traefik: + enabled: true + entrypoints: + - web + - websecure + hosts: *hosts + asserts: + - documentIndex: *ingressDoc + isKind: + of: Ingress + - documentIndex: *ingressDoc + equal: + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc + equal: + path: metadata.annotations + value: + traefik.ingress.kubernetes.io/router.entrypoints: web,websecure + traefik.ingress.kubernetes.io/router.middlewares: chain-basic-tc-system@kubernetescrd + + - it: should not contain fixed middlewares when global is disabled + set: + operator: *operator + service: *service + global: + traefik: + enableFixedMiddlewares: false + ingress: + my-ingress: + enabled: true + primary: true + integrations: + traefik: + enabled: true + hosts: *hosts + asserts: + - documentIndex: *ingressDoc + isKind: + of: Ingress + - documentIndex: *ingressDoc + equal: + path: metadata.annotations + value: + traefik.ingress.kubernetes.io/router.entrypoints: websecure + + - it: should not contain fixed middlewares when local is disabled + set: + operator: *operator + service: *service + global: + traefik: + enableFixedMiddlewares: true + ingress: + my-ingress: + enabled: true + primary: true + integrations: + traefik: + enabled: true + enableFixedMiddlewares: false + hosts: *hosts + asserts: + - documentIndex: *ingressDoc + isKind: + of: Ingress + - documentIndex: *ingressDoc + equal: + path: metadata.annotations + value: + traefik.ingress.kubernetes.io/router.entrypoints: websecure + + - it: should set correct namespace when operator is registered + set: + operator: + verify: + enabled: false + traefik: + namespace: some-ns + service: *service + ingress: + my-ingress: + enabled: true + primary: true + integrations: + traefik: + enabled: true + entrypoints: + - web + - websecure + hosts: *hosts + asserts: + - documentIndex: *ingressDoc + isKind: + of: Ingress + - documentIndex: *ingressDoc + equal: + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc + equal: + path: metadata.annotations + value: + traefik.ingress.kubernetes.io/router.entrypoints: web,websecure + traefik.ingress.kubernetes.io/router.middlewares: chain-basic-some-ns@kubernetescrd + + - it: should set correct namespace when ingressClassName is defined regardless of operator + set: + operator: + verify: + enabled: false + traefik: + namespace: some-ns + someclass: some-class + service: *service + ingress: + my-ingress: + enabled: true + primary: true + integrations: + traefik: + enabled: true + ingressClassName: "{{ .Values.someclass }}" + hosts: *hosts + asserts: + - documentIndex: *ingressDoc + isKind: + of: Ingress + - documentIndex: *ingressDoc + equal: + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc + equal: + path: metadata.annotations + value: + traefik.ingress.kubernetes.io/router.entrypoints: websecure + traefik.ingress.kubernetes.io/router.middlewares: chain-basic-some-class@kubernetescrd + + - it: should set correct namespace when ingressClassName is defined in SCALE regardless of operator + set: + operator: + verify: + enabled: false + traefik: + namespace: some-ns + service: *service + global: + ixChartContext: + imNotEmpty: true + namespace: ix-namespace + ingress: + my-ingress: + enabled: true + primary: true + integrations: + traefik: + enabled: true + ingressClassName: some-class + hosts: *hosts + asserts: + - documentIndex: *ingressDoc + isKind: + of: Ingress + - documentIndex: *ingressDoc + equal: + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc + equal: + path: metadata.annotations + value: + traefik.ingress.kubernetes.io/router.entrypoints: websecure + traefik.ingress.kubernetes.io/router.middlewares: chain-basic-ix-some-class@kubernetescrd + + - it: should add the defined middlewares to the ingress + set: + operator: *operator + service: *service + ingress: + my-ingress: + enabled: true + primary: true + integrations: + traefik: + enabled: true + middlewares: + - some-middleware + - some-other-middleware + hosts: *hosts + asserts: + - documentIndex: *ingressDoc + isKind: + of: Ingress + - documentIndex: *ingressDoc + isKind: + of: Ingress + - documentIndex: *ingressDoc + equal: + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc + equal: + path: metadata.annotations + value: + traefik.ingress.kubernetes.io/router.entrypoints: websecure + traefik.ingress.kubernetes.io/router.middlewares: chain-basic-tc-system@kubernetescrd,some-middleware-tc-system@kubernetescrd,some-other-middleware-tc-system@kubernetescrd + + # Failures + - it: should fail with entrypoint not a slice + set: + operator: *operator + service: *service + ingress: + my-ingress1: + enabled: true + primary: true + integrations: + traefik: + enabled: true + entrypoints: "not a string" + hosts: *hosts + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [integrations.traefik.entrypoints] to be a [slice], but got [string] + + - it: should fail with middlewares not a slice + set: + operator: *operator + service: *service + ingress: + my-ingress1: + enabled: true + primary: true + integrations: + traefik: + enabled: true + middlewares: "not a slice" + hosts: *hosts + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [integrations.traefik.middlewares] to be a [slice], but got [string] + + - it: should fail with fixedMiddlewares not a slice + set: + operator: *operator + service: *service + ingress: + my-ingress1: + enabled: true + primary: true + integrations: + traefik: + enabled: true + fixedMiddlewares: "not a slice" + hosts: *hosts + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [integrations.traefik.fixedMiddlewares] to be a [slice], but got [string] + + - it: should fail with duplicate middlewares + set: + operator: *operator + service: *service + ingress: + my-ingress1: + enabled: true + primary: true + integrations: + traefik: + enabled: true + middlewares: + - chain-basic + hosts: *hosts + asserts: + - failedTemplate: + errorMessage: Ingress - Combined traefik middlewares contain duplicates [chain-basic, chain-basic] + + - it: should fail with duplicate entrypoints + set: + operator: *operator + service: *service + ingress: + my-ingress1: + enabled: true + primary: true + integrations: + traefik: + enabled: true + entrypoints: + - websecure + - websecure + hosts: *hosts + asserts: + - failedTemplate: + errorMessage: Ingress - Combined traefik entrypoints contain duplicates [websecure, websecure] diff --git a/library/common-test/tests/ingress/validation_test.yaml b/library/common-test/tests/ingress/validation_test.yaml new file mode 100644 index 00000000..bd7dd62c --- /dev/null +++ b/library/common-test/tests/ingress/validation_test.yaml @@ -0,0 +1,607 @@ +suite: ingress validation test +templates: + - common.yaml +release: + name: test-release-name + namespace: test-release-namespace +tests: + - it: should fail if required is true but enabled is false + set: + operator: &operator + verify: + enabled: false + service: &service + my-service: + enabled: true + primary: true + ports: + main: + enabled: true + primary: true + port: 80 + ingress: + my-ingress: + enabled: false + required: true + asserts: + - failedTemplate: + errorMessage: Ingress - Expected ingress [my-ingress] to be enabled. This chart is designed to work only with ingress enabled. + + - it: should fail with name longer than 253 characters + set: + operator: *operator + service: *service + ingress: + my-ing: + enabled: true + primary: true + hosts: &hosts + - host: test-host + paths: + - path: /test-path + my-ingress-super-long-name-that-is-longer-than-253-characters-my-ingress-super-long-name-that-is-longer-than-253-characters-my-ingress-super-long-name-that-is-longer-than-253-characters-my-ingress-super-long-long-long-long-long-long-long-long-name: + enabled: true + asserts: + - failedTemplate: + errorMessage: Name [test-release-name-common-test-my-ingress-super-long-name-that-is-longer-than-253-characters-my-ingress-super-long-name-that-is-longer-than-253-characters-my-ingress-super-long-name-that-is-longer-than-253-characters-my-ingress-super-long-long-long-long-long-long-long-long-name] is not valid. Must start and end with an alphanumeric lowercase character. It can contain '-'. And must be at most 253 characters. + + - it: should fail with name starting with underscore + set: + operator: *operator + service: *service + ingress: + my-ing: + enabled: true + primary: true + hosts: *hosts + _my-ingress: + enabled: true + asserts: + - failedTemplate: + errorMessage: Name [test-release-name-common-test-_my-ingress] is not valid. Must start and end with an alphanumeric lowercase character. It can contain '-'. And must be at most 253 characters. + + - it: should fail with namespace longer than 63 characters + set: + operator: *operator + service: *service + ingress: + my-ingress: + enabled: true + primary: true + hosts: *hosts + namespace: my-extra-super-duper-long-name-that-is-longer-than-63-characters + asserts: + - failedTemplate: + errorMessage: Ingress - Namespace [my-extra-super-duper-long-name-that-is-longer-than-63-characters] is not valid. Must start and end with an alphanumeric lowercase character. It can contain '-'. And must be at most 63 characters. + + - it: should fail with namespace not starting with [ix-] in TrueNAS SCALE + set: + global: + ixChartContext: + iAmNotEmpty: true + operator: *operator + service: + my-service: + enabled: true + primary: true + namespace: ix-namespace + ports: + main: + enabled: true + primary: true + port: 80 + ingress: + my-ingress: + enabled: true + primary: true + hosts: *hosts + namespace: my-namespace + asserts: + - failedTemplate: + errorMessage: Ingress - Namespace [my-namespace] expected to have [ix-] prefix when installed in TrueNAS SCALE + + - it: should fail with labels not a dict + set: + operator: *operator + ingress: + my-ingress: + enabled: true + primary: true + labels: "not a dict" + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [labels] to be a dictionary, but got [string] + + - it: should fail with annotations not a dict + set: + operator: *operator + ingress: + my-ingress: + enabled: true + primary: true + annotations: "not a dict" + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [annotations] to be a dictionary, but got [string] + + - it: should fail with empty enabled + set: + operator: *operator + ingress: + my-ingress: + enabled: + asserts: + - failedTemplate: + errorMessage: Ingress - Expected the defined key [enabled] in [ingress.my-ingress] to not be empty + + - it: should fail with targetSelector not a map + set: + operator: *operator + ingress: + my-ingress: + enabled: true + primary: true + targetSelector: "not a map" + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [targetSelector] to be a [map], but got [string] + + - it: should fail with targetSelector having more than one key + set: + operator: *operator + ingress: + my-ingress: + enabled: true + primary: true + targetSelector: + main: main + other: other + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [targetSelector] to have exactly one key, but got [2] + + - it: should fail with targetSelector key missing value + set: + operator: *operator + ingress: + my-ingress: + enabled: true + primary: true + targetSelector: + main: + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [targetSelector.main] to have a value + + - it: should fail with targetSelector key having non-string value + set: + operator: *operator + ingress: + my-ingress: + enabled: true + primary: true + targetSelector: + main: + - not a string + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [targetSelector.main] to be a [string], but got [slice] + + - it: should fail with no hosts + set: + operator: *operator + ingress: + my-ingress: + enabled: true + primary: true + hosts: [] + asserts: + - failedTemplate: + errorMessage: Ingress - Expected non-empty [hosts] + + - it: should fail with hosts not a slice + set: + operator: *operator + ingress: + my-ingress: + enabled: true + primary: true + hosts: not-a-slice + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [hosts] to be a [slice], but got [string] + + - it: should fail with no hosts.host + set: + operator: *operator + ingress: + my-ingress: + enabled: true + primary: true + hosts: + - paths: + - path: /test-path + asserts: + - failedTemplate: + errorMessage: Ingress - Expected non-empty [hosts.host] + + - it: should fail with host starting with https:// + set: + operator: *operator + ingress: + my-ingress: + enabled: true + primary: true + hosts: + - host: https://test-host + paths: + - path: /test-path + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [hosts.host] to not start with [https://], but got [https://test-host] + + - it: should fail with host starting with http:// + set: + operator: *operator + ingress: + my-ingress: + enabled: true + primary: true + hosts: + - host: http://test-host + paths: + - path: /test-path + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [hosts.host] to not start with [http://], but got [http://test-host] + + - it: should fail with host contain ":" + set: + operator: *operator + ingress: + my-ingress: + enabled: true + primary: true + hosts: + - host: test-host:123 + paths: + - path: /test-path + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [hosts.host] to not contain [:], but got [test-host:123] + + - it: should fail without paths + set: + operator: *operator + ingress: + my-ingress: + enabled: true + primary: true + hosts: + - host: test-host + asserts: + - failedTemplate: + errorMessage: Ingress - Expected non-empty [hosts.paths] + + - it: should fail with paths not a slice + set: + operator: *operator + ingress: + my-ingress: + enabled: true + primary: true + hosts: + - host: test-host + paths: not-a-slice + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [hosts.paths] to be a [slice], but got [string] + + - it: should fail with invalid pathType + set: + operator: *operator + ingress: + my-ingress: + enabled: true + primary: true + hosts: + - host: test-host + paths: + - path: /test-path + pathType: not-a-valid-path-type + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [hosts.paths.pathType] to be one of [Prefix, Exact, ImplementationSpecific], but got [not-a-valid-path-type] + + - it: should fail with path not starting with / (only on pathType Exact and Prefix) + set: + operator: *operator + ingress: + my-ingress: + enabled: true + primary: true + hosts: + - host: test-host + paths: + - path: test-path + pathType: Prefix + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [hosts.paths.path] to start with [/], but got [test-path] + + - it: should fail if name in the overrideService is missing + set: + operator: *operator + ingress: + my-ingress: + enabled: true + primary: true + hosts: + - host: test-host + paths: + - path: /test-path + overrideService: + port: 80 + asserts: + - failedTemplate: + errorMessage: Ingress - Expected non-empty [hosts.paths.overrideService.name] + + - it: should fail if port in the overrideService is missing + set: + operator: *operator + ingress: + my-ingress: + enabled: true + primary: true + hosts: + - host: test-host + paths: + - path: /test-path + overrideService: + name: test-service + asserts: + - failedTemplate: + errorMessage: Ingress - Expected non-empty [hosts.paths.overrideService.port] + + - it: should fail if targeted service does not exist + set: + operator: *operator + ingress: + my-ingress: + enabled: true + primary: true + targetSelector: + my-service: my-port + hosts: + - host: test-host + paths: + - path: /test-path + asserts: + - failedTemplate: + errorMessage: Ingress - Expected targeted service [my-service] to exist + + - it: should fail if targeted service is not enabled + set: + operator: *operator + service: + my-service: + enabled: false + primary: true + ports: + my-port: + enabled: true + primary: true + port: 80 + ingress: + my-ingress: + enabled: true + primary: true + targetSelector: + my-service: my-port + hosts: + - host: test-host + paths: + - path: /test-path + asserts: + - failedTemplate: + errorMessage: Ingress - Expected targeted service [my-service] to be enabled + + - it: should fail without primary service or a targetSelector + set: + operator: *operator + ingress: + my-ingress: + enabled: true + primary: true + hosts: + - host: test-host + paths: + - path: /test-path + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [targetSelector] or a primary service to exist + + - it: should fail if the targeted service does not have the targeted port + set: + operator: *operator + service: + my-service: + enabled: true + primary: true + ports: + my-other-port: + enabled: true + primary: true + port: 80 + ingress: + my-ingress: + enabled: true + primary: true + targetSelector: + my-service: my-port + hosts: + - host: test-host + paths: + - path: /test-path + asserts: + - failedTemplate: + errorMessage: Ingress - Expected targeted service [my-service] to have port [my-port] + + - it: should fail if the targeted service port is not enabled + set: + operator: *operator + service: + my-service: + enabled: true + primary: true + ports: + my-port: + enabled: false + primary: true + port: 80 + my-other-port: + enabled: true + primary: true + port: 80 + ingress: + my-ingress: + enabled: true + primary: true + targetSelector: + my-service: my-port + hosts: + - host: test-host + paths: + - path: /test-path + asserts: + - failedTemplate: + errorMessage: Ingress - Expected targeted service port [my-port] to be enabled + + - it: should fail if tls.hosts are empty + set: + operator: *operator + service: *service + ingress: + my-ingress: + enabled: true + primary: true + hosts: *hosts + tls: + - hosts: [] + asserts: + - failedTemplate: + errorMessage: Ingress - Expected non-empty [tls.hosts] + + - it: should fail if tls.hosts is not a slice + set: + operator: *operator + service: *service + ingress: + my-ingress: + enabled: true + primary: true + hosts: *hosts + tls: + - hosts: not-a-slice + asserts: + - failedTemplate: + errorMessage: Ingress - Expected [tls.hosts] to be a [slice], but got [string] + + - it: should fail if tls.hosts.host is empty + set: + operator: *operator + service: *service + ingress: + my-ingress: + enabled: true + primary: true + hosts: *hosts + tls: + - hosts: + - "" + asserts: + - failedTemplate: + errorMessage: Ingress - Expected non-empty entry in [tls.hosts] + + - it: should fail if tls.hosts.host starts with https:// + set: + operator: *operator + service: *service + ingress: + my-ingress: + enabled: true + primary: true + hosts: *hosts + tls: + - hosts: + - https://test-host + asserts: + - failedTemplate: + errorMessage: Ingress - Expected entry in [tls.hosts] to not start with [https://], but got [https://test-host] + + - it: should fail if tls.hosts.host starts with http:// + set: + operator: *operator + service: *service + ingress: + my-ingress: + enabled: true + primary: true + hosts: *hosts + tls: + - hosts: + - http://test-host + asserts: + - failedTemplate: + errorMessage: Ingress - Expected entry in [tls.hosts] to not start with [http://], but got [http://test-host] + + - it: should fail if tls.hosts.host contains ":" + set: + operator: *operator + service: *service + ingress: + my-ingress: + enabled: true + primary: true + hosts: *hosts + tls: + - hosts: + - test-host:123 + asserts: + - failedTemplate: + errorMessage: Ingress - Expected entry in [tls.hosts] to not contain [:], but got [test-host:123] + + - it: should fail if more than 1 cert option is set under tls + set: + operator: *operator + service: *service + ingress: + my-ingress: + enabled: true + primary: true + hosts: *hosts + tls: + - hosts: + - test-host + secretName: test-secret + scaleCert: "1" + asserts: + - failedTemplate: + errorMessage: Ingress - Expected only one of [scaleCert, secretName] to be set, but got [scaleCert, secretName] + + - it: should fail with scaleCert outside of SCALE + set: + operator: *operator + service: *service + ingress: + my-ingress: + enabled: true + primary: true + hosts: *hosts + tls: + - hosts: + - test-host + scaleCert: "1" + asserts: + - failedTemplate: + errorMessage: Ingress - [tls.scalecert] can only be used in TrueNAS SCALE diff --git a/library/common-test/tests/ingress/values_test.yaml b/library/common-test/tests/ingress/values_test.yaml deleted file mode 100644 index ef06584e..00000000 --- a/library/common-test/tests/ingress/values_test.yaml +++ /dev/null @@ -1,143 +0,0 @@ -suite: ingress values -templates: - - common.yaml -release: - name: test-release-name - namespace: test-release-namespace -tests: - - it: default should pass - set: - operator: - verify: - enabled: false - service: - main: - enabled: true - ports: - main: - enabled: true - primary: true - port: 12345 - workload: - my-workload: - enabled: true - primary: true - type: Deployment - podSpec: {} - ingress.main.enabled: true - asserts: - - documentIndex: &ingressDocument 2 - isKind: - of: Ingress - - documentIndex: *ingressDocument - equal: - path: spec.rules[0].host - value: chart-example.local - - documentIndex: *ingressDocument - equal: - path: spec.rules[0].http.paths[0].path - value: "/" - - - it: custom host and path should pass - set: - operator: - verify: - enabled: false - service: - main: - enabled: true - ports: - main: - enabled: true - primary: true - port: 12345 - workload: - my-workload: - enabled: true - primary: true - type: Deployment - podSpec: {} - ingress.main: - enabled: true - hosts: - - host: chart-test.local - paths: - - path: /test - asserts: - - documentIndex: &ingressDocument 2 - isKind: - of: Ingress - - documentIndex: *ingressDocument - equal: - path: spec.rules[0].host - value: chart-test.local - - documentIndex: *ingressDocument - equal: - path: spec.rules[0].http.paths[0].path - value: "/test" - - - it: host with template should pass - set: - operator: - verify: - enabled: false - service: - main: - enabled: true - ports: - main: - enabled: true - primary: true - port: 12345 - workload: - my-workload: - enabled: true - primary: true - type: Deployment - podSpec: {} - ingress.main: - enabled: true - hosts: - - host: "{{ .Release.Name }}.hostname" - asserts: - - documentIndex: &ingressDocument 2 - isKind: - of: Ingress - - documentIndex: *ingressDocument - equal: - path: spec.rules[0].host - value: test-release-name.hostname - - - it: path with template should pass - set: - operator: - verify: - enabled: false - service: - main: - enabled: true - ports: - main: - enabled: true - primary: true - port: 12345 - workload: - my-workload: - enabled: true - primary: true - type: Deployment - podSpec: {} - ingress.main: - enabled: true - hosts: - - host: chart-test.local - paths: - - path: "/{{ .Release.Name }}.path" - asserts: - - documentIndex: &ingressDocument 2 - isKind: - of: Ingress - - documentIndex: *ingressDocument - equal: - path: spec.rules[0].http.paths[0].path - value: "/test-release-name.path" diff --git a/library/common-test/tests/service/metadata_test.yaml b/library/common-test/tests/service/metadata_test.yaml index b3af6915..681e57c7 100644 --- a/library/common-test/tests/service/metadata_test.yaml +++ b/library/common-test/tests/service/metadata_test.yaml @@ -113,11 +113,13 @@ tests: path: metadata.namespace value: test-release-namespace - - it: should pass with service type LoadBalancer, with https port and addMetalLBAnnotations/Traefik true + - it: should pass with service type LoadBalancer, with https port and metallb.addServiceAnnotations/Traefik true set: global: - addMetalLBAnnotations: true - addTraefikAnnotations: true + metallb: + addServiceAnnotations: true + traefik: + addServiceAnnotations: true proto: https service: my-service1: diff --git a/library/common/Chart.yaml b/library/common/Chart.yaml index c49add2c..377e2622 100644 --- a/library/common/Chart.yaml +++ b/library/common/Chart.yaml @@ -15,4 +15,4 @@ maintainers: name: common sources: null type: library -version: 16.0.0 +version: 16.1.0 diff --git a/library/common/templates/class/_ingress.tpl b/library/common/templates/class/_ingress.tpl index f85fe63b..6e925721 100644 --- a/library/common/templates/class/_ingress.tpl +++ b/library/common/templates/class/_ingress.tpl @@ -1,157 +1,93 @@ -{{/* -This template serves as a blueprint for all Ingress objects that are created -within the common library. +{{/* Ingress Class */}} +{{/* Call this template: +{{ include "tc.v1.common.class.ingress" (dict "rootCtx" $ "objectData" $objectData) }} + +rootCtx: The root context of the chart. +objectData: The object data to be used to render the Ingress. */}} + {{- define "tc.v1.common.class.ingress" -}} - {{- $fullName := include "tc.v1.common.lib.chart.names.fullname" . -}} - {{- $ingressName := $fullName -}} - {{- $values := .Values.ingress -}} - {{- if hasKey . "ObjectValues" -}} - {{- with .ObjectValues.ingress -}} - {{- $values = . -}} - {{- end -}} + {{- $rootCtx := .rootCtx -}} + {{- $objectData := .objectData -}} + + {{- $svcData := (include "tc.v1.common.lib.ingress.targetSelector" (dict "rootCtx" $rootCtx "objectData" $objectData) | fromYaml) -}} + + {{- if not (hasKey $objectData "integrations") -}} + {{- $_ := set $objectData "integrations" dict -}} {{- end -}} - {{- $ingressLabels := $values.labels -}} - {{- $ingressAnnotations := $values.annotations -}} - - {{- $ingressName = $values.name -}} - - {{/* Get the name of the primary service, if any */}} - {{- $primaryServiceName := (include "tc.v1.common.lib.util.service.primary" (dict "services" .Values.service "root" .)) -}} - {{/* Get service values of the primary service, if any */}} - {{- $primaryService := get .Values.service $primaryServiceName -}} - {{- $defaultServiceName := $fullName -}} - - {{- if and (hasKey $primaryService "nameOverride") $primaryService.nameOverride -}} - {{- $defaultServiceName = printf "%v-%v" $defaultServiceName $primaryService.nameOverride -}} - {{- end -}} - {{- $defaultServicePort := get $primaryService.ports (include "tc.v1.common.lib.util.service.ports.primary" (dict "svcValues" $primaryService "svcName" $primaryServiceName )) -}} - - {{- $mddwrNamespace := "tc-system" -}} - {{- if $.Values.operator.traefik -}} - {{- if $.Values.operator.traefik.namespace -}} - {{- $mddwrNamespace = $.Values.operator.traefik.namespace -}} - {{- end -}} + {{- if not (hasKey $objectData "annotations") -}} + {{- $_ := set $objectData "annotations" dict -}} {{- end -}} - {{- if $values.ingressClassName -}} - - {{- if $.Values.global.ixChartContext -}} - {{- $mddwrNamespace = (printf "ix-%s" $values.ingressClassName) -}} - {{- else -}} - {{- $mddwrNamespace = $values.ingressClassName -}} - {{- end -}} - {{- end -}} - - {{- $fixedMiddlewares := "" -}} - {{- if $values.enableFixedMiddlewares -}} - - {{/* If cors is enabled, replace the default fixedMiddleware with the opencors chain */}} - {{- if $values.allowCors -}} - {{- $corsMiddlewares := list "tc-opencors-chain" }} - {{- $_ := set $values "fixedMiddlewares" $corsMiddlewares -}} - {{- end -}} - - {{- range $index, $fixedMiddleware := $values.fixedMiddlewares -}} - {{- if $index -}} - {{- $fixedMiddlewares = ( printf "%v, %v-%v@%v" $fixedMiddlewares $mddwrNamespace $fixedMiddleware "kubernetescrd" ) -}} - {{- else -}} - {{- $fixedMiddlewares = ( printf "%v-%v@%v" $mddwrNamespace $fixedMiddleware "kubernetescrd" ) -}} - {{- end -}} - {{- end -}} - {{- end -}} - - {{- $middlewares := "" -}} - {{- range $index, $middleware := $values.middlewares -}} - {{- if $index -}} - {{- $middlewares = ( printf "%v, %v-%v@%v" $middlewares $mddwrNamespace $middleware "kubernetescrd" ) -}} - {{- else -}} - {{- $middlewares = ( printf "%v-%v@%v" $mddwrNamespace $middleware "kubernetescrd" ) -}} - {{- end -}} - {{ end }} - - {{- if and ( $fixedMiddlewares ) ( $middlewares ) -}} - {{- $middlewares = ( printf "%v, %v" $fixedMiddlewares $middlewares ) -}} - {{- else if $fixedMiddlewares -}} - {{- $middlewares = ( printf "%s" $fixedMiddlewares ) -}} - {{- end }} + {{- include "tc.v1.common.lib.ingress.integration.certManager" (dict "rootCtx" $rootCtx "objectData" $objectData) -}} + {{- include "tc.v1.common.lib.ingress.integration.traefik" (dict "rootCtx" $rootCtx "objectData" $objectData) -}} + {{- include "tc.v1.common.lib.ingress.integration.homepage" (dict "rootCtx" $rootCtx "objectData" $objectData) }} --- -apiVersion: {{ include "tc.v1.common.capabilities.ingress.apiVersion" $ }} +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: - name: {{ $ingressName }} - namespace: {{ $.Values.namespace | default $.Values.global.namespace | default $.Release.Namespace }} - {{- $labels := (mustMerge ($ingressLabels | default dict) (include "tc.v1.common.lib.metadata.allLabels" $ | fromYaml)) -}} - {{- with (include "tc.v1.common.lib.metadata.render" (dict "rootCtx" $ "labels" $labels) | trim) }} + name: {{ $objectData.name }} + namespace: {{ include "tc.v1.common.lib.metadata.namespace" (dict "rootCtx" $rootCtx "objectData" $objectData "caller" "Ingress") }} + {{- $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 ($ingressAnnotations | default dict) (include "tc.v1.common.lib.metadata.allAnnotations" $ | fromYaml) (include "tc.v1.common.lib.ingress.integration.homepage" (dict "objectData" $values "rootCtx" $) | fromYaml)) }} + {{- $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: - {{- with $values.certificateIssuer }} - cert-manager.io/cluster-issuer: {{ tpl ( toYaml . ) $ }} - cert-manager.io/private-key-rotation-policy: Always - {{- end }} - "traefik.ingress.kubernetes.io/router.entrypoints": {{ $values.entrypoint | default "websecure" }} - "traefik.ingress.kubernetes.io/router.middlewares": {{ $middlewares | quote }} - {{- with (include "tc.v1.common.lib.metadata.render" (dict "rootCtx" $ "annotations" $annotations) | trim) }} {{- . | nindent 4 }} {{- end }} spec: - {{- if $values.ingressClassName }} - ingressClassName: {{ $values.ingressClassName }} - {{- end -}} - {{- if $values.certificateIssuer }} - tls: - {{- range $index, $hostsValues := $values.hosts }} - - hosts: - - {{ tpl $hostsValues.host $ | quote }} - secretName: {{ ( printf "%v-%v-%v" $ingressName "tls" $index ) }} - {{- end -}} - {{- else if $values.tls }} - tls: - {{- range $index, $tlsValues := $values.tls }} - {{- $tlsName := ( printf "%v-%v" "tls" $index ) }} - - hosts: - {{- range $tlsValues.hosts }} - - {{ tpl . $ | quote }} - {{- end -}} - {{- if $tlsValues.certificateIssuer }} - secretName: {{ printf "%v-%v" $ingressName $tlsName }} - {{- else if and ($tlsValues.scaleCert) ($.Values.global.ixChartContext) -}} - {{- $cert := dict }} - {{- $_ := set $cert "id" $tlsValues.scaleCert }} - {{- $_ := set $cert "nameOverride" $tlsName }} - secretName: {{ printf "%s-tls-%v" (include "tc.v1.common.lib.chart.names.fullname" $) $index }} - {{- else if .clusterCertificate }} - secretName: clusterissuer-templated-{{ tpl .clusterCertificate $ }} - {{- else if .secretName }} - secretName: {{ tpl .secretName $ | quote }} - {{- end -}} - {{- end -}} + {{- if $objectData.ingressClassName }} + ingressClassName: {{ tpl $objectData.ingressClassName $rootCtx }} {{- end }} rules: - {{- range $values.hosts }} - - host: {{ tpl .host $ | quote }} + {{- range $h := $objectData.hosts }} + - host: {{ tpl $h.host $rootCtx }} http: paths: - {{- range .paths -}} - {{- $service := $defaultServiceName -}} - {{- $port := $defaultServicePort.port -}} - {{- if .service -}} - {{- $service = default $service .service.name -}} - {{- $port = default $port .service.port -}} + {{- range $p := $h.paths -}} + {{- with $p.overrideService -}} + {{- $svcData = (dict "name" .name "port" .port) -}} {{- end }} - - path: {{ tpl .path $ | quote }} - pathType: {{ default "Prefix" .pathType }} + - path: {{ tpl $p.path $rootCtx }} + pathType: {{ tpl ($p.pathType | default "Prefix") $rootCtx }} backend: service: - name: {{ $service }} + name: {{ $svcData.name }} port: - number: {{ $port }} + number: {{ $svcData.port }} {{- end -}} + {{- end -}} + {{/* If a certificateIssuer is defined in the whole ingress, use that */}} + {{- if and $objectData.integrations.certManager $objectData.integrations.certManager.enabled }} + tls: + {{- range $idx, $h := $objectData.hosts }} + - secretName: {{ printf "%s-tls-%d" $objectData.name ($idx | int) }} + hosts: + - {{ tpl $h.host $rootCtx }} + {{- end -}} + {{/* else if a tls section is defined use the configuration from there */}} + {{- else if $objectData.tls }} + tls: + {{- range $idx, $t := $objectData.tls -}} + {{- $secretName := "" -}} + {{- if $t.secretName -}} + {{- $secretName = tpl $t.secretName $rootCtx -}} + {{- else if $t.scaleCert -}} + {{- $secretName = printf "%s-scale-tls-%d" $objectData.name ($idx | int) -}} + {{- else if $t.certificateIssuer -}} + {{- $secretName = printf "%s-tls-%d" $objectData.name ($idx | int) -}} + {{- else if $t.clusterCertificate -}} + {{/* TODO: Needs the refactor of Certificate object */}} + {{- end }} + - secretName: {{ $secretName }} + hosts: + {{- range $h := $t.hosts }} + - {{ tpl $h $rootCtx }} + {{- end -}} + {{- end -}} {{- end -}} - - {{- end -}} diff --git a/library/common/templates/class/_priorityClass.tpl b/library/common/templates/class/_priorityClass.tpl index 4789f9b8..3b4b8450 100644 --- a/library/common/templates/class/_priorityClass.tpl +++ b/library/common/templates/class/_priorityClass.tpl @@ -22,7 +22,7 @@ apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: {{ $objectData.name }} - namespace: {{ include "tc.v1.common.lib.metadata.namespace" (dict "rootCtx" $rootCtx "objectData" $objectData "caller" "priorityclass") }} + namespace: {{ include "tc.v1.common.lib.metadata.namespace" (dict "rootCtx" $rootCtx "objectData" $objectData "caller" "Priority Class") }} {{- $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: diff --git a/library/common/templates/class/cnpg/_cluster.tpl b/library/common/templates/class/cnpg/_cluster.tpl index 7be41c44..a0bf8834 100644 --- a/library/common/templates/class/cnpg/_cluster.tpl +++ b/library/common/templates/class/cnpg/_cluster.tpl @@ -158,7 +158,7 @@ spec: {{- end -}} {{- with $preloadLibraries }} shared_preload_libraries: - {{- range $lib := (. | uniq) }} + {{- range $lib := (. | mustUniq) }} - {{ $lib | quote }} {{- end -}} {{- end -}} diff --git a/library/common/templates/lib/_tc_capabilities.tpl b/library/common/templates/lib/_tc_capabilities.tpl index e4187638..4d911dd8 100644 --- a/library/common/templates/lib/_tc_capabilities.tpl +++ b/library/common/templates/lib/_tc_capabilities.tpl @@ -13,11 +13,6 @@ {{- print "monitoring.coreos.com/v1" -}} {{- end -}} -{{/* Return the appropriate apiVersion for Ingress */}} -{{- define "tc.v1.common.capabilities.ingress.apiVersion" -}} - {{- print "networking.k8s.io/v1" -}} -{{- end -}} - {{/* Return the appropriate apiVersion for NetworkPolicy*/}} {{- define "tc.v1.common.capabilities.networkpolicy.apiVersion" -}} {{- print "networking.k8s.io/v1" -}} diff --git a/library/common/templates/lib/container/_securityContext.tpl b/library/common/templates/lib/container/_securityContext.tpl index 4736a2f5..3552a2f8 100644 --- a/library/common/templates/lib/container/_securityContext.tpl +++ b/library/common/templates/lib/container/_securityContext.tpl @@ -172,7 +172,7 @@ objectData: The object data to be used to render the container. {{- end -}} {{- end -}} - {{- if not (deepEqual (uniq $item) $item) -}} + {{- if not (deepEqual (mustUniq $item) $item) -}} {{- fail (printf "Container - Expected items of [securityContext.capabilities.%s] to be unique, but got [%s]" $key (join ", " $item)) -}} {{- end -}} {{- end -}} diff --git a/library/common/templates/lib/ingress/_targetSelector.tpl b/library/common/templates/lib/ingress/_targetSelector.tpl new file mode 100644 index 00000000..17115631 --- /dev/null +++ b/library/common/templates/lib/ingress/_targetSelector.tpl @@ -0,0 +1,85 @@ +{{/* Returns the selected service or fallback to primary */}} +{{- define "tc.v1.common.lib.ingress.targetSelector" -}} + {{- $rootCtx := .rootCtx -}} + {{- $objectData := .objectData -}} + + {{- $selectedService := (dict "name" "" "port" 0) -}} + {{- $svcData := dict -}} + {{- $portData := dict -}} + {{- $svcName := "" -}} + {{- $portName := "" -}} + + {{- if $objectData.targetSelector -}} + {{/* We have validation that only 1 key is allowed */}} + {{- $svcName = ($objectData.targetSelector | keys | mustFirst) -}} + {{- $portName = (get $objectData.targetSelector $svcName) -}} + {{- $svcData = (get $rootCtx.Values.service $svcName) -}} + + {{- if not $svcData -}} + {{- fail (printf "Ingress - Expected targeted service [%s] to exist" $svcName) -}} + {{- end -}} + + {{- $enabled := (include "tc.v1.common.lib.util.enabled" (dict + "rootCtx" $rootCtx "objectData" $svcData + "name" $svcName "caller" "Ingress" + "key" "ingress")) -}} + + {{- if ne $enabled "true" -}} + {{- fail (printf "Ingress - Expected targeted service [%s] to be enabled" $svcName) -}} + {{- end -}} + + {{- else -}} + {{/* Find the primary service */}} + {{- range $name, $service := $rootCtx.Values.service -}} + + {{- $enabled := (include "tc.v1.common.lib.util.enabled" (dict + "rootCtx" $rootCtx "objectData" $service + "name" $name "caller" "Ingress" + "key" "ingress")) -}} + + {{/* Check if its enabled */}} + {{- if eq $enabled "true" -}} + + {{- if $service.primary -}} + {{- $svcName = $name -}} + {{- $svcData = $service -}} + + {{/* Find the primary port */}} + {{- range $name, $port := $svcData.ports -}} + {{- if $port.primary -}} + {{- $portName = $name -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- if not $svcData -}} + {{- fail "Ingress - Expected [targetSelector] or a primary service to exist" -}} + {{- end -}} + + {{- end -}} + + {{- $portData = (get $svcData.ports $portName) -}} + {{- if not $portData -}} + {{- fail (printf "Ingress - Expected targeted service [%s] to have port [%s]" $svcName $portName) -}} + {{- end -}} + + {{- $enabled := (include "tc.v1.common.lib.util.enabled" (dict + "rootCtx" $rootCtx "objectData" $portData + "name" $portName "caller" "Ingress" + "key" "ingress")) -}} + + {{- if ne $enabled "true" -}} + {{- fail (printf "Ingress - Expected targeted service port [%s] to be enabled" $portName) -}} + {{- end -}} + + {{- $expandedSvcName := include "tc.v1.common.lib.chart.names.fullname" $rootCtx -}} + {{- if not $svcData.primary -}} + {{- $expandedSvcName = printf "%s-%s" $expandedSvcName $svcName -}} + {{- end -}} + + {{- $selectedService = (dict "name" $expandedSvcName "port" (tpl ($portData.port | toString) $rootCtx)) -}} + + {{- $selectedService | toYaml -}} +{{- end -}} diff --git a/library/common/templates/lib/ingress/_validation.tpl b/library/common/templates/lib/ingress/_validation.tpl index a63bc583..216ef5e9 100644 --- a/library/common/templates/lib/ingress/_validation.tpl +++ b/library/common/templates/lib/ingress/_validation.tpl @@ -1,14 +1,182 @@ {{/* Ingress Validation */}} {{/* Call this template: -{{ include "tc.v1.common.lib.ingress.validation" (dict "objectData" $objectData) -}} +{{ include "tc.v1.common.lib.ingress.validation" (dict "rootCtx" $ "objectData" $objectData) -}} objectData: rootCtx: The root context of the chart. - objectData: The ingress object. + objectData: The Ingress object. */}} {{- define "tc.v1.common.lib.ingress.validation" -}} {{- $rootCtx := .rootCtx -}} {{- $objectData := .objectData -}} + {{- if $objectData.targetSelector -}} + {{- if not (kindIs "map" $objectData.targetSelector) -}} + {{- fail (printf "Ingress - Expected [targetSelector] to be a [map], but got [%s]" (kindOf $objectData.targetSelector)) -}} + {{- end -}} + + {{- $selectors := $objectData.targetSelector | keys | len -}} + {{- if (gt $selectors 1) -}} + {{ fail (printf "Ingress - Expected [targetSelector] to have exactly one key, but got [%d]" $selectors) -}} + {{- end -}} + + {{- range $k, $v := $objectData.targetSelector -}} + {{- if not $v -}} + {{- fail (printf "Ingress - Expected [targetSelector.%s] to have a value" $k) -}} + {{- end -}} + + {{- if not (kindIs "string" $v) -}} + {{- fail (printf "Ingress - Expected [targetSelector.%s] to be a [string], but got [%s]" $k (kindOf $v)) -}} + {{- end -}} + {{- end -}} + {{- end -}} + + {{- if not $objectData.hosts -}} + {{- fail "Ingress - Expected non-empty [hosts]" -}} + {{- end -}} + + {{- if not (kindIs "slice" $objectData.hosts) -}} + {{- fail (printf "Ingress - Expected [hosts] to be a [slice], but got [%s]" (kindOf $objectData.hosts)) -}} + {{- end -}} + + {{- range $h := $objectData.hosts -}} + {{- if not $h.host -}} + {{- fail "Ingress - Expected non-empty [hosts.host]" -}} + {{- end -}} + + {{- $host := tpl $h.host $rootCtx -}} + {{- if (hasPrefix "http://" $host) -}} + {{- fail (printf "Ingress - Expected [hosts.host] to not start with [http://], but got [%s]" $host) -}} + {{- end -}} + {{- if (hasPrefix "https://" $host) -}} + {{- fail (printf "Ingress - Expected [hosts.host] to not start with [https://], but got [%s]" $host) -}} + {{- end -}} + {{- if (contains ":" $host) -}} + {{- fail (printf "Ingress - Expected [hosts.host] to not contain [:], but got [%s]" $host) -}} + {{- end -}} + + {{- if not $h.paths -}} + {{- fail "Ingress - Expected non-empty [hosts.paths]" -}} + {{- end -}} + + {{- if not (kindIs "slice" $h.paths) -}} + {{- fail (printf "Ingress - Expected [hosts.paths] to be a [slice], but got [%s]" (kindOf $h.paths)) -}} + {{- end -}} + + {{- range $p := $h.paths -}} + {{- $pathType := "Prefix" -}} + {{- if $p.pathType -}} + {{- $pathType = tpl $p.pathType $rootCtx -}} + {{- end -}} + + {{- $validPathTypes := (list "Prefix" "Exact" "ImplementationSpecific") -}} + {{- if not (mustHas $pathType $validPathTypes) -}} + {{- fail (printf "Ingress - Expected [hosts.paths.pathType] to be one of [%s], but got [%s]" (join ", " $validPathTypes) $pathType) -}} + {{- end -}} + + {{- $path := tpl $p.path $rootCtx -}} + {{- $prefixSlashTypes := (list "Prefix" "Exact") -}} + {{- if (mustHas $pathType $prefixSlashTypes) -}} + {{- if not (hasPrefix "/" $path) -}} + {{- fail (printf "Ingress - Expected [hosts.paths.path] to start with [/], but got [%s]" $path) -}} + {{- end -}} + {{- end -}} + + {{/* If at least one thing in overrideService is defined... */}} + {{- with $p.overrideService -}} + {{- if not .name -}} + {{- fail "Ingress - Expected non-empty [hosts.paths.overrideService.name]" -}} + {{- end -}} + {{- if not .port -}} + {{- fail "Ingress - Expected non-empty [hosts.paths.overrideService.port]" -}} + {{- end -}} + {{- end -}} + + {{- end -}} + {{- end -}} + + {{- range $t := $objectData.tls -}} + {{- if not $t.hosts -}} + {{- fail "Ingress - Expected non-empty [tls.hosts]" -}} + {{- end -}} + + {{- if not (kindIs "slice" $t.hosts) -}} + {{- fail (printf "Ingress - Expected [tls.hosts] to be a [slice], but got [%s]" (kindOf $t.hosts)) -}} + {{- end -}} + + {{- range $h := $t.hosts -}} + {{- if not $h -}} + {{- fail "Ingress - Expected non-empty entry in [tls.hosts]" -}} + {{- end -}} + + {{- $host := tpl $h $rootCtx -}} + {{- if (hasPrefix "http://" $host) -}} + {{- fail (printf "Ingress - Expected entry in [tls.hosts] to not start with [http://], but got [%s]" $host) -}} + {{- end -}} + {{- if (hasPrefix "https://" $host) -}} + {{- fail (printf "Ingress - Expected entry in [tls.hosts] to not start with [https://], but got [%s]" $host) -}} + {{- end -}} + {{- if (contains ":" $host) -}} + {{- fail (printf "Ingress - Expected entry in [tls.hosts] to not contain [:], but got [%s]" $host) -}} + {{- end -}} + {{- end -}} + + {{/* TODO: Add the rest of the options?! */}} + {{- $certOptions := (list "scaleCert" "secretName") -}} + {{- $optsSet := list -}} + {{- range $opt := $certOptions -}} + {{- if (get $t $opt) -}} + {{- $optsSet = mustAppend $optsSet $opt -}} + {{- end -}} + {{- end -}} + + {{- if gt ($optsSet | len) 1 -}} + {{- fail (printf "Ingress - Expected only one of [%s] to be set, but got [%s]" (join ", " $certOptions) (join ", " $optsSet)) -}} + {{- end -}} + + {{- end -}} + +{{- end -}} + +{{/* Ingress Primary Validation */}} +{{/* Call this template: +{{ include "tc.v1.common.lib.ingress.primaryValidation" $ -}} +*/}} + +{{- define "tc.v1.common.lib.ingress.primaryValidation" -}} + + {{/* Initialize values */}} + {{- $hasPrimary := false -}} + {{- $hasEnabled := false -}} + + {{- range $name, $ingress := $.Values.ingress -}} + + {{- $enabled := (include "tc.v1.common.lib.util.enabled" (dict + "rootCtx" $ "objectData" $ingress + "name" $name "caller" "Ingress" + "key" "ingress")) -}} + + {{/* If ingress is enabled */}} + {{- if eq $enabled "true" -}} + {{- $hasEnabled = true -}} + + {{/* And ingress is primary */}} + {{- if and (hasKey $ingress "primary") ($ingress.primary) -}} + {{/* Fail if there is already a primary ingress */}} + {{- if $hasPrimary -}} + {{- fail "Ingress - Only one ingress can be primary" -}} + {{- end -}} + + {{- $hasPrimary = true -}} + + {{- end -}} + + {{- end -}} + {{- end -}} + + {{/* Require at least one primary ingress, if any enabled */}} + {{- if and $hasEnabled (not $hasPrimary) -}} + {{- fail "Ingress - At least one enabled ingress must be primary" -}} + {{- end -}} {{- end -}} diff --git a/library/common/templates/lib/ingress/integrations/_certManager.tpl b/library/common/templates/lib/ingress/integrations/_certManager.tpl new file mode 100644 index 00000000..2df0cdbf --- /dev/null +++ b/library/common/templates/lib/ingress/integrations/_certManager.tpl @@ -0,0 +1,29 @@ +{{- define "tc.v1.common.lib.ingress.integration.certManager" -}} + {{- $objectData := .objectData -}} + {{- $rootCtx := .rootCtx -}} + + {{- $certManager := $objectData.integrations.certManager -}} + + {{- if $certManager.enabled -}} + {{- include "tc.v1.common.lib.ingress.integration.certManager.validate" (dict "objectData" $objectData) -}} + + {{- $_ := set $objectData.annotations "cert-manager.io/cluster-issuer" $certManager.certificateIssuer -}} + {{- $_ := set $objectData.annotations "cert-manager.io/private-key-rotation-policy" "Always" -}} + + {{- end -}} +{{- end -}} + +{{- define "tc.v1.common.lib.ingress.integration.certManager.validate" -}} + {{- $objectData := .objectData -}} + + {{- $certManager := $objectData.integrations.certManager -}} + + {{- if not $certManager.certificateIssuer -}} + {{- fail "Ingress - Expected a non-empty [integrations.certManager.certificateIssuer]" -}} + {{- end -}} + + {{- if not (kindIs "string" $certManager.certificateIssuer) -}} + {{- fail (printf "Ingress - Expected [integrations.certManager.certificateIssuer] to be a [string], but got [%s]" (kindOf $certManager.certificateIssuer)) -}} + {{- end -}} + +{{- end -}} diff --git a/library/common/templates/lib/ingress/integrations/_homepage.tpl b/library/common/templates/lib/ingress/integrations/_homepage.tpl index 73692bb5..94863efb 100644 --- a/library/common/templates/lib/ingress/integrations/_homepage.tpl +++ b/library/common/templates/lib/ingress/integrations/_homepage.tpl @@ -1,35 +1,75 @@ -{{/* Ingress Homepage Integration */}} -{{/* Call this template: -{{ include "tc.v1.common.lib.ingress.integration.homepage" (dict "rootCtx" $rootCtx "objectData" $objectData) -}} -objectData: - rootCtx: The root context of the chart. - objectData: The ingress object. -*/}} - {{- define "tc.v1.common.lib.ingress.integration.homepage" -}} + {{- $objectData := .objectData -}} {{- $rootCtx := .rootCtx -}} + + {{- $homepage := $objectData.integrations.homepage -}} + {{- if and $homepage $homepage.enabled -}} + {{- if not (hasKey $homepage "widget") -}} + {{- $_ := set $objectData.integrations.homepage "widget" dict -}} + {{- end -}} + + {{- include "tc.v1.common.lib.ingress.integration.homepage.validation" (dict "objectData" $objectData) -}} + + {{- $name := $homepage.name | default ($rootCtx.Chart.Name | camelcase) -}} + {{- $desc := $homepage.description | default $rootCtx.Chart.Description -}} + {{- $icon := $homepage.icon | default $rootCtx.Chart.Icon -}} + {{- $type := $homepage.widget.type | default $rootCtx.Chart.Name -}} + {{- $url := $homepage.widget.url -}} + + {{- if not $url -}} + {{- $fHost := $objectData.hosts | mustFirst -}} + {{- $fPath := $fHost.paths | mustFirst -}} + {{- $host := tpl $fHost.host $rootCtx -}} + {{- $path := tpl $fPath.path $rootCtx -}} + + {{- $url = printf "https://%s/%s" $host ($path | trimPrefix "/") -}} + {{- end -}} + + {{- $_ := set $objectData.annotations "gethomepage.dev/enabled" "true" -}} + {{- $_ := set $objectData.annotations "gethomepage.dev/name" (tpl $name $rootCtx) -}} + {{- $_ := set $objectData.annotations "gethomepage.dev/description" (tpl $desc $rootCtx) -}} + {{- $_ := set $objectData.annotations "gethomepage.dev/icon" (tpl $icon $rootCtx) -}} + {{- $_ := set $objectData.annotations "gethomepage.dev/widget.type" (tpl $type $rootCtx) -}} + {{- with $homepage.group -}} + {{- $_ := set $objectData.annotations "gethomepage.dev/group" (tpl . $rootCtx) -}} + {{- end -}} + + {{- with $homepage.weight -}} + {{- $_ := set $objectData.annotations "gethomepage.dev/weight" (. | toString) -}} + {{- end -}} + + {{- with $url -}} + {{- $_ := set $objectData.annotations "gethomepage.dev/widget.url" (tpl $url $rootCtx) -}} + {{- end -}} + + {{- if $homepage.widget.custom -}} + {{- range $k, $v := $homepage.widget.custom -}} + {{- $_ := set $objectData.annotations (printf "gethomepage.dev/widget.%s" $k) (tpl $v $rootCtx | toString) -}} + {{- end -}} + {{- end -}} + + {{- with $homepage.podSelector -}} + {{- $selector := (printf "pod.name in (%s)" (join "," .)) -}} + {{- $_ := set $objectData.annotations "gethomepage.dev/pod-selector" $selector -}} + {{- end -}} + + {{- end -}} +{{- end -}} + +{{- define "tc.v1.common.lib.ingress.integration.homepage.validation" -}} {{- $objectData := .objectData -}} -{{- if and $objectData.integration $objectData.integration.homepage $objectData.integration.homepage.enabled -}} -gethomepage.dev/enabled: "true" -gethomepage.dev/name: {{ $objectData.integration.homepage.name | default ( camelcase $rootCtx.Chart.Name ) }} -gethomepage.dev/description: {{ $objectData.integration.homepage.description | default $rootCtx.Chart.Description }} -gethomepage.dev/group: {{ $objectData.integration.homepage.group | default "default" }} -gethomepage.dev/icon: {{ $objectData.integration.homepage.icon | default $rootCtx.Chart.Icon }} -{{- if $objectData.integration.homepage.podSelector -}} -gethomepage.dev/pod-selector: {{ . }} -{{- else -}} -gethomepage.dev/pod-selector: "" -{{- end -}} -{{- with $objectData.integration.homepage.weight -}} -gethomepage.dev/weight: {{ . }} -{{- end -}} -gethomepage.dev/widget.type: {{ $objectData.integration.homepage.widget.type | default $rootCtx.Chart.Name }} -{{- with (index $objectData.hosts 0) -}} -gethomepage.dev/widget.url: {{ $objectData.integration.homepage.widget.url | default (printf "%v%v" .host ( .path | default "/")) }} -{{- end -}} -{{- range $objectData.integration.homepage.widget.custom -}} -gethomepage.dev/widget.{{ .name }}: {{ .value }} -{{- end -}} -{{- end -}} + {{- $homepage := $objectData.integrations.homepage -}} + + {{- with $homepage.podSelector -}} + {{- if not (kindIs "slice" .) -}} + {{- fail (printf "Ingress - Expected [integrations.homepage.podSelector] to be a [slice], but got [%s]" (kindOf .)) -}} + {{- end -}} + {{- end -}} + + {{- if $homepage.widget.custom -}} + {{- if not (kindIs "map" $homepage.widget.custom) -}} + {{- fail (printf "Ingress - Expected [integrations.homepage.widget.custom] to be a [map], but got [%s]" (kindOf $homepage.widget.custom)) -}} + {{- end -}} + {{- end -}} {{- end -}} diff --git a/library/common/templates/lib/ingress/integrations/_traefik.tpl b/library/common/templates/lib/ingress/integrations/_traefik.tpl new file mode 100644 index 00000000..4dcef8dd --- /dev/null +++ b/library/common/templates/lib/ingress/integrations/_traefik.tpl @@ -0,0 +1,115 @@ +{{- define "tc.v1.common.lib.ingress.integration.traefik" -}} + {{- $objectData := .objectData -}} + {{- $rootCtx := .rootCtx -}} + + {{- $traefik := $objectData.integrations.traefik -}} + + {{- $enabled := true -}} + {{- if and $traefik (hasKey $traefik "enabled") (kindIs "bool" $traefik.enabled) -}} + {{- $enabled = $traefik.enabled -}} + {{- end -}} + + {{- if $enabled -}} + {{- include "tc.v1.common.lib.ingress.integration.traefik.validate" (dict "objectData" $objectData) -}} + + {{- $fixedMiddlewares := list -}} + {{- $enableFixed := false -}} + {{- if (hasKey $rootCtx.Values.global "traefik") -}} + {{- $fixedMiddlewares = $rootCtx.Values.global.traefik.fixedMiddlewares -}} + {{- $enableFixed = $rootCtx.Values.global.traefik.enableFixedMiddlewares -}} + {{- end -}} + + {{/* Override global (enable)fixedMiddlewares with local */}} + {{- if $traefik.fixedMiddlewares -}} + {{- $fixedMiddlewares = $traefik.fixedMiddlewares -}} + {{- end -}} + + {{/* Replace global fixed with local fixed */}} + {{- if and (hasKey $traefik "enableFixedMiddlewares") (kindIs "bool" $traefik.enableFixedMiddlewares) -}} + {{- $enableFixed = $traefik.enableFixedMiddlewares -}} + {{- end -}} + + {{/* Replace global and local fixed middlewares with the opencors-chain */}} + {{- if $traefik.allowCors -}} + {{- $fixedMiddlewares = list "tc-opencors-chain" -}} + {{- end -}} + + {{- $entrypoints := $traefik.entrypoints | default (list "websecure") -}} + {{- $middlewares := list -}} + + {{/* Add the fixedMiddlewares */}} + {{- if and $enableFixed $fixedMiddlewares -}} + {{- $middlewares = concat $middlewares $fixedMiddlewares -}} + {{- end -}} + + {{/* Add the user middlewares */}} + {{- if $traefik.middlewares -}} + {{- $middlewares = concat $middlewares $traefik.middlewares -}} + {{- end -}} + + {{/* Make sure we dont have dupes */}} + {{- if $middlewares -}} + {{- if not (deepEqual (mustUniq $middlewares) $middlewares) -}} + {{- fail (printf "Ingress - Combined traefik middlewares contain duplicates [%s]" (join ", " $middlewares)) -}} + {{- end -}} + {{- end -}} + + {{- if not (deepEqual (mustUniq $entrypoints) $entrypoints) -}} + {{- fail (printf "Ingress - Combined traefik entrypoints contain duplicates [%s]" (join ", " $entrypoints)) -}} + {{- end -}} + + {{- $midNamespace := "tc-system" -}} + {{/* If our hook has set operator.traefik.namespace, use that */}} + {{- if (hasKey $rootCtx.Values.operator "traefik") -}} + {{- if $rootCtx.Values.operator.traefik.namespace -}} + {{- $midNamespace = $rootCtx.Values.operator.traefik.namespace -}} + {{- end -}} + {{- end -}} + + {{- if $traefik.ingressClassName -}} + {{- $midNamespace = tpl $traefik.ingressClassName $rootCtx -}} + + {{/* On SCALE prepend with ix- */}} + {{- if $rootCtx.Values.global.ixChartContext -}} + {{- $midNamespace = (printf "ix-%s" $midNamespace) -}} + {{- end -}} + {{- end -}} + + {{/* Format middlewares */}} + {{- $formMiddlewares := list -}} + {{- range $mid := $middlewares -}} + {{- $formMiddlewares = mustAppend $formMiddlewares (printf "%s-%s@kubernetescrd" $mid $midNamespace) -}} + {{- end -}} + + {{- $_ := set $objectData.annotations "traefik.ingress.kubernetes.io/router.entrypoints" (join "," $entrypoints) -}} + {{- if $formMiddlewares -}} + {{- $_ := set $objectData.annotations "traefik.ingress.kubernetes.io/router.middlewares" (join "," $formMiddlewares) -}} + {{- end -}} + + {{- end -}} +{{- end -}} + +{{- define "tc.v1.common.lib.ingress.integration.traefik.validate" -}} + {{- $objectData := .objectData -}} + + {{- $traefik := $objectData.integrations.traefik -}} + + {{- if $traefik.entrypoints -}} + {{- if not (kindIs "slice" $traefik.entrypoints) -}} + {{- fail (printf "Ingress - Expected [integrations.traefik.entrypoints] to be a [slice], but got [%s]" (kindOf $traefik.entrypoints)) -}} + {{- end -}} + {{- end -}} + + {{- if $traefik.middlewares -}} + {{- if not (kindIs "slice" $traefik.middlewares) -}} + {{- fail (printf "Ingress - Expected [integrations.traefik.middlewares] to be a [slice], but got [%s]" (kindOf $traefik.middlewares)) -}} + {{- end -}} + {{- end -}} + + {{- if $traefik.fixedMiddlewares -}} + {{- if not (kindIs "slice" $traefik.fixedMiddlewares) -}} + {{- fail (printf "Ingress - Expected [integrations.traefik.fixedMiddlewares] to be a [slice], but got [%s]" (kindOf $traefik.fixedMiddlewares)) -}} + {{- end -}} + {{- end -}} + +{{- end -}} diff --git a/library/common/templates/lib/service/_additionalAnnotations.tpl b/library/common/templates/lib/service/_additionalAnnotations.tpl index ab4e8dcc..e314083c 100644 --- a/library/common/templates/lib/service/_additionalAnnotations.tpl +++ b/library/common/templates/lib/service/_additionalAnnotations.tpl @@ -18,8 +18,10 @@ annotations: The annotations variable reference, to append the MetalLB annotatio {{- $sharedKey = tpl . $rootCtx -}} {{- end -}} - {{- if $rootCtx.Values.global.addMetalLBAnnotations -}} - {{- $_ := set $annotations "metallb.universe.tf/allow-shared-ip" $sharedKey -}} + {{- if (hasKey $rootCtx.Values.global "metallb") -}} + {{- if $rootCtx.Values.global.metallb.addServiceAnnotations -}} + {{- $_ := set $annotations "metallb.universe.tf/allow-shared-ip" $sharedKey -}} + {{- end -}} {{- end -}} {{- end -}} @@ -34,7 +36,9 @@ annotations: The annotations variable reference, to append the Traefik annotatio {{- $rootCtx := .rootCtx -}} {{- $annotations := .annotations -}} - {{- if $rootCtx.Values.global.addTraefikAnnotations -}} - {{- $_ := set $annotations "traefik.ingress.kubernetes.io/service.serversscheme" "https" -}} + {{- if (hasKey $rootCtx.Values.global "traefik") -}} + {{- if $rootCtx.Values.global.traefik.addServiceAnnotations -}} + {{- $_ := set $annotations "traefik.ingress.kubernetes.io/service.serversscheme" "https" -}} + {{- end -}} {{- end -}} {{- end -}} diff --git a/library/common/templates/lib/util/_primary_service.tpl b/library/common/templates/lib/util/_primary_service.tpl index b661a250..75f57631 100644 --- a/library/common/templates/lib/util/_primary_service.tpl +++ b/library/common/templates/lib/util/_primary_service.tpl @@ -32,8 +32,8 @@ {{- end -}} {{- if $result -}} - {{- $result -}} + {{- $result -}} {{- else -}} - {{- fail "No primary and enabled service found" -}} + {{- fail "No primary and enabled service found" -}} {{- end -}} {{- end -}} diff --git a/library/common/templates/loader/_init.tpl b/library/common/templates/loader/_init.tpl index aff423a4..13111e53 100644 --- a/library/common/templates/loader/_init.tpl +++ b/library/common/templates/loader/_init.tpl @@ -8,7 +8,7 @@ {{- include "tc.v1.common.loader.lists" . -}} {{/* Ensure TrueCharts chart context information is available */}} - {{- include "tc.v1.common.lib.util.chartcontext" . -}} + {{- /* include "tc.v1.common.lib.util.chartcontext" . */ -}} {{/* Autogenerate postgresql passwords if needed */}} {{- include "tc.v1.common.spawner.cnpg" . }} diff --git a/library/common/templates/spawner/_ingress.tpl b/library/common/templates/spawner/_ingress.tpl index 07353144..cadf12ca 100644 --- a/library/common/templates/spawner/_ingress.tpl +++ b/library/common/templates/spawner/_ingress.tpl @@ -1,62 +1,95 @@ -{{/* Renders the Ingress objects required by the chart */}} +{{/* Ingress Spawwner */}} +{{/* Call this template: +{{ include "tc.v1.common.spawner.ingress" $ -}} +*/}} + {{- define "tc.v1.common.spawner.ingress" -}} {{- $fullname := include "tc.v1.common.lib.chart.names.fullname" $ -}} - {{/* Generate named ingresses as required */}} + {{/* Validate that only 1 primary exists */}} + {{- include "tc.v1.common.lib.ingress.primaryValidation" $ -}} + {{- range $name, $ingress := .Values.ingress -}} - {{- if $ingress.enabled -}} - {{- $ingressValues := $ingress -}} - {{- $ingressName := $fullname -}} - {{/* set defaults */}} - {{- if and (not $ingressValues.nameOverride) (ne $name (include "tc.v1.common.lib.util.ingress.primary" $)) -}} - {{- $_ := set $ingressValues "nameOverride" $name -}} + {{- $enabled := (include "tc.v1.common.lib.util.enabled" (dict + "rootCtx" $ "objectData" $ingress + "name" $name "caller" "Ingress" + "key" "ingress")) -}} + + {{- if and (eq $enabled "false") ($ingress.required) -}} + {{- fail (printf "Ingress - Expected ingress [%s] to be enabled. This chart is designed to work only with ingress enabled." $name) -}} + {{- end -}} + + {{- if eq $enabled "true" -}} + + {{/* Create a copy of the ingress */}} + {{- $objectData := (mustDeepCopy $ingress) -}} + + {{/* Init object name */}} + {{- $objectName := $name -}} + + {{- $expandName := (include "tc.v1.common.lib.util.expandName" (dict + "rootCtx" $ "objectData" $objectData + "name" $name "caller" "Ingress" + "key" "ingress")) -}} + + {{- if eq $expandName "true" -}} + {{/* Expand the name of the service if expandName resolves to true */}} + {{- $objectName = $fullname -}} {{- end -}} - {{- if $ingressValues.nameOverride -}} - {{- $ingressName = printf "%v-%v" $ingressName $ingressValues.nameOverride -}} + {{- if and (eq $expandName "true") (not $objectData.primary) -}} + {{/* If the ingress is not primary append its name to fullname */}} + {{- $objectName = (printf "%s-%s" $fullname $name) -}} {{- end -}} - {{- $_ := set $ingressValues "name" $ingressName -}} + {{/* Perform validations */}} + {{- include "tc.v1.common.lib.chart.names.validation" (dict "name" $objectName "length" 253) -}} + {{- include "tc.v1.common.lib.metadata.validation" (dict "objectData" $objectData "caller" "Ingress") -}} + {{- include "tc.v1.common.lib.ingress.validation" (dict "rootCtx" $ "objectData" $objectData) -}} - {{- $_ := set $ "ObjectValues" (dict "ingress" $ingressValues) -}} - {{- include "tc.v1.common.class.ingress" $ -}} - {{- if and ( $ingressValues.tls ) ( not $ingressValues.clusterIssuer ) -}} - {{- range $index, $tlsValues := $ingressValues.tls -}} - {{- $tlsName := ( printf "%v-%v" "tls" $index ) -}} - {{- if $tlsValues.certificateIssuer -}} - {{- include "tc.v1.common.class.certificate" (dict "root" $ "name" ( printf "%v-%v" $ingressName $tlsName ) "certificateIssuer" $tlsValues.certificateIssuer "hosts" $tlsValues.hosts ) -}} - {{- else if and ( $tlsValues.scaleCert ) ( $.Values.global.ixChartContext ) -}} + {{/* Set the name of the ingress */}} + {{- $_ := set $objectData "name" $objectName -}} + {{- $_ := set $objectData "shortName" $name -}} - {{/* Create certificate object and use it to construct a secret */}} - {{- $objectData := dict -}} - {{- $_ := set $objectData "id" .scaleCert -}} - - {{- $objectName := (printf "%s-%s" $fullname $tlsName) -}} - {{/* Perform validations */}} - {{- include "tc.v1.common.lib.chart.names.validation" (dict "name" $objectName) -}} - {{- include "tc.v1.common.lib.scaleCertificate.validation" (dict "objectData" $objectData) -}} - {{- include "tc.v1.common.lib.metadata.validation" (dict "objectData" $objectData "caller" "Certificate") -}} - - {{/* Prepare data */}} - {{- $data := fromJson (include "tc.v1.common.lib.scaleCertificate.getData" (dict "rootCtx" $ "objectData" $objectData)) -}} - {{- $_ := set $objectData "data" $data -}} - - {{/* Set the type to certificate */}} - {{- $_ := set $objectData "type" "certificate" -}} - - {{/* Set the name of the certificate */}} - {{- $_ := set $objectData "name" $objectName -}} - {{- $_ := set $objectData "shortName" $name -}} - - {{/* Call class to create the object */}} - {{- include "tc.v1.common.class.secret" (dict "rootCtx" $ "objectData" $objectData) -}} + {{/* Call class to create the object */}} + {{- include "tc.v1.common.class.ingress" (dict "rootCtx" $ "objectData" $objectData) -}} + {{/* TODO: range over TLS and do stuff */}} + {{- $hasCertIssuer := false -}} + {{- if $objectData.integrations -}} + {{- if and $objectData.integrations.certManager $objectData.integrations.certManager.enabled -}} + {{- $hasCertIssuer = true -}} {{- end -}} {{- end -}} + + {{- if not $hasCertIssuer -}} + {{- range $idx, $tlsData := $objectData.tls -}} + {{- if $tlsData.scaleCert -}} + {{- if not $.Values.global.ixChartContext -}} + {{- fail "Ingress - [tls.scalecert] can only be used in TrueNAS SCALE" -}} + {{- end -}} + + {{- $certData := (include "tc.v1.common.lib.scaleCertificate.getData" (dict "rootCtx" $ "objectData" (dict "id" $tlsData.scaleCert)) | fromJson) -}} + {{- $certName := printf "%s-scale-tls-%d" $objectData.name ($idx | int) -}} + + {{- $certObjData := (dict + "id" $tlsData.scaleCert "type" "certificate" + "name" $certName "shortName" $name + "data" $certData + ) -}} + + {{- include "tc.v1.common.lib.chart.names.validation" (dict "name" $certName) -}} + {{- include "tc.v1.common.lib.scaleCertificate.validation" (dict "objectData" $certObjData) -}} + {{- include "tc.v1.common.lib.metadata.validation" (dict "objectData" $certObjData "caller" "Ingress") -}} + + {{/* Create the secret with the certData */}} + {{- include "tc.v1.common.class.secret" (dict "rootCtx" $ "objectData" $certObjData) -}} + {{- else if $tlsData.clusterCertificate -}} + {{/* TODO: Needs the refactor of Certificate object */}} + {{- end -}} + {{- end -}} {{- end -}} - {{- else if $ingress.required -}} - {{- fail (printf "Ingress - [ingress.%s] is set to be [required] and cannot be disabled" $name) -}} {{- end -}} {{- end -}} {{- end -}} diff --git a/library/common/templates/spawner/_priorityClass.tpl b/library/common/templates/spawner/_priorityClass.tpl index a7391d5d..07ecb992 100644 --- a/library/common/templates/spawner/_priorityClass.tpl +++ b/library/common/templates/spawner/_priorityClass.tpl @@ -1,4 +1,4 @@ -{{/* priorityclass Spawwner */}} +{{/* Priority Class Spawner */}} {{/* Call this template: {{ include "tc.v1.common.spawner.priorityclass" $ -}} */}} diff --git a/library/common/templates/spawner/_service.tpl b/library/common/templates/spawner/_service.tpl index 86d40841..57081af9 100644 --- a/library/common/templates/spawner/_service.tpl +++ b/library/common/templates/spawner/_service.tpl @@ -43,7 +43,7 @@ {{- include "tc.v1.common.lib.metadata.validation" (dict "objectData" $objectData "caller" "Service") -}} {{- include "tc.v1.common.lib.service.validation" (dict "rootCtx" $ "objectData" $objectData) -}} - {{/* Set the name of the service account */}} + {{/* Set the name of the service */}} {{- $_ := set $objectData "name" $objectName -}} {{- $_ := set $objectData "shortName" $name -}} diff --git a/library/common/values.yaml b/library/common/values.yaml index 0123a962..ffa44111 100644 --- a/library/common/values.yaml +++ b/library/common/values.yaml @@ -7,10 +7,19 @@ global: # -- Set a global namespace # TODO: Currently some objects do not support this namespace: "" - # -- Adds metalLB annotations to services - addMetalLBAnnotations: true - # -- Adds traefik annotations to services - addTraefikAnnotations: true + metallb: + # -- Adds metalLB annotations to services + addServiceAnnotations: true + traefik: + # -- Adds traefik annotations to services (when needed) + addServiceAnnotations: true + # Enables or disables the fixed middlewares on all ingresses + # Can be overruled per ingress + enableFixedMiddlewares: true + # Applies middleware to all ingresses + # Can be overruled per ingress + fixedMiddlewares: + - chain-basic # -- Minimum nodePort value minNodePort: 9000 # -- Enable to stop most pods and containers including cnpg @@ -515,7 +524,6 @@ wireguardImage: # -- Specify the WireGuard image pull policy pullPolicy: IfNotPresent - # -- Configure the ingresses for the chart here. # Additional ingresses can be added by adding a dictionary key similar to the 'main' ingress. # @default -- See below @@ -523,104 +531,81 @@ ingress: main: # -- Enables or disables the ingress enabled: false - - # -- Adds integrations to ingress -# integration: -# homepage: -# enabled: true -# # Default: chart name -# name: somename -# # Default: chart description -# description: some description -# group: somegroup -# # Default: chart icon -# icon: icon.png -# pod-selector: "" -# widget: -# # Default: chartname -# type: "sometype" -# # Default: host-path of first ingress -# url: "https://example.com" -# custom: -# - somesetting: some value - # -- Make this the primary ingress (used in probes, notes, etc...). # If there is more than 1 ingress, make sure that only 1 ingress is marked as primary. primary: true - # -- Ensure this ingress is always enabled. required: false - - # -- Override the name suffix that is used for this ingress. - nameOverride: - - # -- Autolink the ingress to a service and port, both with the same name as the ingress. - autoLink: false - - # -- disable to ignore any default middlwares - enableFixedMiddlewares: true - - # -- set the Cert-Manager clusterissuer for this ingress - clusterIssuer: "" - - # -- List of middlewares in the traefikmiddlewares k8s namespace to add automatically - # Creates an annotation with the middlewares and appends k8s and traefik namespaces to the middleware names - # Primarily used for TrueNAS SCALE to add additional (seperate) middlewares without exposing them to the end-user - fixedMiddlewares: - - chain-basic - - # -- Additional List of middlewares in the traefikmiddlewares k8s namespace to add automatically - # Creates an annotation with the middlewares and appends k8s and traefik namespaces to the middleware names - middlewares: [] - annotationsList: [] - # - name: somename - # value: somevalue - # -- Provide additional annotations which may be required. - annotations: {} - # kubernetes.io/ingress.class: nginx - # kubernetes.io/tls-acme: "true" - - labelsList: [] - # - name: somename - # value: somevalue - # -- Set labels on the deployment/statefulset/daemonset - # -- Provide additional labels which may be required. + expandObjectName: false # -- Provide additional labels which may be required. labels: {} - + # -- Provide additional annotations which may be required. + annotations: {} # -- Set the ingressClass that is used for this ingress. # Requires Kubernetes >=1.19 - ingressClassName: # "nginx" - - # Enable or disable CORS Requests to the ingress - allowCors: false - + ingressClassName: "" + # Defaults to primary service and primary port + # targetSelector: + # # service: port + # main: main ## Configure the hosts for the ingress - hosts: - - # -- Host address. Helm template can be passed. - host: chart-example.local - ## Configure the paths for the host - paths: - - # -- Path. Helm template can be passed. - path: / - # -- Ignored if not kubeVersion >= 1.14-0 - pathType: Prefix - service: - # -- Overrides the service name reference for this path - name: - # -- Overrides the service port reference for this path - port: - + hosts: [] + # - # -- Host address. Helm template can be passed. + # host: chart-example.local + # ## Configure the paths for the host + # paths: + # - # -- Path. Helm template can be passed. + # path: / + # # -- Ignored if not kubeVersion >= 1.14-0 + # pathType: Prefix + # # -- Overrides the service reference for this path, by default the selector is honored + # overrideService: + # # -- Overrides the service name reference for this path + # name: + # # -- Overrides the service port reference for this path + # port: # -- Configure TLS for the ingress. Both secretName and hosts can process a Helm template. # Gets ignored when clusterIssuer is filled tls: [] # - secretName: chart-example-tls # # Cannot be combined with scaleCert - # clusterIssuer: "" - # # Cannot be combined with clusterIssuer + # certificateIssuer: "" + # # Cannot be combined with certificateIssuer # scaleCert: "" # hosts: # - chart-example.local + integrations: + certManager: + enabled: false + certificateIssuer: "" + traefik: + enabled: true + # Default to websecure + entrypoints: + - websecure + enableFixedMiddlewares: true + # Drops both global and local fixedMiddlewares when enabled + allowCors: false + # fixedMiddlewares: + # - chain-basic + middlewares: [] + homepage: + enabled: false + # Default: chart name + name: somename + # Default: chart description + description: some description + # Default: no group + group: somegroup + # Default: chart icon + icon: icon.png + widget: + # Default: chartname + type: "sometype" + # Default to ingress host 0 + url: "https://example.com" + custom: + - somesetting: some value # -- BETA: Configure the gateway routes for the chart here. # Additional routes can be added by adding a dictionary key similar to the 'main' route. From 6c3e94dc840690c3904ba2ba2a8c6c4b6cf5ac60 Mon Sep 17 00:00:00 2001 From: Stavros Kois <47820033+stavros-k@users.noreply.github.com> Date: Fri, 8 Dec 2023 16:45:05 +0200 Subject: [PATCH 6/9] bump --- library/common/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/common/Chart.yaml b/library/common/Chart.yaml index 377e2622..24a1ebea 100644 --- a/library/common/Chart.yaml +++ b/library/common/Chart.yaml @@ -15,4 +15,4 @@ maintainers: name: common sources: null type: library -version: 16.1.0 +version: 16.2.0 From ed7d67d60a90464547bb0beabd52596478e365ca Mon Sep 17 00:00:00 2001 From: Stavros Kois <47820033+stavros-k@users.noreply.github.com> Date: Fri, 8 Dec 2023 16:45:20 +0200 Subject: [PATCH 7/9] feat(certificate): refactor + tests (#626) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Description** ⚒️ Fixes # **⚙️ Type of change** - [x] ⚙️ Feature/App addition - [x] 🪛 Bugfix - [ ] ⚠️ Breaking change (fix or feature that would cause existing functionality to not work as expected) - [x] 🔃 Refactor of current code **🧪 How Has This Been Tested?** **📃 Notes:** **✔️ Checklist:** - [x] ⚖️ My code follows the style guidelines of this project - [x] 👀 I have performed a self-review of my own code - [x] #️⃣ I have commented my code, particularly in hard-to-understand areas - [ ] 📄 I have made corresponding changes to the documentation - [x] ⚠️ My changes generate no new warnings - [x] 🧪 I have added tests to this description that prove my fix is effective or that my feature works - [ ] ⬆️ I increased versions for any altered app according to semantic versioning **➕ App addition** If this PR is an app addition please make sure you have done the following. - [ ] 🪞 I have opened a PR on [truecharts/containers](https://github.com/truecharts/containers) adding the container to TrueCharts mirror repo. - [ ] 🖼️ I have added an icon in the Chart's root directory called `icon.png` --- _Please don't blindly check all the boxes. Read them and only check those that apply. Those checkboxes are there for the reviewer to see what is this all about and the status of this PR with a quick glance._ --- .../tests/certificate/data_test.yaml | 106 ++++++++-- .../tests/certificate/metadata_test.yaml | 193 ++++++++++++++++-- .../tests/certificate/name_test.yaml | 44 ++-- .../tests/certificate/validation_test.yaml | 183 +++++++++++------ .../tests/scaleCertificate/data_test.yaml | 33 +++ .../tests/scaleCertificate/metadata_test.yaml | 64 ++++++ .../tests/scaleCertificate/name_test.yaml | 44 ++++ .../scaleCertificate/validation_test.yaml | 146 +++++++++++++ library/common/Chart.yaml | 2 +- .../common/templates/class/_certificate.tpl | 45 ---- .../class/cert-manager/_certificate.tpl | 59 ++++++ .../common/templates/lib/_tc_capabilities.tpl | 5 - .../templates/lib/certificate/_validation.tpl | 49 +++++ .../common/templates/spawner/_certificate.tpl | 27 --- .../spawner/cert-manager/_certificate.tpl | 44 ++++ library/common/values.yaml | 11 + 16 files changed, 860 insertions(+), 195 deletions(-) create mode 100644 library/common-test/tests/scaleCertificate/data_test.yaml create mode 100644 library/common-test/tests/scaleCertificate/metadata_test.yaml create mode 100644 library/common-test/tests/scaleCertificate/name_test.yaml create mode 100644 library/common-test/tests/scaleCertificate/validation_test.yaml delete mode 100644 library/common/templates/class/_certificate.tpl create mode 100644 library/common/templates/class/cert-manager/_certificate.tpl create mode 100644 library/common/templates/lib/certificate/_validation.tpl delete mode 100644 library/common/templates/spawner/_certificate.tpl create mode 100644 library/common/templates/spawner/cert-manager/_certificate.tpl diff --git a/library/common-test/tests/certificate/data_test.yaml b/library/common-test/tests/certificate/data_test.yaml index daaa7faa..06620e44 100644 --- a/library/common-test/tests/certificate/data_test.yaml +++ b/library/common-test/tests/certificate/data_test.yaml @@ -7,27 +7,99 @@ release: name: test-release-name namespace: test-release-namespace tests: - - it: should pass with secret created for certificate + - it: should pass with certificate created set: - ixCertificates: - "1": - certificate: some_cert - privatekey: some_key - scaleCertificate: - my-cert: + issuer: some-issuer + host: host1 + certificate: + my-certificate1: enabled: true - id: 1 + hosts: + - "{{ .Values.host }}" + certificateIssuer: "{{ .Values.issuer }}" + my-certificate2: + enabled: true + hosts: + - host2 + certificateIssuer: some-other-issuer + certificateSecretTemplate: + labels: + label1: label1 + label2: label2 + annotations: + annotation1: annotation1 + annotation2: annotation2 asserts: - - documentIndex: &secretDoc 0 + - documentIndex: &certDoc 0 isKind: - of: Secret - - documentIndex: *secretDoc + of: Certificate + - documentIndex: *certDoc + isAPIVersion: + of: cert-manager.io/v1 + - documentIndex: *certDoc equal: - path: data + path: metadata.name + value: test-release-name-common-test-my-certificate1 + - documentIndex: *certDoc + equal: + path: metadata.namespace + value: test-release-namespace + - documentIndex: *certDoc + equal: + path: spec value: - tls.crt: c29tZV9jZXJ0 - tls.key: c29tZV9rZXk= - - documentIndex: *secretDoc + secretName: test-release-name-common-test-my-certificate1 + dnsNames: + - host1 + issuerRef: + name: some-issuer + kind: ClusterIssuer + group: cert-manager.io + privateKey: + algorithm: ECDSA + size: 256 + rotationPolicy: Always + - documentIndex: &otherCertDoc 1 + isKind: + of: Certificate + - documentIndex: *otherCertDoc + isAPIVersion: + of: cert-manager.io/v1 + - documentIndex: *otherCertDoc equal: - path: type - value: kubernetes.io/tls + path: spec + value: + secretName: certificate-issuer-my-certificate2 + dnsNames: + - host2 + issuerRef: + name: some-other-issuer + kind: ClusterIssuer + group: cert-manager.io + privateKey: + algorithm: ECDSA + size: 256 + rotationPolicy: Always + secretTemplate: + labels: + label1: label1 + label2: label2 + app: common-test-1.0.0 + app.kubernetes.io/instance: test-release-name + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: common-test + app.kubernetes.io/version: v9.9.9 + helm-revision: "0" + helm.sh/chart: common-test-1.0.0 + release: test-release-name + annotations: + annotation1: annotation1 + annotation2: annotation2 + - documentIndex: *otherCertDoc + equal: + path: metadata.name + value: certificate-issuer-my-certificate2 + - documentIndex: *otherCertDoc + equal: + path: metadata.namespace + value: test-release-namespace diff --git a/library/common-test/tests/certificate/metadata_test.yaml b/library/common-test/tests/certificate/metadata_test.yaml index ff620ca1..cbc59307 100644 --- a/library/common-test/tests/certificate/metadata_test.yaml +++ b/library/common-test/tests/certificate/metadata_test.yaml @@ -11,8 +11,10 @@ tests: set: label1: label1 label2: global_label2 + label3: label3 annotation1: annotation1 annotation2: global_annotation2 + annotation3: annotation3 global: labels: g_label1: global_label1 @@ -20,25 +22,44 @@ tests: annotations: g_annotation1: global_annotation1 g_annotation2: "{{ .Values.annotation2 }}" - ixCertificates: - "1": - certificate: some_cert - privatekey: some_key - scaleCertificate: - my-cert: + certificate: + my-certificate1: enabled: true - id: 1 - labels: - label1: "{{ .Values.label1 }}" - label2: label2 annotations: annotation1: "{{ .Values.annotation1 }}" annotation2: annotation2 + labels: + label1: "{{ .Values.label1 }}" + label2: label2 + hosts: + - host1 + certificateIssuer: some-issuer + my-certificate2: + enabled: true + annotations: + annotation1: "{{ .Values.annotation1 }}" + annotation2: annotation2 + labels: + label1: "{{ .Values.label1 }}" + label2: label2 + hosts: + - host1 + certificateIssuer: some-issuer + certificateSecretTemplate: + labels: + label3: "{{ .Values.label3 }}" + label4: label4 + annotations: + annotation3: "{{ .Values.annotation3 }}" + annotation4: annotation4 asserts: - - documentIndex: &secretDoc 0 + - documentIndex: &certDoc 0 isKind: - of: Secret - - documentIndex: *secretDoc + of: Certificate + - documentIndex: *certDoc + isAPIVersion: + of: cert-manager.io/v1 + - documentIndex: *certDoc equal: path: metadata.annotations value: @@ -46,7 +67,7 @@ tests: annotation2: annotation2 g_annotation1: global_annotation1 g_annotation2: global_annotation2 - - documentIndex: *secretDoc + - documentIndex: *certDoc equal: path: metadata.labels value: @@ -54,11 +75,151 @@ tests: 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 + app.kubernetes.io/instance: test-release-name + app.kubernetes.io/name: common-test g_label1: global_label1 g_label2: global_label2 label1: label1 label2: label2 + - documentIndex: *certDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-certificate1 + - documentIndex: *certDoc + equal: + path: metadata.namespace + value: test-release-namespace + + - documentIndex: &otherCertDoc 1 + isKind: + of: Certificate + - documentIndex: *otherCertDoc + isAPIVersion: + of: cert-manager.io/v1 + - documentIndex: *otherCertDoc + equal: + path: metadata.annotations + value: + annotation1: annotation1 + annotation2: annotation2 + g_annotation1: global_annotation1 + g_annotation2: global_annotation2 + - documentIndex: *otherCertDoc + 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/managed-by: Helm + app.kubernetes.io/version: *appVer + app.kubernetes.io/instance: test-release-name + app.kubernetes.io/name: common-test + g_label1: global_label1 + g_label2: global_label2 + label1: label1 + label2: label2 + - documentIndex: *otherCertDoc + equal: + path: metadata.name + value: certificate-issuer-my-certificate2 + - documentIndex: *otherCertDoc + equal: + path: metadata.namespace + value: test-release-namespace + - documentIndex: *otherCertDoc + equal: + path: spec.secretTemplate.annotations + value: + annotation3: annotation3 + annotation4: annotation4 + g_annotation1: global_annotation1 + g_annotation2: global_annotation2 + - documentIndex: *otherCertDoc + equal: + path: spec.secretTemplate.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/managed-by: Helm + app.kubernetes.io/version: *appVer + app.kubernetes.io/instance: test-release-name + app.kubernetes.io/name: common-test + g_label1: global_label1 + g_label2: global_label2 + label3: label3 + label4: label4 + + - it: should pass with certificate created with namespace from tpl + set: + key: some-namespace + certificate: + my-cert1: + enabled: true + namespace: "{{ .Values.key }}" + hosts: + - host1 + certificateIssuer: some-issuer + asserts: + - documentIndex: *certDoc + equal: + path: metadata.namespace + value: some-namespace + + - it: should pass with certificate created with global namespace from tpl + set: + key: global-namespace + global: + namespace: "{{ .Values.key }}" + certificate: + my-cert1: + enabled: true + hosts: + - host1 + certificateIssuer: some-issuer + asserts: + - documentIndex: *certDoc + equal: + path: metadata.namespace + value: global-namespace + + - it: should pass with certificate created with root namespace from tpl + set: + key: local-namespace + namespace: "{{ .Values.key }}" + global: + namespace: global-namespace + certificate: + my-cert1: + enabled: true + hosts: + - host1 + certificateIssuer: some-issuer + asserts: + - documentIndex: *certDoc + equal: + path: metadata.namespace + value: local-namespace + + - it: should pass with certificate created with namespace in TrueNAS SCALE + set: + global: + ixChartContext: + iAmNotEmpty: true + namespace: ix-namespace + certificate: + my-cert1: + enabled: true + hosts: + - host1 + certificateIssuer: some-issuer + asserts: + - documentIndex: *certDoc + equal: + path: metadata.namespace + value: ix-namespace diff --git a/library/common-test/tests/certificate/name_test.yaml b/library/common-test/tests/certificate/name_test.yaml index a3402018..31ff78c3 100644 --- a/library/common-test/tests/certificate/name_test.yaml +++ b/library/common-test/tests/certificate/name_test.yaml @@ -7,38 +7,40 @@ release: tests: - it: should generate correct name set: - ixCertificates: - "1": - certificate: some_cert - privatekey: some_key - "2": - certificate: some_cert - privatekey: some_key - scaleCertificate: + certificate: my-cert1: enabled: true - id: 1 + hosts: + - host1 + certificateIssuer: some-issuer my-cert2: enabled: true - id: 2 + hosts: + - host1 + certificateIssuer: some-issuer + certificateSecretTemplate: + labels: + some-label: my-cert2 + annotations: + some-annotation: my-cert2 asserts: - - documentIndex: &secretDoc 0 + - documentIndex: &certDoc 0 isKind: - of: Secret - - documentIndex: *secretDoc + of: Certificate + - documentIndex: *certDoc isAPIVersion: - of: v1 - - documentIndex: *secretDoc + of: cert-manager.io/v1 + - documentIndex: *certDoc equal: path: metadata.name value: test-release-name-common-test-my-cert1 - - documentIndex: &otherSecretDoc 1 + - documentIndex: &otherCertDoc 1 isKind: - of: Secret - - documentIndex: *otherSecretDoc + of: Certificate + - documentIndex: *otherCertDoc isAPIVersion: - of: v1 - - documentIndex: *otherSecretDoc + of: cert-manager.io/v1 + - documentIndex: *otherCertDoc equal: path: metadata.name - value: test-release-name-common-test-my-cert2 + value: certificate-issuer-my-cert2 diff --git a/library/common-test/tests/certificate/validation_test.yaml b/library/common-test/tests/certificate/validation_test.yaml index 8b5bccd2..5ed4b27f 100644 --- a/library/common-test/tests/certificate/validation_test.yaml +++ b/library/common-test/tests/certificate/validation_test.yaml @@ -7,140 +7,197 @@ release: tests: - it: should fail with name longer than 253 characters set: - scaleCertificate: - my-certificate-super-long-name-that-is-longer-than-253-characters-my-certificate-super-long-name-that-is-longer-than-253-characters-my-certificate-super-long-name-that-is-longer-than-253-characters-my-certificate-super-long-long-long-long-long-long-name: + certificate: + my-certificate-super-long-name-that-is-longer-than-253-characters-my-certificate-super-long-name-that-is-longer-than-253-characters-my-certificate-super-long-name-that-is-longer-than-253-characters-my-certificate-super-long-long-long-long-long-long-long-long-name: enabled: true - id: 1 asserts: - failedTemplate: - errorMessage: Name [test-release-name-common-test-my-certificate-super-long-name-that-is-longer-than-253-characters-my-certificate-super-long-name-that-is-longer-than-253-characters-my-certificate-super-long-name-that-is-longer-than-253-characters-my-certificate-super-long-long-long-long-long-long-name] is not valid. Must start and end with an alphanumeric lowercase character. It can contain '-'. And must be at most 253 characters. + errorMessage: Name [test-release-name-common-test-my-certificate-super-long-name-that-is-longer-than-253-characters-my-certificate-super-long-name-that-is-longer-than-253-characters-my-certificate-super-long-name-that-is-longer-than-253-characters-my-certificate-super-long-long-long-long-long-long-long-long-name] is not valid. Must start and end with an alphanumeric lowercase character. It can contain '-'. And must be at most 253 characters. - it: should fail with name starting with underscore set: - scaleCertificate: + certificate: _my-cert: enabled: true - id: 1 asserts: - failedTemplate: errorMessage: Name [test-release-name-common-test-_my-cert] is not valid. Must start and end with an alphanumeric lowercase character. It can contain '-'. And must be at most 253 characters. + - it: should fail with namespace longer than 63 characters + set: + certificate: + my-certificate: + enabled: true + namespace: my-extra-super-duper-long-name-that-is-longer-than-63-characters + certificateIssuer: some-issuer + hosts: + - test-host + asserts: + - failedTemplate: + errorMessage: Cert Manager Certificate - Namespace [my-extra-super-duper-long-name-that-is-longer-than-63-characters] is not valid. Must start and end with an alphanumeric lowercase character. It can contain '-'. And must be at most 63 characters. + + - it: should fail with namespace not starting with [ix-] in TrueNAS SCALE + set: + global: + ixChartContext: + iAmNotEmpty: true + certificate: + my-certificate: + enabled: true + namespace: my-namespace + certificateIssuer: some-issuer + hosts: + - test-host + asserts: + - failedTemplate: + errorMessage: Cert Manager Certificate - Namespace [my-namespace] expected to have [ix-] prefix when installed in TrueNAS SCALE + - it: should fail with labels not a dict set: - scaleCertificate: + certificate: my-cert: enabled: true labels: "not a dict" - id: 1 asserts: - failedTemplate: - errorMessage: Certificate - Expected [labels] to be a dictionary, but got [string] + errorMessage: Cert Manager Certificate - Expected [labels] to be a dictionary, but got [string] - it: should fail with annotations not a dict set: - scaleCertificate: - my-cert: + certificate: + my-certificate: enabled: true annotations: "not a dict" - id: 1 asserts: - failedTemplate: - errorMessage: Certificate - Expected [annotations] to be a dictionary, but got [string] + errorMessage: Cert Manager Certificate - Expected [annotations] to be a dictionary, but got [string] - - it: should fail without id + - it: should fail with empty enabled set: - scaleCertificate: + certificate: + my-certificate: + enabled: + asserts: + - failedTemplate: + errorMessage: Cert Manager Certificate - Expected the defined key [enabled] in [certificate.my-certificate] to not be empty + + - it: should fail if certificateIssuer is missing + set: + certificate: my-cert: enabled: true - id: "" asserts: - failedTemplate: - errorMessage: Certificate - Expected non-empty [id] + errorMessage: Cert Manager Certificate - Expected non-empty [certificateIssuer] - - it: should fail with targetSelector not a dict + - it: should fail if hosts are empty set: - scaleCertificate: + certificate: my-cert: enabled: true - id: 1 - targetSelector: "not a dict" + certificateIssuer: some-issuer + hosts: [] asserts: - failedTemplate: - errorMessage: Certificate - Expected [targetSelector] to be a [map], but got [string] + errorMessage: Cert Manager Certificate - Expected non-empty [hosts] - - it: should fail with empty ixCertificates when cert is defined + - it: should fail if hosts is not slice set: - ixCertificates: [] - scaleCertificate: + certificate: my-cert: enabled: true - id: 1 + certificateIssuer: some-issuer + hosts: not-a-slice asserts: - failedTemplate: - errorMessage: Certificate - Expected non-empty [ixCertificates] + errorMessage: Cert Manager Certificate - Expected [hosts] to be a [slice], but got [string] - - it: should fail with not defined id in ixCertificates when cert is defined + - it: should fail if hosts entry is empty set: - ixCertificates: - "2": - key: value - scaleCertificate: + certificate: my-cert: enabled: true - id: 1 + certificateIssuer: some-issuer + hosts: + - "" asserts: - failedTemplate: - errorMessage: Certificate - Expected certificate with [id] ["1"] to exist in [ixCertificates] + errorMessage: Cert Manager Certificate - Expected non-empty entry in [hosts] - - it: should fail with with revoked cert + - it: should fail if hosts entry starts with https:// set: - ixCertificates: - "1": - revoked: true - scaleCertificate: + certificate: my-cert: enabled: true - id: 1 + certificateIssuer: some-issuer + hosts: + - https://test-host asserts: - failedTemplate: - errorMessage: Certificate - Expected non-revoked certificate with [id] ["1"] + errorMessage: Cert Manager Certificate - Expected entry in [hosts] to not start with [https://], but got [https://test-host] - - it: should fail with with expired cert + - it: should fail if hosts entry starts with http:// set: - ixCertificates: - "1": - expired: true - scaleCertificate: + certificate: my-cert: enabled: true - id: 1 + certificateIssuer: some-issuer + hosts: + - http://test-host asserts: - failedTemplate: - errorMessage: Certificate - Expected non-expired certificate with [id] ["1"] + errorMessage: Cert Manager Certificate - Expected entry in [hosts] to not start with [http://], but got [http://test-host] - - it: should fail with with empty certificate + - it: should fail if hosts entry contains ":" set: - ixCertificates: - "1": - certificate: "" - scaleCertificate: + certificate: my-cert: enabled: true - id: 1 + certificateIssuer: some-issuer + hosts: + - test-host:123 asserts: - failedTemplate: - errorMessage: Certificate - Expected non-empty [certificate] in certificate with [id] ["1"] in [ixCertificates] + errorMessage: Cert Manager Certificate - Expected entry in [hosts] to not contain [:], but got [test-host:123] - - it: should fail with with empty privatekey + - it: should fail if certificateSecretTemplate missing both labels and annotations set: - ixCertificates: - "1": - certificate: some_value - privatekey: "" - scaleCertificate: + certificate: my-cert: enabled: true - id: 1 + certificateIssuer: some-issuer + hosts: + - test-host + certificateSecretTemplate: + some-key: some-value asserts: - failedTemplate: - errorMessage: Certificate - Expected non-empty [privatekey] in certificate with [id] ["1"] in [ixCertificates] + errorMessage: Cert Manager Certificate - Expected [certificateSecretTemplate] to have at least one of [labels, annotations] + + - it: should fail if certificateSecretTemplate labels are not a map + set: + certificate: + my-cert: + enabled: true + certificateIssuer: some-issuer + hosts: + - test-host + certificateSecretTemplate: + labels: "not a map" + asserts: + - failedTemplate: + errorMessage: Cert Manager Certificate (certificateSecretTemplate) - Expected [labels] to be a dictionary, but got [string] + + - it: should fail if certificateSecretTemplate annotations are not a map + set: + certificate: + my-cert: + enabled: true + certificateIssuer: some-issuer + hosts: + - test-host + certificateSecretTemplate: + annotations: "not a map" + asserts: + - failedTemplate: + errorMessage: Cert Manager Certificate (certificateSecretTemplate) - Expected [annotations] to be a dictionary, but got [string] diff --git a/library/common-test/tests/scaleCertificate/data_test.yaml b/library/common-test/tests/scaleCertificate/data_test.yaml new file mode 100644 index 00000000..6f942b74 --- /dev/null +++ b/library/common-test/tests/scaleCertificate/data_test.yaml @@ -0,0 +1,33 @@ +suite: scale certificate data test +templates: + - common.yaml +chart: + appVersion: &appVer v9.9.9 +release: + name: test-release-name + namespace: test-release-namespace +tests: + - it: should pass with secret created for certificate + set: + ixCertificates: + "1": + certificate: some_cert + privatekey: some_key + scaleCertificate: + my-cert: + enabled: true + id: 1 + asserts: + - documentIndex: &secretDoc 0 + isKind: + of: Secret + - documentIndex: *secretDoc + equal: + path: data + value: + tls.crt: c29tZV9jZXJ0 + tls.key: c29tZV9rZXk= + - documentIndex: *secretDoc + equal: + path: type + value: kubernetes.io/tls diff --git a/library/common-test/tests/scaleCertificate/metadata_test.yaml b/library/common-test/tests/scaleCertificate/metadata_test.yaml new file mode 100644 index 00000000..e769afbb --- /dev/null +++ b/library/common-test/tests/scaleCertificate/metadata_test.yaml @@ -0,0 +1,64 @@ +suite: scale certificate 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 certificate 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 }}" + ixCertificates: + "1": + certificate: some_cert + privatekey: some_key + scaleCertificate: + my-cert: + enabled: true + id: 1 + labels: + label1: "{{ .Values.label1 }}" + label2: label2 + annotations: + annotation1: "{{ .Values.annotation1 }}" + annotation2: annotation2 + asserts: + - documentIndex: &secretDoc 0 + isKind: + of: Secret + - 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/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/scaleCertificate/name_test.yaml b/library/common-test/tests/scaleCertificate/name_test.yaml new file mode 100644 index 00000000..754fbc10 --- /dev/null +++ b/library/common-test/tests/scaleCertificate/name_test.yaml @@ -0,0 +1,44 @@ +suite: scale certificate name test +templates: + - common.yaml +release: + name: test-release-name + namespace: test-release-namespace +tests: + - it: should generate correct name + set: + ixCertificates: + "1": + certificate: some_cert + privatekey: some_key + "2": + certificate: some_cert + privatekey: some_key + scaleCertificate: + my-cert1: + enabled: true + id: 1 + my-cert2: + enabled: true + id: 2 + asserts: + - documentIndex: &secretDoc 0 + isKind: + of: Secret + - documentIndex: *secretDoc + isAPIVersion: + of: v1 + - documentIndex: *secretDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-cert1 + - documentIndex: &otherSecretDoc 1 + isKind: + of: Secret + - documentIndex: *otherSecretDoc + isAPIVersion: + of: v1 + - documentIndex: *otherSecretDoc + equal: + path: metadata.name + value: test-release-name-common-test-my-cert2 diff --git a/library/common-test/tests/scaleCertificate/validation_test.yaml b/library/common-test/tests/scaleCertificate/validation_test.yaml new file mode 100644 index 00000000..443d514e --- /dev/null +++ b/library/common-test/tests/scaleCertificate/validation_test.yaml @@ -0,0 +1,146 @@ +suite: scale certificate validation test +templates: + - common.yaml +release: + name: test-release-name + namespace: test-release-namespace +tests: + - it: should fail with name longer than 253 characters + set: + scaleCertificate: + my-certificate-super-long-name-that-is-longer-than-253-characters-my-certificate-super-long-name-that-is-longer-than-253-characters-my-certificate-super-long-name-that-is-longer-than-253-characters-my-certificate-super-long-long-long-long-long-long-name: + enabled: true + id: 1 + asserts: + - failedTemplate: + errorMessage: Name [test-release-name-common-test-my-certificate-super-long-name-that-is-longer-than-253-characters-my-certificate-super-long-name-that-is-longer-than-253-characters-my-certificate-super-long-name-that-is-longer-than-253-characters-my-certificate-super-long-long-long-long-long-long-name] is not valid. Must start and end with an alphanumeric lowercase character. It can contain '-'. And must be at most 253 characters. + + - it: should fail with name starting with underscore + set: + scaleCertificate: + _my-cert: + enabled: true + id: 1 + asserts: + - failedTemplate: + errorMessage: Name [test-release-name-common-test-_my-cert] is not valid. Must start and end with an alphanumeric lowercase character. It can contain '-'. And must be at most 253 characters. + + - it: should fail with labels not a dict + set: + scaleCertificate: + my-cert: + enabled: true + labels: "not a dict" + id: 1 + asserts: + - failedTemplate: + errorMessage: Certificate - Expected [labels] to be a dictionary, but got [string] + + - it: should fail with annotations not a dict + set: + scaleCertificate: + my-cert: + enabled: true + annotations: "not a dict" + id: 1 + asserts: + - failedTemplate: + errorMessage: Certificate - Expected [annotations] to be a dictionary, but got [string] + + - it: should fail without id + set: + scaleCertificate: + my-cert: + enabled: true + id: "" + asserts: + - failedTemplate: + errorMessage: Certificate - Expected non-empty [id] + + - it: should fail with targetSelector not a dict + set: + scaleCertificate: + my-cert: + enabled: true + id: 1 + targetSelector: "not a dict" + asserts: + - failedTemplate: + errorMessage: Certificate - Expected [targetSelector] to be a [map], but got [string] + + - it: should fail with empty ixCertificates when cert is defined + set: + ixCertificates: [] + scaleCertificate: + my-cert: + enabled: true + id: 1 + asserts: + - failedTemplate: + errorMessage: Certificate - Expected non-empty [ixCertificates] + + - it: should fail with not defined id in ixCertificates when cert is defined + set: + ixCertificates: + "2": + key: value + scaleCertificate: + my-cert: + enabled: true + id: 1 + asserts: + - failedTemplate: + errorMessage: Certificate - Expected certificate with [id] ["1"] to exist in [ixCertificates] + + - it: should fail with with revoked cert + set: + ixCertificates: + "1": + revoked: true + scaleCertificate: + my-cert: + enabled: true + id: 1 + asserts: + - failedTemplate: + errorMessage: Certificate - Expected non-revoked certificate with [id] ["1"] + + - it: should fail with with expired cert + set: + ixCertificates: + "1": + expired: true + scaleCertificate: + my-cert: + enabled: true + id: 1 + asserts: + - failedTemplate: + errorMessage: Certificate - Expected non-expired certificate with [id] ["1"] + + - it: should fail with with empty certificate + set: + ixCertificates: + "1": + certificate: "" + scaleCertificate: + my-cert: + enabled: true + id: 1 + asserts: + - failedTemplate: + errorMessage: Certificate - Expected non-empty [certificate] in certificate with [id] ["1"] in [ixCertificates] + + - it: should fail with with empty privatekey + set: + ixCertificates: + "1": + certificate: some_value + privatekey: "" + scaleCertificate: + my-cert: + enabled: true + id: 1 + asserts: + - failedTemplate: + errorMessage: Certificate - Expected non-empty [privatekey] in certificate with [id] ["1"] in [ixCertificates] diff --git a/library/common/Chart.yaml b/library/common/Chart.yaml index 377e2622..24a1ebea 100644 --- a/library/common/Chart.yaml +++ b/library/common/Chart.yaml @@ -15,4 +15,4 @@ maintainers: name: common sources: null type: library -version: 16.1.0 +version: 16.2.0 diff --git a/library/common/templates/class/_certificate.tpl b/library/common/templates/class/_certificate.tpl deleted file mode 100644 index 5178dc22..00000000 --- a/library/common/templates/class/_certificate.tpl +++ /dev/null @@ -1,45 +0,0 @@ -{{/* -This template serves as a blueprint for all Cert-Manager Certificate objects that are created -within the common library. -*/}} -{{- define "tc.v1.common.class.certificate" -}} -{{- $root := .root -}} -{{- $name := .name -}} -{{- $hosts := .hosts -}} -{{- $certificateIssuer := .certificateIssuer -}} -{{- $certificateSecretTemplate := .secretTemplate }} ---- -apiVersion: {{ include "tc.v1.common.capabilities.cert-manager.certificate.apiVersion" $ }} -kind: Certificate -metadata: - name: {{ $name }} - namespace: {{ $root.Values.namespace | default $root.Values.global.namespace | default $root.Release.Namespace }} -spec: - secretName: {{ $name }} - dnsNames: - {{- range $hosts }} - - {{ tpl . $root | quote }} - {{- end }} - privateKey: - algorithm: ECDSA - size: 256 - rotationPolicy: Always - issuerRef: - name: {{ tpl $certificateIssuer $root | quote }} - kind: ClusterIssuer - group: cert-manager.io - {{- if $certificateSecretTemplate }} - secretTemplate: - {{- $labels := (mustMerge ($certificateSecretTemplate.labels | default dict) (include "tc.v1.common.lib.metadata.allLabels" $root | fromYaml)) -}} - {{- with (include "tc.v1.common.lib.metadata.render" (dict "rootCtx" $root "labels" $labels) | trim) }} - labels: - {{- . | nindent 6 }} - {{- end -}} - {{- $annotations := (mustMerge ($certificateSecretTemplate.annotations | default dict) (include "tc.v1.common.lib.metadata.allAnnotations" $root | fromYaml)) -}} - {{- with (include "tc.v1.common.lib.metadata.render" (dict "rootCtx" $root "annotations" $annotations) | trim) }} - annotations: - {{- . | nindent 6 }} - {{- end -}} - {{- end -}} - -{{- end -}} diff --git a/library/common/templates/class/cert-manager/_certificate.tpl b/library/common/templates/class/cert-manager/_certificate.tpl new file mode 100644 index 00000000..d4a41687 --- /dev/null +++ b/library/common/templates/class/cert-manager/_certificate.tpl @@ -0,0 +1,59 @@ +{{/* Certificate Class */}} +{{/* Call this template: +{{ include "tc.v1.common.class.certificate" (dict "rootCtx" $ "objectData" $objectData) }} + +rootCtx: The root context of the chart. +objectData: + name: The name of the certificate. + labels: The labels of the certificate. + annotations: The annotations of the certificate. + namespace: The namespace of the certificate. (Optional) +*/}} +{{- define "tc.v1.common.class.certificate" -}} + + {{- $rootCtx := .rootCtx -}} + {{- $objectData := .objectData }} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ $objectData.name }} + namespace: {{ include "tc.v1.common.lib.metadata.namespace" (dict "rootCtx" $rootCtx "objectData" $objectData "caller" "Cert Manager Certificate") }} + {{- $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: + secretName: {{ $objectData.name }} + dnsNames: + {{- range $h := $objectData.hosts }} + - {{ tpl $h $rootCtx }} + {{- end }} + privateKey: + algorithm: ECDSA + size: 256 + rotationPolicy: Always + issuerRef: + name: {{ tpl $objectData.certificateIssuer $rootCtx }} + kind: ClusterIssuer + group: cert-manager.io + {{- if $objectData.certificateSecretTemplate }} + secretTemplate: + {{- $labels := (mustMerge ($objectData.certificateSecretTemplate.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 6 }} + {{- end -}} + {{- $annotations := (mustMerge ($objectData.certificateSecretTemplate.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 6 }} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/library/common/templates/lib/_tc_capabilities.tpl b/library/common/templates/lib/_tc_capabilities.tpl index 4d911dd8..c3e61706 100644 --- a/library/common/templates/lib/_tc_capabilities.tpl +++ b/library/common/templates/lib/_tc_capabilities.tpl @@ -22,8 +22,3 @@ {{- define "tc.v1.common.capabilities.hpa.apiVersion" -}} {{- print "autoscaling/v2" -}} {{- end -}} - -{{/* Return the appropriate apiVersion for Cert-Manager certificates */}} -{{- define "tc.v1.common.capabilities.cert-manager.certificate.apiVersion" -}} - {{- print "cert-manager.io/v1" -}} -{{- end -}} diff --git a/library/common/templates/lib/certificate/_validation.tpl b/library/common/templates/lib/certificate/_validation.tpl new file mode 100644 index 00000000..9e84d102 --- /dev/null +++ b/library/common/templates/lib/certificate/_validation.tpl @@ -0,0 +1,49 @@ +{{/* Certificate Validation */}} +{{/* Call this template: +{{ include "tc.v1.common.lib.certificate.validation" (dict "rootCtx" $ "objectData" $objectData) -}} +objectData: + rootCtx: The root context of the chart. + objectData: The Certificate object. +*/}} + +{{- define "tc.v1.common.lib.certificate.validation" -}} + {{- $rootCtx := .rootCtx -}} + {{- $objectData := .objectData -}} + + {{- if not $objectData.certificateIssuer -}} + {{- fail "Cert Manager Certificate - Expected non-empty [certificateIssuer]" -}} + {{- end -}} + + {{- if not $objectData.hosts -}} + {{- fail "Cert Manager Certificate - Expected non-empty [hosts]" -}} + {{- end -}} + + {{- if not (kindIs "slice" $objectData.hosts) -}} + {{- fail (printf "Cert Manager Certificate - Expected [hosts] to be a [slice], but got [%s]" (kindOf $objectData.hosts)) -}} + {{- end -}} + + {{- range $h := $objectData.hosts -}} + {{- if not $h -}} + {{- fail "Cert Manager Certificate - Expected non-empty entry in [hosts]" -}} + {{- end -}} + + {{- $host := tpl $h $rootCtx -}} + {{- if (hasPrefix "http://" $host) -}} + {{- fail (printf "Cert Manager Certificate - Expected entry in [hosts] to not start with [http://], but got [%s]" $host) -}} + {{- end -}} + {{- if (hasPrefix "https://" $host) -}} + {{- fail (printf "Cert Manager Certificate - Expected entry in [hosts] to not start with [https://], but got [%s]" $host) -}} + {{- end -}} + {{- if (contains ":" $host) -}} + {{- fail (printf "Cert Manager Certificate - Expected entry in [hosts] to not contain [:], but got [%s]" $host) -}} + {{- end -}} + + {{- with $objectData.certificateSecretTemplate -}} + {{- if and (not .labels) (not .annotations) -}} + {{- fail "Cert Manager Certificate - Expected [certificateSecretTemplate] to have at least one of [labels, annotations]" -}} + {{- end -}} + + {{- include "tc.v1.common.lib.metadata.validation" (dict "objectData" $objectData.certificateSecretTemplate "caller" "Cert Manager Certificate (certificateSecretTemplate)") -}} + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/library/common/templates/spawner/_certificate.tpl b/library/common/templates/spawner/_certificate.tpl deleted file mode 100644 index 0dd53528..00000000 --- a/library/common/templates/spawner/_certificate.tpl +++ /dev/null @@ -1,27 +0,0 @@ -{{/* Renders the certificate objects required by the chart */}} -{{- define "tc.v1.common.spawner.certificate" -}} - {{- $fullname := include "tc.v1.common.lib.chart.names.fullname" $ -}} - - {{/* Generate named certs as required */}} - {{- range $name, $cert := .Values.cert -}} - {{- if $cert.enabled -}} - {{- $certValues := $cert -}} - {{- $certName := $fullname -}} - - {{/* set defaults */}} {{/* FIXME: the primary template does not exist */}} - {{- if and (not $certValues.nameOverride) (ne $name (include "tc.v1.common.lib.util.cert.primary" $)) -}} - {{- $_ := set $certValues "nameOverride" $name -}} - {{- end -}} - - {{- if $certValues.nameOverride -}} - {{- $certName = printf "%v-%v" $certName $certValues.nameOverride -}} - {{- end -}} - - {{- if $certValues.secretTemplate -}} - {{- $certName = printf "%v-%v" "clusterissuer-templated" $name -}} - {{- end -}} - - {{- include "tc.v1.common.class.certificate" (dict "root" $ "name" $certName "certificateIssuer" $cert.certificateIssuer "hosts" $cert.hosts "secretTemplate" $cert.secretTemplate ) -}} - {{- end -}} - {{- end -}} -{{- end -}} diff --git a/library/common/templates/spawner/cert-manager/_certificate.tpl b/library/common/templates/spawner/cert-manager/_certificate.tpl new file mode 100644 index 00000000..92389382 --- /dev/null +++ b/library/common/templates/spawner/cert-manager/_certificate.tpl @@ -0,0 +1,44 @@ +{{/* Certificate Spawner */}} +{{/* Call this template: +{{ include "tc.v1.common.spawner.priorityclass" $ -}} +*/}} + +{{- define "tc.v1.common.spawner.certificate" -}} + {{- $fullname := include "tc.v1.common.lib.chart.names.fullname" $ -}} + + {{- range $name, $cert := .Values.certificate -}} + + {{- $enabled := (include "tc.v1.common.lib.util.enabled" (dict + "rootCtx" $ "objectData" $cert + "name" $name "caller" "Cert Manager Certificate" + "key" "certificate")) -}} + {{- if eq $enabled "true" -}} + {{- $objectData := (mustDeepCopy $cert) -}} + + {{- $objectName := (printf "%s-%s" $fullname $name) -}} + {{- if hasKey $objectData "expandObjectName" -}} + {{- if not $objectData.expandObjectName -}} + {{- $objectName = $name -}} + {{- end -}} + {{- end -}} + + {{/* If a certificateSecretTemplate is defined, adjust name */}} + {{- if $objectData.certificateSecretTemplate }} + {{- $objectName = printf "certificate-issuer-%s" $name -}} + {{- end -}} + + {{/* Perform validations */}} + {{- include "tc.v1.common.lib.chart.names.validation" (dict "name" $objectName "length" 253) -}} + {{- include "tc.v1.common.lib.metadata.validation" (dict "objectData" $objectData "caller" "Cert Manager Certificate") -}} + {{- include "tc.v1.common.lib.certificate.validation" (dict "rootCtx" $ "objectData" $objectData) -}} + + {{/* Set the name of the secret */}} + {{- $_ := set $objectData "name" $objectName -}} + {{- $_ := set $objectData "shortName" $name -}} + + {{/* Call class to create the object */}} + {{- include "tc.v1.common.class.certificate" (dict "rootCtx" $ "objectData" $objectData) -}} + + {{- end -}} + {{- end -}} +{{- end -}} diff --git a/library/common/values.yaml b/library/common/values.yaml index ffa44111..b1abdcda 100644 --- a/library/common/values.yaml +++ b/library/common/values.yaml @@ -607,6 +607,17 @@ ingress: custom: - somesetting: some value +certificate: {} + # main: + # enabled: false + # certificateIssuer: someissuer + # hosts: + # - somehost + # # Optional + # certificateSecretTemplate: + # labels: {} + # annotations: {} + # -- BETA: Configure the gateway routes for the chart here. # Additional routes can be added by adding a dictionary key similar to the 'main' route. # Please be aware that this is an early beta of this feature, TrueCharts does not guarantee this actually works. From a0e766ac50f7b0a32090f28aca8ae8f28013c084 Mon Sep 17 00:00:00 2001 From: Stavros Kois <47820033+stavros-k@users.noreply.github.com> Date: Fri, 8 Dec 2023 16:49:48 +0200 Subject: [PATCH 8/9] feat(ingress): finish ingress cert options (#627) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Description** ⚒️ Fixes # **⚙️ Type of change** - [x] ⚙️ Feature/App addition - [x] 🪛 Bugfix - [ ] ⚠️ Breaking change (fix or feature that would cause existing functionality to not work as expected) - [x] 🔃 Refactor of current code **🧪 How Has This Been Tested?** **📃 Notes:** **✔️ Checklist:** - [x] ⚖️ My code follows the style guidelines of this project - [x] 👀 I have performed a self-review of my own code - [x] #️⃣ I have commented my code, particularly in hard-to-understand areas - [ ] 📄 I have made corresponding changes to the documentation - [x] ⚠️ My changes generate no new warnings - [x] 🧪 I have added tests to this description that prove my fix is effective or that my feature works - [ ] ⬆️ I increased versions for any altered app according to semantic versioning **➕ App addition** If this PR is an app addition please make sure you have done the following. - [ ] 🪞 I have opened a PR on [truecharts/containers](https://github.com/truecharts/containers) adding the container to TrueCharts mirror repo. - [ ] 🖼️ I have added an icon in the Chart's root directory called `icon.png` --- _Please don't blindly check all the boxes. Read them and only check those that apply. Those checkboxes are there for the reviewer to see what is this all about and the status of this PR with a quick glance._ --- .../common-test/tests/ingress/tls_test.yaml | 97 ++++++++++++++++++- .../tests/ingress/validation_test.yaml | 6 +- library/common/Chart.yaml | 2 +- library/common/templates/class/_ingress.tpl | 4 +- .../templates/lib/ingress/_validation.tpl | 9 +- library/common/templates/spawner/_ingress.tpl | 23 ++++- 6 files changed, 127 insertions(+), 14 deletions(-) diff --git a/library/common-test/tests/ingress/tls_test.yaml b/library/common-test/tests/ingress/tls_test.yaml index 089ef69f..3cff336a 100644 --- a/library/common-test/tests/ingress/tls_test.yaml +++ b/library/common-test/tests/ingress/tls_test.yaml @@ -148,7 +148,7 @@ tests: - some-other-test-host secretName: test-release-name-common-test-scale-tls-1 - - it: should pass with ingress created with tls with certificateIssuer + - it: should pass with ingress created with clusterCertificate set: operator: *operator service: *service @@ -167,10 +167,58 @@ tests: - hosts: - test-host - other-test-host + clusterCertificate: some-cert + - hosts: + - some-other-test-host + clusterCertificate: some-other-cert + integrations: &integrations + traefik: + enabled: false + asserts: + - documentIndex: &ingressDoc 1 + isKind: + of: Ingress + - documentIndex: *ingressDoc + equal: + path: metadata.name + value: test-release-name-common-test + - documentIndex: *ingressDoc + equal: + path: spec.tls + value: + - hosts: + - test-host + - other-test-host + secretName: certificate-issuer-some-cert + - hosts: + - some-other-test-host + secretName: certificate-issuer-some-other-cert + + - it: should pass with ingress created with tls with certificateIssuer + set: + operator: *operator + service: *service + otherhost: other-test-host + othercertissuer: some-other-issuer + ingress: + my-ingress: + enabled: true + primary: true + hosts: + - host: test-host + paths: + - path: /test-path + - host: other-test-host + paths: + - path: /other-test-path + tls: + - hosts: + - test-host + - "{{ .Values.otherhost }}" certificateIssuer: some-issuer - hosts: - some-other-test-host - certificateIssuer: some-other-issuer + certificateIssuer: "{{ .Values.othercertissuer }}" integrations: &integrations traefik: enabled: false @@ -193,3 +241,48 @@ tests: - hosts: - some-other-test-host secretName: test-release-name-common-test-tls-1 + - documentIndex: &certDoc 2 + isKind: + of: Certificate + - documentIndex: *certDoc + equal: + path: metadata.name + value: test-release-name-common-test-tls-0 + - documentIndex: *certDoc + equal: + path: spec.secretName + value: test-release-name-common-test-tls-0 + - documentIndex: *certDoc + isSubset: + path: spec + content: + secretName: test-release-name-common-test-tls-0 + dnsNames: + - test-host + - other-test-host + issuerRef: + name: some-issuer + kind: ClusterIssuer + group: cert-manager.io + - documentIndex: &otherCertDoc 3 + isKind: + of: Certificate + - documentIndex: *otherCertDoc + equal: + path: metadata.name + value: test-release-name-common-test-tls-1 + - documentIndex: *otherCertDoc + equal: + path: spec.secretName + value: test-release-name-common-test-tls-1 + - documentIndex: *otherCertDoc + isSubset: + path: spec + content: + secretName: test-release-name-common-test-tls-1 + dnsNames: + - some-other-test-host + issuerRef: + name: some-other-issuer + kind: ClusterIssuer + group: cert-manager.io diff --git a/library/common-test/tests/ingress/validation_test.yaml b/library/common-test/tests/ingress/validation_test.yaml index bd7dd62c..23d7e3bb 100644 --- a/library/common-test/tests/ingress/validation_test.yaml +++ b/library/common-test/tests/ingress/validation_test.yaml @@ -584,10 +584,10 @@ tests: - hosts: - test-host secretName: test-secret - scaleCert: "1" + clusterCertificate: some-cert asserts: - failedTemplate: - errorMessage: Ingress - Expected only one of [scaleCert, secretName] to be set, but got [scaleCert, secretName] + errorMessage: Ingress - Expected only one of [scaleCert, secretName, certificateIssuer, clusterCertificate] to be set, but got [secretName, clusterCertificate] - it: should fail with scaleCert outside of SCALE set: @@ -604,4 +604,4 @@ tests: scaleCert: "1" asserts: - failedTemplate: - errorMessage: Ingress - [tls.scalecert] can only be used in TrueNAS SCALE + errorMessage: Ingress - [tls.scaleCert] can only be used in TrueNAS SCALE diff --git a/library/common/Chart.yaml b/library/common/Chart.yaml index 24a1ebea..7543edd2 100644 --- a/library/common/Chart.yaml +++ b/library/common/Chart.yaml @@ -15,4 +15,4 @@ maintainers: name: common sources: null type: library -version: 16.2.0 +version: 16.2.1 diff --git a/library/common/templates/class/_ingress.tpl b/library/common/templates/class/_ingress.tpl index 6e925721..08bcbea4 100644 --- a/library/common/templates/class/_ingress.tpl +++ b/library/common/templates/class/_ingress.tpl @@ -78,10 +78,10 @@ spec: {{- $secretName = tpl $t.secretName $rootCtx -}} {{- else if $t.scaleCert -}} {{- $secretName = printf "%s-scale-tls-%d" $objectData.name ($idx | int) -}} - {{- else if $t.certificateIssuer -}} + {{- else if $t.certificateIssuer -}} {{/* TODO: UT */}} {{- $secretName = printf "%s-tls-%d" $objectData.name ($idx | int) -}} {{- else if $t.clusterCertificate -}} - {{/* TODO: Needs the refactor of Certificate object */}} + {{- $secretName = printf "certificate-issuer-%s" (tpl $t.clusterCertificate $rootCtx) -}} {{- end }} - secretName: {{ $secretName }} hosts: diff --git a/library/common/templates/lib/ingress/_validation.tpl b/library/common/templates/lib/ingress/_validation.tpl index 216ef5e9..cee39de0 100644 --- a/library/common/templates/lib/ingress/_validation.tpl +++ b/library/common/templates/lib/ingress/_validation.tpl @@ -96,6 +96,12 @@ objectData: {{- end -}} {{- range $t := $objectData.tls -}} + {{- if $t.scaleCert -}} + {{- if not $rootCtx.Values.global.ixChartContext -}} + {{- fail "Ingress - [tls.scaleCert] can only be used in TrueNAS SCALE" -}} + {{- end -}} + {{- end -}} + {{- if not $t.hosts -}} {{- fail "Ingress - Expected non-empty [tls.hosts]" -}} {{- end -}} @@ -121,8 +127,7 @@ objectData: {{- end -}} {{- end -}} - {{/* TODO: Add the rest of the options?! */}} - {{- $certOptions := (list "scaleCert" "secretName") -}} + {{- $certOptions := (list "scaleCert" "secretName" "certificateIssuer" "clusterCertificate") -}} {{- $optsSet := list -}} {{- range $opt := $certOptions -}} {{- if (get $t $opt) -}} diff --git a/library/common/templates/spawner/_ingress.tpl b/library/common/templates/spawner/_ingress.tpl index cadf12ca..cd019f95 100644 --- a/library/common/templates/spawner/_ingress.tpl +++ b/library/common/templates/spawner/_ingress.tpl @@ -67,7 +67,7 @@ {{- range $idx, $tlsData := $objectData.tls -}} {{- if $tlsData.scaleCert -}} {{- if not $.Values.global.ixChartContext -}} - {{- fail "Ingress - [tls.scalecert] can only be used in TrueNAS SCALE" -}} + {{- fail "Ingress - [tls.scaleCert] can only be used in TrueNAS SCALE" -}} {{- end -}} {{- $certData := (include "tc.v1.common.lib.scaleCertificate.getData" (dict "rootCtx" $ "objectData" (dict "id" $tlsData.scaleCert)) | fromJson) -}} @@ -80,13 +80,28 @@ ) -}} {{- include "tc.v1.common.lib.chart.names.validation" (dict "name" $certName) -}} + {{- include "tc.v1.common.lib.metadata.validation" (dict "objectData" $certObjData "caller" "Ingress (scaleCert)") -}} {{- include "tc.v1.common.lib.scaleCertificate.validation" (dict "objectData" $certObjData) -}} - {{- include "tc.v1.common.lib.metadata.validation" (dict "objectData" $certObjData "caller" "Ingress") -}} {{/* Create the secret with the certData */}} {{- include "tc.v1.common.class.secret" (dict "rootCtx" $ "objectData" $certObjData) -}} - {{- else if $tlsData.clusterCertificate -}} - {{/* TODO: Needs the refactor of Certificate object */}} + + {{- else if $tlsData.certificateIssuer -}} + {{- $certName := printf "%s-tls-%d" $objectData.name ($idx | int) -}} + + {{- $certObjData := (dict + "name" $certName "shortName" $name + "hosts" $tlsData.hosts + "certificateIssuer" $tlsData.certificateIssuer + ) -}} + + {{- include "tc.v1.common.lib.chart.names.validation" (dict "name" $certName) -}} + {{- include "tc.v1.common.lib.metadata.validation" (dict "objectData" $certObjData "caller" "Ingress (certificateIssuer)") -}} + {{- include "tc.v1.common.lib.certificate.validation" (dict "rootCtx" $ "objectData" $certObjData) -}} + + {{/* Create the certificate with the certData */}} + {{- include "tc.v1.common.class.certificate" (dict "rootCtx" $ "objectData" $certObjData) -}} + {{- end -}} {{- end -}} {{- end -}} From 676f9f476505eac717156e20896b619f1888a7dd Mon Sep 17 00:00:00 2001 From: Stavros Kois <47820033+stavros-k@users.noreply.github.com> Date: Fri, 8 Dec 2023 16:50:27 +0200 Subject: [PATCH 9/9] bump --- library/common/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/common/Chart.yaml b/library/common/Chart.yaml index 7543edd2..0b25e2f6 100644 --- a/library/common/Chart.yaml +++ b/library/common/Chart.yaml @@ -15,4 +15,4 @@ maintainers: name: common sources: null type: library -version: 16.2.1 +version: 16.2.2