Hi all I'm starting to really love Pulumi. It's s...
# getting-started
p
Hi all I'm starting to really love Pulumi. It's so fast and simple in most cases. I'm just really stuck on one thing: Outputs and Inputs. I tried reading the docs and it makes sense but it breaks down as soon as I apply it to something practical. For example: I'm trying to pass a Pulumi secret config value to an AWS LaunchTemplate's user_data script. As far as I can understand this variable:
gitlab_runner_token = gitlab_config.require_secret("token")
contains an
Input
. Eventually, in my code, this input gets implicitly converted to a string:
Copy code
t = Template(open(f"{getcwd()}/modules/aws_asg/user_data.tpl.sh").read())
templated_user_data = t.substitute({
    'gitlab_runner_token' : gitlab_runner_token,
})
I would expect the secret value in the template, but instead it printed this:
Calling __str__ on an Output[T] is not supported. To get the value of an Output[T] as an Output[str] consider: 1. o.apply(lambda v: f"prefix{v}suffix") See <https://pulumi.io/help/outputs> for more details.
. Firstly I don't understand why we're now talking about an
Output
instead of an
Input
, but that aside. I've followed the error message and googled this many times and most of the time the solution seems to be to use the
.apply()
function as it says. However I haven't found a working solution using the
.apply()
function. Mostly it just prints the same error whatever I try. For example, I would expect the following to unwrap the output into a string given the error message but it prints the same error:
Copy code
t = Template(open(f"{getcwd()}/modules/aws_asg/user_data.tpl.sh").read())
templated_user_data = t.substitute({
    'gitlab_runner_token' : gitlab_runner_token.apply(lambda v: f"{v}"),
})
My hunch here is that the apply function which takes an
Output
does not return a string, but an
Output
. https://www.pulumi.com/docs/reference/pkg/python/pulumi/#pulumi.Output.apply I don't understand why this would ever be useful. 😄 I kind of understand why this is the behavior, it's never converted to a string until somewhere deep in the pulumi code to protect it being a secret, but this makes it totally unusable in many cases where you want the secret before Pulumi starts its templating magic. So how does the apply function really work? Can Outputs ever be converted to strings to be used in templating scripts? Am I better off not using Pulumi secrets for this use case or is it possible? Thanks a lot! Ben
b
@plain-mechanic-14459 I definitely hear you when it comes to outputs. I struggled with them as well. I previously wrote this which you may have come across when googling: https://leebriggs.co.uk/blog/2021/05/09/pulumi-apply
this definitely works, unfortunately you’re just using the
apply
in the wrong place in your code. To break this down a bit, an Input/Output is a value that isn’t know until after you get the result back from the cloud provider API. Similar to a python List or Dictionary, you have to unpack it before you can use it. In the same way you can’t access a list element without a loop, you can’t use an Input until you’ve resolved the value If you semantically think of
apply
as
resolve_api_call
it starts to make a bit more sense
To use your concrete example:
Copy code
t = Template(open(f"{getcwd()}/modules/aws_asg/user_data.tpl.sh").read())
templated_user_data = t.substitute({
    'gitlab_runner_token' : gitlab_runner_token.apply(lambda v: f"{v}"),
})
In this situation, you’re opening the
.tpl
template, then you’re trying to resolve the gitlab token value, which is the wrong way round. What you need to do, is reolsve the gitlab token value, then open the template. It ends up looking a bit like this:
Copy code
gitlab_runner_token.apply(lambda v: Template(open(f"{getcwd()}/modules/aws_asg/user_data.tpl.sh").read()).substitute.....
so in this case, you’re: • resolving the gitlab_runner_token async value • once it’s resolved, it’s now a plain string and can be used as usual in a template
if you’re still struggling, send me the full code you’re using to provision the token and I can get it working for you
p
Thanks for the in depth explanation and link!! This definitely helps, thanks a lot!
Got it to work! Your blog post explained it very well. How would you tackle having multiple Input secrets that need to be templated into one file?
Would that require the
all()
function?
b
yes you’d use
pulumi.Output.all
@plain-mechanic-14459 I took some of the feedback and rewrote our inputs/outputs page. WOuld you mind rereading and see if this improves things/helps? http://pulumi-hugo-origin-pr-2996-1599ff0f.s3-website.us-west-2.amazonaws.com/docs/concepts/inputs-outputs/
p
@billowy-army-68599 That link doesn't work for me
Was it a temporary deployment? I'm getting a
404 Not Found
b
p
Looks good! @billowy-army-68599
I especially like the 'Common pitfalls' section, but maybe you can make it more clear that the code is faulty other than adding
# NOTE: This example is not correct
? Maybe a big red bar in CSS 😄