https://pulumi.com logo
#typescript
Title
# typescript
e

elegant-crayon-4967

11/21/2022, 8:14 PM
How many folks place pulumi resources inside a
.apply
of another resource to ensure you get the proper
string
type you want, where if you didn’t, you’d most likely get an error of undefined. I do this all the time, but on a net new stack, pulumi won’t show the resources to be created inside that
.apply
which makes sense to me, but also very hard as some of these resources I want to import before my pulumi up and can’t verify they are imported
v

victorious-church-57397

11/21/2022, 8:30 PM
not sure if i understand the problem 100% here, but could you not use
dependsOn
to achieve this?
e

elegant-crayon-4967

11/21/2022, 8:36 PM
well I’d be using the string as a conditional
_asg_._loadBalancer_._dnsName_.apply((albDnsName) =>
that’s how I’m getting my albDnsName, and then based upon that name (a string) then do “things”
hard to do a depends on with that
v

victorious-church-57397

11/21/2022, 8:38 PM
ok got you, are you hitting a race condition where the resource isnt imported? or is it just a concern? i cant imagine pulumi would execute that code without the resource being there
i personally tend to avoid resource importing, and instead use stack outputs for stuff that needs to be shared between stacks
e

elegant-crayon-4967

11/21/2022, 8:39 PM
yea it’s tough one where using a 3rd party provider (we created) and earlier work was done via the console, so now we want it behind code
of course it’s in prod 🙂
v

victorious-church-57397

11/21/2022, 8:41 PM
i was trying to use imported resources just for github repos and config and it was a nightmare, luckily i work at a startup so we have built everything. my approach would be to get some downtime in to recreate things 😬
i appreciate thats not helpful
maybe you could create a stack that only imports resources and outputs the information you need, then you could use stackreferences?
e

elegant-crayon-4967

11/21/2022, 8:43 PM
honestly, we’ll probably just do a 2nd run, where we build everything but what we need, and then add in the imported resources when the promise is known
v

victorious-church-57397

11/21/2022, 8:44 PM
let me see how i handled the imports first in what i was doing, deleted the code now but should be in git somewhere
looks like i wrapped the imports in a function to get them, then used
.then()
then you can guarantee the import is attempted first
l

little-cartoon-10569

11/21/2022, 8:52 PM
place pulumi resources inside a .apply of another resource to ensure you get the proper string type you want
This is never be necessary, and (imo) always wrong. You can use the output properties of the first resource in the 2nd resource without a problem.
e

elegant-crayon-4967

11/21/2022, 8:55 PM
you can provide a working example?
l

little-cartoon-10569

11/21/2022, 8:56 PM
Of using a resource's outputs in another resource? All the example code should do that.. have you browsed github.com/pulumi/examples?
e

elegant-crayon-4967

11/21/2022, 8:56 PM
are you familiar with promises?
l

little-cartoon-10569

11/21/2022, 8:56 PM
Yes.
Very.
e

elegant-crayon-4967

11/21/2022, 8:57 PM
ok, then you know this doesn’t just work on using new resources
l

little-cartoon-10569

11/21/2022, 8:57 PM
It does. Pulumi takes care of it for you.
The output of the 1st resource is waiting on by Pulumi for you, so you don't have to (and shouldn't).
e

elegant-crayon-4967

11/21/2022, 8:58 PM
this isn’t just the output from one pulumi to pulumi input type by the 2nd
l

little-cartoon-10569

11/21/2022, 8:58 PM
Ah, sorry. Can you explain in more detail then? Example code, perhaps?
e

elegant-crayon-4967

11/21/2022, 8:58 PM
it’s getting a promise back from a library and using the promised string type value as a conditional value to do more things
l

little-cartoon-10569

11/21/2022, 8:58 PM
Promises are in the Input union type, you can use them like outputs.
e

elegant-crayon-4967

11/21/2022, 8:59 PM
this is part of code that is NOT a pulumi resource, it’s being used to decide which pulumi to create next
l

little-cartoon-10569

11/21/2022, 9:00 PM
Can I ask: ideally, would you be creating all the resources? And you're using the promised value to decide whether or not you have enough information to do it now?
info is earlier in the thread @little-cartoon-10569
l

little-cartoon-10569

