Hi team, On the <documentation page for apply>, it...
# getting-started
c
Hi team, On the documentation page for apply, it says to not have side-effects - like creating new resources - in the callback passed to apply, which makes absolute sense based on the explanation. Yet, in the Crosswalk for AWS documentation that's exactly what's being done in one of the examples. So, what IS the recommended best practice?
d
In this case, DefaultVpc is just a wrapped invoke, which will still run during preview. Awsx is using
pulumi.output
to wrap promises, so it's a different lifecycle that can be treated as "sync" before a stack is constructed. If it's an output from a resource, you should still avoid using
.apply
to create other resources
c
Thanks for the swift answer. So, do I need to know implementation details to understand when I can create resources inside apply and when not? Or am I missing something?
d
Only that an invoke (provider function) runs before the stack is constructed unless it depends on a resource output. This goes for if you're wrapping your own async code with
pulumi.output
too. You shouldn't need to dive further into implementation details than that
c
I don't think I understand your reference to "invoke (provider function)". When I create an instance of
awsx.ec2.DefaultVpc
it has a property
publicSubnetIds
. The type of that property is
pulumi.Output<string[]>
. An instance of type
aws.acm.Certificate
has a property
domainValidationOptions
of type
pulumi.Output<CertificateDomainValidationOptions[]>
. How do I know on which of these properties I'm allowed to create new resources inside the
apply
callback and on which not? I see no way except looking into the code of the corresponding package implementations.
d
If the docs provide an example, it'll be safe. But yes, without that example you'd need to check the code
This gives the basics of provider functions: https://www.pulumi.com/docs/concepts/resources/functions/
c
Got it, thanks!
But yes, without that example you'd need to check the code
This does sound like a bit of a design flaw to me.
d
Yes, perhaps Invokes should have a new type of
KnownOutput
to make it clearer when it's always safe to use. I don't think it'd help much though, as there wouldn't be a way to warn about resource creation inside the function body
c
Right. It would require a complete redesign of how resources are being created...
d
I meant in terms of static type analysis. It'd be easy enough to warn at runtime
c
Yes, that's what I meant as well. To be able to prevent people from writing code that creates new resources inside the apply function, the way resources are created would need to be changed, e.g. to using a factory class instead of `new`ing them up. And then, an instance of this factory class is being passed - by pulumi - only to places where resources may be created.
b
There’s some nuance here. It’s not best practice to create resources inside an apply, but due to the design of some cloud provider APIs, there really isn’t much choice in some situations. It’s really API dependent. The domain validation one for ACM certificates is a great example of that - you need to create DNS records for the cert but can’t do it until the API has returned values. You can use lifting, but that often means not doing it idiomatically.
d
Given it's a common question, going to look at doing some articles on life cycles within within pulumi
c
Thanks for the additional insight!