Skip to content

Commit 9123a99

Browse files
Add Diagnostics and Warnings to Deployments WhatIf/Validate cmdlets (Azure#26732)
* Add diagnostics to what if output * Update ChangeLog.md * Add unsupportedReason to diagnostics * Add Diagnostics to TestDeployments * Remove comments * Update Test cmdlets to match WhatIf output * Update with Environment.NewLine * Update src/Resources/Resources/ChangeLog.md --------- Co-authored-by: Tate Smalligan <[email protected]> Co-authored-by: Yabo Hu <[email protected]>
1 parent ef7eb8c commit 9123a99

File tree

17 files changed

+357
-33
lines changed

17 files changed

+357
-33
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.Deployments;
2+
using System;
3+
using System.Collections.Generic;
4+
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Formatters;
5+
using System.Text;
6+
using Microsoft.Azure.Management.Resources.Models;
7+
8+
namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Extensions
9+
{
10+
public static class DiagnosticExtensions
11+
{
12+
private static readonly IReadOnlyDictionary<string, Color> ColorsByDiagnosticLevel =
13+
new Dictionary<string, Color>
14+
{
15+
[Level.Error] = Color.Red,
16+
[Level.Warning] = Color.DarkYellow,
17+
[Level.Info] = Color.Reset,
18+
};
19+
20+
public static Color ToColor(this string level)
21+
{
22+
bool success = ColorsByDiagnosticLevel.TryGetValue(level, out Color colorCode);
23+
24+
if (!success)
25+
{
26+
return Color.Gray;
27+
}
28+
29+
return colorCode;
30+
}
31+
}
32+
}

src/Resources/ResourceManager/Formatters/Color.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ public class Color : IEquatable<Color>
3434

3535
public static Color Reset { get; } = new Color($"{Esc}[0m");
3636

37+
public static Color Red { get; } = new Color($"{Esc}[38;5;196m");
38+
39+
public static Color DarkYellow { get; } = new Color($"{Esc}[38;5;136m");
40+
3741
private Color(string colorCode)
3842
{
3943
this.colorCode = colorCode;

src/Resources/ResourceManager/Formatters/WhatIfOperationResultFormatter.cs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Formatters
2828

2929
public class WhatIfOperationResultFormatter : WhatIfJsonFormatter
3030
{
31-
private WhatIfOperationResultFormatter(ColoredStringBuilder builder)
31+
public WhatIfOperationResultFormatter(ColoredStringBuilder builder)
3232
: base(builder)
3333
{
3434
}
@@ -47,6 +47,7 @@ public static string Format(PSWhatIfOperationResult result)
4747
formatter.FormatLegend(result.Changes);
4848
formatter.FormatResourceChanges(result.Changes);
4949
formatter.FormatStats(result.Changes);
50+
formatter.FormatDiagnostics(result.Diagnostics, result.Changes);
5051

5152
return builder.ToString();
5253
}
@@ -112,6 +113,45 @@ private void FormatStats(IList<PSWhatIfChange> resourceChanges)
112113
this.Builder.Append(".");
113114
}
114115

116+
public void FormatDiagnostics(IList<DeploymentDiagnosticsDefinition> diagnostics, IList<PSWhatIfChange> changes)
117+
{
118+
if (changes != null)
119+
{
120+
var unsupportedChanges = changes
121+
.Where(c => c.ChangeType == ChangeType.Unsupported)
122+
.ToList();
123+
124+
if (diagnostics == null)
125+
{
126+
diagnostics = new List<DeploymentDiagnosticsDefinition>();
127+
}
128+
foreach (var change in unsupportedChanges)
129+
{
130+
diagnostics.Add(new DeploymentDiagnosticsDefinition(level: Level.Warning, code: "Unsupported", message: change.UnsupportedReason, target: change.FullyQualifiedResourceId));
131+
}
132+
}
133+
134+
if (diagnostics == null || diagnostics.Count == 0)
135+
{
136+
return;
137+
}
138+
139+
this.Builder.AppendLine().AppendLine();
140+
141+
this.Builder.Append($"Diagnostics ({diagnostics.Count}): ").AppendLine();
142+
143+
diagnostics.ForEach(d =>
144+
{
145+
using (this.Builder.NewColorScope(DiagnosticExtensions.ToColor(d.Level)))
146+
{
147+
this.Builder.Append($"({d.Target})").Append(Symbol.WhiteSpace);
148+
this.Builder.Append(d.Message).Append(Symbol.WhiteSpace);
149+
this.Builder.Append($"({d.Code})");
150+
this.Builder.AppendLine();
151+
}
152+
});
153+
}
154+
115155
private string FormatChangeTypeCount(ChangeType changeType, int count)
116156
{
117157
switch (changeType)
@@ -141,7 +181,6 @@ private void FormatLegend(IList<PSWhatIfChange> resourceChanges)
141181
{
142182
return;
143183
}
144-
145184
var psChangeTypeSet = new HashSet<PSChangeType>();
146185

147186
void PopulateChangeTypeSet(IList<PSWhatIfPropertyChange> propertyChanges)

src/Resources/ResourceManager/Implementation/CmdletBase/TestDeploymentCmdletBase.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
24
using System.Management.Automation;
35
using Microsoft.Azure.Commands.Common.Strategies;
46
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Formatters;
7+
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.NewSdkExtensions;
58
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Properties;
69
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels;
710
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.Deployments;
@@ -23,5 +26,23 @@ public override object GetDynamicParameters()
2326
return base.GetDynamicParameters();
2427
}
2528

29+
public void WriteOutput(TemplateValidationInfo validationInfo)
30+
{
31+
if (validationInfo.Errors.Count == 0)
32+
{
33+
var builder = new ColoredStringBuilder();
34+
35+
var formatter = new WhatIfOperationResultFormatter(builder);
36+
37+
formatter.FormatDiagnostics(validationInfo.Diagnostics, new List<PSWhatIfChange>());
38+
39+
WriteObject(builder.ToString());
40+
}
41+
else
42+
{
43+
WriteObject(validationInfo.Errors.Select(e => e.ToPSResourceManagerError()).ToList());
44+
}
45+
}
46+
2647
}
2748
}

