diff --git a/Cargo.lock b/Cargo.lock index 49dc33a71d..98dd66447a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -518,9 +518,9 @@ dependencies = [ "futures", "serde", "serde_json", + "time", "tokio", "tracing", - "typespec_client_core", "url", "uuid", ] diff --git a/Cargo.toml b/Cargo.toml index 6a074b9af0..4deb686fff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -110,7 +110,6 @@ getrandom = { version = "0.3" } gloo-timers = { version = "0.3" } hmac = { version = "0.12" } include-file = { version = "0.5.1", default-features = false } -litemap = "0.7.4" openssl = { version = "0.10.72" } opentelemetry = { version = "0.30", features = ["trace"] } opentelemetry_sdk = "0.30" @@ -151,7 +150,6 @@ url = "2.2" uuid = { version = "1.18", features = ["v4"] } wasm-bindgen-futures = "0.4" wasm-bindgen-test = "0.3" -zerofrom = "0.1.5" zip = { version = "4.0.0", default-features = false, features = ["deflate"] } moka = { version = "0.12", features = ["future"] } diff --git a/sdk/storage/.dict.txt b/sdk/storage/.dict.txt index 7c5493ce8a..2b62121318 100644 --- a/sdk/storage/.dict.txt +++ b/sdk/storage/.dict.txt @@ -22,6 +22,7 @@ RAGRS restype ruleid secondtag +subsecond testblob1 testblob2 testblob3 diff --git a/sdk/storage/azure_storage_blob/CHANGELOG.md b/sdk/storage/azure_storage_blob/CHANGELOG.md index e261aac57c..8f6adf301d 100644 --- a/sdk/storage/azure_storage_blob/CHANGELOG.md +++ b/sdk/storage/azure_storage_blob/CHANGELOG.md @@ -4,6 +4,12 @@ ### Features Added +- Added support for `set_access_policy` to `BlobContainerClient`. +- Added support for `get_access_policy` to `BlobContainerClient`. + +### Breaking Changes + +- Changed conversion implementation from `BlobTags` to `HashMap` from `TryFrom` to `From`. - Added `continuation_token` to `PagerOptions` for methods that return a `Pager`. ### Breaking Changes diff --git a/sdk/storage/azure_storage_blob/Cargo.toml b/sdk/storage/azure_storage_blob/Cargo.toml index 0e0d67aa08..7c62935a12 100644 --- a/sdk/storage/azure_storage_blob/Cargo.toml +++ b/sdk/storage/azure_storage_blob/Cargo.toml @@ -21,7 +21,7 @@ async-trait.workspace = true azure_core = { workspace = true, features = ["xml"] } serde.workspace = true serde_json.workspace = true -typespec_client_core = { workspace = true, features = ["derive"] } +time.workspace = true url.workspace = true uuid.workspace = true diff --git a/sdk/storage/azure_storage_blob/assets.json b/sdk/storage/azure_storage_blob/assets.json index dae255a41b..d6fb63c173 100644 --- a/sdk/storage/azure_storage_blob/assets.json +++ b/sdk/storage/azure_storage_blob/assets.json @@ -1,6 +1,6 @@ { "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "rust", - "Tag": "rust/azure_storage_blob_1e5e3b2c6c", + "Tag": "rust/azure_storage_blob_e59ab40a70", "TagPrefix": "rust/azure_storage_blob" } diff --git a/sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs b/sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs index e8175de936..c6ab182ef2 100644 --- a/sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs +++ b/sdk/storage/azure_storage_blob/src/clients/blob_container_client.rs @@ -9,12 +9,13 @@ use crate::{ BlobContainerClientBreakLeaseOptions, BlobContainerClientBreakLeaseResult, BlobContainerClientChangeLeaseOptions, BlobContainerClientChangeLeaseResult, BlobContainerClientCreateOptions, BlobContainerClientDeleteOptions, - BlobContainerClientFindBlobsByTagsOptions, BlobContainerClientGetAccountInfoOptions, - BlobContainerClientGetAccountInfoResult, BlobContainerClientGetPropertiesOptions, - BlobContainerClientGetPropertiesResult, BlobContainerClientListBlobFlatSegmentOptions, - BlobContainerClientReleaseLeaseOptions, BlobContainerClientReleaseLeaseResult, - BlobContainerClientRenewLeaseOptions, BlobContainerClientRenewLeaseResult, - BlobContainerClientSetMetadataOptions, + BlobContainerClientFindBlobsByTagsOptions, BlobContainerClientGetAccessPolicyOptions, + BlobContainerClientGetAccountInfoOptions, BlobContainerClientGetAccountInfoResult, + BlobContainerClientGetPropertiesOptions, BlobContainerClientGetPropertiesResult, + BlobContainerClientListBlobFlatSegmentOptions, BlobContainerClientReleaseLeaseOptions, + BlobContainerClientReleaseLeaseResult, BlobContainerClientRenewLeaseOptions, + BlobContainerClientRenewLeaseResult, BlobContainerClientSetAccessPolicyOptions, + BlobContainerClientSetMetadataOptions, SignedIdentifiers, }, models::{FilterBlobSegment, ListBlobsFlatSegmentResponse, StorageErrorCode}, pipeline::StorageHeadersPolicy, @@ -25,7 +26,7 @@ use azure_core::{ error::ErrorKind, http::{ policies::{BearerTokenAuthorizationPolicy, Policy}, - NoFormat, Pager, Pipeline, Response, StatusCode, Url, XmlFormat, + NoFormat, Pager, Pipeline, RequestContent, Response, StatusCode, Url, XmlFormat, }, tracing, Result, }; @@ -365,4 +366,51 @@ impl BlobContainerClient { Err(e) => Err(e), } } + + /// 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. You can create this from a + /// [`HashMap`] using [`SignedIdentifiers::from()`] and then wrapping it into a RequestContent. + /// * `options` - Optional configuration for the request. + /// + /// # Example + /// + /// ```rust, ignore + /// use azure_core::http::RequestContent; + /// use azure_storage_blob::models::{AccessPolicy, SignedIdentifiers}; + /// use typespec_client_core::time::OffsetDateTime; + /// + /// let mut policies = HashMap::new(); + /// policies.insert("some_policy_id".to_string(), AccessPolicy { + /// start: Some(OffsetDateTime::now_utc()), + /// expiry: Some(OffsetDateTime::now_utc() + Duration::from_secs(10)), + /// permission: Some("rwd".to_string()), + /// }); + /// + /// let request_content = RequestContent::try_from(SignedIdentifiers::from(policies))?; + /// container_client.set_access_policy(request_content, None).await?; + /// ``` + pub async fn set_access_policy( + &self, + container_acl: RequestContent, + options: Option>, + ) -> Result> { + self.client.set_access_policy(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>, + ) -> Result> { + self.client.get_access_policy(options).await + } } diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/blob_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/blob_client.rs index b6156ea10e..c91c306f58 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/blob_client.rs @@ -15,10 +15,10 @@ use crate::generated::models::{ BlobClientReleaseLeaseOptions, BlobClientReleaseLeaseResult, BlobClientRenewLeaseOptions, BlobClientRenewLeaseResult, BlobClientSetExpiryOptions, BlobClientSetExpiryResult, BlobClientSetImmutabilityPolicyOptions, BlobClientSetImmutabilityPolicyResult, - BlobClientSetLegalHoldOptions, BlobClientSetLegalHoldResult, BlobClientSetMetadataOptions, - BlobClientSetPropertiesOptions, BlobClientSetTagsOptions, BlobClientSetTierOptions, - BlobClientStartCopyFromUrlOptions, BlobClientStartCopyFromUrlResult, BlobClientUndeleteOptions, - BlobClientUndeleteResult, BlobExpiryOptions, BlobTags, + BlobClientSetLegalHoldOptions, BlobClientSetMetadataOptions, BlobClientSetPropertiesOptions, + BlobClientSetTagsOptions, BlobClientSetTierOptions, BlobClientStartCopyFromUrlOptions, + BlobClientStartCopyFromUrlResult, BlobClientUndeleteOptions, BlobClientUndeleteResult, + BlobExpiryOptions, BlobTags, }; use azure_core::{ base64::encode, @@ -1645,39 +1645,12 @@ impl BlobClient { /// /// * `legal_hold` - Required. Specifies the legal hold status to set on the blob. /// * `options` - Optional parameters for the request. - /// - /// ## Response Headers - /// - /// The returned [`Response`](azure_core::http::Response) implements the [`BlobClientSetLegalHoldResultHeaders`] trait, which provides - /// access to response headers. For example: - /// - /// ```no_run - /// use azure_core::{Result, http::{Response, NoFormat}}; - /// use azure_storage_blob::models::{BlobClientSetLegalHoldResult, BlobClientSetLegalHoldResultHeaders}; - /// async fn example() -> Result<()> { - /// let response: Response = unimplemented!(); - /// // Access response headers - /// if let Some(date) = response.date()? { - /// println!("Date: {:?}", date); - /// } - /// if let Some(legal_hold) = response.legal_hold()? { - /// println!("x-ms-legal-hold: {:?}", legal_hold); - /// } - /// Ok(()) - /// } - /// ``` - /// - /// ### Available headers - /// * [`date`()](crate::generated::models::BlobClientSetLegalHoldResultHeaders::date) - Date - /// * [`legal_hold`()](crate::generated::models::BlobClientSetLegalHoldResultHeaders::legal_hold) - x-ms-legal-hold - /// - /// [`BlobClientSetLegalHoldResultHeaders`]: crate::generated::models::BlobClientSetLegalHoldResultHeaders #[tracing::function("Storage.Blob.Blob.setLegalHold")] pub async fn set_legal_hold( &self, legal_hold: bool, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); diff --git a/sdk/storage/azure_storage_blob/src/generated/clients/blob_container_client.rs b/sdk/storage/azure_storage_blob/src/generated/clients/blob_container_client.rs index bebffe5c2f..d59e9b053f 100644 --- a/sdk/storage/azure_storage_blob/src/generated/clients/blob_container_client.rs +++ b/sdk/storage/azure_storage_blob/src/generated/clients/blob_container_client.rs @@ -17,9 +17,8 @@ use crate::generated::models::{ BlobContainerClientRenameResult, BlobContainerClientRenewLeaseOptions, BlobContainerClientRenewLeaseResult, BlobContainerClientRestoreOptions, BlobContainerClientRestoreResult, BlobContainerClientSetAccessPolicyOptions, - BlobContainerClientSetAccessPolicyResult, BlobContainerClientSetMetadataOptions, - FilterBlobSegment, ListBlobsFlatSegmentResponse, ListBlobsHierarchySegmentResponse, - SignedIdentifier, + BlobContainerClientSetMetadataOptions, FilterBlobSegment, ListBlobsFlatSegmentResponse, + ListBlobsHierarchySegmentResponse, SignedIdentifiers, }; use azure_core::{ credentials::TokenCredential, @@ -522,40 +521,39 @@ impl BlobContainerClient { /// /// ## Response Headers /// - /// The returned [`Response`](azure_core::http::Response) implements the [`VecSignedIdentifierHeaders`] trait, which provides + /// The returned [`Response`](azure_core::http::Response) implements the [`SignedIdentifiersHeaders`] trait, which provides /// access to response headers. For example: /// /// ```no_run /// use azure_core::{Result, http::{Response, XmlFormat}}; - /// use azure_storage_blob::models::{SignedIdentifier, VecSignedIdentifierHeaders}; + /// use azure_storage_blob::models::{SignedIdentifiers, SignedIdentifiersHeaders}; /// async fn example() -> Result<()> { - /// let response: Response, XmlFormat> = unimplemented!(); + /// let response: Response = unimplemented!(); /// // Access response headers - /// if let Some(date) = response.date()? { - /// println!("Date: {:?}", date); - /// } /// if let Some(last_modified) = response.last_modified()? { /// println!("Last-Modified: {:?}", last_modified); /// } /// if let Some(etag) = response.etag()? { /// println!("etag: {:?}", etag); /// } + /// if let Some(access) = response.access()? { + /// println!("x-ms-blob-public-access: {:?}", access); + /// } /// Ok(()) /// } /// ``` /// /// ### Available headers - /// * [`date`()](crate::generated::models::VecSignedIdentifierHeaders::date) - Date - /// * [`last_modified`()](crate::generated::models::VecSignedIdentifierHeaders::last_modified) - Last-Modified - /// * [`etag`()](crate::generated::models::VecSignedIdentifierHeaders::etag) - etag - /// * [`access`()](crate::generated::models::VecSignedIdentifierHeaders::access) - x-ms-blob-public-access + /// * [`last_modified`()](crate::generated::models::SignedIdentifiersHeaders::last_modified) - Last-Modified + /// * [`etag`()](crate::generated::models::SignedIdentifiersHeaders::etag) - etag + /// * [`access`()](crate::generated::models::SignedIdentifiersHeaders::access) - x-ms-blob-public-access /// - /// [`VecSignedIdentifierHeaders`]: crate::generated::models::VecSignedIdentifierHeaders + /// [`SignedIdentifiersHeaders`]: crate::generated::models::SignedIdentifiersHeaders #[tracing::function("Storage.Blob.Container.getAccessPolicy")] pub async fn get_access_policy( &self, options: Option>, - ) -> Result, XmlFormat>> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); @@ -1285,43 +1283,12 @@ impl BlobContainerClient { /// /// * `container_acl` - The access control list for the container. /// * `options` - Optional parameters for the request. - /// - /// ## Response Headers - /// - /// The returned [`Response`](azure_core::http::Response) implements the [`BlobContainerClientSetAccessPolicyResultHeaders`] trait, which provides - /// access to response headers. For example: - /// - /// ```no_run - /// use azure_core::{Result, http::{Response, NoFormat}}; - /// use azure_storage_blob::models::{BlobContainerClientSetAccessPolicyResult, BlobContainerClientSetAccessPolicyResultHeaders}; - /// async fn example() -> Result<()> { - /// let response: Response = unimplemented!(); - /// // Access response headers - /// if let Some(date) = response.date()? { - /// println!("Date: {:?}", date); - /// } - /// if let Some(last_modified) = response.last_modified()? { - /// println!("Last-Modified: {:?}", last_modified); - /// } - /// if let Some(etag) = response.etag()? { - /// println!("etag: {:?}", etag); - /// } - /// Ok(()) - /// } - /// ``` - /// - /// ### Available headers - /// * [`date`()](crate::generated::models::BlobContainerClientSetAccessPolicyResultHeaders::date) - Date - /// * [`last_modified`()](crate::generated::models::BlobContainerClientSetAccessPolicyResultHeaders::last_modified) - Last-Modified - /// * [`etag`()](crate::generated::models::BlobContainerClientSetAccessPolicyResultHeaders::etag) - etag - /// - /// [`BlobContainerClientSetAccessPolicyResultHeaders`]: crate::generated::models::BlobContainerClientSetAccessPolicyResultHeaders #[tracing::function("Storage.Blob.Container.setAccessPolicy")] pub async fn set_access_policy( &self, - container_acl: RequestContent, XmlFormat>, + container_acl: RequestContent, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); diff --git a/sdk/storage/azure_storage_blob/src/generated/models/header_traits.rs b/sdk/storage/azure_storage_blob/src/generated/models/header_traits.rs index 1f97273c52..4236dd618d 100644 --- a/sdk/storage/azure_storage_blob/src/generated/models/header_traits.rs +++ b/sdk/storage/azure_storage_blob/src/generated/models/header_traits.rs @@ -11,13 +11,13 @@ use super::{ BlobClientDeleteImmutabilityPolicyResult, BlobClientDownloadResult, BlobClientGetAccountInfoResult, BlobClientGetPropertiesResult, BlobClientReleaseLeaseResult, BlobClientRenewLeaseResult, BlobClientSetExpiryResult, BlobClientSetImmutabilityPolicyResult, - BlobClientSetLegalHoldResult, BlobClientStartCopyFromUrlResult, BlobClientUndeleteResult, + BlobClientStartCopyFromUrlResult, BlobClientUndeleteResult, BlobContainerClientAcquireLeaseResult, BlobContainerClientBreakLeaseResult, BlobContainerClientChangeLeaseResult, BlobContainerClientGetAccountInfoResult, BlobContainerClientGetPropertiesResult, BlobContainerClientReleaseLeaseResult, BlobContainerClientRenameResult, BlobContainerClientRenewLeaseResult, - BlobContainerClientRestoreResult, BlobContainerClientSetAccessPolicyResult, - BlobImmutabilityPolicyMode, BlobServiceClientGetAccountInfoResult, BlobTags, BlobType, + BlobContainerClientRestoreResult, BlobImmutabilityPolicyMode, + BlobServiceClientGetAccountInfoResult, BlobTags, BlobType, BlockBlobClientCommitBlockListResult, BlockBlobClientQueryResult, BlockBlobClientStageBlockFromUrlResult, BlockBlobClientStageBlockResult, BlockBlobClientUploadBlobFromUrlResult, BlockBlobClientUploadResult, BlockList, CopyStatus, @@ -26,7 +26,7 @@ use super::{ PageBlobClientCopyIncrementalResult, PageBlobClientCreateResult, PageBlobClientResizeResult, PageBlobClientSetSequenceNumberResult, PageBlobClientUploadPagesFromUrlResult, PageBlobClientUploadPagesResult, PageList, PublicAccessType, RehydratePriority, - SignedIdentifier, SkuName, StorageServiceStats, UserDelegationKey, + SignedIdentifiers, SkuName, StorageServiceStats, UserDelegationKey, }; use azure_core::{ base64::decode, @@ -1646,42 +1646,6 @@ impl BlobClientSetImmutabilityPolicyResultHeaders } } -/// Provides access to typed response headers for `BlobClient::set_legal_hold()` -/// -/// # Examples -/// -/// ```no_run -/// use azure_core::{Result, http::{Response, NoFormat}}; -/// use azure_storage_blob::models::{BlobClientSetLegalHoldResult, BlobClientSetLegalHoldResultHeaders}; -/// async fn example() -> Result<()> { -/// let response: Response = unimplemented!(); -/// // Access response headers -/// if let Some(date) = response.date()? { -/// println!("Date: {:?}", date); -/// } -/// if let Some(legal_hold) = response.legal_hold()? { -/// println!("x-ms-legal-hold: {:?}", legal_hold); -/// } -/// Ok(()) -/// } -/// ``` -pub trait BlobClientSetLegalHoldResultHeaders: private::Sealed { - fn date(&self) -> Result>; - fn legal_hold(&self) -> Result>; -} - -impl BlobClientSetLegalHoldResultHeaders for Response { - /// UTC date/time value generated by the service that indicates the time at which the response was initiated - fn date(&self) -> Result> { - Headers::get_optional_with(self.headers(), &DATE, |h| parse_rfc7231(h.as_str())) - } - - /// Specifies the legal hold status to set on the blob. - fn legal_hold(&self) -> Result> { - Headers::get_optional_as(self.headers(), &LEGAL_HOLD) - } -} - /// Provides access to typed response headers for `BlobClient::start_copy_from_url()` /// /// # Examples @@ -2237,55 +2201,6 @@ impl BlobContainerClientRestoreResultHeaders } } -/// Provides access to typed response headers for `BlobContainerClient::set_access_policy()` -/// -/// # Examples -/// -/// ```no_run -/// use azure_core::{Result, http::{Response, NoFormat}}; -/// use azure_storage_blob::models::{BlobContainerClientSetAccessPolicyResult, BlobContainerClientSetAccessPolicyResultHeaders}; -/// async fn example() -> Result<()> { -/// let response: Response = unimplemented!(); -/// // Access response headers -/// if let Some(date) = response.date()? { -/// println!("Date: {:?}", date); -/// } -/// if let Some(last_modified) = response.last_modified()? { -/// println!("Last-Modified: {:?}", last_modified); -/// } -/// if let Some(etag) = response.etag()? { -/// println!("etag: {:?}", etag); -/// } -/// Ok(()) -/// } -/// ``` -pub trait BlobContainerClientSetAccessPolicyResultHeaders: private::Sealed { - fn date(&self) -> Result>; - fn last_modified(&self) -> Result>; - fn etag(&self) -> Result>; -} - -impl BlobContainerClientSetAccessPolicyResultHeaders - for Response -{ - /// UTC date/time value generated by the service that indicates the time at which the response was initiated - fn date(&self) -> Result> { - Headers::get_optional_with(self.headers(), &DATE, |h| parse_rfc7231(h.as_str())) - } - - /// The date/time that the container was last modified. - fn last_modified(&self) -> Result> { - Headers::get_optional_with(self.headers(), &LAST_MODIFIED, |h| { - parse_rfc7231(h.as_str()) - }) - } - - /// The ETag contains a value that you can use to perform operations conditionally. - fn etag(&self) -> Result> { - Headers::get_optional_as(self.headers(), &ETAG) - } -} - /// Provides access to typed response headers for `BlobServiceClient::get_account_info()` /// /// # Examples @@ -3583,42 +3498,62 @@ impl PageListHeaders for Response { } } -/// Provides access to typed response headers for `BlobServiceClient::get_statistics()` +/// Provides access to typed response headers for `BlobContainerClient::get_access_policy()` /// /// # Examples /// /// ```no_run /// use azure_core::{Result, http::{Response, XmlFormat}}; -/// use azure_storage_blob::models::{StorageServiceStats, StorageServiceStatsHeaders}; +/// use azure_storage_blob::models::{SignedIdentifiers, SignedIdentifiersHeaders}; /// async fn example() -> Result<()> { -/// let response: Response = unimplemented!(); +/// let response: Response = unimplemented!(); /// // Access response headers -/// if let Some(date) = response.date()? { -/// println!("Date: {:?}", date); +/// if let Some(last_modified) = response.last_modified()? { +/// println!("Last-Modified: {:?}", last_modified); +/// } +/// if let Some(etag) = response.etag()? { +/// println!("etag: {:?}", etag); +/// } +/// if let Some(access) = response.access()? { +/// println!("x-ms-blob-public-access: {:?}", access); /// } /// Ok(()) /// } /// ``` -pub trait StorageServiceStatsHeaders: private::Sealed { - fn date(&self) -> Result>; +pub trait SignedIdentifiersHeaders: private::Sealed { + fn last_modified(&self) -> Result>; + fn etag(&self) -> Result>; + fn access(&self) -> Result>; } -impl StorageServiceStatsHeaders for Response { - /// UTC date/time value generated by the service that indicates the time at which the response was initiated - fn date(&self) -> Result> { - Headers::get_optional_with(self.headers(), &DATE, |h| parse_rfc7231(h.as_str())) +impl SignedIdentifiersHeaders for Response { + /// The date/time that the container was last modified. + fn last_modified(&self) -> Result> { + Headers::get_optional_with(self.headers(), &LAST_MODIFIED, |h| { + parse_rfc7231(h.as_str()) + }) + } + + /// The ETag contains a value that you can use to perform operations conditionally. + fn etag(&self) -> Result> { + Headers::get_optional_as(self.headers(), &ETAG) + } + + /// The public access setting for the container. + fn access(&self) -> Result> { + Headers::get_optional_as(self.headers(), &BLOB_PUBLIC_ACCESS) } } -/// Provides access to typed response headers for `BlobServiceClient::get_user_delegation_key()` +/// Provides access to typed response headers for `BlobServiceClient::get_statistics()` /// /// # Examples /// /// ```no_run /// use azure_core::{Result, http::{Response, XmlFormat}}; -/// use azure_storage_blob::models::{UserDelegationKey, UserDelegationKeyHeaders}; +/// use azure_storage_blob::models::{StorageServiceStats, StorageServiceStatsHeaders}; /// async fn example() -> Result<()> { -/// let response: Response = unimplemented!(); +/// let response: Response = unimplemented!(); /// // Access response headers /// if let Some(date) = response.date()? { /// println!("Date: {:?}", date); @@ -3626,68 +3561,42 @@ impl StorageServiceStatsHeaders for Response { /// Ok(()) /// } /// ``` -pub trait UserDelegationKeyHeaders: private::Sealed { +pub trait StorageServiceStatsHeaders: private::Sealed { fn date(&self) -> Result>; } -impl UserDelegationKeyHeaders for Response { +impl StorageServiceStatsHeaders for Response { /// UTC date/time value generated by the service that indicates the time at which the response was initiated fn date(&self) -> Result> { Headers::get_optional_with(self.headers(), &DATE, |h| parse_rfc7231(h.as_str())) } } -/// Provides access to typed response headers for `BlobContainerClient::get_access_policy()` +/// Provides access to typed response headers for `BlobServiceClient::get_user_delegation_key()` /// /// # Examples /// /// ```no_run /// use azure_core::{Result, http::{Response, XmlFormat}}; -/// use azure_storage_blob::models::{SignedIdentifier, VecSignedIdentifierHeaders}; +/// use azure_storage_blob::models::{UserDelegationKey, UserDelegationKeyHeaders}; /// async fn example() -> Result<()> { -/// let response: Response, XmlFormat> = unimplemented!(); +/// let response: Response = unimplemented!(); /// // Access response headers /// if let Some(date) = response.date()? { /// println!("Date: {:?}", date); /// } -/// if let Some(last_modified) = response.last_modified()? { -/// println!("Last-Modified: {:?}", last_modified); -/// } -/// if let Some(etag) = response.etag()? { -/// println!("etag: {:?}", etag); -/// } /// Ok(()) /// } /// ``` -pub trait VecSignedIdentifierHeaders: private::Sealed { +pub trait UserDelegationKeyHeaders: private::Sealed { fn date(&self) -> Result>; - fn last_modified(&self) -> Result>; - fn etag(&self) -> Result>; - fn access(&self) -> Result>; } -impl VecSignedIdentifierHeaders for Response, XmlFormat> { +impl UserDelegationKeyHeaders for Response { /// UTC date/time value generated by the service that indicates the time at which the response was initiated fn date(&self) -> Result> { Headers::get_optional_with(self.headers(), &DATE, |h| parse_rfc7231(h.as_str())) } - - /// The date/time that the container was last modified. - fn last_modified(&self) -> Result> { - Headers::get_optional_with(self.headers(), &LAST_MODIFIED, |h| { - parse_rfc7231(h.as_str()) - }) - } - - /// The ETag contains a value that you can use to perform operations conditionally. - fn etag(&self) -> Result> { - Headers::get_optional_as(self.headers(), &ETAG) - } - - /// The public access setting for the container. - fn access(&self) -> Result> { - Headers::get_optional_as(self.headers(), &BLOB_PUBLIC_ACCESS) - } } mod private { @@ -3699,13 +3608,12 @@ mod private { BlobClientDeleteImmutabilityPolicyResult, BlobClientDownloadResult, BlobClientGetAccountInfoResult, BlobClientGetPropertiesResult, BlobClientReleaseLeaseResult, BlobClientRenewLeaseResult, BlobClientSetExpiryResult, - BlobClientSetImmutabilityPolicyResult, BlobClientSetLegalHoldResult, - BlobClientStartCopyFromUrlResult, BlobClientUndeleteResult, - BlobContainerClientAcquireLeaseResult, BlobContainerClientBreakLeaseResult, - BlobContainerClientChangeLeaseResult, BlobContainerClientGetAccountInfoResult, - BlobContainerClientGetPropertiesResult, BlobContainerClientReleaseLeaseResult, - BlobContainerClientRenameResult, BlobContainerClientRenewLeaseResult, - BlobContainerClientRestoreResult, BlobContainerClientSetAccessPolicyResult, + BlobClientSetImmutabilityPolicyResult, BlobClientStartCopyFromUrlResult, + BlobClientUndeleteResult, BlobContainerClientAcquireLeaseResult, + BlobContainerClientBreakLeaseResult, BlobContainerClientChangeLeaseResult, + BlobContainerClientGetAccountInfoResult, BlobContainerClientGetPropertiesResult, + BlobContainerClientReleaseLeaseResult, BlobContainerClientRenameResult, + BlobContainerClientRenewLeaseResult, BlobContainerClientRestoreResult, BlobServiceClientGetAccountInfoResult, BlobTags, BlockBlobClientCommitBlockListResult, BlockBlobClientQueryResult, BlockBlobClientStageBlockFromUrlResult, BlockBlobClientStageBlockResult, BlockBlobClientUploadBlobFromUrlResult, @@ -3714,7 +3622,7 @@ mod private { PageBlobClientCopyIncrementalResult, PageBlobClientCreateResult, PageBlobClientResizeResult, PageBlobClientSetSequenceNumberResult, PageBlobClientUploadPagesFromUrlResult, PageBlobClientUploadPagesResult, PageList, - SignedIdentifier, StorageServiceStats, UserDelegationKey, + SignedIdentifiers, StorageServiceStats, UserDelegationKey, }; use azure_core::http::{AsyncResponse, NoFormat, Response, XmlFormat}; @@ -3739,7 +3647,6 @@ mod private { impl Sealed for Response {} impl Sealed for Response {} impl Sealed for Response {} - impl Sealed for Response {} impl Sealed for Response {} impl Sealed for Response {} impl Sealed for Response {} @@ -3751,7 +3658,6 @@ mod private { impl Sealed for Response {} impl Sealed for Response {} impl Sealed for Response {} - impl Sealed for Response {} impl Sealed for Response {} impl Sealed for Response {} impl Sealed for Response {} @@ -3770,7 +3676,7 @@ mod private { impl Sealed for Response {} impl Sealed for Response {} impl Sealed for Response {} + impl Sealed for Response {} impl Sealed for Response {} impl Sealed for Response {} - impl Sealed for Response, XmlFormat> {} } diff --git a/sdk/storage/azure_storage_blob/src/generated/models/models_impl.rs b/sdk/storage/azure_storage_blob/src/generated/models/models_impl.rs index 41d2372850..0888b6df09 100644 --- a/sdk/storage/azure_storage_blob/src/generated/models/models_impl.rs +++ b/sdk/storage/azure_storage_blob/src/generated/models/models_impl.rs @@ -6,7 +6,7 @@ use super::{ BlobItemInternal, BlobServiceProperties, BlobTags, BlockLookupList, ContainerItem, KeyInfo, ListBlobsFlatSegmentResponse, ListBlobsHierarchySegmentResponse, ListContainersSegmentResponse, - QueryRequest, + QueryRequest, SignedIdentifiers, }; use async_trait::async_trait; use azure_core::{ @@ -79,3 +79,10 @@ impl TryFrom for RequestContent { Ok(to_xml(&value)?.into()) } } + +impl TryFrom for RequestContent { + type Error = azure_core::Error; + fn try_from(value: SignedIdentifiers) -> Result { + Ok(to_xml(&value)?.into()) + } +} diff --git a/sdk/storage/azure_storage_blob/src/generated/models/models_serde.rs b/sdk/storage/azure_storage_blob/src/generated/models/models_serde.rs index 537e58d75c..953f32131e 100644 --- a/sdk/storage/azure_storage_blob/src/generated/models/models_serde.rs +++ b/sdk/storage/azure_storage_blob/src/generated/models/models_serde.rs @@ -176,6 +176,54 @@ impl Serialize for ParquetConfiguration { } } +pub mod option_offset_date_time_rfc3339_fixed_width { + #![allow(clippy::type_complexity)] + use azure_core::time::{parse_rfc3339, OffsetDateTime}; + use serde::{Deserialize, Deserializer, Serialize, Serializer}; + use std::{num::NonZero, result::Result}; + use time::format_description::well_known::{iso8601, Iso8601}; + + pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let to_deserialize = >::deserialize(deserializer)?; + match to_deserialize { + Some(to_deserialize) => { + let decoded0 = parse_rfc3339(&to_deserialize).map_err(serde::de::Error::custom)?; + Ok(Some(decoded0)) + } + None => Ok(None), + } + } + + pub fn serialize( + to_serialize: &Option, + serializer: S, + ) -> Result + where + S: Serializer, + { + let format = Iso8601::< + { + iso8601::Config::DEFAULT + .set_time_precision(iso8601::TimePrecision::Second { + decimal_digits: NonZero::new(7), + }) + .encode() + }, + >; + if let Some(to_serialize) = to_serialize { + let encoded0 = to_serialize + .format(&format) + .map_err(serde::ser::Error::custom)?; + >::serialize(&Some(encoded0), serializer) + } else { + serializer.serialize_none() + } + } +} + pub mod option_vec_encoded_bytes_std { #![allow(clippy::type_complexity)] use azure_core::base64::{decode, encode}; diff --git a/sdk/storage/azure_storage_blob/src/generated/models/pub_models.rs b/sdk/storage/azure_storage_blob/src/generated/models/pub_models.rs index 98b7338004..4c509d07fa 100644 --- a/sdk/storage/azure_storage_blob/src/generated/models/pub_models.rs +++ b/sdk/storage/azure_storage_blob/src/generated/models/pub_models.rs @@ -30,7 +30,7 @@ pub struct AccessPolicy { default, rename = "Expiry", skip_serializing_if = "Option::is_none", - with = "azure_core::time::rfc7231::option" + with = "models_serde::option_offset_date_time_rfc3339_fixed_width" )] pub expiry: Option, @@ -43,7 +43,7 @@ pub struct AccessPolicy { default, rename = "Start", skip_serializing_if = "Option::is_none", - with = "azure_core::time::rfc7231::option" + with = "models_serde::option_offset_date_time_rfc3339_fixed_width" )] pub start: Option, } @@ -155,10 +155,6 @@ pub struct BlobClientSetExpiryResult; #[derive(SafeDebug)] pub struct BlobClientSetImmutabilityPolicyResult; -/// Contains results for `BlobClient::set_legal_hold()` -#[derive(SafeDebug)] -pub struct BlobClientSetLegalHoldResult; - /// Contains results for `BlobClient::start_copy_from_url()` #[derive(SafeDebug)] pub struct BlobClientStartCopyFromUrlResult; @@ -203,10 +199,6 @@ pub struct BlobContainerClientRenewLeaseResult; #[derive(SafeDebug)] pub struct BlobContainerClientRestoreResult; -/// Contains results for `BlobContainerClient::set_access_policy()` -#[derive(SafeDebug)] -pub struct BlobContainerClientSetAccessPolicyResult; - /// The blob flat list segment. #[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] #[non_exhaustive] @@ -1302,6 +1294,14 @@ pub struct SignedIdentifier { pub id: Option, } +/// Represents an array of signed identifiers +#[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] +pub struct SignedIdentifiers { + /// The array of signed identifiers. + #[serde(rename = "SignedIdentifier", skip_serializing_if = "Option::is_none")] + pub items: Option>, +} + /// The properties that enable an account to host a static website #[derive(Clone, Default, Deserialize, SafeDebug, Serialize)] pub struct StaticWebsite { diff --git a/sdk/storage/azure_storage_blob/src/models/extensions.rs b/sdk/storage/azure_storage_blob/src/models/extensions.rs index 6a3a0683db..7e0833226b 100644 --- a/sdk/storage/azure_storage_blob/src/models/extensions.rs +++ b/sdk/storage/azure_storage_blob/src/models/extensions.rs @@ -2,8 +2,9 @@ // Licensed under the MIT License. use crate::models::{ - AppendBlobClientCreateOptions, BlobTag, BlobTags, BlockBlobClientUploadBlobFromUrlOptions, - BlockBlobClientUploadOptions, PageBlobClientCreateOptions, + AccessPolicy, AppendBlobClientCreateOptions, BlobTag, BlobTags, + BlockBlobClientUploadBlobFromUrlOptions, BlockBlobClientUploadOptions, + PageBlobClientCreateOptions, SignedIdentifier, SignedIdentifiers, }; use std::collections::HashMap; @@ -67,29 +68,18 @@ impl BlockBlobClientUploadOptions<'_> { } /// Converts a `BlobTags` struct into `HashMap`. -impl TryFrom for HashMap { - type Error = azure_core::Error; - - fn try_from(blob_tags: BlobTags) -> Result { +impl From for HashMap { + fn from(blob_tags: BlobTags) -> Self { let mut map = HashMap::new(); if let Some(tags) = blob_tags.blob_tag_set { for tag in tags { - match (tag.key, tag.value) { - (Some(k), Some(v)) => { - map.insert(k, v); - } - _ => { - return Err(azure_core::Error::with_message( - azure_core::error::ErrorKind::DataConversion, - "BlobTag missing key or value", - )); - } + if let (Some(key), Some(value)) = (tag.key, tag.value) { + map.insert(key, value); } } } - - Ok(map) + map } } @@ -108,3 +98,24 @@ impl From> for BlobTags { } } } + +/// Converts a `HashMap` into a `SignedIdentifiers` struct. +impl From> for SignedIdentifiers { + fn from(policies: HashMap) -> Self { + if policies.is_empty() { + return SignedIdentifiers { items: None }; + } + + let signed_identifiers: Vec = policies + .into_iter() + .map(|(id, access_policy)| SignedIdentifier { + id: Some(id), + access_policy: Some(access_policy), + }) + .collect(); + + SignedIdentifiers { + items: Some(signed_identifiers), + } + } +} diff --git a/sdk/storage/azure_storage_blob/src/models/mod.rs b/sdk/storage/azure_storage_blob/src/models/mod.rs index a33510fc8c..32ede71734 100644 --- a/sdk/storage/azure_storage_blob/src/models/mod.rs +++ b/sdk/storage/azure_storage_blob/src/models/mod.rs @@ -4,7 +4,7 @@ mod extensions; pub use crate::generated::models::{ - AccessTier, AccountKind, AppendBlobClientAppendBlockFromUrlOptions, + AccessPolicy, AccessTier, AccountKind, AppendBlobClientAppendBlockFromUrlOptions, AppendBlobClientAppendBlockFromUrlResult, AppendBlobClientAppendBlockFromUrlResultHeaders, AppendBlobClientAppendBlockOptions, AppendBlobClientAppendBlockResult, AppendBlobClientAppendBlockResultHeaders, AppendBlobClientCreateOptions, @@ -26,7 +26,6 @@ pub use crate::generated::models::{ BlobClientReleaseLeaseResultHeaders, BlobClientRenewLeaseOptions, BlobClientRenewLeaseResult, BlobClientRenewLeaseResultHeaders, BlobClientSetExpiryResult, BlobClientSetExpiryResultHeaders, BlobClientSetImmutabilityPolicyResult, BlobClientSetImmutabilityPolicyResultHeaders, - BlobClientSetLegalHoldResult, BlobClientSetLegalHoldResultHeaders, BlobClientSetMetadataOptions, BlobClientSetPropertiesOptions, BlobClientSetTagsOptions, BlobClientSetTierOptions, BlobClientStartCopyFromUrlResult, BlobClientStartCopyFromUrlResultHeaders, BlobClientUndeleteResult, @@ -36,16 +35,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, - BlobContainerClientSetAccessPolicyResult, BlobContainerClientSetAccessPolicyResultHeaders, + BlobContainerClientFindBlobsByTagsOptions, BlobContainerClientGetAccessPolicyOptions, + BlobContainerClientGetAccountInfoOptions, BlobContainerClientGetAccountInfoResult, + BlobContainerClientGetAccountInfoResultHeaders, BlobContainerClientGetPropertiesOptions, + BlobContainerClientGetPropertiesResult, BlobContainerClientGetPropertiesResultHeaders, + BlobContainerClientListBlobFlatSegmentOptions, BlobContainerClientReleaseLeaseOptions, + BlobContainerClientReleaseLeaseResult, BlobContainerClientReleaseLeaseResultHeaders, + BlobContainerClientRenameResult, BlobContainerClientRenameResultHeaders, + BlobContainerClientRenewLeaseOptions, BlobContainerClientRenewLeaseResult, + BlobContainerClientRenewLeaseResultHeaders, BlobContainerClientRestoreResult, + BlobContainerClientRestoreResultHeaders, BlobContainerClientSetAccessPolicyOptions, BlobContainerClientSetMetadataOptions, BlobCopySourceTags, BlobDeleteType, BlobExpiryOptions, BlobFlatListSegment, BlobImmutabilityPolicyMode, BlobItemInternal, BlobMetadata, BlobName, BlobPropertiesInternal, BlobServiceClientFindBlobsByTagsOptions, @@ -79,7 +78,7 @@ pub use crate::generated::models::{ PageBlobClientUploadPagesFromUrlResultHeaders, PageBlobClientUploadPagesOptions, PageBlobClientUploadPagesResult, PageBlobClientUploadPagesResultHeaders, PageList, PageListHeaders, PremiumPageBlobAccessTier, PublicAccessType, QueryRequestType, QueryType, - RehydratePriority, RetentionPolicy, SequenceNumberActionType, SignedIdentifier, SkuName, - StaticWebsite, StorageErrorCode, StorageServiceStats, StorageServiceStatsHeaders, - UserDelegationKey, UserDelegationKeyHeaders, VecSignedIdentifierHeaders, + RehydratePriority, RetentionPolicy, SequenceNumberActionType, SignedIdentifier, + SignedIdentifiers, SignedIdentifiersHeaders, SkuName, StaticWebsite, StorageErrorCode, + StorageServiceStats, StorageServiceStatsHeaders, UserDelegationKey, UserDelegationKeyHeaders, }; diff --git a/sdk/storage/azure_storage_blob/tests/blob_client.rs b/sdk/storage/azure_storage_blob/tests/blob_client.rs index e969dd5cad..44f0d01228 100644 --- a/sdk/storage/azure_storage_blob/tests/blob_client.rs +++ b/sdk/storage/azure_storage_blob/tests/blob_client.rs @@ -2,7 +2,7 @@ // Licensed under the MIT License. use azure_core::{ - http::{ClientOptions, RequestContent, StatusCode}, + http::{ClientOptions, RequestContent, StatusCode, Url}, Bytes, }; use azure_core_test::{recorded, Matcher, TestContext}; @@ -21,7 +21,6 @@ use azure_storage_blob_test::{create_test_blob, get_blob_name, get_container_cli use futures::TryStreamExt; use std::{collections::HashMap, error::Error, time::Duration}; use tokio::time; -use typespec_client_core::http::Url; #[recorded::test] async fn test_get_blob_properties(ctx: TestContext) -> Result<(), Box> { @@ -456,7 +455,7 @@ async fn test_blob_tags(ctx: TestContext) -> Result<(), Box> { // Assert let response_tags = blob_client.get_tags(None).await?.into_model()?; - let map: HashMap = response_tags.try_into()?; + let map: HashMap = response_tags.into(); assert_eq!(blob_tags, map); // Set Tags with No Tags (Clear Tags) @@ -464,7 +463,7 @@ async fn test_blob_tags(ctx: TestContext) -> Result<(), Box> { // Assert let response_tags = blob_client.get_tags(None).await?.into_model()?; - let map: HashMap = response_tags.try_into()?; + let map: HashMap = response_tags.into(); assert_eq!(HashMap::new(), map); container_client.delete_container(None).await?; diff --git a/sdk/storage/azure_storage_blob/tests/blob_container_client.rs b/sdk/storage/azure_storage_blob/tests/blob_container_client.rs index 78a38b5134..fe86e6b1e9 100644 --- a/sdk/storage/azure_storage_blob/tests/blob_container_client.rs +++ b/sdk/storage/azure_storage_blob/tests/blob_container_client.rs @@ -1,14 +1,18 @@ // 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_core::{ + http::{RequestContent, StatusCode}, + time::{parse_rfc3339, to_rfc3339, OffsetDateTime}, +}; +use azure_core_test::{recorded, Matcher, TestContext, TestMode, VarOptions}; use azure_storage_blob::format_filter_expression; use azure_storage_blob::models::{ - AccountKind, BlobContainerClientAcquireLeaseResultHeaders, + AccessPolicy, AccountKind, BlobContainerClientAcquireLeaseResultHeaders, BlobContainerClientChangeLeaseResultHeaders, BlobContainerClientGetAccountInfoResultHeaders, BlobContainerClientGetPropertiesResultHeaders, BlobContainerClientListBlobFlatSegmentOptions, BlobContainerClientSetMetadataOptions, BlobType, BlockBlobClientUploadOptions, LeaseState, + SignedIdentifiers, }; use azure_storage_blob_test::{ create_test_blob, get_blob_name, get_blob_service_client, get_container_client, @@ -400,3 +404,92 @@ async fn test_find_blobs_by_tags_container(ctx: TestContext) -> Result<(), Box Result<(), Box> { + // Recording Setup + let recording = ctx.recording(); + recording.set_matcher(Matcher::BodilessMatcher).await?; + let container_client = get_container_client(recording, false).await?; + container_client.create_container(None).await?; + + // Set Access Policy w/ Multiple Policy Defined + let expiry = recording.var( + "expiry", + Some(VarOptions { + default_value: Some( + to_rfc3339(&(OffsetDateTime::now_utc() + Duration::from_secs(10))).into(), + ), + ..Default::default() + }), + ); + let start = recording.var( + "start", + Some(VarOptions { + default_value: Some(to_rfc3339(&OffsetDateTime::now_utc()).into()), + ..Default::default() + }), + ); + println!("Expiry: {}", &expiry); + println!("Start: {}", &start); + let test_id_1: Option = Some("testid_1".into()); + let test_id_2: Option = Some("testid_2".into()); + let access_policy_1 = AccessPolicy { + expiry: Some(parse_rfc3339(&expiry)?), + permission: Some("rw".to_string()), + start: Some(parse_rfc3339(&start)?), + }; + let access_policy_2 = AccessPolicy { + expiry: Some(parse_rfc3339(&expiry)?), + permission: Some("cd".to_string()), + start: Some(parse_rfc3339(&start)?), + }; + let policies: HashMap = HashMap::from([ + (test_id_1.clone().unwrap(), access_policy_1.clone()), + (test_id_2.clone().unwrap(), access_policy_2.clone()), + ]); + container_client + .set_access_policy( + RequestContent::try_from(SignedIdentifiers::from(policies))?, + None, + ) + .await?; + + // Assert + let response = container_client.get_access_policy(None).await?; + let signed_identifiers = response.into_model()?; + + let mut remaining_count = 2; + for signed_identifier in signed_identifiers.items.as_ref().unwrap() { + // Check ID matches one of the expected IDs from set_access_policy + assert!([&test_id_1, &test_id_2].contains(&&signed_identifier.id)); + + if let Some(access_policy) = &signed_identifier.access_policy { + // Check permission, start, and expiry match one of the expected values from set_access_policy + assert!([&access_policy_1.permission, &access_policy_2.permission] + .contains(&&access_policy.permission)); + assert!( + [&access_policy_1.expiry, &access_policy_2.expiry].contains(&&access_policy.expiry) + ); + assert!( + [&access_policy_1.start, &access_policy_2.start].contains(&&access_policy.start) + ); + } + + remaining_count -= 1; + } + assert_eq!(remaining_count, 0); + + // Clear Access Policy + let clear_signed_identifiers: SignedIdentifiers = HashMap::::new().into(); + container_client + .set_access_policy(RequestContent::try_from(clear_signed_identifiers)?, None) + .await?; + + // Assert + let cleared_response = container_client.get_access_policy(None).await?; + let cleared_signed_identifiers = cleared_response.into_model()?; + assert!(cleared_signed_identifiers.items.is_none()); + + Ok(()) +} diff --git a/sdk/storage/azure_storage_blob/tsp-location.yaml b/sdk/storage/azure_storage_blob/tsp-location.yaml index 2f51fc4061..68483e5e13 100644 --- a/sdk/storage/azure_storage_blob/tsp-location.yaml +++ b/sdk/storage/azure_storage_blob/tsp-location.yaml @@ -1,4 +1,4 @@ directory: specification/storage/Microsoft.BlobStorage -commit: 6b5a0fdadca03abe0b8e91a68a62cd1e639ed55e +commit: 76ab9e72c8747dc01f2f406caa796d03160b813d repo: Azure/azure-rest-api-specs additionalDirectories: