Is there any way to recursively unwrap all the `Output` properties of resources? I've got a load of ...
b
Is there any way to recursively unwrap all the
Output
properties of resources? I've got a load of
ComponentResource
objects with
Output
properties and ideally what i'd love to be able to do is call
pulumi.all([resource].apply(([r]) => r.propA + r.propB)
or whatever (but for many more properties). But when I try that sort of thing I still end up having to unwrap all the properties individually 😞
l
In what context? Properties unwrap themselves in many contexts, it's a feature of Output. Can you post a snippet of code that doesn't allow the normal auto-unwrap to work?
e
Yeh node is normally smart enough to unwrap things when
apply
is called. Exact type signatures might give us a hint here.
b
I've got a ComponentResource
Scheduler
, and I need to use a load of the output properties of that to build the config for another ComponentResource:
Portal
. So what I want to do is:
Copy code
const scheduler = new Scheduler('foo', args, opts);
const portal = new Portal('bar', { scheduler, ... }, opts);
And then inside the
Portal
constructor:
Copy code
const config = pulumi.all([template, scheduler, a, b, c]).apply((template, scheduler, a, b, c) =>
  template
    .replace(/__X__/g, scheduler.x)
    .replace(/__Y__/g, scheduler.y)
    .replace(/__Z__/g, scheduler.z)
    .replace(/__A__/g, a)
    ...
)
But that errors because
scheduler.x
is type
Output<string>
, not
string
, and
replace
doesn't know what to do with it. So I end up having to do:
Copy code
const config = pulumi.all([template, scheduler.x, scheduler.y, scheduler.z, a, b, c]).apply((template, x, y, z, a, b, c) =>
  template
    .replace(/__X__/g, x)
    .replace(/__Y__/g, y)
    .replace(/__Z__/g, z)
    .replace(/__A__/g, a)
    ...
)
which gets really long and unwieldy and also completely breaks when I am trying to pass >8 outputs into
pulumi.all
and they're a mix of
number
,
string
etc output types instead of all being the same.
e
Does it work if you pass the scheduler object through the
pulumi.output
methods first? Because that tries to unwrap nested output values in the structure
b
I thought that was what
pulumi.all
was supposed to do? Effectively call
pulumi.output
on each provided item
e
yeh but TS is probably not able to deal with all the different types being pass to all there
b
Seemingly not. I'm still being told the attributes are type
Output<string>
and that doesn't match the params for
replace
. Something that I have been playing with and seems to work, but feels a bit janky, is I've been defining an interface for all the `Output`s which must be provided in all the classes under the attribute
outputs
. So something like:
Copy code
export interface PortalOutputs {
  appName: Output<string>;
  frontendHostname: Output<string>;
  frontendPort: Output<number>;
  grpcHostname: Output<string>;
  grpcPort: Output<number>;
}

export interface IPortal {
  outputs: PortalOutputs;
}

export class Portal extends pulumi.ComponentResource implements IPortal {
  ...
}

const portal = new Portal(...)
If what I pass in to
pulumi.all
is
portal.outputs
instead of passing
portal
directly and having the
Output
attributes as direct properties of
Portal
, then everything works as expected. I can even nest them inside other objects, so I can have
Copy code
const portalResource = new Portal(...);
const portal = portalResource.outputs;

const args = {
  portal,
  foo,
}

pulumi.all([args, bar]).apply(([args, bar]) => args.portal.frontendHostname)
and it works fine,
frontendHostname
is correctly read as a
string
, not
Output<string>
e
oh odd, maybe TS is treating structs and interfaces different here. I'll try and have a look deeper when I've got some time.
🙏 1
🙏 1