src/Resources/ResourceManager/Implementation/Deployments/TestAzureManagementGroupDeploymentCmdlet.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ protected override void OnProcessRecord()
5858
ParameterUri = this.TemplateParameterUri
5959
};
6060

61-
WriteObject(NewResourceManagerSdkClient.ValidateDeployment(parameters));
61+
var validationInfo = NewResourceManagerSdkClient.ValidateDeployment(parameters);
62+
63+
WriteOutput(validationInfo);
6264
}
6365
}
6466
}

src/Resources/ResourceManager/Implementation/Deployments/TestAzureSubscriptionDeploymentCmdlet.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ protected override void OnProcessRecord()
5454
ParameterUri = TemplateParameterUri
5555
};
5656

57-
WriteObject(NewResourceManagerSdkClient.ValidateDeployment(parameters));
57+
var validationInfo = NewResourceManagerSdkClient.ValidateDeployment(parameters);
58+
59+
WriteOutput(validationInfo);
5860
}
5961
}
6062
}

src/Resources/ResourceManager/Implementation/Deployments/TestAzureTenantDeploymentCmdlet.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ protected override void OnProcessRecord()
5454
ParameterUri = this.TemplateParameterUri
5555
};
5656

57-
WriteObject(NewResourceManagerSdkClient.ValidateDeployment(parameters));
57+
var validationInfo = NewResourceManagerSdkClient.ValidateDeployment(parameters);
58+
59+
WriteOutput(validationInfo);
5860
}
5961
}
6062
}

src/Resources/ResourceManager/Implementation/ResourceGroupDeployments/TestAzureResourceGroupDeploymentCmdlet.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ protected override void OnProcessRecord()
7979
: null
8080
};
8181

82-
WriteObject(NewResourceManagerSdkClient.ValidateDeployment(parameters));
82+
var validationInfo = NewResourceManagerSdkClient.ValidateDeployment(parameters);
83+
84+
WriteOutput(validationInfo);
8385
}
8486
}
8587
}

