What are the best practices when it comes to namin...
# getting-started
d
What are the best practices when it comes to naming resources inside a component resource? I am trying to understand whether it's an anti-pattern to use the resource name of the parent as part of the resource name of its children (I don't mean the actual name of the resource, I mean the one that refers to the resource inside the stack). Reason I ask is that doing so seems to make renaming component resources absurdly difficult, but not doing so seems to not allow a user to create two of the same component inside the same stack due to name clashes
Seems like the documentation has been updated since I last saw it: https://www.pulumi.com/docs/iac/concepts/components/#creating-child-resources This is what I have been doing, so I guess my question becomes how do you perform a rename of a component resource using this pattern? Setting an alias on the component resource only seems to affect it and not the children
l
I generally try to use
name
only. I definitely don't like adding the resource type into the name (though it seems to be hugely popular.. no idea why). The only time I change the name of a child from that of the parent is when there's more than one child of that type.
Copy code
new aws.s3.Bucket(`${name}-bucket`, {});
Ick. What's wrong with
Copy code
new aws.s3.Bucket(name, {})
?
This is interesting:
Also, when constructing a resource, children must be registered as such. To do this, pass the component resource itself as the parent option.
That's not a "must". You can pass anything as the parent, or pass nothing. It won't break (so long as you don't have circular dependencies). It's just a good idea to pass the component resource as the parent, most of the time.
d
Maybe I haven't described the problem properly. Imagine I have a component resource like this (using Python because that's what I'm using to author the components):
Copy code
class EC2SecurityGroup(pulumi.ComponentResource):
    """AWS EC2 Security Group."""

    security_group_id: Output[str]
    """The ID of the security group."""
    vpc_id: Output[str]
    """The VPC ID the security group is in."""

    def __init__(
        self,
        resource_id: str,
        args: EC2SecurityGroupArgs,
        opts: pulumi.ResourceOptions | None = None,
    ) -> None:
        """AWS EC2 Security Group."""
        super().__init__("my:custom:SecurityGroup", resource_id, None, opts=opts)
        security_group = pulumi_aws.ec2.SecurityGroup(
            "security-group",
            group_name=args.name,
            group_name_prefix=args.name_prefix,
            description=args.description,
            tags=args.tags,
            vpc_id=args.vpc_id,
            opts=opts.merge(pulumi.ResourceOptions(parent=self)),
        )
If I use a static name for the security group to be something like
"security-group"
and not
name
, then if I create two instances of the component I get a name clash on the child security group resource. However, if I use some dynamic name like
name
, then when you pass
aliases=[pulumi.Alias(name="old-name")]
to the ResourceOptions object of the parent, that takes effect only on the parent and not on the security group child resource underneath
The doco suggests that it's totally normal for the children to take a dynamic name. I have been passing name, or some resource name that uses name in the name if there is some variable number of children underneath (e.g. creating ingress/egress rules for the security group from some map of inputs), but when it comes to changing the name of the component resource I am trying to understand what it takes to avoid having to recreate everything contained in the component resource
l
That is correct. Pass
name
to all the children. This will handle 90% of cases
If you are creating more than one type of the same resource, you'll need to build a longer string from name and use it to discriminate.
d
Hmmm, seems like this gets super complicated if you try to use the component resources remotely: https://github.com/pulumi/pulumi/issues/18801
l
That doesn't seem related. That's about getting a component resource to not delete if you rename it and try to use aliases to ensure that Pulumi doesn't delete it.
Is that a problem that you're coming up against?
d
It says that they drop aliases when using component resources over RPC, does it not?
l
Only for the component resource. Not for the real resource within.
Plus, it is likely to be important?
I've been using component resources since before v1 and it's never come up
d
The options are coming from the parent and then merged with a parent option, so they would also affect the children
l
The aliases are provided to all children when I write my code. I think it's that way in the examples too?
Plus, how often will you want to rename a component resource this way? It's very uncommon
I remember doing it once: it was awkward because I had to temporarily add aliases to all resources in the component resource. It wasn't ideal. But it only took 15 minutes to sort.
d
It's uncommon enough that likely surgery on the state could fix it, but I'm also not going to be the person actually wanting to do the renaming most of the time
l
I didn't need surgery in state. I updated the code to add the aliases to each of the resources, ran
pulumi up
, then remove the aliases from code.
d
Yeah, it's not impossible to fix, I'm just trying to make sure I'm not doing the obviously wrong thing because I'm using component resources directly for some of my stuff and then trying to expose them for multi-language use for others to use (frontend teams, etc.)
l
This wouldn't work for all people all the time. But we only had two stacks and didn't re-use that stuff in any other projects, so it was easy.
It will be fine. Component Resources save a lot more effort than they cause.
d
100%, but then some of the costs are not named upfront, so I'm just trying to make sure that I'm doing the right thing so at least if I hit a problem like this that I know it's not me doing a footgun
l
My rule of thumb is: if you can talk to all the consumers of the code, just use a component resource, it's easiest. If you need to share the code with people you don't (often) talk to, then one of the provider options is probably better.
d
My issues are more around the features that work or don't work when the component resource is triggered over RPC
Like the use of resource transforms getting any map and turning it into an Output[map] if the map contains an Output value, etc.
If I author and consume the component resource in the same language then some of these problems disappear
💯 1
But I'm trying to write my stuff to make sure I'm not having to use the same language because of how I've written my stuff
l
Ah, the old "AWSX" conundrum. That library is actually a good example of the problems that widely-used component resources can bring 🙂
s
@delightful-queen-14969 The short answer (I think?) to your original question: The component's name should be templated in the child resource names, e.g.
${name}-cluster
. I'll ensure that we note the specific case of renames (which I had not even considered - thank you!)
d
Thanks, I'm just trying to make sure that my stuff is following best practices so at least I can know I'm not swimming upstream when something isn't working. Cheers for the confirmation
👍 1
s
Keep me posted on what your major questions are because many of my customers are also adopting components and I want to make sure the docs are as complete, accurate, and easy to use as possible.
d
Right now my main pain points are trying to work out whether I'm the problem or whether something just doesn't work when trying to use components in a multi language setting. I'm trying to write my stuff to keep my options open but I wouldn't have expected aliases to just be dropped, for example
I hit another issue a while back where using a resource transform with components caused any mapping input containing an Output to make the whole map an input. It's documented that there are limitations but without knowing exactly what those limitations are it makes debugging issues difficult. I tend to assume I've done something wrong and then find out that the two features don't work together