Search code examples
kubernetes-helm

Building a String with Helm Named Template


I'd like to leverage a named template in a helm chart to build a string whose value ultimately is going to be the aws-load-balancer-controller annotation for alb.ingress.kubernetes.io/certificate-arn, which is just a comma separated list of applicable ACM certs.

In my values.yaml I support override for additional certs as an object like this:

# in values.yaml as default
ingress.additional_certs: {}

# as an override of the above:
ingress.additonal_certs:
  - arn: "arn:aws:acm:us-west-2:xxxxxxxxxxx:certificate/357ac969-643b-4424-a028-57183e02a765"
    host: "somedomain.sub.com"
  - arn: "arn:aws:acm:us-west-2:xxxxxxxxxxx:certificate/357ac969-643b-4424-a028-57183e02a764"
    host: "someotherdomain.foo.com"

The idea is you're likely going to have a different cert for each domain, so it's easier for the end user to keep track of what goes to what. By calling the override "additional_certs", it follows there's a default ACM cert used so anything under "additional_certs" is just tacked on to the annotation string and also enumerated properly under ingress.spec.rules.

The problem I'm having a lot of trouble wrapping my head around is how I can take a base string (in this case, the default ACM ARN) and build onto it. Conceptually this is just a simple string building exercise, for example:

# in pseudocode
var cert_arns = "arn:aws:acm:us-west-2:xxxxxxxxxxx:certificate/357ac969-643b-4424-a028-57183e02a761"

cert_arns += "," + ingress.additional_certs.arn[0]
# so cert_arns ostensibly becomes "arn:aws:acm:us-west-2:xxxxxxxxxxx:certificate/357ac969-643b-4424-a028-57183e02a761,arn:aws:acm:us-west-2:xxxxxxxxxxx:certificate/357ac969-643b-4424-a028-57183e02a765"

To be frank, I'm not even sure how to try doing this with a named template. Most examples using range tend to be for looping over filling in yaml like labels. How one would go about simply iterating over a range and tacking on the value (in this case it'd be something like range $k, $v := .Values.ingress.additional_certs, so $v.arn) simply isn't clicking and I haven't stumbled across any examples of doing string building.

If there are better methods of accomplishing this that isn't a named template I'm all ears.


Solution

  • Helm has concepts of "lists" and "dictionaries", but there aren't a lot of manipulation functions that work on them. You could imagine wanting to construct a list of all of the arn values and then joining that list together with commas, for example, but with a dynamic-length list this turns out to be a little beyond what Helm's extension functions provide.

    For a sufficiently short list (the couple of items you'd configure in a values.yaml file would be fine) you can write a recursive function. Remember that Helm templates don't "return values" per se, they output text and include collects that output text. You could write a recursive template like:

    {{- define "cert-arns" -}}
      {{- if . -}}
        {{- (first .).arn -}}
        {{- include "cert-arns.more" (rest .) -}}
      {{- end -}}
    {{- end -}}
    
    {{- define "cert-arns.more" -}}
      {{- if . -}}
        ,{{- (first .).arn -}}
        {{- include "cert-arns.more" (rest .) -}}
      {{- end -}}
    {{- end -}}
    
    {{- include "cert-arns" (index .Values "ingress.additional_certs") -}}
    

    Note the comma in the fourth-to-last line; that is not a typo. I've indented everything for clarity but also note that the - inside the curly braces suppresses all of the whitespace.