pulumi / pulumi-azure-native

Azure Native Provider
Apache License 2.0
126 stars 33 forks source link

Auto-purge CognitiveServices accounts on delete #2529

Open zlepper opened 1 year ago

zlepper commented 1 year ago

What happened?

Azure has made an absolutely stupid api.

If you create a cognitive services multi-service account (By specifying kind = "CognitiveServices") using pulumi. Delete it using pulumi and then try to create again you will be told you cannot create it because it has only been soft deleted.

Expected Behavior

I expect the resource to be completely and absolutely gone so I can reuse the name.

Steps to reproduce

 var account = new Account("account", new()
        {
            ResourceGroupName = args.ResourceGroup,
            Location = args.Location,
            Identity = new IdentityArgs()
            {
                Type = ResourceIdentityType.None,
            },
            Kind = "CognitiveServices", // Enable all cognitive services
            AccountName = accountName,
            Sku = new SkuArgs()
            {
                Name = "S0"
            },
            Properties = new AccountPropertiesArgs()
            {
                PublicNetworkAccess = PublicNetworkAccess.Enabled,
                CustomSubDomainName = accountName,
                NetworkAcls = new NetworkRuleSetArgs()
                {
                    DefaultAction = NetworkRuleAction.Deny,
                    VirtualNetworkRules = new VirtualNetworkRuleArgs()
                    {
                        Id = args.DigizuiteCoreSubnetId,
                        IgnoreMissingVnetServiceEndpoint = false,
                    }
                },
            },
            Tags = args.Tags,
        }, opts);

Run pulumi up, down and up on that.

Output of pulumi about

This is a pulumi automation project, so not quite possible.

Additional context

This is not pulumi that is in the wrong here.

Azure is doing something absolutely absurdly horrifyingly immensely stupid here. To actually clean up the account completely, you have to call the "purge" API here: https://learn.microsoft.com/en-us/rest/api/cognitiveservices/accountmanagement/deleted-accounts/purge?tabs=HTTP after you have called delete on the resource. And then you have to await the operation, which they have not documented how to do....

I have not encountered any other resource with this behavior so far.

Contributing

Vote on this issue by adding a đź‘Ť reaction. To contribute a fix for this issue, leave a comment (and link to your pull request, if you've opened one already).

danielrbradley commented 1 year ago

Thanks for filing this @zlepper

I'm going to update this to be an enhancement given that we're following the spec accurately right now, but this would be a good option to provide to a user to auto-purge on delete.

A quick search shows around 100 specifications which have a /purge endpoint available so this is likely a wider issue that could be solved.

I believe a good design here would be to add a custom property along the lines of "PurgeOnDelete" which opts-in to this behaviour. I think this should be opt-in as we generally want to have comparible behaviour to ARM as a starting point.

This should be implemented based on inspecting the specification for if there's a purge endpoint available for a given resource and automatically adapting the resource to have this functionality.

chutch1122 commented 1 year ago

In the meantime, the way I have solved this is to have your Cognitive Services account depend on a custom command (from @pulumi/command) that runs an Azure CLI command when it is deleted.

When your Cognitive Services account is deleted, the az cognitiveservices account purge command will be run.

My example is in Python, but the pattern should work similarly for TypeScript.

purge_azure_cognitive_services_account = Command(
    "purge-cognitive-service-account",
    delete=Output.format(
        "az cognitiveservices account purge --name {resource_name} --resource-group {resource_group_name} --location {location}",
        resource_name=resource_name("cs"), # this must match the name of the cognitive services account you are going to create below
        resource_group_name=resource_group.name,
        location="eastus2",
    ),
)

cognitive_services_account = Account(
    "cognitive-services-account",
    account_name=resource_name("cs"),
    # ...
    opts=pulumi.ResourceOptions(
        depends_on=[purge_azure_cognitive_services_account],
        ignore_changes=["properties.provisioningState"],
    )
)
danielrbradley commented 1 year ago

Excellent, thank you for sharing that @chutch1122

nadavfischer commented 3 months ago

Important note: if you have multiple subscriptions the purge might fail if the correct subscription is not specified. This is the full command to use: az cognitiveservices account purge --name {resource_name} --resource-group {resource_group_name} --location {location} --subscription {subscription_id}