Terraspace Ruby YAML 1.2

Hi

We use a yaml data file to drive some of our terraspace .tf generation, however, we’ve noticed that the yaml for string values “yes”, “no”, “on”, “off” are getting converted to boolean true, false. We believe this is behaviour compliant with YAML 1.1 that has been changed in the YAML 1.2 specification. This is breaking the generation of parameters that are going into terraform resources.

Is there any way to get terraspace to use the YAML 1.2 specification rather than YAML 1.1?

Regards
Martyn

Unsure. A snippet of code with how you’re grabbing the YAML and building the tf file would be helpful. Guessing you’re just using ERB and calling YAML.load

This seems to be what you’re looking for

Basically, the options:

  1. quote the values in the YAML file so they’re not casted to booleans
  2. monkey patch - person does not recommend. For probably good reasons
  3. create your own custom YAML method and use that instead. It would load the on and off as strings, the old behavior

Hope that helps.

Thanks @tung - yes, we’re using YAML.load and ERB.

We’d seen that but we have an issue though in that the YAML is being generated from multiple sources - including conversion from JSON for some of it and that strips the quotes.

The later YAML 1.2 spec removes using yes, no, on, off, y, n, etc, etc as boolean so I just wondered if it was an option.

I’ll see if I can work around via another method anyway. Thanks for the response.

Here you go. It’s the #3 approach. It traverses the nodes and uses the clever trick node.quoted = true from the stackoverflow link above. Did it only for on and off. You can customize it to your needs.

Code

config/helpers/yaml_helper.rb


require "yaml"

module Terraspace::Project::YamlHelper
  # Thanks https://stackoverflow.com/questions/28507195/yaml-ruby-loading-on-as-true
  def yaml_load(path)
    nodes = YAML.parse_file(path)
    nodes.each do |node|
      yaml_load_tranverse(node)
    end
    nodes.to_ruby
   end

  def yaml_load_tranverse(node)
    if node.is_a?(Psych::Nodes::Scalar) && %w(on off).include?(node.value)
      node.quoted = true
    end
    node.children do |child|
      yaml_load_tranverse(child)
    end
  end
end

app/stacks/demo/main.tf

resource "random_pet" "this" {
  keepers = {
    test_true  = "<%= yaml_load('config/data/sample.yml')['test_on'] %>"
    test_false = "<%= yaml_load('config/data/sample.yml')['test_false'] %>"
    test_yes   = "<%= yaml_load('config/data/sample.yml')['test_yes'] %>"
    test_no    = "<%= yaml_load('config/data/sample.yml')['test_no'] %>"
    test_on    = "<%= yaml_load('config/data/sample.yml')['test_on'] %>"  # should load as "on" string instead of boolean true
    test_off   = "<%= yaml_load('config/data/sample.yml')['test_off'] %>" # should load as "off" string instead of boolean false
    test_y     = "<%= yaml_load('config/data/sample.yml')['test_y'] %>"
    test_n     = "<%= yaml_load('config/data/sample.yml')['test_n'] %>"
    test_Y     = "<%= yaml_load('config/data/sample.yml')['test_Y'] %>"
    test_N     = "<%= yaml_load('config/data/sample.yml')['test_N'] %>"
  }
}

config/data/sample.yml

---
test_true: true
test_false: false
test_yes: yes
test_no: no
test_on: on      # should load as "on" string instead of boolean true
test_off: off    # should load as "off" string instead of boolean false
test_y: y
test_n: n
test_Y: Y
test_N: N

Debugging

$ terraspace build demo
Building .terraspace-cache/us-west-2/dev/stacks/demo
$ cat .terraspace-cache/us-west-2/dev/stacks/demo/main.tf
resource "random_pet" "this" {
  keepers = {
    test_true  = "on"
    test_false = "false"
    test_yes   = "true"
    test_no    = "false"
    test_on    = "on"  # should load as "on" string instead of boolean true
    test_off   = "off" # should load as "off" string instead of boolean false
    test_y     = "y"
    test_n     = "n"
    test_Y     = "Y"
    test_N     = "N"
  }
}
$

GitHub Repo and Relevant Links

Thanks tung. That works.