Skip to content

Commit c52cb24

Browse files
committed
Display nested errors when template deployment validate fails in new-deployment
1 parent 60f541b commit c52cb24

File tree

10 files changed

+123
-39
lines changed

10 files changed

+123
-39
lines changed

src/ResourceManager/Resources/Commands.Resources.Test/Commands.Resources.Test.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
</Reference>
7373
<Reference Include="Microsoft.Azure.ResourceManager, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
7474
<SpecificVersion>False</SpecificVersion>
75-
<HintPath>..\..\..\packages\Microsoft.Azure.Management.Resources.2.19.0-preview\lib\net40\Microsoft.Azure.ResourceManager.dll</HintPath>
75+
<HintPath>..\..\..\packages\Microsoft.Azure.Management.Resources.2.20.0-preview\lib\net40\Microsoft.Azure.ResourceManager.dll</HintPath>
7676
</Reference>
7777
<Reference Include="Microsoft.Azure.Test.Framework">
7878
<HintPath>..\..\..\packages\Microsoft.Azure.Test.Framework.1.0.5896.19355-prerelease\lib\net45\Microsoft.Azure.Test.Framework.dll</HintPath>

src/ResourceManager/Resources/Commands.Resources.Test/Models.ResourceGroups/ResourceClientTests.cs

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -833,21 +833,16 @@ public void TestTemplateShowsErrorMessage()
833833
.Returns(Task.Factory.StartNew(() => new DeploymentValidateResponse
834834
{
835835
IsValid = false,
836-
Error = new ResourceManagementErrorWithDetails()
836+
Error = new ResourceManagementError()
837837
{
838838
Code = "404",
839-
Message = "Awesome error message",
840-
Details = new List<ResourceManagementError>(new[] { new ResourceManagementError
841-
{
842-
Code = "SubError",
843-
Message = "Sub error message"
844-
}})
839+
Message = "Awesome error message"
845840
}
846841
}))
847842
.Callback((string rg, string dn, Deployment d, CancellationToken c) => { deploymentFromValidate = d; });
848843

849844
IEnumerable<PSResourceManagerError> error = resourcesClient.ValidatePSResourceGroupDeployment(parameters, DeploymentMode.Incremental);
850-
Assert.Equal(2, error.Count());
845+
Assert.Equal(1, error.Count());
851846
}
852847

853848
[Fact]
@@ -870,15 +865,10 @@ public void TestTemplateShowsSuccessMessage()
870865
.Returns(Task.Factory.StartNew(() => new DeploymentValidateResponse
871866
{
872867
IsValid = true,
873-
Error = new ResourceManagementErrorWithDetails()
868+
Error = new ResourceManagementError()
874869
{
875870
Code = "404",
876-
Message = "Awesome error message",
877-
Details = new List<ResourceManagementError>(new[] { new ResourceManagementError
878-
{
879-
Code = "SubError",
880-
Message = "Sub error message"
881-
}})
871+
Message = "Awesome error message"
882872
}
883873
}))
884874
.Callback((string rg, string dn, Deployment d, CancellationToken c) => { deploymentFromValidate = d; });
@@ -907,7 +897,7 @@ public void NewResourceGroupUsesDeploymentNameForDeploymentName()
907897
.Returns(Task.Factory.StartNew(() => new DeploymentValidateResponse
908898
{
909899
IsValid = true,
910-
Error = new ResourceManagementErrorWithDetails()
900+
Error = new ResourceManagementError()
911901
}))
912902
.Callback((string rg, string dn, Deployment d, CancellationToken c) => { deploymentFromValidate = d; });
913903

