Skip to content

Commit 3df0573

Browse files
authored
Adding min version requirements for flex consumption (#10290)
1 parent 91e0bf7 commit 3df0573

20 files changed

+794
-62
lines changed

src/WebJobs.Script.WebHost/Program.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public static IWebHost BuildWebHost(string[] args)
3838

3939
public static IWebHostBuilder CreateWebHostBuilder(string[] args = null)
4040
{
41-
// Setting this env variable to test placeholder scenarios locally.
41+
// Setting this env variable to test placeholder scenarios locally.
4242
#if PLACEHOLDERSIMULATION
4343
SystemEnvironment.Instance.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsitePlaceholderMode, "1");
4444
SystemEnvironment.Instance.SetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteContainerReady, "0");
@@ -75,6 +75,12 @@ public static IWebHostBuilder CreateWebHostBuilder(string[] args = null)
7575
IsLinuxAppServiceEnvironment = SystemEnvironment.Instance.IsLinuxAppService()
7676
});
7777
config.Add(new FunctionsHostingConfigSource(SystemEnvironment.Instance));
78+
79+
var hostingEnvironmentConfigFilePath = SystemEnvironment.Instance.GetFunctionsHostingEnvironmentConfigFilePath();
80+
if (!string.IsNullOrEmpty(hostingEnvironmentConfigFilePath))
81+
{
82+
config.AddJsonFile(hostingEnvironmentConfigFilePath, optional: true, reloadOnChange: false);
83+
}
7884
})
7985
.ConfigureLogging((context, loggingBuilder) =>
8086
{

src/WebJobs.Script.WebHost/WebHostServiceCollectionExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ public static void AddWebJobsScriptHost(this IServiceCollection services, IConfi
216216
services.ConfigureOptions<FlexConsumptionMetricsPublisherOptionsSetup>();
217217
services.ConfigureOptions<ConsoleLoggingOptionsSetup>();
218218
services.AddHostingConfigOptions(configuration);
219+
services.ConfigureOptions<ExtensionRequirementOptionsSetup>();
219220

220221
services.TryAddSingleton<IDependencyValidator, DependencyValidator>();
221222
services.TryAddSingleton<IJobHostMiddlewarePipeline>(s => DefaultMiddlewarePipeline.Empty);

src/WebJobs.Script.WebHost/WebScriptHostBuilderExtension.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ public static IHostBuilder AddWebScriptHost(this IHostBuilder builder, IServiceP
170170
IOptionsMonitor<FunctionsHostingConfigOptions> hostingConfigOptionsMonitor = rootServiceProvider.GetService<IOptionsMonitor<FunctionsHostingConfigOptions>>();
171171
services.AddSingleton(hostingConfigOptions);
172172
services.AddSingleton(hostingConfigOptionsMonitor);
173+
IOptions<ExtensionRequirementOptions> extensionRequirementOptions = rootServiceProvider.GetService<IOptions<ExtensionRequirementOptions>>();
174+
services.AddSingleton(extensionRequirementOptions);
173175

174176
ConfigureRegisteredBuilders(services, rootServiceProvider);
175177
});
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using Microsoft.Azure.WebJobs.Script.ExtensionRequirements;
7+
using Microsoft.Azure.WebJobs.Script.Workers.Rpc;
8+
9+
namespace Microsoft.Azure.WebJobs.Script.Config
10+
{
11+
/// <summary>
12+
/// Represents collection of minumum bundle and extension requirements for a function app.
13+
/// </summary>
14+
public class ExtensionRequirementOptions
15+
{
16+
/// <summary>
17+
/// Gets or sets the minimum bundles configuration required for the function app.
18+
/// </summary>
19+
public IEnumerable<BundleRequirement> Bundles { get; set; }
20+
21+
/// <summary>
22+
/// Gets or Sets the minimum versions of extensions required for the function app.
23+
/// </summary>
24+
public IEnumerable<ExtensionStartupTypeRequirement> Extensions { get; set; }
25+
}
26+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Configuration;
7+
using System.Linq;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
using Microsoft.Azure.WebJobs.Script.Configuration;
11+
using Microsoft.Extensions.Configuration;
12+
using Microsoft.Extensions.Options;
13+
14+
namespace Microsoft.Azure.WebJobs.Script.Config
15+
{
16+
internal class ExtensionRequirementOptionsSetup : IConfigureOptions<ExtensionRequirementOptions>
17+
{
18+
private readonly IConfiguration _configuration;
19+
20+
public ExtensionRequirementOptionsSetup(IConfiguration configuration)
21+
{
22+
_configuration = configuration;
23+
}
24+
25+
public void Configure(ExtensionRequirementOptions options)
26+
{
27+
IConfigurationSection requirementsSection = _configuration.GetSection(ScriptConstants.ExtensionRequirementsSection);
28+
if (requirementsSection.Exists())
29+
{
30+
requirementsSection.Bind(options);
31+
}
32+
}
33+
}
34+
}

src/WebJobs.Script/DependencyInjection/ScriptStartupTypeLocator.cs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Reflection;
1010
using System.Threading.Tasks;
1111
using Microsoft.Azure.WebJobs.Hosting;
12+
using Microsoft.Azure.WebJobs.Script.Config;
1213
using Microsoft.Azure.WebJobs.Script.Description;
1314
using Microsoft.Azure.WebJobs.Script.Diagnostics;
1415
using Microsoft.Azure.WebJobs.Script.Diagnostics.Extensions;
@@ -38,12 +39,11 @@ public class ScriptStartupTypeLocator : IWebJobsStartupTypeLocator
3839
private readonly IMetricsLogger _metricsLogger;
3940
private readonly Lazy<IEnumerable<Type>> _startupTypes;
4041
private readonly IOptionsMonitor<LanguageWorkerOptions> _languageWorkerOptions;
41-
42-
private static readonly ExtensionRequirementsInfo _extensionRequirements = DependencyHelper.GetExtensionRequirements();
42+
private readonly IOptions<ExtensionRequirementOptions> _extensionRequirementOptions;
4343
private static string[] _builtinExtensionAssemblies = GetBuiltinExtensionAssemblies();
4444

4545
public ScriptStartupTypeLocator(string rootScriptPath, ILogger<ScriptStartupTypeLocator> logger, IExtensionBundleManager extensionBundleManager,
46-
IFunctionMetadataManager functionMetadataManager, IMetricsLogger metricsLogger, IOptionsMonitor<LanguageWorkerOptions> languageWorkerOptions)
46+
IFunctionMetadataManager functionMetadataManager, IMetricsLogger metricsLogger, IOptionsMonitor<LanguageWorkerOptions> languageWorkerOptions, IOptions<ExtensionRequirementOptions> extensionRequirementOptions)
4747
{
4848
_rootScriptPath = rootScriptPath ?? throw new ArgumentNullException(nameof(rootScriptPath));
4949
_extensionBundleManager = extensionBundleManager ?? throw new ArgumentNullException(nameof(extensionBundleManager));
@@ -52,6 +52,7 @@ public ScriptStartupTypeLocator(string rootScriptPath, ILogger<ScriptStartupType
5252
_metricsLogger = metricsLogger;
5353
_startupTypes = new Lazy<IEnumerable<Type>>(() => GetExtensionsStartupTypesAsync().ConfigureAwait(false).GetAwaiter().GetResult());
5454
_languageWorkerOptions = languageWorkerOptions;
55+
_extensionRequirementOptions = extensionRequirementOptions;
5556
}
5657

5758
private static string[] GetBuiltinExtensionAssemblies()
@@ -84,11 +85,12 @@ public async Task<IEnumerable<Type>> GetExtensionsStartupTypesAsync()
8485

8586
// dotnet app precompiled -> Do not use bundles
8687
var workerConfigs = _languageWorkerOptions.CurrentValue.WorkerConfigs;
88+
ExtensionRequirementsInfo extensionRequirements = GetExtensionRequirementsInfo();
8789
ImmutableArray<FunctionMetadata> functionMetadataCollection = ImmutableArray<FunctionMetadata>.Empty;
8890
if (bundleConfigured)
8991
{
9092
ExtensionBundleDetails bundleDetails = await _extensionBundleManager.GetExtensionBundleDetails();
91-
ValidateBundleRequirements(bundleDetails);
93+
ValidateBundleRequirements(bundleDetails, extensionRequirements);
9294

9395
functionMetadataCollection = _functionMetadataManager.GetFunctionMetadata(forceRefresh: true, includeCustomProviders: false, workerConfigs: workerConfigs);
9496
bindingsSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
@@ -218,7 +220,7 @@ public async Task<IEnumerable<Type>> GetExtensionsStartupTypesAsync()
218220
}
219221
}
220222

221-
ValidateExtensionRequirements(startupTypes);
223+
ValidateExtensionRequirements(startupTypes, extensionRequirements);
222224

223225
return startupTypes;
224226
}
@@ -254,9 +256,10 @@ private ExtensionReference[] ParseExtensions(string metadataFilePath)
254256
}
255257
}
256258

