iceberg/io/config/
azdls.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Azure Data Lake Storage configuration.
19//!
20//! This module provides configuration constants and types for Azure Data Lake Storage.
21
22use serde::{Deserialize, Serialize};
23use typed_builder::TypedBuilder;
24
25use super::StorageConfig;
26use crate::Result;
27
28/// A connection string.
29///
30/// Note, this string is parsed first, and any other passed adls.* properties
31/// will override values from the connection string.
32pub const ADLS_CONNECTION_STRING: &str = "adls.connection-string";
33/// The account that you want to connect to.
34pub const ADLS_ACCOUNT_NAME: &str = "adls.account-name";
35/// The key to authentication against the account.
36pub const ADLS_ACCOUNT_KEY: &str = "adls.account-key";
37/// The shared access signature.
38pub const ADLS_SAS_TOKEN: &str = "adls.sas-token";
39/// The tenant-id.
40pub const ADLS_TENANT_ID: &str = "adls.tenant-id";
41/// The client-id.
42pub const ADLS_CLIENT_ID: &str = "adls.client-id";
43/// The client-secret.
44pub const ADLS_CLIENT_SECRET: &str = "adls.client-secret";
45/// The authority host of the service principal.
46/// - required for client_credentials authentication
47/// - default value: `https://login.microsoftonline.com`
48pub const ADLS_AUTHORITY_HOST: &str = "adls.authority-host";
49
50/// Azure Data Lake Storage configuration.
51///
52/// This struct contains all the configuration options for connecting to Azure Data Lake Storage.
53/// Use the builder pattern via `AzdlsConfig::builder()` to construct instances.
54/// ```
55#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, TypedBuilder)]
56pub struct AzdlsConfig {
57    /// Connection string.
58    #[builder(default, setter(strip_option, into))]
59    pub connection_string: Option<String>,
60    /// Account name.
61    #[builder(default, setter(strip_option, into))]
62    pub account_name: Option<String>,
63    /// Account key.
64    #[builder(default, setter(strip_option, into))]
65    pub account_key: Option<String>,
66    /// SAS token.
67    #[builder(default, setter(strip_option, into))]
68    pub sas_token: Option<String>,
69    /// Tenant ID.
70    #[builder(default, setter(strip_option, into))]
71    pub tenant_id: Option<String>,
72    /// Client ID.
73    #[builder(default, setter(strip_option, into))]
74    pub client_id: Option<String>,
75    /// Client secret.
76    #[builder(default, setter(strip_option, into))]
77    pub client_secret: Option<String>,
78    /// Authority host.
79    #[builder(default, setter(strip_option, into))]
80    pub authority_host: Option<String>,
81    /// Endpoint URL.
82    #[builder(default, setter(strip_option, into))]
83    pub endpoint: Option<String>,
84    /// Filesystem name.
85    #[builder(default, setter(into))]
86    pub filesystem: String,
87}
88
89impl TryFrom<&StorageConfig> for AzdlsConfig {
90    type Error = crate::Error;
91
92    fn try_from(config: &StorageConfig) -> Result<Self> {
93        let props = config.props();
94
95        let mut cfg = AzdlsConfig::default();
96
97        if let Some(connection_string) = props.get(ADLS_CONNECTION_STRING) {
98            cfg.connection_string = Some(connection_string.clone());
99        }
100        if let Some(account_name) = props.get(ADLS_ACCOUNT_NAME) {
101            cfg.account_name = Some(account_name.clone());
102        }
103        if let Some(account_key) = props.get(ADLS_ACCOUNT_KEY) {
104            cfg.account_key = Some(account_key.clone());
105        }
106        if let Some(sas_token) = props.get(ADLS_SAS_TOKEN) {
107            cfg.sas_token = Some(sas_token.clone());
108        }
109        if let Some(tenant_id) = props.get(ADLS_TENANT_ID) {
110            cfg.tenant_id = Some(tenant_id.clone());
111        }
112        if let Some(client_id) = props.get(ADLS_CLIENT_ID) {
113            cfg.client_id = Some(client_id.clone());
114        }
115        if let Some(client_secret) = props.get(ADLS_CLIENT_SECRET) {
116            cfg.client_secret = Some(client_secret.clone());
117        }
118        if let Some(authority_host) = props.get(ADLS_AUTHORITY_HOST) {
119            cfg.authority_host = Some(authority_host.clone());
120        }
121
122        Ok(cfg)
123    }
124}
125
126#[cfg(test)]
127mod tests {
128    use super::*;
129
130    #[test]
131    fn test_azdls_config_builder() {
132        let config = AzdlsConfig::builder()
133            .account_name("myaccount")
134            .account_key("my-account-key")
135            .build();
136
137        assert_eq!(config.account_name.as_deref(), Some("myaccount"));
138        assert_eq!(config.account_key.as_deref(), Some("my-account-key"));
139    }
140
141    #[test]
142    fn test_azdls_config_from_storage_config() {
143        let storage_config = StorageConfig::new()
144            .with_prop(ADLS_ACCOUNT_NAME, "myaccount")
145            .with_prop(ADLS_ACCOUNT_KEY, "my-account-key");
146
147        let azdls_config = AzdlsConfig::try_from(&storage_config).unwrap();
148
149        assert_eq!(azdls_config.account_name.as_deref(), Some("myaccount"));
150        assert_eq!(azdls_config.account_key.as_deref(), Some("my-account-key"));
151    }
152
153    #[test]
154    fn test_azdls_config_with_sas_token() {
155        let storage_config = StorageConfig::new()
156            .with_prop(ADLS_ACCOUNT_NAME, "myaccount")
157            .with_prop(ADLS_SAS_TOKEN, "my-sas-token");
158
159        let azdls_config = AzdlsConfig::try_from(&storage_config).unwrap();
160
161        assert_eq!(azdls_config.account_name.as_deref(), Some("myaccount"));
162        assert_eq!(azdls_config.sas_token.as_deref(), Some("my-sas-token"));
163    }
164
165    #[test]
166    fn test_azdls_config_with_client_credentials() {
167        let storage_config = StorageConfig::new()
168            .with_prop(ADLS_ACCOUNT_NAME, "myaccount")
169            .with_prop(ADLS_TENANT_ID, "my-tenant")
170            .with_prop(ADLS_CLIENT_ID, "my-client")
171            .with_prop(ADLS_CLIENT_SECRET, "my-secret");
172
173        let azdls_config = AzdlsConfig::try_from(&storage_config).unwrap();
174
175        assert_eq!(azdls_config.account_name.as_deref(), Some("myaccount"));
176        assert_eq!(azdls_config.tenant_id.as_deref(), Some("my-tenant"));
177        assert_eq!(azdls_config.client_id.as_deref(), Some("my-client"));
178        assert_eq!(azdls_config.client_secret.as_deref(), Some("my-secret"));
179    }
180}