@@ -27,6 +27,12 @@ namespace Microsoft.Azure.WebJobs.Script.WebHost.Management
27
27
{
28
28
public class FunctionsSyncManager : IFunctionsSyncManager , IDisposable
29
29
{
30
+ // Until ANT 82 is fully released, the default value is disabled and we continue
31
+ // to return just the trigger data.
32
+ // After ANT 82, we will change the default to enabled.
33
+ // Note that this app setting is honored by both GeoMaster and Runtime.
34
+ public const string AzureWebsiteArmCacheEnabledDefaultValue = "0" ;
35
+
30
36
private const string HubName = "HubName" ;
31
37
private const string TaskHubName = "taskHubName" ;
32
38
private const string Connection = "connection" ;
@@ -47,10 +53,10 @@ public class FunctionsSyncManager : IFunctionsSyncManager, IDisposable
47
53
48
54
private CloudBlockBlob _hashBlob ;
49
55
50
- public FunctionsSyncManager ( IConfiguration configuration , IHostIdProvider hostIdProvider , IOptionsMonitor < ScriptApplicationHostOptions > applicationHostOptions , IOptions < LanguageWorkerOptions > languageWorkerOptions , ILoggerFactory loggerFactory , HttpClient httpClient , ISecretManagerProvider secretManagerProvider , IScriptWebHostEnvironment webHostEnvironment , IEnvironment environment , HostNameProvider hostNameProvider )
56
+ public FunctionsSyncManager ( IConfiguration configuration , IHostIdProvider hostIdProvider , IOptionsMonitor < ScriptApplicationHostOptions > applicationHostOptions , IOptions < LanguageWorkerOptions > languageWorkerOptions , ILogger < FunctionsSyncManager > logger , HttpClient httpClient , ISecretManagerProvider secretManagerProvider , IScriptWebHostEnvironment webHostEnvironment , IEnvironment environment , HostNameProvider hostNameProvider )
51
57
{
52
58
_applicationHostOptions = applicationHostOptions ;
53
- _logger = loggerFactory ? . CreateLogger ( ScriptConstants . LogCategoryHostGeneral ) ;
59
+ _logger = logger ;
54
60
_workerConfigs = languageWorkerOptions . Value . WorkerConfigs ;
55
61
_httpClient = httpClient ;
56
62
_secretManagerProvider = secretManagerProvider ;
@@ -61,6 +67,14 @@ public FunctionsSyncManager(IConfiguration configuration, IHostIdProvider hostId
61
67
_hostNameProvider = hostNameProvider ;
62
68
}
63
69
70
+ internal bool ArmCacheEnabled
71
+ {
72
+ get
73
+ {
74
+ return _environment . GetEnvironmentVariableOrDefault ( EnvironmentSettingNames . AzureWebsiteArmCacheEnabled , AzureWebsiteArmCacheEnabledDefaultValue ) == "1" ;
75
+ }
76
+ }
77
+
64
78
public async Task < SyncTriggersResult > TrySyncTriggersAsync ( bool checkHash = false )
65
79
{
66
80
var result = new SyncTriggersResult
@@ -237,15 +251,72 @@ internal async Task<CloudBlockBlob> GetHashBlobAsync()
237
251
return _hashBlob ;
238
252
}
239
253
240
- public async Task < JArray > GetSyncTriggersPayload ( )
254
+ public async Task < JToken > GetSyncTriggersPayload ( )
241
255
{
242
256
var hostOptions = _applicationHostOptions . CurrentValue . ToHostOptions ( ) ;
243
- var functionsMetadata = WebFunctionsManager . GetFunctionsMetadata ( hostOptions , _workerConfigs , _logger , includeProxies : true ) ;
257
+ var functionsMetadata = WebFunctionsManager . GetFunctionsMetadata ( hostOptions , _workerConfigs , _logger ) ;
244
258
245
- // Add trigger information used by the ScaleController
246
- JObject result = new JObject ( ) ;
259
+ // trigger information used by the ScaleController
247
260
var triggers = await GetFunctionTriggers ( functionsMetadata , hostOptions ) ;
248
- return new JArray ( triggers ) ;
261
+ var triggersArray = new JArray ( triggers ) ;
262
+
263
+ if ( ! ArmCacheEnabled )
264
+ {
265
+ // extended format is disabled - just return triggers
266
+ return triggersArray ;
267
+ }
268
+
269
+ // Add triggers to the payload
270
+ JObject result = new JObject ( ) ;
271
+ result . Add ( "triggers" , triggersArray ) ;
272
+
273
+ // Add functions details to the payload
274
+ JObject functions = new JObject ( ) ;
275
+ string routePrefix = await WebFunctionsManager . GetRoutePrefix ( hostOptions . RootScriptPath ) ;
276
+ var functionDetails = await WebFunctionsManager . GetFunctionMetadataResponse ( functionsMetadata , hostOptions , _hostNameProvider ) ;
277
+ result . Add ( "functions" , new JArray ( functionDetails . Select ( p => JObject . FromObject ( p ) ) ) ) ;
278
+
279
+ // Add functions secrets to the payload
280
+ // Only secret types we own/control can we cache directly
281
+ // Encryption is handled by Antares before storage
282
+ var secretsStorageType = _environment . GetEnvironmentVariable ( EnvironmentSettingNames . AzureWebJobsSecretStorageType ) ;
283
+ if ( string . IsNullOrEmpty ( secretsStorageType ) ||
284
+ string . Compare ( secretsStorageType , "files" , StringComparison . OrdinalIgnoreCase ) == 0 ||
285
+ string . Compare ( secretsStorageType , "blob" , StringComparison . OrdinalIgnoreCase ) == 0 )
286
+ {
287
+ JObject secrets = new JObject ( ) ;
288
+ result . Add ( "secrets" , secrets ) ;
289
+
290
+ // add host secrets
291
+ var hostSecretsInfo = await _secretManagerProvider . Current . GetHostSecretsAsync ( ) ;
292
+ var hostSecrets = new JObject ( ) ;
293
+ hostSecrets . Add ( "master" , hostSecretsInfo . MasterKey ) ;
294
+ hostSecrets . Add ( "function" , JObject . FromObject ( hostSecretsInfo . FunctionKeys ) ) ;
295
+ hostSecrets . Add ( "system" , JObject . FromObject ( hostSecretsInfo . SystemKeys ) ) ;
296
+ secrets . Add ( "host" , hostSecrets ) ;
297
+
298
+ // add function secrets
299
+ var functionSecrets = new JArray ( ) ;
300
+ var httpFunctions = functionsMetadata . Where ( p => ! p . IsProxy && p . InputBindings . Any ( q => q . IsTrigger && string . Compare ( q . Type , "httptrigger" , StringComparison . OrdinalIgnoreCase ) == 0 ) ) . Select ( p => p . Name ) ;
301
+ foreach ( var functionName in httpFunctions )
302
+ {
303
+ var currSecrets = await _secretManagerProvider . Current . GetFunctionSecretsAsync ( functionName ) ;
304
+ var currElement = new JObject ( )
305
+ {
306
+ { "name" , functionName } ,
307
+ { "secrets" , JObject . FromObject ( currSecrets ) }
308
+ } ;
309
+ functionSecrets . Add ( currElement ) ;
310
+ }
311
+ secrets . Add ( "function" , functionSecrets ) ;
312
+ }
313
+ else
314
+ {
315
+ // TODO: handle other external key storage types
316
+ // like KeyVault when the feature comes online
317
+ }
318
+
319
+ return result ;
249
320
}
250
321
251
322
internal async Task < IEnumerable < JObject > > GetFunctionTriggers ( IEnumerable < FunctionMetadata > functionsMetadata , ScriptJobHostOptions hostOptions )
@@ -352,7 +423,15 @@ internal HttpRequestMessage BuildSetTriggersRequest()
352
423
{
353
424
var token = SimpleWebTokenHelper . CreateToken ( DateTime . UtcNow . AddMinutes ( 5 ) ) ;
354
425
355
- _logger . LogDebug ( $ "SyncTriggers content: { content } ") ;
426
+ string sanitizedContentString = content ;
427
+ if ( ArmCacheEnabled )
428
+ {
429
+ // sanitize the content before logging
430
+ var sanitizedContent = JObject . Parse ( content ) ;
431
+ sanitizedContent . Remove ( "secrets" ) ;
432
+ sanitizedContentString = sanitizedContent . ToString ( ) ;
433
+ }
434
+ _logger . LogDebug ( $ "SyncTriggers content: { sanitizedContentString } ") ;
356
435
357
436
using ( var request = BuildSetTriggersRequest ( ) )
358
437
{
@@ -381,4 +460,4 @@ public void Dispose()
381
460
_syncSemaphore . Dispose ( ) ;
382
461
}
383
462
}
384
- }
463
+ }
0 commit comments