I’ve playing with Pulumi recently, and came across an issue trying to generate an IAM PolicyDocument that included an ARN resource.
After hours of searching and trying to get my head around the Ouput<T>
types, I found Output.Format()
.
The Problem
Pulumi allows you to define everything you want to create in C#. What it also does is then workout the order in which it needs to create things. This is because things are not procedural in C#, so the model is built, and then applied.
C# would let you do something like this.
public DemoStack()
{
var demoTable = new Table("demo", new TableArgs
{
Attributes = new List<TableAttributeArgs> {
new TableAttributeArgs {
Name = "DemoId",
Type = "S"
}
},
HashKey = "DemoId",
});
Console.WriteLine(demoTable.Arn);
}
However, when the code above runs, the property has not be assigned yet, and therefore it’s empty. This is an issue as when you’re creating an IAM policy, you need to create a JSON formatted string that includes that generated ARN. This is the sort of string we’re looking for:
var policyDoc = $@"{{
""Version"": ""2012-10-17"",
""Statement"": [
{{
""Effect"": ""Allow"",
""Action"": [
""dynamodb:*""
],
""Resource"": [
""{demoTable.Arn}"",
""{demoTable.Arn}/index/*""
]
}}
]
}}";
However, this isn’t going to get the value, as the .Arn
properties will not have been set with their values by this stage.
Enter Output.Format()
This is a handy little static helper that will resolve the Output<T> values so they are usable. From the documentation:
Takes in a
System.FormattableString
with potentialPulumi.Input<T>
orPulumi.Output<T>
in the ‘placeholder holes’. Conceptually, this method unwraps all the underlying values in the holes, combines them appropriately with the System.FormattableString.Format string, and produces an Pulumi.Output`1 containing the final result.
If any of thePulumi.Input<T>
orPulumi.Output<T>
are not known, the final result will be not known. Similarly, if any of thePulumi.Input<T>
orPulumi.Output<T>
are secrets, then the final result will be a secret.
To cut through the Pulumi orientated stuff, it’s basically a string.Format()
function that works with Output<T>
objects from your resources.
So now, the policy code looks like this:
var policyDoc = Output.Format($@"{{
""Version"": ""2012-10-17"",
""Statement"": [
{{
""Effect"": ""Allow"",
""Action"": [
""dynamodb:*""
],
""Resource"": [
""{demoTable.Arn}"",
""{demoTable.Arn}/index/*""
]
}}
]
}}");
So you can now assign that to the policy document.
Conclusion
You have to rethink your mental model a bit when it comes to working with some of the more advanced concepts in Pulumi. That said, once you do, as a C# dev, it feel really nice to have a programming model that makes sense to me. I’m excited to see what else I can do with it.
Full Example here: https://gist.github.com/martinjt/d273643227c93715aea015015b688343
Sidenote: I love that this is the full example code, in 1 single gist file.
Leave a Reply