@@ -1109,7 +1099,7 @@ public void NewResourceGroupWithDeploymentSucceeds()
11091099
.Returns(Task.Factory.StartNew(() => new DeploymentValidateResponse
11101100
{
11111101
IsValid = true,
1112-
Error = new ResourceManagementErrorWithDetails()
1102+
Error = new ResourceManagementError()
11131103
}))
11141104
.Callback((string rg, string dn, Deployment d, CancellationToken c) => { deploymentFromValidate = d; });
11151105
SetupListForResourceGroupAsync(parameters.ResourceGroupName, new List<GenericResourceExtended>() { new GenericResourceExtended() { Name = "website" } });
@@ -1210,7 +1200,7 @@ public void ShowsFailureErrorWhenResourceGroupWithDeploymentFails()
12101200
.Returns(Task.Factory.StartNew(() => new DeploymentValidateResponse
12111201
{
12121202
IsValid = true,
1213-
Error = new ResourceManagementErrorWithDetails()
1203+
Error = new ResourceManagementError()
12141204
}))
12151205
.Callback((string rg, string dn, Deployment d, CancellationToken c) => { deploymentFromValidate = d; });
12161206
SetupListForResourceGroupAsync(parameters.ResourceGroupName, new List<GenericResourceExtended>() { new GenericResourceExtended() { Name = "website" } });
@@ -1311,7 +1301,7 @@ public void ExtractsErrorMessageFromFailedDeploymentOperation()
13111301
.Returns(Task.Factory.StartNew(() => new DeploymentValidateResponse
13121302
{
13131303
IsValid = true,
1314-
Error = new ResourceManagementErrorWithDetails()
1304+
Error = new ResourceManagementError()
13151305
}))
13161306
.Callback((string rg, string dn, Deployment d, CancellationToken c) => { deploymentFromValidate = d; });
13171307
SetupListForResourceGroupAsync(parameters.ResourceGroupName, new List<GenericResourceExtended>() { new GenericResourceExtended() { Name = "website" } });

src/ResourceManager/Resources/Commands.Resources.Test/packages.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<package id="Microsoft.Azure.Insights" version="0.10.0-preview" targetFramework="net45" />
99
<package id="Microsoft.Azure.KeyVault.Core" version="1.0.0" targetFramework="net45" />
1010
<package id="Microsoft.Azure.Management.Authorization" version="1.1.0" targetFramework="net45" />
11-
<package id="Microsoft.Azure.Management.Resources" version="2.19.0-preview" targetFramework="net45" />
11+
<package id="Microsoft.Azure.Management.Resources" version="2.20.0-preview" targetFramework="net45" />
1212
<package id="Microsoft.Azure.Test.Framework" version="1.0.5896.19355-prerelease" targetFramework="net45" />
1313
<package id="Microsoft.Azure.Test.HttpRecorder" version="1.0.5896.19355-prerelease" targetFramework="net45" />
1414
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />

src/ResourceManager/Resources/Commands.Resources/Commands.Resources.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
</Reference>
7171
<Reference Include="Microsoft.Azure.ResourceManager, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
7272
<SpecificVersion>False</SpecificVersion>
73-
<HintPath>..\..\..\packages\Microsoft.Azure.Management.Resources.2.19.0-preview\lib\net40\Microsoft.Azure.ResourceManager.dll</HintPath>
73+
<HintPath>..\..\..\packages\Microsoft.Azure.Management.Resources.2.20.0-preview\lib\net40\Microsoft.Azure.ResourceManager.dll</HintPath>
7474
</Reference>
7575
<Reference Include="Microsoft.IdentityModel.Clients.ActiveDirectory, Version=2.18.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
7676
<HintPath>..\..\..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.18.206251556\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll</HintPath>

src/ResourceManager/Resources/Commands.Resources/Microsoft.Azure.Commands.Resources.format.ps1xml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@
1717
<ListItem>
1818
<Label>Message</Label>
1919
<PropertyName>Message</PropertyName>
20-
</ListItem>
20+
</ListItem>
21+
<ListItem>
22+
<Label>Details</Label>
23+
<PropertyName>Details</PropertyName>
24+
</ListItem>
2125
</ListItems>
2226
</ListEntry>
2327
</ListEntries>

src/ResourceManager/Resources/Commands.Resources/Models.ResourceGroups/PSResourceManagerError.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,17 @@
1313
// ----------------------------------------------------------------------------------
1414

1515

