Terraform-provider-helm: Escaping periods in release set names

Created on 11 Apr 2018  Â·  19Comments  Â·  Source: hashicorp/terraform-provider-helm

I've a fleet of services that will all need ingress annotations. For example this an attempt to get traefik-dashboard to use traefik:

set {
  name = "dashboard.ingress.annotations.kubernetes.io/ingress.class"
  value = "traefik"
}

This results in:

apiVersion: v1
items:
- apiVersion: extensions/v1beta1
  kind: Ingress
  metadata:
    annotations:
      kubernetes: map[io/ingress:map[class:traefik]]

This problem isn't unique to terraform-helm-provider. The helm command line client provides a --set-string option to handle similar.

Most helpful comment

Sorry for resurrecting an old thread but the magic escape syntax is eg.

  set {
    name  = "web.ingresss.annotations.\"kubernetes\\.io/ingress\\.class\""
    value = "nginx"
  }

All 19 comments

The command line flag is ... hard to find. See here:
https://github.com/kubernetes/helm/blob/master/cmd/helm/install.go#L195

I started working on this, your comments helped a lot.

resource_release.go contains this code and the parsing seems to be analogous to some parsing from helm's code:

    for _, raw := range d.Get("set").(*schema.Set).List() {
        set := raw.(map[string]interface{})

        name := set["name"].(string)
        value := set["value"].(string)

        if err := strvals.ParseInto(fmt.Sprintf("%s=%s", name, value), base); err != nil {
            return nil, fmt.Errorf("failed parsing key %q with value %s, %s", name, value, err)
        }
    }

https://github.com/kubernetes/helm/blob/9654c616c2538530aa8d2388a150eeb31e040851/cmd/helm/install.go#L357

    // User specified a value via --set
    for _, value := range values {
        if err := strvals.ParseInto(value, base); err != nil {
            return []byte{}, fmt.Errorf("failed parsing --set data: %s", err)
        }
    }

    // User specified a value via --set-string
    for _, value := range stringValues {
        if err := strvals.ParseIntoString(value, base); err != nil {
            return []byte{}, fmt.Errorf("failed parsing --set-string data: %s", err)
        }
    }

so i tried adding a setString method like this:

