vidispine / hull

The incredible HULL - Helm Uniform Layer Library - is a Helm library chart to improve Helm chart based workflows
https://github.com/vidispine/hull
Apache License 2.0
213 stars 12 forks source link

Something is wrong when using a transformation in hull.objects.ingress.*.tls.*.hosts #272

Closed khmarochos closed 9 months ago

khmarochos commented 9 months ago

Hello again,

It seems that I've found another interesting phenomenon.

Let's assume we have the following values.yaml:

hull:
  objects:
    ingress:
      test:
        rules:
          default:
            host: example.org
            http:
              paths:
                root:
                  path: /
                  pathType: Prefix
                  backend:
                    service:
                      name: test
                      port:
                        name: http
        tls:
          default:
            hosts:
              - example.org
            secretName: tls-certificate

Everything seems to be fine in this case, we get the following Ingress object:

kind: Ingress
metadata:
  annotations: {}
  labels:
    app.kubernetes.io/component: test
    app.kubernetes.io/instance: test
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: hull-test-3
    app.kubernetes.io/part-of: undefined
    app.kubernetes.io/version: 0.0.0
    helm.sh/chart: hull-test-3-0.0.0
  name: test-hull-test-3-test
  namespace: default
spec:
  rules:
  - host: example.org
    http:
      paths:
      - backend:
          service:
            name: test-hull-test-3-test
            port:
              name: http
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - example.org
    secretName: test-hull-test-3-tls-certificate

The spec.tls part is valid.

But when we try to use a transformation in hull.objects.ingress.*.tls.*.hosts, we have something different.

Here's values.yaml:

hull:
  objects:
    ingress:
      test:
        rules:
          default:
            host: example.org
            http:
              paths:
                root:
                  path: /
                  pathType: Prefix
                  backend:
                    service:
                      name: test
                      port:
                        name: http
        tls:
          default:
            hosts:
              - _HT/util.domainNames.getIngressHostname
            secretName: tls-certificate

The templates/_domain_names.tpl module is simple and straightforward:

{{- define "util.domainNames.getIngressHostname" -}}
example.org
{{- end -}}

In this case we have the following result:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations: {}
  labels:
    app.kubernetes.io/component: test
    app.kubernetes.io/instance: test
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: hull-test-3
    app.kubernetes.io/part-of: undefined
    app.kubernetes.io/version: 0.0.0
    helm.sh/chart: hull-test-3-0.0.0
  name: test-hull-test-3-test
  namespace: default
spec:
  rules:
  - host: example.org
    http:
      paths:
      - backend:
          service:
            name: test-hull-test-3-test
            port:
              name: http
        path: /
        pathType: Prefix
  tls:
  - hosts: example.org
    secretName: test-hull-test-3-tls-certificate

The spec.tls structure is wrong: the hosts parameter has become a string instead of being an array.

What do you think, why does it happen?

Thank you!

khmarochos commented 9 months ago

I changed _HT/util.domainNames.getIngressHostname to _HT/hosts/util.domainNames.getIngressHostname in values.yaml:

hull:
  objects:
    ingress:
      test:
        rules:
          default:
            host: example.org
            http:
              paths:
                root:
                  path: /
                  pathType: Prefix
                  backend:
                    service:
                      name: test
                      port:
                        name: http
        tls:
          default:
            hosts: _HT/hosts/util.domainNames.getIngressHostname
            secretName: tls-certificate

templates/_domain_names.tpl:

{{- define "util.domainNames.getIngressHostname" -}}
hosts:
- example.org
{{- end -}}

The result:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations: {}
  labels:
    app.kubernetes.io/component: test
    app.kubernetes.io/instance: test
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: hull-test-3
    app.kubernetes.io/part-of: undefined
    app.kubernetes.io/version: 0.0.0
    helm.sh/chart: hull-test-3-0.0.0
  name: test-hull-test-3-test
  namespace: default
spec:
  rules:
  - host: example.org
    http:
      paths:
      - backend:
          service:
            name: test-hull-test-3-test
            port:
              name: http
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - example.org
    secretName: test-hull-test-3-tls-certificate

But why does it work this way (when I use a transformation for the whole spec.tls.hosts) and doesn't work that way (when I use a transformation for one element of spec.tls.hosts only)?

gre9ory commented 9 months ago

Hi @khmarochos,

this one I think I can explain quickly.

As discuessed in more detail in this issue comment the following is equivalent for an array like hosts:

              hosts:
                - _HT ... 
              hosts: _HT ...

The syntax where the transformation is the first (and only) element of an array stems from the beginnings of this project when there was no full support for using _HT transformation strings everywhere. Supporting this involved a lot of work on the JSON schema of which I wasn't sure it's gonna work out (which it did in the end). So when the schema demanded an array this trick was used to input an array and still get the transformation triggered (returning in turn an array) and this is still valid.

Regarding arrays the transformations cannot be applied to individual array elements, you always need to return the full array. Being able to transform individual array elements would have raised already existing complexity significantly when evaluating these transformations and I decided against pursuing this. For my usecases it was sofar also always sufficient to return full arrays always when I needed to run transformations on arrays.

I hope this also explains why you got a string back in both cases: your transformation result in both ways of triggering the transformation serves as the hosts value. So when the transformation delivers a string, result is a string in both cases.


To solve your scenario the solution is to return an array for hosts and use either way of transformation triggering. As always let me know if you need help with that - but I am sure you figure this one out, it is same as with the imagePullSecrets essentially.

khmarochos commented 9 months ago

Thank you very much for the detailed explanation (and, again, for the great tool you've made)!

If I had been more careful, I would have found #237 without bothering you. If I had been smarter, I would have found the answer in the source code.