in cli/azd/pkg/infra/provisioning/bicep/bicep_provider.go [769:918]
func (p *BicepProvider) Destroy(
ctx context.Context,
options provisioning.DestroyOptions,
) (*provisioning.DestroyResult, error) {
modulePath := p.modulePath()
p.console.ShowSpinner(ctx, "Discovering resources to delete...", input.Step)
defer p.console.StopSpinner(ctx, "", input.StepDone)
compileResult, err := p.compileBicep(ctx, modulePath)
if err != nil {
return nil, fmt.Errorf("creating template: %w", err)
}
scope, err := p.scopeForTemplate(compileResult.Template)
if err != nil {
return nil, fmt.Errorf("computing deployment scope: %w", err)
}
completedDeployments, err := p.deploymentManager.CompletedDeployments(ctx, scope, p.env.Name(), "")
if err != nil {
return nil, fmt.Errorf("finding completed deployments: %w", err)
}
if len(completedDeployments) == 0 {
return nil, fmt.Errorf("no deployments found for environment, '%s'", p.env.Name())
}
mostRecentDeployment := completedDeployments[0]
deploymentToDelete := scope.Deployment(mostRecentDeployment.Name)
resourcesToDelete, err := deploymentToDelete.Resources(ctx)
if err != nil {
return nil, fmt.Errorf("getting resources to delete: %w", err)
}
groupedResources, err := azapi.GroupByResourceGroup(resourcesToDelete)
if err != nil {
return nil, fmt.Errorf("mapping resources to resource groups: %w", err)
}
if len(groupedResources) == 0 {
return nil, fmt.Errorf("%w, '%s'", infra.ErrDeploymentResourcesNotFound, deploymentToDelete.Name())
}
keyVaults, err := p.getKeyVaultsToPurge(ctx, groupedResources)
if err != nil {
return nil, fmt.Errorf("getting key vaults to purge: %w", err)
}
managedHSMs, err := p.getManagedHSMsToPurge(ctx, groupedResources)
if err != nil {
return nil, fmt.Errorf("getting managed hsms to purge: %w", err)
}
appConfigs, err := p.getAppConfigsToPurge(ctx, groupedResources)
if err != nil {
return nil, fmt.Errorf("getting app configurations to purge: %w", err)
}
apiManagements, err := p.getApiManagementsToPurge(ctx, groupedResources)
if err != nil {
return nil, fmt.Errorf("getting API managements to purge: %w", err)
}
cognitiveAccounts, err := p.getCognitiveAccountsToPurge(ctx, groupedResources)
if err != nil {
return nil, fmt.Errorf("getting cognitive accounts to purge: %w", err)
}
p.console.StopSpinner(ctx, "", input.StepDone)
if err := p.destroyDeploymentWithConfirmation(
ctx,
options,
deploymentToDelete,
groupedResources,
len(resourcesToDelete),
); err != nil {
return nil, fmt.Errorf("deleting resource groups: %w", err)
}
keyVaultsPurge := itemToPurge{
resourceType: "Key Vault",
count: len(keyVaults),
purge: func(skipPurge bool, self *itemToPurge) error {
return p.purgeKeyVaults(ctx, keyVaults, skipPurge)
},
}
managedHSMsPurge := itemToPurge{
resourceType: "Managed HSM",
count: len(managedHSMs),
purge: func(skipPurge bool, self *itemToPurge) error {
return p.purgeManagedHSMs(ctx, managedHSMs, skipPurge)
},
}
appConfigsPurge := itemToPurge{
resourceType: "App Configuration",
count: len(appConfigs),
purge: func(skipPurge bool, self *itemToPurge) error {
return p.purgeAppConfigs(ctx, appConfigs, skipPurge)
},
}
aPIManagement := itemToPurge{
resourceType: "API Management",
count: len(apiManagements),
purge: func(skipPurge bool, self *itemToPurge) error {
return p.purgeAPIManagement(ctx, apiManagements, skipPurge)
},
}
var purgeItem []itemToPurge
for _, item := range []itemToPurge{keyVaultsPurge, managedHSMsPurge, appConfigsPurge, aPIManagement} {
if item.count > 0 {
purgeItem = append(purgeItem, item)
}
}
// cognitive services are grouped by resource group because the name of the resource group is required to purge
groupByKind := cognitiveAccountsByKind(cognitiveAccounts)
for name, cogAccounts := range groupByKind {
addPurgeItem := itemToPurge{
resourceType: name,
count: len(cogAccounts),
purge: func(skipPurge bool, self *itemToPurge) error {
return p.purgeCognitiveAccounts(ctx, self.cognitiveAccounts, skipPurge)
},
cognitiveAccounts: groupByKind[name],
}
purgeItem = append(purgeItem, addPurgeItem)
}
if err := p.purgeItems(ctx, purgeItem, options); err != nil {
return nil, fmt.Errorf("purging resources: %w", err)
}
destroyResult := &provisioning.DestroyResult{
InvalidatedEnvKeys: slices.Collect(maps.Keys(p.createOutputParameters(
compileResult.Template.Outputs,
azapi.CreateDeploymentOutput(mostRecentDeployment.Outputs),
))),
}
// Since we have deleted the resource group, add AZURE_RESOURCE_GROUP to the list of invalidated env vars
// so it will be removed from the .env file.
if _, ok := scope.(*infra.ResourceGroupScope); ok {
destroyResult.InvalidatedEnvKeys = append(
destroyResult.InvalidatedEnvKeys, environment.ResourceGroupEnvVarName,
)
}
return destroyResult, nil
}