From 8113772cf2339be765c0c5453d7eb5fac410e9d0 Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Wed, 12 Nov 2025 14:28:46 -0800 Subject: [PATCH 1/4] Fully fleshed out, but will need to iterate after other 2x PRs go through --- .../src/clients/blob_client.rs | 41 +++++++++++++--- .../src/generated/models/enums_impl.rs | 30 ++++++------ .../src/models/extensions.rs | 15 +++++- .../azure_storage_blob/src/models/mod.rs | 19 ++++---- .../azure_storage_blob/tests/blob_client.rs | 48 ++++++++++++++++++- .../azure_storage_blob/tsp-location.yaml | 2 +- 6 files changed, 120 insertions(+), 35 deletions(-) diff --git a/sdk/storage/azure_storage_blob/src/clients/blob_client.rs b/sdk/storage/azure_storage_blob/src/clients/blob_client.rs index 4e24a99d04..51ffb9a111 100644 --- a/sdk/storage/azure_storage_blob/src/clients/blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/clients/blob_client.rs @@ -8,16 +8,19 @@ use crate::{ generated::clients::PageBlobClient as GeneratedPageBlobClient, generated::models::{ BlobClientAcquireLeaseResult, BlobClientBreakLeaseResult, BlobClientChangeLeaseResult, - BlobClientDownloadResult, BlobClientGetAccountInfoResult, BlobClientGetPropertiesResult, - BlobClientReleaseLeaseResult, BlobClientRenewLeaseResult, BlockBlobClientUploadResult, + BlobClientDeleteImmutabilityPolicyResult, BlobClientDownloadResult, + BlobClientGetAccountInfoResult, BlobClientGetPropertiesResult, + BlobClientReleaseLeaseResult, BlobClientRenewLeaseResult, + BlobClientSetImmutabilityPolicyResult, BlockBlobClientUploadResult, }, models::{ AccessTier, BlobClientAcquireLeaseOptions, BlobClientBreakLeaseOptions, - BlobClientChangeLeaseOptions, BlobClientDeleteOptions, BlobClientDownloadOptions, - BlobClientGetAccountInfoOptions, BlobClientGetPropertiesOptions, BlobClientGetTagsOptions, - BlobClientReleaseLeaseOptions, BlobClientRenewLeaseOptions, BlobClientSetMetadataOptions, - BlobClientSetPropertiesOptions, BlobClientSetTagsOptions, BlobClientSetTierOptions, - BlobTags, BlockBlobClientUploadOptions, StorageErrorCode, + BlobClientChangeLeaseOptions, BlobClientDeleteImmutabilityPolicyOptions, + BlobClientDeleteOptions, BlobClientDownloadOptions, BlobClientGetAccountInfoOptions, + BlobClientGetPropertiesOptions, BlobClientGetTagsOptions, BlobClientReleaseLeaseOptions, + BlobClientRenewLeaseOptions, BlobClientSetImmutabilityPolicyOptions, + BlobClientSetMetadataOptions, BlobClientSetPropertiesOptions, BlobClientSetTagsOptions, + BlobClientSetTierOptions, BlobTags, BlockBlobClientUploadOptions, StorageErrorCode, }, pipeline::StorageHeadersPolicy, AppendBlobClient, BlobClientOptions, BlockBlobClient, PageBlobClient, @@ -436,4 +439,28 @@ impl BlobClient { Err(e) => Err(e), } } + + /// Sets the immutability policy on the blob. + /// + /// # Arguments + /// + /// * `options` - Optional configuration for the request. + pub async fn set_immutability_policy( + &self, + options: Option>, + ) -> Result> { + self.client.set_immutability_policy(options).await + } + + /// Deletes the immutability policy on the blob. + /// + /// # Arguments + /// + /// * `options` - Optional configuration for the request. + pub async fn delete_immutability_policy( + &self, + options: Option>, + ) -> Result> { + self.client.delete_immutability_policy(options).await + } } diff --git a/sdk/storage/azure_storage_blob/src/generated/models/enums_impl.rs b/sdk/storage/azure_storage_blob/src/generated/models/enums_impl.rs index 376b01f54d..db095f8e86 100644 --- a/sdk/storage/azure_storage_blob/src/generated/models/enums_impl.rs +++ b/sdk/storage/azure_storage_blob/src/generated/models/enums_impl.rs @@ -319,9 +319,9 @@ impl FromStr for BlobImmutabilityPolicyMode { type Err = Error; fn from_str(s: &str) -> ::core::result::Result::Err> { Ok(match s { - "Locked" => BlobImmutabilityPolicyMode::Locked, - "Mutable" => BlobImmutabilityPolicyMode::Mutable, - "Unlocked" => BlobImmutabilityPolicyMode::Unlocked, + "locked" => BlobImmutabilityPolicyMode::Locked, + "mutable" => BlobImmutabilityPolicyMode::Mutable, + "unlocked" => BlobImmutabilityPolicyMode::Unlocked, _ => { return Err(Error::with_message_fn(ErrorKind::DataConversion, || { format!("unknown variant of BlobImmutabilityPolicyMode found: \"{s}\"") @@ -334,9 +334,9 @@ impl FromStr for BlobImmutabilityPolicyMode { impl AsRef for BlobImmutabilityPolicyMode { fn as_ref(&self) -> &str { match self { - BlobImmutabilityPolicyMode::Locked => "Locked", - BlobImmutabilityPolicyMode::Mutable => "Mutable", - BlobImmutabilityPolicyMode::Unlocked => "Unlocked", + BlobImmutabilityPolicyMode::Locked => "locked", + BlobImmutabilityPolicyMode::Mutable => "mutable", + BlobImmutabilityPolicyMode::Unlocked => "unlocked", } } } @@ -344,9 +344,9 @@ impl AsRef for BlobImmutabilityPolicyMode { impl Display for BlobImmutabilityPolicyMode { fn fmt(&self, f: &mut Formatter<'_>) -> ::std::fmt::Result { match self { - BlobImmutabilityPolicyMode::Locked => Display::fmt("Locked", f), - BlobImmutabilityPolicyMode::Mutable => Display::fmt("Mutable", f), - BlobImmutabilityPolicyMode::Unlocked => Display::fmt("Unlocked", f), + BlobImmutabilityPolicyMode::Locked => Display::fmt("locked", f), + BlobImmutabilityPolicyMode::Mutable => Display::fmt("mutable", f), + BlobImmutabilityPolicyMode::Unlocked => Display::fmt("unlocked", f), } } } @@ -644,8 +644,8 @@ impl FromStr for ImmutabilityPolicyMode { type Err = Error; fn from_str(s: &str) -> ::core::result::Result::Err> { Ok(match s { - "Locked" => ImmutabilityPolicyMode::Locked, - "Unlocked" => ImmutabilityPolicyMode::Unlocked, + "locked" => ImmutabilityPolicyMode::Locked, + "unlocked" => ImmutabilityPolicyMode::Unlocked, _ => { return Err(Error::with_message_fn(ErrorKind::DataConversion, || { format!("unknown variant of ImmutabilityPolicyMode found: \"{s}\"") @@ -658,8 +658,8 @@ impl FromStr for ImmutabilityPolicyMode { impl AsRef for ImmutabilityPolicyMode { fn as_ref(&self) -> &str { match self { - ImmutabilityPolicyMode::Locked => "Locked", - ImmutabilityPolicyMode::Unlocked => "Unlocked", + ImmutabilityPolicyMode::Locked => "locked", + ImmutabilityPolicyMode::Unlocked => "unlocked", } } } @@ -667,8 +667,8 @@ impl AsRef for ImmutabilityPolicyMode { impl Display for ImmutabilityPolicyMode { fn fmt(&self, f: &mut Formatter<'_>) -> ::std::fmt::Result { match self { - ImmutabilityPolicyMode::Locked => Display::fmt("Locked", f), - ImmutabilityPolicyMode::Unlocked => Display::fmt("Unlocked", f), + ImmutabilityPolicyMode::Locked => Display::fmt("locked", f), + ImmutabilityPolicyMode::Unlocked => Display::fmt("unlocked", f), } } } diff --git a/sdk/storage/azure_storage_blob/src/models/extensions.rs b/sdk/storage/azure_storage_blob/src/models/extensions.rs index 6a3a0683db..089fa14d58 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, + AppendBlobClientCreateOptions, BlobImmutabilityPolicyMode, BlobTag, BlobTags, + BlockBlobClientUploadBlobFromUrlOptions, BlockBlobClientUploadOptions, ImmutabilityPolicyMode, + PageBlobClientCreateOptions, }; use std::collections::HashMap; @@ -108,3 +109,13 @@ impl From> for BlobTags { } } } + +// Converts a `ImmutabilityPolicyMode` into an `BlobImmutabilityPolicyMode`. +impl From for BlobImmutabilityPolicyMode { + fn from(mode: ImmutabilityPolicyMode) -> Self { + match mode { + ImmutabilityPolicyMode::Locked => BlobImmutabilityPolicyMode::Locked, + ImmutabilityPolicyMode::Unlocked => BlobImmutabilityPolicyMode::Unlocked, + } + } +} diff --git a/sdk/storage/azure_storage_blob/src/models/mod.rs b/sdk/storage/azure_storage_blob/src/models/mod.rs index a33510fc8c..004ea4586f 100644 --- a/sdk/storage/azure_storage_blob/src/models/mod.rs +++ b/sdk/storage/azure_storage_blob/src/models/mod.rs @@ -16,15 +16,16 @@ pub use crate::generated::models::{ BlobClientBreakLeaseResultHeaders, BlobClientChangeLeaseOptions, BlobClientChangeLeaseResult, BlobClientChangeLeaseResultHeaders, BlobClientCopyFromUrlResult, BlobClientCopyFromUrlResultHeaders, BlobClientCreateSnapshotResult, - BlobClientCreateSnapshotResultHeaders, BlobClientDeleteImmutabilityPolicyResult, - BlobClientDeleteImmutabilityPolicyResultHeaders, BlobClientDeleteOptions, - BlobClientDownloadOptions, BlobClientDownloadResult, BlobClientDownloadResultHeaders, - BlobClientGetAccountInfoOptions, BlobClientGetAccountInfoResult, - BlobClientGetAccountInfoResultHeaders, BlobClientGetPropertiesOptions, - BlobClientGetPropertiesResult, BlobClientGetPropertiesResultHeaders, BlobClientGetTagsOptions, - BlobClientReleaseLeaseOptions, BlobClientReleaseLeaseResult, - BlobClientReleaseLeaseResultHeaders, BlobClientRenewLeaseOptions, BlobClientRenewLeaseResult, - BlobClientRenewLeaseResultHeaders, BlobClientSetExpiryResult, BlobClientSetExpiryResultHeaders, + BlobClientCreateSnapshotResultHeaders, BlobClientDeleteImmutabilityPolicyOptions, + BlobClientDeleteImmutabilityPolicyResult, BlobClientDeleteImmutabilityPolicyResultHeaders, + BlobClientDeleteOptions, BlobClientDownloadOptions, BlobClientDownloadResult, + BlobClientDownloadResultHeaders, BlobClientGetAccountInfoOptions, + BlobClientGetAccountInfoResult, BlobClientGetAccountInfoResultHeaders, + BlobClientGetPropertiesOptions, BlobClientGetPropertiesResult, + BlobClientGetPropertiesResultHeaders, BlobClientGetTagsOptions, BlobClientReleaseLeaseOptions, + BlobClientReleaseLeaseResult, BlobClientReleaseLeaseResultHeaders, BlobClientRenewLeaseOptions, + BlobClientRenewLeaseResult, BlobClientRenewLeaseResultHeaders, BlobClientSetExpiryResult, + BlobClientSetExpiryResultHeaders, BlobClientSetImmutabilityPolicyOptions, BlobClientSetImmutabilityPolicyResult, BlobClientSetImmutabilityPolicyResultHeaders, BlobClientSetLegalHoldResult, BlobClientSetLegalHoldResultHeaders, BlobClientSetMetadataOptions, BlobClientSetPropertiesOptions, BlobClientSetTagsOptions, diff --git a/sdk/storage/azure_storage_blob/tests/blob_client.rs b/sdk/storage/azure_storage_blob/tests/blob_client.rs index e969dd5cad..51060f0d97 100644 --- a/sdk/storage/azure_storage_blob/tests/blob_client.rs +++ b/sdk/storage/azure_storage_blob/tests/blob_client.rs @@ -3,6 +3,7 @@ use azure_core::{ http::{ClientOptions, RequestContent, StatusCode}, + time::OffsetDateTime, Bytes, }; use azure_core_test::{recorded, Matcher, TestContext}; @@ -12,8 +13,10 @@ use azure_storage_blob::{ BlobClientChangeLeaseResultHeaders, BlobClientDownloadOptions, BlobClientDownloadResultHeaders, BlobClientGetAccountInfoResultHeaders, BlobClientGetPropertiesOptions, BlobClientGetPropertiesResultHeaders, + BlobClientSetImmutabilityPolicyOptions, BlobClientSetImmutabilityPolicyResultHeaders, BlobClientSetMetadataOptions, BlobClientSetPropertiesOptions, BlobClientSetTierOptions, - BlockBlobClientUploadOptions, LeaseState, + BlobImmutabilityPolicyMode, BlockBlobClientUploadOptions, ImmutabilityPolicyMode, + LeaseState, }, BlobClient, BlobClientOptions, BlobContainerClient, BlobContainerClientOptions, }; @@ -644,3 +647,46 @@ async fn test_encoding_edge_cases(ctx: TestContext) -> Result<(), Box Ok(()) } + +#[recorded::test] +async fn test_immutability_policy(ctx: TestContext) -> Result<(), Box> { + //TODO: Point to versioning account, add datetimes to recording variables + // Recording Setup + let recording = ctx.recording(); + let container_client = get_container_client(recording, false).await?; + let blob_client = container_client.blob_client(&get_blob_name(recording)); + container_client.create_container(None).await?; + create_test_blob(&blob_client, None, None).await?; + let test_expiry_time = Some(OffsetDateTime::now_utc() + Duration::from_secs(300)); + let test_immutability_policy_mode = ImmutabilityPolicyMode::Unlocked; + + // Set Immutability Policy + let immutability_policy_options = BlobClientSetImmutabilityPolicyOptions { + immutability_policy_expiry: test_expiry_time.clone(), + immutability_policy_mode: Some(test_immutability_policy_mode), + ..Default::default() + }; + let response = blob_client + .set_immutability_policy(Some(immutability_policy_options)) + .await?; + + // Assert + let mode = response.immutability_policy_mode()?; + let expires_on = response.immutability_policy_expires_on()?; + + let response_mode: BlobImmutabilityPolicyMode = test_immutability_policy_mode.into(); + assert_eq!(response_mode, mode.unwrap()); + assert_eq!(test_expiry_time, expires_on); + + // Delete Immutability Policy + blob_client.delete_immutability_policy(None).await?; + let response = blob_client.get_properties(None).await?; + + // Assert + let mode = response.immutability_policy_mode()?; + let expires_on = response.immutability_policy_expires_on()?; + assert!(mode.is_none()); + assert!(expires_on.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..3800f8649f 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: 64da9cf708dfbae0ff9ca2cde6829b123d9966bb repo: Azure/azure-rest-api-specs additionalDirectories: From b62b8148eaa88d0df5df3f02fcf673172de69e5c Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Wed, 12 Nov 2025 14:42:23 -0800 Subject: [PATCH 2/4] Strip nanoseconds --- sdk/storage/azure_storage_blob/tests/blob_client.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sdk/storage/azure_storage_blob/tests/blob_client.rs b/sdk/storage/azure_storage_blob/tests/blob_client.rs index 51060f0d97..79f1b2e07f 100644 --- a/sdk/storage/azure_storage_blob/tests/blob_client.rs +++ b/sdk/storage/azure_storage_blob/tests/blob_client.rs @@ -676,7 +676,11 @@ async fn test_immutability_policy(ctx: TestContext) -> Result<(), Box let response_mode: BlobImmutabilityPolicyMode = test_immutability_policy_mode.into(); assert_eq!(response_mode, mode.unwrap()); - assert_eq!(test_expiry_time, expires_on); + // Need to ignore nanoseconds due to Service truncation + assert_eq!( + test_expiry_time.map(|dt| dt.replace_nanosecond(0).unwrap()), + expires_on + ); // Delete Immutability Policy blob_client.delete_immutability_policy(None).await?; From e00eafd58717dc611394c1913f7ca22053630faa Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Fri, 14 Nov 2025 16:17:23 -0800 Subject: [PATCH 3/4] Fully fleshed, pending other PRs to get playback-only decorator, and to fix up legal hold to point to versioned as well + get bicep updated to work --- sdk/storage/azure_storage_blob/assets.json | 2 +- .../src/clients/blob_client.rs | 16 +-- .../src/generated/clients/blob_client.rs | 86 +++------------ .../src/generated/models/enums.rs | 19 +--- .../src/generated/models/enums_impl.rs | 50 ++------- .../src/generated/models/enums_serde.rs | 30 +---- .../src/generated/models/header_traits.rs | 103 ++---------------- .../src/generated/models/method_options.rs | 3 - .../src/generated/models/pub_models.rs | 14 +-- .../src/models/extensions.rs | 15 +-- .../azure_storage_blob/src/models/mod.rs | 51 ++++----- .../azure_storage_blob/tests/blob_client.rs | 84 +++++++++----- .../azure_storage_blob/tsp-location.yaml | 2 +- .../azure_storage_blob_test/src/lib.rs | 48 +++++++- 14 files changed, 188 insertions(+), 335 deletions(-) diff --git a/sdk/storage/azure_storage_blob/assets.json b/sdk/storage/azure_storage_blob/assets.json index dae255a41b..29ee6df18e 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_eb66ce4488", "TagPrefix": "rust/azure_storage_blob" } diff --git a/sdk/storage/azure_storage_blob/src/clients/blob_client.rs b/sdk/storage/azure_storage_blob/src/clients/blob_client.rs index 51ffb9a111..e06f720e8d 100644 --- a/sdk/storage/azure_storage_blob/src/clients/blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/clients/blob_client.rs @@ -8,10 +8,8 @@ use crate::{ generated::clients::PageBlobClient as GeneratedPageBlobClient, generated::models::{ BlobClientAcquireLeaseResult, BlobClientBreakLeaseResult, BlobClientChangeLeaseResult, - BlobClientDeleteImmutabilityPolicyResult, BlobClientDownloadResult, - BlobClientGetAccountInfoResult, BlobClientGetPropertiesResult, - BlobClientReleaseLeaseResult, BlobClientRenewLeaseResult, - BlobClientSetImmutabilityPolicyResult, BlockBlobClientUploadResult, + BlobClientDownloadResult, BlobClientGetAccountInfoResult, BlobClientGetPropertiesResult, + BlobClientReleaseLeaseResult, BlobClientRenewLeaseResult, BlockBlobClientUploadResult, }, models::{ AccessTier, BlobClientAcquireLeaseOptions, BlobClientBreakLeaseOptions, @@ -32,6 +30,7 @@ use azure_core::{ policies::{BearerTokenAuthorizationPolicy, Policy}, AsyncResponse, NoFormat, Pipeline, RequestContent, Response, StatusCode, Url, XmlFormat, }, + time::OffsetDateTime, tracing, Bytes, Result, }; use std::collections::HashMap; @@ -447,9 +446,12 @@ impl BlobClient { /// * `options` - Optional configuration for the request. pub async fn set_immutability_policy( &self, + immutability_policy_expiry: &OffsetDateTime, options: Option>, - ) -> Result> { - self.client.set_immutability_policy(options).await + ) -> Result> { + self.client + .set_immutability_policy(immutability_policy_expiry, options) + .await } /// Deletes the immutability policy on the blob. @@ -460,7 +462,7 @@ impl BlobClient { pub async fn delete_immutability_policy( &self, options: Option>, - ) -> Result> { + ) -> Result> { self.client.delete_immutability_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..f888ab6048 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 @@ -9,16 +9,16 @@ use crate::generated::models::{ BlobClientBreakLeaseResult, BlobClientChangeLeaseOptions, BlobClientChangeLeaseResult, BlobClientCopyFromUrlOptions, BlobClientCopyFromUrlResult, BlobClientCreateSnapshotOptions, BlobClientCreateSnapshotResult, BlobClientDeleteImmutabilityPolicyOptions, - BlobClientDeleteImmutabilityPolicyResult, BlobClientDeleteOptions, BlobClientDownloadOptions, - BlobClientDownloadResult, BlobClientGetAccountInfoOptions, BlobClientGetAccountInfoResult, + BlobClientDeleteOptions, BlobClientDownloadOptions, BlobClientDownloadResult, + BlobClientGetAccountInfoOptions, BlobClientGetAccountInfoResult, BlobClientGetPropertiesOptions, BlobClientGetPropertiesResult, BlobClientGetTagsOptions, BlobClientReleaseLeaseOptions, BlobClientReleaseLeaseResult, BlobClientRenewLeaseOptions, BlobClientRenewLeaseResult, BlobClientSetExpiryOptions, BlobClientSetExpiryResult, - BlobClientSetImmutabilityPolicyOptions, BlobClientSetImmutabilityPolicyResult, - BlobClientSetLegalHoldOptions, BlobClientSetLegalHoldResult, BlobClientSetMetadataOptions, - BlobClientSetPropertiesOptions, BlobClientSetTagsOptions, BlobClientSetTierOptions, - BlobClientStartCopyFromUrlOptions, BlobClientStartCopyFromUrlResult, BlobClientUndeleteOptions, - BlobClientUndeleteResult, BlobExpiryOptions, BlobTags, + BlobClientSetImmutabilityPolicyOptions, BlobClientSetLegalHoldOptions, + BlobClientSetLegalHoldResult, BlobClientSetMetadataOptions, BlobClientSetPropertiesOptions, + BlobClientSetTagsOptions, BlobClientSetTierOptions, BlobClientStartCopyFromUrlOptions, + BlobClientStartCopyFromUrlResult, BlobClientUndeleteOptions, BlobClientUndeleteResult, + BlobExpiryOptions, BlobTags, }; use azure_core::{ base64::encode, @@ -30,7 +30,7 @@ use azure_core::{ AsyncResponse, ClientOptions, Method, NoFormat, Pipeline, PipelineSendOptions, PipelineStreamOptions, Request, RequestContent, Response, Url, XmlFormat, }, - time::to_rfc7231, + time::{to_rfc7231, OffsetDateTime}, tracing, Result, }; use std::{collections::HashMap, sync::Arc}; @@ -791,34 +791,11 @@ impl BlobClient { /// # Arguments /// /// * `options` - Optional parameters for the request. - /// - /// ## Response Headers - /// - /// The returned [`Response`](azure_core::http::Response) implements the [`BlobClientDeleteImmutabilityPolicyResultHeaders`] trait, which provides - /// access to response headers. For example: - /// - /// ```no_run - /// use azure_core::{Result, http::{Response, NoFormat}}; - /// use azure_storage_blob::models::{BlobClientDeleteImmutabilityPolicyResult, BlobClientDeleteImmutabilityPolicyResultHeaders}; - /// async fn example() -> Result<()> { - /// let response: Response = unimplemented!(); - /// // Access response headers - /// if let Some(date) = response.date()? { - /// println!("Date: {:?}", date); - /// } - /// Ok(()) - /// } - /// ``` - /// - /// ### Available headers - /// * [`date`()](crate::generated::models::BlobClientDeleteImmutabilityPolicyResultHeaders::date) - Date - /// - /// [`BlobClientDeleteImmutabilityPolicyResultHeaders`]: crate::generated::models::BlobClientDeleteImmutabilityPolicyResultHeaders #[tracing::function("Storage.Blob.Blob.deleteImmutabilityPolicy")] pub async fn delete_immutability_policy( &self, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); @@ -1553,43 +1530,14 @@ impl BlobClient { /// /// # Arguments /// + /// * `immutability_policy_expiry` - Specifies the date time when the blobs immutability policy is set to expire. /// * `options` - Optional parameters for the request. - /// - /// ## Response Headers - /// - /// The returned [`Response`](azure_core::http::Response) implements the [`BlobClientSetImmutabilityPolicyResultHeaders`] trait, which provides - /// access to response headers. For example: - /// - /// ```no_run - /// use azure_core::{Result, http::{Response, NoFormat}}; - /// use azure_storage_blob::models::{BlobClientSetImmutabilityPolicyResult, BlobClientSetImmutabilityPolicyResultHeaders}; - /// async fn example() -> Result<()> { - /// let response: Response = unimplemented!(); - /// // Access response headers - /// if let Some(date) = response.date()? { - /// println!("Date: {:?}", date); - /// } - /// if let Some(immutability_policy_mode) = response.immutability_policy_mode()? { - /// println!("x-ms-immutability-policy-mode: {:?}", immutability_policy_mode); - /// } - /// if let Some(immutability_policy_expires_on) = response.immutability_policy_expires_on()? { - /// println!("x-ms-immutability-policy-until-date: {:?}", immutability_policy_expires_on); - /// } - /// Ok(()) - /// } - /// ``` - /// - /// ### Available headers - /// * [`date`()](crate::generated::models::BlobClientSetImmutabilityPolicyResultHeaders::date) - Date - /// * [`immutability_policy_mode`()](crate::generated::models::BlobClientSetImmutabilityPolicyResultHeaders::immutability_policy_mode) - x-ms-immutability-policy-mode - /// * [`immutability_policy_expires_on`()](crate::generated::models::BlobClientSetImmutabilityPolicyResultHeaders::immutability_policy_expires_on) - x-ms-immutability-policy-until-date - /// - /// [`BlobClientSetImmutabilityPolicyResultHeaders`]: crate::generated::models::BlobClientSetImmutabilityPolicyResultHeaders #[tracing::function("Storage.Blob.Blob.setImmutabilityPolicy")] pub async fn set_immutability_policy( &self, + immutability_policy_expiry: &OffsetDateTime, options: Option>, - ) -> Result> { + ) -> Result> { let options = options.unwrap_or_default(); let ctx = options.method_options.context.to_borrowed(); let mut url = self.endpoint.clone(); @@ -1616,12 +1564,10 @@ impl BlobClient { immutability_policy_mode.to_string(), ); } - if let Some(immutability_policy_expiry) = options.immutability_policy_expiry { - request.insert_header( - "x-ms-immutability-policy-until-date", - to_rfc7231(&immutability_policy_expiry), - ); - } + request.insert_header( + "x-ms-immutability-policy-until-date", + to_rfc7231(immutability_policy_expiry), + ); request.insert_header("x-ms-version", &self.version); let rsp = self .pipeline diff --git a/sdk/storage/azure_storage_blob/src/generated/models/enums.rs b/sdk/storage/azure_storage_blob/src/generated/models/enums.rs index 74343ff9f9..de9c5df696 100644 --- a/sdk/storage/azure_storage_blob/src/generated/models/enums.rs +++ b/sdk/storage/azure_storage_blob/src/generated/models/enums.rs @@ -135,20 +135,6 @@ pub enum BlobExpiryOptions { UnknownValue(String), } -/// The immutability policy mode. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -#[non_exhaustive] -pub enum BlobImmutabilityPolicyMode { - /// The immutability policy is locked. - Locked, - - /// The immutability policy is mutable. - Mutable, - - /// The immutability policy is unlocked. - Unlocked, -} - /// The blob type. #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[non_exhaustive] @@ -253,13 +239,16 @@ pub enum GeoReplicationStatusType { UnknownValue(String), } -/// The immutability policy mode used in requests. +/// The immutability policy mode used in requests and responses. #[derive(Clone, Copy, Debug, Eq, PartialEq)] #[non_exhaustive] pub enum ImmutabilityPolicyMode { /// The immutability policy is locked. Locked, + /// The immutability policy is mutable. Should never be set, only returned. + Mutable, + /// The immutability policy is unlocked. Unlocked, } diff --git a/sdk/storage/azure_storage_blob/src/generated/models/enums_impl.rs b/sdk/storage/azure_storage_blob/src/generated/models/enums_impl.rs index db095f8e86..7bad409c5f 100644 --- a/sdk/storage/azure_storage_blob/src/generated/models/enums_impl.rs +++ b/sdk/storage/azure_storage_blob/src/generated/models/enums_impl.rs @@ -5,12 +5,11 @@ use super::{ AccessTier, AccountKind, ArchiveStatus, BlobCopySourceTags, BlobDeleteType, BlobExpiryOptions, - BlobImmutabilityPolicyMode, BlobType, BlockListType, CopyStatus, DeleteSnapshotsOptionType, - EncryptionAlgorithmType, FileShareTokenIntent, FilterBlobsIncludeItem, - GeoReplicationStatusType, ImmutabilityPolicyMode, LeaseDuration, LeaseState, LeaseStatus, - ListBlobsIncludeItem, ListContainersIncludeType, PremiumPageBlobAccessTier, PublicAccessType, - QueryRequestType, QueryType, RehydratePriority, SequenceNumberActionType, SkuName, - StorageErrorCode, + BlobType, BlockListType, CopyStatus, DeleteSnapshotsOptionType, EncryptionAlgorithmType, + FileShareTokenIntent, FilterBlobsIncludeItem, GeoReplicationStatusType, ImmutabilityPolicyMode, + LeaseDuration, LeaseState, LeaseStatus, ListBlobsIncludeItem, ListContainersIncludeType, + PremiumPageBlobAccessTier, PublicAccessType, QueryRequestType, QueryType, RehydratePriority, + SequenceNumberActionType, SkuName, StorageErrorCode, }; use azure_core::error::{Error, ErrorKind}; use std::{ @@ -315,42 +314,6 @@ impl Display for BlobExpiryOptions { } } -impl FromStr for BlobImmutabilityPolicyMode { - type Err = Error; - fn from_str(s: &str) -> ::core::result::Result::Err> { - Ok(match s { - "locked" => BlobImmutabilityPolicyMode::Locked, - "mutable" => BlobImmutabilityPolicyMode::Mutable, - "unlocked" => BlobImmutabilityPolicyMode::Unlocked, - _ => { - return Err(Error::with_message_fn(ErrorKind::DataConversion, || { - format!("unknown variant of BlobImmutabilityPolicyMode found: \"{s}\"") - })) - } - }) - } -} - -impl AsRef for BlobImmutabilityPolicyMode { - fn as_ref(&self) -> &str { - match self { - BlobImmutabilityPolicyMode::Locked => "locked", - BlobImmutabilityPolicyMode::Mutable => "mutable", - BlobImmutabilityPolicyMode::Unlocked => "unlocked", - } - } -} - -impl Display for BlobImmutabilityPolicyMode { - fn fmt(&self, f: &mut Formatter<'_>) -> ::std::fmt::Result { - match self { - BlobImmutabilityPolicyMode::Locked => Display::fmt("locked", f), - BlobImmutabilityPolicyMode::Mutable => Display::fmt("mutable", f), - BlobImmutabilityPolicyMode::Unlocked => Display::fmt("unlocked", f), - } - } -} - impl FromStr for BlobType { type Err = Error; fn from_str(s: &str) -> ::core::result::Result::Err> { @@ -645,6 +608,7 @@ impl FromStr for ImmutabilityPolicyMode { fn from_str(s: &str) -> ::core::result::Result::Err> { Ok(match s { "locked" => ImmutabilityPolicyMode::Locked, + "mutable" => ImmutabilityPolicyMode::Mutable, "unlocked" => ImmutabilityPolicyMode::Unlocked, _ => { return Err(Error::with_message_fn(ErrorKind::DataConversion, || { @@ -659,6 +623,7 @@ impl AsRef for ImmutabilityPolicyMode { fn as_ref(&self) -> &str { match self { ImmutabilityPolicyMode::Locked => "locked", + ImmutabilityPolicyMode::Mutable => "mutable", ImmutabilityPolicyMode::Unlocked => "unlocked", } } @@ -668,6 +633,7 @@ impl Display for ImmutabilityPolicyMode { fn fmt(&self, f: &mut Formatter<'_>) -> ::std::fmt::Result { match self { ImmutabilityPolicyMode::Locked => Display::fmt("locked", f), + ImmutabilityPolicyMode::Mutable => Display::fmt("mutable", f), ImmutabilityPolicyMode::Unlocked => Display::fmt("unlocked", f), } } diff --git a/sdk/storage/azure_storage_blob/src/generated/models/enums_serde.rs b/sdk/storage/azure_storage_blob/src/generated/models/enums_serde.rs index 216765cd2e..df6d8aca99 100644 --- a/sdk/storage/azure_storage_blob/src/generated/models/enums_serde.rs +++ b/sdk/storage/azure_storage_blob/src/generated/models/enums_serde.rs @@ -5,12 +5,11 @@ use super::{ AccessTier, AccountKind, ArchiveStatus, BlobCopySourceTags, BlobDeleteType, BlobExpiryOptions, - BlobImmutabilityPolicyMode, BlobType, BlockListType, CopyStatus, DeleteSnapshotsOptionType, - EncryptionAlgorithmType, FileShareTokenIntent, FilterBlobsIncludeItem, - GeoReplicationStatusType, ImmutabilityPolicyMode, LeaseDuration, LeaseState, LeaseStatus, - ListBlobsIncludeItem, ListContainersIncludeType, PremiumPageBlobAccessTier, PublicAccessType, - QueryRequestType, QueryType, RehydratePriority, SequenceNumberActionType, SkuName, - StorageErrorCode, + BlobType, BlockListType, CopyStatus, DeleteSnapshotsOptionType, EncryptionAlgorithmType, + FileShareTokenIntent, FilterBlobsIncludeItem, GeoReplicationStatusType, ImmutabilityPolicyMode, + LeaseDuration, LeaseState, LeaseStatus, ListBlobsIncludeItem, ListContainersIncludeType, + PremiumPageBlobAccessTier, PublicAccessType, QueryRequestType, QueryType, RehydratePriority, + SequenceNumberActionType, SkuName, StorageErrorCode, }; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -128,25 +127,6 @@ impl Serialize for BlobExpiryOptions { } } -impl<'de> Deserialize<'de> for BlobImmutabilityPolicyMode { - fn deserialize(deserializer: D) -> ::core::result::Result - where - D: Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - s.parse().map_err(serde::de::Error::custom) - } -} - -impl Serialize for BlobImmutabilityPolicyMode { - fn serialize(&self, s: S) -> ::core::result::Result - where - S: Serializer, - { - s.serialize_str(self.as_ref()) - } -} - impl<'de> Deserialize<'de> for BlobType { fn deserialize(deserializer: D) -> ::core::result::Result where 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..d1e9b73c74 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 @@ -8,20 +8,19 @@ use super::{ AppendBlobClientCreateResult, AppendBlobClientSealResult, ArchiveStatus, BlobClientAbortCopyFromUrlResult, BlobClientAcquireLeaseResult, BlobClientBreakLeaseResult, BlobClientChangeLeaseResult, BlobClientCopyFromUrlResult, BlobClientCreateSnapshotResult, - BlobClientDeleteImmutabilityPolicyResult, BlobClientDownloadResult, - BlobClientGetAccountInfoResult, BlobClientGetPropertiesResult, BlobClientReleaseLeaseResult, - BlobClientRenewLeaseResult, BlobClientSetExpiryResult, BlobClientSetImmutabilityPolicyResult, + BlobClientDownloadResult, BlobClientGetAccountInfoResult, BlobClientGetPropertiesResult, + BlobClientReleaseLeaseResult, BlobClientRenewLeaseResult, BlobClientSetExpiryResult, BlobClientSetLegalHoldResult, BlobClientStartCopyFromUrlResult, BlobClientUndeleteResult, BlobContainerClientAcquireLeaseResult, BlobContainerClientBreakLeaseResult, BlobContainerClientChangeLeaseResult, BlobContainerClientGetAccountInfoResult, BlobContainerClientGetPropertiesResult, BlobContainerClientReleaseLeaseResult, BlobContainerClientRenameResult, BlobContainerClientRenewLeaseResult, BlobContainerClientRestoreResult, BlobContainerClientSetAccessPolicyResult, - BlobImmutabilityPolicyMode, BlobServiceClientGetAccountInfoResult, BlobTags, BlobType, + BlobServiceClientGetAccountInfoResult, BlobTags, BlobType, BlockBlobClientCommitBlockListResult, BlockBlobClientQueryResult, BlockBlobClientStageBlockFromUrlResult, BlockBlobClientStageBlockResult, BlockBlobClientUploadBlobFromUrlResult, BlockBlobClientUploadResult, BlockList, CopyStatus, - LeaseDuration, LeaseState, LeaseStatus, ListBlobsFlatSegmentResponse, + ImmutabilityPolicyMode, LeaseDuration, LeaseState, LeaseStatus, ListBlobsFlatSegmentResponse, ListBlobsHierarchySegmentResponse, PageBlobClientClearPagesResult, PageBlobClientCopyIncrementalResult, PageBlobClientCreateResult, PageBlobClientResizeResult, PageBlobClientSetSequenceNumberResult, PageBlobClientUploadPagesFromUrlResult, @@ -737,35 +736,6 @@ impl BlobClientCreateSnapshotResultHeaders for Response Result<()> { -/// let response: Response = unimplemented!(); -/// // Access response headers -/// if let Some(date) = response.date()? { -/// println!("Date: {:?}", date); -/// } -/// Ok(()) -/// } -/// ``` -pub trait BlobClientDeleteImmutabilityPolicyResultHeaders: private::Sealed { - fn date(&self) -> Result>; -} - -impl BlobClientDeleteImmutabilityPolicyResultHeaders - 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 `BlobClient::download()` /// /// # Examples @@ -813,7 +783,7 @@ pub trait BlobClientDownloadResultHeaders: private::Sealed { fn creation_time(&self) -> Result>; fn encryption_key_sha256(&self) -> Result>; fn encryption_scope(&self) -> Result>; - fn immutability_policy_mode(&self) -> Result>; + fn immutability_policy_mode(&self) -> Result>; fn immutability_policy_expires_on(&self) -> Result>; fn is_current_version(&self) -> Result>; fn last_accessed(&self) -> Result>; @@ -979,7 +949,7 @@ impl BlobClientDownloadResultHeaders for AsyncResponse } /// Indicates the immutability policy mode of the blob. - fn immutability_policy_mode(&self) -> Result> { + fn immutability_policy_mode(&self) -> Result> { Headers::get_optional_as(self.headers(), &IMMUTABILITY_POLICY_MODE) } @@ -1173,7 +1143,7 @@ pub trait BlobClientGetPropertiesResultHeaders: private::Sealed { fn encryption_key_sha256(&self) -> Result>; fn encryption_scope(&self) -> Result>; fn expires_on(&self) -> Result>; - fn immutability_policy_mode(&self) -> Result>; + fn immutability_policy_mode(&self) -> Result>; fn immutability_policy_expires_on(&self) -> Result>; fn is_incremental_copy(&self) -> Result>; fn is_current_version(&self) -> Result>; @@ -1361,7 +1331,7 @@ impl BlobClientGetPropertiesResultHeaders for Response Result> { + fn immutability_policy_mode(&self) -> Result> { Headers::get_optional_as(self.headers(), &IMMUTABILITY_POLICY_MODE) } @@ -1597,55 +1567,6 @@ impl BlobClientSetExpiryResultHeaders for Response Result<()> { -/// let response: Response = unimplemented!(); -/// // Access response headers -/// if let Some(date) = response.date()? { -/// println!("Date: {:?}", date); -/// } -/// if let Some(immutability_policy_mode) = response.immutability_policy_mode()? { -/// println!("x-ms-immutability-policy-mode: {:?}", immutability_policy_mode); -/// } -/// if let Some(immutability_policy_expires_on) = response.immutability_policy_expires_on()? { -/// println!("x-ms-immutability-policy-until-date: {:?}", immutability_policy_expires_on); -/// } -/// Ok(()) -/// } -/// ``` -pub trait BlobClientSetImmutabilityPolicyResultHeaders: private::Sealed { - fn date(&self) -> Result>; - fn immutability_policy_mode(&self) -> Result>; - fn immutability_policy_expires_on(&self) -> Result>; -} - -impl BlobClientSetImmutabilityPolicyResultHeaders - 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())) - } - - /// Indicates the immutability policy mode of the blob. - fn immutability_policy_mode(&self) -> Result> { - Headers::get_optional_as(self.headers(), &IMMUTABILITY_POLICY_MODE) - } - - /// UTC date/time value generated by the service that indicates the time at which the blob immutability policy will expire. - fn immutability_policy_expires_on(&self) -> Result> { - Headers::get_optional_with(self.headers(), &IMMUTABILITY_POLICY_UNTIL_DATE, |h| { - parse_rfc7231(h.as_str()) - }) - } -} - /// Provides access to typed response headers for `BlobClient::set_legal_hold()` /// /// # Examples @@ -3695,12 +3616,10 @@ mod private { AppendBlobClientAppendBlockFromUrlResult, AppendBlobClientAppendBlockResult, AppendBlobClientCreateResult, AppendBlobClientSealResult, BlobClientAbortCopyFromUrlResult, BlobClientAcquireLeaseResult, BlobClientBreakLeaseResult, BlobClientChangeLeaseResult, - BlobClientCopyFromUrlResult, BlobClientCreateSnapshotResult, - BlobClientDeleteImmutabilityPolicyResult, BlobClientDownloadResult, + BlobClientCopyFromUrlResult, BlobClientCreateSnapshotResult, BlobClientDownloadResult, BlobClientGetAccountInfoResult, BlobClientGetPropertiesResult, BlobClientReleaseLeaseResult, BlobClientRenewLeaseResult, BlobClientSetExpiryResult, - BlobClientSetImmutabilityPolicyResult, BlobClientSetLegalHoldResult, - BlobClientStartCopyFromUrlResult, BlobClientUndeleteResult, + BlobClientSetLegalHoldResult, BlobClientStartCopyFromUrlResult, BlobClientUndeleteResult, BlobContainerClientAcquireLeaseResult, BlobContainerClientBreakLeaseResult, BlobContainerClientChangeLeaseResult, BlobContainerClientGetAccountInfoResult, BlobContainerClientGetPropertiesResult, BlobContainerClientReleaseLeaseResult, @@ -3732,13 +3651,11 @@ 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 {} impl Sealed for Response {} impl Sealed for Response {} - impl Sealed for Response {} impl Sealed for Response {} impl Sealed for Response {} impl Sealed for Response {} diff --git a/sdk/storage/azure_storage_blob/src/generated/models/method_options.rs b/sdk/storage/azure_storage_blob/src/generated/models/method_options.rs index 8bd7ddb93f..a5e744030a 100644 --- a/sdk/storage/azure_storage_blob/src/generated/models/method_options.rs +++ b/sdk/storage/azure_storage_blob/src/generated/models/method_options.rs @@ -781,9 +781,6 @@ pub struct BlobClientSetImmutabilityPolicyOptions<'a> { /// A date-time value. A request is made under the condition that the resource has not been modified since the specified date-time. pub if_unmodified_since: Option, - /// Specifies the date time when the blobs immutability policy is set to expire. - pub immutability_policy_expiry: Option, - /// Specifies the immutability policy mode to set on the blob. pub immutability_policy_mode: Option, 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..56b7a6d41c 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 @@ -9,8 +9,8 @@ use super::{ Blob_tag_setTag, BlobsBlob, Committed_blocksBlock, Container_itemsContainer, CorsCorsRule, SchemaField, Uncommitted_blocksBlock, }, - AccessTier, ArchiveStatus, BlobImmutabilityPolicyMode, BlobType, CopyStatus, - GeoReplicationStatusType, LeaseDuration, LeaseState, LeaseStatus, PublicAccessType, + AccessTier, ArchiveStatus, BlobType, CopyStatus, GeoReplicationStatusType, + ImmutabilityPolicyMode, LeaseDuration, LeaseState, LeaseStatus, PublicAccessType, QueryRequestType, QueryType, RehydratePriority, }; use azure_core::{ @@ -123,10 +123,6 @@ pub struct BlobClientCopyFromUrlResult; #[derive(SafeDebug)] pub struct BlobClientCreateSnapshotResult; -/// Contains results for `BlobClient::delete_immutability_policy()` -#[derive(SafeDebug)] -pub struct BlobClientDeleteImmutabilityPolicyResult; - /// Contains results for `BlobClient::download()` #[derive(SafeDebug)] pub struct BlobClientDownloadResult; @@ -151,10 +147,6 @@ pub struct BlobClientRenewLeaseResult; #[derive(SafeDebug)] pub struct BlobClientSetExpiryResult; -/// Contains results for `BlobClient::set_immutability_policy()` -#[derive(SafeDebug)] -pub struct BlobClientSetImmutabilityPolicyResult; - /// Contains results for `BlobClient::set_legal_hold()` #[derive(SafeDebug)] pub struct BlobClientSetLegalHoldResult; @@ -477,7 +469,7 @@ pub struct BlobPropertiesInternal { rename = "ImmutabilityPolicyMode", skip_serializing_if = "Option::is_none" )] - pub immutability_policy_mode: Option, + pub immutability_policy_mode: Option, /// Whether the blob is incremental copy. #[serde(rename = "IncrementalCopy", skip_serializing_if = "Option::is_none")] diff --git a/sdk/storage/azure_storage_blob/src/models/extensions.rs b/sdk/storage/azure_storage_blob/src/models/extensions.rs index 089fa14d58..6a3a0683db 100644 --- a/sdk/storage/azure_storage_blob/src/models/extensions.rs +++ b/sdk/storage/azure_storage_blob/src/models/extensions.rs @@ -2,9 +2,8 @@ // Licensed under the MIT License. use crate::models::{ - AppendBlobClientCreateOptions, BlobImmutabilityPolicyMode, BlobTag, BlobTags, - BlockBlobClientUploadBlobFromUrlOptions, BlockBlobClientUploadOptions, ImmutabilityPolicyMode, - PageBlobClientCreateOptions, + AppendBlobClientCreateOptions, BlobTag, BlobTags, BlockBlobClientUploadBlobFromUrlOptions, + BlockBlobClientUploadOptions, PageBlobClientCreateOptions, }; use std::collections::HashMap; @@ -109,13 +108,3 @@ impl From> for BlobTags { } } } - -// Converts a `ImmutabilityPolicyMode` into an `BlobImmutabilityPolicyMode`. -impl From for BlobImmutabilityPolicyMode { - fn from(mode: ImmutabilityPolicyMode) -> Self { - match mode { - ImmutabilityPolicyMode::Locked => BlobImmutabilityPolicyMode::Locked, - ImmutabilityPolicyMode::Unlocked => BlobImmutabilityPolicyMode::Unlocked, - } - } -} diff --git a/sdk/storage/azure_storage_blob/src/models/mod.rs b/sdk/storage/azure_storage_blob/src/models/mod.rs index 004ea4586f..aa7460c4ca 100644 --- a/sdk/storage/azure_storage_blob/src/models/mod.rs +++ b/sdk/storage/azure_storage_blob/src/models/mod.rs @@ -17,7 +17,6 @@ pub use crate::generated::models::{ BlobClientChangeLeaseResultHeaders, BlobClientCopyFromUrlResult, BlobClientCopyFromUrlResultHeaders, BlobClientCreateSnapshotResult, BlobClientCreateSnapshotResultHeaders, BlobClientDeleteImmutabilityPolicyOptions, - BlobClientDeleteImmutabilityPolicyResult, BlobClientDeleteImmutabilityPolicyResultHeaders, BlobClientDeleteOptions, BlobClientDownloadOptions, BlobClientDownloadResult, BlobClientDownloadResultHeaders, BlobClientGetAccountInfoOptions, BlobClientGetAccountInfoResult, BlobClientGetAccountInfoResultHeaders, @@ -26,7 +25,6 @@ pub use crate::generated::models::{ BlobClientReleaseLeaseResult, BlobClientReleaseLeaseResultHeaders, BlobClientRenewLeaseOptions, BlobClientRenewLeaseResult, BlobClientRenewLeaseResultHeaders, BlobClientSetExpiryResult, BlobClientSetExpiryResultHeaders, BlobClientSetImmutabilityPolicyOptions, - BlobClientSetImmutabilityPolicyResult, BlobClientSetImmutabilityPolicyResultHeaders, BlobClientSetLegalHoldResult, BlobClientSetLegalHoldResultHeaders, BlobClientSetMetadataOptions, BlobClientSetPropertiesOptions, BlobClientSetTagsOptions, BlobClientSetTierOptions, BlobClientStartCopyFromUrlResult, @@ -48,31 +46,30 @@ pub use crate::generated::models::{ BlobContainerClientRestoreResult, BlobContainerClientRestoreResultHeaders, BlobContainerClientSetAccessPolicyResult, BlobContainerClientSetAccessPolicyResultHeaders, BlobContainerClientSetMetadataOptions, BlobCopySourceTags, BlobDeleteType, BlobExpiryOptions, - BlobFlatListSegment, BlobImmutabilityPolicyMode, BlobItemInternal, BlobMetadata, BlobName, - BlobPropertiesInternal, BlobServiceClientFindBlobsByTagsOptions, - BlobServiceClientGetAccountInfoOptions, BlobServiceClientGetAccountInfoResult, - BlobServiceClientGetAccountInfoResultHeaders, BlobServiceClientGetPropertiesOptions, - BlobServiceClientListContainersSegmentOptions, BlobServiceClientSetPropertiesOptions, - BlobServiceProperties, BlobTag, BlobTags, BlobTagsHeaders, BlobType, Block, - BlockBlobClientCommitBlockListOptions, BlockBlobClientCommitBlockListResult, - BlockBlobClientCommitBlockListResultHeaders, BlockBlobClientGetBlockListOptions, - BlockBlobClientQueryResult, BlockBlobClientQueryResultHeaders, - BlockBlobClientStageBlockFromUrlResult, BlockBlobClientStageBlockFromUrlResultHeaders, - BlockBlobClientStageBlockOptions, BlockBlobClientStageBlockResult, - BlockBlobClientStageBlockResultHeaders, BlockBlobClientUploadBlobFromUrlOptions, - BlockBlobClientUploadBlobFromUrlResult, BlockBlobClientUploadBlobFromUrlResultHeaders, - BlockBlobClientUploadOptions, BlockBlobClientUploadResult, BlockBlobClientUploadResultHeaders, - BlockList, BlockListHeaders, BlockListType, BlockLookupList, ContainerItem, CopyStatus, - CorsRule, DeleteSnapshotsOptionType, EncryptionAlgorithmType, FileShareTokenIntent, - FilterBlobItem, FilterBlobSegment, FilterBlobsIncludeItem, GeoReplicationStatusType, - ImmutabilityPolicyMode, LeaseDuration, LeaseState, LeaseStatus, ListBlobsFlatSegmentResponse, - ListBlobsFlatSegmentResponseHeaders, ListBlobsHierarchySegmentResponse, - ListBlobsHierarchySegmentResponseHeaders, ListBlobsIncludeItem, ListContainersIncludeType, - ListContainersSegmentResponse, Logging, Metrics, ObjectReplicationMetadata, - PageBlobClientClearPagesOptions, PageBlobClientClearPagesResult, - PageBlobClientClearPagesResultHeaders, PageBlobClientCopyIncrementalResult, - PageBlobClientCopyIncrementalResultHeaders, PageBlobClientCreateOptions, - PageBlobClientCreateResult, PageBlobClientCreateResultHeaders, + BlobFlatListSegment, BlobItemInternal, BlobMetadata, BlobName, BlobPropertiesInternal, + BlobServiceClientFindBlobsByTagsOptions, BlobServiceClientGetAccountInfoOptions, + BlobServiceClientGetAccountInfoResult, BlobServiceClientGetAccountInfoResultHeaders, + BlobServiceClientGetPropertiesOptions, BlobServiceClientListContainersSegmentOptions, + BlobServiceClientSetPropertiesOptions, BlobServiceProperties, BlobTag, BlobTags, + BlobTagsHeaders, BlobType, Block, BlockBlobClientCommitBlockListOptions, + BlockBlobClientCommitBlockListResult, BlockBlobClientCommitBlockListResultHeaders, + BlockBlobClientGetBlockListOptions, BlockBlobClientQueryResult, + BlockBlobClientQueryResultHeaders, BlockBlobClientStageBlockFromUrlResult, + BlockBlobClientStageBlockFromUrlResultHeaders, BlockBlobClientStageBlockOptions, + BlockBlobClientStageBlockResult, BlockBlobClientStageBlockResultHeaders, + BlockBlobClientUploadBlobFromUrlOptions, BlockBlobClientUploadBlobFromUrlResult, + BlockBlobClientUploadBlobFromUrlResultHeaders, BlockBlobClientUploadOptions, + BlockBlobClientUploadResult, BlockBlobClientUploadResultHeaders, BlockList, BlockListHeaders, + BlockListType, BlockLookupList, ContainerItem, CopyStatus, CorsRule, DeleteSnapshotsOptionType, + EncryptionAlgorithmType, FileShareTokenIntent, FilterBlobItem, FilterBlobSegment, + FilterBlobsIncludeItem, GeoReplicationStatusType, ImmutabilityPolicyMode, LeaseDuration, + LeaseState, LeaseStatus, ListBlobsFlatSegmentResponse, ListBlobsFlatSegmentResponseHeaders, + ListBlobsHierarchySegmentResponse, ListBlobsHierarchySegmentResponseHeaders, + ListBlobsIncludeItem, ListContainersIncludeType, ListContainersSegmentResponse, Logging, + Metrics, ObjectReplicationMetadata, PageBlobClientClearPagesOptions, + PageBlobClientClearPagesResult, PageBlobClientClearPagesResultHeaders, + PageBlobClientCopyIncrementalResult, PageBlobClientCopyIncrementalResultHeaders, + PageBlobClientCreateOptions, PageBlobClientCreateResult, PageBlobClientCreateResultHeaders, PageBlobClientGetPageRangesOptions, PageBlobClientResizeOptions, PageBlobClientResizeResult, PageBlobClientResizeResultHeaders, PageBlobClientSetSequenceNumberOptions, PageBlobClientSetSequenceNumberResult, PageBlobClientSetSequenceNumberResultHeaders, diff --git a/sdk/storage/azure_storage_blob/tests/blob_client.rs b/sdk/storage/azure_storage_blob/tests/blob_client.rs index 79f1b2e07f..339364245a 100644 --- a/sdk/storage/azure_storage_blob/tests/blob_client.rs +++ b/sdk/storage/azure_storage_blob/tests/blob_client.rs @@ -3,24 +3,25 @@ use azure_core::{ http::{ClientOptions, RequestContent, StatusCode}, - time::OffsetDateTime, + time::{parse_rfc3339, to_rfc3339, OffsetDateTime}, Bytes, }; -use azure_core_test::{recorded, Matcher, TestContext}; +use azure_core_test::{recorded, Matcher, TestContext, VarOptions}; use azure_storage_blob::{ models::{ AccessTier, AccountKind, BlobClientAcquireLeaseResultHeaders, BlobClientChangeLeaseResultHeaders, BlobClientDownloadOptions, BlobClientDownloadResultHeaders, BlobClientGetAccountInfoResultHeaders, BlobClientGetPropertiesOptions, BlobClientGetPropertiesResultHeaders, - BlobClientSetImmutabilityPolicyOptions, BlobClientSetImmutabilityPolicyResultHeaders, - BlobClientSetMetadataOptions, BlobClientSetPropertiesOptions, BlobClientSetTierOptions, - BlobImmutabilityPolicyMode, BlockBlobClientUploadOptions, ImmutabilityPolicyMode, - LeaseState, + BlobClientSetImmutabilityPolicyOptions, BlobClientSetMetadataOptions, + BlobClientSetPropertiesOptions, BlobClientSetTierOptions, BlockBlobClientUploadOptions, + ImmutabilityPolicyMode, LeaseState, }, BlobClient, BlobClientOptions, BlobContainerClient, BlobContainerClientOptions, }; -use azure_storage_blob_test::{create_test_blob, get_blob_name, get_container_client}; +use azure_storage_blob_test::{ + create_test_blob, get_blob_name, get_container_client, use_storage_account, StorageAccount, +}; use futures::TryStreamExt; use std::{collections::HashMap, error::Error, time::Duration}; use tokio::time; @@ -650,37 +651,36 @@ async fn test_encoding_edge_cases(ctx: TestContext) -> Result<(), Box #[recorded::test] async fn test_immutability_policy(ctx: TestContext) -> Result<(), Box> { - //TODO: Point to versioning account, add datetimes to recording variables + //TODO: Mark as playback only once set_legal_hold PR is in // Recording Setup let recording = ctx.recording(); + use_storage_account(StorageAccount::Versioned); let container_client = get_container_client(recording, false).await?; let blob_client = container_client.blob_client(&get_blob_name(recording)); container_client.create_container(None).await?; create_test_blob(&blob_client, None, None).await?; - let test_expiry_time = Some(OffsetDateTime::now_utc() + Duration::from_secs(300)); - let test_immutability_policy_mode = ImmutabilityPolicyMode::Unlocked; - // Set Immutability Policy - let immutability_policy_options = BlobClientSetImmutabilityPolicyOptions { - immutability_policy_expiry: test_expiry_time.clone(), - immutability_policy_mode: Some(test_immutability_policy_mode), - ..Default::default() - }; - let response = blob_client - .set_immutability_policy(Some(immutability_policy_options)) - .await?; + // Set Immutability Policy (No Mode Specified, Default to Unlocked) + let expiry_1_str = recording.var( + "expiry_1", + Some(VarOptions { + default_value: Some( + to_rfc3339(&(OffsetDateTime::now_utc() + Duration::from_secs(5))).into(), + ), + ..Default::default() + }), + ); + let expiry_1 = parse_rfc3339(&expiry_1_str)?; + + blob_client.set_immutability_policy(&expiry_1, None).await?; // Assert + let response = blob_client.get_properties(None).await?; let mode = response.immutability_policy_mode()?; let expires_on = response.immutability_policy_expires_on()?; - - let response_mode: BlobImmutabilityPolicyMode = test_immutability_policy_mode.into(); - assert_eq!(response_mode, mode.unwrap()); + assert_eq!(ImmutabilityPolicyMode::Unlocked, mode.unwrap()); // Need to ignore nanoseconds due to Service truncation - assert_eq!( - test_expiry_time.map(|dt| dt.replace_nanosecond(0).unwrap()), - expires_on - ); + assert_eq!(expiry_1.replace_nanosecond(0)?, expires_on.unwrap()); // Delete Immutability Policy blob_client.delete_immutability_policy(None).await?; @@ -692,5 +692,37 @@ async fn test_immutability_policy(ctx: TestContext) -> Result<(), Box assert!(mode.is_none()); assert!(expires_on.is_none()); + // Set Immutability Policy (Locked Mode) + let expiry_2_str = recording.var( + "expiry_2", + Some(VarOptions { + default_value: Some( + to_rfc3339(&(OffsetDateTime::now_utc() + Duration::from_secs(5))).into(), + ), + ..Default::default() + }), + ); + let expiry_2 = parse_rfc3339(&expiry_2_str)?; + let immutability_policy_options = BlobClientSetImmutabilityPolicyOptions { + immutability_policy_mode: Some(ImmutabilityPolicyMode::Locked), + ..Default::default() + }; + blob_client + .set_immutability_policy(&expiry_2, Some(immutability_policy_options)) + .await?; + + // Assert + let response = blob_client.get_properties(None).await?; + let mode = response.immutability_policy_mode()?; + let expires_on = response.immutability_policy_expires_on()?; + assert_eq!(ImmutabilityPolicyMode::Locked, mode.unwrap()); + // Need to ignore nanoseconds due to Service truncation + assert_eq!(expiry_2.replace_nanosecond(0)?, expires_on.unwrap()); + + // Sleep to allow immutability policy to expire + time::sleep(Duration::from_secs(5)).await; + + blob_client.delete(None).await?; + Ok(()) } diff --git a/sdk/storage/azure_storage_blob/tsp-location.yaml b/sdk/storage/azure_storage_blob/tsp-location.yaml index 3800f8649f..d0e2014108 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: 64da9cf708dfbae0ff9ca2cde6829b123d9966bb +commit: ac380eab6c90329c3d9382989a6b1b6766ed6ec0 repo: Azure/azure-rest-api-specs additionalDirectories: diff --git a/sdk/storage/azure_storage_blob_test/src/lib.rs b/sdk/storage/azure_storage_blob_test/src/lib.rs index 48b88a6f9f..55947ce10d 100644 --- a/sdk/storage/azure_storage_blob_test/src/lib.rs +++ b/sdk/storage/azure_storage_blob_test/src/lib.rs @@ -11,6 +11,46 @@ use azure_storage_blob::{ BlobClient, BlobContainerClient, BlobContainerClientOptions, BlobServiceClient, BlobServiceClientOptions, }; +use std::cell::RefCell; + +/// Specifies which storage account to use for testing. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum StorageAccount { + /// The standard storage account (AZURE_STORAGE_ACCOUNT_NAME) + Standard, + /// The versioned storage account (VERSIONED_AZURE_STORAGE_ACCOUNT_NAME) + Versioned, +} + +// Will use standard Storage account by default. +thread_local! { + static STORAGE_ACCOUNT: RefCell = const { RefCell::new(StorageAccount::Standard) }; +} + +/// Sets the storage account to use for all subsequent test helper function calls in this thread. +/// +/// # Arguments +/// +/// * `account` - The storage account type enum variant to use. +/// +/// # Example +/// +/// ```rust +/// // At the beginning of your test +/// use_storage_account(StorageAccount::Versioned); +/// +/// // All subsequent calls will use the versioned storage account +/// let service_client = get_blob_service_client(recording)?; +/// let container_client = get_container_client(recording, true).await?; +/// ``` +pub fn use_storage_account(account: StorageAccount) { + STORAGE_ACCOUNT.with(|a| *a.borrow_mut() = account); +} + +/// Gets the currently configured storage account for this thread. +fn get_current_storage_account() -> StorageAccount { + STORAGE_ACCOUNT.with(|a| *a.borrow()) +} /// Takes in a Recording instance and returns an instrumented options bag and endpoint. /// @@ -20,9 +60,15 @@ use azure_storage_blob::{ pub fn recorded_test_setup(recording: &Recording) -> (ClientOptions, String) { let mut client_options = ClientOptions::default(); recording.instrument(&mut client_options); + + let account_name_var = match get_current_storage_account() { + StorageAccount::Standard => "AZURE_STORAGE_ACCOUNT_NAME", + StorageAccount::Versioned => "VERSIONED_AZURE_STORAGE_ACCOUNT_NAME", + }; + let endpoint = format!( "https://{}.blob.core.windows.net/", - recording.var("AZURE_STORAGE_ACCOUNT_NAME", None).as_str() + recording.var(account_name_var, None).as_str() ); (client_options, endpoint) From c8552fb723b674d361c0eb77b963bd3369316d59 Mon Sep 17 00:00:00 2001 From: Vincent Tran Date: Tue, 18 Nov 2025 16:14:45 -0800 Subject: [PATCH 4/4] PR feedback rename to expiry --- .../azure_storage_blob/src/clients/blob_client.rs | 7 +++---- .../src/generated/clients/blob_client.rs | 9 +++------ sdk/storage/azure_storage_blob/tsp-location.yaml | 2 +- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/sdk/storage/azure_storage_blob/src/clients/blob_client.rs b/sdk/storage/azure_storage_blob/src/clients/blob_client.rs index e06f720e8d..92b78ec555 100644 --- a/sdk/storage/azure_storage_blob/src/clients/blob_client.rs +++ b/sdk/storage/azure_storage_blob/src/clients/blob_client.rs @@ -443,15 +443,14 @@ impl BlobClient { /// /// # Arguments /// + /// * `expiry` - Specifies the date time when the blobs immutability policy is set to expire. /// * `options` - Optional configuration for the request. pub async fn set_immutability_policy( &self, - immutability_policy_expiry: &OffsetDateTime, + expiry: &OffsetDateTime, options: Option>, ) -> Result> { - self.client - .set_immutability_policy(immutability_policy_expiry, options) - .await + self.client.set_immutability_policy(expiry, options).await } /// Deletes the immutability policy on the blob. 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 f888ab6048..cf01b5bb8a 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 @@ -1530,12 +1530,12 @@ impl BlobClient { /// /// # Arguments /// - /// * `immutability_policy_expiry` - Specifies the date time when the blobs immutability policy is set to expire. + /// * `expiry` - Specifies the date time when the blobs immutability policy is set to expire. /// * `options` - Optional parameters for the request. #[tracing::function("Storage.Blob.Blob.setImmutabilityPolicy")] pub async fn set_immutability_policy( &self, - immutability_policy_expiry: &OffsetDateTime, + expiry: &OffsetDateTime, options: Option>, ) -> Result> { let options = options.unwrap_or_default(); @@ -1564,10 +1564,7 @@ impl BlobClient { immutability_policy_mode.to_string(), ); } - request.insert_header( - "x-ms-immutability-policy-until-date", - to_rfc7231(immutability_policy_expiry), - ); + request.insert_header("x-ms-immutability-policy-until-date", to_rfc7231(expiry)); request.insert_header("x-ms-version", &self.version); let rsp = self .pipeline diff --git a/sdk/storage/azure_storage_blob/tsp-location.yaml b/sdk/storage/azure_storage_blob/tsp-location.yaml index d0e2014108..c64c399001 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: ac380eab6c90329c3d9382989a6b1b6766ed6ec0 +commit: d4b481872fcf0e42901cb1c4ab01a3ce6c4772a6 repo: Azure/azure-rest-api-specs additionalDirectories: