Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sdk/storage/.dict.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ testblob2
testblob3
testblob4
testcontainer
testid
uncommittedblobs
westus
yourtagname
2 changes: 1 addition & 1 deletion sdk/storage/azure_storage_blob/assets.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "rust",
"Tag": "rust/azure_storage_blob_094782fa40",
"Tag": "rust/azure_storage_blob_c8c2bbe44d",
"TagPrefix": "rust/azure_storage_blob"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,24 @@
// Licensed under the MIT License.

use crate::{
generated::clients::BlobContainerClient as GeneratedBlobContainerClient,
generated::models::{
BlobContainerClientAcquireLeaseResult, BlobContainerClientBreakLeaseResult,
BlobContainerClientChangeLeaseResult, BlobContainerClientGetAccountInfoResult,
BlobContainerClientGetPropertiesResult, BlobContainerClientReleaseLeaseResult,
BlobContainerClientRenewLeaseResult,
generated::{
clients::BlobContainerClient as GeneratedBlobContainerClient,
models::{
BlobContainerClientAcquireLeaseResult, BlobContainerClientBreakLeaseResult,
BlobContainerClientChangeLeaseResult, BlobContainerClientGetAccountInfoResult,
BlobContainerClientGetPropertiesResult, BlobContainerClientReleaseLeaseResult,
BlobContainerClientRenewLeaseResult, SignedIdentifier,
},
},
models::{
BlobContainerClientAcquireLeaseOptions, BlobContainerClientBreakLeaseOptions,
BlobContainerClientChangeLeaseOptions, BlobContainerClientCreateOptions,
BlobContainerClientDeleteOptions, BlobContainerClientFindBlobsByTagsOptions,
format_signed_identifiers, BlobContainerClientAcquireLeaseOptions,
BlobContainerClientBreakLeaseOptions, BlobContainerClientChangeLeaseOptions,
BlobContainerClientCreateOptions, BlobContainerClientDeleteOptions,
BlobContainerClientFindBlobsByTagsOptions, BlobContainerClientGetAccessPolicyOptions,
BlobContainerClientGetAccountInfoOptions, BlobContainerClientGetPropertiesOptions,
BlobContainerClientListBlobFlatSegmentOptions, BlobContainerClientReleaseLeaseOptions,
BlobContainerClientRenewLeaseOptions, BlobContainerClientSetMetadataOptions,
BlobContainerClientRenewLeaseOptions, BlobContainerClientSetAccessPolicyOptions,
BlobContainerClientSetAccessPolicyResult, BlobContainerClientSetMetadataOptions,
FilterBlobSegment, ListBlobsFlatSegmentResponse,
},
pipeline::StorageHeadersPolicy,
Expand All @@ -25,7 +29,7 @@ use azure_core::{
credentials::TokenCredential,
http::{
policies::{BearerTokenCredentialPolicy, Policy},
NoFormat, PageIterator, Pager, Response, Url, XmlFormat,
NoFormat, PageIterator, Pager, RequestContent, Response, Url, XmlFormat,
},
Result,
};
Expand Down Expand Up @@ -275,4 +279,34 @@ impl BlobContainerClient {
) -> Result<Response<BlobContainerClientGetAccountInfoResult, NoFormat>> {
self.client.get_account_info(options).await
}

/// Sets the permissions for the specified container. The permissions indicate whether blobs in a
/// container may be accessed publicly.
///
/// # Arguments
///
/// * `container_acl` - The access control list for the container.
/// * `options` - Optional configuration for the request.
pub async fn set_access_policy(
&self,
container_acl: Vec<SignedIdentifier>,
options: Option<BlobContainerClientSetAccessPolicyOptions<'_>>,
) -> Result<Response<BlobContainerClientSetAccessPolicyResult, NoFormat>> {
self.client
.set_access_policy(format_signed_identifiers(container_acl)?, options)
.await
}

/// Gets the permissions for the specified container. The permissions indicate whether container data
/// may be accessed publicly.
///
/// # Arguments
///
/// * `options` - Optional configuration for the request.
pub async fn get_access_policy(
&self,
options: Option<BlobContainerClientGetAccessPolicyOptions<'_>>,
) -> Result<Response<Vec<SignedIdentifier>, XmlFormat>> {
self.client.get_access_policy(options).await
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 22 additions & 1 deletion sdk/storage/azure_storage_blob/src/models/extensions.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

use azure_core::{
http::{RequestContent, XmlFormat},
xml::to_xml_with_root,
};
use serde::Serialize;

use crate::models::{
AppendBlobClientCreateOptions, BlobTag, BlobTags, BlockBlobClientUploadBlobFromUrlOptions,
BlockBlobClientUploadOptions, PageBlobClientCreateOptions,
BlockBlobClientUploadOptions, PageBlobClientCreateOptions, SignedIdentifier,
};
use azure_core::error::ErrorKind;
use std::collections::HashMap;
Expand Down Expand Up @@ -109,3 +115,18 @@ impl From<HashMap<String, String>> for BlobTags {
}
}
}

// SignedIdentifiers wrapper for correct XML serialization.
#[derive(Serialize)]
struct SignedIdentifiersWrapper {
#[serde(rename = "SignedIdentifier")]
items: Vec<SignedIdentifier>,
}

// Converts a `Vec<SignedIdentifier>` into `RequestContent<Vec<SignedIdentifier>, XmlFormat>`.
pub(crate) fn format_signed_identifiers(
value: Vec<SignedIdentifier>,
) -> Result<RequestContent<Vec<SignedIdentifier>, XmlFormat>, azure_core::Error> {
let wrapper = SignedIdentifiersWrapper { items: value };
Ok(to_xml_with_root("SignedIdentifiers", &wrapper)?.into())
}
21 changes: 11 additions & 10 deletions sdk/storage/azure_storage_blob/src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
mod extensions;

pub use crate::generated::models::{
AccessTier, AccountKind, AppendBlobClientAppendBlockFromUrlOptions,
AccessPolicy, AccessTier, AccountKind, AppendBlobClientAppendBlockFromUrlOptions,
AppendBlobClientAppendBlockFromUrlResult, AppendBlobClientAppendBlockFromUrlResultHeaders,
AppendBlobClientAppendBlockOptions, AppendBlobClientAppendBlockResult,
AppendBlobClientAppendBlockResultHeaders, AppendBlobClientCreateOptions,
Expand Down Expand Up @@ -36,15 +36,16 @@ pub use crate::generated::models::{
BlobContainerClientBreakLeaseResultHeaders, BlobContainerClientChangeLeaseOptions,
BlobContainerClientChangeLeaseResult, BlobContainerClientChangeLeaseResultHeaders,
BlobContainerClientCreateOptions, BlobContainerClientDeleteOptions,
BlobContainerClientFindBlobsByTagsOptions, BlobContainerClientGetAccountInfoOptions,
BlobContainerClientGetAccountInfoResult, BlobContainerClientGetAccountInfoResultHeaders,
BlobContainerClientGetPropertiesOptions, BlobContainerClientGetPropertiesResult,
BlobContainerClientGetPropertiesResultHeaders, BlobContainerClientListBlobFlatSegmentOptions,
BlobContainerClientReleaseLeaseOptions, BlobContainerClientReleaseLeaseResult,
BlobContainerClientReleaseLeaseResultHeaders, BlobContainerClientRenameResult,
BlobContainerClientRenameResultHeaders, BlobContainerClientRenewLeaseOptions,
BlobContainerClientRenewLeaseResult, BlobContainerClientRenewLeaseResultHeaders,
BlobContainerClientRestoreResult, BlobContainerClientRestoreResultHeaders,
BlobContainerClientFindBlobsByTagsOptions, BlobContainerClientGetAccessPolicyOptions,
BlobContainerClientGetAccountInfoOptions, BlobContainerClientGetAccountInfoResult,
BlobContainerClientGetAccountInfoResultHeaders, BlobContainerClientGetPropertiesOptions,
BlobContainerClientGetPropertiesResult, BlobContainerClientGetPropertiesResultHeaders,
BlobContainerClientListBlobFlatSegmentOptions, BlobContainerClientReleaseLeaseOptions,
BlobContainerClientReleaseLeaseResult, BlobContainerClientReleaseLeaseResultHeaders,
BlobContainerClientRenameResult, BlobContainerClientRenameResultHeaders,
BlobContainerClientRenewLeaseOptions, BlobContainerClientRenewLeaseResult,
BlobContainerClientRenewLeaseResultHeaders, BlobContainerClientRestoreResult,
BlobContainerClientRestoreResultHeaders, BlobContainerClientSetAccessPolicyOptions,
BlobContainerClientSetAccessPolicyResult, BlobContainerClientSetAccessPolicyResultHeaders,
BlobContainerClientSetMetadataOptions, BlobCopySourceTags, BlobDeleteType, BlobFlatListSegment,
BlobImmutabilityPolicyMode, BlobItemInternal, BlobMetadata, BlobName, BlobPropertiesInternal,
Expand Down
7 changes: 4 additions & 3 deletions sdk/storage/azure_storage_blob/src/parsers.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

use crate::models::{BlobTag, BlobTags};
use std::collections::HashMap;
use std::io::{Error, ErrorKind};
use std::{
collections::HashMap,
io::{Error, ErrorKind},
};

/// Takes in an offset and a length, verifies alignment to a 512-byte boundary, and
/// returns the HTTP range in String format.
Expand Down
99 changes: 37 additions & 62 deletions sdk/storage/azure_storage_blob/tests/blob_container_client.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

use azure_core::http::{RequestContent, StatusCode};
use azure_core_test::{recorded, Matcher, TestContext, TestMode};
use azure_storage_blob::format_filter_expression;
use azure_core::{
http::StatusCode,
time::{Duration, OffsetDateTime},
};
use azure_core_test::{recorded, TestContext};
use azure_storage_blob::models::{
AccountKind, BlobContainerClientAcquireLeaseResultHeaders,
AccessPolicy, AccountKind, BlobContainerClientAcquireLeaseResultHeaders,
BlobContainerClientChangeLeaseResultHeaders, BlobContainerClientGetAccountInfoResultHeaders,
BlobContainerClientGetPropertiesResultHeaders, BlobContainerClientListBlobFlatSegmentOptions,
BlobContainerClientSetMetadataOptions, BlobType, BlockBlobClientUploadOptions, LeaseState,
BlobContainerClientSetMetadataOptions, BlobType, LeaseState, SignedIdentifier,
};
use azure_storage_blob_test::{
create_test_blob, get_blob_name, get_blob_service_client, get_container_client,
get_container_name,
create_test_blob, get_blob_service_client, get_container_client, get_container_name,
};
use futures::{StreamExt, TryStreamExt};
use std::{collections::HashMap, error::Error, time::Duration};
use std::{collections::HashMap, error::Error};
use tokio::time;

#[recorded::test]
Expand Down Expand Up @@ -275,7 +276,7 @@ async fn test_container_lease_operations(ctx: TestContext) -> Result<(), Box<dyn
assert_eq!(proposed_lease_id.clone().to_string(), lease_id);

// Sleep until lease expires
time::sleep(Duration::from_secs(15)).await;
time::sleep(std::time::Duration::from_secs(15)).await;

// Renew Lease
container_client
Expand Down Expand Up @@ -327,64 +328,38 @@ async fn test_get_account_info(ctx: TestContext) -> Result<(), Box<dyn Error>> {
}

#[recorded::test]
async fn test_find_blobs_by_tags_container(ctx: TestContext) -> Result<(), Box<dyn Error>> {
async fn test_container_access_policy(ctx: TestContext) -> Result<(), Box<dyn Error>> {
// Recording Setup
let recording = ctx.recording();
recording.set_matcher(Matcher::HeaderlessMatcher).await?;
let container_client = get_container_client(recording, true).await?;

// Create Test Blobs with Tags
let blob1_name = get_blob_name(recording);
create_test_blob(
&container_client.blob_client(blob1_name.clone()),
Some(RequestContent::from("hello world".as_bytes().into())),
Some(
BlockBlobClientUploadOptions::default().with_tags(HashMap::from([
("foo".to_string(), "bar".to_string()),
("alice".to_string(), "bob".to_string()),
])),
),
)
.await?;
let blob2_name = get_blob_name(recording);
let blob2_tags = HashMap::from([("fizz".to_string(), "buzz".to_string())]);
create_test_blob(
&container_client.blob_client(blob2_name.clone()),
Some(RequestContent::from("ferris the crab".as_bytes().into())),
Some(BlockBlobClientUploadOptions::default().with_tags(blob2_tags.clone())),
)
.await?;
let container_client = get_container_client(recording, false).await?;
container_client.create_container(None).await?;

// Sleep in live mode to allow tags to be indexed on the service
if recording.test_mode() == TestMode::Live {
time::sleep(Duration::from_secs(5)).await;
}
// Set Access Policy w/ Policy Defined
let access_policy = AccessPolicy {
expiry: Some(OffsetDateTime::now_utc() + Duration::seconds(10)),
permission: Some("rw".to_string()),
start: Some(OffsetDateTime::now_utc()),
};
let signed_identifier = SignedIdentifier {
access_policy: Some(access_policy),
id: Some("testid".into()),
};

// Find "hello world" blob by its tag {"foo": "bar"}
let response = container_client
.find_blobs_by_tags("\"foo\"='bar'", None)
.await?;
let filter_blob_segment = response.into_body().await?;
let blobs = filter_blob_segment.blobs.unwrap();
assert!(
blobs
.iter()
.any(|blob| blob.name.as_ref().unwrap() == &blob1_name),
"Failed to find \"{blob1_name}\" in filtered blob results."
);

// Find "ferris the crab" blob by its tag {"fizz": "buzz"}
let response = container_client
.find_blobs_by_tags(&format_filter_expression(&blob2_tags)?, None)
container_client
.set_access_policy(vec![signed_identifier], None)
.await?;
let filter_blob_segment = response.into_body().await?;
let blobs = filter_blob_segment.blobs.unwrap();
assert!(
blobs
.iter()
.any(|blob| blob.name.as_ref().unwrap() == &blob2_name),
"Failed to find \"{blob2_name}\" in filtered blob results."
);

// Assert
let access_policy_response = container_client.get_access_policy(None).await?;
let signed_identifiers = access_policy_response.into_body().await?;
for signed_identifier in &signed_identifiers {
if let Some(access_policy) = &signed_identifier.access_policy {
assert!(signed_identifier.id.is_some());
assert!(access_policy.start.is_some());
assert!(access_policy.expiry.is_some());
assert_eq!("rw", access_policy.permission.as_ref().unwrap());
}
}

container_client.delete_container(None).await?;
Ok(())
Expand Down
4 changes: 2 additions & 2 deletions sdk/storage/azure_storage_blob/tsp-location.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
directory: specification/storage/Microsoft.BlobStorage
commit: 2e3571e7b2c729281b6819574cf358fd87ded3ab
commit: c3d773693455458c91efba4c2e72c3084458d8fe
repo: Azure/azure-rest-api-specs
additionalDirectories:
additionalDirectories:
Loading