257-
private void ValidateBundleRequirements(ExtensionBundleDetails bundleDetails)
259+
private void ValidateBundleRequirements(ExtensionBundleDetails bundleDetails, ExtensionRequirementsInfo requirementsInfo)
258260
{
259-
if (_extensionRequirements.BundleRequirementsByBundleId.TryGetValue(bundleDetails.Id, out BundleRequirement requirement))
261+
if (requirementsInfo.BundleRequirementsByBundleId != null
262+
&& requirementsInfo.BundleRequirementsByBundleId.TryGetValue(bundleDetails.Id, out BundleRequirement requirement))
260263
{
261264
var bundleVersion = new Version(bundleDetails.Version);
262265
var minimumVersion = new Version(requirement.MinimumVersion);
@@ -269,8 +272,12 @@ private void ValidateBundleRequirements(ExtensionBundleDetails bundleDetails)
269272
}
270273
}
271274

272-
private void ValidateExtensionRequirements(List<Type> startupTypes)
275+
private void ValidateExtensionRequirements(List<Type> startupTypes, ExtensionRequirementsInfo requirementsInfo)
273276
{
277+
if (requirementsInfo.ExtensionRequirementsByStartupType is null)
278+
{
279+
return;
280+
}
274281
var errors = new List<string>();
275282

276283
void CollectError(Type extensionType, Version minimumVersion, ExtensionStartupTypeRequirement requirement)
@@ -282,7 +289,7 @@ void CollectError(Type extensionType, Version minimumVersion, ExtensionStartupTy
282289

283290
foreach (var extensionType in startupTypes)
284291
{
285-
if (_extensionRequirements.ExtensionRequirementsByStartupType.TryGetValue(extensionType.Name, out ExtensionStartupTypeRequirement requirement))
292+
if (requirementsInfo.ExtensionRequirementsByStartupType.TryGetValue(extensionType.Name, out ExtensionStartupTypeRequirement requirement))
286293
{
287294
Version minimumAssemblyVersion = new Version(requirement.MinimumAssemblyVersion);
288295

@@ -342,6 +349,14 @@ private bool IsDotnetIsolatedApp(IEnumerable<FunctionMetadata> functions, IEnvir
342349
return workerRuntime?.Equals(RpcWorkerConstants.DotNetIsolatedLanguageWorkerName, StringComparison.OrdinalIgnoreCase) ?? false;
343350
}
344351

352+
private ExtensionRequirementsInfo GetExtensionRequirementsInfo()
353+
{
354+
ExtensionRequirementsInfo requirementsInfo = _extensionRequirementOptions.Value.Bundles != null || _extensionRequirementOptions.Value.Extensions != null
355+
? new ExtensionRequirementsInfo(_extensionRequirementOptions.Value.Bundles, _extensionRequirementOptions.Value.Extensions)
356+
: DependencyHelper.GetExtensionRequirements();
357+
return requirementsInfo;
358+
}
359+
345360
private class TypeNameEqualityComparer : IEqualityComparer<Type>
346361
{
347362
public bool Equals(Type x, Type y)

src/WebJobs.Script/Environment/EnvironmentExtensions.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,14 @@ public static string GetAntaresComputerName(this IEnvironment environment)
399399
return environment.GetEnvironmentVariableOrDefault(AntaresComputerName, string.Empty);
400400
}
401401

402+
/// <summary>
403+
/// Get hosting environment configuration file (different from scmhosting file).
404+
/// </summary>
405+
public static string GetFunctionsHostingEnvironmentConfigFilePath(this IEnvironment environment)
406+
{
407+
return environment.GetEnvironmentVariableOrDefault(FunctionsHostingEnvironmentConfigFilePath, string.Empty);
408+
}
409+
402410
/// <summary>
403411
/// Gets if runtime environment is logic apps.
404412
/// </summary>

src/WebJobs.Script/Environment/EnvironmentSettingNames.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public static class EnvironmentSettingNames
7474
public const string FunctionsRequestBodySizeLimit = "FUNCTIONS_REQUEST_BODY_SIZE_LIMIT";
7575
public const string FunctionsHostIdCheckLevel = "FUNCTIONS_HOSTID_CHECK_LEVEL";
7676
public const string FunctionsPlatformConfigFilePath = "FUNCTIONS_PLATFORM_CONFIG_FILE_PATH";
77+
public const string FunctionsHostingEnvironmentConfigFilePath = "FUNCTIONS_HOSTING_ENVIRONMENT_CONFIG_FILE_PATH";
7778
public const string TargetBaseScalingEnabled = "TARGET_BASED_SCALING_ENABLED";
7879
public const string WebsiteNodeDefaultVersion = "WEBSITE_NODE_DEFAULT_VERSION";
7980
public const string FunctionsMetricsPublishPath = "FUNCTIONS_METRICS_PUBLISH_PATH";

src/WebJobs.Script/ExtensionRequirements/BundleRequirement.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
namespace Microsoft.Azure.WebJobs.Script.ExtensionRequirements
99
{
10-
internal sealed class BundleRequirement
10+
public sealed class BundleRequirement
1111
{
1212
public string Id { get; set; }
1313

src/WebJobs.Script/ExtensionRequirements/ExtensionRequirementsInfo.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,9 @@ internal sealed class ExtensionRequirementsInfo
1111
{
1212
public ExtensionRequirementsInfo(IEnumerable<BundleRequirement> bundleRequirements, IEnumerable<ExtensionStartupTypeRequirement> extensionRequirements)
1313
{
14-
BundleRequirementsByBundleId = bundleRequirements
15-
.ToDictionary(a => a.Id, StringComparer.OrdinalIgnoreCase);
14+
BundleRequirementsByBundleId = bundleRequirements?.ToDictionary(a => a.Id, StringComparer.OrdinalIgnoreCase);
1615

17-
ExtensionRequirementsByStartupType = extensionRequirements
18-
.ToDictionary(a => a.Name, StringComparer.OrdinalIgnoreCase);
16+
ExtensionRequirementsByStartupType = extensionRequirements?.ToDictionary(a => a.Name, StringComparer.OrdinalIgnoreCase);
1917
}
2018

2119
public Dictionary<string, BundleRequirement> BundleRequirementsByBundleId { get; private set; }

0 commit comments

Comments
 (0)