Skip to content

Commit 89ac373

Browse files
committed
Add parameter -DiagnosticsConfiguration, so the Set-AzureServiceDiagnosticsExtension can take an array of configuration and update multi roles with different configurations
1 parent 1f41627 commit 89ac373

File tree

4 files changed

+164
-38
lines changed

4 files changed

+164
-38
lines changed

src/ServiceManagement/Compute/Commands.ServiceManagement/Extensions/Common/BaseAzureServiceExtensionCmdlet.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public abstract class BaseAzureServiceExtensionCmdlet : ServiceManagementBaseCmd
4141
protected const string NewExtensionUsingThumbprintParameterSetName = "NewExtensionUsingThumbprint";
4242
protected const string SetExtensionParameterSetName = "SetExtension";
4343
protected const string SetExtensionUsingThumbprintParameterSetName = "SetExtensionUsingThumbprint";
44+
protected const string SetExtensionUsingDiagnosticsConfigurationParameterSetName = "SetExtensionUsingDiagnosticsConfiguration";
4445
protected const string RemoveByRolesParameterSet = "RemoveByRoles";
4546
protected const string RemoveAllRolesParameterSet = "RemoveAllRoles";
4647

@@ -115,10 +116,9 @@ protected void ValidateDeployment()
115116
PeerDeployment = GetPeerDeployment(Slot);
116117
}
117118

