Are there any good solutions for working with an a...
# dotnet
a
Are there any good solutions for working with an apply that needs to create resources? For example, I'm working with an Azure App Service. It outputs a list of potential outbound IP addresses that I then need to fire over to Mongo to create IP allow rules for. The code I have at the moment looks like this (
WebAppComponent
is a simple wrapper that constructs a
WebApp
,
AppServicePlan
, and
WebAppSlot
)
Copy code
public void UpdateAccessList(WebAppComponent webApp)
{
    _ = webApp.Resource.PossibleOutboundIpAddresses.Apply(
        outboundIps => outboundIps.Split(",").Select(
            outboundIp => new ProjectIpAccessList(NameGenerator.MongoIpAccessRule(outboundIp), new ProjectIpAccessListArgs
            {
                Comment = webApp.Resource.Name.Apply(x => $"Azure AppService - {x}"),
                IpAddress = outboundIp,
                ProjectId = Resource.ProjectId,
            }, new CustomResourceOptions
            {
                Provider = MongoProvider.Provider,
                DependsOn = { webApp.Resource, Resource }
            })
        ).ToList());
}
Which is super, until at some point Pulumi (arguably, reasonably) decides that all these resources need to be deleted because subsequent previews don't include them 😄 EDIT: It seems that if you go through with the update pulumi doesn't actually delete the
ProjectIpAccessList
resources - presumably because the value of the
.apply
becomes available during the run, but this is not available at
preview
time. I wonder if this could be solved by making the
PossibleOutboundIpAddresses
property an output so that it is available for subsequent runs of
up
?
s
Creating resources in an apply is to be avoided, but isn't always avoidable (sad panda). Your first preview/apply will definitely not include anything in an apply one way or the other because the value isn't known. I can't remember if subsequent preview/applies will include the resource - gonna have to run it and see. I have a vague notion that resources in an apply are included because the value is known, but that could be wishful thinking. The main issue is that you don't get the preview reliably, but the behavior of the program will be the same regardless. That is, there's no connection between preview and apply in the sense that the preview is just a dry run (which you can even skip if you want to, but don't do that for anything important). The apply is not necessarily bound by what is shown in the preview.
a
Very much sad panda 😄
s
I don't know these particular resources, but this seems like the type of place where you do need to create resources in an apply. For me, it's nearly always involved dealing with an Output that's an Array.
The place where I hit it often is with the AWSX VPC and then needing to add routes or VPC endpoints in a
foreach id in subnetIds
.
a
Just made an edit along the lines of your reply after realising what was going on after following through with the update. It seems that outputting the value leads to more reliable previews, so this may be a workaround?
s
Yeah, or you could do the
ProjectIpAccessList
in a separate stack if the overhead is worth the safety you'd get.
Inputs, Outputs, and Apply is the necessary tax you pay tradeoff for being able to use a general purpose programming languages in a declarative way. Unfortunately, languages do not have the necessary constructs to do it any other way.
a
Yeah, really anything that is a firewall or network type config is going to have this issue where the resource addresses are unknown. I can think of a few ways to work around it, but they would all have drawbacks - which I guess explains why it works how it works
I guess it kinda depends how much you care about the Preview being accurate. If there was a way to annotate these kinds of resources so that they get previewed and created in a separate phase after everything else completes that would be a solution.
s
If you don't need a
/32
for these rules (i.e. a single IP), you might be able to avoid the apply. Could you maybe provision the public IP separately and pass it through?