12
12
// limitations under the License.
13
13
// ----------------------------------------------------------------------------------
14
14
15
+ using System . Collections . Generic ;
15
16
using System . Linq ;
16
17
using System . Management . Automation ;
17
18
using System . Security . Cryptography . X509Certificates ;
@@ -29,6 +30,7 @@ public class SetAzureServiceDiagnosticsExtensionCommand : BaseAzureServiceDiagno
29
30
{
30
31
[ Parameter ( Position = 0 , ValueFromPipelineByPropertyName = true , ParameterSetName = SetExtensionParameterSetName , HelpMessage = ExtensionParameterPropertyHelper . ServiceNameHelpMessage ) ]
31
32
[ Parameter ( Position = 0 , ValueFromPipelineByPropertyName = true , ParameterSetName = SetExtensionUsingThumbprintParameterSetName , HelpMessage = ExtensionParameterPropertyHelper . ServiceNameHelpMessage ) ]
33
+ [ Parameter ( Position = 0 , ValueFromPipelineByPropertyName = true , ParameterSetName = SetExtensionUsingDiagnosticsConfigurationParameterSetName , HelpMessage = ExtensionParameterPropertyHelper . ServiceNameHelpMessage ) ]
32
34
public override string ServiceName
33
35
{
34
36
get ;
@@ -37,6 +39,7 @@ public override string ServiceName
37
39
38
40
[ Parameter ( Position = 1 , ValueFromPipelineByPropertyName = true , ParameterSetName = SetExtensionParameterSetName , HelpMessage = ExtensionParameterPropertyHelper . SlotHelpMessage ) ]
39
41
[ Parameter ( Position = 1 , ValueFromPipelineByPropertyName = true , ParameterSetName = SetExtensionUsingThumbprintParameterSetName , HelpMessage = ExtensionParameterPropertyHelper . SlotHelpMessage ) ]
42
+ [ Parameter ( Position = 1 , ValueFromPipelineByPropertyName = true , ParameterSetName = SetExtensionUsingDiagnosticsConfigurationParameterSetName , HelpMessage = ExtensionParameterPropertyHelper . SlotHelpMessage ) ]
40
43
[ ValidateSet ( DeploymentSlotType . Production , DeploymentSlotType . Staging , IgnoreCase = true ) ]
41
44
public override string Slot
42
45
{
@@ -53,6 +56,14 @@ public override string[] Role
53
56
set ;
54
57
}
55
58
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
+
56
67
[ Parameter ( Position = 3 , ValueFromPipelineByPropertyName = true , ParameterSetName = SetExtensionParameterSetName , HelpMessage = ExtensionParameterPropertyHelper . X509CertificateHelpMessage ) ]
57
68
[ ValidateNotNullOrEmpty ]
58
69
public override X509Certificate2 X509Certificate
@@ -142,49 +153,152 @@ public override string ExtensionId
142
153
143
154
protected override void ValidateParameters ( )
144
155
{
156
+ // Common validation
145
157
base . ValidateParameters ( ) ;
146
158
ValidateService ( ) ;
147
159
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
+ }
152
177
}
153
178
154
179
public void ExecuteCommand ( )
155
180
{
156
181
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 ++ )
158
226
{
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
+ {
178
268
ExtensionConfigurationBuilder builder = ExtensionManager . GetBuilder ( extConfig ) ;
179
- if ( Role == null || ! Role . Any ( ) )
269
+ if ( configInput . Roles . All ( r => r . Default ) )
180
270
{
271
+ // If the configuration applies to all roles, remove the ones defined in each named roles
181
272
foreach ( var role in Deployment . Roles )
182
273
{
183
274
builder . Remove ( role . RoleName , ProviderNamespace , ExtensionName ) ;
184
275
}
185
276
}
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
+ }
186
300
187
- ChangeDeployment ( builder . ToConfiguration ( ) ) ;
301
+ return builder . ToConfiguration ( ) ;
188
302
}
189
303
190
304
protected override void OnProcessRecord ( )
0 commit comments