How can I get the pulumi Resource object from the ...
# general
g
How can I get the pulumi Resource object from the StackReferece? stack A
Copy code
oai = cloudfront.OriginAccessIdentity(
    f"{PREFIX}-oai"
)
pulumi.export('origin_access_identity', oai)
stack B
Copy code
ref_oai = StackReference(name="stackA").require_output('origin_access_identity')
The reference gives me the
Output[dict]
with the exactly same parameters as created object in stack A Is it possible to create an object
OriginAccessIdentity
from this, without calling AWS API with
OriginAccessIdentity.get()
?
b
You can’t export the resource object, only the properties on it, which is what you’re seeing. You’ll need to run a get on the resource id
g
get
does call the AWS API right? CDK has both options to construct resource from properties or from lookup. Did I notice correctly that
awsx
may offer the same thing?
b
get will create a resource for an existing object, which in this case is in another stack. So
.get()
is what you're looking for
awsx
doesn't have any
.get
objects because you'd just use the native aws provider
r
FWIW 
.get()
 actually adds the resource to your stack state. So then this resource would be tracked in two different stacks? Not sure that’s what you want. 
get[Resource]
 just does a read - which maybe is what you want?
g
right, so Get somehow looks up another stack, - is there any deeper documentation about Get? It would be nice if I could avoid unnecessary API calls since I already have all data though
I keep getting confused by Get and
get_some_resource()
methods
@red-match-15116 oh okay, I do not think I want that oai tracked by 2 stacks, since the second one should point to it as a reference. by
get[Resource]
you refer to eg. this? https://www.pulumi.com/docs/reference/pkg/aws/ec2/getsecuritygroup/ That won't work because it is not implemented for OAI
r
This is the
.get()
method which is on each resource. It has nothing to do with “looking up another stack”, it will find the resource and add it to your stack to start tracking it within your pulumi stack (regardless of whether it was originally deployed as part of a pulumi stack or directly in the console or any other way) https://www.pulumi.com/docs/reference/pkg/aws/cloudfront/originaccessidentity/#look-up This is the
get[Resource]
function which is only available for certain resources. It is used to look up information about a resource without adding it to your stack. https://www.pulumi.com/docs/reference/pkg/aws/cloudfront/getdistribution/
Is it possible to create an object 
OriginAccessIdentity
 from this, without calling AWS API with 
OriginAccessIdentity.get()
?
I don’t really understand the premise of your question, why do you need to create the object when you have all of its outputs available to you? What good is the object to you apart from its properties which you already have available in the stackreference?
g
it will find the resource
- here my question is how and where does it look My point here is that I do not want to pass around a
StackReference
because that's not clear what it is, I want to be able to pass
OriginAccessIdentity
object. And since this particular
StackReference
contains all data about my oai I do not think it is necessary to search or look up.
r
My point here is that I do not want to pass around a 
StackReference
 because that’s not clear what it is,
I want to be able to pass 
OriginAccessIdentity
 object.
Got it. Unfortunately that would require deserializing your stack reference into an
OriginAccessIdentity
resource but not tracking it as a resource in stack B. We can’t do that at this time. You can do this with the
get[Resource]
functions that are available for some resources, but since this is a bridged terraform provider we do not control which resources have a
get[Resource]
function.
And since this particular 
StackReference
 contains all data about my oai I do not think it is necessary to search or look up.
Right, the benefit of pulumi is that you are just writing code. So if this is something that you want and you believe it is entirely straightforward to do so, you should be able to do so within your code. You could create an
OriginAccessIdentityOutputs
data class and rehydrate it with the properties of your stack reference, or whatever else you need to do to get the end state you would like.
Personally this is not something that I would do. I would structure
stackB
in a way that it only requires certain properties of
OriginAccessIdentity
as inputs, and I would only output those specific properties from
stackA
and reference them in
stackB
. But I understand it is a matter of personal preference, and if my personal preference defers from the provided constructs then I write the code to enable my preferences.
g
it only requires certain properties of
- this is what I do but I'm balancing on thin ice with this feature. mainly due to comfort
pulumi.export('reource', resource)
vs:
pulumi.export('resource_property', resource.property
in case I need more than 2 properties it becomes too repetitive. but it's pretty much dependent on the resource, so to take a shortcut I simply wanted to expose an entire resource so I do not have to maintain make so many code changes in case I need another property Deserialising
StackReference
into a dataclass is exactly what I'm doing, but
Output
are what makes it difficult (you may remember our previous conversations about it) I wonder if there is a pattern that would allow simple dictionary unpacking on Outputs
r
I wonder if there is a pattern that would allow simple dictionary unpacking on Outputs
Hmm interesting. So you basically need to have your data class accept an output[dict] and have it resolve the properties to individual outputs. Something like:
Copy code
class OriginAccessIdentityOutputs:
    def __init__(self, props: Output[dict]) -> None:
        self.prop1 = props.apply(lambda args: args["prop1"])
        self.prop2 = props.apply(lambda args: args["prop2"])
g
yes, I use pydantic instead of a dataclasses but that would be the very similar:
Copy code
import pulumi
from pydantic import BaseModel


class OriginAccessIdentity(BaseModel):
    cloudfront_access_identity_path: Union[str, pulumi.Output]
    iam_arn: Union[str, pulumi.Output]
I can instantiate this class like a so:
Copy code
resource = StackReference.get_output('resource')
OriginAccessIdentity(prop1=resource.apply(lambda x: x['prop1']
but it is possible to instantiate a dataclass or pydantic model from dict
Copy code
OriginAccessIdentity(**{"prop1":resource.apply(lambda x: x['prop1']}
on top of that pydantic offers
OriginAccessIdentity.parse_obj(dict_with_props)
pain point is repetion of
resource.apply(lambda x: x['prop1']
- which kills the productivity
having the ability
OriginAccessIdentityOutputs.parse_obj(pulumi.Output)
- would be amazing or
OriginAccessIdentityOutputs(**pulumi.Output)
b
I feel like we've covered this before: it's not possible to validate the output values outside of an apply because they aren't known at runtime. It would involve completely rearchitecting how Pulumi works. It's never going to be possible. I understand your frustration but what you're asking for isn't the way things work
r
So, concretely here’s what I recommend: 1. You can open an issue for us to look into this - but honestly it’s unlikely it’ll be prioritized anytime soon. 2. If you know the properties you can do something like:
Copy code
props = ["prop1", "prop2", "blah"]

OriginAccessIdentityOutputs(**{p: resource.apply(lambda x: x[p]) for p in props})
But honestly is it really worth it?
g
It goes against the documentation, but I do create resources inside of callback loops in certain circumstances, and that has allowed me to do repetitious things that required an Output to have been applied in order to create further resources… I believe there was an issue raised about this in regards to conditionally creating Resources so they appear in the graph, but maybe not ncessarily creating them in the underlying API… similar to count = 0 in TF.
in your case @great-sunset-355 your class could implement an iterator against a dict/map of keys and create OriginAccessIdentity() resources inside of the loop, inside of the Output.all().apply() callback.
Not exactly what you are doing in this case, but another example of “the docs say don’t do this” but Pulumi doesn’t offer a real good alternative in both this scenario (issue 4834) nor when you n eed to conditionally create resources in a loop or based off of some output being applied already etc
it felt like a hack in HCL [count = “${var.something ? 1 : 0}” anyone? :P], and still feels like a hack in Pulumi (due to the async nature).
g
Thanks Thomas, I read the 4834 while researching this. I know this hack from HCL, however, if felt way less hacky than putting a whole lot of code inside
apply