Skip to content

Commit 7564641

Browse files
[Storage] stage_block, commit_block_list for BlobClient, get_container_properties for ContainerClient, ServiceClient (#2273)
1 parent ef27816 commit 7564641

File tree

18 files changed

+610
-109
lines changed

18 files changed

+610
-109
lines changed

.vscode/cspell.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"ignorePaths": [
66
"**/test-resources.bicep",
77
"**/test-resources.json",
8+
"**/assets.json",
89
".config",
910
".devcontainer/devcontainer.json",
1011
".devcontainer/Dockerfile",
@@ -193,4 +194,4 @@
193194
]
194195
}
195196
]
196-
}
197+
}

Cargo.lock

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,6 @@ path = "sdk/core/azure_core_test_macros"
7171
# azure_identity should only ever be in dev-dependencies herein
7272
path = "sdk/identity/azure_identity"
7373

74-
[workspace.dependencies.azure_storage_common]
75-
version = "0.1.0"
76-
path = "sdk/storage"
77-
7874
[workspace.dependencies]
7975
async-lock = "3.0"
8076
async-process = "2.0"

sdk/storage/.dict.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
AAABBBCCC
12
appendblock
23
appendpos
34
blockid

sdk/storage/assets.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"AssetsRepo": "Azure/azure-sdk-assets",
33
"AssetsRepoPrefixPath": "rust",
4-
"Tag": "rust/azure_storage_blob_d76e2bb82c",
4+
"Tag": "rust/azure_storage_blob_aae4c1fefc",
55
"TagPrefix": "rust/azure_storage_blob"
66
}

sdk/storage/azure_storage_blob/Cargo.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,19 @@ rust-version.workspace = true
1111

1212
[dependencies]
1313
async-trait.workspace = true
14-
azure_storage_common.workspace = true
1514
azure_core = { workspace = true, features = ["xml"] }
15+
azure_storage_common = { version = "0.1.0", path = ".." }
1616
serde.workspace = true
1717
time.workspace = true
1818
typespec_client_core = { workspace = true, features = ["derive"] }
19-
uuid.workspace = true
2019
url.workspace = true
20+
uuid.workspace = true
2121

2222
[lints]
2323
workspace = true
2424

2525
[dev-dependencies]
26-
tokio = { workspace = true, features = ["macros"] }
27-
azure_identity.workspace = true
2826
azure_core_test.workspace = true
27+
azure_identity.workspace = true
28+
azure_storage_blob_test.path = "../azure_storage_blob_test"
29+
tokio = { workspace = true, features = ["macros"] }

sdk/storage/azure_storage_blob/src/clients/blob_client.rs

Lines changed: 81 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@ use crate::{
55
clients::GeneratedBlobClient,
66
models::{
77
BlobBlobClientDownloadOptions, BlobBlobClientGetPropertiesOptions,
8-
BlobBlockBlobClientUploadOptions, BlobProperties,
8+
BlobBlockBlobClientCommitBlockListOptions, BlobBlockBlobClientStageBlockOptions,
9+
BlobBlockBlobClientUploadOptions, BlobProperties, BlockLookupList,
910
},
1011
pipeline::StorageHeadersPolicy,
1112
BlobClientOptions,
1213
};
1314
use azure_core::{
14-
credentials::TokenCredential, BearerTokenCredentialPolicy, Bytes, Policy, RequestContent,
15-
Response, Result, Url,
15+
base64, credentials::TokenCredential, BearerTokenCredentialPolicy, Bytes, Policy,
16+
RequestContent, Response, Result, Url,
1617
};
1718
use std::sync::Arc;
1819

