3
votes

I have the following ARM Template structure:

Parent Template
  |--Nested Template 1 
  |--...
  |--Nested Template 6

So I only have 2 levels of templates, Parent and nested.

Lets say I deploy parent to an empty resource group and everything works well. After that I delete one of the resources and want to deploy the same Parent Template with the same parameters to bring deleted resources back. But the deployment would fail saying that the resource already exists (the other, not the one i'm tried to recreate). I tried both incremental mode and full mode for deployments. If i directly invoke nested template with the missing resources it works as expected (so specifically creating a deployment with nested template only, not with parent that invokes nested template).

UPD: After some additional testing I can conclude thats even weirder then before. So I'm starting this deployment with powershell:

New-AzureRmResourceGroupDeployment @parameters

And it deploys just fine, however if I invoke the same command after the first deployment completed I would get an error:

The resource 'gggg-1s-the-wordd' already exists in location 'westeurope' in resource group 'gggg'. A resource with the same name cannot be created in location 'northeurope'. Please select a new resource name.

Is this behavior excepted? I can't seem to find anything relevant, thanks!

UPD2: It doesn't really matter if I use portal or powershell, I get the same error.

3
Redeploy simply starts a new deployment with the same template and parameters, so it makes sense that it does the same thing as a separate deployment in either portal or PowerShell.Michael Flanakin
But it doesn't make sense that it errors out4c74356b41
There is difference in how resourceGroup() function resolves between nested and linked template. Basically in nested template specifying resourcegroup gets resourcegroup of the main template, so if you use resourceGroup().location, you could be pointing in the wrong place. The following document explains it well. docs.microsoft.com/en-us/azure/azure-resource-manager/…Gopal Krishnan

3 Answers

2
votes

So with the help from Brian we were able to identify the culprit. The issue was that the WebApp had its location set to resourcegroup().location while the App Service Plan was correctly getting location from parameters. So that lead to a problem where at deployment time WebApp would deploy to the region where its App Service Plan was, but at evaluation time it would consider that this WebApp belongs to the region where the resource group was. TLDR - copy paste error, which coupled with a bug in evaluation of location in ARM lead to a quite weird behavior.

1
votes

If you deploy the same resource (intentionally did not use the word "template" there) to the same resource group, Azure should "make it so". IOW, if it's not there, it will create it, if it is there, it should no-op. It's not that black and white there are some nuances (like you can't change certain properties if the resource exsists) but if you deploy the same resource with the same property values to the same resource group you should not get an error.

In general, nesting (or not) shouldn't affect any of this.

If you're deploying to different resource groups, then you could see an error about "already exists" depending on the resource.

All that said, it's really hard to tell in your specific case what's going on without more detail... So if this doesn't help, can you add some detail (what's the exact error message) or a repro (template that we could see the problem with)?

1
votes

I experienced the same issue. The reason was that, location of App Service was defined as [resourceGroup().location] instead of App service plan (ASP) location, which was creating the problem. I changed it by passing the location of ASP as a parameter to the template.

Getting location of of ASP is as:

internal static string GetASPLocation(TokenCloudCredentials credentials, string resourceGroup, string ASP)
    {
        Console.WriteLine($"Getting location of App Service Plan {ASP} in Resource Group {resourceGroup}");
        var resourceClient = new ResourceManagementClient(credentials);
        ResourceExistsResult result = resourceClient.Resources.CheckExistence(resourceGroup, new ResourceIdentity(ASP, "Microsoft.Web/serverfarms", "2015-08-01"));
        var appServicePlan = resourceClient.Resources.Get(resourceGroup, new ResourceIdentity(ASP, "Microsoft.Web/serverfarms", "2015-08-01"));
        return appServicePlan.Resource.Location;
    }

And in ARM template, location can be changed as :

"location": "[parameters('ASPLocation')]"