https://pulumi.com logo
#general
Title
# general
i

important-market-84330

10/25/2023, 9:14 AM
Is there a way to set global CustomResourceOptions? Pulumi fails so much when trying to create something before deleting the original because of duplicate *something*, it's really annoying me. Why doesn't the deleteBeforeReplace have a sensible default for each resources? If you know the replace is going to fail anyway if you create a new one of a given resource before deleting the original, why isn't this behaviour preset based on the resource type? And if you set deleteBeforeReplace to true, it doesn't work on the next run because I guess it first needs to do a successful run to apply that option, and then it takes effect on the next change? Pfff.... In general it would avoid a lot of trouble if Pulumi would execute *delete*'s before *create*'s always. If I change a resource name, it will result in a delete and a create operation. But Pulumi first tries to create the duplicate, which in most cases will conflict with the existing resources anyway. Cue Pulumi hand-holding (ie. modify-the-code-and-apply iterations) to fix this. Disclaimer: pretty new to Pulumi and mostly really liking it, but some default behaviour doesn't seem to make sense to me at the moment.
d

dry-keyboard-94795

10/25/2023, 9:24 AM
The common practice is to not specify the name, and let pulumi assign a random suffix. When you specify the name of a resource explicitly, it should also set
deleteBeforeCreate
implicitly for you. What resources are you having trouble with?
i

important-market-84330

10/25/2023, 9:25 AM
In this case is was an AWS Route. I don't know how to NOT specify the name? The API is always like this: Resource(String name, ResourceArgs args) ?
d

dry-keyboard-94795

10/25/2023, 9:26 AM
The name being the name under
args
i

important-market-84330

