Skip to content

Commit 10564cc

Browse files
authored
Add cloud configuration API (#3087)
1 parent 0d49509 commit 10564cc

File tree

4 files changed

+134
-0
lines changed

4 files changed

+134
-0
lines changed

sdk/core/azure_core/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- Added `RawResponse::deconstruct()`.
1212
- Added `ResponseBody::collect_string()`.
1313
- Added `ResponseBody::from_bytes()`.
14+
- Added the `cloud` module with types for configuring clients to use different Azure clouds.
1415
- Implemented `AsRef<[u8]>` and `Deref<Target = [u8]>` for `ResponseBody`.
1516

1617
### Breaking Changes

sdk/core/azure_core/src/cloud.rs

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
//! Azure cloud configuration.
5+
6+
use std::{any::TypeId, collections::HashMap};
7+
8+
/// Configurations for different Azure clouds.
9+
#[derive(Clone, Debug, Default, Eq, PartialEq)]
10+
#[non_exhaustive]
11+
pub enum CloudConfiguration {
12+
/// Azure Public Cloud
13+
#[default]
14+
AzurePublic,
15+
16+
/// Azure Government
17+
AzureGovernment,
18+
19+
/// Azure in China
20+
AzureChina,
21+
22+
/// A custom cloud.
23+
///
24+
/// # Example
25+
///
26+
/// ```
27+
/// # mod azure_service_module {
28+
/// # pub struct Audience;
29+
/// # }
30+
///
31+
/// use azure_core::{
32+
/// cloud::{Audiences, CloudConfiguration, CustomConfiguration},
33+
/// http::ClientOptions,
34+
/// };
35+
///
36+
/// let mut custom = CustomConfiguration::default();
37+
/// custom.audiences = Audiences::new()
38+
/// .with::<azure_service_module::Audience>("https://service.mycloud.local".to_string());
39+
/// custom.authority_host = "https://login.mycloud.local".to_string();
40+
/// let cloud: CloudConfiguration = custom.into();
41+
/// ```
42+
Custom(CustomConfiguration),
43+
}
44+
45+
/// Configuration for a custom cloud.
46+
#[derive(Clone, Debug, Default, Eq, PartialEq)]
47+
#[non_exhaustive]
48+
pub struct CustomConfiguration {
49+
/// Base URL for authentication, for example "https://login.microsoftonline.com"
50+
pub authority_host: String,
51+
52+
/// Map of SDK modules to their Entra ID audiences.
53+
pub audiences: Audiences,
54+
}
55+
56+
impl From<CustomConfiguration> for CloudConfiguration {
57+
fn from(config: CustomConfiguration) -> Self {
58+
Self::Custom(config)
59+
}
60+
}
61+
62+
/// Collection of audiences for an Azure cloud's services
63+
#[derive(Clone, Debug, Default, Eq, PartialEq)]
64+
pub struct Audiences(HashMap<TypeId, String>);
65+
66+
impl Audiences {
67+
/// Create an empty `Audiences` map.
68+
pub fn new() -> Self {
69+
Self(HashMap::new())
70+
}
71+
72+
/// Get a module's audience.
73+
pub fn get<T: 'static>(&self) -> Option<&str> {
74+
self.0.get(&TypeId::of::<T>()).map(|s| s.as_str())
75+
}
76+
77+
/// Insert or replace an audience.
78+
pub fn insert<T: 'static>(&mut self, audience: String) {
79+
self.0.insert(TypeId::of::<T>(), audience);
80+
}
81+
82+
/// Insert or replace an audience and return `Self` to allow chaining.
83+
pub fn with<T: 'static>(mut self, audience: String) -> Self {
84+
self.0.insert(TypeId::of::<T>(), audience);
85+
self
86+
}
87+
}
88+
89+
#[cfg(test)]
90+
mod tests {
91+
use super::*;
92+
93+
#[test]
94+
fn custom() {
95+
struct A;
96+
struct B;
97+
struct C;
98+
99+
let cloud = CustomConfiguration {
100+
authority_host: "https://login.mycloud.local".to_string(),
101+
audiences: Audiences::new()
102+
.with::<A>("A".to_string())
103+
.with::<B>("B".to_string()),
104+
}
105+
.into();
106+
107+
let CloudConfiguration::Custom(mut custom) = cloud else {
108+
unreachable!();
109+
};
110+
111+
assert_eq!(custom.authority_host, "https://login.mycloud.local");
112+
assert_eq!(custom.audiences.get::<A>(), Some("A"));
113+
assert_eq!(custom.audiences.get::<B>(), Some("B"));
114+
assert_eq!(custom.audiences.get::<C>(), None);
115+
116+
custom.audiences.insert::<C>("C".to_string());
117+
assert_eq!(custom.audiences.get::<C>(), Some("C"));
118+
}
119+
120+
#[test]
121+
fn default() {
122+
assert_eq!(
123+
CloudConfiguration::AzurePublic,
124+
CloudConfiguration::default()
125+
);
126+
}
127+
}

sdk/core/azure_core/src/http/options/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ pub use typespec_client_core::http::{
1313
};
1414
pub use user_agent::*;
1515

16+
use crate::cloud::CloudConfiguration;
17+
1618
/// Client options allow customization of general client policies, retry options, and more.
1719
#[derive(Clone, Debug, Default)]
1820
pub struct ClientOptions {
@@ -41,6 +43,9 @@ pub struct ClientOptions {
4143
///
4244
/// Specifies which headers and query parameters should be logged. All headers and query parameters not in the allow list will be redacted.
4345
pub logging: LoggingOptions,
46+
47+
/// Cloud configuration for the client. If None, the client will default to Azure Public Cloud.
48+
pub cloud: Option<Arc<CloudConfiguration>>,
4449
}
4550

4651
pub(crate) struct CoreClientOptions {

sdk/core/azure_core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#[macro_use]
1111
mod macros;
1212

13+
pub mod cloud;
1314
mod constants;
1415
pub mod credentials;
1516
pub mod error;

0 commit comments

Comments
 (0)