Skip to content

Commit b6343c0

Browse files
karshinlinHanzhang Zeng (Roger)
authored andcommitted
[pack] Reacting to ScriptHost configuration changes for AzureStorageProvider
1 parent 1d096e5 commit b6343c0

File tree

10 files changed

+53
-42
lines changed

10 files changed

+53
-42
lines changed

release_notes.md

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,2 @@
11
### Release notes
2-
<!-- Please add your release notes in the following format:
3-
- My change description (#PR)
4-
-->
5-
- Update Python Worker Version to [1.2.1](https://github.com/Azure/azure-functions-python-worker/releases/tag/1.2.1)
6-
7-
- Added a feature flag to opt out of the default behavior where the host sets the environment name to `Development` when running in debug mode. To disable the behavior, set the app setting: `AzureWebJobsFeatureFlags` to `DisableDevModeInDebug`
8-
- Reorder CORS and EasyAuth middleware to prevent EasyAuth from blocking CORS requests (#7315)
9-
- Updated PowerShell Worker (PS7) to [3.0.833](https://github.com/Azure/azure-functions-powershell-worker/releases/tag/v3.0.833)
10-
- Add IDistributedLockManager for Kubernetes environment (#7327)
11-
- Call EnableDrainModeAsync on ApplicationStopping (#7262)
12-
13-
**Release sprint:** Sprint 100
14-
[ [bugs](https://github.com/Azure/azure-functions-host/issues?q=is%3Aissue+milestone%3A%22Functions+Sprint+100%22+label%3Abug+is%3Aclosed) | [features](https://github.com/Azure/azure-functions-host/issues?q=is%3Aissue+milestone%3A%22Functions+Sprint+100%22+label%3Afeature+is%3Aclosed) ]
15-
- Update App Service Authentication/Authorization on Linux Consumption from 1.4.0 to 1.4.5. Release notes for this feature captured at https://github.com/Azure/app-service-announcements/issues. (#7205)
16-
- Add v12 Storage-dependent implementations to Functions Host to support Managed Identity integration
2+
This is a hotfix addressing issue with AzureStorageProvider using the wrong configuration in custom startup scenarios (#7424) [ [bug](https://github.com/Azure/azure-functions-host/issues/7440) ]

src/WebJobs.Script/ScriptHostBuilderExtensions.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,10 +464,15 @@ private static void AddProcessRegistry(IServiceCollection services)
464464
private static IDistributedLockManager GetBlobLockManager(IServiceProvider provider)
465465
{
466466
var azureStorageProvider = provider.GetRequiredService<IAzureStorageProvider>();
467+
var configuration = provider.GetRequiredService<IConfiguration>();
467468
var loggerFactory = provider.GetRequiredService<ILoggerFactory>();
468469
try
469470
{
470-
var container = azureStorageProvider.GetBlobContainerClient();
471+
// BlobLeaseDistributedLockManager is created during ScriptHost service registration since it is
472+
// conditioned on having a valid storage connection. The configuration should be from the IServiceProvider
473+
// that registers the IDistributedLockManager.
474+
// The configuration used by AzureStorageProvider will be updated through the IScriptHostManager.HostInitializing event handler
475+
var container = azureStorageProvider.GetBlobContainerClient(configuration);
471476
return new BlobLeaseDistributedLockManager(loggerFactory, azureStorageProvider);
472477
}
473478
catch (InvalidOperationException)

src/WebJobs.Script/StorageProvider/AzureStorageProvider.cs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using Azure.Storage.Blobs;
66
using Microsoft.Azure.WebJobs.Script.StorageProvider;
77
using Microsoft.Extensions.Configuration;
8+
using Microsoft.Extensions.DependencyInjection;
89
using Microsoft.Extensions.Logging;
910
using Microsoft.Extensions.Options;
1011

@@ -18,16 +19,23 @@ namespace Microsoft.Azure.WebJobs.Script
1819
internal class AzureStorageProvider : IAzureStorageProvider
1920
{
2021
private readonly BlobServiceClientProvider _blobServiceClientProvider;
21-
private readonly IConfiguration _configuration;
22-
private readonly ILogger _logger;
22+
private readonly IServiceProvider _serviceProvider;
2323
private IOptionsMonitor<JobHostInternalStorageOptions> _storageOptions;
24+
private IConfiguration _configuration;
2425

25-
public AzureStorageProvider(IConfiguration configuration, BlobServiceClientProvider blobServiceClientProvider, IOptionsMonitor<JobHostInternalStorageOptions> options, ILogger<AzureStorageProvider> logger)
26+
public AzureStorageProvider(IScriptHostManager scriptHostManager, IConfiguration configuration, BlobServiceClientProvider blobServiceClientProvider, IOptionsMonitor<JobHostInternalStorageOptions> options)
2627
{
2728
_blobServiceClientProvider = blobServiceClientProvider;
2829
_configuration = configuration;
30+
_serviceProvider = scriptHostManager as IServiceProvider;
2931
_storageOptions = options;
30-
_logger = logger;
32+
33+
// Every time script host is re-intializing, we also need to re-initialize
34+
// services that change with the scope of the script host.
35+
scriptHostManager.HostInitializing += (s, e) =>
36+
{
37+
InitializeServices();
38+
};
3139
}
3240

3341
/// <summary>
@@ -49,25 +57,30 @@ public virtual bool TryGetBlobServiceClientFromConnectionString(out BlobServiceC
4957
/// <param name="client">client to instantiate</param>
5058
/// <param name="connection">Name of the connection to use</param>
5159
/// <returns>successful client creation</returns>
52-
public virtual bool TryGetBlobServiceClientFromConnection(out BlobServiceClient client, string connection = null)
60+
public virtual bool TryGetBlobServiceClientFromConnection(out BlobServiceClient client, string connection = null, IConfiguration configurationOverride = null)
5361
{
5462
var connectionToUse = connection ?? ConnectionStringNames.Storage;
55-
return _blobServiceClientProvider.TryGet(connectionToUse, out client);
63+
return _blobServiceClientProvider.TryGet(connectionToUse, configurationOverride ?? _configuration, out client);
5664
}
5765

58-
public virtual BlobContainerClient GetBlobContainerClient()
66+
public virtual BlobContainerClient GetBlobContainerClient(IConfiguration configurationOverride = null)
5967
{
6068
if (_storageOptions?.CurrentValue.InternalSasBlobContainer != null)
6169
{
6270
return new BlobContainerClient(new Uri(_storageOptions.CurrentValue.InternalSasBlobContainer));
6371
}
6472

65-
if (!TryGetBlobServiceClientFromConnection(out BlobServiceClient blobServiceClient, ConnectionStringNames.Storage))
73+
if (!TryGetBlobServiceClientFromConnection(out BlobServiceClient blobServiceClient, ConnectionStringNames.Storage, configurationOverride))
6674
{
6775
throw new InvalidOperationException($"Could not create BlobServiceClient to obtain the BlobContainerClient using Connection: {ConnectionStringNames.Storage}");
6876
}
6977

7078
return blobServiceClient.GetBlobContainerClient(ScriptConstants.AzureWebJobsHostsContainerName);
7179
}
80+
81+
private void InitializeServices()
82+
{
83+
_configuration = _serviceProvider.GetService<IConfiguration>();
84+
}
7285
}
7386
}

src/WebJobs.Script/StorageProvider/BlobServiceClientProvider.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ namespace Microsoft.Azure.WebJobs.Script.StorageProvider
1616
/// </summary>
1717
internal class BlobServiceClientProvider : StorageClientProvider<BlobServiceClient, BlobClientOptions>
1818
{
19-
public BlobServiceClientProvider(IConfiguration configuration, AzureComponentFactory componentFactory, AzureEventSourceLogForwarder logForwarder, ILogger<BlobServiceClient> logger)
20-
: base(configuration, componentFactory, logForwarder, logger) { }
19+
public BlobServiceClientProvider(AzureComponentFactory componentFactory, AzureEventSourceLogForwarder logForwarder, ILogger<BlobServiceClient> logger)
20+
: base(componentFactory, logForwarder, logger) { }
2121

2222
/// <inheritdoc/>
2323
protected override string ServiceUriSubDomain

src/WebJobs.Script/StorageProvider/IAzureStorageProvider.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

44
using Azure.Storage.Blobs;
5+
using Microsoft.Extensions.Configuration;
56

67
namespace Microsoft.Azure.WebJobs.Script
78
{
@@ -13,8 +14,8 @@ public interface IAzureStorageProvider
1314
{
1415
bool TryGetBlobServiceClientFromConnectionString(out BlobServiceClient client, string connectionString);
1516

16-
bool TryGetBlobServiceClientFromConnection(out BlobServiceClient client, string connection);
17+
bool TryGetBlobServiceClientFromConnection(out BlobServiceClient client, string connection, IConfiguration configurationOverride = null);
1718

18-
BlobContainerClient GetBlobContainerClient();
19+
BlobContainerClient GetBlobContainerClient(IConfiguration configurationOverride = null);
1920
}
2021
}

src/WebJobs.Script/StorageProvider/StorageClientProvider.cs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ namespace Microsoft.Azure.WebJobs.Script.StorageProvider
2121
/// </summary>
2222
internal abstract class StorageClientProvider<TClient, TClientOptions> where TClientOptions : ClientOptions
2323
{
24-
private readonly IConfiguration _configuration;
2524
private readonly AzureComponentFactory _componentFactory;
2625
private readonly AzureEventSourceLogForwarder _logForwarder;
2726
private readonly ILogger _logger;
@@ -32,9 +31,8 @@ internal abstract class StorageClientProvider<TClient, TClientOptions> where TCl
3231
/// <param name="configuration">The configuration to use when creating Client-specific objects. <see cref="IConfiguration"/></param>
3332
/// <param name="componentFactory">The Azure factory responsible for creating clients. <see cref="AzureComponentFactory"/></param>
3433
/// <param name="logForwarder">Log forwarder that forwards events to ILogger. <see cref="AzureEventSourceLogForwarder"/></param>
35-
public StorageClientProvider(IConfiguration configuration, AzureComponentFactory componentFactory, AzureEventSourceLogForwarder logForwarder, ILogger<TClient> logger)
34+
public StorageClientProvider(AzureComponentFactory componentFactory, AzureEventSourceLogForwarder logForwarder, ILogger<TClient> logger)
3635
{
37-
_configuration = configuration;
3836
_componentFactory = componentFactory;
3937
_logForwarder = logForwarder;
4038
_logger = logger;
@@ -53,13 +51,14 @@ public StorageClientProvider(IConfiguration configuration, AzureComponentFactory
5351
/// Gets the storage client specified by <paramref name="name"/>
5452
/// </summary>
5553
/// <param name="name">Name of the connection to use</param>
54+
/// <param name="configuration">Configuration to use</param>
5655
/// <param name="client">Client that was created if the connection was valid; otherwise, the default value for the type of <paramref name="client"/>.</param>
5756
/// <returns>true if the client could be created; false otherwise</returns>
58-
public virtual bool TryGet(string name, out TClient client)
57+
public virtual bool TryGet(string name, IConfiguration configuration, out TClient client)
5958
{
6059
try
6160
{
62-
client = Get(name);
61+
client = Get(name, configuration);
6362
return true;
6463
}
6564
catch (Exception ex)
@@ -96,27 +95,29 @@ public virtual bool TryGetFromConnectionString(string connectionString, out TCli
9695
/// </summary>
9796
/// <param name="name">Name of the connection to use</param>
9897
/// <param name="resolver">A resolver to interpret the provided connection <paramref name="name"/>.</param>
98+
/// <param name="configuration">Configuration to use</param>
9999
/// <returns>Client that was created.</returns>
100-
public virtual TClient Get(string name, INameResolver resolver)
100+
public virtual TClient Get(string name, INameResolver resolver, IConfiguration configuration)
101101
{
102102
var resolvedName = resolver.ResolveWholeString(name);
103-
return this.Get(resolvedName);
103+
return this.Get(resolvedName, configuration);
104104
}
105105

106106
/// <summary>
107107
/// Gets the storage client specified by <paramref name="name"/>
108108
/// </summary>
109109
/// <param name="name">Name of the connection to use</param>
110+
/// <param name="configuration">Configuration to use</param>
110111
/// <returns>Client that was created.</returns>
111-
public virtual TClient Get(string name)
112+
public virtual TClient Get(string name, IConfiguration configuration)
112113
{
113114
if (string.IsNullOrWhiteSpace(name))
114115
{
115116
name = ConnectionStringNames.Storage; // default
116117
}
117118

118119
// $$$ Where does validation happen?
119-
IConfigurationSection connectionSection = _configuration.GetWebJobsConnectionStringSection(name);
120+
IConfigurationSection connectionSection = configuration.GetWebJobsConnectionStringSection(name);
120121
if (!connectionSection.Exists())
121122
{
122123
// Not found
@@ -148,7 +149,7 @@ protected virtual TClient CreateClient(IConfiguration configuration, TokenCreden
148149
/// <returns>Storage client</returns>
149150
public virtual TClient GetHost()
150151
{
151-
return this.Get(null);
152+
return this.Get(null, null);
152153
}
153154

154155
/// <summary>

test/WebJobs.Script.Tests.Integration/Host/SingletonTests/SingletonEndToEndTests.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
using Newtonsoft.Json.Linq;
2626
using Xunit;
2727
using Microsoft.Azure.WebJobs.Host;
28+
using Microsoft.WebJobs.Script.Tests;
2829

2930
namespace Microsoft.Azure.WebJobs.Script.Tests.Integration.Host.SingletonTests
3031
{
@@ -655,6 +656,7 @@ private IHost CreateTestJobHost<TProg>(int hostId, Action<IHostBuilder> extraCon
655656
});
656657

657658
services.AddSingleton<IDistributedLockManager, BlobLeaseDistributedLockManager>();
659+
TestHostBuilderExtensions.AddMockedSingleton<IScriptHostManager>(services);
658660
services.AddAzureStorageProvider();
659661
});
660662

test/WebJobs.Script.Tests.Integration/ScriptHostEndToEnd/FunctionGeneratorEndToEndTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using Microsoft.Extensions.DependencyInjection;
1313
using Microsoft.Extensions.Hosting;
1414
using Microsoft.Extensions.Logging;
15+
using Microsoft.WebJobs.Script.Tests;
1516
using Xunit;
1617

1718
namespace Microsoft.Azure.WebJobs.Script.Tests
@@ -70,7 +71,7 @@ public async Task Generate_EndToEnd()
7071
{
7172
s.AddSingleton<ITypeLocator>(new TestTypeLocator(functionType));
7273
s.AddSingleton<ILoggerFactory>(new LoggerFactory());
73-
74+
TestHostBuilderExtensions.AddMockedSingleton<IScriptHostManager>(s);
7475
s.AddAzureStorageProvider();
7576
});
7677

test/WebJobs.Script.Tests.Integration/Storage/BlobStorageProviderTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ public BlobStorageProviderTests()
3636
[Fact]
3737
public async Task TestBlobStorageProvider_TryConnectionName()
3838
{
39-
Assert.True(_blobServiceClientProvider.TryGet(StorageConnection, out BlobServiceClient client));
39+
Assert.True(_blobServiceClientProvider.TryGet(StorageConnection, _configuration, out BlobServiceClient client));
4040
await VerifyServiceAvailable(client);
4141
}
4242

4343
[Fact]
4444
public async Task TestBlobStorageProvider_ConnectionName()
4545
{
46-
BlobServiceClient client = _blobServiceClientProvider.Get(StorageConnection);
46+
BlobServiceClient client = _blobServiceClientProvider.Get(StorageConnection, _configuration);
4747
await VerifyServiceAvailable(client);
4848
}
4949

@@ -52,7 +52,7 @@ public async Task TestBlobStorageProvider_ConnectionNameWithResolver()
5252
{
5353
var resolver = new DefaultNameResolver(_configuration);
5454

55-
BlobServiceClient client = _blobServiceClientProvider.Get(StorageConnection, resolver);
55+
BlobServiceClient client = _blobServiceClientProvider.Get(StorageConnection, resolver, _configuration);
5656
await VerifyServiceAvailable(client);
5757
}
5858

test/WebJobs.Script.Tests.Shared/TestHelpers.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
using Microsoft.Extensions.DependencyInjection;
2121
using Microsoft.Extensions.Hosting;
2222
using Microsoft.Extensions.Options;
23+
using Microsoft.WebJobs.Script.Tests;
2324

2425
namespace Microsoft.Azure.WebJobs.Script.Tests
2526
{
@@ -407,6 +408,7 @@ public static IAzureStorageProvider GetAzureStorageProvider(IConfiguration confi
407408
{
408409
// Override configuration
409410
services.AddSingleton(configuration);
411+
TestHostBuilderExtensions.AddMockedSingleton<IScriptHostManager>(services);
410412
services.AddAzureStorageProvider();
411413
if (storageOptions != null)
412414
{

0 commit comments

Comments
 (0)