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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
use crate::{
generated::clients::BlobContainerClient as GeneratedBlobContainerClient,
generated::clients::BlobServiceClient as GeneratedBlobServiceClient,
generated::models::BlobServiceClientGetAccountInfoResult,
models::{
BlobServiceClientFindBlobsByTagsOptions, BlobServiceClientGetAccountInfoOptions,
BlobServiceClientGetPropertiesOptions, BlobServiceClientGetStatisticsOptions,
BlobServiceClientListContainersSegmentOptions, BlobServiceClientSetPropertiesOptions,
BlobServiceProperties, FilterBlobSegment, ListContainersSegmentResponse,
StorageServiceStats,
},
pipeline::StorageHeadersPolicy,
BlobContainerClient, BlobServiceClientOptions,
};
use azure_core::{
credentials::TokenCredential,
http::{
policies::{auth::BearerTokenAuthorizationPolicy, Policy},
NoFormat, Pager, Pipeline, RequestContent, Response, Url, XmlFormat,
},
tracing, Result,
};
use std::sync::Arc;
/// A client to interact with an Azure storage account.
pub struct BlobServiceClient {
pub(super) client: GeneratedBlobServiceClient,
}
impl GeneratedBlobServiceClient {
/// Creates a new GeneratedBlobServiceClient from the URL of the Azure storage account.
///
/// # Arguments
///
/// * `blob_service_url` - The full URL of the Azure storage account, for example `https://myaccount.blob.core.windows.net/`.
/// * `credential` - An optional implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating.
/// * `options` - Optional configuration for the client.
#[tracing::new("Storage.Blob.Service")]
pub fn from_url(
blob_service_url: Url,
credential: Option<Arc<dyn TokenCredential>>,
options: Option<BlobServiceClientOptions>,
) -> Result<Self> {
let mut options = options.unwrap_or_default();
let storage_headers_policy = Arc::new(StorageHeadersPolicy);
options
.client_options
.per_call_policies
.push(storage_headers_policy);
let per_retry_policies = if let Some(token_credential) = credential {
if !blob_service_url.scheme().starts_with("https") {
return Err(azure_core::Error::with_message(
azure_core::error::ErrorKind::Other,
format!("{blob_service_url} must use https"),
));
}
let auth_policy: Arc<dyn Policy> = Arc::new(BearerTokenAuthorizationPolicy::new(
token_credential,
vec!["https://storage.azure.com/.default"],
));
vec![auth_policy]
} else {
Vec::default()
};
let pipeline = Pipeline::new(
option_env!("CARGO_PKG_NAME"),
option_env!("CARGO_PKG_VERSION"),
options.client_options.clone(),
Vec::default(),
per_retry_policies,
None,
);
Ok(Self {
endpoint: blob_service_url,
version: options.version,
pipeline,
})
}
}
impl BlobServiceClient {
/// Creates a new BlobServiceClient, using Entra ID authentication.
///
/// # Arguments
///
/// * `endpoint` - The full URL of the Azure storage account, for example `https://myaccount.blob.core.windows.net/`
/// * `credential` - An optional implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating.
/// * `options` - Optional configuration for the client.
pub fn new(
endpoint: &str,
credential: Option<Arc<dyn TokenCredential>>,
options: Option<BlobServiceClientOptions>,
) -> Result<Self> {
let url = Url::parse(endpoint)?;
let client = GeneratedBlobServiceClient::from_url(url, credential, options)?;
Ok(Self { client })
}
/// Returns a new instance of BlobContainerClient.
///
/// # Arguments
///
/// * `container_name` - The name of the container.
pub fn blob_container_client(&self, container_name: &str) -> BlobContainerClient {
let mut container_url = self.url().clone();
container_url
.path_segments_mut()
// This should not fail as service URL has already been validated on client construction.
.expect("Cannot be a base URL.")
.push(container_name);
let client = GeneratedBlobContainerClient {
endpoint: container_url,
pipeline: self.client.pipeline.clone(),
version: self.client.version.clone(),
tracer: self.client.tracer.clone(),
};
BlobContainerClient { client }
}
/// Gets the URL of the resource this client is configured for.
pub fn url(&self) -> &Url {
&self.client.endpoint
}
/// Gets the properties of a Storage account's Blob service, including Azure Storage Analytics.
///
/// # Arguments
///
/// * `options` - Optional configuration for the request.
pub async fn get_properties(
&self,
options: Option<BlobServiceClientGetPropertiesOptions<'_>>,
) -> Result<Response<BlobServiceProperties, XmlFormat>> {
self.client.get_properties(options).await
}
/// Returns a list of the containers under the specified Storage account.
///
/// # Arguments
///
/// * `options` - Optional configuration for the request.
pub fn list_containers(
&self,
options: Option<BlobServiceClientListContainersSegmentOptions<'_>>,
) -> Result<Pager<ListContainersSegmentResponse, XmlFormat, String>> {
self.client.list_containers_segment(options)
}
/// Returns a list of blobs across all containers whose tags match a given search expression.
///
/// # Arguments
///
/// * `filter_expression` - The expression to find blobs whose tags matches the specified condition.
/// eg.
/// ```text
/// "\"yourtagname\"='firsttag' and \"yourtagname2\"='secondtag'"
/// ```
/// To specify a container, eg.
/// ```text
/// "@container='containerName' and \"Name\"='C'"
/// ```
/// See [`format_filter_expression()`](crate::format_filter_expression) for help with the expected String format.
/// * `options` - Optional parameters for the request.
pub async fn find_blobs_by_tags(
&self,
filter_expression: &str,
options: Option<BlobServiceClientFindBlobsByTagsOptions<'_>>,
) -> Result<Response<FilterBlobSegment, XmlFormat>> {
self.client
.find_blobs_by_tags(filter_expression, options)
.await
}
/// Sets properties for a Storage account's Blob service endpoint, including properties for Storage Analytics and CORS rules.
///
/// # Arguments
///
/// * `storage_service_properties` - The Storage service properties to set.
/// * `options` - Optional configuration for the request.
pub async fn set_properties(
&self,
storage_service_properties: RequestContent<BlobServiceProperties, XmlFormat>,
options: Option<BlobServiceClientSetPropertiesOptions<'_>>,
) -> Result<Response<(), NoFormat>> {
self.client
.set_properties(storage_service_properties, options)
.await
}
/// Gets information related to the Storage account.
/// This includes the `sku_name` and `account_kind`.
///
/// # Arguments
///
/// * `options` - Optional configuration for the request.
pub async fn get_account_info(
&self,
options: Option<BlobServiceClientGetAccountInfoOptions<'_>>,
) -> Result<Response<BlobServiceClientGetAccountInfoResult, NoFormat>> {
self.client.get_account_info(options).await
}
/// Retrieves statistics related to replication for the Blob service. It is only available on the secondary location endpoint
/// when read-access geo-redundant replication is enabled for the storage account.
///
/// # Arguments
///
/// * `options` - Optional configuration for the request.
pub async fn get_statistics(
&self,
options: Option<BlobServiceClientGetStatisticsOptions<'_>>,
) -> Result<Response<StorageServiceStats, XmlFormat>> {
self.client.get_statistics(options).await
}
}