Hi Friends... I'm wondering how we gracefully hand...
# python
b
Hi Friends... I'm wondering how we gracefully handle the case when we do a remote stack reference, and we cannot find the key we expect. Since this is an Output[T] situation the answer is not so simple because of async logic. Hope someone can shed some light on this for me. Thank you! 🙂
e
Depends a little on what your doing, but it might be reasonable to just put a large portion of your program inside an apply on the Output[T]. The usual advice about not doing too much inside apply doesn't really apply here because stack references are always known so the apply will always run even in preview.
a
Although it isn't a publicly exposed method you could use
pulumi.runtime.sync_await._sync_await
as outlined in a comment to #12172
And you can do runtime checks on the result as you would normally. Even use it for naming Pulumi resources, despite Outputs not being supported in that scenario.
b
This is cool! I shall try it out, thanks 🙂
r
I am facing the same problem, and running into issues with apply. I exported a resource in stack A... and am trying to refer to it from stack B... I've tried
apply
:
Copy code
_route53 = pulumi.StackReference(...)
domain_name     = _route53.get_output('zone').name.apply(lambda v: f'{ v }')
Nope!
Copy code
pulumi.Output.format('{ 0 }', _route53.get_output('zone').name)
Nope!
Copy code
pulumi.Output.format('{ 0 }', _route53.get_output('zone').name.apply(lambda v: f'{v}'))
e
What doesn't work there?
r
(sorry was in the midst of editing)
I am trying to use
domain_name
in an aws.acm.Certificate resource... but keep getting this:
Copy code
aws:acm:Certificate (admin.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://www.pulumi.com/docs/concepts/inputs-outputs> for more details.
This function may throw in a future version of Pulumi.):
    error: aws:acm/certificate:Certificate resource 'admin.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://www.pulumi.com/docs/concepts/inputs-outputs> for more details.
    This function may throw in a future version of Pulumi.' has a problem: invalid value for domain_name (cannot end with a period). Examine values at 'Certificate.DomainName'.
a snippet of my code:
Copy code
common_name = f"{ cert['subdomain'] }.{ vars.domain_name }"

cert = aws.acm.Certificate(common_name,
        domain_name       = common_name,
        validation_method = 'DNS',
)
e
r
how am I supposed to interpret
Copy code
To get the value of an Output[T] as an Output[str] consider:
1. o.apply(lambda v: f"prefix{v}suffix")
?
it's fine if I'm not supposed to use f-strings. What do I do then?
e
Use 'f' strings inside an apply, or use
pulumi*.*Output*.*format
as described in https://www.pulumi.com/docs/concepts/inputs-outputs/all/#using-string-interpolation
r
basically I exported a aws.route53.Zone resource from stack A... and now I am just trying to get several properties from this output. Namely
.name
, and
.id
e
Either use the
_sync_await
trick listed by @adventurous-butcher-54166 above, or put the code that needs to use the name and id inside an
apply
function
r
will this work?
Copy code
domain_name = _sync_await(_route53.get_output_details('zone')).value.name
e
I think so, but I haven't used resources in stack references for a while so can't recall the exact semantics of them
r
hm I get this:
Copy code
domain_name      = _sync_await(_route53.get_output_details('zone')).value.name
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    AttributeError: 'dict' object has no attribute 'name'
e
try
["name"]
r
trying that now... Makes sense since it seems like there is a type conversion going on now
... and it works! I think i get it now... it was just confusing that the code samples that I see all involve a simple assignment to a
.apply
call, as if that's what you need to get the value. In truth (correct me if I'm wrong, pls), the simple assignment only works if what you're assigning becomes an input to a resource. Otherwise, you really need to do everything (why...) in
.apply
or
.all
lambdas.
e
yup
r
thank you. It's been a frustrating thing trying to figure this thing out
e
yeh outputs are odd, unfortunately a necessary complication for the system to work
r
thank you again
a
I'd use sync_await sparingly as it will block all operation while waiting for its output. I have only used it to populate stack configs where I explicitly want to validate the input before running any Pulumi operations. There's also
pulumi.Output.concat()
which is useful for concatenating multiple outputs, even with raw strings...
r
ok. I do need multiple values... but not concat-ed
for the record, the documentation isnt exactly clear on when you can pass an output to a resource as an input. I have tried to create an
aws.acm.Certificate
, with a resource name based on an output from another stack (my
route53
stack) because I would like to have the name of the domain be part of the resource name. It doesn't look like this is ok:
Copy code
_route53 = pulumi.StackReference('some/ref/stack')
domain_name      = _route53.get_output('zone')['name'] # '`.name` instead gives me `AttributeError: 'dict' object has no attribute 'name'`

common_name = domain_name.apply(lambda v: f"{ subdomain }.{ v }")
cert = aws.acm.Certificate(common_name,
    domain_name       = common_name,
    ...

)
I get
Copy code
error: Program failed with an unhandled exception:
    Traceback (most recent call last):
      File "/Users/jf/../acm/__main__.py", line 10, in <module>
        cert = aws.acm.Certificate(common_name,
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
    TypeError: Expected resource name to be a string
Perhaps only the resource name has an issue being passed an output... but this needs to be noted down somewhere.
e
The first parameter there is the "logical" name it can't be an output. But the domain_name parameter can be an output. The logical name needs to resolve to a real version at preview time, so it can't depend on outputs because they might not resolve till update time. In this case because your using stack references you can get out of "output space" by using the stack reference output details feature: https://www.pulumi.com/blog/stack-reference-output-details/
r
> The first parameter there is the "logical" name it can't be an output. But the domain_name parameter can be an output. > The logical name needs to resolve to a real version at preview time, so it can't depend on outputs because they might not resolve till update time. thank you. This makes sense now. > In this case because your using stack references you can get out of "output space" by using the stack reference output details feature: https://www.pulumi.com/blog/stack-reference-output-details/ ok. Let me read this in a bit. Thank you
Just went through the article. I have 2 thoughts / questuons. 1. Yes, the outputs from a stack should intuitively be available already. That's been my hangup with having to deal with them still as outputs. So if
the outputs of the referenced stack are available immediately
, why do we still need to
await
them? 2. Is there any more documentation on this besides one blog entry showing things in one language that isn't python?
e
1. It's still a network call so it at least needs to be async awaited. Also they might be marked secret, which wrapping in Output<T> deals with keeping track of that for you, so there is a cost to leaving the output space like this. 2. I think just the API docs https://www.pulumi.com/docs/reference/pkg/python/pulumi/#pulumi.StackReference.get_output_details.
r
1. thank you! that makes sense 2. ok. It would be nice to get proper same code like for the other stuff, but I will work with this.