-
Notifications
You must be signed in to change notification settings - Fork 471
Conditional based profiles for workers #8365
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
Merged
shreyas-gopalakrishna
merged 9 commits into
dev
from
shreyasg/conditional-based-profiles
Jun 16, 2022
Merged
Changes from 8 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
04b665c
Conditional based profiles
shreyas-gopalakrishna c4e9e93
WIP: Example refactoring using registered services
fabiocav 5a144d8
Use the Profile manager to store, load and evaluate profiles
shreyas-gopalakrishna da7546d
Addressing review comments
shreyas-gopalakrishna f6fc193
Adding unit tests for profiles
shreyas-gopalakrishna 567780b
Fixed dependency injection and review comments
shreyas-gopalakrishna 7a8cde1
Fixing unit tests
shreyas-gopalakrishna 76710af
Updating WorkerProfileConditionProvider and tests
shreyas-gopalakrishna 6273049
Rename SetWorkerDescriptionProfiles
shreyas-gopalakrishna File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
82 changes: 82 additions & 0 deletions
82
src/WebJobs.Script/Workers/Profiles/EnvironmentCondition.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| // Copyright (c) .NET Foundation. All rights reserved. | ||
| // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using System; | ||
| using System.ComponentModel.DataAnnotations; | ||
| using System.Text.RegularExpressions; | ||
| using Microsoft.Azure.WebJobs.Script.Workers.Profiles; | ||
| using Microsoft.Extensions.Logging; | ||
|
|
||
| namespace Microsoft.Azure.WebJobs.Script.Workers | ||
| { | ||
| /// <summary> | ||
| /// An implementation of an <see cref="IWorkerProfileCondition"/> that checks if | ||
| /// environment variables match the expected output | ||
| /// </summary> | ||
| public class EnvironmentCondition : IWorkerProfileCondition | ||
| { | ||
| private readonly ILogger _logger; | ||
| private readonly IEnvironment _environment; | ||
| private readonly string _name; | ||
| private readonly string _expression; | ||
| private Regex _regex; | ||
|
|
||
| internal EnvironmentCondition(ILogger logger, IEnvironment environment, WorkerProfileConditionDescriptor descriptor) | ||
| { | ||
| if (descriptor is null) | ||
| { | ||
| throw new ArgumentNullException(nameof(descriptor)); | ||
| } | ||
|
|
||
| _logger = logger ?? throw new ArgumentNullException(nameof(logger)); | ||
| _environment = environment ?? throw new ArgumentNullException(nameof(environment)); | ||
|
|
||
| descriptor.Properties.TryGetValue(WorkerConstants.WorkerDescriptionProfileConditionName, out _name); | ||
| descriptor.Properties.TryGetValue(WorkerConstants.WorkerDescriptionProfileConditionExpression, out _expression); | ||
|
|
||
| Validate(); | ||
| } | ||
|
|
||
| public string Name => _name; | ||
|
|
||
| public string Expression => _expression; | ||
|
|
||
| /// <inheritdoc /> | ||
| public bool Evaluate() | ||
| { | ||
| string value = _environment.GetEnvironmentVariable(Name); | ||
|
|
||
| if (string.IsNullOrEmpty(value)) | ||
shreyas-gopalakrishna marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| return false; | ||
| } | ||
|
|
||
| _logger.LogDebug($"Evaluating EnvironmentCondition with value '{value}' and expression '{Expression}'"); | ||
|
|
||
| return _regex.IsMatch(value); | ||
| } | ||
|
|
||
| // Validates if condition parametrs meet expected values, fail if they don't | ||
| private void Validate() | ||
| { | ||
| if (string.IsNullOrEmpty(Name)) | ||
| { | ||
| throw new ValidationException($"EnvironmentCondition {nameof(Name)} cannot be empty."); | ||
| } | ||
|
|
||
| if (string.IsNullOrEmpty(Expression)) | ||
| { | ||
| throw new ValidationException($"EnvironmentCondition {nameof(Expression)} cannot be empty."); | ||
| } | ||
|
|
||
| try | ||
| { | ||
| _regex = new Regex(Expression); | ||
| } | ||
| catch | ||
| { | ||
| throw new ValidationException($"EnvironmentCondition {nameof(Expression)} must be a valid regular expression."); | ||
| } | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| // Copyright (c) .NET Foundation. All rights reserved. | ||
| // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| namespace Microsoft.Azure.WebJobs.Script.Workers | ||
| { | ||
| /// <summary> | ||
| /// An implementation of an <see cref="IWorkerProfileCondition"/> that always evaluates to false. | ||
| /// This condition is used to disable a profile when condition providers fail to resolve conditions. | ||
| /// </summary> | ||
| public class FalseCondition : IWorkerProfileCondition | ||
shreyas-gopalakrishna marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| public bool Evaluate() | ||
| { | ||
| return false; | ||
| } | ||
| } | ||
| } | ||
104 changes: 104 additions & 0 deletions
104
src/WebJobs.Script/Workers/Profiles/HostPropertyCondition.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| // Copyright (c) .NET Foundation. All rights reserved. | ||
| // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using System; | ||
| using System.ComponentModel.DataAnnotations; | ||
| using System.Linq; | ||
| using System.Text.RegularExpressions; | ||
| using Microsoft.Azure.WebJobs.Script.Config; | ||
| using Microsoft.Azure.WebJobs.Script.Workers.Profiles; | ||
| using Microsoft.Extensions.Logging; | ||
|
|
||
| namespace Microsoft.Azure.WebJobs.Script.Workers | ||
| { | ||
| /// <summary> | ||
| /// An implementation of an <see cref="IWorkerProfileCondition"/> that checks if different host properties | ||
| /// such as Sku, Platform, HostVersion match the expected output | ||
| /// </summary> | ||
| public class HostPropertyCondition : IWorkerProfileCondition | ||
| { | ||
| private readonly ILogger _logger; | ||
| private readonly ISystemRuntimeInformation _systemRuntimeInformation; | ||
| private readonly string _name; | ||
| private readonly string _expression; | ||
| private Regex _regex; | ||
|
|
||
| public HostPropertyCondition(ILogger logger, ISystemRuntimeInformation systemRuntimeInformation, WorkerProfileConditionDescriptor descriptor) | ||
| { | ||
| if (descriptor is null) | ||
| { | ||
| throw new ArgumentNullException(nameof(descriptor)); | ||
| } | ||
|
|
||
| _logger = logger ?? throw new ArgumentNullException(nameof(logger)); | ||
| _systemRuntimeInformation = systemRuntimeInformation ?? throw new ArgumentNullException(nameof(systemRuntimeInformation)); | ||
|
|
||
| descriptor.Properties.TryGetValue(WorkerConstants.WorkerDescriptionProfileConditionName, out _name); | ||
| descriptor.Properties.TryGetValue(WorkerConstants.WorkerDescriptionProfileConditionExpression, out _expression); | ||
|
|
||
| Validate(); | ||
| } | ||
|
|
||
| public enum HostProperty | ||
| { | ||
| Sku, | ||
| Platform, | ||
| HostVersion | ||
| } | ||
|
|
||
| public string Name => _name; | ||
|
|
||
| public string Expression => _expression; | ||
|
|
||
| /// <inheritdoc /> | ||
| public bool Evaluate() | ||
| { | ||
| var hostPropertyName = Enum.Parse(typeof(HostProperty), Name, true); | ||
|
|
||
| string value = hostPropertyName switch | ||
| { | ||
| HostProperty.Sku => ScriptSettingsManager.Instance.GetSetting(EnvironmentSettingNames.AzureWebsiteSku), | ||
| HostProperty.Platform => _systemRuntimeInformation.GetOSPlatform().ToString(), | ||
| HostProperty.HostVersion => ScriptHost.Version, | ||
| _ => null | ||
| }; | ||
|
|
||
| if (string.IsNullOrEmpty(value)) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| _logger.LogDebug($"Evaluating HostPropertyCondition with value: {value} and expression {Expression}"); | ||
|
|
||
| return _regex.IsMatch(value); | ||
| } | ||
|
|
||
| // Validates if condition parametrs meet expected values, fail if they don't | ||
| private void Validate() | ||
| { | ||
| if (string.IsNullOrEmpty(Name)) | ||
| { | ||
| throw new ValidationException($"HostPropertyCondition {nameof(Name)} cannot be empty."); | ||
| } | ||
|
|
||
| if (!Enum.GetNames(typeof(HostProperty)).Any(x => x.ToLower().Contains(Name.ToLower()))) | ||
| { | ||
| throw new ValidationException($"HostPropertyCondition {nameof(Name)} is not a valid host property name."); | ||
| } | ||
|
|
||
| if (string.IsNullOrEmpty(Expression)) | ||
| { | ||
| throw new ValidationException($"HostPropertyCondition {nameof(Expression)} cannot be empty."); | ||
| } | ||
|
|
||
| try | ||
| { | ||
| _regex = new Regex(Expression); | ||
| } | ||
| catch | ||
| { | ||
| throw new ValidationException($"HostPropertyCondition {nameof(Expression)} must be a valid regular expression."); | ||
| } | ||
| } | ||
| } | ||
| } |
16 changes: 16 additions & 0 deletions
16
src/WebJobs.Script/Workers/Profiles/IWorkerProfileCondition.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| // Copyright (c) .NET Foundation. All rights reserved. | ||
| // Licensed under the MIT License. See License.txt in the project root for license information. | ||
|
|
||
| namespace Microsoft.Azure.WebJobs.Script.Workers | ||
| { | ||
| /// <summary> | ||
| /// Interface for different types of profile conditions | ||
| /// </summary> | ||
| public interface IWorkerProfileCondition | ||
| { | ||
| /// <summary> | ||
| /// Check if different condition type meet their criteria | ||
| /// </summary> | ||
| bool Evaluate(); | ||
shreyas-gopalakrishna marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
16 changes: 16 additions & 0 deletions
16
src/WebJobs.Script/Workers/Profiles/IWorkerProfileConditionProvider.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| // Copyright (c) .NET Foundation. All rights reserved. | ||
| // Licensed under the MIT License. See License.txt in the project root for license information. | ||
|
|
||
| namespace Microsoft.Azure.WebJobs.Script.Workers.Profiles | ||
| { | ||
| /// <summary> | ||
| /// Interface to manage different profile condition providers | ||
| /// </summary> | ||
| internal interface IWorkerProfileConditionProvider | ||
| { | ||
| /// <summary> | ||
| /// Factory method to create a profile condition | ||
| /// </summary> | ||
| bool TryCreateCondition(WorkerProfileConditionDescriptor descriptor, out IWorkerProfileCondition condition); | ||
| } | ||
| } |
35 changes: 35 additions & 0 deletions
35
src/WebJobs.Script/Workers/Profiles/IWorkerProfileManager.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| // Copyright (c) .NET Foundation. All rights reserved. | ||
| // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using System.Collections.Generic; | ||
| using Microsoft.Azure.WebJobs.Script.Workers.Profiles; | ||
| using Microsoft.Azure.WebJobs.Script.Workers.Rpc; | ||
|
|
||
| namespace Microsoft.Azure.WebJobs.Script.Workers | ||
| { | ||
| /// <summary> | ||
| /// Interface to regulate profile operations through the profile manager | ||
| /// </summary> | ||
| public interface IWorkerProfileManager | ||
shreyas-gopalakrishna marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| /// <summary> | ||
| /// Creates profile condition using different condition descriptor properties | ||
| /// </summary> | ||
| bool TryCreateWorkerProfileCondition(WorkerProfileConditionDescriptor conditionDescriptor, out IWorkerProfileCondition condition); | ||
|
|
||
| /// <summary> | ||
| /// Save different profiles for a given worker runtime language | ||
| /// </summary> | ||
| void SaveWorkerDescriptionProfiles(List<WorkerDescriptionProfile> workerDescriptionProfiles, string language); | ||
|
|
||
| /// <summary> | ||
| /// Load a profile that meets it's conditions | ||
| /// </summary> | ||
| void LoadWorkerDescriptionFromProfiles(RpcWorkerDescription defaultWorkerDescription, out RpcWorkerDescription workerDescription); | ||
|
|
||
| /// <summary> | ||
| /// Verify if the current profile's conditions have changed | ||
| /// </summary> | ||
| bool IsCorrectProfileLoaded(string workerRuntime); | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.