-
Notifications
You must be signed in to change notification settings - Fork 478
Implement app capabilities feature #11577
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
9fde852
202d79c
a60d87f
207e653
8bfdf38
2645fbf
c9db304
3b1e467
813bf10
7069ed2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| // Copyright (c) .NET Foundation. All rights reserved. | ||
| // Licensed under the MIT License. See License.txt in the project root for license information. | ||
|
|
||
| #nullable enable | ||
|
|
||
| using System; | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace Microsoft.Azure.WebJobs.Script.AppCapabilities | ||
| { | ||
| public sealed class AppCapabilitiesOptions | ||
| { | ||
| private readonly Dictionary<string, string> _capabilities; | ||
|
|
||
| public AppCapabilitiesOptions() | ||
| { | ||
| _capabilities = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); | ||
| } | ||
|
|
||
| public Dictionary<string, string> Capabilities => _capabilities; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| <Project> | ||
| <PropertyGroup> | ||
| <VersionPrefix>1.0.4</VersionPrefix> | ||
| <VersionSuffix>preview</VersionSuffix> | ||
| <VersionSuffix>preview2</VersionSuffix> | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO: remove test change |
||
| </PropertyGroup> | ||
| </Project> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -140,6 +140,9 @@ message WorkerInitResponse { | |
|
|
||
| // Worker metadata captured for telemetry purposes | ||
| WorkerMetadata worker_metadata = 4; | ||
|
|
||
| // App capabilities or features (different from worker capabilities above) | ||
| map<string,string> app_capabilities = 5; | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO: Move this change to protobuf repo, make sure that is merged into host before this PR |
||
| } | ||
|
|
||
| message WorkerMetadata { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| // Copyright (c) .NET Foundation. All rights reserved. | ||
| // Licensed under the MIT License. See License.txt in the project root for license information. | ||
|
|
||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
| using Microsoft.AspNetCore.Authorization; | ||
| using Microsoft.AspNetCore.Mvc; | ||
| using Microsoft.Azure.WebJobs.Script.AppCapabilities; | ||
| using Microsoft.Azure.WebJobs.Script.WebHost.Filters; | ||
| using Microsoft.Azure.WebJobs.Script.WebHost.Security.Authorization.Policies; | ||
| using Microsoft.Extensions.Options; | ||
|
|
||
| namespace Microsoft.Azure.WebJobs.Script.WebHost.Controllers | ||
| { | ||
| public class AppCapabilitiesController | ||
| { | ||
| private readonly AppCapabilitiesOptions _capabilitiesOptions; | ||
|
|
||
| public AppCapabilitiesController(IOptions<AppCapabilitiesOptions> capabilitiesOptions) | ||
| { | ||
| _capabilitiesOptions = capabilitiesOptions.Value; | ||
| } | ||
|
|
||
| [HttpGet] | ||
| [Route("admin/capabilities")] | ||
| [Authorize(Policy = PolicyNames.AdminAuthLevel)] | ||
| [RequiresRunningHost] | ||
| public IActionResult GetCapabilities([FromServices] IAppCapabilitiesProvider appCapabilitiesProvider) | ||
| { | ||
| // Get capabilities from options | ||
| var optionsCapabilities = _capabilitiesOptions.Capabilities ?? new Dictionary<string, string>(); | ||
|
|
||
| // Get capabilities from provider (worker) | ||
| var providerCapabilities = appCapabilitiesProvider?.GetCapabilities() ?? new Dictionary<string, string>(); | ||
|
|
||
| // Merge: worker provider wins on collision | ||
| var merged = optionsCapabilities | ||
| .Concat(providerCapabilities) | ||
| .GroupBy(kvp => kvp.Key, System.StringComparer.OrdinalIgnoreCase) | ||
| .Select(g => g.Last()) // provider comes after options, so Last() wins | ||
| .ToDictionary(kvp => kvp.Key, kvp => kvp.Value, System.StringComparer.OrdinalIgnoreCase); | ||
|
|
||
| return new OkObjectResult(merged); | ||
| } | ||
|
|
||
| [HttpGet] | ||
| [Route("admin/capabilities/{name}")] | ||
| [Authorize(Policy = PolicyNames.AdminAuthLevel)] | ||
| [RequiresRunningHost] | ||
| public IActionResult Get(string name, [FromServices] IAppCapabilitiesProvider appCapabilitiesProvider) | ||
| { | ||
| // check worker provider first | ||
| var providerCapabilities = appCapabilitiesProvider?.GetCapabilities(); | ||
| var providerCapability = providerCapabilities?.FirstOrDefault(kvp => string.Equals(kvp.Key, name, System.StringComparison.OrdinalIgnoreCase)); | ||
|
|
||
| if (providerCapability is KeyValuePair<string, string> kvp && kvp.Key is not null) | ||
| { | ||
| return new OkObjectResult(kvp.Value); | ||
| } | ||
|
|
||
| // check options | ||
| var optionsCapabilities = _capabilitiesOptions.Capabilities; | ||
| var optionCapability = optionsCapabilities.FirstOrDefault(kvp => string.Equals(kvp.Key, name, System.StringComparison.OrdinalIgnoreCase)); | ||
|
|
||
| if (optionCapability.Key is not null) | ||
| { | ||
| return new OkObjectResult(optionCapability.Value); | ||
| } | ||
|
|
||
| return new NotFoundResult(); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,7 +21,7 @@ public static void AddScriptPolicies(this AuthorizationOptions options) | |
| options.AddPolicy(PolicyNames.AdminAuthLevel, p => | ||
| { | ||
| p.AddScriptAuthenticationSchemes(); | ||
| p.AddRequirements(new AuthLevelRequirement(AuthorizationLevel.Admin)); | ||
| //p.AddRequirements(new AuthLevelRequirement(AuthorizationLevel.Admin)); | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO: remove local testing change |
||
| p.RequireAssertion(c => | ||
| { | ||
| if (c.Resource is AuthorizationFilterContext filterContext) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| // Copyright (c) .NET Foundation. All rights reserved. | ||
| // Licensed under the MIT License. See License.txt in the project root for license information. | ||
|
|
||
| using Microsoft.Extensions.Configuration; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
| using Microsoft.Extensions.Logging; | ||
| using Microsoft.Extensions.Options; | ||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Linq; | ||
|
|
||
| #nullable enable | ||
|
|
||
| namespace Microsoft.Azure.WebJobs.Script.AppCapabilities | ||
| { | ||
| internal sealed class AppCapabilitiesOptionsSetup : IConfigureOptions<AppCapabilitiesOptions> | ||
| { | ||
| private readonly IConfiguration _configuration; | ||
| private readonly string configSectionName = "azureFunctionsJobHost:appCapabilities"; | ||
| private readonly ILogger<AppCapabilitiesOptionsSetup> _logger; | ||
|
|
||
| public AppCapabilitiesOptionsSetup( | ||
| IConfiguration configuration, | ||
| ILogger<AppCapabilitiesOptionsSetup> logger) | ||
| { | ||
| _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); | ||
| _logger = logger ?? throw new ArgumentNullException(nameof(logger)); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Configures the <see cref="AppCapabilitiesOptions"/> by reading from known configuration sources. | ||
| /// </summary> | ||
| /// <param name="options">The options instance to configure.</param> | ||
| public void Configure(AppCapabilitiesOptions options) | ||
| { | ||
| var jobHostCapabilitiesSection = _configuration.GetSection(configSectionName); | ||
| if (jobHostCapabilitiesSection.Exists()) | ||
| { | ||
| AddCapabilitiesFromSection(options, jobHostCapabilitiesSection); | ||
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Adds capabilities from a configuration section. | ||
| /// </summary> | ||
| /// <param name="options">The options to add capabilities to.</param> | ||
| /// <param name="section">The configuration section containing capability definitions.</param> | ||
| private void AddCapabilitiesFromSection( | ||
| AppCapabilitiesOptions options, | ||
| IConfigurationSection section) | ||
| { | ||
| var children = section.GetChildren(); | ||
| _logger.LogDebug("Loading App Capabilities from configuration section '{sectionName}' with {count} entries.", | ||
| section.Path, children.Count()); | ||
|
|
||
| foreach (var child in children) | ||
| { | ||
| var capabilityName = child.Key; | ||
| var capabilityValue = child.Value; | ||
|
|
||
| options.Capabilities[capabilityName] = capabilityValue ?? string.Empty; | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| // Copyright (c) .NET Foundation. All rights reserved. | ||
| // Licensed under the MIT License. See License.txt in the project root for license information. | ||
|
|
||
| using System.Collections.Generic; | ||
|
|
||
| namespace Microsoft.Azure.WebJobs.Script.AppCapabilities | ||
| { | ||
| internal class DefaultAppCapabilitiesProvider : IAppCapabilitiesProvider | ||
| { | ||
| private readonly Dictionary<string, string> _capabilities = new Dictionary<string, string>(); | ||
|
|
||
| public Dictionary<string, string> GetCapabilities() | ||
| { | ||
| return _capabilities; | ||
| } | ||
|
|
||
| public void SetCapability(string capability, string value) | ||
| { | ||
| _capabilities[capability] = value; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| // Copyright (c) .NET Foundation. All rights reserved. | ||
| // Licensed under the MIT License. See License.txt in the project root for license information. | ||
|
|
||
| using System.Collections.Generic; | ||
|
|
||
| namespace Microsoft.Azure.WebJobs.Script.AppCapabilities | ||
| { | ||
| public interface IAppCapabilitiesProvider | ||
| { | ||
| Dictionary<string, string> GetCapabilities(); | ||
|
|
||
| void SetCapability(string capability, string value); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar setup to
azure-functions-host/src/WebJobs.Script/Config/FunctionsHostingConfigOptions.cs
Line 14 in 436350a