10/25/2023, 9:26 AM
I don't think I ever set that one ..
Take for example the situation where I just change the Route like this: Route("name-a", ...) to Route("name-b", ...) Since default behaviour is create-before-delete, this will not work.
So then I have to remove the resource and do a stack up (hoping the resource does not have dependents and you don't have to go through that rabbit hole), and then re-add it and do another stack up. A bit silly honestly. I feel like I'm doing something wrong.
d

dry-keyboard-94795

10/25/2023, 9:29 AM
It looks like there isn't a name for Route. I know some of the vpc resources can be tough to handle for creation/deletion, often times from upstream bugs in the terraform provider code.
i

important-market-84330

10/25/2023, 9:30 AM
I feel like I want to a a default deleteBeforeReplace on everything. I'd rather have it take a bit longer and work, then having to jump through hoops to get it set up ... 😞
d

dry-keyboard-94795

10/25/2023, 9:33 AM
I think in your case, you'll just need to specify deleteBeforeCreate for any Route resources. Other resources won't need it
i

important-market-84330

10/25/2023, 9:36 AM
But even that doesn't work in the case I described, because the new Pulumi resource name implies a new resource. So I would need some kind of switch to ask Pulumi to delete resources before creating new ones? Kind of surprised this doesn't exist actually, especially given the amount of times I've run into this.
d

dry-keyboard-94795

10/25/2023, 9:37 AM
If you're renaming the resource, it's worth checking out the
alias
option, so that pulumi handles the state migration. This will prevent the need for recreating the resource in aws
i

important-market-84330

10/25/2023, 9:37 AM
Ohh! I don't know that one yet. That seems like the missing link πŸ˜„
Yep that seems exactly what I need! Thank you ☺️
d

dry-keyboard-94795

10/25/2023, 9:40 AM
In general, renaming a resource should go fine like this too, as cloud providers usually just do duplicate checks based on the resource name (such as ec2 instance id). It's just the Route resource in aws is a little more complex, likely doing duplicate checks based on a combination of attributes to prevent duplicate entries in the route table. Happy the
alias
option will do the job for you here
i

important-market-84330

10/25/2023, 9:48 AM
Just ran into this situation again btw, where the alias doesn't help: Trying to change a ClientVPN network assocation from a private to a public subnet. Pulumi tries to create the new association first, which apparently isn't allowed because you can have only one association per AZ. So yet again, I have to fallback to a 2-step process of: 1. Deleting the resource in the code -> pulumi up 2. Re-adding the modified resource -> pulumi up A
--delete-before-create
flag or some kind of global setting would fix this.
d

dry-keyboard-94795

10/25/2023, 9:57 AM
It looks like the route is also still recreating, so I'm not sure the alias took effect. Do you have a code example?
i

important-market-84330

10/25/2023, 10:02 AM
That's a different route, it's not really relevant for this situation I think. Code example is tricky, it's a decently complex setup...
Well actually, this illustrates it I think:
Copy code
private val networkAssociations = attachedSubnets
        .map { subnet ->
            subnet.id().applyValue { it ->
                NetworkAssociation(
                    "clientvpn-attachment-${it}",
                    NetworkAssociationArgs.builder()
                        .clientVpnEndpointId(this.id())
                        .subnetId(subnet.id())
                        .build()
                )
            }
        }
I changed the
attachedSubnets
from a list with one private subnet to a list with one public subnet (in the same AZ)
Kotlin btw! ❀️
d

dry-keyboard-94795

10/25/2023, 10:08 AM
It's generally not a good idea to create resources within the Apply block. Also not that familiar with kotlin, what is
${it}
?
i

important-market-84330

10/25/2023, 10:08 AM
It's equal to this in java:
Copy code
subnet.id().applyValue(it -> ...
)
(trying to remember java πŸ™ˆ ) It's basically just an implied variable
d

dry-keyboard-94795

10/25/2023, 10:09 AM
Thought so, just wanted to check
i

important-market-84330

10/25/2023, 10:09 AM
I edited the code to make it clearer
Copy code
It's generally not a good idea to create resources within the Apply block.
Yes I read that, but I think I still make that mistake too much. Good point, will fix that!
Actually that's another issue I have: if I want to use an
Output<String>
as a resource name, it gets tricky fast ... I guess maybe that's just a bad idea πŸ˜• ? But for example when creating one resource per subnet it is very tempting to put the subnet name in the resource name. And that is quite hard actually. How do people do this usually?
d

dry-keyboard-94795

10/25/2023, 10:14 AM
Depends on the case. Sometimes Maps to keep track of resources associated to a name, or a ComponentResource to group creation together
Others just use a list index, though maps are safer as they're order independent (less side effects when modifying the list)
i

important-market-84330

10/25/2023, 10:18 AM
Yep I think I used indexes before, but I am indeed a bit scared of ordering... I updated the code to this now:
Copy code
private val networkAssociations = attachedSubnets
        .mapIndexed { i, subnet ->
            NetworkAssociation(
                "clientvpn-attachment-$i",
                NetworkAssociationArgs.builder()
                    .clientVpnEndpointId(this.id())
                    .subnetId(subnet.id())
                    .build(),
                CustomResourceOptions.builder()
                    .aliases(Alias.builder().name("clientvpn-attachment-subnet-0b1ccce02a2395452").build())
                    .build()
            )
        }
Using the alias πŸ˜‰
I'm a bit sad I can't see which AZ or subnet the attachment is for in the resource name though.
d

dry-keyboard-94795

10/25/2023, 10:24 AM
You could use tuples to store the subnet name, or key a Map with the AZ name. I could see using a ComponentResource per AZ to be useful, though that's a more involved change
i

important-market-84330

10/25/2023, 10:24 AM
Hmm I need to look into ComponentResource also, haven't used it yet
I've been using inheritance now to logically group resources, that pattern seems to work nicely
The Kotlin way of inheritance lends itself very well to this
Eg.:
Copy code
class MyVpc(...) : Vpc(...) {
  val myCustomVpcResource = ...

  private val myHiddenCustomVpcResource = ...
}
5 Views