src/Resources/ResourceManager/SdkClient/NewResourceManagerSdkClient.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -491,17 +491,17 @@ private TemplateValidationInfo GetTemplateValidationResult(PSDeploymentCmdletPar
491491
switch (validationResult)
492492
{
493493
case DeploymentExtended deploymentExtended:
494-
return new TemplateValidationInfo(deploymentExtended.Properties?.Providers?.ToList() ?? new List<Provider>(), new List<ErrorDetail>());
494+
return new TemplateValidationInfo(deploymentExtended.Properties?.Providers?.ToList() ?? new List<Provider>(), new List<ErrorDetail>(), deploymentExtended.Properties?.Diagnostics?.ToList() ?? new List<DeploymentDiagnosticsDefinition>());
495495
case DeploymentValidationError deploymentValidationError:
496-
return new TemplateValidationInfo(new List<Provider>(), new List<ErrorDetail>(deploymentValidationError.Error.AsArray()));
496+
return new TemplateValidationInfo(new List<Provider>(), new List<ErrorDetail>(deploymentValidationError.Error.AsArray()), new List<DeploymentDiagnosticsDefinition>());
497497
default:
498498
throw new InvalidOperationException($"Received unexpected type {validationResult.GetType()}");
499499
}
500500
}
501501
catch (Exception ex)
502502
{
503503
var error = HandleError(ex).FirstOrDefault();
504-
return new TemplateValidationInfo(new List<Provider>(), error.AsArray().ToList());
504+
return new TemplateValidationInfo(new List<Provider>(), error.AsArray().ToList(), new List<DeploymentDiagnosticsDefinition>());
505505
}
506506
}
507507

@@ -1716,8 +1716,8 @@ private void CancelDeploymentAtResourceGroup(List<PSDeployment> deployments, str
17161716
/// Validates a given deployment.
17171717
/// </summary>
17181718
/// <param name="parameters">The deployment create options</param>
1719-
/// <returns>The validation errors if there's any, or empty list otherwise.</returns>
1720-
public virtual List<PSResourceManagerError> ValidateDeployment(PSDeploymentCmdletParameters parameters)
1719+
/// <returns>The validation info</returns>
1720+
public virtual TemplateValidationInfo ValidateDeployment(PSDeploymentCmdletParameters parameters)
17211721
{
17221722
if (parameters.DeploymentName == null)
17231723
{
@@ -1731,7 +1731,7 @@ public virtual List<PSResourceManagerError> ValidateDeployment(PSDeploymentCmdle
17311731
{
17321732
WriteVerbose(ProjectResources.TemplateValid);
17331733
}
1734-
return validationInfo.Errors.Select(e => e.ToPSResourceManagerError()).ToList();
1734+
return validationInfo;
17351735
}
17361736

17371737
public string GetDeploymentErrorMessagesWithOperationId(DeploymentOperationErrorInfo errorInfo, string deploymentName = null, string correlationId = null)

src/Resources/ResourceManager/SdkModels/Deployments/PSWhatIfChange.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public PSWhatIfChange(WhatIfChange whatIfChange)
4141
(string scope, string relativeResourceId) = ResourceIdUtility.SplitResourceId(whatIfChange.ResourceId);
4242
this.Scope = scope;
4343
this.RelativeResourceId = relativeResourceId;
44+
this.UnsupportedReason = whatIfChange.UnsupportedReason;
4445

4546
this.apiVersion = new Lazy<string>(() =>
4647
this.Before?["apiVersion"]?.Value<string>() ?? this.After?["apiVersion"]?.Value<string>());
@@ -54,6 +55,8 @@ public PSWhatIfChange(WhatIfChange whatIfChange)
5455

5556
public string RelativeResourceId { get; }
5657

58+
public string UnsupportedReason { get; }
59+
5760
public string FullyQualifiedResourceId => this.whatIfChange.ResourceId;
5861

5962
public ChangeType ChangeType => this.whatIfChange.ChangeType;

0 commit comments

Comments
 (0)