J'ai des problèmes pour parcourir une liste d'objets dans un modèle interprété par la fonction templatefile.

J'ai la var suivante:

variable "destinations" {
  description = "A list of EML Channel Destinations."

  type = list(object({
    id  = string
    url = string
  }))
}

Ceci est passé à la fonction templatefile en tant que destinations. L'extrait de modèle pertinent est le suivant:

Destinations:
  %{ for dest in destinations ~}
  - Id: ${dest.id}
    Settings:
      URL: ${dest.url}
  %{ endfor }

Lors de la planification de Terraform, cela donne une erreur de:

Error: "template_body" contains an invalid YAML: yaml: line 26: did not find expected key

J'ai essayé de changer le code du modèle comme suit:

Destinations:
  %{ for id, url in destinations ~}
  - Id: ${id}
    Settings:
      URL: ${url}
  %{ endfor }

Ce qui donne une erreur différente:

Call to function "templatefile" failed:
../../local-tfmodules/eml/templates/eml.yaml.tmpl:25,20-23: Invalid template
interpolation value; Cannot include the given value in a string template:
string required., and 2 other diagnostic(s).

[!] something went wrong when creating the environment TF plan

J'ai l'impression que mon itération sur le type de données ici est en quelque sorte incorrecte, mais je ne peux pas comprendre comment et je ne trouve aucune documentation à ce sujet.

Voici un exemple simplifié de la façon dont j'appelle ce module:

module "eml" {
  source = "../../local-tfmodules/eml"

  name = "my_eml"

  destinations = [
    {
      id  = "6"
      url = "https://example.com"
    },
    {
      id  = "7"
      url = "https://example.net"
    }
  ]
<cut>
}
3
Danny Roberts 2 nov. 2020 à 21:32

3 réponses

Meilleure réponse

Je viens de découvrir (après avoir créé un petit module Terraform pour tester uniquement la sortie templatefile) que la configuration d'origine fonctionne (au moins dans TF v0.12.29).

Les erreurs données sont un peu un Red Herring - le problème est lié à l'indentation dans le modèle, par exemple au lieu de:

Destinations:
  %{ for destination in destinations  ~}
  - Id: ${destination.id}
    Settings:
      URL: ${destination.url}
  %{ endfor ~}

Ça devrait être:

Destinations:
  %{~ for destination in destinations  ~}
  - Id: ${destination.id}
    Settings:
      URL: ${destination.url}
  %{~ endfor ~}

Notez le tilde supplémentaire (~) au début des directives Terraform. Cela rend l'alignement Yaml fonctionne correctement (vous obtenez des lignes mal indentées et des lignes vides). Après cela, le code original de ma question fonctionne comme je m'y attendais & amp; produit un yaml valide.

0
Danny Roberts 3 nov. 2020 à 12:43

Vous ne pouvez pas transmettre var.destinations comme liste de cartes au modèle. Il doit s'agir d'une liste / d'un ensemble de chaînes.

Mais vous pouvez faire ce qui suit:

templatefile("eml.yaml.tmpl", 
          { 
            ids =  [for v in var.destinations: v.id]
            urls =  [for v in var.destinations: v.url] 
          }
    )

eml.yaml.tmpl est

Destinations:
  %{ for id, url in zipmap(ids, urls)  ~}
  - Id: ${id}
    Settings:
      URL: ${url}
  %{ endfor ~}
1
Marcin 3 nov. 2020 à 01:12

Puisque vous souhaitez générer un résultat YAML, je vous suggère de suivre les conseils de le { {X0}} documentation sur générer JSON ou YAML à partir d'un modèle.

L'utilisation de la yamlencode fonction garantira que le résultat est YAML toujours valide, sans que vous ayez à vous soucier du positionnement correct des nouvelles lignes ou des guillemets / échappements de chaînes pouvant contenir des caractères spéciaux.

Rédigez votre appel templatefile comme ceci:

templatefile("${path.module}/templates/eml.yaml.tmpl", {
  destinations = var.destinations
})

Ensuite, dans eml.yaml.tmpl, faites en sorte que le modèle entier soit le résultat de l'appel de yamlencode, comme ceci:

${yamlencode({
  Destinations = [
    for dest in destinations : {
      Id = dest.id
      Settings = {
        URL = dest.url
      }
    }
  ]
})

Notez que l'argument de yamlencode est syntaxe d'expression Terraform plutôt que Syntaxe YAML, car dans ce cas il est de la responsabilité de Terraform de faire l'encodage YAML, et tout ce que vous avez à faire est de fournir une valeur appropriée pour Terraform à encoder, en suivant les mappages des types Terraform aux types YAML donnés dans la documentation yamldecode .

0
Martin Atkins 6 nov. 2020 à 01:53