bazaarvoice / cloudformation-ruby-dsl

Ruby DSL for creating Cloudformation templates
Apache License 2.0
210 stars 76 forks source link

Variables aren't passed down to the other objects #53

Closed linuxboytoo closed 9 years ago

linuxboytoo commented 9 years ago

Not sure this is a bug but I cannot find the "right" way to do this. I have defined a variable in the root RB template and it is not in scope when calling the load_from_file method. I used super global (@@) variables to get around this but this doesn't seem quite right.

Suggestions?

jonaf commented 9 years ago

You can write any valid Ruby syntax within your template. You should not need super globals, or globals, to reference variables that you define. Can you provide an example snippet, please?

temujin9 commented 9 years ago

@jonaf The behavior of load_from_file and interpolate is rather . . . idiomatic . . . and does not include useful variable expansion (although it does allow some function calls). I'd be in favor of adding a more modern templating solution, like ERB, and then deprecating interpolate.

temujin9 commented 9 years ago

@linuxboytoo Using interpolate and {{ref('ParameterName')}} should let you pass variable information into the template via parameters, and from there into the userdata script.

jonaf commented 9 years ago

@temujin9 Sorry I missed the load_from_file part. You can actually write (most) valid Ruby syntax in {{ and }} and it will work (I think the only real exception is if you syntax for any reason includes double braces, as the regex matcher will consider this the termination of the Ruby expression and evaluate the incomplete expression instead, resulting in a SyntaxError). Despite this, I am in agreement with you and would like to see us deprecate this syntax in favor of erb (although erb support is already available -- just call erb_template("template.erb") -- and it uses the current context of the DSL, unlike interpolate), especially since the scope is inherited from TemplateDSL. However, @linuxboytoo , the interpolate method takes a second argument called locals, which will yield a variable to the context of the file or string that is being interpolated, so you could use that if you were using interpolate(file("some file")). On the other hand, using load_from_file does little more than copy the provided file and output it (if you load a .rb file, it will also eval it, but of course, the scope in this case is not going to pick up on your globals).

Some examples (imagine you're calling interpolate(file("some file")) and the following code represents the contents of some file).

Getting the value of a parameter:

MY_PARAM={{parameters.fetch('my_parameter', '')}}

Checking if a parameter is empty and, if so, interpolating another file and expanding it into the current one.

{{ interpolate(file('inc/source-universe-autorestore.sh')) unless parameters['SourceUniverse'].empty? }}

Using the locals parameter in a cfn-template.rb:

MYVAR = "hello, world!"
# outputs "hello, world!"
interpolate("{{puts MYVAR}}", MYVAR)

I'll admit that erb_template may need some love, though. For example, right now you have to add split("\n") to the result if you want the resulting JSON to be readable (or match the behavior of interpolate's output).

jonaf commented 9 years ago

@linuxboytoo I'm closing this issue for now. Please let me know if you have additional feedback.