func resourceRelease() *schema.Resource {
    return &schema.Resource{
        Create: resourceReleaseCreate,
        Read:   resourceReleaseRead,
        Delete: resourceReleaseDelete,
        Update: resourceReleaseUpdate,
        Exists: resourceReleaseExists,
        Schema: map[string]*schema.Schema{
            "name": {
                Type:        schema.TypeString,
                Required:    true,
                ForceNew:    true,
                Description: "Release name.",
            },
            "repository": {
                Type:        schema.TypeString,

... ... ... ... ...
            "setString": {
                Type:        schema.TypeSet,
                Optional:    true,
                Description: "Custom values to be merge with the values.",
                Elem: &schema.Resource{
                    Schema: map[string]*schema.Schema{
                        "name": {
                            Type:     schema.TypeString,
                            Required: true,
                        },
                        "value": {
                            Type:     schema.TypeString,
                            Required: true,
                        },
                    },
                },
            },
    for _, raw := range d.Get("setString").(*schema.Set).List() {
        set := raw.(map[string]interface{})

        name := set["name"].(string)
        value := set["value"].(string)

        if err := strvals.ParseIntoString(fmt.Sprintf("%s=%s", name, value), base); err != nil {
            return nil, fmt.Errorf("failed parsing key %q with value %s, %s", name, value, err)
        }
    }

but I get an exec error when its applied.

OH you'll also need to replace vendor/k8s.io/helm/pkg/strvals with the up to date code:
https://github.com/kubernetes/helm/tree/e269b89438dd64e7afbaef8891d575b72f132084/pkg/strvals

Same problems here, is there any workaround, guys?

The workaround I'm using is a HEREDOC:

  values = [
    <<-EOF
    replicaCount: 1
    image:
      repository: nginx
      env:
        SOME_VAR: "SOME_VALUE"
    EOF
  ]

@dangarthwaite thank you. Unfortunately I cannot control chart's sources.
I'm trying to install stable/minio chart, and enable let's encrypt in ingress.
Ingress templates looks like this:

{{- with .Values.ingress.annotations }}
  annotations:
{{ toYaml . | indent 4 }}
{{- end }}

So my main.tf file has the following:

    set {
        name  = "ingress.annotations.\"kubernetes\\.io/tls-acme\""
        value = "true"
    }

I tried many conbinations of escaping, but none of them works.

You can cut and paste the whole yaml section from values.yaml:

values = [
  <<-EOF
    ingress:
      enabled: true
      annotations: {}
        kubernetes.io/ingress.class: nginx
        kubernetes.io/tls-acme: "true"
      path: /
      hosts:
        - minion.example.com
      tls: []
  EOF
]

@dangarthwaite thank you very much. You saved my day.

Fixed in: https://github.com/mcuadros/terraform-provider-helm/pull/74
Introduces a set_string option that works like helm's set-string.

@stevenaldinger Should this issue be closed?

I think it can be, yeah. I'm not a golang person so I'm not sure if I did anything stupid/introduced anything to worry about with the fix but I haven't run into issues on that branch/PR yet.

Thanks.

I got annoyed with how difficult this is to work with so am publicly hosting the linux binary for an up-to-date version in one of my buckets, community is more than welcome to use it if you're fighting this problem too and don't want to deal with local builds.

curl -Lo "/tmp/terraform-provider-helm.tar.gz" \
  https://storage.googleapis.com/steven-aldinger/terraform-provider-helm_v0.5.3_linux_amd64.tar.gz

Sorry for resurrecting an old thread but the magic escape syntax is eg.

  set {
    name  = "web.ingresss.annotations.\"kubernetes\\.io/ingress\\.class\""
    value = "nginx"
  }

@jgrau Awesome. Thanks.

Any reason to reopen this, @dangarthwaite?

No reason to reopen. Use set_string, not set and it should escape
things.

On Fri, Feb 8, 2019, 10:38 AM Rafael Porres Molina <[email protected]
wrote:

Any reason to reopen this, @dangarthwaite
https://github.com/dangarthwaite?

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/terraform-providers/terraform-provider-helm/issues/64#issuecomment-461843329,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ALQ35ogAdA2NuryCap0GbMUscbs7Q94aks5vLZn_gaJpZM4TQeCw
.

@dangarthwaite I tried your workaroudn with the HEREDOC:

`resource "helm_release" "prometheus-operator" {
name = "prometheus-operator"
chart = "stable/prometheus-operator"
namespace = "monitoring"

set_string {
  name = "prometheus.prometheusSpec.storageSpec"
  value = [
    <<EOF
     volumeClaimTemplate:
       spec:
         storageClassName: ssd
         accessModes: ["ReadWriteOnce"]
         resources:
           requests:
             storage: 50Gi
       selector: {}
  EOF
]
}

}
`

I get this:
helm_release.prometheus-operator: set_string.0.value must be a single value, not a list

@syst0m In that case you should use values param instead of the set_string, for example:

resource "helm_release" "prometheus-operator" {
  name = "prometheus-operator"
  chart = "stable/prometheus-operator"
  namespace = "monitoring"

  values = [
    <<-EOF
    prometheus:
      prometheusSpec:
        storageSpec:
          volumeClaimTemplate:
              spec:
              storageClassName: ssd
              accessModes: ["ReadWriteOnce"]
              resources:
                  requests:
                  storage: 50Gi
              selector: {}
    EOF
  ]
}

Just a note to anyone else that might encounter this issue. For us it was Grafana and it's values.yaml for setting up generic_oauth looks something like this:

grafana.ini:
  auth.generic_oauth:
     client_secret: XXX

We tried all proposed solutions but none of them worked. In the end we figured out that only dots need to be escaped and the key is set properly using any of the set* blocks.

name = "grafana\\.ini.auth\\.generic_oauth.client_secret"
Was this page helpful?
0 / 5 - 0 ratings