118-
protected void ValidateRoles()
119+
protected void ValidateRoles(string[] roles)
119120
{
120-
Role = Role == null ? new string[0] : Role.Select(r => r == null ? string.Empty : r.Trim()).Distinct().ToArray();
121-
foreach (string roleName in Role)
121+
foreach (string roleName in roles)
122122
{
123123
if (Deployment.Roles == null || !Deployment.Roles.Any(r => r.RoleName == roleName))
124124
{
@@ -132,6 +132,12 @@ protected void ValidateRoles()
132132
}
133133
}
134134

135+
protected void ValidateRoles()
136+
{
137+
Role = Role == null ? new string[0] : Role.Select(r => r == null ? string.Empty : r.Trim()).Distinct().ToArray();
138+
ValidateRoles(Role);
139+
}
140+
135141
protected void ValidateThumbprint(bool uploadCert)
136142
{
137143
if (X509Certificate != null)

src/ServiceManagement/Compute/Commands.ServiceManagement/Extensions/Common/ExtensionManager.cs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,15 +140,10 @@ private void GetThumbprintAndAlgorithm(IList<HostedServiceListExtensionsResponse
140140
thumbprintAlgorithm = string.Empty;
141141
}
142142
}
143-
143+
144144
public ExtensionConfiguration InstallExtension(ExtensionConfigurationInput context, string slot,
145-
DeploymentGetResponse deployment, DeploymentGetResponse peerDeployment)
145+
ExtensionConfiguration extConfig, ExtensionConfiguration secondSlotExtConfig)
146146
{
147-
Func<DeploymentGetResponse, ExtensionConfiguration> func = (d) => d == null ? null : d.ExtensionConfiguration;
148-
149-
ExtensionConfiguration extConfig = func(deployment);
150-
ExtensionConfiguration secondSlotExtConfig = func(peerDeployment);
151-
152147
ExtensionConfigurationBuilder builder = GetBuilder(extConfig);
153148
ExtensionConfigurationBuilder secondSlotConfigBuilder = null;
154149
if (secondSlotExtConfig != null)
@@ -240,6 +235,17 @@ public ExtensionConfiguration InstallExtension(ExtensionConfigurationInput conte
240235
return builder.ToConfiguration();
241236
}
242237

238+
public ExtensionConfiguration InstallExtension(ExtensionConfigurationInput context, string slot,
239+
DeploymentGetResponse deployment, DeploymentGetResponse peerDeployment)
240+
{
241+
Func<DeploymentGetResponse, ExtensionConfiguration> func = (d) => d == null ? null : d.ExtensionConfiguration;
242+
243+
ExtensionConfiguration extConfig = func(deployment);
244+
ExtensionConfiguration secondSlotExtConfig = func(peerDeployment);
245+
246+
return InstallExtension(context, slot, extConfig, secondSlotExtConfig);
247+
}
248+
243249
public void Uninstall(string nameSpace, string type, Microsoft.WindowsAzure.Management.Compute.Models.ExtensionConfiguration extConfig)
244250
{
245251
var extBuilder = GetBuilder(extConfig);

src/ServiceManagement/Compute/Commands.ServiceManagement/Extensions/Diagnostics/NewAzureServiceDiagnosticsExtensionConfig.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ public override AzureStorageContext StorageContext
9595
set;
9696
}
9797

98-
[Parameter(Position = 7, ValueFromPipelineByPropertyName = true, ParameterSetName = NewExtensionParameterSetName, HelpMessage = "Diagnostics Configuration")]
99-
[Parameter(Position = 7, ValueFromPipelineByPropertyName = true, ParameterSetName = NewExtensionUsingThumbprintParameterSetName, HelpMessage = "Diagnostics Configuration")]
98+
[Parameter(Position = 7, ValueFromPipelineByPropertyName = true, Mandatory = true, ParameterSetName = NewExtensionParameterSetName, HelpMessage = "Diagnostics Configuration")]
99+
[Parameter(Position = 7, ValueFromPipelineByPropertyName = true, Mandatory = true, ParameterSetName = NewExtensionUsingThumbprintParameterSetName, HelpMessage = "Diagnostics Configuration")]
100100
[ValidateNotNullOrEmpty]
101101
public override string DiagnosticsConfigurationPath
102102
{

src/ServiceManagement/Compute/Commands.ServiceManagement/Extensions/Diagnostics/SetAzureServiceDiagnosticsExtension.cs

Lines changed: 140 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// limitations under the License.
1313
// ----------------------------------------------------------------------------------
1414

15+
using System.Collections.Generic;
1516
using System.Linq;
1617
using System.Management.Automation;
1718
using System.Security.Cryptography.X509Certificates;
@@ -29,6 +30,7 @@ public class SetAzureServiceDiagnosticsExtensionCommand : BaseAzureServiceDiagno
2930
{
3031
[Parameter(Position = 0, ValueFromPipelineByPropertyName = true, ParameterSetName = SetExtensionParameterSetName, HelpMessage = ExtensionParameterPropertyHelper.ServiceNameHelpMessage)]
3132
[Parameter(Position = 0, ValueFromPipelineByPropertyName = true, ParameterSetName = SetExtensionUsingThumbprintParameterSetName, HelpMessage = ExtensionParameterPropertyHelper.ServiceNameHelpMessage)]
33+
[Parameter(Position = 0, ValueFromPipelineByPropertyName = true, ParameterSetName = SetExtensionUsingDiagnosticsConfigurationParameterSetName, HelpMessage = ExtensionParameterPropertyHelper.ServiceNameHelpMessage)]
3234
public override string ServiceName
3335
{
3436
get;
@@ -37,6 +39,7 @@ public override string ServiceName
3739

3840
[Parameter(Position = 1, ValueFromPipelineByPropertyName = true, ParameterSetName = SetExtensionParameterSetName, HelpMessage = ExtensionParameterPropertyHelper.SlotHelpMessage)]
3941
[Parameter(Position = 1, ValueFromPipelineByPropertyName = true, ParameterSetName = SetExtensionUsingThumbprintParameterSetName, HelpMessage = ExtensionParameterPropertyHelper.SlotHelpMessage)]
42+
[Parameter(Position = 1, ValueFromPipelineByPropertyName = true, ParameterSetName = SetExtensionUsingDiagnosticsConfigurationParameterSetName, HelpMessage = ExtensionParameterPropertyHelper.SlotHelpMessage)]
4043
[ValidateSet(DeploymentSlotType.Production, DeploymentSlotType.Staging, IgnoreCase = true)]
4144
public override string Slot
4245
{
@@ -53,6 +56,14 @@ public override string[] Role
5356
set;
5457
}
5558

59+
[Parameter(Position = 2, ValueFromPipelineByPropertyName = true, Mandatory = true, ParameterSetName = SetExtensionUsingDiagnosticsConfigurationParameterSetName, HelpMessage = "Diagnostics configuration")]
60+
[ValidateNotNullOrEmpty]
61+
public ExtensionConfigurationInput[] DiagnosticsConfiguration
62+
{
63+
get;
64+
set;
65+
}
66+
5667
[Parameter(Position = 3, ValueFromPipelineByPropertyName = true, ParameterSetName = SetExtensionParameterSetName, HelpMessage = ExtensionParameterPropertyHelper.X509CertificateHelpMessage)]
5768
[ValidateNotNullOrEmpty]
5869
public override X509Certificate2 X509Certificate
@@ -142,49 +153,152 @@ public override string ExtensionId
142153

143154
protected override void ValidateParameters()
144155
{
156+
// Common validation
145157
base.ValidateParameters();
146158
ValidateService();
147159
ValidateDeployment();
148-
ValidateRoles();
149-
ValidateThumbprint(true);
150-
ValidateStorageAccount();
151-
ValidateConfiguration();
160+
161+
if (this.ParameterSetName == SetExtensionUsingDiagnosticsConfigurationParameterSetName)
162+
{
163+
// Validate Role for each diagnostics configuration. Other validations have been done when create the configuration.
164+
foreach (var config in this.DiagnosticsConfiguration)
165+
{
166+
var roleNames = config.Roles.Where(r => !r.Default).Select(r => r.RoleName).ToArray();
167+
ValidateRoles(roleNames);
168+
}
169+
}
170+
else
171+
{
172+
ValidateRoles();
173+
ValidateThumbprint(true);
174+
ValidateStorageAccount();
175+
ValidateConfiguration();
176+
}
152177
}
153178

154179
public void ExecuteCommand()
155180
{
156181
ValidateParameters();
157-
ExtensionConfigurationInput context = new ExtensionConfigurationInput
182+
183+
var configurations = GetConfigurations();
184+
185+
var extConfig = Deployment == null ? null : Deployment.ExtensionConfiguration;
186+
var secondSlotExtConfig = PeerDeployment == null ? null : PeerDeployment.ExtensionConfiguration;
187+
188+
// The later configuration will override the previous one
189+
foreach (var config in configurations)
190+
{
191+
extConfig = ExtensionManager.InstallExtension(config, Slot, extConfig, secondSlotExtConfig);
192+
extConfig = PostProcessExtensionConfigAfterInstallExtension(config, extConfig);
193+
}
194+
195+
ChangeDeployment(extConfig);
196+
}
197+
198+
private List<ExtensionConfigurationInput> GetConfigurations()
199+
{
200+
var initConfigs = ParameterSetName == SetExtensionUsingDiagnosticsConfigurationParameterSetName
201+
? DiagnosticsConfiguration
202+
: new ExtensionConfigurationInput[] {
203+
new ExtensionConfigurationInput
204+
{
205+
Id = ExtensionId,
206+
Version = Version,
207+
ProviderNameSpace = ProviderNamespace,
208+
Type = ExtensionName,
209+
CertificateThumbprint = CertificateThumbprint,
210+
ThumbprintAlgorithm = ThumbprintAlgorithm,
211+
X509Certificate = X509Certificate,
212+
PublicConfiguration = PublicConfiguration,
213+
PrivateConfiguration = PrivateConfiguration,
214+
Roles = new ExtensionRoleList(Role != null && Role.Any()
215+
? Role.Select(r => new ExtensionRole(r))
216+
: Enumerable.Repeat(new ExtensionRole(), 1))
217+
}
218+
};
219+
220+
// Remove duplicate configuration for the same role.
221+
// This not only improve the efficieny, one more important reason is current InstallExtension() implementation assumes
222+
// we call change deployment directly after installation. Calling InstallExtension() multiple times for the same role
223+
// may result in removing the extension which is still working.
224+
var result = new List<ExtensionConfigurationInput>();
225+
for (var i = 0; i < initConfigs.Length; i++)
158226
{
159-
Id = ExtensionId,
160-
Version = Version,
161-
ProviderNameSpace = ProviderNamespace,
162-
Type = ExtensionName,
163-
CertificateThumbprint = CertificateThumbprint,
164-
ThumbprintAlgorithm = ThumbprintAlgorithm,
165-
X509Certificate = X509Certificate,
166-
PublicConfiguration = PublicConfiguration,
167-
PrivateConfiguration = PrivateConfiguration,
168-
Roles = new ExtensionRoleList(Role != null && Role.Any() ? Role.Select(r => new ExtensionRole(r)) : Enumerable.Repeat(new ExtensionRole(), 1))
169-
};
170-
171-
var secondSlotDeployment = GetDeployment(this.Slot == DeploymentSlotType.Production ? DeploymentSlotType.Staging : DeploymentSlotType.Production);
172-
173-
var extConfig = ExtensionManager.InstallExtension(context, Slot, Deployment, secondSlotDeployment);
174-
175-
// When Role is not specified, the extension is applied to allRoles.
176-
// However, we must clear the extension defined in any namedRoles. Otherwise, it will fail for trying to apply the same extension.
177-
// We only apply the fix here but not in ExtensionManager, so other commands won't get affected.
227+
var currentConfig = initConfigs[i];
228+
for (var j = i + 1; j < initConfigs.Length && currentConfig.Roles.Any(); j++)
229+
{
230+
var followingConfig = initConfigs[j];
231+
232+
// If the following configuration is applied to all roles, we simply ingore the whole current config.
233+
if (followingConfig.Roles.Any(r => r.Default))
234+
{
235+
currentConfig.Roles.Clear();
236+
}
237+
238+
// If the role appears in following config, we will take the later one and remove the role from current config.
239+
foreach(var role in currentConfig.Roles.ToArray())
240+
{
241+
if (followingConfig.Roles.Any(r => r.RoleName == role.RoleName))
242+
{
243+
currentConfig.Roles.Remove(role);
244+
}
245+
}
246+
}
247+
248+
if (currentConfig.Roles.Any())
249+
{
250+
result.Add(currentConfig);
251+
}
252+
}
253+
254+
return result;
255+
}
256+
257+
/// <summary>
258+
/// The configuration must be defined in either allRoles or namedRoles.
259+
/// Otherwise, it will fail for trying to apply the same extension.
260+
/// We only apply the fix here but not in ExtensionManager, so other commands won't get affected.
261+
/// </summary>
262+
/// <param name="configInput">The configuration used for InstallExtension()</param>
263+
/// <param name="extConfig">The extension config after InstallExtension()</param>
264+
private Microsoft.WindowsAzure.Management.Compute.Models.ExtensionConfiguration PostProcessExtensionConfigAfterInstallExtension(
265+
ExtensionConfigurationInput configInput,
266+
Microsoft.WindowsAzure.Management.Compute.Models.ExtensionConfiguration extConfig)
267+
{
178268
ExtensionConfigurationBuilder builder = ExtensionManager.GetBuilder(extConfig);
179-
if (Role == null || !Role.Any())
269+
if (configInput.Roles.All(r => r.Default))
180270
{
271+
// If the configuration applies to all roles, remove the ones defined in each named roles
181272
foreach (var role in Deployment.Roles)
182273
{
183274
builder.Remove(role.RoleName, ProviderNamespace, ExtensionName);
184275
}
185276
}
277+
else
278+
{
279+
// If the configuration applies to some specific roles and there is already extension defined in allRoles,
280+
// we remove the setting from allRoles and move it to specific namedRoles.
281+
if (builder.ExistDefault(ProviderNamespace, ExtensionName))
282+
{
283+
var diagnosticExtensionId = extConfig.AllRoles.FirstOrDefault(ext =>
284+
{
285+
var e = ExtensionManager.GetExtension(ext.Id);
286+
return e != null && e.ProviderNamespace == ProviderNamespace && e.Type == ExtensionName;
287+
}).Id;
288+
builder.RemoveDefault(diagnosticExtensionId);
289+
290+
foreach (var role in Deployment.Roles)
291+
{
292+
// The role is previously configured by allRoles, move it to the namedRole itself
293+
if (!configInput.Roles.Exists(r => r.RoleName == role.RoleName))
294+
{
295+
builder.Add(role.RoleName, diagnosticExtensionId);
296+
}
297+
}
298+
}
299+
}
186300

187-
ChangeDeployment(builder.ToConfiguration());
301+
return builder.ToConfiguration();
188302
}
189303

190304
protected override void OnProcessRecord()

0 commit comments

Comments
 (0)