diff --git a/sdk/storage/Azure.Storage.Blobs.Batch/CHANGELOG.md b/sdk/storage/Azure.Storage.Blobs.Batch/CHANGELOG.md index 535e674ac9de3..91634cac36c86 100644 --- a/sdk/storage/Azure.Storage.Blobs.Batch/CHANGELOG.md +++ b/sdk/storage/Azure.Storage.Blobs.Batch/CHANGELOG.md @@ -1,14 +1,7 @@ # Release History ## 12.18.0-beta.1 (Unreleased) - -### Features Added - -### Breaking Changes - -### Bugs Fixed - -### Other Changes +- Added support for service version 2024-08-04. ## 12.17.0 (2024-05-15) - Includes all features from 12.17.0-beta.1 and 12.17.0-beta.2. diff --git a/sdk/storage/Azure.Storage.Blobs.Batch/assets.json b/sdk/storage/Azure.Storage.Blobs.Batch/assets.json index 89cecd7ab6127..a82847cd8dacf 100644 --- a/sdk/storage/Azure.Storage.Blobs.Batch/assets.json +++ b/sdk/storage/Azure.Storage.Blobs.Batch/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "net", "TagPrefix": "net/storage/Azure.Storage.Blobs.Batch", - "Tag": "net/storage/Azure.Storage.Blobs.Batch_df2c3bed41" + "Tag": "net/storage/Azure.Storage.Blobs.Batch_34b0b578dc" } diff --git a/sdk/storage/Azure.Storage.Blobs.ChangeFeed/CHANGELOG.md b/sdk/storage/Azure.Storage.Blobs.ChangeFeed/CHANGELOG.md index 5e5374664728c..5958418c9e9a6 100644 --- a/sdk/storage/Azure.Storage.Blobs.ChangeFeed/CHANGELOG.md +++ b/sdk/storage/Azure.Storage.Blobs.ChangeFeed/CHANGELOG.md @@ -1,14 +1,7 @@ # Release History ## 12.0.0-preview.45 (Unreleased) - -### Features Added - -### Breaking Changes - -### Bugs Fixed - -### Other Changes +- Added support for service version 2024-08-04. ## 12.0.0-preview.44 (2024-05-13) - This release contains bug fixes to improve quality. diff --git a/sdk/storage/Azure.Storage.Blobs.ChangeFeed/tests/ChangeFeedTestBase.cs b/sdk/storage/Azure.Storage.Blobs.ChangeFeed/tests/ChangeFeedTestBase.cs index 83323a9a2fbfd..d41bd8539b214 100644 --- a/sdk/storage/Azure.Storage.Blobs.ChangeFeed/tests/ChangeFeedTestBase.cs +++ b/sdk/storage/Azure.Storage.Blobs.ChangeFeed/tests/ChangeFeedTestBase.cs @@ -30,6 +30,7 @@ namespace Azure.Storage.Blobs.ChangeFeed.Tests BlobClientOptions.ServiceVersion.V2023_11_03, BlobClientOptions.ServiceVersion.V2024_02_04, BlobClientOptions.ServiceVersion.V2024_05_04, + BlobClientOptions.ServiceVersion.V2024_08_04, StorageVersionExtensions.LatestVersion, StorageVersionExtensions.MaxVersion, RecordingServiceVersion = StorageVersionExtensions.MaxVersion, diff --git a/sdk/storage/Azure.Storage.Blobs/CHANGELOG.md b/sdk/storage/Azure.Storage.Blobs/CHANGELOG.md index e29b41aa1cc38..05ac7d99c99d9 100644 --- a/sdk/storage/Azure.Storage.Blobs/CHANGELOG.md +++ b/sdk/storage/Azure.Storage.Blobs/CHANGELOG.md @@ -1,14 +1,10 @@ # Release History ## 12.21.0-beta.1 (Unreleased) - -### Features Added - -### Breaking Changes - -### Bugs Fixed - -### Other Changes +- Added support for service version 2024-08-04. +- Added BlobContainerClient.GetAccountInfo(), .GetAccountInfoAsync(), BlobBaseClient.GetAccountInfo(), and .GetAccountInfoAsync() APIs. +- Added more detailed messaging for blob copy operations resulting in an error. +- Added more detailed messaging for authorization failure cases. ## 12.20.0 (2024-05-13) - Includes all features from 12.20.0-beta.1 and 12.20.0-beta.2. diff --git a/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.net6.0.cs b/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.net6.0.cs index 2e1a79f257e4e..0cd2740a4b1c1 100644 --- a/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.net6.0.cs +++ b/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.net6.0.cs @@ -85,6 +85,7 @@ public enum ServiceVersion V2023_11_03 = 20, V2024_02_04 = 21, V2024_05_04 = 22, + V2024_08_04 = 23, } } public partial class BlobContainerClient @@ -132,6 +133,8 @@ public BlobContainerClient(System.Uri blobContainerUri, Azure.Storage.StorageSha public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.BlobSasBuilder builder) { throw null; } public virtual Azure.Response GetAccessPolicy(Azure.Storage.Blobs.Models.BlobRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Threading.Tasks.Task> GetAccessPolicyAsync(Azure.Storage.Blobs.Models.BlobRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response GetAccountInfo(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> GetAccountInfoAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } protected internal virtual Azure.Storage.Blobs.Specialized.AppendBlobClient GetAppendBlobClientCore(string blobName) { throw null; } protected internal virtual Azure.Storage.Blobs.Specialized.BlobBaseClient GetBlobBaseClientCore(string blobName) { throw null; } public virtual Azure.Storage.Blobs.BlobClient GetBlobClient(string blobName) { throw null; } @@ -1617,6 +1620,8 @@ public BlobBaseClient(System.Uri blobUri, Azure.Storage.StorageSharedKeyCredenti public virtual System.Threading.Tasks.Task> ExistsAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.BlobSasBuilder builder) { throw null; } public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.BlobSasPermissions permissions, System.DateTimeOffset expiresOn) { throw null; } + public virtual Azure.Response GetAccountInfo(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> GetAccountInfoAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } protected internal virtual Azure.Storage.Blobs.Specialized.BlobLeaseClient GetBlobLeaseClientCore(string leaseId) { throw null; } protected static System.Threading.Tasks.Task GetCopyAuthorizationHeaderAsync(Azure.Storage.Blobs.Specialized.BlobBaseClient client, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } protected internal virtual Azure.Storage.Blobs.BlobContainerClient GetParentBlobContainerClientCore() { throw null; } diff --git a/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.0.cs b/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.0.cs index 2e1a79f257e4e..0cd2740a4b1c1 100644 --- a/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.0.cs +++ b/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.0.cs @@ -85,6 +85,7 @@ public enum ServiceVersion V2023_11_03 = 20, V2024_02_04 = 21, V2024_05_04 = 22, + V2024_08_04 = 23, } } public partial class BlobContainerClient @@ -132,6 +133,8 @@ public BlobContainerClient(System.Uri blobContainerUri, Azure.Storage.StorageSha public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.BlobSasBuilder builder) { throw null; } public virtual Azure.Response GetAccessPolicy(Azure.Storage.Blobs.Models.BlobRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Threading.Tasks.Task> GetAccessPolicyAsync(Azure.Storage.Blobs.Models.BlobRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response GetAccountInfo(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> GetAccountInfoAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } protected internal virtual Azure.Storage.Blobs.Specialized.AppendBlobClient GetAppendBlobClientCore(string blobName) { throw null; } protected internal virtual Azure.Storage.Blobs.Specialized.BlobBaseClient GetBlobBaseClientCore(string blobName) { throw null; } public virtual Azure.Storage.Blobs.BlobClient GetBlobClient(string blobName) { throw null; } @@ -1617,6 +1620,8 @@ public BlobBaseClient(System.Uri blobUri, Azure.Storage.StorageSharedKeyCredenti public virtual System.Threading.Tasks.Task> ExistsAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.BlobSasBuilder builder) { throw null; } public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.BlobSasPermissions permissions, System.DateTimeOffset expiresOn) { throw null; } + public virtual Azure.Response GetAccountInfo(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> GetAccountInfoAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } protected internal virtual Azure.Storage.Blobs.Specialized.BlobLeaseClient GetBlobLeaseClientCore(string leaseId) { throw null; } protected static System.Threading.Tasks.Task GetCopyAuthorizationHeaderAsync(Azure.Storage.Blobs.Specialized.BlobBaseClient client, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } protected internal virtual Azure.Storage.Blobs.BlobContainerClient GetParentBlobContainerClientCore() { throw null; } diff --git a/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.1.cs b/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.1.cs index 2e1a79f257e4e..0cd2740a4b1c1 100644 --- a/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.1.cs +++ b/sdk/storage/Azure.Storage.Blobs/api/Azure.Storage.Blobs.netstandard2.1.cs @@ -85,6 +85,7 @@ public enum ServiceVersion V2023_11_03 = 20, V2024_02_04 = 21, V2024_05_04 = 22, + V2024_08_04 = 23, } } public partial class BlobContainerClient @@ -132,6 +133,8 @@ public BlobContainerClient(System.Uri blobContainerUri, Azure.Storage.StorageSha public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.BlobSasBuilder builder) { throw null; } public virtual Azure.Response GetAccessPolicy(Azure.Storage.Blobs.Models.BlobRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Threading.Tasks.Task> GetAccessPolicyAsync(Azure.Storage.Blobs.Models.BlobRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response GetAccountInfo(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> GetAccountInfoAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } protected internal virtual Azure.Storage.Blobs.Specialized.AppendBlobClient GetAppendBlobClientCore(string blobName) { throw null; } protected internal virtual Azure.Storage.Blobs.Specialized.BlobBaseClient GetBlobBaseClientCore(string blobName) { throw null; } public virtual Azure.Storage.Blobs.BlobClient GetBlobClient(string blobName) { throw null; } @@ -1617,6 +1620,8 @@ public BlobBaseClient(System.Uri blobUri, Azure.Storage.StorageSharedKeyCredenti public virtual System.Threading.Tasks.Task> ExistsAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.BlobSasBuilder builder) { throw null; } public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.BlobSasPermissions permissions, System.DateTimeOffset expiresOn) { throw null; } + public virtual Azure.Response GetAccountInfo(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> GetAccountInfoAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } protected internal virtual Azure.Storage.Blobs.Specialized.BlobLeaseClient GetBlobLeaseClientCore(string leaseId) { throw null; } protected static System.Threading.Tasks.Task GetCopyAuthorizationHeaderAsync(Azure.Storage.Blobs.Specialized.BlobBaseClient client, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } protected internal virtual Azure.Storage.Blobs.BlobContainerClient GetParentBlobContainerClientCore() { throw null; } diff --git a/sdk/storage/Azure.Storage.Blobs/assets.json b/sdk/storage/Azure.Storage.Blobs/assets.json index 223607dd9566b..ed50b4446fc0d 100644 --- a/sdk/storage/Azure.Storage.Blobs/assets.json +++ b/sdk/storage/Azure.Storage.Blobs/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "net", "TagPrefix": "net/storage/Azure.Storage.Blobs", - "Tag": "net/storage/Azure.Storage.Blobs_142f6b4d45" + "Tag": "net/storage/Azure.Storage.Blobs_62a8c8fa29" } diff --git a/sdk/storage/Azure.Storage.Blobs/src/BlobBaseClient.cs b/sdk/storage/Azure.Storage.Blobs/src/BlobBaseClient.cs index 9b6e85553a1a9..91805476dc387 100644 --- a/sdk/storage/Azure.Storage.Blobs/src/BlobBaseClient.cs +++ b/sdk/storage/Azure.Storage.Blobs/src/BlobBaseClient.cs @@ -6530,6 +6530,127 @@ private async Task> SetLegalHoldInternal( } #endregion + #region GetAccountInfo + /// + /// The operation returns the sku + /// name and account kind for the specified account. + /// + /// For more information, see + /// + /// Get Account Information. + /// + /// + /// Optional to propagate + /// notifications that the operation should be cancelled. + /// + /// + /// A describing the account. + /// + /// + /// A will be thrown if + /// a failure occurs. + /// + public virtual Response GetAccountInfo( + CancellationToken cancellationToken = default) => + GetAccountInfoInternal( + false, // async + cancellationToken) + .EnsureCompleted(); + + /// + /// The operation returns the sku + /// name and account kind for the specified account. + /// + /// For more information, see + /// + /// Get Account Information. + /// + /// + /// Optional to propagate + /// notifications that the operation should be cancelled. + /// + /// + /// A describing the account. + /// + /// + /// A will be thrown if + /// a failure occurs. + /// + public virtual async Task> GetAccountInfoAsync( + CancellationToken cancellationToken = default) => + await GetAccountInfoInternal( + true, // async + cancellationToken) + .ConfigureAwait(false); + + /// + /// The operation returns the sku + /// name and account kind for the specified account. + /// + /// For more information, see + /// + /// Get Account Information. + /// + /// + /// Whether to invoke the operation asynchronously. + /// + /// + /// Optional to propagate + /// notifications that the operation should be cancelled. + /// + /// + /// A describing the account. + /// + /// + /// A will be thrown if + /// a failure occurs. + /// + private async Task> GetAccountInfoInternal( + bool async, + CancellationToken cancellationToken) + { + using (ClientConfiguration.Pipeline.BeginLoggingScope(nameof(BlobBaseClient))) + { + ClientConfiguration.Pipeline.LogMethodEnter(nameof(BlobBaseClient), message: $"{nameof(Uri)}: {Uri}"); + + DiagnosticScope scope = ClientConfiguration.ClientDiagnostics.CreateScope($"{nameof(BlobBaseClient)}.{nameof(GetAccountInfo)}"); + + try + { + scope.Start(); + ResponseWithHeaders response; + + if (async) + { + response = await BlobRestClient.GetAccountInfoAsync( + cancellationToken: cancellationToken) + .ConfigureAwait(false); + } + else + { + response = BlobRestClient.GetAccountInfo( + cancellationToken: cancellationToken); + } + + return Response.FromValue( + response.ToAccountInfo(), + response.GetRawResponse()); + } + catch (Exception ex) + { + ClientConfiguration.Pipeline.LogException(ex); + scope.Failed(ex); + throw; + } + finally + { + ClientConfiguration.Pipeline.LogMethodExit(nameof(BlobServiceClient)); + scope.Dispose(); + } + } + } + #endregion GetAccountInfo + #region GenerateSas /// /// The diff --git a/sdk/storage/Azure.Storage.Blobs/src/BlobClientOptions.cs b/sdk/storage/Azure.Storage.Blobs/src/BlobClientOptions.cs index c2dae15976fa6..a678a0afd38ba 100644 --- a/sdk/storage/Azure.Storage.Blobs/src/BlobClientOptions.cs +++ b/sdk/storage/Azure.Storage.Blobs/src/BlobClientOptions.cs @@ -141,7 +141,12 @@ public enum ServiceVersion /// /// The 2024-05-04 service version. /// - V2024_05_04 = 22 + V2024_05_04 = 22, + + /// + /// The 2024-08-04 service version. + /// + V2024_08_04 = 23 #pragma warning restore CA1707 // Identifiers should not contain underscores } @@ -301,6 +306,8 @@ private void AddHeadersAndQueryParameters() Diagnostics.LoggedHeaderNames.Add("x-ms-source-if-unmodified-since"); Diagnostics.LoggedHeaderNames.Add("x-ms-tag-count"); Diagnostics.LoggedHeaderNames.Add("x-ms-encryption-key-sha256"); + Diagnostics.LoggedHeaderNames.Add("x-ms-copy-source-error-code"); + Diagnostics.LoggedHeaderNames.Add("x-ms-copy-source-status-code"); Diagnostics.LoggedQueryParameters.Add("comp"); Diagnostics.LoggedQueryParameters.Add("maxresults"); diff --git a/sdk/storage/Azure.Storage.Blobs/src/BlobContainerClient.cs b/sdk/storage/Azure.Storage.Blobs/src/BlobContainerClient.cs index f44cc2c593a64..b432ff9fa057e 100644 --- a/sdk/storage/Azure.Storage.Blobs/src/BlobContainerClient.cs +++ b/sdk/storage/Azure.Storage.Blobs/src/BlobContainerClient.cs @@ -3550,6 +3550,127 @@ internal async Task> FindBlobsByTagsInternal( } #endregion FilterBlobs + #region GetAccountInfo + /// + /// The operation returns the sku + /// name and account kind for the specified account. + /// + /// For more information, see + /// + /// Get Account Information. + /// + /// + /// Optional to propagate + /// notifications that the operation should be cancelled. + /// + /// + /// A describing the account. + /// + /// + /// A will be thrown if + /// a failure occurs. + /// + public virtual Response GetAccountInfo( + CancellationToken cancellationToken = default) => + GetAccountInfoInternal( + false, // async + cancellationToken) + .EnsureCompleted(); + + /// + /// The operation returns the sku + /// name and account kind for the specified account. + /// + /// For more information, see + /// + /// Get Account Information. + /// + /// + /// Optional to propagate + /// notifications that the operation should be cancelled. + /// + /// + /// A describing the account. + /// + /// + /// A will be thrown if + /// a failure occurs. + /// + public virtual async Task> GetAccountInfoAsync( + CancellationToken cancellationToken = default) => + await GetAccountInfoInternal( + true, // async + cancellationToken) + .ConfigureAwait(false); + + /// + /// The operation returns the sku + /// name and account kind for the specified account. + /// + /// For more information, see + /// + /// Get Account Information. + /// + /// + /// Whether to invoke the operation asynchronously. + /// + /// + /// Optional to propagate + /// notifications that the operation should be cancelled. + /// + /// + /// A describing the account. + /// + /// + /// A will be thrown if + /// a failure occurs. + /// + private async Task> GetAccountInfoInternal( + bool async, + CancellationToken cancellationToken) + { + using (ClientConfiguration.Pipeline.BeginLoggingScope(nameof(BlobServiceClient))) + { + ClientConfiguration.Pipeline.LogMethodEnter(nameof(BlobServiceClient), message: $"{nameof(Uri)}: {Uri}"); + + DiagnosticScope scope = ClientConfiguration.ClientDiagnostics.CreateScope($"{nameof(BlobContainerClient)}.{nameof(GetAccountInfo)}"); + + try + { + scope.Start(); + ResponseWithHeaders response; + + if (async) + { + response = await ContainerRestClient.GetAccountInfoAsync( + cancellationToken: cancellationToken) + .ConfigureAwait(false); + } + else + { + response = ContainerRestClient.GetAccountInfo( + cancellationToken: cancellationToken); + } + + return Response.FromValue( + response.ToAccountInfo(), + response.GetRawResponse()); + } + catch (Exception ex) + { + ClientConfiguration.Pipeline.LogException(ex); + scope.Failed(ex); + throw; + } + finally + { + ClientConfiguration.Pipeline.LogMethodExit(nameof(BlobServiceClient)); + scope.Dispose(); + } + } + } + #endregion GetAccountInfo + #region GenerateSas /// /// The diff --git a/sdk/storage/Azure.Storage.Blobs/src/BlobExtensions.cs b/sdk/storage/Azure.Storage.Blobs/src/BlobExtensions.cs index a4f7a470989ee..a82a7be5eb7ed 100644 --- a/sdk/storage/Azure.Storage.Blobs/src/BlobExtensions.cs +++ b/sdk/storage/Azure.Storage.Blobs/src/BlobExtensions.cs @@ -245,6 +245,34 @@ internal static AccountInfo ToAccountInfo(this ResponseWithHeaders response) + { + if (response == null) + { + return null; + } + return new AccountInfo + { + SkuName = response.Headers.SkuName.GetValueOrDefault(), + AccountKind = response.Headers.AccountKind.GetValueOrDefault(), + IsHierarchicalNamespaceEnabled = response.Headers.IsHierarchicalNamespaceEnabled.GetValueOrDefault() + }; + } + + internal static AccountInfo ToAccountInfo(this ResponseWithHeaders response) + { + if (response == null) + { + return null; + } + return new AccountInfo + { + SkuName = response.Headers.SkuName.GetValueOrDefault(), + AccountKind = response.Headers.AccountKind.GetValueOrDefault(), + IsHierarchicalNamespaceEnabled = response.Headers.IsHierarchicalNamespaceEnabled.GetValueOrDefault() + }; + } #endregion #region ToBlobContainerInfo diff --git a/sdk/storage/Azure.Storage.Blobs/src/Generated/AppendBlobRestClient.cs b/sdk/storage/Azure.Storage.Blobs/src/Generated/AppendBlobRestClient.cs index a6ea23fa34fc1..88104aa95bb00 100644 --- a/sdk/storage/Azure.Storage.Blobs/src/Generated/AppendBlobRestClient.cs +++ b/sdk/storage/Azure.Storage.Blobs/src/Generated/AppendBlobRestClient.cs @@ -29,7 +29,7 @@ internal partial class AppendBlobRestClient /// The handler for diagnostic messaging in the client. /// The HTTP pipeline for sending and receiving REST requests and responses. /// The URL of the service account, container, or blob that is the target of the desired operation. - /// Specifies the version of the operation to use for this request. The default value is "2021-12-02". + /// Specifies the version of the operation to use for this request. The default value is "2024-08-04". /// , , or is null. public AppendBlobRestClient(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, string url, string version) { diff --git a/sdk/storage/Azure.Storage.Blobs/src/Generated/BlobGetAccountInfoHeaders.cs b/sdk/storage/Azure.Storage.Blobs/src/Generated/BlobGetAccountInfoHeaders.cs new file mode 100644 index 0000000000000..a65871dcee3a6 --- /dev/null +++ b/sdk/storage/Azure.Storage.Blobs/src/Generated/BlobGetAccountInfoHeaders.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using Azure.Core; +using Azure.Storage.Blobs.Models; + +namespace Azure.Storage.Blobs +{ + internal partial class BlobGetAccountInfoHeaders + { + private readonly Response _response; + public BlobGetAccountInfoHeaders(Response response) + { + _response = response; + } + /// Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above. + public string Version => _response.Headers.TryGetValue("x-ms-version", out string value) ? value : null; + /// Identifies the sku name of the account. + public SkuName? SkuName => _response.Headers.TryGetValue("x-ms-sku-name", out string value) ? value.ToSkuName() : null; + /// Identifies the account kind. + public AccountKind? AccountKind => _response.Headers.TryGetValue("x-ms-account-kind", out string value) ? value.ToAccountKind() : null; + /// Version 2019-07-07 and newer. Indicates if the account has a hierarchical namespace enabled. + public bool? IsHierarchicalNamespaceEnabled => _response.Headers.TryGetValue("x-ms-is-hns-enabled", out bool? value) ? value : null; + } +} diff --git a/sdk/storage/Azure.Storage.Blobs/src/Generated/BlobRestClient.cs b/sdk/storage/Azure.Storage.Blobs/src/Generated/BlobRestClient.cs index cc34ecc39c24b..615257741b781 100644 --- a/sdk/storage/Azure.Storage.Blobs/src/Generated/BlobRestClient.cs +++ b/sdk/storage/Azure.Storage.Blobs/src/Generated/BlobRestClient.cs @@ -30,7 +30,7 @@ internal partial class BlobRestClient /// The handler for diagnostic messaging in the client. /// The HTTP pipeline for sending and receiving REST requests and responses. /// The URL of the service account, container, or blob that is the target of the desired operation. - /// Specifies the version of the operation to use for this request. The default value is "2021-12-02". + /// Specifies the version of the operation to use for this request. The default value is "2024-08-04". /// , , or is null. public BlobRestClient(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, string url, string version) { @@ -2311,6 +2311,59 @@ public ResponseWithHeaders SetTier(AccessTier tier, string s } } + internal HttpMessage CreateGetAccountInfoRequest(int? timeout) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.AppendRaw(_url, false); + uri.AppendQuery("restype", "account", true); + uri.AppendQuery("comp", "properties", true); + if (timeout != null) + { + uri.AppendQuery("timeout", timeout.Value, true); + } + request.Uri = uri; + request.Headers.Add("x-ms-version", _version); + request.Headers.Add("Accept", "application/xml"); + return message; + } + + /// Returns the sku name and account kind. + /// The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + /// The cancellation token to use. + public async Task> GetAccountInfoAsync(int? timeout = null, CancellationToken cancellationToken = default) + { + using var message = CreateGetAccountInfoRequest(timeout); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + var headers = new BlobGetAccountInfoHeaders(message.Response); + switch (message.Response.Status) + { + case 200: + return ResponseWithHeaders.FromValue(headers, message.Response); + default: + throw new RequestFailedException(message.Response); + } + } + + /// Returns the sku name and account kind. + /// The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + /// The cancellation token to use. + public ResponseWithHeaders GetAccountInfo(int? timeout = null, CancellationToken cancellationToken = default) + { + using var message = CreateGetAccountInfoRequest(timeout); + _pipeline.Send(message, cancellationToken); + var headers = new BlobGetAccountInfoHeaders(message.Response); + switch (message.Response.Status) + { + case 200: + return ResponseWithHeaders.FromValue(headers, message.Response); + default: + throw new RequestFailedException(message.Response); + } + } + internal HttpMessage CreateQueryRequest(string snapshot, int? timeout, string leaseId, string encryptionKey, string encryptionKeySha256, EncryptionAlgorithmTypeInternal? encryptionAlgorithm, DateTimeOffset? ifModifiedSince, DateTimeOffset? ifUnmodifiedSince, string ifMatch, string ifNoneMatch, string ifTags, QueryRequest queryRequest) { var message = _pipeline.CreateMessage(); diff --git a/sdk/storage/Azure.Storage.Blobs/src/Generated/BlockBlobRestClient.cs b/sdk/storage/Azure.Storage.Blobs/src/Generated/BlockBlobRestClient.cs index 960152859ec7c..0723c07204ac2 100644 --- a/sdk/storage/Azure.Storage.Blobs/src/Generated/BlockBlobRestClient.cs +++ b/sdk/storage/Azure.Storage.Blobs/src/Generated/BlockBlobRestClient.cs @@ -30,7 +30,7 @@ internal partial class BlockBlobRestClient /// The handler for diagnostic messaging in the client. /// The HTTP pipeline for sending and receiving REST requests and responses. /// The URL of the service account, container, or blob that is the target of the desired operation. - /// Specifies the version of the operation to use for this request. The default value is "2021-12-02". + /// Specifies the version of the operation to use for this request. The default value is "2024-08-04". /// , , or is null. public BlockBlobRestClient(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, string url, string version) { diff --git a/sdk/storage/Azure.Storage.Blobs/src/Generated/ContainerGetAccountInfoHeaders.cs b/sdk/storage/Azure.Storage.Blobs/src/Generated/ContainerGetAccountInfoHeaders.cs new file mode 100644 index 0000000000000..19f1d2b517540 --- /dev/null +++ b/sdk/storage/Azure.Storage.Blobs/src/Generated/ContainerGetAccountInfoHeaders.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using Azure.Core; +using Azure.Storage.Blobs.Models; + +namespace Azure.Storage.Blobs +{ + internal partial class ContainerGetAccountInfoHeaders + { + private readonly Response _response; + public ContainerGetAccountInfoHeaders(Response response) + { + _response = response; + } + /// Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above. + public string Version => _response.Headers.TryGetValue("x-ms-version", out string value) ? value : null; + /// Identifies the sku name of the account. + public SkuName? SkuName => _response.Headers.TryGetValue("x-ms-sku-name", out string value) ? value.ToSkuName() : null; + /// Identifies the account kind. + public AccountKind? AccountKind => _response.Headers.TryGetValue("x-ms-account-kind", out string value) ? value.ToAccountKind() : null; + /// Version 2019-07-07 and newer. Indicates if the account has a hierarchical namespace enabled. + public bool? IsHierarchicalNamespaceEnabled => _response.Headers.TryGetValue("x-ms-is-hns-enabled", out bool? value) ? value : null; + } +} diff --git a/sdk/storage/Azure.Storage.Blobs/src/Generated/ContainerRestClient.cs b/sdk/storage/Azure.Storage.Blobs/src/Generated/ContainerRestClient.cs index 8d763cbd51073..024bfecd4e90b 100644 --- a/sdk/storage/Azure.Storage.Blobs/src/Generated/ContainerRestClient.cs +++ b/sdk/storage/Azure.Storage.Blobs/src/Generated/ContainerRestClient.cs @@ -31,7 +31,7 @@ internal partial class ContainerRestClient /// The handler for diagnostic messaging in the client. /// The HTTP pipeline for sending and receiving REST requests and responses. /// The URL of the service account, container, or blob that is the target of the desired operation. - /// Specifies the version of the operation to use for this request. The default value is "2021-12-02". + /// Specifies the version of the operation to use for this request. The default value is "2024-08-04". /// , , or is null. public ContainerRestClient(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, string url, string version) { @@ -1524,6 +1524,59 @@ public ResponseWithHeaders Returns the sku name and account kind. + /// The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + /// The cancellation token to use. + public async Task> GetAccountInfoAsync(int? timeout = null, CancellationToken cancellationToken = default) + { + using var message = CreateGetAccountInfoRequest(timeout); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + var headers = new ContainerGetAccountInfoHeaders(message.Response); + switch (message.Response.Status) + { + case 200: + return ResponseWithHeaders.FromValue(headers, message.Response); + default: + throw new RequestFailedException(message.Response); + } + } + + /// Returns the sku name and account kind. + /// The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. + /// The cancellation token to use. + public ResponseWithHeaders GetAccountInfo(int? timeout = null, CancellationToken cancellationToken = default) + { + using var message = CreateGetAccountInfoRequest(timeout); + _pipeline.Send(message, cancellationToken); + var headers = new ContainerGetAccountInfoHeaders(message.Response); + switch (message.Response.Status) + { + case 200: + return ResponseWithHeaders.FromValue(headers, message.Response); + default: + throw new RequestFailedException(message.Response); + } + } + internal HttpMessage CreateListBlobFlatSegmentNextPageRequest(string nextLink, string prefix, string marker, int? maxresults, IEnumerable include, int? timeout) { var message = _pipeline.CreateMessage(); diff --git a/sdk/storage/Azure.Storage.Blobs/src/Generated/Models/StorageError.Serialization.cs b/sdk/storage/Azure.Storage.Blobs/src/Generated/Models/StorageError.Serialization.cs index 6b3203194ba9f..ad3a7c8008cc2 100644 --- a/sdk/storage/Azure.Storage.Blobs/src/Generated/Models/StorageError.Serialization.cs +++ b/sdk/storage/Azure.Storage.Blobs/src/Generated/Models/StorageError.Serialization.cs @@ -14,11 +14,26 @@ internal partial class StorageError internal static StorageError DeserializeStorageError(XElement element) { string message = default; + long? copySourceStatusCode = default; + string copySourceErrorCode = default; + string copySourceErrorMessage = default; if (element.Element("Message") is XElement messageElement) { message = (string)messageElement; } - return new StorageError(message); + if (element.Element("CopySourceStatusCode") is XElement copySourceStatusCodeElement) + { + copySourceStatusCode = (long?)copySourceStatusCodeElement; + } + if (element.Element("CopySourceErrorCode") is XElement copySourceErrorCodeElement) + { + copySourceErrorCode = (string)copySourceErrorCodeElement; + } + if (element.Element("CopySourceErrorMessage") is XElement copySourceErrorMessageElement) + { + copySourceErrorMessage = (string)copySourceErrorMessageElement; + } + return new StorageError(message, copySourceStatusCode, copySourceErrorCode, copySourceErrorMessage); } } } diff --git a/sdk/storage/Azure.Storage.Blobs/src/Generated/Models/StorageError.cs b/sdk/storage/Azure.Storage.Blobs/src/Generated/Models/StorageError.cs index 4b0d8038c2e79..45d235870e081 100644 --- a/sdk/storage/Azure.Storage.Blobs/src/Generated/Models/StorageError.cs +++ b/sdk/storage/Azure.Storage.Blobs/src/Generated/Models/StorageError.cs @@ -17,12 +17,24 @@ internal StorageError() /// Initializes a new instance of . /// - internal StorageError(string message) + /// + /// + /// + internal StorageError(string message, long? copySourceStatusCode, string copySourceErrorCode, string copySourceErrorMessage) { Message = message; + CopySourceStatusCode = copySourceStatusCode; + CopySourceErrorCode = copySourceErrorCode; + CopySourceErrorMessage = copySourceErrorMessage; } /// Gets the message. public string Message { get; } + /// Gets the copy source status code. + public long? CopySourceStatusCode { get; } + /// Gets the copy source error code. + public string CopySourceErrorCode { get; } + /// Gets the copy source error message. + public string CopySourceErrorMessage { get; } } } diff --git a/sdk/storage/Azure.Storage.Blobs/src/Generated/PageBlobRestClient.cs b/sdk/storage/Azure.Storage.Blobs/src/Generated/PageBlobRestClient.cs index 685f21e4a5f9e..260d8021543e2 100644 --- a/sdk/storage/Azure.Storage.Blobs/src/Generated/PageBlobRestClient.cs +++ b/sdk/storage/Azure.Storage.Blobs/src/Generated/PageBlobRestClient.cs @@ -30,7 +30,7 @@ internal partial class PageBlobRestClient /// The handler for diagnostic messaging in the client. /// The HTTP pipeline for sending and receiving REST requests and responses. /// The URL of the service account, container, or blob that is the target of the desired operation. - /// Specifies the version of the operation to use for this request. The default value is "2021-12-02". + /// Specifies the version of the operation to use for this request. The default value is "2024-08-04". /// , , or is null. public PageBlobRestClient(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, string url, string version) { diff --git a/sdk/storage/Azure.Storage.Blobs/src/Generated/ServiceRestClient.cs b/sdk/storage/Azure.Storage.Blobs/src/Generated/ServiceRestClient.cs index 930e4e978cbf1..f7a0d8f2a3425 100644 --- a/sdk/storage/Azure.Storage.Blobs/src/Generated/ServiceRestClient.cs +++ b/sdk/storage/Azure.Storage.Blobs/src/Generated/ServiceRestClient.cs @@ -31,7 +31,7 @@ internal partial class ServiceRestClient /// The handler for diagnostic messaging in the client. /// The HTTP pipeline for sending and receiving REST requests and responses. /// The URL of the service account, container, or blob that is the target of the desired operation. - /// Specifies the version of the operation to use for this request. The default value is "2021-12-02". + /// Specifies the version of the operation to use for this request. The default value is "2024-08-04". /// , , or is null. public ServiceRestClient(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, string url, string version) { @@ -434,7 +434,7 @@ public ResponseWithHeaders Returns the sku name and account kind. + /// The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. /// The cancellation token to use. - public async Task> GetAccountInfoAsync(CancellationToken cancellationToken = default) + public async Task> GetAccountInfoAsync(int? timeout = null, CancellationToken cancellationToken = default) { - using var message = CreateGetAccountInfoRequest(); + using var message = CreateGetAccountInfoRequest(timeout); await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); var headers = new ServiceGetAccountInfoHeaders(message.Response); switch (message.Response.Status) @@ -467,10 +472,11 @@ public async Task> GetAccountI } /// Returns the sku name and account kind. + /// The timeout parameter is expressed in seconds. For more information, see <a href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting Timeouts for Blob Service Operations.</a>. /// The cancellation token to use. - public ResponseWithHeaders GetAccountInfo(CancellationToken cancellationToken = default) + public ResponseWithHeaders GetAccountInfo(int? timeout = null, CancellationToken cancellationToken = default) { - using var message = CreateGetAccountInfoRequest(); + using var message = CreateGetAccountInfoRequest(timeout); _pipeline.Send(message, cancellationToken); var headers = new ServiceGetAccountInfoHeaders(message.Response); switch (message.Response.Status) diff --git a/sdk/storage/Azure.Storage.Blobs/src/autorest.md b/sdk/storage/Azure.Storage.Blobs/src/autorest.md index c1d6a8c429776..098399c4e7f41 100644 --- a/sdk/storage/Azure.Storage.Blobs/src/autorest.md +++ b/sdk/storage/Azure.Storage.Blobs/src/autorest.md @@ -4,7 +4,7 @@ Run `dotnet build /t:GenerateCode` to generate code. ``` yaml input-file: - - https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5da3c08b92d05858b728b013b69502dc93485373/specification/storage/data-plane/Microsoft.BlobStorage/stable/2021-12-02/blob.json + - https://raw.githubusercontent.com/Azure/azure-rest-api-specs/8b14ba4a3232adb8538d96832a47dfd695904341/specification/storage/data-plane/Microsoft.BlobStorage/stable/2024-08-04/blob.json generation1-convenience-client: true # https://github.com/Azure/autorest/issues/4075 skip-semantics-validation: true @@ -131,25 +131,6 @@ directive: delete $.EncryptionScope["x-ms-parameter-grouping"]; ``` -### Remove Container_GetAccountInfo and Blob_GetAccountInfo. Unused and clashes with Service_GetAccountInfo after removal of path params. -``` yaml -directive: -- from: swagger-document - where: $["x-ms-paths"] - transform: > - for (const property in $) - { - if (property.includes('/{containerName}?restype=account&comp=properties')) - { - delete $[property]; - } - if (property.includes('/{containerName}/{blob}?restype=account&comp=properties')) - { - delete $[property]; - } - } -``` - ### Fix 304s ``` yaml directive: diff --git a/sdk/storage/Azure.Storage.Blobs/tests/AppendBlobClientTests.cs b/sdk/storage/Azure.Storage.Blobs/tests/AppendBlobClientTests.cs index 40c7fa0997143..7fae438be11d1 100644 --- a/sdk/storage/Azure.Storage.Blobs/tests/AppendBlobClientTests.cs +++ b/sdk/storage/Azure.Storage.Blobs/tests/AppendBlobClientTests.cs @@ -1317,6 +1317,27 @@ public async Task AppendBlockFromUriAsync_Min() } } + [RecordedTest] + [ServiceVersion(Min = BlobClientOptions.ServiceVersion.V2024_08_04)] + public async Task AppendBlockFromUriAsync_SourceErrorAndStatusCode() + { + await using DisposingContainer test = await GetTestContainerAsync(publicAccessType: PublicAccessType.None); + + AppendBlobClient sourceBlob = InstrumentClient(test.Container.GetAppendBlobClient(GetNewBlobName())); + AppendBlobClient destBlob = InstrumentClient(test.Container.GetAppendBlobClient(GetNewBlobName())); + await destBlob.CreateIfNotExistsAsync(); + + // Act + await TestHelper.AssertExpectedExceptionAsync( + destBlob.AppendBlockFromUriAsync(sourceBlob.Uri), + e => + { + Assert.IsTrue(e.Message.Contains("CopySourceStatusCode: 409")); + Assert.IsTrue(e.Message.Contains("CopySourceErrorCode: PublicAccessNotPermitted")); + Assert.IsTrue(e.Message.Contains("CopySourceErrorMessage: Public access is not permitted on this storage account.")); + }); + } + [RecordedTest] [TestCase(nameof(AppendBlobRequestConditions.LeaseId))] [TestCase(nameof(AppendBlobRequestConditions.TagConditions))] diff --git a/sdk/storage/Azure.Storage.Blobs/tests/BlobBaseClientTests.cs b/sdk/storage/Azure.Storage.Blobs/tests/BlobBaseClientTests.cs index 1b34a6bda2dcc..ef231d3cea1e5 100644 --- a/sdk/storage/Azure.Storage.Blobs/tests/BlobBaseClientTests.cs +++ b/sdk/storage/Azure.Storage.Blobs/tests/BlobBaseClientTests.cs @@ -1999,6 +1999,29 @@ public async Task StartCopyFromUriAsync() Assert.IsTrue(operation.HasValue); } + [RecordedTest] + [ServiceVersion(Min = BlobClientOptions.ServiceVersion.V2024_08_04)] + public async Task StartCopyFromUriAsync_SourceErrorAndStatusCode() + { + await using DisposingContainer test = await GetTestContainerAsync(publicAccessType: PublicAccessType.None); + + // Arrange + BlobBaseClient srcBlob = InstrumentClient(test.Container.GetBlockBlobClient(GetNewBlobName())); + BlockBlobClient destBlob = InstrumentClient(test.Container.GetBlockBlobClient(GetNewBlobName())); + + Uri sourceUri = srcBlob.GenerateSasUri(BlobSasPermissions.Read, GetUtcNow().AddDays(1)); + + // Act + await TestHelper.AssertExpectedExceptionAsync( + destBlob.StartCopyFromUriAsync(sourceUri), + e => + { + Assert.IsTrue(e.Message.Contains("CopySourceStatusCode: 404")); + Assert.IsTrue(e.Message.Contains("CopySourceErrorCode: BlobNotFound")); + Assert.IsTrue(e.Message.Contains("CopySourceErrorMessage: The specified blob does not exist.")); + }); + } + [RecordedTest] [TestCase(nameof(BlobRequestConditions.LeaseId))] public async Task StartCopyFromUriAsync_InvalidSourceRequestConditions(string invalidSourceCondition) @@ -3332,6 +3355,27 @@ await destBlob.SyncCopyFromUriAsync( } } + [RecordedTest] + [ServiceVersion(Min = BlobClientOptions.ServiceVersion.V2024_08_04)] + public async Task SyncCopyFromUriAsync_SourceErrorAndStatusCode() + { + await using DisposingContainer test = await GetTestContainerAsync(publicAccessType: PublicAccessType.None); + + // Arrange + BlockBlobClient srcBlob = InstrumentClient(test.Container.GetBlockBlobClient(GetNewBlobName())); + BlockBlobClient destBlob = InstrumentClient(test.Container.GetBlockBlobClient(GetNewBlobName())); + + // Act + await TestHelper.AssertExpectedExceptionAsync( + destBlob.SyncCopyFromUriAsync(srcBlob.Uri), + e => + { + Assert.IsTrue(e.Message.Contains("CopySourceStatusCode: 409")); + Assert.IsTrue(e.Message.Contains("CopySourceErrorCode: PublicAccessNotPermitted")); + Assert.IsTrue(e.Message.Contains("CopySourceErrorMessage: Public access is not permitted on this storage account.")); + }); + } + [RecordedTest] public async Task DeleteAsync() { @@ -7779,6 +7823,40 @@ public void CanMockClientConstructors() mock = new Mock(new Uri("https://test/test"), Tenants.GetOAuthCredential(Tenants.TestConfigHierarchicalNamespace), new BlobClientOptions()).Object; } + [RecordedTest] + public async Task GetAccountInfoAsync() + { + await using DisposingContainer test = await GetTestContainerAsync(); + + // Arrange + BlobBaseClient blob = await GetNewBlobClient(test.Container); + + // Act + Response response = await blob.GetAccountInfoAsync(); + + // Assert + Assert.AreEqual(SkuName.StandardRagrs, response.Value.SkuName); + Assert.AreEqual(AccountKind.StorageV2, response.Value.AccountKind); + Assert.IsFalse(response.Value.IsHierarchicalNamespaceEnabled); + } + + [RecordedTest] + public async Task GetAccountInfoAsync_Error() + { + // Arrange + BlobServiceClient service = InstrumentClient( + new BlobServiceClient( + BlobsClientBuilder.GetServiceClient_SharedKey().Uri, + GetOptions())); + + BlobClient blobClient = service.GetBlobContainerClient(GetNewContainerName()).GetBlobClient(GetNewBlobName()); + + // Act + await TestHelper.AssertExpectedExceptionAsync( + blobClient.GetAccountInfoAsync(), + e => Assert.AreEqual("ResourceNotFound", e.ErrorCode)); + } + public IEnumerable AccessConditions_Data => new[] { diff --git a/sdk/storage/Azure.Storage.Blobs/tests/BlobsClientTestFixtureAttribute.cs b/sdk/storage/Azure.Storage.Blobs/tests/BlobsClientTestFixtureAttribute.cs index 2d55489fffc11..ff335fb2934a3 100644 --- a/sdk/storage/Azure.Storage.Blobs/tests/BlobsClientTestFixtureAttribute.cs +++ b/sdk/storage/Azure.Storage.Blobs/tests/BlobsClientTestFixtureAttribute.cs @@ -33,6 +33,7 @@ public BlobsClientTestFixtureAttribute(params object[] additionalParameters) BlobClientOptions.ServiceVersion.V2023_11_03, BlobClientOptions.ServiceVersion.V2024_02_04, BlobClientOptions.ServiceVersion.V2024_05_04, + BlobClientOptions.ServiceVersion.V2024_08_04, StorageVersionExtensions.LatestVersion, StorageVersionExtensions.MaxVersion }, diff --git a/sdk/storage/Azure.Storage.Blobs/tests/BlockBlobClientTests.cs b/sdk/storage/Azure.Storage.Blobs/tests/BlockBlobClientTests.cs index 781ebefa35e46..bc4b864e897db 100644 --- a/sdk/storage/Azure.Storage.Blobs/tests/BlockBlobClientTests.cs +++ b/sdk/storage/Azure.Storage.Blobs/tests/BlockBlobClientTests.cs @@ -614,6 +614,27 @@ await RetryAsync( _retryStageBlockFromUri); } + [RecordedTest] + [ServiceVersion(Min = BlobClientOptions.ServiceVersion.V2024_08_04)] + public async Task StageBlobFromUriAsync_SourceErrorAndStatusCode() + { + // Arrange + var constants = TestConstants.Create(this); + await using DisposingContainer test = await GetTestContainerAsync(publicAccessType: PublicAccessType.None); + BlockBlobClient sourceBlob = InstrumentClient(test.Container.GetBlockBlobClient(GetNewBlobName())); + BlockBlobClient destBlob = InstrumentClient(test.Container.GetBlockBlobClient(GetNewBlobName())); + + // Act + await TestHelper.AssertExpectedExceptionAsync( + destBlob.StageBlockFromUriAsync(sourceBlob.Uri, ToBase64(GetNewBlockName())), + e => + { + Assert.IsTrue(e.Message.Contains("CopySourceStatusCode: 409")); + Assert.IsTrue(e.Message.Contains("CopySourceErrorCode: PublicAccessNotPermitted")); + Assert.IsTrue(e.Message.Contains("CopySourceErrorMessage: Public access is not permitted on this storage account.")); + }); + } + [RecordedTest] [TestCase(nameof(BlobRequestConditions.IfModifiedSince))] [TestCase(nameof(BlobRequestConditions.IfUnmodifiedSince))] @@ -2821,6 +2842,27 @@ await TestHelper.AssertExpectedExceptionAsync( e => Assert.AreEqual(BlobErrorCode.CannotVerifyCopySource.ToString(), e.ErrorCode)); } + [RecordedTest] + [ServiceVersion(Min = BlobClientOptions.ServiceVersion.V2024_08_04)] + public async Task SyncUploadFromUriAsync_SourceErrorAndStatusCode() + { + // Arrange + var constants = TestConstants.Create(this); + await using DisposingContainer test = await GetTestContainerAsync(publicAccessType: PublicAccessType.None); + BlockBlobClient sourceBlob = InstrumentClient(test.Container.GetBlockBlobClient(GetNewBlobName())); + BlockBlobClient destBlob = InstrumentClient(test.Container.GetBlockBlobClient(GetNewBlobName())); + + // Act + await TestHelper.AssertExpectedExceptionAsync( + destBlob.SyncUploadFromUriAsync(sourceBlob.Uri), + e => + { + Assert.IsTrue(e.Message.Contains("CopySourceStatusCode: 409")); + Assert.IsTrue(e.Message.Contains("CopySourceErrorCode: PublicAccessNotPermitted")); + Assert.IsTrue(e.Message.Contains("CopySourceErrorMessage: Public access is not permitted on this storage account.")); + }); + } + [RecordedTest] [ServiceVersion(Min = BlobClientOptions.ServiceVersion.V2020_04_08)] public async Task SyncUploadFromUriAsync_OverwriteSourceBlobProperties() diff --git a/sdk/storage/Azure.Storage.Blobs/tests/ContainerClientTests.cs b/sdk/storage/Azure.Storage.Blobs/tests/ContainerClientTests.cs index f0b99c1e31372..db55dddffc336 100644 --- a/sdk/storage/Azure.Storage.Blobs/tests/ContainerClientTests.cs +++ b/sdk/storage/Azure.Storage.Blobs/tests/ContainerClientTests.cs @@ -4017,6 +4017,38 @@ await TestHelper.AssertExpectedExceptionAsync( e => Assert.AreEqual(BlobErrorCode.NoAuthenticationInformation.ToString(), e.ErrorCode)); } + [RecordedTest] + public async Task GetAccountInfoAsync() + { + // Arrange + await using DisposingContainer test = await GetTestContainerAsync(); + + // Act + Response response = await test.Container.GetAccountInfoAsync(); + + // Assert + Assert.AreEqual(SkuName.StandardRagrs, response.Value.SkuName); + Assert.AreEqual(AccountKind.StorageV2, response.Value.AccountKind); + Assert.IsFalse(response.Value.IsHierarchicalNamespaceEnabled); + } + + [RecordedTest] + public async Task GetAccountInfoAsync_Error() + { + // Arrange + BlobServiceClient service = InstrumentClient( + new BlobServiceClient( + BlobsClientBuilder.GetServiceClient_SharedKey().Uri, + GetOptions())); + + BlobContainerClient containerClient = service.GetBlobContainerClient(GetNewContainerName()); + + // Act + await TestHelper.AssertExpectedExceptionAsync( + containerClient.GetAccountInfoAsync(), + e => Assert.AreEqual("ResourceNotFound", e.ErrorCode)); + } + [RecordedTest] public void CanMockClientConstructors() { diff --git a/sdk/storage/Azure.Storage.Blobs/tests/PageBlobClientTests.cs b/sdk/storage/Azure.Storage.Blobs/tests/PageBlobClientTests.cs index a7a1007a5d68e..419e638fa4177 100644 --- a/sdk/storage/Azure.Storage.Blobs/tests/PageBlobClientTests.cs +++ b/sdk/storage/Azure.Storage.Blobs/tests/PageBlobClientTests.cs @@ -3370,6 +3370,31 @@ public async Task UploadPagesFromUriAsync_Min() } } + [RecordedTest] + [ServiceVersion(Min = BlobClientOptions.ServiceVersion.V2024_08_04)] + public async Task UploadPagesFromUriAsync_SourceErrorAndStatusCode() + { + // Arrange + await using DisposingContainer test = await GetTestContainerAsync(publicAccessType: PublicAccessType.None); + + PageBlobClient sourceBlob = InstrumentClient(test.Container.GetPageBlobClient(GetNewBlobName())); + + PageBlobClient destBlob = InstrumentClient(test.Container.GetPageBlobClient(GetNewBlobName())); + await destBlob.CreateIfNotExistsAsync(Constants.KB); + + HttpRange range = new HttpRange(0, Constants.KB); + + // Act + await TestHelper.AssertExpectedExceptionAsync( + destBlob.UploadPagesFromUriAsync(sourceBlob.Uri, range, range), + e => + { + Assert.IsTrue(e.Message.Contains("CopySourceStatusCode: 409")); + Assert.IsTrue(e.Message.Contains("CopySourceErrorCode: PublicAccessNotPermitted")); + Assert.IsTrue(e.Message.Contains("CopySourceErrorMessage: Public access is not permitted on this storage account.")); + }); + } + [RecordedTest] [TestCase(nameof(PageBlobRequestConditions.LeaseId))] [TestCase(nameof(PageBlobRequestConditions.IfSequenceNumberLessThanOrEqual))] diff --git a/sdk/storage/Azure.Storage.Common/CHANGELOG.md b/sdk/storage/Azure.Storage.Common/CHANGELOG.md index 3a8c7af1113a6..d6b291fc1be73 100644 --- a/sdk/storage/Azure.Storage.Common/CHANGELOG.md +++ b/sdk/storage/Azure.Storage.Common/CHANGELOG.md @@ -1,14 +1,7 @@ # Release History ## 12.20.0-beta.1 (Unreleased) - -### Features Added - -### Breaking Changes - -### Bugs Fixed - -### Other Changes +- This release contains bug fixes to improve quality. ## 12.19.0 (2024-05-13) - This release contains bug fixes to improve quality. diff --git a/sdk/storage/Azure.Storage.Common/api/Azure.Storage.Common.net6.0.cs b/sdk/storage/Azure.Storage.Common/api/Azure.Storage.Common.net6.0.cs index a50804a78c8bb..1f6b4e41b4970 100644 --- a/sdk/storage/Azure.Storage.Common/api/Azure.Storage.Common.net6.0.cs +++ b/sdk/storage/Azure.Storage.Common/api/Azure.Storage.Common.net6.0.cs @@ -182,7 +182,7 @@ public enum SasProtocol } public partial class SasQueryParameters { - public const string DefaultSasVersion = "2024-05-04"; + public const string DefaultSasVersion = "2024-08-04"; protected SasQueryParameters() { } protected SasQueryParameters(System.Collections.Generic.IDictionary values) { } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] diff --git a/sdk/storage/Azure.Storage.Common/api/Azure.Storage.Common.netstandard2.0.cs b/sdk/storage/Azure.Storage.Common/api/Azure.Storage.Common.netstandard2.0.cs index 38656a564b122..658a4173c1324 100644 --- a/sdk/storage/Azure.Storage.Common/api/Azure.Storage.Common.netstandard2.0.cs +++ b/sdk/storage/Azure.Storage.Common/api/Azure.Storage.Common.netstandard2.0.cs @@ -181,7 +181,7 @@ public enum SasProtocol } public partial class SasQueryParameters { - public const string DefaultSasVersion = "2024-05-04"; + public const string DefaultSasVersion = "2024-08-04"; protected SasQueryParameters() { } protected SasQueryParameters(System.Collections.Generic.IDictionary values) { } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] diff --git a/sdk/storage/Azure.Storage.Common/src/Shared/Constants.cs b/sdk/storage/Azure.Storage.Common/src/Shared/Constants.cs index c8ce04f6f4e47..48b4ca18cd54f 100644 --- a/sdk/storage/Azure.Storage.Common/src/Shared/Constants.cs +++ b/sdk/storage/Azure.Storage.Common/src/Shared/Constants.cs @@ -25,7 +25,7 @@ internal static class Constants /// Gets the default service version to use when building shared access /// signatures. /// - public const string DefaultSasVersion = "2024-05-04"; + public const string DefaultSasVersion = "2024-08-04"; /// /// Max download range size while requesting a transactional hash. @@ -127,6 +127,7 @@ internal static class Constants public const string DisableExpectContinueHeaderEnvVar = "AZURE_STORAGE_DISABLE_EXPECT_CONTINUE_HEADER"; public const string DefaultScope = "/.default"; + public const string EnUsCulture = "en-US"; /// /// Storage Connection String constant values. @@ -196,6 +197,7 @@ internal static class HeaderNames public const string LeaseId = "x-ms-lease-id"; public const string LastModified = "Last-Modified"; public const string ETag = "ETag"; + public const string CopySourceErrorCode = "x-ms-copy-source-error-code"; } internal static class ErrorCodes diff --git a/sdk/storage/Azure.Storage.Common/src/Shared/StorageResponseClassifier.cs b/sdk/storage/Azure.Storage.Common/src/Shared/StorageResponseClassifier.cs index 01c4dbdad644f..e364faa7f2516 100644 --- a/sdk/storage/Azure.Storage.Common/src/Shared/StorageResponseClassifier.cs +++ b/sdk/storage/Azure.Storage.Common/src/Shared/StorageResponseClassifier.cs @@ -41,6 +41,20 @@ public override bool IsRetriableResponse(HttpMessage message) return true; } } + + // Retry select Copy Source Error Codes. + if (message.Response.Status >= 400 && + message.Response.Headers.TryGetValue(Constants.HeaderNames.CopySourceErrorCode, out string copySourceError)) + { + switch (copySourceError) + { + case Constants.ErrorCodes.InternalError: + case Constants.ErrorCodes.OperationTimedOut: + case Constants.ErrorCodes.ServerBusy: + return true; + } + } + return base.IsRetriableResponse(message); } diff --git a/sdk/storage/Azure.Storage.Common/src/Shared/StorageSharedKeyPipelinePolicy.cs b/sdk/storage/Azure.Storage.Common/src/Shared/StorageSharedKeyPipelinePolicy.cs index ace33c1004318..fe787729a6bab 100644 --- a/sdk/storage/Azure.Storage.Common/src/Shared/StorageSharedKeyPipelinePolicy.cs +++ b/sdk/storage/Azure.Storage.Common/src/Shared/StorageSharedKeyPipelinePolicy.cs @@ -22,6 +22,11 @@ internal sealed class StorageSharedKeyPipelinePolicy : HttpPipelineSynchronousPo /// private const bool IncludeXMsDate = true; + /// + /// CultureInfo used to sort headers in the string to sign. + /// + private static readonly CultureInfo s_cultureInfo = new CultureInfo(Constants.EnUsCulture, useUserOverride: false); + /// /// Shared key credentials used to sign requests /// @@ -112,7 +117,10 @@ private static void BuildCanonicalizedHeaders(StringBuilder stringBuilder, HttpM } } - headers.Sort(static (x, y) => string.CompareOrdinal(x.Name, y.Name)); + headers.Sort(static (x, y) => + {; + return string.Compare(x.Name, y.Name, s_cultureInfo, CompareOptions.IgnoreSymbols); + }); foreach (var header in headers) { diff --git a/sdk/storage/Azure.Storage.Common/src/Shared/StorageVersionExtensions.cs b/sdk/storage/Azure.Storage.Common/src/Shared/StorageVersionExtensions.cs index 652c6058051fc..4cd44e5d626cc 100644 --- a/sdk/storage/Azure.Storage.Common/src/Shared/StorageVersionExtensions.cs +++ b/sdk/storage/Azure.Storage.Common/src/Shared/StorageVersionExtensions.cs @@ -54,7 +54,7 @@ internal static class StorageVersionExtensions /// internal const ServiceVersion MaxVersion = #if BlobSDK || QueueSDK || FileSDK || DataLakeSDK || ChangeFeedSDK || DataMovementSDK || BlobDataMovementSDK || ShareDataMovementSDK - ServiceVersion.V2024_05_04; + ServiceVersion.V2024_08_04; #else ERROR_STORAGE_SERVICE_NOT_DEFINED; #endif @@ -90,30 +90,31 @@ public static string ToVersionString(this ServiceVersion version) => ServiceVersion.V2023_11_03 => "2023-11-03", ServiceVersion.V2024_02_04 => "2024-02-04", ServiceVersion.V2024_05_04 => "2024-05-04", + ServiceVersion.V2024_08_04 => "2024-08-04", #elif QueueSDK - // Queues just bumped the version number without changing the swagger - ServiceVersion.V2019_02_02 => "2018-11-09", - ServiceVersion.V2019_07_07 => "2018-11-09", - ServiceVersion.V2019_12_12 => "2018-11-09", - ServiceVersion.V2020_02_10 => "2018-11-09", - ServiceVersion.V2020_04_08 => "2018-11-09", - ServiceVersion.V2020_06_12 => "2018-11-09", - ServiceVersion.V2020_08_04 => "2018-11-09", - ServiceVersion.V2020_10_02 => "2018-11-09", - ServiceVersion.V2020_12_06 => "2018-11-09", - ServiceVersion.V2021_02_12 => "2018-11-09", - ServiceVersion.V2021_04_10 => "2018-11-09", - ServiceVersion.V2021_06_08 => "2018-11-09", - ServiceVersion.V2021_08_06 => "2018-11-09", - ServiceVersion.V2021_10_04 => "2018-11-09", - ServiceVersion.V2021_12_02 => "2018-11-09", - ServiceVersion.V2022_11_02 => "2018-11-09", - ServiceVersion.V2023_01_03 => "2018-11-09", - ServiceVersion.V2023_05_03 => "2018-11-09", - ServiceVersion.V2023_08_03 => "2018-11-09", - ServiceVersion.V2023_11_03 => "2018-11-09", - ServiceVersion.V2024_02_04 => "2018-11-09", - ServiceVersion.V2024_05_04 => "2018-11-09", + ServiceVersion.V2019_02_02 => "2019-02-02", + ServiceVersion.V2019_07_07 => "2019-07-07", + ServiceVersion.V2019_12_12 => "2019-12-12", + ServiceVersion.V2020_02_10 => "2020-02-10", + ServiceVersion.V2020_04_08 => "2020-04-08", + ServiceVersion.V2020_06_12 => "2020-06-12", + ServiceVersion.V2020_08_04 => "2020-08-04", + ServiceVersion.V2020_10_02 => "2020-10-02", + ServiceVersion.V2020_12_06 => "2020-12-06", + ServiceVersion.V2021_02_12 => "2021-02-12", + ServiceVersion.V2021_04_10 => "2021-04-10", + ServiceVersion.V2021_06_08 => "2021-06-08", + ServiceVersion.V2021_08_06 => "2021-08-06", + ServiceVersion.V2021_10_04 => "2021-10-04", + ServiceVersion.V2021_12_02 => "2021-12-02", + ServiceVersion.V2022_11_02 => "2022-11-02", + ServiceVersion.V2023_01_03 => "2023-01-03", + ServiceVersion.V2023_05_03 => "2023-05-03", + ServiceVersion.V2023_08_03 => "2023-08-03", + ServiceVersion.V2023_11_03 => "2023-11-03", + ServiceVersion.V2024_02_04 => "2024-02-04", + ServiceVersion.V2024_05_04 => "2024-05-04", + ServiceVersion.V2024_08_04 => "2024-08-04", #endif _ => throw Errors.VersionNotSupported(nameof(version)) }; @@ -171,6 +172,8 @@ public static Azure.Storage.Blobs.BlobClientOptions.ServiceVersion AsBlobsVersio Azure.Storage.Blobs.BlobClientOptions.ServiceVersion.V2024_02_04, Azure.Storage.Files.DataLake.DataLakeClientOptions.ServiceVersion.V2024_05_04 => Azure.Storage.Blobs.BlobClientOptions.ServiceVersion.V2024_05_04, + Azure.Storage.Files.DataLake.DataLakeClientOptions.ServiceVersion.V2024_08_04 => + Azure.Storage.Blobs.BlobClientOptions.ServiceVersion.V2024_08_04, _ => throw Errors.VersionNotSupported(nameof(version)) }; #endif diff --git a/sdk/storage/Azure.Storage.Common/tests/CommonTestBase.cs b/sdk/storage/Azure.Storage.Common/tests/CommonTestBase.cs index 6d029fde2b3fa..eb106ad26d093 100644 --- a/sdk/storage/Azure.Storage.Common/tests/CommonTestBase.cs +++ b/sdk/storage/Azure.Storage.Common/tests/CommonTestBase.cs @@ -32,8 +32,9 @@ namespace Azure.Storage.Test BlobClientOptions.ServiceVersion.V2023_11_03, BlobClientOptions.ServiceVersion.V2024_02_04, BlobClientOptions.ServiceVersion.V2024_05_04, - RecordingServiceVersion = BlobClientOptions.ServiceVersion.V2024_05_04, - LiveServiceVersions = new object[] { BlobClientOptions.ServiceVersion.V2024_02_04, })] + BlobClientOptions.ServiceVersion.V2024_08_04, + RecordingServiceVersion = BlobClientOptions.ServiceVersion.V2024_08_04, + LiveServiceVersions = new object[] { BlobClientOptions.ServiceVersion.V2024_05_04, })] public abstract class CommonTestBase : StorageTestBase { protected readonly BlobClientOptions.ServiceVersion _serviceVersion; diff --git a/sdk/storage/Azure.Storage.Common/tests/StorageResponseClassifierTests.cs b/sdk/storage/Azure.Storage.Common/tests/StorageResponseClassifierTests.cs index d2bdb94a5ea3c..dd6384c0d582c 100644 --- a/sdk/storage/Azure.Storage.Common/tests/StorageResponseClassifierTests.cs +++ b/sdk/storage/Azure.Storage.Common/tests/StorageResponseClassifierTests.cs @@ -70,6 +70,30 @@ public void IsRetriableResponse_StorageErrors_SecondaryUri(string errorCode) Assert.IsTrue(classifier.IsRetriableResponse(message)); } + [Test] + [TestCase(Constants.ErrorCodes.ServerBusy)] + [TestCase(Constants.ErrorCodes.InternalError)] + [TestCase(Constants.ErrorCodes.OperationTimedOut)] + public void IsRetriableResponse_CopySourceErrors(string errorCode) + { + var response = new MockResponse(Constants.HttpStatusCode.NotFound); + response.AddHeader(new HttpHeader(Constants.HeaderNames.CopySourceErrorCode, errorCode)); + HttpMessage message = BuildMessage(response); + Assert.IsTrue(classifier.IsRetriableResponse(message)); + } + + [Test] + [TestCase(Constants.ErrorCodes.ServerBusy)] + [TestCase(Constants.ErrorCodes.InternalError)] + [TestCase(Constants.ErrorCodes.OperationTimedOut)] + public void IsRetriableResponse_CopySourceErrors_SecondaryUri(string errorCode) + { + var response = new MockResponse(Constants.HttpStatusCode.NotFound); + response.AddHeader(new HttpHeader(Constants.HeaderNames.CopySourceErrorCode, errorCode)); + HttpMessage message = BuildMessage(response, MockSecondaryUri); + Assert.IsTrue(classifier.IsRetriableResponse(message)); + } + [TestCase("ContainerAlreadyExists", "If-Match", false)] [TestCase("ContainerAlreadyExists","If-None-Match", false)] [TestCase("ContainerAlreadyExists","If-Unmodified-Since", false)] diff --git a/sdk/storage/Azure.Storage.Common/tests/StorageSharedKeyPipelinePolicyTests.cs b/sdk/storage/Azure.Storage.Common/tests/StorageSharedKeyPipelinePolicyTests.cs index b0d7d178f5156..249c7ddcccc6b 100644 --- a/sdk/storage/Azure.Storage.Common/tests/StorageSharedKeyPipelinePolicyTests.cs +++ b/sdk/storage/Azure.Storage.Common/tests/StorageSharedKeyPipelinePolicyTests.cs @@ -56,6 +56,8 @@ public void OnSendingRequest_BuildSignature() mockRequest.Headers.Add("x-ms-meta-meta", "data"); mockRequest.Headers.Add("x-ms-meta-Capital", "letter"); mockRequest.Headers.Add("x-ms-meta-UPPER", "case"); + mockRequest.Headers.Add("x-ms-enable-snapshot-virtual-directory-access", "true"); + mockRequest.Headers.Add("x-ms-enabled-protocols", "NFS"); mockRequest.Headers.Add("User-Agent", "azsdk-net-Storage.Files.Shares/12.13.0-alpha.20221025.1,(.NET 6.0.10; Microsoft Windows 10.0.22621)"); mockRequest.Headers.Add("x-ms-date", "Wed, 23 Feb 2022 02:39:43 GMT"); // value will be replaced by StorageSharedKeyPipelinePolicy @@ -78,6 +80,8 @@ public void OnSendingRequest_BuildSignature() .Append("x-ms-client-request-id:8f978611-738a-4cd4-a318-33b2f31068d9\n") .Append("x-ms-creation-time:Tue, 25 Oct 2022 16:47:17 GMT\n") .Append("x-ms-date:").Append(date).Append("\n") + .Append("x-ms-enabled-protocols:NFS\n") + .Append("x-ms-enable-snapshot-virtual-directory-access:true\n") .Append("x-ms-lease-status:unlocked\n") .Append("x-ms-meta-capital:letter\n") .Append("x-ms-meta-foo:bar\n") diff --git a/sdk/storage/Azure.Storage.DataMovement.Blobs/assets.json b/sdk/storage/Azure.Storage.DataMovement.Blobs/assets.json index 1a16d01306263..5875964cd5cd0 100644 --- a/sdk/storage/Azure.Storage.DataMovement.Blobs/assets.json +++ b/sdk/storage/Azure.Storage.DataMovement.Blobs/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "net", "TagPrefix": "net/storage/Azure.Storage.DataMovement.Blobs", - "Tag": "net/storage/Azure.Storage.DataMovement.Blobs_d772fba911" + "Tag": "net/storage/Azure.Storage.DataMovement.Blobs_0523c237f1" } diff --git a/sdk/storage/Azure.Storage.DataMovement.Files.Shares/assets.json b/sdk/storage/Azure.Storage.DataMovement.Files.Shares/assets.json index 1c21c103f1fa8..430e5e00d15a3 100644 --- a/sdk/storage/Azure.Storage.DataMovement.Files.Shares/assets.json +++ b/sdk/storage/Azure.Storage.DataMovement.Files.Shares/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "net", "TagPrefix": "net/storage/Azure.Storage.DataMovement.Files.Shares", - "Tag": "net/storage/Azure.Storage.DataMovement.Files.Shares_294a5d540c" + "Tag": "net/storage/Azure.Storage.DataMovement.Files.Shares_34fa84b61a" } diff --git a/sdk/storage/Azure.Storage.Files.DataLake/CHANGELOG.md b/sdk/storage/Azure.Storage.Files.DataLake/CHANGELOG.md index 94a17a9f74944..baacc7f3897e4 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/CHANGELOG.md +++ b/sdk/storage/Azure.Storage.Files.DataLake/CHANGELOG.md @@ -1,14 +1,8 @@ # Release History ## 12.19.0-beta.1 (Unreleased) - -### Features Added - -### Breaking Changes - -### Bugs Fixed - -### Other Changes +- Added support for service version 2024-08-04. +- Added more detailed messaging for authorization failure cases. ## 12.18.0 (2024-05-13) - Includes all features from 12.18.0-beta.1 and 12.18.0-beta.2. diff --git a/sdk/storage/Azure.Storage.Files.DataLake/api/Azure.Storage.Files.DataLake.net6.0.cs b/sdk/storage/Azure.Storage.Files.DataLake/api/Azure.Storage.Files.DataLake.net6.0.cs index dddee1e21876b..b2be52e9cd4de 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/api/Azure.Storage.Files.DataLake.net6.0.cs +++ b/sdk/storage/Azure.Storage.Files.DataLake/api/Azure.Storage.Files.DataLake.net6.0.cs @@ -33,6 +33,7 @@ public enum ServiceVersion V2023_11_03 = 20, V2024_02_04 = 21, V2024_05_04 = 22, + V2024_08_04 = 23, } } public partial class DataLakeDirectoryClient : Azure.Storage.Files.DataLake.DataLakePathClient diff --git a/sdk/storage/Azure.Storage.Files.DataLake/api/Azure.Storage.Files.DataLake.netstandard2.0.cs b/sdk/storage/Azure.Storage.Files.DataLake/api/Azure.Storage.Files.DataLake.netstandard2.0.cs index dddee1e21876b..b2be52e9cd4de 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/api/Azure.Storage.Files.DataLake.netstandard2.0.cs +++ b/sdk/storage/Azure.Storage.Files.DataLake/api/Azure.Storage.Files.DataLake.netstandard2.0.cs @@ -33,6 +33,7 @@ public enum ServiceVersion V2023_11_03 = 20, V2024_02_04 = 21, V2024_05_04 = 22, + V2024_08_04 = 23, } } public partial class DataLakeDirectoryClient : Azure.Storage.Files.DataLake.DataLakePathClient diff --git a/sdk/storage/Azure.Storage.Files.DataLake/assets.json b/sdk/storage/Azure.Storage.Files.DataLake/assets.json index becbcf51e5104..9c7dfffe8d717 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/assets.json +++ b/sdk/storage/Azure.Storage.Files.DataLake/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "net", "TagPrefix": "net/storage/Azure.Storage.Files.DataLake", - "Tag": "net/storage/Azure.Storage.Files.DataLake_c330f3640e" + "Tag": "net/storage/Azure.Storage.Files.DataLake_aaa95f3b1a" } diff --git a/sdk/storage/Azure.Storage.Files.DataLake/src/DataLakeClientOptions.cs b/sdk/storage/Azure.Storage.Files.DataLake/src/DataLakeClientOptions.cs index ebf2c176ef20a..655b0a224cf3d 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/src/DataLakeClientOptions.cs +++ b/sdk/storage/Azure.Storage.Files.DataLake/src/DataLakeClientOptions.cs @@ -141,7 +141,12 @@ public enum ServiceVersion /// /// The 2024-05-04 service version. /// - V2024_05_04 = 22 + V2024_05_04 = 22, + + /// + /// The 2024-08-04 service version. + /// + V2024_08_04 = 23 #pragma warning restore CA1707 // Identifiers should not contain underscores } diff --git a/sdk/storage/Azure.Storage.Files.DataLake/tests/DataLakeClientTestFixtureAttribute.cs b/sdk/storage/Azure.Storage.Files.DataLake/tests/DataLakeClientTestFixtureAttribute.cs index 77d2a60379689..2f6cbeb5435ae 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/tests/DataLakeClientTestFixtureAttribute.cs +++ b/sdk/storage/Azure.Storage.Files.DataLake/tests/DataLakeClientTestFixtureAttribute.cs @@ -31,6 +31,7 @@ public DataLakeClientTestFixtureAttribute() DataLakeClientOptions.ServiceVersion.V2023_11_03, DataLakeClientOptions.ServiceVersion.V2024_02_04, DataLakeClientOptions.ServiceVersion.V2024_05_04, + DataLakeClientOptions.ServiceVersion.V2024_08_04, StorageVersionExtensions.LatestVersion, StorageVersionExtensions.MaxVersion) { diff --git a/sdk/storage/Azure.Storage.Files.Shares/CHANGELOG.md b/sdk/storage/Azure.Storage.Files.Shares/CHANGELOG.md index 7b58a325472b9..19ec786040de6 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/CHANGELOG.md +++ b/sdk/storage/Azure.Storage.Files.Shares/CHANGELOG.md @@ -1,14 +1,10 @@ # Release History ## 12.19.0-beta.1 (Unreleased) - -### Features Added - -### Breaking Changes - -### Bugs Fixed - -### Other Changes +- Added support for service version 2024-08-04. +- Added more detailed messaging for authorization failure cases. +- Added support for snapshot management on NFS shares. +- Added more detailed messaging for file copy operations resulting in an error. ## 12.18.0 (2024-05-13) - Includes all features from 12.18.0-beta.1 and 12.18.0-beta.2. diff --git a/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net6.0.cs b/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net6.0.cs index 064276f5b553c..f050dbe2cd84a 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net6.0.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net6.0.cs @@ -128,6 +128,7 @@ public enum ServiceVersion V2023_11_03 = 20, V2024_02_04 = 21, V2024_05_04 = 22, + V2024_08_04 = 23, } } public partial class ShareDirectoryClient @@ -548,6 +549,7 @@ public partial class ShareCreateOptions { public ShareCreateOptions() { } public Azure.Storage.Files.Shares.Models.ShareAccessTier? AccessTier { get { throw null; } set { } } + public bool? EnableSnapshotVirtualDirectoryAccess { get { throw null; } set { } } public System.Collections.Generic.IDictionary Metadata { get { throw null; } set { } } public Azure.Storage.Files.Shares.Models.ShareProtocols? Protocols { get { throw null; } set { } } public int? QuotaInGB { get { throw null; } set { } } @@ -1010,7 +1012,9 @@ public static partial class ShareModelFactory public static Azure.Storage.Files.Shares.Models.ShareProperties ShareProperties(System.DateTimeOffset? lastModified, Azure.ETag? eTag, int? provisionedIops, int? provisionedIngressMBps, int? provisionedEgressMBps, System.DateTimeOffset? nextAllowedQuotaDowngradeTime, int? quotaInGB, System.Collections.Generic.IDictionary metadata) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static Azure.Storage.Files.Shares.Models.ShareProperties ShareProperties(string accessTier, System.DateTimeOffset? lastModified, int? provisionedIops, int? provisionedIngressMBps, int? provisionedEgressMBps, System.DateTimeOffset? nextAllowedQuotaDowngradeTime, System.DateTimeOffset? deletedOn, int? remainingRetentionDays, Azure.ETag? eTag, System.DateTimeOffset? accessTierChangeTime, string accessTierTransitionState, Azure.Storage.Files.Shares.Models.ShareLeaseStatus? leaseStatus, Azure.Storage.Files.Shares.Models.ShareLeaseState? leaseState, Azure.Storage.Files.Shares.Models.ShareLeaseDuration? leaseDuration, int? quotaInGB, System.Collections.Generic.IDictionary metadata) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static Azure.Storage.Files.Shares.Models.ShareProperties ShareProperties(string accessTier = null, System.DateTimeOffset? lastModified = default(System.DateTimeOffset?), int? provisionedIops = default(int?), int? provisionedIngressMBps = default(int?), int? provisionedEgressMBps = default(int?), System.DateTimeOffset? nextAllowedQuotaDowngradeTime = default(System.DateTimeOffset?), System.DateTimeOffset? deletedOn = default(System.DateTimeOffset?), int? remainingRetentionDays = default(int?), Azure.ETag? eTag = default(Azure.ETag?), System.DateTimeOffset? accessTierChangeTime = default(System.DateTimeOffset?), string accessTierTransitionState = null, Azure.Storage.Files.Shares.Models.ShareLeaseStatus? leaseStatus = default(Azure.Storage.Files.Shares.Models.ShareLeaseStatus?), Azure.Storage.Files.Shares.Models.ShareLeaseState? leaseState = default(Azure.Storage.Files.Shares.Models.ShareLeaseState?), Azure.Storage.Files.Shares.Models.ShareLeaseDuration? leaseDuration = default(Azure.Storage.Files.Shares.Models.ShareLeaseDuration?), int? quotaInGB = default(int?), System.Collections.Generic.IDictionary metadata = null, Azure.Storage.Files.Shares.Models.ShareProtocols? protocols = default(Azure.Storage.Files.Shares.Models.ShareProtocols?), Azure.Storage.Files.Shares.Models.ShareRootSquash? rootSquash = default(Azure.Storage.Files.Shares.Models.ShareRootSquash?)) { throw null; } + public static Azure.Storage.Files.Shares.Models.ShareProperties ShareProperties(string accessTier = null, System.DateTimeOffset? lastModified = default(System.DateTimeOffset?), int? provisionedIops = default(int?), int? provisionedIngressMBps = default(int?), int? provisionedEgressMBps = default(int?), System.DateTimeOffset? nextAllowedQuotaDowngradeTime = default(System.DateTimeOffset?), System.DateTimeOffset? deletedOn = default(System.DateTimeOffset?), int? remainingRetentionDays = default(int?), Azure.ETag? eTag = default(Azure.ETag?), System.DateTimeOffset? accessTierChangeTime = default(System.DateTimeOffset?), string accessTierTransitionState = null, Azure.Storage.Files.Shares.Models.ShareLeaseStatus? leaseStatus = default(Azure.Storage.Files.Shares.Models.ShareLeaseStatus?), Azure.Storage.Files.Shares.Models.ShareLeaseState? leaseState = default(Azure.Storage.Files.Shares.Models.ShareLeaseState?), Azure.Storage.Files.Shares.Models.ShareLeaseDuration? leaseDuration = default(Azure.Storage.Files.Shares.Models.ShareLeaseDuration?), int? quotaInGB = default(int?), System.Collections.Generic.IDictionary metadata = null, Azure.Storage.Files.Shares.Models.ShareProtocols? protocols = default(Azure.Storage.Files.Shares.Models.ShareProtocols?), Azure.Storage.Files.Shares.Models.ShareRootSquash? rootSquash = default(Azure.Storage.Files.Shares.Models.ShareRootSquash?), bool? enableSnapshotVirtualDirectoryAccess = default(bool?)) { throw null; } public static Azure.Storage.Files.Shares.Models.ShareSnapshotInfo ShareSnapshotInfo(string snapshot, Azure.ETag eTag, System.DateTimeOffset lastModified) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static Azure.Storage.Files.Shares.Models.ShareStatistics ShareStatistics(int shareUsageBytes) { throw null; } @@ -1026,6 +1030,7 @@ internal ShareProperties() { } public System.DateTimeOffset? AccessTierChangeTime { get { throw null; } } public string AccessTierTransitionState { get { throw null; } } public System.DateTimeOffset? DeletedOn { get { throw null; } } + public bool? EnableSnapshotVirtualDirectoryAccess { get { throw null; } } public Azure.ETag? ETag { get { throw null; } } public System.DateTimeOffset? LastModified { get { throw null; } } public Azure.Storage.Files.Shares.Models.ShareLeaseDuration? LeaseDuration { get { throw null; } } @@ -1080,6 +1085,7 @@ public partial class ShareSetPropertiesOptions public ShareSetPropertiesOptions() { } public Azure.Storage.Files.Shares.Models.ShareAccessTier? AccessTier { get { throw null; } set { } } public Azure.Storage.Files.Shares.Models.ShareFileRequestConditions Conditions { get { throw null; } set { } } + public bool? EnableSnapshotVirtualDirectoryAccess { get { throw null; } set { } } public int? QuotaInGB { get { throw null; } set { } } public Azure.Storage.Files.Shares.Models.ShareRootSquash? RootSquash { get { throw null; } set { } } } diff --git a/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.netstandard2.0.cs b/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.netstandard2.0.cs index 064276f5b553c..f050dbe2cd84a 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.netstandard2.0.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.netstandard2.0.cs @@ -128,6 +128,7 @@ public enum ServiceVersion V2023_11_03 = 20, V2024_02_04 = 21, V2024_05_04 = 22, + V2024_08_04 = 23, } } public partial class ShareDirectoryClient @@ -548,6 +549,7 @@ public partial class ShareCreateOptions { public ShareCreateOptions() { } public Azure.Storage.Files.Shares.Models.ShareAccessTier? AccessTier { get { throw null; } set { } } + public bool? EnableSnapshotVirtualDirectoryAccess { get { throw null; } set { } } public System.Collections.Generic.IDictionary Metadata { get { throw null; } set { } } public Azure.Storage.Files.Shares.Models.ShareProtocols? Protocols { get { throw null; } set { } } public int? QuotaInGB { get { throw null; } set { } } @@ -1010,7 +1012,9 @@ public static partial class ShareModelFactory public static Azure.Storage.Files.Shares.Models.ShareProperties ShareProperties(System.DateTimeOffset? lastModified, Azure.ETag? eTag, int? provisionedIops, int? provisionedIngressMBps, int? provisionedEgressMBps, System.DateTimeOffset? nextAllowedQuotaDowngradeTime, int? quotaInGB, System.Collections.Generic.IDictionary metadata) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static Azure.Storage.Files.Shares.Models.ShareProperties ShareProperties(string accessTier, System.DateTimeOffset? lastModified, int? provisionedIops, int? provisionedIngressMBps, int? provisionedEgressMBps, System.DateTimeOffset? nextAllowedQuotaDowngradeTime, System.DateTimeOffset? deletedOn, int? remainingRetentionDays, Azure.ETag? eTag, System.DateTimeOffset? accessTierChangeTime, string accessTierTransitionState, Azure.Storage.Files.Shares.Models.ShareLeaseStatus? leaseStatus, Azure.Storage.Files.Shares.Models.ShareLeaseState? leaseState, Azure.Storage.Files.Shares.Models.ShareLeaseDuration? leaseDuration, int? quotaInGB, System.Collections.Generic.IDictionary metadata) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static Azure.Storage.Files.Shares.Models.ShareProperties ShareProperties(string accessTier = null, System.DateTimeOffset? lastModified = default(System.DateTimeOffset?), int? provisionedIops = default(int?), int? provisionedIngressMBps = default(int?), int? provisionedEgressMBps = default(int?), System.DateTimeOffset? nextAllowedQuotaDowngradeTime = default(System.DateTimeOffset?), System.DateTimeOffset? deletedOn = default(System.DateTimeOffset?), int? remainingRetentionDays = default(int?), Azure.ETag? eTag = default(Azure.ETag?), System.DateTimeOffset? accessTierChangeTime = default(System.DateTimeOffset?), string accessTierTransitionState = null, Azure.Storage.Files.Shares.Models.ShareLeaseStatus? leaseStatus = default(Azure.Storage.Files.Shares.Models.ShareLeaseStatus?), Azure.Storage.Files.Shares.Models.ShareLeaseState? leaseState = default(Azure.Storage.Files.Shares.Models.ShareLeaseState?), Azure.Storage.Files.Shares.Models.ShareLeaseDuration? leaseDuration = default(Azure.Storage.Files.Shares.Models.ShareLeaseDuration?), int? quotaInGB = default(int?), System.Collections.Generic.IDictionary metadata = null, Azure.Storage.Files.Shares.Models.ShareProtocols? protocols = default(Azure.Storage.Files.Shares.Models.ShareProtocols?), Azure.Storage.Files.Shares.Models.ShareRootSquash? rootSquash = default(Azure.Storage.Files.Shares.Models.ShareRootSquash?)) { throw null; } + public static Azure.Storage.Files.Shares.Models.ShareProperties ShareProperties(string accessTier = null, System.DateTimeOffset? lastModified = default(System.DateTimeOffset?), int? provisionedIops = default(int?), int? provisionedIngressMBps = default(int?), int? provisionedEgressMBps = default(int?), System.DateTimeOffset? nextAllowedQuotaDowngradeTime = default(System.DateTimeOffset?), System.DateTimeOffset? deletedOn = default(System.DateTimeOffset?), int? remainingRetentionDays = default(int?), Azure.ETag? eTag = default(Azure.ETag?), System.DateTimeOffset? accessTierChangeTime = default(System.DateTimeOffset?), string accessTierTransitionState = null, Azure.Storage.Files.Shares.Models.ShareLeaseStatus? leaseStatus = default(Azure.Storage.Files.Shares.Models.ShareLeaseStatus?), Azure.Storage.Files.Shares.Models.ShareLeaseState? leaseState = default(Azure.Storage.Files.Shares.Models.ShareLeaseState?), Azure.Storage.Files.Shares.Models.ShareLeaseDuration? leaseDuration = default(Azure.Storage.Files.Shares.Models.ShareLeaseDuration?), int? quotaInGB = default(int?), System.Collections.Generic.IDictionary metadata = null, Azure.Storage.Files.Shares.Models.ShareProtocols? protocols = default(Azure.Storage.Files.Shares.Models.ShareProtocols?), Azure.Storage.Files.Shares.Models.ShareRootSquash? rootSquash = default(Azure.Storage.Files.Shares.Models.ShareRootSquash?), bool? enableSnapshotVirtualDirectoryAccess = default(bool?)) { throw null; } public static Azure.Storage.Files.Shares.Models.ShareSnapshotInfo ShareSnapshotInfo(string snapshot, Azure.ETag eTag, System.DateTimeOffset lastModified) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static Azure.Storage.Files.Shares.Models.ShareStatistics ShareStatistics(int shareUsageBytes) { throw null; } @@ -1026,6 +1030,7 @@ internal ShareProperties() { } public System.DateTimeOffset? AccessTierChangeTime { get { throw null; } } public string AccessTierTransitionState { get { throw null; } } public System.DateTimeOffset? DeletedOn { get { throw null; } } + public bool? EnableSnapshotVirtualDirectoryAccess { get { throw null; } } public Azure.ETag? ETag { get { throw null; } } public System.DateTimeOffset? LastModified { get { throw null; } } public Azure.Storage.Files.Shares.Models.ShareLeaseDuration? LeaseDuration { get { throw null; } } @@ -1080,6 +1085,7 @@ public partial class ShareSetPropertiesOptions public ShareSetPropertiesOptions() { } public Azure.Storage.Files.Shares.Models.ShareAccessTier? AccessTier { get { throw null; } set { } } public Azure.Storage.Files.Shares.Models.ShareFileRequestConditions Conditions { get { throw null; } set { } } + public bool? EnableSnapshotVirtualDirectoryAccess { get { throw null; } set { } } public int? QuotaInGB { get { throw null; } set { } } public Azure.Storage.Files.Shares.Models.ShareRootSquash? RootSquash { get { throw null; } set { } } } diff --git a/sdk/storage/Azure.Storage.Files.Shares/assets.json b/sdk/storage/Azure.Storage.Files.Shares/assets.json index b7deb183ae341..8f49e15e02591 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/assets.json +++ b/sdk/storage/Azure.Storage.Files.Shares/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "net", "TagPrefix": "net/storage/Azure.Storage.Files.Shares", - "Tag": "net/storage/Azure.Storage.Files.Shares_87d726d414" + "Tag": "net/storage/Azure.Storage.Files.Shares_07c3d59f5a" } diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/DirectoryRestClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/DirectoryRestClient.cs index 617da0993ae90..721c8543f58c5 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/DirectoryRestClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/DirectoryRestClient.cs @@ -33,7 +33,7 @@ internal partial class DirectoryRestClient /// The handler for diagnostic messaging in the client. /// The HTTP pipeline for sending and receiving REST requests and responses. /// The URL of the service account, share, directory or file that is the target of the desired operation. - /// Specifies the version of the operation to use for this request. The default value is "2024-05-04". + /// Specifies the version of the operation to use for this request. The default value is "2024-08-04". /// If true, the trailing dot will not be trimmed from the target URI. /// Valid value is backup. /// If true, the trailing dot will not be trimmed from the source URI. diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/FileRestClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/FileRestClient.cs index 017c18d102599..311768d7eb11d 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/FileRestClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/FileRestClient.cs @@ -34,7 +34,7 @@ internal partial class FileRestClient /// The handler for diagnostic messaging in the client. /// The HTTP pipeline for sending and receiving REST requests and responses. /// The URL of the service account, share, directory or file that is the target of the desired operation. - /// Specifies the version of the operation to use for this request. The default value is "2024-05-04". + /// Specifies the version of the operation to use for this request. The default value is "2024-08-04". /// Only update is supported: - Update: Writes the bytes downloaded from the source url into the specified range. The default value is "update". /// If true, the trailing dot will not be trimmed from the target URI. /// Valid value is backup. diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/SharePropertiesInternal.Serialization.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/SharePropertiesInternal.Serialization.cs index 782d4da23bd81..1ac73541e8bbb 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/SharePropertiesInternal.Serialization.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/SharePropertiesInternal.Serialization.cs @@ -33,6 +33,7 @@ internal static SharePropertiesInternal DeserializeSharePropertiesInternal(XElem ShareLeaseDuration? leaseDuration = default; string enabledProtocols = default; ShareRootSquash? rootSquash = default; + bool? enableSnapshotVirtualDirectoryAccess = default; if (element.Element("Last-Modified") is XElement lastModifiedElement) { lastModified = lastModifiedElement.GetDateTimeOffsetValue("R"); @@ -105,6 +106,10 @@ internal static SharePropertiesInternal DeserializeSharePropertiesInternal(XElem { rootSquash = rootSquashElement.Value.ToShareRootSquash(); } + if (element.Element("EnableSnapshotVirtualDirectoryAccess") is XElement enableSnapshotVirtualDirectoryAccessElement) + { + enableSnapshotVirtualDirectoryAccess = (bool?)enableSnapshotVirtualDirectoryAccessElement; + } return new SharePropertiesInternal( lastModified, etag, @@ -123,7 +128,8 @@ internal static SharePropertiesInternal DeserializeSharePropertiesInternal(XElem leaseState, leaseDuration, enabledProtocols, - rootSquash); + rootSquash, + enableSnapshotVirtualDirectoryAccess); } } } diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/SharePropertiesInternal.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/SharePropertiesInternal.cs index b9744bccc89c6..6ec71d4c99f93 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/SharePropertiesInternal.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/SharePropertiesInternal.cs @@ -46,7 +46,8 @@ internal SharePropertiesInternal(DateTimeOffset lastModified, string etag, int q /// When a share is leased, specifies whether the lease is of infinite or fixed duration. /// /// - internal SharePropertiesInternal(DateTimeOffset lastModified, string etag, int quota, int? provisionedIops, int? provisionedIngressMBps, int? provisionedEgressMBps, int? provisionedBandwidthMiBps, DateTimeOffset? nextAllowedQuotaDowngradeTime, DateTimeOffset? deletedTime, int? remainingRetentionDays, string accessTier, DateTimeOffset? accessTierChangeTime, string accessTierTransitionState, ShareLeaseStatus? leaseStatus, ShareLeaseState? leaseState, ShareLeaseDuration? leaseDuration, string enabledProtocols, ShareRootSquash? rootSquash) + /// + internal SharePropertiesInternal(DateTimeOffset lastModified, string etag, int quota, int? provisionedIops, int? provisionedIngressMBps, int? provisionedEgressMBps, int? provisionedBandwidthMiBps, DateTimeOffset? nextAllowedQuotaDowngradeTime, DateTimeOffset? deletedTime, int? remainingRetentionDays, string accessTier, DateTimeOffset? accessTierChangeTime, string accessTierTransitionState, ShareLeaseStatus? leaseStatus, ShareLeaseState? leaseState, ShareLeaseDuration? leaseDuration, string enabledProtocols, ShareRootSquash? rootSquash, bool? enableSnapshotVirtualDirectoryAccess) { LastModified = lastModified; Etag = etag; @@ -66,6 +67,7 @@ internal SharePropertiesInternal(DateTimeOffset lastModified, string etag, int q LeaseDuration = leaseDuration; EnabledProtocols = enabledProtocols; RootSquash = rootSquash; + EnableSnapshotVirtualDirectoryAccess = enableSnapshotVirtualDirectoryAccess; } /// Gets the last modified. @@ -104,5 +106,7 @@ internal SharePropertiesInternal(DateTimeOffset lastModified, string etag, int q public string EnabledProtocols { get; } /// Gets the root squash. public ShareRootSquash? RootSquash { get; } + /// Gets the enable snapshot virtual directory access. + public bool? EnableSnapshotVirtualDirectoryAccess { get; } } } diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/StorageError.Serialization.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/StorageError.Serialization.cs index f4999a162c6bb..349c345fb98d2 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/StorageError.Serialization.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/StorageError.Serialization.cs @@ -15,11 +15,31 @@ internal partial class StorageError internal static StorageError DeserializeStorageError(XElement element) { string message = default; + long? copySourceStatusCode = default; + string copySourceErrorCode = default; + string copySourceErrorMessage = default; + string authenticationErrorDetail = default; if (element.Element("Message") is XElement messageElement) { message = (string)messageElement; } - return new StorageError(message); + if (element.Element("CopySourceStatusCode") is XElement copySourceStatusCodeElement) + { + copySourceStatusCode = (long?)copySourceStatusCodeElement; + } + if (element.Element("CopySourceErrorCode") is XElement copySourceErrorCodeElement) + { + copySourceErrorCode = (string)copySourceErrorCodeElement; + } + if (element.Element("CopySourceErrorMessage") is XElement copySourceErrorMessageElement) + { + copySourceErrorMessage = (string)copySourceErrorMessageElement; + } + if (element.Element("AuthenticationErrorDetail") is XElement authenticationErrorDetailElement) + { + authenticationErrorDetail = (string)authenticationErrorDetailElement; + } + return new StorageError(message, copySourceStatusCode, copySourceErrorCode, copySourceErrorMessage, authenticationErrorDetail); } internal static StorageError DeserializeStorageError(JsonElement element) @@ -29,6 +49,10 @@ internal static StorageError DeserializeStorageError(JsonElement element) return null; } string message = default; + long? copySourceStatusCode = default; + string copySourceErrorCode = default; + string copySourceErrorMessage = default; + string authenticationErrorDetail = default; foreach (var property in element.EnumerateObject()) { if (property.NameEquals("Message"u8)) @@ -36,8 +60,32 @@ internal static StorageError DeserializeStorageError(JsonElement element) message = property.Value.GetString(); continue; } + if (property.NameEquals("CopySourceStatusCode"u8)) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + copySourceStatusCode = property.Value.GetInt64(); + continue; + } + if (property.NameEquals("CopySourceErrorCode"u8)) + { + copySourceErrorCode = property.Value.GetString(); + continue; + } + if (property.NameEquals("CopySourceErrorMessage"u8)) + { + copySourceErrorMessage = property.Value.GetString(); + continue; + } + if (property.NameEquals("AuthenticationErrorDetail"u8)) + { + authenticationErrorDetail = property.Value.GetString(); + continue; + } } - return new StorageError(message); + return new StorageError(message, copySourceStatusCode, copySourceErrorCode, copySourceErrorMessage, authenticationErrorDetail); } /// Deserializes the model from a raw response. diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/StorageError.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/StorageError.cs index 06a8dc2fbf775..802d735422e67 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/StorageError.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/StorageError.cs @@ -17,12 +17,28 @@ internal StorageError() /// Initializes a new instance of . /// - internal StorageError(string message) + /// + /// + /// + /// + internal StorageError(string message, long? copySourceStatusCode, string copySourceErrorCode, string copySourceErrorMessage, string authenticationErrorDetail) { Message = message; + CopySourceStatusCode = copySourceStatusCode; + CopySourceErrorCode = copySourceErrorCode; + CopySourceErrorMessage = copySourceErrorMessage; + AuthenticationErrorDetail = authenticationErrorDetail; } /// Gets the message. public string Message { get; } + /// Gets the copy source status code. + public long? CopySourceStatusCode { get; } + /// Gets the copy source error code. + public string CopySourceErrorCode { get; } + /// Gets the copy source error message. + public string CopySourceErrorMessage { get; } + /// Gets the authentication error detail. + public string AuthenticationErrorDetail { get; } } } diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ServiceRestClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ServiceRestClient.cs index 3eaa211c4efbd..7f585a313d408 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ServiceRestClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ServiceRestClient.cs @@ -30,7 +30,7 @@ internal partial class ServiceRestClient /// The handler for diagnostic messaging in the client. /// The HTTP pipeline for sending and receiving REST requests and responses. /// The URL of the service account, share, directory or file that is the target of the desired operation. - /// Specifies the version of the operation to use for this request. The default value is "2024-05-04". + /// Specifies the version of the operation to use for this request. The default value is "2024-08-04". /// , , or is null. public ServiceRestClient(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, string url, string version) { diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ShareGetPropertiesHeaders.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ShareGetPropertiesHeaders.cs index 6fcf77b007b79..0927ef1dcd2ae 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ShareGetPropertiesHeaders.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ShareGetPropertiesHeaders.cs @@ -53,5 +53,7 @@ public ShareGetPropertiesHeaders(Response response) public string EnabledProtocols => _response.Headers.TryGetValue("x-ms-enabled-protocols", out string value) ? value : null; /// Valid for NFS shares only. public ShareRootSquash? RootSquash => _response.Headers.TryGetValue("x-ms-root-squash", out string value) ? value.ToShareRootSquash() : null; + /// Version 2023-08-03 and newer. Specifies whether the snapshot virtual directory should be accessible at the root of share mount point when NFS is enabled. This header is only returned for shares, not for snapshots. + public bool? EnableSnapshotVirtualDirectoryAccess => _response.Headers.TryGetValue("x-ms-enable-snapshot-virtual-directory-access", out bool? value) ? value : null; } } diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ShareRestClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ShareRestClient.cs index ee4bb0017b09d..1845a43a18239 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ShareRestClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ShareRestClient.cs @@ -32,7 +32,7 @@ internal partial class ShareRestClient /// The handler for diagnostic messaging in the client. /// The HTTP pipeline for sending and receiving REST requests and responses. /// The URL of the service account, share, directory or file that is the target of the desired operation. - /// Specifies the version of the operation to use for this request. The default value is "2024-05-04". + /// Specifies the version of the operation to use for this request. The default value is "2024-08-04". /// Valid value is backup. /// , , or is null. public ShareRestClient(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, string url, string version, ShareTokenIntent? fileRequestIntent = null) @@ -44,7 +44,7 @@ public ShareRestClient(ClientDiagnostics clientDiagnostics, HttpPipeline pipelin _fileRequestIntent = fileRequestIntent; } - internal HttpMessage CreateCreateRequest(int? timeout, IDictionary metadata, int? quota, ShareAccessTier? accessTier, string enabledProtocols, ShareRootSquash? rootSquash) + internal HttpMessage CreateCreateRequest(int? timeout, IDictionary metadata, int? quota, ShareAccessTier? accessTier, string enabledProtocols, ShareRootSquash? rootSquash, bool? enableSnapshotVirtualDirectoryAccess) { var message = _pipeline.CreateMessage(); var request = message.Request; @@ -78,6 +78,10 @@ internal HttpMessage CreateCreateRequest(int? timeout, IDictionary Specifies the access tier of the share. /// Protocols to enable on the share. /// Root squash to set on the share. Only valid for NFS shares. + /// The ? to use. /// The cancellation token to use. - public async Task> CreateAsync(int? timeout = null, IDictionary metadata = null, int? quota = null, ShareAccessTier? accessTier = null, string enabledProtocols = null, ShareRootSquash? rootSquash = null, CancellationToken cancellationToken = default) + public async Task> CreateAsync(int? timeout = null, IDictionary metadata = null, int? quota = null, ShareAccessTier? accessTier = null, string enabledProtocols = null, ShareRootSquash? rootSquash = null, bool? enableSnapshotVirtualDirectoryAccess = null, CancellationToken cancellationToken = default) { - using var message = CreateCreateRequest(timeout, metadata, quota, accessTier, enabledProtocols, rootSquash); + using var message = CreateCreateRequest(timeout, metadata, quota, accessTier, enabledProtocols, rootSquash, enableSnapshotVirtualDirectoryAccess); await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); var headers = new ShareCreateHeaders(message.Response); switch (message.Response.Status) @@ -111,10 +116,11 @@ public async Task> CreateAsync(int? time /// Specifies the access tier of the share. /// Protocols to enable on the share. /// Root squash to set on the share. Only valid for NFS shares. + /// The ? to use. /// The cancellation token to use. - public ResponseWithHeaders Create(int? timeout = null, IDictionary metadata = null, int? quota = null, ShareAccessTier? accessTier = null, string enabledProtocols = null, ShareRootSquash? rootSquash = null, CancellationToken cancellationToken = default) + public ResponseWithHeaders Create(int? timeout = null, IDictionary metadata = null, int? quota = null, ShareAccessTier? accessTier = null, string enabledProtocols = null, ShareRootSquash? rootSquash = null, bool? enableSnapshotVirtualDirectoryAccess = null, CancellationToken cancellationToken = default) { - using var message = CreateCreateRequest(timeout, metadata, quota, accessTier, enabledProtocols, rootSquash); + using var message = CreateCreateRequest(timeout, metadata, quota, accessTier, enabledProtocols, rootSquash, enableSnapshotVirtualDirectoryAccess); _pipeline.Send(message, cancellationToken); var headers = new ShareCreateHeaders(message.Response); switch (message.Response.Status) @@ -851,7 +857,7 @@ public ResponseWithHeaders GetPermis } } - internal HttpMessage CreateSetPropertiesRequest(int? timeout, int? quota, ShareAccessTier? accessTier, ShareRootSquash? rootSquash, ShareFileRequestConditions leaseAccessConditions) + internal HttpMessage CreateSetPropertiesRequest(int? timeout, int? quota, ShareAccessTier? accessTier, ShareRootSquash? rootSquash, bool? enableSnapshotVirtualDirectoryAccess, ShareFileRequestConditions leaseAccessConditions) { var message = _pipeline.CreateMessage(); var request = message.Request; @@ -882,6 +888,10 @@ internal HttpMessage CreateSetPropertiesRequest(int? timeout, int? quota, ShareA { request.Headers.Add("x-ms-root-squash", rootSquash.Value.ToSerialString()); } + if (enableSnapshotVirtualDirectoryAccess != null) + { + request.Headers.Add("x-ms-enable-snapshot-virtual-directory-access", enableSnapshotVirtualDirectoryAccess.Value); + } request.Headers.Add("Accept", "application/xml"); return message; } @@ -891,11 +901,12 @@ internal HttpMessage CreateSetPropertiesRequest(int? timeout, int? quota, ShareA /// Specifies the maximum size of the share, in gigabytes. /// Specifies the access tier of the share. /// Root squash to set on the share. Only valid for NFS shares. + /// The ? to use. /// Parameter group. /// The cancellation token to use. - public async Task> SetPropertiesAsync(int? timeout = null, int? quota = null, ShareAccessTier? accessTier = null, ShareRootSquash? rootSquash = null, ShareFileRequestConditions leaseAccessConditions = null, CancellationToken cancellationToken = default) + public async Task> SetPropertiesAsync(int? timeout = null, int? quota = null, ShareAccessTier? accessTier = null, ShareRootSquash? rootSquash = null, bool? enableSnapshotVirtualDirectoryAccess = null, ShareFileRequestConditions leaseAccessConditions = null, CancellationToken cancellationToken = default) { - using var message = CreateSetPropertiesRequest(timeout, quota, accessTier, rootSquash, leaseAccessConditions); + using var message = CreateSetPropertiesRequest(timeout, quota, accessTier, rootSquash, enableSnapshotVirtualDirectoryAccess, leaseAccessConditions); await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); var headers = new ShareSetPropertiesHeaders(message.Response); switch (message.Response.Status) @@ -912,11 +923,12 @@ public async Task> SetPropertiesA /// Specifies the maximum size of the share, in gigabytes. /// Specifies the access tier of the share. /// Root squash to set on the share. Only valid for NFS shares. + /// The ? to use. /// Parameter group. /// The cancellation token to use. - public ResponseWithHeaders SetProperties(int? timeout = null, int? quota = null, ShareAccessTier? accessTier = null, ShareRootSquash? rootSquash = null, ShareFileRequestConditions leaseAccessConditions = null, CancellationToken cancellationToken = default) + public ResponseWithHeaders SetProperties(int? timeout = null, int? quota = null, ShareAccessTier? accessTier = null, ShareRootSquash? rootSquash = null, bool? enableSnapshotVirtualDirectoryAccess = null, ShareFileRequestConditions leaseAccessConditions = null, CancellationToken cancellationToken = default) { - using var message = CreateSetPropertiesRequest(timeout, quota, accessTier, rootSquash, leaseAccessConditions); + using var message = CreateSetPropertiesRequest(timeout, quota, accessTier, rootSquash, enableSnapshotVirtualDirectoryAccess, leaseAccessConditions); _pipeline.Send(message, cancellationToken); var headers = new ShareSetPropertiesHeaders(message.Response); switch (message.Response.Status) diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Models/ShareCreateOptions.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Models/ShareCreateOptions.cs index 5a1796cc1da08..21a50550f9ce1 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Models/ShareCreateOptions.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Models/ShareCreateOptions.cs @@ -39,5 +39,12 @@ public class ShareCreateOptions /// The root squash to set for the share. Only valid for NFS shares. /// public ShareRootSquash? RootSquash { get; set; } + + /// + /// Optional. Supported in version 2023-08-03 and above. + /// Specifies whether the snapshot virtual directory should be accessible at the root of share mount point when NFS is enabled. + /// If not specified, the default is true. + /// + public bool? EnableSnapshotVirtualDirectoryAccess { get; set; } } } diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Models/ShareModelFactory.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Models/ShareModelFactory.cs index f67c56cedb1d2..f68c3f3947623 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Models/ShareModelFactory.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Models/ShareModelFactory.cs @@ -22,6 +22,51 @@ public static StorageClosedHandlesSegment StorageClosedHandlesSegment( => StorageClosedHandlesSegment( marker: marker, numberOfHandlesClosed: numberOfHandlesClosed); + /// + /// Creates a new ShareProperties instance for mocking. + /// + public static ShareProperties ShareProperties( + string accessTier = default, + DateTimeOffset? lastModified = default, + int? provisionedIops = default, + int? provisionedIngressMBps = default, + int? provisionedEgressMBps = default, + DateTimeOffset? nextAllowedQuotaDowngradeTime = default, + DateTimeOffset? deletedOn = default, + int? remainingRetentionDays = default, + ETag? eTag = default, + DateTimeOffset? accessTierChangeTime = default, + string accessTierTransitionState = default, + ShareLeaseStatus? leaseStatus = default, + ShareLeaseState? leaseState = default, + ShareLeaseDuration? leaseDuration = default, + int? quotaInGB = default, + IDictionary metadata = default, + ShareProtocols? protocols = default, + ShareRootSquash? rootSquash = default, + bool? enableSnapshotVirtualDirectoryAccess = default) + => new ShareProperties() + { + AccessTier = accessTier, + LastModified = lastModified, + ProvisionedIops = provisionedIops, + ProvisionedIngressMBps = provisionedIngressMBps, + ProvisionedEgressMBps = provisionedEgressMBps, + NextAllowedQuotaDowngradeTime = nextAllowedQuotaDowngradeTime, + DeletedOn = deletedOn, + RemainingRetentionDays = remainingRetentionDays, + ETag = eTag, + AccessTierChangeTime = accessTierChangeTime, + AccessTierTransitionState = accessTierTransitionState, + LeaseStatus = leaseStatus, + LeaseState = leaseState, + LeaseDuration = leaseDuration, + QuotaInGB = quotaInGB, + Metadata = metadata, + Protocols = protocols, + RootSquash = rootSquash, + EnableSnapshotVirtualDirectoryAccess = enableSnapshotVirtualDirectoryAccess + }; /// /// Creates a new ShareProperties instance for mocking. @@ -55,6 +100,7 @@ public static ShareProperties ShareProperties( /// /// Creates a new ShareProperties instance for mocking. /// + [EditorBrowsable(EditorBrowsableState.Never)] public static ShareProperties ShareProperties( string accessTier = default, DateTimeOffset? lastModified = default, diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Models/ShareProperties.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Models/ShareProperties.cs index 40919e0ac3d70..0c09603e73c58 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Models/ShareProperties.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Models/ShareProperties.cs @@ -112,6 +112,13 @@ public class ShareProperties /// public IDictionary Metadata { get; internal set; } + /// + /// Optional. Supported in version 2023-08-03 and above. + /// Specifies whether the snapshot virtual directory should be accessible at the root of share mount point when NFS is enabled. + /// If not specified, the default is true. + /// + public bool? EnableSnapshotVirtualDirectoryAccess { get; internal set; } + /// /// Internal constructor. /// diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Models/ShareSetPropertiesOptions.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Models/ShareSetPropertiesOptions.cs index 62190ab4897f5..8a6ed09409e05 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Models/ShareSetPropertiesOptions.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Models/ShareSetPropertiesOptions.cs @@ -23,6 +23,13 @@ public class ShareSetPropertiesOptions /// public ShareRootSquash? RootSquash { get; set; } + /// + /// Optional. Supported in version 2023-08-03 and above. + /// Specifies whether the snapshot virtual directory should be accessible at the root of share mount point when NFS is enabled. + /// If not specified, the default is true. + /// + + public bool? EnableSnapshotVirtualDirectoryAccess { get; set; } /// /// Optional to add conditions /// on setting the share's properties. diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs index bf1be458c9f62..8e8bd32d3781b 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs @@ -486,6 +486,7 @@ public virtual Response Create( options?.AccessTier, options?.Protocols, options?.RootSquash, + options?.EnableSnapshotVirtualDirectoryAccess, async: false, cancellationToken) .EnsureCompleted(); @@ -523,6 +524,7 @@ await CreateInternal( options?.AccessTier, options?.Protocols, options?.RootSquash, + options?.EnableSnapshotVirtualDirectoryAccess, async: true, cancellationToken) .ConfigureAwait(false); @@ -565,6 +567,7 @@ public virtual Response Create( accessTier: default, enabledProtocols: default, rootSquash: default, + enableSnapshotVirtualDirectoryAccess: default, async: false, cancellationToken) .EnsureCompleted(); @@ -607,6 +610,7 @@ await CreateInternal( accessTier: default, enabledProtocols: default, rootSquash: default, + enableSnapshotVirtualDirectoryAccess: default, async: true, cancellationToken) .ConfigureAwait(false); @@ -635,6 +639,11 @@ await CreateInternal( /// /// Squash root to set on the share. /// + /// + /// Optional. Supported in version 2023-08-03 and above. + /// Specifies whether the snapshot virtual directory should be accessible at the root of share mount point when NFS is enabled. + /// If not specified, the default is true. + /// /// /// Whether to invoke the operation asynchronously. /// @@ -659,6 +668,7 @@ internal async Task> CreateInternal( ShareAccessTier? accessTier, ShareProtocols? enabledProtocols, ShareRootSquash? rootSquash, + bool? enableSnapshotVirtualDirectoryAccess, bool async, CancellationToken cancellationToken, string operationName = default) @@ -687,6 +697,7 @@ internal async Task> CreateInternal( accessTier: accessTier, enabledProtocols: enabledProtocols.ToShareEnableProtocolsString(), rootSquash: rootSquash, + enableSnapshotVirtualDirectoryAccess: enableSnapshotVirtualDirectoryAccess, cancellationToken: cancellationToken) .ConfigureAwait(false); } @@ -698,6 +709,7 @@ internal async Task> CreateInternal( accessTier: accessTier, enabledProtocols: enabledProtocols.ToShareEnableProtocolsString(), rootSquash: rootSquash, + enableSnapshotVirtualDirectoryAccess: enableSnapshotVirtualDirectoryAccess, cancellationToken: cancellationToken); } @@ -754,6 +766,7 @@ public virtual Response CreateIfNotExists( options?.AccessTier, options?.Protocols, options?.RootSquash, + options?.EnableSnapshotVirtualDirectoryAccess, async: false, cancellationToken).EnsureCompleted(); @@ -790,6 +803,7 @@ await CreateIfNotExistsInternal( options?.AccessTier, options?.Protocols, options?.RootSquash, + options?.EnableSnapshotVirtualDirectoryAccess, async: true, cancellationToken).ConfigureAwait(false); @@ -831,6 +845,7 @@ public virtual Response CreateIfNotExists( accessTier: default, enabledProtocols: default, squashRoot: default, + enableSnapshotVirtualDirectoryAccess: default, async: false, cancellationToken).EnsureCompleted(); @@ -871,6 +886,7 @@ await CreateIfNotExistsInternal( accessTier: default, enabledProtocols: default, squashRoot: default, + enableSnapshotVirtualDirectoryAccess: default, async: true, cancellationToken).ConfigureAwait(false); @@ -898,6 +914,11 @@ await CreateIfNotExistsInternal( /// /// Squash root to set on the share. /// + /// + /// Optional. Supported in version 2023-08-03 and above. + /// Specifies whether the snapshot virtual directory should be accessible at the root of share mount point when NFS is enabled. + /// If not specified, the default is true. + /// /// /// Whether to invoke the operation asynchronously. /// @@ -919,6 +940,7 @@ private async Task> CreateIfNotExistsInternal( ShareAccessTier? accessTier, ShareProtocols? enabledProtocols, ShareRootSquash? squashRoot, + bool? enableSnapshotVirtualDirectoryAccess, bool async, CancellationToken cancellationToken) { @@ -938,6 +960,7 @@ private async Task> CreateIfNotExistsInternal( accessTier, enabledProtocols, squashRoot, + enableSnapshotVirtualDirectoryAccess, async, cancellationToken, operationName: $"{nameof(ShareClient)}.{nameof(CreateIfNotExists)}") @@ -1903,6 +1926,7 @@ public virtual Response SetProperties( quotaInGB: options?.QuotaInGB, accessTier: options?.AccessTier, rootSquash: options?.RootSquash, + enableSnapshotVirtualDirectoryAccess: options?.EnableSnapshotVirtualDirectoryAccess, conditions: options?.Conditions, operationName: $"{nameof(ShareClient)}.{nameof(SetProperties)}", async: false, @@ -1938,6 +1962,7 @@ await SetPropertiesInternal( quotaInGB: options?.QuotaInGB, accessTier: options?.AccessTier, rootSquash: options?.RootSquash, + enableSnapshotVirtualDirectoryAccess: options?.EnableSnapshotVirtualDirectoryAccess, conditions: options?.Conditions, operationName: $"{nameof(ShareClient)}.{nameof(SetProperties)}", async: true, @@ -1961,6 +1986,11 @@ await SetPropertiesInternal( /// /// The root squash to set for the share. Only valid for NFS shares. /// + /// + /// Optional. Supported in version 2023-08-03 and above. + /// Specifies whether the snapshot virtual directory should be accessible at the root of share mount point when NFS is enabled. + /// If not specified, the default is true. + /// /// /// Optional to add conditions /// on setting the quota. @@ -1987,6 +2017,7 @@ internal virtual async Task> SetPropertiesInternal( int? quotaInGB, ShareAccessTier? accessTier, ShareRootSquash? rootSquash, + bool? enableSnapshotVirtualDirectoryAccess, ShareFileRequestConditions conditions, string operationName, bool async, @@ -2015,6 +2046,7 @@ internal virtual async Task> SetPropertiesInternal( quota: quotaInGB, accessTier: accessTier, rootSquash: rootSquash, + enableSnapshotVirtualDirectoryAccess: enableSnapshotVirtualDirectoryAccess, leaseAccessConditions: conditions, cancellationToken: cancellationToken) .ConfigureAwait(false); @@ -2025,6 +2057,7 @@ internal virtual async Task> SetPropertiesInternal( quota: quotaInGB, accessTier: accessTier, rootSquash: rootSquash, + enableSnapshotVirtualDirectoryAccess: enableSnapshotVirtualDirectoryAccess, leaseAccessConditions: conditions, cancellationToken: cancellationToken); } @@ -2085,6 +2118,7 @@ public virtual Response SetQuota( quotaInGB: quotaInGB, accessTier: default, rootSquash: default, + enableSnapshotVirtualDirectoryAccess: default, conditions: conditions, operationName: $"{nameof(ShareClient)}.{nameof(SetQuota)}", async: false, @@ -2127,6 +2161,7 @@ await SetPropertiesInternal( quotaInGB: quotaInGB, accessTier: default, rootSquash: default, + enableSnapshotVirtualDirectoryAccess: default, conditions: conditions, operationName: $"{nameof(ShareClient)}.{nameof(SetQuota)}", async: true, @@ -2167,6 +2202,7 @@ public virtual Response SetQuota( quotaInGB: quotaInGB, accessTier: default, rootSquash: default, + enableSnapshotVirtualDirectoryAccess: default, conditions: default, operationName: $"{nameof(ShareClient)}.{nameof(SetQuota)}", async: false, @@ -2206,6 +2242,7 @@ await SetPropertiesInternal( quotaInGB: quotaInGB, accessTier: default, rootSquash: default, + enableSnapshotVirtualDirectoryAccess: default, conditions: default, operationName: $"{nameof(ShareClient)}.{nameof(SetQuota)}", async: true, diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareClientOptions.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareClientOptions.cs index 8a0fea91c2315..0600d6c554182 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareClientOptions.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareClientOptions.cs @@ -138,7 +138,12 @@ public enum ServiceVersion /// /// The 2024-05-04 service version. /// - V2024_05_04 = 22 + V2024_05_04 = 22, + + /// + /// The 2024-08-04 service version. + /// + V2024_08_04 = 23 #pragma warning restore CA1707 // Identifiers should not contain underscores } @@ -259,6 +264,8 @@ private void AddHeadersAndQueryParameters() Diagnostics.LoggedHeaderNames.Add("x-ms-share-quota"); Diagnostics.LoggedHeaderNames.Add("x-ms-type"); Diagnostics.LoggedHeaderNames.Add("x-ms-write"); + Diagnostics.LoggedHeaderNames.Add("x-ms-copy-source-error-code"); + Diagnostics.LoggedHeaderNames.Add("x-ms-copy-source-status-code"); Diagnostics.LoggedQueryParameters.Add("comp"); Diagnostics.LoggedQueryParameters.Add("maxresults"); diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareExtensions.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareExtensions.cs index a578d84b8ca52..199cb9db04547 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareExtensions.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareExtensions.cs @@ -708,8 +708,9 @@ internal static ShareProperties ToShareProperties(this ResponseWithHeaders CreateShare( ShareClient share = GetShareClient(shareName); Response response = share.CreateInternal( - options?.Metadata, - options?.QuotaInGB, - options?.AccessTier, - options?.Protocols, - options?.RootSquash, + metadata: options?.Metadata, + quotaInGB: options?.QuotaInGB, + accessTier: options?.AccessTier, + enabledProtocols: options?.Protocols, + rootSquash: options?.RootSquash, + enableSnapshotVirtualDirectoryAccess: options?.EnableSnapshotVirtualDirectoryAccess, async: false, - cancellationToken, + cancellationToken: cancellationToken, operationName: $"{nameof(ShareServiceClient)}.{nameof(CreateShare)}") .EnsureCompleted(); @@ -931,13 +932,14 @@ public virtual async Task> CreateShareAsync( ShareClient share = GetShareClient(shareName); Response response = await share.CreateInternal( - options?.Metadata, - options?.QuotaInGB, - options?.AccessTier, - options?.Protocols, - options?.RootSquash, + metadata: options?.Metadata, + quotaInGB: options?.QuotaInGB, + accessTier: options?.AccessTier, + enabledProtocols: options?.Protocols, + rootSquash: options?.RootSquash, + enableSnapshotVirtualDirectoryAccess: options?.EnableSnapshotVirtualDirectoryAccess, async: true, - cancellationToken, + cancellationToken: cancellationToken, operationName: $"{nameof(ShareServiceClient)}.{nameof(CreateShare)}") .ConfigureAwait(false); @@ -989,8 +991,9 @@ public virtual Response CreateShare( accessTier: default, enabledProtocols: default, rootSquash: default, + enableSnapshotVirtualDirectoryAccess: default, async: false, - cancellationToken, + cancellationToken: cancellationToken, operationName: $"{nameof(ShareServiceClient)}.{nameof(CreateShare)}") .EnsureCompleted(); @@ -1042,8 +1045,9 @@ public virtual async Task> CreateShareAsync( accessTier: default, enabledProtocols: default, rootSquash: default, + enableSnapshotVirtualDirectoryAccess: default, async: true, - cancellationToken, + cancellationToken: cancellationToken, operationName: $"{nameof(ShareServiceClient)}.{nameof(CreateShare)}") .ConfigureAwait(false); diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/autorest.md b/sdk/storage/Azure.Storage.Files.Shares/src/autorest.md index c2036b083518f..6a871a5763dc3 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/autorest.md +++ b/sdk/storage/Azure.Storage.Files.Shares/src/autorest.md @@ -4,7 +4,7 @@ Run `dotnet build /t:GenerateCode` to generate code. ``` yaml input-file: - - https://raw.githubusercontent.com/Azure/azure-rest-api-specs/5da3c08b92d05858b728b013b69502dc93485373/specification/storage/data-plane/Microsoft.FileStorage/stable/2024-05-04/file.json + - https://raw.githubusercontent.com/Azure/azure-rest-api-specs/8b14ba4a3232adb8538d96832a47dfd695904341/specification/storage/data-plane/Microsoft.FileStorage/stable/2024-08-04/file.json generation1-convenience-client: true # https://github.com/Azure/autorest/issues/4075 skip-semantics-validation: true diff --git a/sdk/storage/Azure.Storage.Files.Shares/tests/FileClientTests.cs b/sdk/storage/Azure.Storage.Files.Shares/tests/FileClientTests.cs index 345ba19f81622..bb5bbd4b2e8d9 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/tests/FileClientTests.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/tests/FileClientTests.cs @@ -1998,6 +1998,24 @@ await TestHelper.AssertExpectedExceptionAsync( e => Assert.AreEqual("CannotVerifyCopySource", e.ErrorCode)); } + [RecordedTest] + [ServiceVersion(Min = ShareClientOptions.ServiceVersion.V2024_08_04)] + public async Task StartCopyAsync_SourceErrorAndStatusCode() + { + await using DisposingFile test = await SharesClientBuilder.GetTestFileAsync(); + ShareFileClient file = test.File; + + // Act + await TestHelper.AssertExpectedExceptionAsync( + file.StartCopyAsync(sourceUri: s_invalidUri), + e => + { + Assert.IsTrue(e.Message.Contains("CopySourceStatusCode: 400")); + Assert.IsTrue(e.Message.Contains("CopySourceErrorCode: InvalidQueryParameterValue")); + Assert.IsTrue(e.Message.Contains("CopySourceErrorMessage: Value for one of the query parameters specified in the request URI is invalid.")); + }); + } + [RecordedTest] public async Task StartCopyAsync_CopySourceFileCreatedOnError() { @@ -4387,6 +4405,38 @@ await TestHelper.AssertExpectedExceptionAsync( e => Assert.AreEqual("CannotVerifyCopySource", e.ErrorCode)); } + [RecordedTest] + [ServiceVersion(Min = ShareClientOptions.ServiceVersion.V2024_08_04)] + public async Task UploadRangeFromUriAsync_SourceErrorAndStatusCode() + { + // Arrange + await using DisposingShare test = await GetTestShareAsync(shareName: GetNewShareName()); + ShareClient share = test.Share; + + ShareDirectoryClient directory = InstrumentClient(share.GetDirectoryClient(GetNewDirectoryName())); + await directory.CreateIfNotExistsAsync(); + + ShareFileClient sourceFile = InstrumentClient(directory.GetFileClient(GetNewFileName())); + + ShareFileClient destFile = directory.GetFileClient(GetNewFileName()); + await destFile.CreateAsync(maxSize: Constants.KB); + + HttpRange range = new HttpRange(0, Constants.KB); + + // Act + await TestHelper.AssertExpectedExceptionAsync( + destFile.UploadRangeFromUriAsync( + sourceUri: destFile.Uri, + range: range, + sourceRange: range), + e => + { + Assert.IsTrue(e.Message.Contains("CopySourceStatusCode: 401")); + Assert.IsTrue(e.Message.Contains("CopySourceErrorCode: NoAuthenticationInformation")); + Assert.IsTrue(e.Message.Contains("CopySourceErrorMessage: Server failed to authenticate the request. Please refer to the information in the www-authenticate header.")); + }); + } + [RecordedTest] [ServiceVersion(Min = ShareClientOptions.ServiceVersion.V2021_06_08)] [TestCase(null)] diff --git a/sdk/storage/Azure.Storage.Files.Shares/tests/ServiceClientTests.cs b/sdk/storage/Azure.Storage.Files.Shares/tests/ServiceClientTests.cs index 353fee18d0844..d05dcc718a12e 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/tests/ServiceClientTests.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/tests/ServiceClientTests.cs @@ -357,6 +357,38 @@ public async Task ListSharesSegmentAsync_EnabledProtocolsAndRootSquash() Assert.AreEqual(ShareRootSquash.AllSquash, shareItem.Properties.RootSquash); } + [RecordedTest] + [ServiceVersion(Min = ShareClientOptions.ServiceVersion.V2024_02_04)] + public async Task ListShares_EnableSnapshotVirtualDirectoryAccess() + { + // Arrange + var shareName = GetNewShareName(); + ShareServiceClient service = SharesClientBuilder.GetServiceClient_SharedKey(); + ShareClient share = InstrumentClient(service.GetShareClient(shareName)); + ShareCreateOptions options = new ShareCreateOptions + { + Protocols = ShareProtocols.Nfs, + EnableSnapshotVirtualDirectoryAccess = true, + }; + + try + { + await share.CreateAsync(options); + + // Act + IList shares = await service.GetSharesAsync().ToListAsync(); + + // Assert + ShareItem shareItem = shares.Where(s => s.Name == share.Name).FirstOrDefault(); + Assert.AreEqual(ShareProtocols.Nfs, shareItem.Properties.Protocols); + Assert.IsTrue(shareItem.Properties.EnableSnapshotVirtualDirectoryAccess); + } + finally + { + await share.DeleteAsync(false); + } + } + [RecordedTest] public async Task CreateShareAsync() { diff --git a/sdk/storage/Azure.Storage.Files.Shares/tests/ShareClientTestFixtureAttribute.cs b/sdk/storage/Azure.Storage.Files.Shares/tests/ShareClientTestFixtureAttribute.cs index 03de4d72432b8..caab598a61d42 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/tests/ShareClientTestFixtureAttribute.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/tests/ShareClientTestFixtureAttribute.cs @@ -35,6 +35,7 @@ public ShareClientTestFixtureAttribute(params object[] additionalParameters) ShareClientOptions.ServiceVersion.V2023_11_03, ShareClientOptions.ServiceVersion.V2024_02_04, ShareClientOptions.ServiceVersion.V2024_05_04, + ShareClientOptions.ServiceVersion.V2024_08_04, StorageVersionExtensions.LatestVersion, StorageVersionExtensions.MaxVersion }, diff --git a/sdk/storage/Azure.Storage.Files.Shares/tests/ShareClientTests.cs b/sdk/storage/Azure.Storage.Files.Shares/tests/ShareClientTests.cs index cfc659905b6da..ed95ba9baa707 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/tests/ShareClientTests.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/tests/ShareClientTests.cs @@ -368,6 +368,30 @@ await TestHelper.AssertExpectedExceptionAsync( await share.DeleteAsync(false); } + /// + /// This test exists to ensure AuthenticationErrorDetail is being properly communicated to the customer. + /// + [RecordedTest] + [ServiceVersion(Min = ShareClientOptions.ServiceVersion.V2024_08_04)] + public async Task CreateAsync_SasError() + { + // Arrange + var shareName = GetNewShareName(); + ShareServiceClient service = SharesClientBuilder.GetServiceClient_SharedKey(); + Uri sasUri = service.GenerateAccountSasUri(AccountSasPermissions.All, GetUtcNow().AddDays(-1), AccountSasResourceTypes.All); + ShareServiceClient unauthorizedServiceClient = InstrumentClient(new ShareServiceClient(sasUri)); + ShareClient share = InstrumentClient(unauthorizedServiceClient.GetShareClient(shareName)); + + // Act + await TestHelper.AssertExpectedExceptionAsync( + share.CreateAsync(), + e => + { + Assert.AreEqual("AuthenticationFailed", e.ErrorCode); + Assert.IsTrue(e.Message.Contains("AuthenticationErrorDetail")); + }); + } + [RecordedTest] public async Task CreateAsync_WithAccountSas() { @@ -500,6 +524,46 @@ public async Task CreateAsync_EnabledProtocolsAndRootSquash() } } + [RecordedTest] + [ServiceVersion(Min = ShareClientOptions.ServiceVersion.V2024_02_04)] + [TestCase(null)] + [TestCase(true)] + [TestCase(false)] + public async Task CreateAsync_EnableSnapshotVirtualDirectoryAccess(bool? enableSnapshotVirtualDirectoryAccess) + { + // Arrange + var shareName = GetNewShareName(); + ShareServiceClient service = SharesClientBuilder.GetServiceClient_SharedKey(); + ShareClient share = InstrumentClient(service.GetShareClient(shareName)); + ShareCreateOptions options = new ShareCreateOptions + { + Protocols = ShareProtocols.Nfs, + EnableSnapshotVirtualDirectoryAccess = enableSnapshotVirtualDirectoryAccess, + }; + + try + { + // Act + await share.CreateAsync(options); + + // Assert + Response response = await share.GetPropertiesAsync(); + Assert.AreEqual(ShareProtocols.Nfs, response.Value.Protocols); + if (enableSnapshotVirtualDirectoryAccess == true || enableSnapshotVirtualDirectoryAccess == null) + { + Assert.IsTrue(response.Value.EnableSnapshotVirtualDirectoryAccess); + } + else + { + Assert.IsFalse(response.Value.EnableSnapshotVirtualDirectoryAccess); + } + } + finally + { + await share.DeleteAsync(false); + } + } + [RecordedTest] public async Task GetPermissionAsync_Error() { @@ -1501,6 +1565,53 @@ await TestHelper.AssertExpectedExceptionAsync( e => Assert.AreEqual(ShareErrorCode.ShareNotFound.ToString(), e.ErrorCode)); } + [RecordedTest] + [ServiceVersion(Min = ShareClientOptions.ServiceVersion.V2024_02_04)] + [TestCase(null)] + [TestCase(true)] + [TestCase(false)] + public async Task SetPropertiesAsync_EnableSnapshotVirtualDirectoryAccess(bool? enableSnapshotVirtualDirectoryAccess) + { + // Arrange + var shareName = GetNewShareName(); + ShareServiceClient service = SharesClientBuilder.GetServiceClient_SharedKey(); + ShareClient share = InstrumentClient(service.GetShareClient(shareName)); + ShareCreateOptions options = new ShareCreateOptions + { + Protocols = ShareProtocols.Nfs + }; + + try + { + await share.CreateAsync(options); + + ShareSetPropertiesOptions setPropertiesOptions = new ShareSetPropertiesOptions + { + EnableSnapshotVirtualDirectoryAccess = enableSnapshotVirtualDirectoryAccess, + AccessTier = ShareAccessTier.TransactionOptimized + }; + + // Act + await share.SetPropertiesAsync(setPropertiesOptions); + + // Assert + Response response = await share.GetPropertiesAsync(); + Assert.AreEqual(ShareProtocols.Nfs, response.Value.Protocols); + if (enableSnapshotVirtualDirectoryAccess == true || enableSnapshotVirtualDirectoryAccess == null) + { + Assert.IsTrue(response.Value.EnableSnapshotVirtualDirectoryAccess); + } + else + { + Assert.IsFalse(response.Value.EnableSnapshotVirtualDirectoryAccess); + } + } + finally + { + await share.DeleteAsync(); + } + } + [RecordedTest] public async Task SetQuotaAsync() { diff --git a/sdk/storage/Azure.Storage.Queues/CHANGELOG.md b/sdk/storage/Azure.Storage.Queues/CHANGELOG.md index 8c9d3be68bbc3..467829226135b 100644 --- a/sdk/storage/Azure.Storage.Queues/CHANGELOG.md +++ b/sdk/storage/Azure.Storage.Queues/CHANGELOG.md @@ -1,14 +1,9 @@ # Release History ## 12.19.0-beta.1 (Unreleased) - -### Features Added - -### Breaking Changes - -### Bugs Fixed - -### Other Changes +- Added support for service version 2024-08-04. +- This package will now respect the QueueClientOptions.ServiceVersion specified by the customer, or default to the latest version. +- Added more detailed messaging for authorization failure cases. ## 12.18.0 (2024-05-13) - Includes all features from 12.18.0-beta.1 and 12.18.0-beta.2. diff --git a/sdk/storage/Azure.Storage.Queues/api/Azure.Storage.Queues.net6.0.cs b/sdk/storage/Azure.Storage.Queues/api/Azure.Storage.Queues.net6.0.cs index c679499f995ae..e39d91de4eda2 100644 --- a/sdk/storage/Azure.Storage.Queues/api/Azure.Storage.Queues.net6.0.cs +++ b/sdk/storage/Azure.Storage.Queues/api/Azure.Storage.Queues.net6.0.cs @@ -101,6 +101,7 @@ public enum ServiceVersion V2023_11_03 = 20, V2024_02_04 = 21, V2024_05_04 = 22, + V2024_08_04 = 23, } } public partial class QueueMessageDecodingFailedEventArgs : Azure.SyncAsyncEventArgs diff --git a/sdk/storage/Azure.Storage.Queues/api/Azure.Storage.Queues.netstandard2.0.cs b/sdk/storage/Azure.Storage.Queues/api/Azure.Storage.Queues.netstandard2.0.cs index c679499f995ae..e39d91de4eda2 100644 --- a/sdk/storage/Azure.Storage.Queues/api/Azure.Storage.Queues.netstandard2.0.cs +++ b/sdk/storage/Azure.Storage.Queues/api/Azure.Storage.Queues.netstandard2.0.cs @@ -101,6 +101,7 @@ public enum ServiceVersion V2023_11_03 = 20, V2024_02_04 = 21, V2024_05_04 = 22, + V2024_08_04 = 23, } } public partial class QueueMessageDecodingFailedEventArgs : Azure.SyncAsyncEventArgs diff --git a/sdk/storage/Azure.Storage.Queues/api/Azure.Storage.Queues.netstandard2.1.cs b/sdk/storage/Azure.Storage.Queues/api/Azure.Storage.Queues.netstandard2.1.cs index c679499f995ae..e39d91de4eda2 100644 --- a/sdk/storage/Azure.Storage.Queues/api/Azure.Storage.Queues.netstandard2.1.cs +++ b/sdk/storage/Azure.Storage.Queues/api/Azure.Storage.Queues.netstandard2.1.cs @@ -101,6 +101,7 @@ public enum ServiceVersion V2023_11_03 = 20, V2024_02_04 = 21, V2024_05_04 = 22, + V2024_08_04 = 23, } } public partial class QueueMessageDecodingFailedEventArgs : Azure.SyncAsyncEventArgs diff --git a/sdk/storage/Azure.Storage.Queues/assets.json b/sdk/storage/Azure.Storage.Queues/assets.json index d573f3b567fd0..535ff1dafb7b3 100644 --- a/sdk/storage/Azure.Storage.Queues/assets.json +++ b/sdk/storage/Azure.Storage.Queues/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "net", "TagPrefix": "net/storage/Azure.Storage.Queues", - "Tag": "net/storage/Azure.Storage.Queues_cd2614948d" + "Tag": "net/storage/Azure.Storage.Queues_85b2d0ff2a" } diff --git a/sdk/storage/Azure.Storage.Queues/src/QueueClientOptions.cs b/sdk/storage/Azure.Storage.Queues/src/QueueClientOptions.cs index c36046e6b3222..e0e9b56bac01c 100644 --- a/sdk/storage/Azure.Storage.Queues/src/QueueClientOptions.cs +++ b/sdk/storage/Azure.Storage.Queues/src/QueueClientOptions.cs @@ -144,7 +144,12 @@ public enum ServiceVersion /// /// The 2024-05-04 service version. /// - V2024_05_04 = 22 + V2024_05_04 = 22, + + /// + /// The 2024-08-04 service version. + /// + V2024_08_04 = 23 #pragma warning restore CA1707 // Identifiers should not contain underscores } diff --git a/sdk/storage/Azure.Storage.Queues/tests/ClientBuilderExtensions.cs b/sdk/storage/Azure.Storage.Queues/tests/ClientBuilderExtensions.cs index 96b191cad9a16..96a47b31d295b 100644 --- a/sdk/storage/Azure.Storage.Queues/tests/ClientBuilderExtensions.cs +++ b/sdk/storage/Azure.Storage.Queues/tests/ClientBuilderExtensions.cs @@ -32,7 +32,7 @@ public static async Task GetTestQueueAsync( public static QueueServiceClient GetServiceClient_SharedKey(this QueuesClientBuilder clientBuilder, QueueClientOptions options = default) => clientBuilder.GetServiceClientFromSharedKeyConfig(clientBuilder.Tenants.TestConfigDefault, options); - public static QueueServiceClient GetServiceClient_OAuth(this QueuesClientBuilder clientBuilder) - => clientBuilder.GetServiceClientFromOauthConfig(clientBuilder.Tenants.TestConfigOAuth); + public static QueueServiceClient GetServiceClient_OAuth(this QueuesClientBuilder clientBuilder, QueueClientOptions options = default) + => clientBuilder.GetServiceClientFromOauthConfig(clientBuilder.Tenants.TestConfigOAuth, options); } } diff --git a/sdk/storage/Azure.Storage.Queues/tests/ClientSideEncryptionTests.cs b/sdk/storage/Azure.Storage.Queues/tests/ClientSideEncryptionTests.cs index 5e5d2e8b1cc52..cc6347250f475 100644 --- a/sdk/storage/Azure.Storage.Queues/tests/ClientSideEncryptionTests.cs +++ b/sdk/storage/Azure.Storage.Queues/tests/ClientSideEncryptionTests.cs @@ -36,8 +36,8 @@ public class ClientSideEncryptionTests : QueueTestBase private readonly string SampleUTF8String = Encoding.UTF8.GetString( new byte[] { 0xe1, 0x9a, 0xa0, 0xe1, 0x9b, 0x87, 0xe1, 0x9a, 0xbb, 0x0a }); // valid UTF-8 bytes - public ClientSideEncryptionTests(bool async) - : base(async, null /* RecordedTestMode.Record /* to re-record */) + public ClientSideEncryptionTests(bool async, QueueClientOptions.ServiceVersion serviceVersion) + : base(async, serviceVersion, null /* RecordedTestMode.Record /* to re-record */) { // TODO: enable after new KeyValue is released (after Dec 2023) TestDiagnostics = false; diff --git a/sdk/storage/Azure.Storage.Queues/tests/QueueClientTestFixtureAttribute.cs b/sdk/storage/Azure.Storage.Queues/tests/QueueClientTestFixtureAttribute.cs new file mode 100644 index 0000000000000..c3b58a518f0ec --- /dev/null +++ b/sdk/storage/Azure.Storage.Queues/tests/QueueClientTestFixtureAttribute.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Azure.Core.TestFramework; +namespace Azure.Storage.Queues.Tests +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)] + public class QueueClientTestFixtureAttribute : ClientTestFixtureAttribute + { + public QueueClientTestFixtureAttribute(params object[] additionalParameters) + : base( + serviceVersions: new object[] + { + QueueClientOptions.ServiceVersion.V2019_02_02, + QueueClientOptions.ServiceVersion.V2019_07_07, + QueueClientOptions.ServiceVersion.V2019_12_12, + QueueClientOptions.ServiceVersion.V2020_02_10, + QueueClientOptions.ServiceVersion.V2020_04_08, + QueueClientOptions.ServiceVersion.V2020_06_12, + QueueClientOptions.ServiceVersion.V2020_08_04, + QueueClientOptions.ServiceVersion.V2020_10_02, + QueueClientOptions.ServiceVersion.V2020_12_06, + QueueClientOptions.ServiceVersion.V2021_02_12, + QueueClientOptions.ServiceVersion.V2021_04_10, + QueueClientOptions.ServiceVersion.V2021_06_08, + QueueClientOptions.ServiceVersion.V2021_08_06, + QueueClientOptions.ServiceVersion.V2021_10_04, + QueueClientOptions.ServiceVersion.V2021_12_02, + QueueClientOptions.ServiceVersion.V2022_11_02, + QueueClientOptions.ServiceVersion.V2023_01_03, + QueueClientOptions.ServiceVersion.V2023_05_03, + QueueClientOptions.ServiceVersion.V2023_08_03, + QueueClientOptions.ServiceVersion.V2023_11_03, + QueueClientOptions.ServiceVersion.V2024_02_04, + QueueClientOptions.ServiceVersion.V2024_05_04, + QueueClientOptions.ServiceVersion.V2024_08_04, + StorageVersionExtensions.LatestVersion, + StorageVersionExtensions.MaxVersion + }, + additionalParameters: additionalParameters) + { + RecordingServiceVersion = StorageVersionExtensions.LatestVersion; + LiveServiceVersions = new object[] { StorageVersionExtensions.LatestVersion, }; + } + } +} diff --git a/sdk/storage/Azure.Storage.Queues/tests/QueueClientTests.cs b/sdk/storage/Azure.Storage.Queues/tests/QueueClientTests.cs index 3dbc4c7ae8821..d092ea2f55a2d 100644 --- a/sdk/storage/Azure.Storage.Queues/tests/QueueClientTests.cs +++ b/sdk/storage/Azure.Storage.Queues/tests/QueueClientTests.cs @@ -22,8 +22,8 @@ namespace Azure.Storage.Queues.Test { public class QueueClientTests : QueueTestBase { - public QueueClientTests(bool async) - : base(async, null /* RecordedTestMode.Record /* to re-record */) + public QueueClientTests(bool async, QueueClientOptions.ServiceVersion serviceVersion) + : base(async, serviceVersion, null /* RecordedTestMode.Record /* to re-record */) { } @@ -327,6 +327,34 @@ public async Task CreateAsync_WithOauth() } } + // Not possible to record + [LiveOnly] + [ServiceVersion(Min = QueueClientOptions.ServiceVersion.V2021_06_08)] + public async Task CreateAsync_WithOauthBearerChallenge() + { + // Arrange + var queueName = GetNewQueueName(); + QueueClientOptions options = new QueueClientOptions + { + Audience = QueueAudience.CreateQueueServiceAccountAudience("account"), + }; + QueueServiceClient service = QueuesClientBuilder.GetServiceClient_OAuth(options); + QueueClient queue = InstrumentClient(service.GetQueueClient(queueName)); + + try + { + // Act + Response result = await queue.CreateAsync(); + + // Assert + Assert.IsNotNull(result.Headers.RequestId, $"{nameof(result)} may not be populated"); + } + finally + { + await queue.DeleteIfExistsAsync(); + } + } + [RecordedTest] public async Task CreateAsync_WithAccountSas() { diff --git a/sdk/storage/Azure.Storage.Queues/tests/QueueSasBuilderTests.cs b/sdk/storage/Azure.Storage.Queues/tests/QueueSasBuilderTests.cs index 5d6473ba8829d..e13d8398e0958 100644 --- a/sdk/storage/Azure.Storage.Queues/tests/QueueSasBuilderTests.cs +++ b/sdk/storage/Azure.Storage.Queues/tests/QueueSasBuilderTests.cs @@ -16,8 +16,8 @@ public class QueueSasBuilderTests : QueueTestBase { private const string Permissions = "raup"; - public QueueSasBuilderTests(bool async) - : base(async, null /* RecordedTestMode.Record /* to re-record */) + public QueueSasBuilderTests(bool async, QueueClientOptions.ServiceVersion serviceVersion) + : base(async, serviceVersion, null /* RecordedTestMode.Record /* to re-record */) { } diff --git a/sdk/storage/Azure.Storage.Queues/tests/QueueSasTests.cs b/sdk/storage/Azure.Storage.Queues/tests/QueueSasTests.cs index 8d07b259de4fc..25859c0b01d85 100644 --- a/sdk/storage/Azure.Storage.Queues/tests/QueueSasTests.cs +++ b/sdk/storage/Azure.Storage.Queues/tests/QueueSasTests.cs @@ -17,8 +17,8 @@ namespace Azure.Storage.Queues.Test { internal class QueueSasTests : QueueTestBase { - public QueueSasTests(bool async) - : base(async, null /* RecordedTestMode.Record /* to re-record */) + public QueueSasTests(bool async, QueueClientOptions.ServiceVersion serviceVersion) + : base(async, serviceVersion, null /* RecordedTestMode.Record /* to re-record */) { } diff --git a/sdk/storage/Azure.Storage.Queues/tests/QueueTestBase.cs b/sdk/storage/Azure.Storage.Queues/tests/QueueTestBase.cs index d718bd3cd7796..2059f6049bf8e 100644 --- a/sdk/storage/Azure.Storage.Queues/tests/QueueTestBase.cs +++ b/sdk/storage/Azure.Storage.Queues/tests/QueueTestBase.cs @@ -15,6 +15,7 @@ namespace Azure.Storage.Queues.Tests { + [QueueClientTestFixture] public class QueueTestBase : StorageTestBase { /// @@ -22,6 +23,8 @@ public class QueueTestBase : StorageTestBase /// protected ClientBuilder QueuesClientBuilder { get; } + protected readonly QueueClientOptions.ServiceVersion _serviceVersion; + public string GetNewQueueName() => QueuesClientBuilder.GetNewQueueName(); public string GetNewMessageId() => QueuesClientBuilder.GetNewMessageId(); @@ -33,11 +36,10 @@ protected string SecondaryStorageTenantPrimaryHost() => protected string SecondaryStorageTenantSecondaryHost() => new Uri(Tenants.TestConfigSecondary.QueueServiceSecondaryEndpoint).Host; - public QueueTestBase(bool async) : this(async, null) { } - - public QueueTestBase(bool async, RecordedTestMode? mode = null) + public QueueTestBase(bool async, QueueClientOptions.ServiceVersion serviceVersion, RecordedTestMode? mode = null) : base(async, mode) { + _serviceVersion = serviceVersion; QueuesClientBuilder = new ClientBuilder( ServiceEndpoint.Queue, Tenants, @@ -45,7 +47,7 @@ public QueueTestBase(bool async, RecordedTestMode? mode = null) (uri, sharedKeyCredential, clientOptions) => new QueueServiceClient(uri, sharedKeyCredential, clientOptions), (uri, tokenCredential, clientOptions) => new QueueServiceClient(uri, tokenCredential, clientOptions), (uri, azureSasCredential, clientOptions) => new QueueServiceClient(uri, azureSasCredential, clientOptions), - () => new QueueClientOptions()); + () => new QueueClientOptions(serviceVersion)); } public QueueClientOptions GetOptions() diff --git a/sdk/storage/Azure.Storage.Queues/tests/QueueUriBuilderTests.cs b/sdk/storage/Azure.Storage.Queues/tests/QueueUriBuilderTests.cs index 821ce6d3d0fde..765c2335ba6b1 100644 --- a/sdk/storage/Azure.Storage.Queues/tests/QueueUriBuilderTests.cs +++ b/sdk/storage/Azure.Storage.Queues/tests/QueueUriBuilderTests.cs @@ -13,8 +13,8 @@ namespace Azure.Storage.Queues.Test { public class QueueUriBuilderTests : QueueTestBase { - public QueueUriBuilderTests(bool async) - : base(async, null /* RecordedTestMode.Record /* to re-record */) + public QueueUriBuilderTests(bool async, QueueClientOptions.ServiceVersion serviceVersion) + : base(async, serviceVersion, null /* RecordedTestMode.Record /* to re-record */) { } diff --git a/sdk/storage/Azure.Storage.Queues/tests/ServiceClientTests.cs b/sdk/storage/Azure.Storage.Queues/tests/ServiceClientTests.cs index 3523c6c8c1999..9803bb34f07b9 100644 --- a/sdk/storage/Azure.Storage.Queues/tests/ServiceClientTests.cs +++ b/sdk/storage/Azure.Storage.Queues/tests/ServiceClientTests.cs @@ -21,8 +21,8 @@ namespace Azure.Storage.Queues.Test [NonParallelizable] public class ServiceClientTests : QueueTestBase { - public ServiceClientTests(bool async) - : base(async, null /* RecordedTestMode.Record /* to re-record */) + public ServiceClientTests(bool async, QueueClientOptions.ServiceVersion serviceVersion) + : base(async, serviceVersion, null /* RecordedTestMode.Record /* to re-record */) { } [RecordedTest]