Skip to content

Commit 5e8b299

Browse files
cleaned up CM workspace APIs (Azure#46649)
* cleaned up workspace APIs * PR feedback
1 parent abc40d3 commit 5e8b299

File tree

9 files changed

+159
-156
lines changed

9 files changed

+159
-156
lines changed

sdk/provisioning/Azure.Provisioning.CloudMachine/api/Azure.Provisioning.CloudMachine.netstandard2.0.cs

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,15 @@ public partial class CloudMachineClient : Azure.CloudMachine.CloudMachineWorkspa
66
public Azure.CloudMachine.MessagingServices Messaging { get { throw null; } }
77
public Azure.CloudMachine.StorageServices Storage { get { throw null; } }
88
}
9-
public partial class CloudMachineWorkspace : Azure.Core.WorkspaceClient
9+
public partial class CloudMachineWorkspace : Azure.Core.ClientWorkspace
1010
{
1111
public CloudMachineWorkspace(Azure.Core.TokenCredential? credential = null, Microsoft.Extensions.Configuration.IConfiguration? configuration = null) { }
1212
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
13-
public override Azure.Core.TokenCredential Credential { get { throw null; } }
14-
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
1513
public string Id { get { throw null; } }
1614
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
1715
public override bool Equals(object? obj) { throw null; }
1816
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
19-
public override Azure.Core.ClientConfiguration? GetConfiguration(string clientId, string? instanceId = null) { throw null; }
17+
public override Azure.Core.ClientConnectionOptions GetConnectionOptions(System.Type clientType, string? instanceId = null) { throw null; }
2018
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
2119
public override int GetHashCode() { throw null; }
2220
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
@@ -46,30 +44,34 @@ namespace Azure.Core
4644
public partial class ClientCache
4745
{
4846
public ClientCache() { }
49-
public T Get<T>(string id, System.Func<T> value) where T : class { throw null; }
47+
public T Get<T>(System.Func<T> value, string? id = null) where T : class { throw null; }
48+
}
49+
public enum ClientConnectionKind
50+
{
51+
EntraId = 0,
52+
ApiKey = 1,
53+
OutOfBand = 2,
5054
}
5155
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
52-
public readonly partial struct ClientConfiguration
56+
public readonly partial struct ClientConnectionOptions
5357
{
5458
private readonly object _dummy;
5559
private readonly int _dummyPrimitive;
56-
public ClientConfiguration(string endpoint, string? apiKey = null) { throw null; }
57-
public string? ApiKey { get { throw null; } }
58-
public Azure.Core.CredentialType CredentialType { get { throw null; } }
59-
public string Endpoint { get { throw null; } }
60+
public ClientConnectionOptions(string subclientId) { throw null; }
61+
public ClientConnectionOptions(System.Uri endpoint, Azure.Core.TokenCredential credential) { throw null; }
62+
public ClientConnectionOptions(System.Uri endpoint, string apiKey) { throw null; }
63+
public string? ApiKeyCredential { get { throw null; } }
64+
public Azure.Core.ClientConnectionKind ConnectionKind { get { throw null; } }
65+
public System.Uri? Endpoint { get { throw null; } }
66+
public string? Id { get { throw null; } }
67+
public Azure.Core.TokenCredential? TokenCredential { get { throw null; } }
6068
}
61-
public enum CredentialType
69+
public abstract partial class ClientWorkspace
6270
{
63-
EntraId = 0,
64-
ApiKey = 1,
65-
}
66-
public abstract partial class WorkspaceClient
67-
{
68-
protected WorkspaceClient() { }
69-
public abstract Azure.Core.TokenCredential Credential { get; }
71+
protected ClientWorkspace() { }
7072
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
7173
public Azure.Core.ClientCache Subclients { get { throw null; } }
72-
public abstract Azure.Core.ClientConfiguration? GetConfiguration(string clientId, string? instanceId = null);
74+
public abstract Azure.Core.ClientConnectionOptions GetConnectionOptions(System.Type clientType, string? instanceId = null);
7375
}
7476
}
7577
namespace Azure.Provisioning.CloudMachine
@@ -96,7 +98,7 @@ namespace Azure.Provisioning.CloudMachine.KeyVault
9698
{
9799
public static partial class KeyVaultExtensions
98100
{
99-
public static Azure.Security.KeyVault.Secrets.SecretClient GetKeyVaultSecretsClient(this Azure.Core.WorkspaceClient workspace) { throw null; }
101+
public static Azure.Security.KeyVault.Secrets.SecretClient GetKeyVaultSecretsClient(this Azure.Core.ClientWorkspace workspace) { throw null; }
100102
}
101103
public partial class KeyVaultFeature : Azure.Provisioning.CloudMachine.CloudMachineFeature
102104
{
@@ -107,15 +109,15 @@ public override void AddTo(Azure.Provisioning.CloudMachine.CloudMachineInfrastru
107109
}
108110
namespace Azure.Provisioning.CloudMachine.OpenAI
109111
{
112+
public static partial class AzureOpenAIExtensions
113+
{
114+
public static OpenAI.Chat.ChatClient GetOpenAIChatClient(this Azure.Core.ClientWorkspace workspace) { throw null; }
115+
}
110116
public partial class OpenAIFeature : Azure.Provisioning.CloudMachine.CloudMachineFeature
111117
{
112118
public OpenAIFeature(string model, string modelVersion) { }
113119
public string Model { get { throw null; } }
114120
public string ModelVersion { get { throw null; } }
115121
public override void AddTo(Azure.Provisioning.CloudMachine.CloudMachineInfrastructure cloudMachine) { }
116122
}
117-
public static partial class OpenAIFeatureExtensions
118-
{
119-
public static OpenAI.Chat.ChatClient GetOpenAIChatClient(this Azure.Core.WorkspaceClient workspace) { throw null; }
120-
}
121123
}

sdk/provisioning/Azure.Provisioning.CloudMachine/src/AzureSdkExtensions/KeyVaultFeature.cs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,19 +64,13 @@ public override void AddTo(CloudMachineInfrastructure infrastructure)
6464

6565
public static class KeyVaultExtensions
6666
{
67-
public static SecretClient GetKeyVaultSecretsClient(this WorkspaceClient workspace)
67+
public static SecretClient GetKeyVaultSecretsClient(this ClientWorkspace workspace)
6868
{
69-
ClientConfiguration? connectionMaybe = workspace.GetConfiguration(typeof(SecretClient).FullName);
70-
if (connectionMaybe == null)
69+
ClientConnectionOptions connection = workspace.GetConnectionOptions(typeof(SecretClient));
70+
if (connection.ConnectionKind == ClientConnectionKind.EntraId)
7171
{
72-
throw new Exception("Connection not found");
72+
return new(connection.Endpoint, connection.TokenCredential);
7373
}
74-
75-
ClientConfiguration connection = connectionMaybe.Value;
76-
if (connection.CredentialType == CredentialType.EntraId)
77-
{
78-
return new(new Uri(connection.Endpoint), workspace.Credential);
79-
}
80-
throw new Exception("ApiKey not supported");
74+
throw new Exception("API key not supported");
8175
}
8276
}

sdk/provisioning/Azure.Provisioning.CloudMachine/src/AzureSdkExtensions/OpenAIFeature.cs

Lines changed: 25 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@
33

44
using System;
55
using System.ClientModel;
6-
using System.ClientModel.Primitives;
7-
using System.Diagnostics.Contracts;
86
using Azure.AI.OpenAI;
9-
using Azure.CloudMachine;
107
using Azure.Core;
118
using Azure.Provisioning.Authorization;
129
using Azure.Provisioning.CognitiveServices;
@@ -62,44 +59,36 @@ public override void AddTo(CloudMachineInfrastructure cloudMachine)
6259
}
6360
}
6461

