martinohmann / hcl-rs

HCL parsing and encoding libraries for rust with serde support
Apache License 2.0
119 stars 14 forks source link

Question: How do you correctly encode references to other terraform resources #313

Closed gahooa closed 6 months ago

gahooa commented 7 months ago

In the following code snippet, I have been unable to figure out how to have the hcl::block! macro output the text aws_role.myrole.name without quoting it.

I have scoured the docs, tried many things, but it eludes me. Can you give a pointer? Thank you!

let role_resource = "myrole";
hcl::block!(
    resource "aws_iam_instance_profile" "myrole" {
        name = "myrole-instance-profile"
        role = (format!("aws_role.{}.name", role_resource)
    }
)
martinohmann commented 7 months ago

Hi there @gahooa!

The macros are relatively basic and do not support some of the more complex cases.

To acheive what you want you'll have to do this:

#[test]
fn issue_313() {
    use hcl::expr::{Traversal, Variable};

    let role_resource = "myrole";

    let role_reference = Traversal::builder(Variable::new("aws_iam_role").unwrap())
        .attr(role_resource)
        .attr("name")
        .build();

    let block = hcl::block!(
        resource "aws_iam_instance_profile" "myrole" {
            name = "myrole-instance-profile"
            role = (role_reference)
        }
    );

    let expected = indoc! {r#"
        resource "aws_iam_instance_profile" "myrole" {
          name = "myrole-instance-profile"
          role = aws_iam_role.myrole.name
        }
    "#};

    assert_eq!(hcl::to_string(&block).unwrap(), expected);
}
martinohmann commented 7 months ago

There's actually an example in the docs which shows how to build these traversals, but it uses the builder APIs exclusively instead of mixing them with the hcl::body! and hcl::block! macros: https://docs.rs/hcl-rs/latest/hcl/#serialization-examples