Using a terraform template to produce a cloud-init yaml: template variables do not respect yaml context/whitespace



  • I am using Terraform. Terraform has a notion https://www.terraform.io/language/functions/templatefile which can be used to take variables that Terraform has access to (locally supplied or retrieved externally) and to apply them to a Jinja2 template. https://learn.hashicorp.com/tutorials/terraform/cloud-init .

    People use these templates to generate cloud-init files with Jinja2 templates. Here is a snipped of the template,

    ssh_keys:
        ecdsa_private: "${ssh_ecdsa_key_private}"
    

    Then these variables get set in Terraform, like this,

    data "template_file" "user_data" {
      template = templatefile(
        "cloud/cloud.cfg",
        {
          ssh_ecdsa_key_private  = file("./ssh/acme-bitbucket-id_ecdsa")
        }
      )
    

    This is however problematic for me presumably because cloud-init is yaml.

      in "", line 22, column 1:
        "
        ^
    could not find expected ':'
      in "", line 24, column 8:
              "-----BEGIN OPENSSH PRIVATE KEY-----
               ^"
    2022-03-18 00:20:32,611 - util.py[WARNING]: Failed at merging in cloud config part from part-001
    2022-03-18 00:20:32,611 - util.py[DEBUG]: Failed at merging in cloud config part from part-001
    Traceback (most recent call last):
      File "/usr/lib/python3/dist-packages/cloudinit/handlers/cloud_config.py", line 140, in handle_part
        self._merge_part(payload, headers)
      File "/usr/lib/python3/dist-packages/cloudinit/handlers/cloud_config.py", line 116, in _merge_part
        (payload_yaml, my_mergers) = self._extract_mergers(payload, headers)
      File "/usr/lib/python3/dist-packages/cloudinit/handlers/cloud_config.py", line 95, in _extract_mergers
        mergers_yaml = mergers.dict_extract_mergers(payload_yaml)
      File "/usr/lib/python3/dist-packages/cloudinit/mergers/__init__.py", line 79, in dict_extract_mergers
        raw_mergers = config.pop('merge_how', None)
    AttributeError: 'NoneType' object has no attribute 'pop'
    2022-03-18 00:20:32,616 - __init__.py[DEBUG]: Calling handler CloudConfigPartHandler: [['text/cloud-config', 'text/cloud-config-jsonp']] (__end__, None, 3) with frequency once-per-instance
    

    I believe what's happening here is the file isn't being indented properly. Let's say ./ssh/acme-bitbucket-id_ecdsa looked like this,

    -----BEGIN OPENSSH PRIVATE KEY-----
    FOO
    BAR
    BAZ
    -----END OPENSSH PRIVATE KEY-----
    

    I think that's getting processed into the template like this,

    ssh_keys:
        ecdsa_private: -----BEGIN OPENSSH PRIVATE KEY-----
    FOO
    BAR
    BAZ
    -----END OPENSSH PRIVATE KEY-----
    

    What is the way to stop properly produce a cloud-init file with Terraform?



  • Here is how I got around it, I declared these as HDL object,

    data "template_file" "user_data" {
      template = templatefile(
        "cloud/cloud.cfg",
        {
          ssh_keys = {
            ssh_ecdsa_key_private  = file("./ssh/acme-bitbucket-id_ecdsa")
            ssh_ecdsa_key_public   = file("./ssh/acme-bitbucket-id_ecdsa.pub")
          }
        }
      )
    }
    

    And then I pulled it into the yaml file using https://www.terraform.io/language/functions/yamlencode .

    There is a bit of documentation that covers this, over at https://www.terraform.io/language/functions/templatefile#generating-json-or-yaml-from-a-template




Suggested Topics

  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2