-
Notifications
You must be signed in to change notification settings - Fork 55
Expand file tree
/
Copy pathDurableTaskSchedulerWorkerOptions.cs
More file actions
183 lines (164 loc) · 7.85 KB
/
DurableTaskSchedulerWorkerOptions.cs
File metadata and controls
183 lines (164 loc) · 7.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.ComponentModel.DataAnnotations;
using Azure.Core;
using Azure.Identity;
using Grpc.Core;
using Grpc.Net.Client;
using Microsoft.DurableTask;
using Microsoft.DurableTask.Worker.Hosting;
namespace Microsoft.DurableTask;
/// <summary>
/// Options for configuring the Durable Task Scheduler.
/// </summary>
public class DurableTaskSchedulerWorkerOptions
{
/// <summary>
/// Gets or sets the endpoint address of the Durable Task Scheduler resource.
/// Expected to be in the format "https://{scheduler-name}.{region}.durabletask.io".
/// </summary>
[Required(ErrorMessage = "Endpoint address is required")]
public string EndpointAddress { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the name of the task hub resource associated with the Durable Task Scheduler resource.
/// </summary>
[Required(ErrorMessage = "Task hub name is required")]
public string TaskHubName { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the credential used to authenticate with the Durable Task Scheduler task hub resource.
/// </summary>
public TokenCredential? Credential { get; set; }
/// <summary>
/// Gets or sets the resource ID of the Durable Task Scheduler resource.
/// The default value is https://durabletask.io.
/// </summary>
public string ResourceId { get; set; } = "https://durabletask.io";
/// <summary>
/// Gets or sets the worker ID used to identify the worker instance.
/// The default value is a string containing the machine name, process ID, and a unique identifier.
/// </summary>
public string WorkerId { get; set; } = $"{Environment.MachineName},{Environment.ProcessId},{Guid.NewGuid():N}";
/// <summary>
/// Gets or sets a value indicating whether to allow insecure channel credentials.
/// This should only be set to true in local development/testing scenarios.
/// </summary>
public bool AllowInsecureCredentials { get; set; }
/// <summary>
/// Creates a new instance of <see cref="DurableTaskSchedulerWorkerOptions"/> from a connection string.
/// </summary>
/// <param name="connectionString">The connection string to parse.</param>
/// <returns>A new instance of <see cref="DurableTaskSchedulerWorkerOptions"/>.</returns>
public static DurableTaskSchedulerWorkerOptions FromConnectionString(string connectionString)
{
return FromConnectionString(new DurableTaskSchedulerConnectionString(connectionString));
}
/// <summary>
/// Creates a new instance of <see cref="DurableTaskSchedulerWorkerOptions"/> from a parsed connection string.
/// </summary>
/// <param name="connectionString">The connection string to parse.</param>
/// <returns>A new instance of <see cref="DurableTaskSchedulerWorkerOptions"/>.</returns>
internal static DurableTaskSchedulerWorkerOptions FromConnectionString(
DurableTaskSchedulerConnectionString connectionString)
{
TokenCredential? credential = GetCredentialFromConnectionString(connectionString);
return new DurableTaskSchedulerWorkerOptions()
{
EndpointAddress = connectionString.Endpoint,
TaskHubName = connectionString.TaskHubName,
Credential = credential,
AllowInsecureCredentials = credential is null,
};
}
/// <summary>
/// Creates a gRPC channel for communicating with the Durable Task Scheduler service.
/// </summary>
/// <returns>A configured <see cref="GrpcChannel"/> instance that can be used to make gRPC calls.</returns>
internal GrpcChannel CreateChannel()
{
Verify.NotNull(this.EndpointAddress, nameof(this.EndpointAddress));
Verify.NotNull(this.TaskHubName, nameof(this.TaskHubName));
string taskHubName = this.TaskHubName;
string endpoint = !this.EndpointAddress.Contains("://")
? $"https://{this.EndpointAddress}"
: this.EndpointAddress;
AccessTokenCache? cache =
this.Credential is not null
? new AccessTokenCache(
this.Credential,
new TokenRequestContext(new[] { $"{this.ResourceId}/.default" }),
TimeSpan.FromMinutes(5))
: null;
CallCredentials managedBackendCreds = CallCredentials.FromInterceptor(
async (context, metadata) =>
{
metadata.Add("taskhub", taskHubName);
// Add user agent header with durabletask-dotnet and DLL version from util
metadata.Add("x-user-agent", $"{DurableTaskUserAgentUtil.GetUserAgent(nameof(DurableTaskWorker))}");
metadata.Add("workerid", this.WorkerId);
if (cache == null)
{
return;
}
AccessToken token = await cache.GetTokenAsync(context.CancellationToken);
metadata.Add("Authorization", $"Bearer {token.Token}");
});
// Production will use HTTPS, but local testing will use HTTP
ChannelCredentials channelCreds = endpoint.StartsWith("https://", StringComparison.OrdinalIgnoreCase) ?
ChannelCredentials.SecureSsl :
ChannelCredentials.Insecure;
return GrpcChannel.ForAddress(endpoint, new GrpcChannelOptions
{
Credentials = ChannelCredentials.Create(channelCreds, managedBackendCreds),
UnsafeUseInsecureChannelCallCredentials = this.AllowInsecureCredentials,
ServiceConfig = GrpcRetryPolicyDefaults.DefaultServiceConfig,
});
}
static TokenCredential? GetCredentialFromConnectionString(DurableTaskSchedulerConnectionString connectionString)
{
string authType = connectionString.Authentication;
// Parse the supported auth types, in a case-insensitive way and without spaces
switch (authType.ToLowerInvariant())
{
case "defaultazure":
return new DefaultAzureCredential(); // CodeQL [SM05137] Use DefaultAzureCredential explicitly for local development and is decided by the user
case "managedidentity":
return new ManagedIdentityCredential(connectionString.ClientId);
case "workloadidentity":
WorkloadIdentityCredentialOptions opts = new WorkloadIdentityCredentialOptions();
if (!string.IsNullOrEmpty(connectionString.ClientId))
{
opts.ClientId = connectionString.ClientId;
}
if (!string.IsNullOrEmpty(connectionString.TenantId))
{
opts.TenantId = connectionString.TenantId;
}
if (connectionString.AdditionallyAllowedTenants is not null)
{
foreach (string tenant in connectionString.AdditionallyAllowedTenants)
{
opts.AdditionallyAllowedTenants.Add(tenant);
}
}
return new WorkloadIdentityCredential(opts);
case "environment":
return new EnvironmentCredential();
case "azurecli":
return new AzureCliCredential();
case "azurepowershell":
return new AzurePowerShellCredential();
case "visualstudio":
return new VisualStudioCredential();
case "visualstudiocode":
return new VisualStudioCodeCredential();
case "interactivebrowser":
return new InteractiveBrowserCredential();
case "none":
return null;
default:
throw new ArgumentException(
$"The connection string contains an unsupported authentication type '{authType}'.",
nameof(connectionString));
}
}
}