| 1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
use crate::StoreUrl; |
| 11 |
use object_store::azure::{MicrosoftAzure, MicrosoftAzureBuilder}; |
| 12 |
use oxy_core::strata::{Error, Result}; |
| 13 |
|
| 14 |
pub const HINT: &str = "run `az login`, or set AZURE_CLIENT_ID, AZURE_CLIENT_SECRET and AZURE_TENANT_ID for a service principal, or AZURE_STORAGE_ACCOUNT_KEY"; |
| 15 |
|
| 16 |
fn env(name: &str) -> Option<String> { |
| 17 |
std::env::var(name).ok().filter(|v| !v.is_empty()) |
| 18 |
} |
| 19 |
|
| 20 |
|
| 21 |
pub fn open(url: &StoreUrl) -> Result<(MicrosoftAzure, String)> { |
| 22 |
let (container, prefix) = match url.path.split_once('/') { |
| 23 |
Some((c, p)) => (c.to_string(), p.to_string()), |
| 24 |
None if !url.path.is_empty() => (url.path.clone(), String::new()), |
| 25 |
None => { |
| 26 |
return Err(Error::Backend(format!( |
| 27 |
"{}: an Azure store URL names the account and the container: az://ACCOUNT/CONTAINER/PREFIX", |
| 28 |
url.plain() |
| 29 |
))) |
| 30 |
} |
| 31 |
}; |
| 32 |
let mut b = MicrosoftAzureBuilder::from_env() |
| 33 |
.with_account(&url.host) |
| 34 |
.with_container_name(&container) |
| 35 |
.with_http_connector(crate::http::UreqConnector); |
| 36 |
let principal = ( |
| 37 |
env("AZURE_CLIENT_ID").or_else(|| env("AZURE_STORAGE_CLIENT_ID")), |
| 38 |
env("AZURE_CLIENT_SECRET").or_else(|| env("AZURE_STORAGE_CLIENT_SECRET")), |
| 39 |
env("AZURE_TENANT_ID").or_else(|| env("AZURE_STORAGE_TENANT_ID")), |
| 40 |
); |
| 41 |
let mut explicit = false; |
| 42 |
if let (Some(id), Some(secret), Some(tenant)) = principal { |
| 43 |
b = b.with_client_secret_authorization(id, secret, tenant); |
| 44 |
explicit = true; |
| 45 |
} |
| 46 |
if env("AZURE_STORAGE_ACCOUNT_KEY").is_some() |
| 47 |
|| env("AZURE_STORAGE_ACCESS_KEY").is_some() |
| 48 |
|| env("AZURE_STORAGE_SAS_TOKEN").is_some() |
| 49 |
|| env("AZURE_STORAGE_SAS_KEY").is_some() |
| 50 |
{ |
| 51 |
explicit = true; |
| 52 |
} |
| 53 |
if let Some(endpoint) = url.param("endpoint") { |
| 54 |
b = b |
| 55 |
.with_endpoint(endpoint.to_string()) |
| 56 |
.with_allow_http(endpoint.starts_with("http://")); |
| 57 |
} |
| 58 |
if !explicit { |
| 59 |
|
| 60 |
b = b.with_use_azure_cli(true); |
| 61 |
} |
| 62 |
let store = b |
| 63 |
.build() |
| 64 |
.map_err(|e| Error::Backend(format!("{}: {e}: {HINT}", url.plain())))?; |
| 65 |
Ok((store, prefix)) |
| 66 |
} |