65-
public static class OpenAIFeatureExtensions
62+
public static class AzureOpenAIExtensions
6663
{
67-
public static ChatClient GetOpenAIChatClient(this WorkspaceClient workspace)
64+
public static ChatClient GetOpenAIChatClient(this ClientWorkspace workspace)
6865
{
69-
string chatClientId = typeof(ChatClient).FullName;
70-
71-
ChatClient client = workspace.Subclients.Get(chatClientId, () =>
66+
ChatClient chatClient = workspace.Subclients.Get(() =>
7267
{
73-
string azureOpenAIClientId = typeof(AzureOpenAIClient).FullName;
74-
75-
AzureOpenAIClient aoia = workspace.Subclients.Get(azureOpenAIClientId, () =>
76-
{
77-
ClientConfiguration? connectionMaybe = workspace.GetConfiguration(typeof(AzureOpenAIClient).FullName);
78-
if (connectionMaybe == null) throw new Exception("Connection not found");
68+
AzureOpenAIClient aoiaClient = workspace.Subclients.Get(() => CreateAzureOpenAIClient(workspace));
69+
return workspace.CreateChatClient(aoiaClient);
70+
});
7971

80-
ClientConfiguration connection = connectionMaybe.Value;
81-
Uri endpoint = new(connection.Endpoint);
82-
var clientOptions = new AzureOpenAIClientOptions();
83-
if (connection.CredentialType == CredentialType.EntraId)
84-
{
85-
AzureOpenAIClient aoai = new(endpoint, workspace.Credential, clientOptions);
86-
return aoai;
87-
}
88-
else
89-
{
90-
AzureOpenAIClient aoai = new(endpoint, new ApiKeyCredential(connection.ApiKey!), clientOptions);
91-
return aoai;
92-
}
93-
});
72+
return chatClient;
73+
}
9474

95-
string azureOpenAIChatClientId = typeof(ChatClient).FullName;
96-
ClientConfiguration? connectionMaybe = workspace.GetConfiguration(azureOpenAIChatClientId);
97-
if (connectionMaybe == null) throw new Exception("Connection not found");
98-
var connection = connectionMaybe.Value;
99-
ChatClient chat = aoia.GetChatClient(connection.Endpoint);
100-
return chat;
101-
});
75+
private static AzureOpenAIClient CreateAzureOpenAIClient(this ClientWorkspace workspace)
76+
{
77+
ClientConnectionOptions connection = workspace.GetConnectionOptions(typeof(AzureOpenAIClient));
78+
if (connection.ConnectionKind == ClientConnectionKind.EntraId)
79+
{
80+
return new(connection.Endpoint, connection.TokenCredential);
81+
}
82+
else
83+
{
84+
return new(connection.Endpoint, new ApiKeyCredential(connection.ApiKeyCredential!));
85+
}
86+
}
10287