16+
using System.Collections.Generic;
1617
namespace Microsoft.Azure.Commands.Resources.Models
1718
{
1819
public class PSResourceManagerError
1920
{
2021
public string Code { get; set; }
2122

2223
public string Message { get; set; }
24+
25+
public string Target { get; set; }
26+
27+
public List<PSResourceManagerError> Details { get; set; }
2328
}
2429
}

src/ResourceManager/Resources/Commands.Resources/Models.ResourceGroups/ResourceClient.ResourceManager.cs

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,24 @@
1717
using System.Collections.Generic;
1818
using System.IO;
1919
using System.Linq;
20-
using System.Text;
2120
using Microsoft.Azure.Commands.Tags.Model;
2221
using Microsoft.Azure.Management.Resources;
2322
using Microsoft.Azure.Management.Resources.Models;
24-
using Microsoft.WindowsAzure;
2523
using ProjectResources = Microsoft.Azure.Commands.Resources.Properties.Resources;
2624
using Hyak.Common;
25+
using Newtonsoft.Json;
26+
using Newtonsoft.Json.Linq;
27+
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Entities.ErrorResponses;
28+
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Extensions;
2729

2830
namespace Microsoft.Azure.Commands.Resources.Models
2931
{
3032
public partial class ResourcesClient
3133
{
3234
public const string ResourceGroupTypeName = "ResourceGroup";
3335

36+
public const string ErrorFormat = "Error: Code={0}; Message={1}\r\n";
37+
3438
public static List<string> KnownLocations = new List<string>
3539
{
3640
"East Asia", "South East Asia", "East US", "West US", "North Central US",
@@ -302,11 +306,15 @@ public virtual PSResourceGroupDeployment ExecuteDeployment(CreatePSResourceGroup
302306

303307
if (validationInfo.Errors.Count != 0)
304308
{
305-
int counter = 1;
306-
string errorFormat = "Error {0}: Code={1}; Message={2}\r\n";
307-
StringBuilder errorsString = new StringBuilder();
308-
validationInfo.Errors.ForEach(e => errorsString.AppendFormat(errorFormat, counter++, e.Code, e.Message));
309-
throw new ArgumentException(errorsString.ToString());
309+
foreach(var error in validationInfo.Errors)
310+
{
311+
WriteError(string.Format(ErrorFormat, error.Code, error.Message));
312+
if(!string.IsNullOrEmpty(error.Details))
313+
{
314+
DisplayDetailedErrorMessage(error.Details);
315+
}
316+
}
317+
throw new InvalidOperationException("The deployment validation failed.");
310318
}
311319
else
312320
{
@@ -320,6 +328,40 @@ public virtual PSResourceGroupDeployment ExecuteDeployment(CreatePSResourceGroup
320328
return result.ToPSResourceGroupDeployment(parameters.ResourceGroupName);
321329
}
322330

331+
private void DisplayDetailedErrorMessage(string details)
332+
{
333+
dynamic errorMessage = JsonConvert.DeserializeObject(details);
334+
if (errorMessage != null)
335+
{
336+
var token = JToken.Parse(errorMessage.ToString());
337+
if(token is JArray)
338+
{
339+
var errors = details.FromJson<ExtendedErrorInfo[]>();
340+
foreach(var error in errors)
341+
{
342+
DisplayInnerDetailErrorMessage(error);
343+
}
344+
}
345+
else if (token is JObject)
346+
{
347+
var error = details.FromJson<ExtendedErrorInfo>();
348+
DisplayInnerDetailErrorMessage(error);
349+
}
350+
}
351+
}
352+
353+
private void DisplayInnerDetailErrorMessage(ExtendedErrorInfo error)
354+
{
355+
WriteError(string.Format(ErrorFormat, error.Code, error.Message));
356+
if(error.Details != null)
357+
{
358+
foreach(var innerError in error.Details)
359+
{
360+
DisplayInnerDetailErrorMessage(innerError);
361+
}
362+
}
363+
}
364+
323365
private string GenerateDeploymentName(CreatePSResourceGroupDeploymentParameters parameters)
324366
{
325367
if (!string.IsNullOrEmpty(parameters.DeploymentName))

src/ResourceManager/Resources/Commands.Resources/Models.ResourceGroups/ResourcesExtensions.cs

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
using Newtonsoft.Json;
2727
using Microsoft.Azure.Commands.Resources.Models.Authorization;
2828
using Microsoft.Azure.Management.Authorization.Models;
29+
using Newtonsoft.Json.Linq;
30+
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Entities.ErrorResponses;
31+
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Extensions;
2932

3033
namespace Microsoft.Azure.Commands.Resources.Models
3134
{
@@ -78,11 +81,55 @@ public static PSResourceGroupDeployment ToPSResourceGroupDeployment(this Deploym
7881

7982
public static PSResourceManagerError ToPSResourceManagerError(this ResourceManagementError error)
8083
{
81-
return new PSResourceManagerError
84+
PSResourceManagerError rmError = new PSResourceManagerError
85+
{
86+
Code = error.Code,
87+
Message = error.Message,
88+
Target = string.IsNullOrEmpty(error.Target) ? null : error.Target
89+
};
90+
91+
if(!string.IsNullOrEmpty(error.Details))
92+
{
93+
var token = JToken.Parse(error.Details);
94+
if (token is JArray)
8295
{
83-
Code = error.Code,
84-
Message = error.Message
85-
};
96+
var errors = error.Details.FromJson<ExtendedErrorInfo[]>();
97+
List<PSResourceManagerError> innerRMErrors = new List<PSResourceManagerError>();
98+
foreach (var innerError in errors)
99+
{
100+
innerRMErrors.Add(innerError.ToPSResourceManagerError());
101+
}
102+
rmError.Details = innerRMErrors;
103+
}
104+
else if (token is JObject)
105+
{
106+
var innerError = error.Details.FromJson<ResourceManagementError>();
107+
rmError.Details = new List<PSResourceManagerError> { innerError.ToPSResourceManagerError() };
108+
}
109+
}
110+
return rmError;
111+
}
112+
113+
public static PSResourceManagerError ToPSResourceManagerError(this ExtendedErrorInfo error)
114+
{
115+
PSResourceManagerError rmError = new PSResourceManagerError
116+
{
117+
Code = error.Code,
118+
Message = error.Message,
119+
Target = string.IsNullOrEmpty(error.Target) ? null : error.Target
120+
};
121+
122+
if(error.Details != null)
123+
{
124+
List<PSResourceManagerError> innerRMErrors = new List<PSResourceManagerError>();
125+
foreach(var innerError in error.Details)
126+
{
127+
innerRMErrors.Add(innerError.ToPSResourceManagerError());
128+
}
129+
rmError.Details = innerRMErrors;
130+
}
131+
132+
return rmError;
86133
}
87134

88135
public static PSResource ToPSResource(this GenericResourceExtended resource, ResourcesClient client, bool minimal)

src/ResourceManager/Resources/Commands.Resources/Models.ResourceGroups/TemplateValidationInfo.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,6 @@ public TemplateValidationInfo(DeploymentValidateResponse validationResult)
2929
if (validationResult.Error != null)
3030
{
3131
Errors.Add(validationResult.Error);
32-
if (validationResult.Error.Details != null && validationResult.Error.Details.Count > 0)
33-
{
34-
Errors.AddRange(validationResult.Error.Details);
35-
}
3632
}
3733
}
3834

src/ResourceManager/Resources/Commands.Resources/packages.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<package id="Microsoft.Azure.Gallery" version="2.6.2-preview" targetFramework="net45" />
77
<package id="Microsoft.Azure.Graph.RBAC" version="1.9.0-preview" targetFramework="net45" />
88
<package id="Microsoft.Azure.Management.Authorization" version="2.0.0" targetFramework="net45" />
9-
<package id="Microsoft.Azure.Management.Resources" version="2.19.0-preview" targetFramework="net45" />
9+
<package id="Microsoft.Azure.Management.Resources" version="2.20.0-preview" targetFramework="net45" />
1010
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="net45" />
1111
<package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net45" />
1212
<package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net45" />

0 commit comments

Comments
 (0)