11/21/2022, 9:01 PM
I don't think I'm gleaning enough from that. You can use get-methods and imports to avoid putting anything inside a .then() or .apply(). It's not always obvious, but in my experience, it's always possible.
For example, if you have a promised loadbalancer, and you need to use its dnsName to create a DNS record, you could use something like:
Copy code
const record = new aws.route53.Record(name, {
  name: pulumi.output(loadbalancer).dnsName,
  ...
And Pulumi will resolve the promise dependency and create the record only when the name is available.
e

elegant-crayon-4967

11/21/2022, 9:04 PM
here is some code
Copy code
// Call MBX EC2 Library
	const asg = new mbxec2.ASG({
	...does things
	)}

	// Build DNS Entries for Ultra DNS & CloudFlare
	asg.loadBalancer.dnsName.apply((albDnsName) => {
		// AWS ALB Specific Record per Environment
		if (env.appEnv.includes('-example')) {
			config.ultraDnsRecords.map((ultraRecord) => {
				new ultradns.Record(`${env.appEnv}-${ultraRecord.subDomain}-ultraDnsRecord`, {
					ownerName: ultraRecord.subDomain,
					recordType: 'CNAME',
					zoneName: config.bookerTld,
					ttl: 3600,
					recordDatas:
						ultraRecord.data == 'ALB-DNS-PLACEHOLDER' ? [`${albDnsName}.`] : [`${ultraRecord.data}`]
				});
			});
I’m calling a library that creates a bunch of resources related to an Auto-Scaling Group
then using that alb dns name, I create a record with it at ultradns
v

victorious-church-57397

11/21/2022, 9:05 PM
do you return the outputs in the library? by extending the pulumi componentresource class
e

elegant-crayon-4967

11/21/2022, 9:05 PM
unfortunately the ultraDNS provider wants an array of strings
l

little-cartoon-10569

11/21/2022, 9:06 PM
Can you not move the use of loadBalancer.dnsName down to inside recordDates?
e

elegant-crayon-4967

11/21/2022, 9:06 PM
if you just use
asg.loadBalancer.dnsName
in the recordDates I would get undefined
l

little-cartoon-10569

11/21/2022, 9:06 PM
If the output is resolved inside the constructor parameters, then you don't have to call the constructor inside an apply.
e

elegant-crayon-4967

11/21/2022, 9:06 PM
w/o the apply
mind you all this is being built at the same time
l

little-cartoon-10569

11/21/2022, 9:07 PM
So is the problem that ultraRecord is somehow not a promise, but not available until after dnsName's promise resolves?
e

elegant-crayon-4967

11/21/2022, 9:08 PM
correct
l

little-cartoon-10569

11/21/2022, 9:08 PM
Then make it a promise.
If it's essentially a real value that changes during runtime, then it has to be a promise (or an output).
e

elegant-crayon-4967

11/21/2022, 9:09 PM
yea we only get an alb Dns name once the resource is created
l

little-cartoon-10569

11/21/2022, 9:09 PM
And it would be as simple as
const ultraPromised = lb.name.apply((_) => ultraReal))
It is possible to unconditionally construct the records, and give it promised / outputted parameters. Pulumi will wait correctly, based on those parameters. You never have to do the waiting on Pulumi's behalf.
e

elegant-crayon-4967

11/21/2022, 9:10 PM
I will try what you suggest, but feel like it will leave me right back where I started. Thanks all for the feedback!
l

little-cartoon-10569

11/21/2022, 9:11 PM
There is one exception to this rule, and Pulumi have fallen victim to it themselves:
If the number of things created isn't known until after some other thing is created, then you end up in a very awkward situation, and sometimes have to await/apply.
awsx.ec2.Vpc's subnets do this, and they're wrong.
c

clever-sunset-76585

11/23/2022, 2:36 AM
@elegant-crayon-4967
unfortunately the ultraDNS provider wants an array of strings
It seems that the
recordDatas
property takes in an
Input
of array of
Input<string>
. So you should be able to use the ALB's
dnsName
property directly as @little-cartoon-10569 suggested.
Input
is a type union:
Copy code
export declare type Input<T> = T | Promise<T> | OutputInstance<T>;
if you just use
asg.loadBalancer.dnsName
in the recordDates I would get undefined
I think this might provide a hint as to what might be wrong here. How is the
loadBalancer
property getting its value in the component resource
mbxec2.ASG
? Also are you calling
super.registerOutputs({})
in your component resource after you've created all the resources you need to?
2 Views