pulumi / pulumi-azure-native

Azure Native Provider
Apache License 2.0
127 stars 34 forks source link

cannot create already existing resource virtualHubs/<hub>/hubRouteTables/Default #1350

Open graemefoster opened 2 years ago

graemefoster commented 2 years ago

Hello!

Issue details

I cannot update the defaultRouteTable created by Azure when I create a Virtual Hub. It's one of 2 automatically generated HubRouteTables. The other is 'noneRouteTable'.

Steps to reproduce

        var vhub = new VirtualHub(_name, new VirtualHubArgs()
        {
            ResourceGroupName = resourceGroup.Name,
            Location = resourceGroup.Location,
            AddressPrefix = "192.168.0.0/22",
            Sku = "Basic",
            VirtualWan = new SubResourceArgs
            {
                Id = vwan.Id
            }
        });

       //create a firewall which we want to send all traffic via

           var vhubRoutes = new HubRouteTable($"defaultRouteTable",
            new HubRouteTableArgs()
            {
                ResourceGroupName = resourceGroup.Name,
                RouteTableName = "defaultRouteTable",
                VirtualHubName = vhub.Name,
                Labels = { "default" },
                Routes = {},
                Routes = new InputList<HubRouteArgs>()
                {
                    new HubRouteArgs()
                    {
                       Name = "all_traffic",
                      Destinations = _connectedThings.Select(x => x.IpRange).ToArray(),
                      DestinationType = "CIDR",
                      NextHop = fwall.Id,
                      NextHopType = "ResourceId",
                   }
               }
            });

Expected: To add routes to the auto generated defaultRouteTable Actual: Error "cannot create already existing resource"

mikhailshilkov commented 2 years ago

@graemefoster Thank you for reporting this issue.

There is a routes property on VirtualHub - I wonder if you could specify the defaultRouteTable properties there inline as a workaround? Would you be able to give it a try and let us know if that unblocks you?

graemefoster commented 2 years ago

Thanks for the suggestion. My problem is not urgent, but the suggestion doesn’t work.

I need to add a default route to my firewall, on the route table generated by azure when I create the hub. But I cannot create the firewall without the virtual hub there, as the firewall references the hub.

So it’s a catch 22.

I can get around it by declaring the route table as an existing resource. But because of the random string attached to resources I don’t know it’s id until the stack is built.

Maybe these resources generated by the platform could be declared to Pulumi using output properties from resources created by my stack? So if Pulumi allowed me to specify a resource as “PlatformGenerated” using an Output as it’s id, Pulumi could grab it’s state the first time it sees it, and then let me update it in the same pass.

mikhailshilkov commented 2 years ago

That makes sense, thank you for the explanation. Any chance you can build a full repro (including all parent resources) that I could run and fix the issue?

the random string attached to resources I don’t know it’s id until the stack is built.

You could choose to specify an explicit name with virtualHubName property, then there will be no random suffix appended.

graemefoster commented 2 years ago

Cool - will get a full repo tomorrow for you. Am in Perth, Australia so a bit late at night here now.

Thanks for jumping onto the issue. Really appreciate the quick feedback loop.

And thanks for the tip on the explicit name.

mikhailshilkov commented 2 years ago

@graemefoster Are you still blocked on this? Any progress with a full repro?

graemefoster commented 2 years ago

Hey @mikhailshilkov apologies this wasn't blocking me and I completely forgot to respond. Here's some code that hopefully demonstrates the problem and you can use to recreate. I've added comments to the code where the problem is:

using Pulumi;
using Pulumi.AzureNative.Network;
using Pulumi.AzureNative.Network.Inputs;
using Pulumi.AzureNative.Resources;
using SubResourceArgs = Pulumi.AzureNative.Network.Inputs.SubResourceArgs;

public class FirewallIssue : Stack
{
    public FirewallIssue()
    {
        var resourceGroup = new ResourceGroup("resource-group");
        var vwan = new VirtualWan("test-vwan", new VirtualWanArgs
        {
            ResourceGroupName = resourceGroup.Name,
            Location = resourceGroup.Location,
            AllowVnetToVnetTraffic = true,
            AllowBranchToBranchTraffic = true
        });

        var vhub = new VirtualHub("test-vhub", new VirtualHubArgs
        {
            ResourceGroupName = resourceGroup.Name,
            Location = resourceGroup.Location,
            AddressPrefix = "192.168.0.0/22",
            Sku = "Standard",
            VirtualWan = new SubResourceArgs()
            {
                Id = vwan.Id
            }
        });

        var fwallPolicy = new FirewallPolicy($"test-fwall-policy",
            new FirewallPolicyArgs
            {
                ResourceGroupName = resourceGroup.Name,
                ThreatIntelMode = AzureFirewallThreatIntelMode.Alert,
                Sku = new FirewallPolicySkuArgs
                {
                    Tier = FirewallPolicySkuTier.Standard
                }
            });

        var fwall = new AzureFirewall($"test-fwall", new AzureFirewallArgs
        {
            Location = resourceGroup.Location,
            ResourceGroupName = resourceGroup.Name,
            Sku = new AzureFirewallSkuArgs
            {
                Tier = AzureFirewallSkuTier.Standard,
                Name = AzureFirewallSkuName.AZFW_Hub
            },
            VirtualHub = new SubResourceArgs
            {
                Id = vhub.Id
            },
            HubIPAddresses = new HubIPAddressesArgs
            {
                PublicIPs = new HubPublicIPAddressesArgs
                {
                    Count = 1
                }
            },
            FirewallPolicy = new SubResourceArgs
            {
                Id = fwallPolicy.Id
            }
        });

        //Problem is here. defaultRouteTable is automatically created as a new resource by the Virtual Hub, but Pulumi
        //is not aware of it. So this line fails with 'cannot create existing resource'.
        //There is also another route table created by the VHub called 'noneRouteTable'.
        //
        //To make it worse the VHub must exist before the firewall as there is a property on the Firewall called 'VHubId' which
        //associates the firewall with the VHub.
        //
        //So for this to work I need to be able to 
        // - Create the VHub
        // - Create the Firewall
        // - Get hold of the route table auto generated by the VHub and add a route pointing to the firewall. 
        var vhubRoutes = new HubRouteTable("defaultRouteTable",
            new HubRouteTableArgs
            {
                ResourceGroupName = resourceGroup.Name,
                RouteTableName = "defaultRouteTable",
                VirtualHubName = vhub.Name,
                Labels = { "default" },
                Name = "defaultRouteTable",
                Routes = new InputList<HubRouteArgs>
                {
                    new HubRouteArgs
                    {
                        Name = "all_traffic",
                        Destinations = new [] { "0.0.0.0/0"} ,
                        DestinationType = "CIDR",
                        NextHop = fwall.Id,
                        NextHopType = "ResourceId"
                    }
                }
            });
    }
}