103-
return client;
88+
private static ChatClient CreateChatClient(this ClientWorkspace workspace, AzureOpenAIClient client)
89+
{
90+
ClientConnectionOptions connection = workspace.GetConnectionOptions(typeof(ChatClient));
91+
ChatClient chat = client.GetChatClient(connection.Id);
92+
return chat;
10493
}
10594
}

sdk/provisioning/Azure.Provisioning.CloudMachine/src/Core/ClientCache.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,24 @@ namespace Azure.Core;
99
// TODO: this is a very demo implementation. We need to do better
1010
public class ClientCache
1111
{
12-
private readonly Dictionary<string, object> _clients = new Dictionary<string, object>();
12+
private readonly Dictionary<(Type, string?), object> _clients = new Dictionary<(Type, string?), object>();
1313

14-
// TODO: consider uisng ICLientCreator instead of Func
15-
public T Get<T>(string id, Func<T> value) where T: class
14+
public T Get<T>(Func<T> value, string? id = default) where T: class
1615
{
16+
var client = (typeof(T), id);
1717
lock (_clients)
1818
{
19-
if (_clients.TryGetValue(id, out object cached))
19+
if (_clients.TryGetValue(client, out object cached))
2020
{
21-
T client = (T)cached;
22-
return client;
21+
return (T)cached;
2322
}
2423

2524
if (_clients.Count > 100)
2625
{
2726
GC();
2827
}
2928
T created = value();
30-
_clients.Add(id, created);
29+
_clients.Add(client, created);
3130
return created;
3231
}
3332

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.ComponentModel;
6+
7+
namespace Azure.Core;
8+
9+
public abstract class ClientWorkspace
10+
{
11+
public abstract ClientConnectionOptions GetConnectionOptions(Type clientType, string? instanceId = default);
12+
13+
[EditorBrowsable(EditorBrowsableState.Never)]
14+
public ClientCache Subclients { get; } = new ClientCache();
15+
}
16+
17+
public readonly struct ClientConnectionOptions
18+
{
19+
public ClientConnectionOptions(Uri endpoint, string apiKey)
20+
{
21+
Endpoint = endpoint;
22+
ApiKeyCredential = apiKey;
23+
ConnectionKind = ClientConnectionKind.ApiKey;
24+
}
25+
public ClientConnectionOptions(Uri endpoint, TokenCredential credential)
26+
{
27+
Endpoint = endpoint;
28+
TokenCredential = credential;
29+
ConnectionKind = ClientConnectionKind.EntraId;
30+
}
31+
public ClientConnectionOptions(string subclientId)
32+
{
33+
Id = subclientId;
34+
ConnectionKind = ClientConnectionKind.OutOfBand;
35+
}
36+
37+
public ClientConnectionKind ConnectionKind { get; }
38+
39+
public Uri? Endpoint { get; }
40+
public string? Id { get; }
41+
public string? ApiKeyCredential { get; }
42+
public TokenCredential? TokenCredential { get; }
43+
}
44+
45+
public enum ClientConnectionKind
46+
{
47+
EntraId,
48+
ApiKey,
49+
OutOfBand
50+
}

sdk/provisioning/Azure.Provisioning.CloudMachine/src/Core/WorkspaceClient.cs

Lines changed: 0 additions & 35 deletions
This file was deleted.

sdk/provisioning/Azure.Provisioning.CloudMachine/src/OFX/CloudMachineWorkspace.cs

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,16 @@
1010

1111
namespace Azure.CloudMachine;
1212

13-
public class CloudMachineWorkspace : WorkspaceClient
13+
public class CloudMachineWorkspace : ClientWorkspace
1414
{
15-
[EditorBrowsable(EditorBrowsableState.Never)]
16-
public string Id { get; }
17-
18-
[EditorBrowsable(EditorBrowsableState.Never)]
19-
public override TokenCredential Credential { get; } = new ChainedTokenCredential(
15+
private TokenCredential Credential { get; } = new ChainedTokenCredential(
2016
new AzureCliCredential(),
2117
new AzureDeveloperCliCredential()
2218
);
2319

20+
[EditorBrowsable(EditorBrowsableState.Never)]
21+
public string Id { get; }
22+
2423
[SuppressMessage("Usage", "AZC0007:DO provide a minimal constructor that takes only the parameters required to connect to the service.", Justification = "<Pending>")]
2524
public CloudMachineWorkspace(TokenCredential? credential = default, IConfiguration? configuration = default)
2625
{
@@ -45,29 +44,25 @@ public CloudMachineWorkspace(TokenCredential? credential = default, IConfigurati
4544
}
4645

4746
[EditorBrowsable(EditorBrowsableState.Never)]
48-
public override ClientConfiguration? GetConfiguration(string clientId, string? instanceId = default)
47+
public override ClientConnectionOptions GetConnectionOptions(Type clientType, string? instanceId = default)
4948
{
49+
string clientId = clientType.FullName;
5050
switch (clientId)
5151
{
5252
case "Azure.Security.KeyVault.Secrets.SecretClient":
53-
return new ClientConfiguration($"https://{this.Id}.vault.azure.net/");
53+
return new ClientConnectionOptions(new($"https://{this.Id}.vault.azure.net/"), Credential);
5454
case "Azure.Messaging.ServiceBus.ServiceBusClient":
55-
return new ClientConfiguration($"{this.Id}.servicebus.windows.net");
55+
return new ClientConnectionOptions(new($"{this.Id}.servicebus.windows.net"), Credential);
5656
case "Azure.Messaging.ServiceBus.ServiceBusSender":
5757
if (instanceId == default) instanceId = "cm_default_topic_sender";
58-
return new ClientConfiguration(instanceId);
58+
return new ClientConnectionOptions(instanceId);
5959
case "Azure.Storage.Blobs.BlobContainerClient":
6060
if (instanceId == default) instanceId = "default";
61-
return new ClientConfiguration($"https://{this.Id}.blob.core.windows.net/{instanceId}");
61+
return new ClientConnectionOptions(new($"https://{this.Id}.blob.core.windows.net/{instanceId}"), Credential);
6262
case "Azure.AI.OpenAI.AzureOpenAIClient":
63-
string endpoint = $"https://{this.Id}.openai.azure.com";
64-
string? key = null; // Environment.GetEnvironmentVariable("openai_cm_key");
65-
if (key != null)
66-
return new ClientConfiguration(endpoint, key);
67-
else
68-
return new ClientConfiguration(endpoint);
63+
return new ClientConnectionOptions(new($"https://{this.Id}.openai.azure.com"), Credential);
6964
case "OpenAI.Chat.ChatClient":
70-
return new ClientConfiguration(this.Id);
65+
return new ClientConnectionOptions(Id);
7166
default:
7267
throw new Exception($"unknown client {clientId}");
7368
}

0 commit comments

Comments
 (0)