20+
/// A client to interact with a specific Azure storage blob, although that blob may not yet exist.
1921
pub struct BlobClient {
2022
endpoint: Url,
2123
container_name: String,
@@ -24,6 +26,15 @@ pub struct BlobClient {
2426
}
2527

2628
impl BlobClient {
29+
/// Creates a new BlobClient, using Entra ID authentication.
30+
///
31+
/// # Arguments
32+
///
33+
/// * `endpoint` - The full URL of the Azure storage account, for example `https://myaccount.blob.core.windows.net/`
34+
/// * `container_name` - The name of the container containing this blob.
35+
/// * `blob_name` - The name of the blob to interact with.
36+
/// * `credential` - An implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating.
37+
/// * `options` - Optional configuration for the client.
2738
pub fn new(
2839
endpoint: &str,
2940
container_name: String,
@@ -57,18 +68,27 @@ impl BlobClient {
5768
})
5869
}
5970

71+
/// Gets the endpoint of the Storage account this client is connected to.
6072
pub fn endpoint(&self) -> &Url {
6173
&self.endpoint
6274
}
6375

76+
/// Gets the container name of the Storage account this client is connected to.
6477
pub fn container_name(&self) -> &str {
6578
&self.container_name
6679
}
6780

81+
/// Gets the blob name of the Storage account this client is connected to.
6882
pub fn blob_name(&self) -> &str {
6983
&self.blob_name
7084
}
7185

86+
/// Returns all user-defined metadata, standard HTTP properties, and system properties for the blob.
87+
/// The data returned does not include the content of the blob.
88+
///
89+
/// # Arguments
90+
///
91+
/// * `options` - Optional configuration for the request.
7292
pub async fn get_blob_properties(
7393
&self,
7494
options: Option<BlobBlobClientGetPropertiesOptions<'_>>,
@@ -83,6 +103,11 @@ impl BlobClient {
83103
Ok(blob_properties)
84104
}
85105

106+
/// Downloads a blob from the service, including its metadata and properties.
107+
///
108+
/// # Arguments
109+
///
110+
/// * `options` - Optional configuration for the request.
86111
pub async fn download_blob(
87112
&self,
88113
options: Option<BlobBlobClientDownloadOptions<'_>>,
@@ -95,7 +120,15 @@ impl BlobClient {
95120
Ok(response)
96121
}
97122

98-
// For now, this is single-shot, block blob hot path only.
123+
/// Creates a new blob from a data source.
124+
///
125+
/// # Arguments
126+
///
127+
/// * `data` - The blob data to upload.
128+
/// * `overwrite` - Whether the blob to be uploaded should overwrite the current data. If True, `upload_blob` will overwrite the existing data.
129+
/// If False, the operation will fail with ResourceExistsError.
130+
/// * `content_length` - Total length of the blob data to be uploaded.
131+
/// * `options` - Optional configuration for the request.
99132
pub async fn upload_blob(
100133
&self,
101134
data: RequestContent<Bytes>,
@@ -105,7 +138,6 @@ impl BlobClient {
105138
) -> Result<Response<()>> {
106139
let mut options = options.unwrap_or_default();
107140

108-
// Check if they want overwrite, by default overwrite=False
109141
if !overwrite {
110142
options.if_none_match = Some(String::from("*"));
111143
}
@@ -117,4 +149,48 @@ impl BlobClient {
117149
.await?;
118150
Ok(response)
119151
}
152+
153+
/// Creates a new block to be later committed as part of a blob.
154+
///
155+
/// # Arguments
156+
///
157+
/// * `block_id` - The unique identifier for the block. The identifier should be less than or equal to 64 bytes in size.
158+
/// For a given blob, the `block_id` must be the same size for each block.
159+
/// * `content_length` - Total length of the blob data to be staged.
160+
/// * `data` - The content of the blob.
161+
/// * `options` - Optional configuration for the request.
162+
pub async fn stage_block(
163+
&self,
164+
block_id: &str,
165+
content_length: i64,
166+
data: RequestContent<Bytes>,
167+
options: Option<BlobBlockBlobClientStageBlockOptions<'_>>,
168+
) -> Result<Response<()>> {
169+
let block_id = base64::encode(block_id);
170+
let response = self
171+
.client
172+
.get_blob_block_blob_client(self.container_name.clone(), self.blob_name.clone())
173+
.stage_block(&block_id, content_length, data, options)
174+
.await?;
175+
Ok(response)
176+
}
177+
178+
/// Writes to a blob based on blocks specified by the list of IDs and content that make up the blob.
179+
///
180+
/// # Arguments
181+
///
182+
/// * `blocks` - The list of Block Blobs to commit.
183+
/// * `options` - Optional configuration for the request.
184+
pub async fn commit_block_list(
185+
&self,
186+
blocks: RequestContent<BlockLookupList>,
187+
options: Option<BlobBlockBlobClientCommitBlockListOptions<'_>>,
188+
) -> Result<Response<()>> {
189+
let response = self
190+
.client
191+
.get_blob_block_blob_client(self.container_name.clone(), self.blob_name.clone())
192+
.commit_block_list(blocks, options)
193+
.await?;
194+
Ok(response)
195+
}
120196
}

sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,36 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4-
use crate::clients::GeneratedBlobClient;
5-
use crate::models::{BlobContainerClientCreateOptions, BlobContainerClientDeleteOptions};
6-
use crate::pipeline::StorageHeadersPolicy;
7-
use crate::BlobClientOptions;
4+
use crate::{
5+
clients::GeneratedBlobClient,
6+
models::{
7+
BlobContainerClientCreateOptions, BlobContainerClientDeleteOptions,
8+
BlobContainerClientGetPropertiesOptions, ContainerProperties,
9+
},
10+
pipeline::StorageHeadersPolicy,
11+
BlobClientOptions,
12+
};
813
use azure_core::{
914
credentials::TokenCredential, BearerTokenCredentialPolicy, Policy, Response, Result, Url,
1015
};
1116
use std::sync::Arc;
1217

18+
/// A client to interact with a specified Azure storage container.
1319
pub struct BlobContainerClient {
1420
endpoint: Url,
1521
container_name: String,
1622
client: GeneratedBlobClient,
1723
}
1824

1925
impl BlobContainerClient {
26+
/// Creates a new BlobContainerClient, using Entra ID authentication.
27+
///
28+
/// # Arguments
29+
///
30+
/// * `endpoint` - The full URL of the Azure storage account, for example `https://myaccount.blob.core.windows.net/`
31+
/// * `container_name` - The name of the container.
32+
/// * `credential` - An implementation of [`TokenCredential`] that can provide an Entra ID token to use when authenticating.
33+
/// * `options` - Optional configuration for the client.
2034
pub fn new(
2135
endpoint: &str,
2236
container_name: String,
@@ -49,14 +63,21 @@ impl BlobContainerClient {
4963
})
5064
}
5165

66+
/// Gets the endpoint of the Storage account this client is connected to.
5267
pub fn endpoint(&self) -> &Url {
5368
&self.endpoint
5469
}
5570

71+
/// Gets the container name of the Storage account this client is connected to.
5672
pub fn container_name(&self) -> &str {
5773
&self.container_name
5874
}
5975

76+
/// Creates a new container under the specified account. If the container with the same name already exists, the operation fails.
77+
///
78+
/// # Arguments
79+
///
80+
/// * `options` - Optional configuration for the request.
6081
pub async fn create_container(
6182
&self,
6283
options: Option<BlobContainerClientCreateOptions<'_>>,
@@ -69,6 +90,11 @@ impl BlobContainerClient {
6990
Ok(response)
7091
}
7192

93+
/// Marks the specified container for deletion. The container and any blobs contained within are later deleted during garbage collection.
94+
///
95+
/// # Arguments
96+
///
97+
/// * `options` - Optional configuration for the request.
7298
pub async fn delete_container(
7399
&self,
74100
options: Option<BlobContainerClientDeleteOptions<'_>>,
@@ -80,4 +106,24 @@ impl BlobContainerClient {
80106
.await?;
81107
Ok(response)
82108
}
109+
110+
/// Returns all user-defined metadata and system properties for the specified container.
111+
/// The data returned does not include the container's list of blobs.
112+
///
113+
/// # Arguments
114+
///
115+
/// * `options` - Optional configuration for the request.
116+
pub async fn get_container_properties(
117+
&self,
118+
options: Option<BlobContainerClientGetPropertiesOptions<'_>>,
119+
) -> Result<ContainerProperties> {
120+
let response = self
121+
.client
122+
.get_blob_container_client(self.container_name.clone())
123+
.get_properties(options)
124+
.await?;
125+
126+
let container_properties: ContainerProperties = response.headers().get()?;
127+
Ok(container_properties)
128+
}
83129
}

0 commit comments

Comments
 (0)