From 3de57667d49a81655430fe9578bf1e655b191bde Mon Sep 17 00:00:00 2001 From: Kan Tang Date: Tue, 4 Aug 2020 09:54:04 +0800 Subject: [PATCH] Added support for create/delete file shares. (#382) * Added support for create/delete file shares. * Removed nullable for metadata. --- sdk/storage/CMakeLists.txt | 2 + .../inc/shares/protocol/share_rest_client.hpp | 683 +++++++----------- sdk/storage/inc/shares/service_client.hpp | 13 +- sdk/storage/inc/shares/share_client.hpp | 102 +++ sdk/storage/inc/shares/share_options.hpp | 46 ++ sdk/storage/inc/shares/share_responses.hpp | 4 + sdk/storage/inc/shares/shares.hpp | 3 +- sdk/storage/src/shares/service_client.cpp | 18 +- sdk/storage/src/shares/share_client.cpp | 135 ++++ sdk/storage/test/CMakeLists.txt | 8 +- .../test/shares/service_client_test.cpp | 127 ++++ .../test/shares/service_client_test.hpp | 24 + sdk/storage/test/shares/share_client_test.cpp | 57 ++ sdk/storage/test/shares/share_client_test.hpp | 20 + 14 files changed, 800 insertions(+), 442 deletions(-) create mode 100644 sdk/storage/inc/shares/share_client.hpp create mode 100644 sdk/storage/src/shares/share_client.cpp create mode 100644 sdk/storage/test/shares/service_client_test.cpp create mode 100644 sdk/storage/test/shares/service_client_test.hpp create mode 100644 sdk/storage/test/shares/share_client_test.cpp create mode 100644 sdk/storage/test/shares/share_client_test.hpp diff --git a/sdk/storage/CMakeLists.txt b/sdk/storage/CMakeLists.txt index 1987a41c3..87428d36e 100644 --- a/sdk/storage/CMakeLists.txt +++ b/sdk/storage/CMakeLists.txt @@ -146,10 +146,12 @@ set (AZURE_STORAGE_SHARES_HEADER inc/shares/share_options.hpp inc/shares/share_responses.hpp inc/shares/service_client.hpp + inc/shares/share_client.hpp ) set (AZURE_STORAGE_SHARES_SOURCE src/shares/service_client.cpp + src/shares/share_client.cpp ) add_library(azure-storage-file-share ${AZURE_STORAGE_SHARES_HEADER} ${AZURE_STORAGE_SHARES_SOURCE}) diff --git a/sdk/storage/inc/shares/protocol/share_rest_client.hpp b/sdk/storage/inc/shares/protocol/share_rest_client.hpp index e605163d1..fba4ac3c4 100644 --- a/sdk/storage/inc/shares/protocol/share_rest_client.hpp +++ b/sdk/storage/inc/shares/protocol/share_rest_client.hpp @@ -939,7 +939,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { std::string CopyId; std::string CopyProgress; std::string CopySource; - CopyStatusType CopyStatus; + CopyStatusType CopyStatus = CopyStatusType::Unknown; std::string FileContentMD5; bool IsServerEncrypted = bool(); std::string FileAttributes; @@ -949,9 +949,9 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { std::string FilePermissionKey; std::string FileId; std::string FileParentId; - LeaseDurationType LeaseDuration; - LeaseStateType LeaseState; - LeaseStatusType LeaseStatus; + LeaseDurationType LeaseDuration = LeaseDurationType::Unknown; + LeaseStateType LeaseState = LeaseStateType::Unknown; + LeaseStatusType LeaseStatus = LeaseStatusType::Unknown; }; struct FileGetPropertiesResponse @@ -968,7 +968,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { std::string CopyId; std::string CopyProgress; std::string CopySource; - CopyStatusType CopyStatus; + CopyStatusType CopyStatus = CopyStatusType::Unknown; bool IsServerEncrypted = bool(); std::string FileAttributes; std::string FileCreationTime; @@ -977,9 +977,9 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { std::string FilePermissionKey; std::string FileId; std::string FileParentId; - LeaseDurationType LeaseDuration; - LeaseStateType LeaseState; - LeaseStatusType LeaseStatus; + LeaseDurationType LeaseDuration = LeaseDurationType::Unknown; + LeaseStateType LeaseState = LeaseStateType::Unknown; + LeaseStatusType LeaseStatus = LeaseStatusType::Unknown; }; struct FileDeleteResponse @@ -1062,7 +1062,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { std::string ETag; std::string LastModified; std::string CopyId; - CopyStatusType CopyStatus; + CopyStatusType CopyStatus = CopyStatusType::Unknown; }; struct FileAbortCopyResponse @@ -1334,7 +1334,6 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { enum class XmlTagName { c_Unknown, - c_RetentionPolicy, c_Enabled, c_Days, }; @@ -1361,11 +1360,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "RetentionPolicy") == 0) - { - path.emplace_back(XmlTagName::c_RetentionPolicy); - } - else if (std::strcmp(node.Name, "Enabled") == 0) + if (std::strcmp(node.Name, "Enabled") == 0) { path.emplace_back(XmlTagName::c_Enabled); } @@ -1380,14 +1375,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } else if (node.Type == XmlNodeType::Text) { - if (path.size() == 2 && path[0] == XmlTagName::c_RetentionPolicy - && path[1] == XmlTagName::c_Enabled) + if (path.size() == 1 && path[0] == XmlTagName::c_Enabled) { result.Enabled = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_RetentionPolicy - && path[1] == XmlTagName::c_Days) + else if (path.size() == 1 && path[0] == XmlTagName::c_Days) { result.Days = std::stoi(node.Value); } @@ -1402,7 +1394,6 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { enum class XmlTagName { c_Unknown, - c_Metrics, c_Version, c_Enabled, c_IncludeAPIs, @@ -1431,11 +1422,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "Metrics") == 0) - { - path.emplace_back(XmlTagName::c_Metrics); - } - else if (std::strcmp(node.Name, "Version") == 0) + if (std::strcmp(node.Name, "Version") == 0) { path.emplace_back(XmlTagName::c_Version); } @@ -1456,8 +1443,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { path.emplace_back(XmlTagName::c_Unknown); } - if (path.size() == 2 && path[0] == XmlTagName::c_Metrics - && path[1] == XmlTagName::c_RetentionPolicy) + if (path.size() == 1 && path[0] == XmlTagName::c_RetentionPolicy) { result.ShareRetentionPolicy = RetentionPolicyFromXml(reader); path.pop_back(); @@ -1465,20 +1451,15 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } else if (node.Type == XmlNodeType::Text) { - if (path.size() == 2 && path[0] == XmlTagName::c_Metrics - && path[1] == XmlTagName::c_Version) + if (path.size() == 1 && path[0] == XmlTagName::c_Version) { result.Version = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Metrics - && path[1] == XmlTagName::c_Enabled) + else if (path.size() == 1 && path[0] == XmlTagName::c_Enabled) { result.Enabled = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Metrics - && path[1] == XmlTagName::c_IncludeAPIs) + else if (path.size() == 1 && path[0] == XmlTagName::c_IncludeAPIs) { result.IncludeAPIs = node.Value; } @@ -1493,7 +1474,6 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { enum class XmlTagName { c_Unknown, - c_Cors, c_AllowedOrigins, c_AllowedMethods, c_AllowedHeaders, @@ -1523,11 +1503,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "Cors") == 0) - { - path.emplace_back(XmlTagName::c_Cors); - } - else if (std::strcmp(node.Name, "AllowedOrigins") == 0) + if (std::strcmp(node.Name, "AllowedOrigins") == 0) { path.emplace_back(XmlTagName::c_AllowedOrigins); } @@ -1554,32 +1530,23 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } else if (node.Type == XmlNodeType::Text) { - if (path.size() == 2 && path[0] == XmlTagName::c_Cors - && path[1] == XmlTagName::c_AllowedOrigins) + if (path.size() == 1 && path[0] == XmlTagName::c_AllowedOrigins) { result.AllowedOrigins = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Cors - && path[1] == XmlTagName::c_AllowedMethods) + else if (path.size() == 1 && path[0] == XmlTagName::c_AllowedMethods) { result.AllowedMethods = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Cors - && path[1] == XmlTagName::c_AllowedHeaders) + else if (path.size() == 1 && path[0] == XmlTagName::c_AllowedHeaders) { result.AllowedHeaders = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Cors - && path[1] == XmlTagName::c_ExposedHeaders) + else if (path.size() == 1 && path[0] == XmlTagName::c_ExposedHeaders) { result.ExposedHeaders = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Cors - && path[1] == XmlTagName::c_MaxAgeInSeconds) + else if (path.size() == 1 && path[0] == XmlTagName::c_MaxAgeInSeconds) { result.MaxAgeInSeconds = std::stoi(node.Value); } @@ -1657,7 +1624,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { path.pop_back(); } else if ( - path.size() == 3 && path[0] == XmlTagName::c_StorageServiceProperties + path.size() == 2 && path[0] == XmlTagName::c_StorageServiceProperties && path[1] == XmlTagName::c_Cors) { result.Cors.emplace_back(CorsRuleFromXml(reader)); @@ -1711,7 +1678,6 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { enum class XmlTagName { c_Unknown, - c_Properties, c_LastModified, c_Etag, c_Quota, @@ -1745,11 +1711,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "Properties") == 0) - { - path.emplace_back(XmlTagName::c_Properties); - } - else if (std::strcmp(node.Name, "Last-Modified") == 0) + if (std::strcmp(node.Name, "Last-Modified") == 0) { path.emplace_back(XmlTagName::c_LastModified); } @@ -1792,56 +1754,39 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } else if (node.Type == XmlNodeType::Text) { - if (path.size() == 2 && path[0] == XmlTagName::c_Properties - && path[1] == XmlTagName::c_LastModified) + if (path.size() == 1 && path[0] == XmlTagName::c_LastModified) { result.LastModified = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Properties - && path[1] == XmlTagName::c_Etag) + else if (path.size() == 1 && path[0] == XmlTagName::c_Etag) { result.Etag = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Properties - && path[1] == XmlTagName::c_Quota) + else if (path.size() == 1 && path[0] == XmlTagName::c_Quota) { result.Quota = std::stoi(node.Value); } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Properties - && path[1] == XmlTagName::c_ProvisionedIops) + else if (path.size() == 1 && path[0] == XmlTagName::c_ProvisionedIops) { result.ProvisionedIops = std::stoi(node.Value); } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Properties - && path[1] == XmlTagName::c_ProvisionedIngressMBps) + else if (path.size() == 1 && path[0] == XmlTagName::c_ProvisionedIngressMBps) { result.ProvisionedIngressMBps = std::stoi(node.Value); } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Properties - && path[1] == XmlTagName::c_ProvisionedEgressMBps) + else if (path.size() == 1 && path[0] == XmlTagName::c_ProvisionedEgressMBps) { result.ProvisionedEgressMBps = std::stoi(node.Value); } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Properties - && path[1] == XmlTagName::c_NextAllowedQuotaDowngradeTime) + else if (path.size() == 1 && path[0] == XmlTagName::c_NextAllowedQuotaDowngradeTime) { result.NextAllowedQuotaDowngradeTime = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Properties - && path[1] == XmlTagName::c_DeletedTime) + else if (path.size() == 1 && path[0] == XmlTagName::c_DeletedTime) { result.DeletedTime = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Properties - && path[1] == XmlTagName::c_RemainingRetentionDays) + else if (path.size() == 1 && path[0] == XmlTagName::c_RemainingRetentionDays) { result.RemainingRetentionDays = std::stoi(node.Value); } @@ -1890,7 +1835,6 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { enum class XmlTagName { c_Unknown, - c_Share, c_Name, c_Snapshot, c_Deleted, @@ -1921,11 +1865,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "Share") == 0) - { - path.emplace_back(XmlTagName::c_Share); - } - else if (std::strcmp(node.Name, "Name") == 0) + if (std::strcmp(node.Name, "Name") == 0) { path.emplace_back(XmlTagName::c_Name); } @@ -1954,15 +1894,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { path.emplace_back(XmlTagName::c_Unknown); } - if (path.size() == 2 && path[0] == XmlTagName::c_Share - && path[1] == XmlTagName::c_Properties) + if (path.size() == 1 && path[0] == XmlTagName::c_Properties) { result.Properties = SharePropertiesFromXml(reader); path.pop_back(); } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Share - && path[1] == XmlTagName::c_Metadata) + else if (path.size() == 1 && path[0] == XmlTagName::c_Metadata) { result.ShareMetadata = MetadataFromXml(reader); path.pop_back(); @@ -1970,25 +1907,19 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } else if (node.Type == XmlNodeType::Text) { - if (path.size() == 2 && path[0] == XmlTagName::c_Share && path[1] == XmlTagName::c_Name) + if (path.size() == 1 && path[0] == XmlTagName::c_Name) { result.Name = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Share - && path[1] == XmlTagName::c_Snapshot) + else if (path.size() == 1 && path[0] == XmlTagName::c_Snapshot) { result.Snapshot = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Share - && path[1] == XmlTagName::c_Deleted) + else if (path.size() == 1 && path[0] == XmlTagName::c_Deleted) { result.Deleted = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Share - && path[1] == XmlTagName::c_Version) + else if (path.size() == 1 && path[0] == XmlTagName::c_Version) { result.Version = node.Value; } @@ -2102,7 +2033,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::Attribute) { if (path.size() == 1 && path[0] == XmlTagName::c_EnumerationResults - && std::strcmp(node.Name, "ServiceEndpoint")) + && (std::strcmp(node.Name, "ServiceEndpoint") == 0)) { result.ServiceEndpoint = node.Value; } @@ -2134,9 +2065,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Timeout; // The timeout parameter is expressed in seconds. For more information, see Setting // Timeouts for File Service Operations. - Azure::Core::Nullable> Metadata - = std::map(); // A name-value pair to associate with a file - // storage object. + std::map + Metadata; // A name-value pair to associate with a file storage object. Azure::Core::Nullable ShareQuota; // Specifies the maximum size of the share, in gigabytes. std::string ApiVersionParameter @@ -2158,7 +2088,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.AddQueryParameter( Details::c_QueryTimeout, std::to_string(createOptions.Timeout.GetValue())); } - for (const auto& pair : createOptions.Metadata.GetValue()) + for (const auto& pair : createOptions.Metadata) { request.AddHeader(Details::c_HeaderMetadata + pair.first, pair.second); } @@ -2258,9 +2188,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Timeout; // The timeout parameter is expressed in seconds. For more information, see Setting // Timeouts for File Service Operations. - Azure::Core::Nullable> Metadata - = std::map(); // A name-value pair to associate with a file - // storage object. + std::map + Metadata; // A name-value pair to associate with a file storage object. std::string ApiVersionParameter = Details::c_DefaultServiceApiVersion; // Specifies the version of the operation to use // for this request. @@ -2281,7 +2210,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.AddQueryParameter( Details::c_QueryTimeout, std::to_string(createSnapshotOptions.Timeout.GetValue())); } - for (const auto& pair : createSnapshotOptions.Metadata.GetValue()) + for (const auto& pair : createSnapshotOptions.Metadata) { request.AddHeader(Details::c_HeaderMetadata + pair.first, pair.second); } @@ -2404,9 +2333,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Timeout; // The timeout parameter is expressed in seconds. For more information, see Setting // Timeouts for File Service Operations. - Azure::Core::Nullable> Metadata - = std::map(); // A name-value pair to associate with a file - // storage object. + std::map + Metadata; // A name-value pair to associate with a file storage object. std::string ApiVersionParameter = Details::c_DefaultServiceApiVersion; // Specifies the version of the operation to use // for this request. @@ -2427,7 +2355,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.AddQueryParameter( Details::c_QueryTimeout, std::to_string(setMetadataOptions.Timeout.GetValue())); } - for (const auto& pair : setMetadataOptions.Metadata.GetValue()) + for (const auto& pair : setMetadataOptions.Metadata) { request.AddHeader(Details::c_HeaderMetadata + pair.first, pair.second); } @@ -2807,7 +2735,6 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { enum class XmlTagName { c_Unknown, - c_AccessPolicy, c_Start, c_Expiry, c_Permission, @@ -2835,11 +2762,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "AccessPolicy") == 0) - { - path.emplace_back(XmlTagName::c_AccessPolicy); - } - else if (std::strcmp(node.Name, "Start") == 0) + if (std::strcmp(node.Name, "Start") == 0) { path.emplace_back(XmlTagName::c_Start); } @@ -2858,20 +2781,15 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } else if (node.Type == XmlNodeType::Text) { - if (path.size() == 2 && path[0] == XmlTagName::c_AccessPolicy - && path[1] == XmlTagName::c_Start) + if (path.size() == 1 && path[0] == XmlTagName::c_Start) { result.Start = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_AccessPolicy - && path[1] == XmlTagName::c_Expiry) + else if (path.size() == 1 && path[0] == XmlTagName::c_Expiry) { result.Expiry = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_AccessPolicy - && path[1] == XmlTagName::c_Permission) + else if (path.size() == 1 && path[0] == XmlTagName::c_Permission) { result.Permission = node.Value; } @@ -2886,7 +2804,6 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { enum class XmlTagName { c_Unknown, - c_SignedIdentifier, c_Id, c_AccessPolicy, }; @@ -2913,11 +2830,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "SignedIdentifier") == 0) - { - path.emplace_back(XmlTagName::c_SignedIdentifier); - } - else if (std::strcmp(node.Name, "Id") == 0) + if (std::strcmp(node.Name, "Id") == 0) { path.emplace_back(XmlTagName::c_Id); } @@ -2930,8 +2843,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { path.emplace_back(XmlTagName::c_Unknown); } - if (path.size() == 2 && path[0] == XmlTagName::c_SignedIdentifier - && path[1] == XmlTagName::c_AccessPolicy) + if (path.size() == 1 && path[0] == XmlTagName::c_AccessPolicy) { result.Policy = AccessPolicyFromXml(reader); path.pop_back(); @@ -2939,8 +2851,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } else if (node.Type == XmlNodeType::Text) { - if (path.size() == 2 && path[0] == XmlTagName::c_SignedIdentifier - && path[1] == XmlTagName::c_Id) + if (path.size() == 1 && path[0] == XmlTagName::c_Id) { result.Id = node.Value; } @@ -3188,9 +3099,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Timeout; // The timeout parameter is expressed in seconds. For more information, see Setting // Timeouts for File Service Operations. - Azure::Core::Nullable> Metadata - = std::map(); // A name-value pair to associate with a file - // storage object. + std::map + Metadata; // A name-value pair to associate with a file storage object. std::string ApiVersionParameter = Details::c_DefaultServiceApiVersion; // Specifies the version of the operation to use // for this request. @@ -3227,7 +3137,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.AddQueryParameter( Details::c_QueryTimeout, std::to_string(createOptions.Timeout.GetValue())); } - for (const auto& pair : createOptions.Metadata.GetValue()) + for (const auto& pair : createOptions.Metadata) { request.AddHeader(Details::c_HeaderMetadata + pair.first, pair.second); } @@ -3380,9 +3290,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Timeout; // The timeout parameter is expressed in seconds. For more information, see Setting // Timeouts for File Service Operations. - Azure::Core::Nullable> Metadata - = std::map(); // A name-value pair to associate with a file - // storage object. + std::map + Metadata; // A name-value pair to associate with a file storage object. std::string ApiVersionParameter = Details::c_DefaultServiceApiVersion; // Specifies the version of the operation to use // for this request. @@ -3403,7 +3312,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.AddQueryParameter( Details::c_QueryTimeout, std::to_string(setMetadataOptions.Timeout.GetValue())); } - for (const auto& pair : setMetadataOptions.Metadata.GetValue()) + for (const auto& pair : setMetadataOptions.Metadata) { request.AddHeader(Details::c_HeaderMetadata + pair.first, pair.second); } @@ -3765,11 +3674,161 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { enum class XmlTagName { c_Unknown, - c_Directory, c_Name, }; std::vector path; + while (true) + { + auto node = reader.Read(); + if (node.Type == XmlNodeType::End) + { + break; + } + else if (node.Type == XmlNodeType::EndTag) + { + if (path.size() > 0) + { + path.pop_back(); + } + else + { + break; + } + } + else if (node.Type == XmlNodeType::StartTag) + { + + if (std::strcmp(node.Name, "Name") == 0) + { + path.emplace_back(XmlTagName::c_Name); + } + else + { + path.emplace_back(XmlTagName::c_Unknown); + } + } + } + return result; + } + + static FileProperty FilePropertyFromXml(XmlReader& reader) + { + auto result = FileProperty(); + enum class XmlTagName + { + c_Unknown, + c_ContentLength, + }; + std::vector path; + + while (true) + { + auto node = reader.Read(); + if (node.Type == XmlNodeType::End) + { + break; + } + else if (node.Type == XmlNodeType::EndTag) + { + if (path.size() > 0) + { + path.pop_back(); + } + else + { + break; + } + } + else if (node.Type == XmlNodeType::StartTag) + { + + if (std::strcmp(node.Name, "Content-Length") == 0) + { + path.emplace_back(XmlTagName::c_ContentLength); + } + else + { + path.emplace_back(XmlTagName::c_Unknown); + } + } + } + return result; + } + + static FileItem FileItemFromXml(XmlReader& reader) + { + auto result = FileItem(); + enum class XmlTagName + { + c_Unknown, + c_Name, + c_Properties, + }; + std::vector path; + + while (true) + { + auto node = reader.Read(); + if (node.Type == XmlNodeType::End) + { + break; + } + else if (node.Type == XmlNodeType::EndTag) + { + if (path.size() > 0) + { + path.pop_back(); + } + else + { + break; + } + } + else if (node.Type == XmlNodeType::StartTag) + { + + if (std::strcmp(node.Name, "Name") == 0) + { + path.emplace_back(XmlTagName::c_Name); + } + else if (std::strcmp(node.Name, "Properties") == 0) + { + path.emplace_back(XmlTagName::c_Properties); + } + else + { + path.emplace_back(XmlTagName::c_Unknown); + } + + if (path.size() == 1 && path[0] == XmlTagName::c_Properties) + { + result.Properties = FilePropertyFromXml(reader); + path.pop_back(); + } + } + else if (node.Type == XmlNodeType::Text) + { + if (path.size() == 1 && path[0] == XmlTagName::c_Name) + { + result.Name = node.Value; + } + } + } + return result; + } + + static FilesAndDirectoriesListSegment FilesAndDirectoriesListSegmentFromXml(XmlReader& reader) + { + auto result = FilesAndDirectoriesListSegment(); + enum class XmlTagName + { + c_Unknown, + c_Directory, + c_File, + }; + std::vector path; + while (true) { auto node = reader.Read(); @@ -3795,193 +3854,6 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { path.emplace_back(XmlTagName::c_Directory); } - else if (std::strcmp(node.Name, "Name") == 0) - { - path.emplace_back(XmlTagName::c_Name); - } - else - { - path.emplace_back(XmlTagName::c_Unknown); - } - } - else if (node.Type == XmlNodeType::Text) - { - if (path.size() == 2 && path[0] == XmlTagName::c_Directory - && path[1] == XmlTagName::c_Name) - { - result.Name = node.Value; - } - } - } - return result; - } - - static FileProperty FilePropertyFromXml(XmlReader& reader) - { - auto result = FileProperty(); - enum class XmlTagName - { - c_Unknown, - c_Properties, - c_ContentLength, - }; - std::vector path; - - while (true) - { - auto node = reader.Read(); - if (node.Type == XmlNodeType::End) - { - break; - } - else if (node.Type == XmlNodeType::EndTag) - { - if (path.size() > 0) - { - path.pop_back(); - } - else - { - break; - } - } - else if (node.Type == XmlNodeType::StartTag) - { - - if (std::strcmp(node.Name, "Properties") == 0) - { - path.emplace_back(XmlTagName::c_Properties); - } - else if (std::strcmp(node.Name, "Content-Length") == 0) - { - path.emplace_back(XmlTagName::c_ContentLength); - } - else - { - path.emplace_back(XmlTagName::c_Unknown); - } - } - else if (node.Type == XmlNodeType::Text) - { - if (path.size() == 2 && path[0] == XmlTagName::c_Properties - && path[1] == XmlTagName::c_ContentLength) - { - result.ContentLength = std::stoll(node.Value); - } - } - } - return result; - } - - static FileItem FileItemFromXml(XmlReader& reader) - { - auto result = FileItem(); - enum class XmlTagName - { - c_Unknown, - c_File, - c_Name, - c_Properties, - }; - std::vector path; - - while (true) - { - auto node = reader.Read(); - if (node.Type == XmlNodeType::End) - { - break; - } - else if (node.Type == XmlNodeType::EndTag) - { - if (path.size() > 0) - { - path.pop_back(); - } - else - { - break; - } - } - else if (node.Type == XmlNodeType::StartTag) - { - - if (std::strcmp(node.Name, "File") == 0) - { - path.emplace_back(XmlTagName::c_File); - } - else if (std::strcmp(node.Name, "Name") == 0) - { - path.emplace_back(XmlTagName::c_Name); - } - else if (std::strcmp(node.Name, "Properties") == 0) - { - path.emplace_back(XmlTagName::c_Properties); - } - else - { - path.emplace_back(XmlTagName::c_Unknown); - } - - if (path.size() == 2 && path[0] == XmlTagName::c_File - && path[1] == XmlTagName::c_Properties) - { - result.Properties = FilePropertyFromXml(reader); - path.pop_back(); - } - } - else if (node.Type == XmlNodeType::Text) - { - if (path.size() == 2 && path[0] == XmlTagName::c_File && path[1] == XmlTagName::c_Name) - { - result.Name = node.Value; - } - } - } - return result; - } - - static FilesAndDirectoriesListSegment FilesAndDirectoriesListSegmentFromXml(XmlReader& reader) - { - auto result = FilesAndDirectoriesListSegment(); - enum class XmlTagName - { - c_Unknown, - c_Entries, - c_Directory, - c_File, - }; - std::vector path; - - while (true) - { - auto node = reader.Read(); - if (node.Type == XmlNodeType::End) - { - break; - } - else if (node.Type == XmlNodeType::EndTag) - { - if (path.size() > 0) - { - path.pop_back(); - } - else - { - break; - } - } - else if (node.Type == XmlNodeType::StartTag) - { - - if (std::strcmp(node.Name, "Entries") == 0) - { - path.emplace_back(XmlTagName::c_Entries); - } - else if (std::strcmp(node.Name, "Directory") == 0) - { - path.emplace_back(XmlTagName::c_Directory); - } else if (std::strcmp(node.Name, "File") == 0) { path.emplace_back(XmlTagName::c_File); @@ -3990,15 +3862,12 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { { path.emplace_back(XmlTagName::c_Unknown); } - if (path.size() == 3 && path[0] == XmlTagName::c_Entries - && path[1] == XmlTagName::c_Directory) + if (path.size() == 1 && path[0] == XmlTagName::c_Directory) { result.DirectoryItems.emplace_back(DirectoryItemFromXml(reader)); path.pop_back(); } - else if ( - path.size() == 3 && path[0] == XmlTagName::c_Entries - && path[1] == XmlTagName::c_File) + else if (path.size() == 1 && path[0] == XmlTagName::c_File) { result.FileItems.emplace_back(FileItemFromXml(reader)); path.pop_back(); @@ -4113,25 +3982,25 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::Attribute) { if (path.size() == 1 && path[0] == XmlTagName::c_EnumerationResults - && std::strcmp(node.Name, "ServiceEndpoint")) + && (std::strcmp(node.Name, "ServiceEndpoint") == 0)) { result.ServiceEndpoint = node.Value; } else if ( path.size() == 1 && path[0] == XmlTagName::c_EnumerationResults - && std::strcmp(node.Name, "ShareName")) + && (std::strcmp(node.Name, "ShareName") == 0)) { result.ShareName = node.Value; } else if ( path.size() == 1 && path[0] == XmlTagName::c_EnumerationResults - && std::strcmp(node.Name, "ShareSnapshot")) + && (std::strcmp(node.Name, "ShareSnapshot") == 0)) { result.ShareSnapshot = node.Value; } else if ( path.size() == 1 && path[0] == XmlTagName::c_EnumerationResults - && std::strcmp(node.Name, "DirectoryPath")) + && (std::strcmp(node.Name, "DirectoryPath") == 0)) { result.DirectoryPath = node.Value; } @@ -4188,7 +4057,6 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { enum class XmlTagName { c_Unknown, - c_Handle, c_HandleId, c_Path, c_FileId, @@ -4221,11 +4089,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "Handle") == 0) - { - path.emplace_back(XmlTagName::c_Handle); - } - else if (std::strcmp(node.Name, "HandleId") == 0) + if (std::strcmp(node.Name, "HandleId") == 0) { path.emplace_back(XmlTagName::c_HandleId); } @@ -4264,50 +4128,35 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } else if (node.Type == XmlNodeType::Text) { - if (path.size() == 2 && path[0] == XmlTagName::c_Handle - && path[1] == XmlTagName::c_HandleId) + if (path.size() == 1 && path[0] == XmlTagName::c_HandleId) { result.HandleId = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Handle - && path[1] == XmlTagName::c_Path) + else if (path.size() == 1 && path[0] == XmlTagName::c_Path) { result.Path = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Handle - && path[1] == XmlTagName::c_FileId) + else if (path.size() == 1 && path[0] == XmlTagName::c_FileId) { result.FileId = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Handle - && path[1] == XmlTagName::c_ParentId) + else if (path.size() == 1 && path[0] == XmlTagName::c_ParentId) { result.ParentId = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Handle - && path[1] == XmlTagName::c_SessionId) + else if (path.size() == 1 && path[0] == XmlTagName::c_SessionId) { result.SessionId = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Handle - && path[1] == XmlTagName::c_ClientIp) + else if (path.size() == 1 && path[0] == XmlTagName::c_ClientIp) { result.ClientIp = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Handle - && path[1] == XmlTagName::c_OpenTime) + else if (path.size() == 1 && path[0] == XmlTagName::c_OpenTime) { result.OpenTime = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Handle - && path[1] == XmlTagName::c_LastReconnectTime) + else if (path.size() == 1 && path[0] == XmlTagName::c_LastReconnectTime) { result.LastReconnectTime = node.Value; } @@ -4448,9 +4297,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Azure::Core::Nullable FileContentMD5; // Sets the file's MD5 hash. Azure::Core::Nullable FileContentDisposition; // Sets the file's Content-Disposition header. - Azure::Core::Nullable> Metadata - = std::map(); // A name-value pair to associate with a file - // storage object. + std::map + Metadata; // A name-value pair to associate with a file storage object. Azure::Core::Nullable FilePermission; // If specified the permission (security descriptor) shall be set for // the directory/file. This header can be used if Permission size is <= @@ -4521,7 +4369,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Details::c_HeaderFileContentDisposition, createOptions.FileContentDisposition.GetValue()); } - for (const auto& pair : createOptions.Metadata.GetValue()) + for (const auto& pair : createOptions.Metadata) { request.AddHeader(Details::c_HeaderMetadata + pair.first, pair.second); } @@ -4804,9 +4652,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Timeout; // The timeout parameter is expressed in seconds. For more information, see Setting // Timeouts for File Service Operations. - Azure::Core::Nullable> Metadata - = std::map(); // A name-value pair to associate with a file - // storage object. + std::map + Metadata; // A name-value pair to associate with a file storage object. std::string ApiVersionParameter = Details::c_DefaultServiceApiVersion; // Specifies the version of the operation to use // for this request. @@ -4829,7 +4676,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { request.AddQueryParameter( Details::c_QueryTimeout, std::to_string(setMetadataOptions.Timeout.GetValue())); } - for (const auto& pair : setMetadataOptions.Metadata.GetValue()) + for (const auto& pair : setMetadataOptions.Metadata) { request.AddHeader(Details::c_HeaderMetadata + pair.first, pair.second); } @@ -5270,9 +5117,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { std::string ApiVersionParameter = Details::c_DefaultServiceApiVersion; // Specifies the version of the operation to use // for this request. - Azure::Core::Nullable> Metadata - = std::map(); // A name-value pair to associate with a file - // storage object. + std::map + Metadata; // A name-value pair to associate with a file storage object. std::string CopySource; // Specifies the URL of the source file or blob, up to 2 KB in length. To // copy a file to another file within the same storage account, you may use @@ -5339,7 +5185,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Details::c_QueryTimeout, std::to_string(startCopyOptions.Timeout.GetValue())); } request.AddHeader(Details::c_HeaderVersion, startCopyOptions.ApiVersionParameter); - for (const auto& pair : startCopyOptions.Metadata.GetValue()) + for (const auto& pair : startCopyOptions.Metadata) { request.AddHeader(Details::c_HeaderMetadata + pair.first, pair.second); } @@ -5982,7 +5828,6 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { enum class XmlTagName { c_Unknown, - c_Range, c_Start, c_End, }; @@ -6009,11 +5854,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "Range") == 0) - { - path.emplace_back(XmlTagName::c_Range); - } - else if (std::strcmp(node.Name, "Start") == 0) + if (std::strcmp(node.Name, "Start") == 0) { path.emplace_back(XmlTagName::c_Start); } @@ -6028,13 +5869,11 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } else if (node.Type == XmlNodeType::Text) { - if (path.size() == 2 && path[0] == XmlTagName::c_Range - && path[1] == XmlTagName::c_Start) + if (path.size() == 1 && path[0] == XmlTagName::c_Start) { result.Start = std::stoll(node.Value); } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Range && path[1] == XmlTagName::c_End) + else if (path.size() == 1 && path[0] == XmlTagName::c_End) { result.End = std::stoll(node.Value); } @@ -6181,7 +6020,6 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { enum class XmlTagName { c_Unknown, - c_Handle, c_HandleId, c_Path, c_FileId, @@ -6214,11 +6052,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { else if (node.Type == XmlNodeType::StartTag) { - if (std::strcmp(node.Name, "Handle") == 0) - { - path.emplace_back(XmlTagName::c_Handle); - } - else if (std::strcmp(node.Name, "HandleId") == 0) + if (std::strcmp(node.Name, "HandleId") == 0) { path.emplace_back(XmlTagName::c_HandleId); } @@ -6257,50 +6091,35 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { } else if (node.Type == XmlNodeType::Text) { - if (path.size() == 2 && path[0] == XmlTagName::c_Handle - && path[1] == XmlTagName::c_HandleId) + if (path.size() == 1 && path[0] == XmlTagName::c_HandleId) { result.HandleId = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Handle - && path[1] == XmlTagName::c_Path) + else if (path.size() == 1 && path[0] == XmlTagName::c_Path) { result.Path = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Handle - && path[1] == XmlTagName::c_FileId) + else if (path.size() == 1 && path[0] == XmlTagName::c_FileId) { result.FileId = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Handle - && path[1] == XmlTagName::c_ParentId) + else if (path.size() == 1 && path[0] == XmlTagName::c_ParentId) { result.ParentId = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Handle - && path[1] == XmlTagName::c_SessionId) + else if (path.size() == 1 && path[0] == XmlTagName::c_SessionId) { result.SessionId = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Handle - && path[1] == XmlTagName::c_ClientIp) + else if (path.size() == 1 && path[0] == XmlTagName::c_ClientIp) { result.ClientIp = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Handle - && path[1] == XmlTagName::c_OpenTime) + else if (path.size() == 1 && path[0] == XmlTagName::c_OpenTime) { result.OpenTime = node.Value; } - else if ( - path.size() == 2 && path[0] == XmlTagName::c_Handle - && path[1] == XmlTagName::c_LastReconnectTime) + else if (path.size() == 1 && path[0] == XmlTagName::c_LastReconnectTime) { result.LastReconnectTime = node.Value; } diff --git a/sdk/storage/inc/shares/service_client.hpp b/sdk/storage/inc/shares/service_client.hpp index a8a221400..2a07e0541 100644 --- a/sdk/storage/inc/shares/service_client.hpp +++ b/sdk/storage/inc/shares/service_client.hpp @@ -17,6 +17,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { + class ShareClient; + class ServiceClient { public: /** @@ -60,6 +62,13 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { const std::string& serviceUri, const ServiceClientOptions& options = ServiceClientOptions()); + /** + * @brief Create a ShareClient from current ServiceClient + * @param shareName The name of the file share. + * @return ShareClient A share client that can be used to manage a share resource. + */ + ShareClient GetShareClient(const std::string& shareName) const; + /** * @brief Gets the file share service's primary uri endpoint. * @@ -70,8 +79,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { /** * @brief List the shares from the service. * @param options Optional parameters to list the shares. - * @return Azure::Core::Response The results containing the shares returned - * and information used for future list operation on valid result not yet returned. + * @return Azure::Core::Response The results containing the shares + * returned and information used for future list operation on valid result not yet returned. */ Azure::Core::Response ListSharesSegment( const ListSharesOptions& options = ListSharesOptions()) const; diff --git a/sdk/storage/inc/shares/share_client.hpp b/sdk/storage/inc/shares/share_client.hpp new file mode 100644 index 000000000..fb7598a88 --- /dev/null +++ b/sdk/storage/inc/shares/share_client.hpp @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common/storage_credential.hpp" +#include "common/storage_uri_builder.hpp" +#include "credentials/credentials.hpp" +#include "http/pipeline.hpp" +#include "protocol/share_rest_client.hpp" +#include "response.hpp" +#include "share_options.hpp" +#include "share_responses.hpp" +#include "shares/service_client.hpp" + +#include +#include + +namespace Azure { namespace Storage { namespace Files { namespace Shares { + + class ShareClient { + public: + /** + * @brief Create from connection string + * @param connectionString Azure Storage connection string. + * @param shareName The name of a file share. + * @param options Optional parameters used to initialize the client. + * @return ShareClient The client that can be used to manage a share resource. + */ + static ShareClient CreateFromConnectionString( + const std::string& connectionString, + const std::string& shareName, + const ShareClientOptions& options = ShareClientOptions()); + + /** + * @brief Shared key authentication client. + * @param shareUri The URI of the file share this client's request targets. + * @param credential The shared key credential used to initialize the client. + * @param options Optional parameters used to initialize the client. + */ + explicit ShareClient( + const std::string& shareUri, + std::shared_ptr credential, + const ShareClientOptions& options = ShareClientOptions()); + + /** + * @brief Bearer token authentication client. + * @param shareUri The URI of the file share this client's request targets. + * @param credential The token credential used to initialize the client. + * @param options Optional parameters used to initialize the client. + */ + explicit ShareClient( + const std::string& shareUri, + std::shared_ptr credential, + const ShareClientOptions& options = ShareClientOptions()); + + /** + * @brief Anonymous/SAS/customized pipeline auth. + * @param shareUri The URI of the file share this client's request targets. + * @param options Optional parameters used to initialize the client. + */ + explicit ShareClient( + const std::string& shareUri, + const ShareClientOptions& options = ShareClientOptions()); + + /** + * @brief Gets the share's primary uri endpoint. + * + * @return The share's primary uri endpoint. + */ + std::string GetUri() const { return m_shareUri.ToString(); } + + /** + * @brief Creates the file share. + * @param options Optional parameters to create this file share. + * @return Azure::Core::Response The information containing the version and modified + * time of a share. + */ + Azure::Core::Response Create( + const CreateShareOptions& options = CreateShareOptions()) const; + + /** + * @brief Deletes the file share. + * @param options Optional parameters to delete this file share. + * @return Azure::Core::Response Currently empty and reserved for future usage. + */ + Azure::Core::Response Delete( + const DeleteShareOptions& options = DeleteShareOptions()) const; + + private: + UriBuilder m_shareUri; + std::shared_ptr m_pipeline; + + explicit ShareClient( + UriBuilder shareUri, + std::shared_ptr pipeline) + : m_shareUri(std::move(shareUri)), m_pipeline(std::move(pipeline)) + { + } + friend class ServiceClient; + }; +}}}} // namespace Azure::Storage::Files::Shares diff --git a/sdk/storage/inc/shares/share_options.hpp b/sdk/storage/inc/shares/share_options.hpp index 5b4a5402d..9fefb1276 100644 --- a/sdk/storage/inc/shares/share_options.hpp +++ b/sdk/storage/inc/shares/share_options.hpp @@ -23,6 +23,15 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { std::vector> PerRetryPolicies; }; + /** + * @brief Share client options used to initalize ShareClient. + */ + struct ShareClientOptions + { + std::vector> PerOperationPolicies; + std::vector> PerRetryPolicies; + }; + struct ListSharesOptions { /** @@ -57,4 +66,41 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { Azure::Core::Nullable ListSharesInclude; }; + struct CreateShareOptions + { + /** + * @brief Context for cancelling long running operations. + */ + Azure::Core::Context Context; + + /** + * @brief A name-value pair to associate with a file storage object. + */ + std::map Metadata; + + /** + * @brief Specifies the maximum size of the share, in gigabytes. + */ + Azure::Core::Nullable ShareQuota; + }; + + struct DeleteShareOptions + { + /** + * @brief Context for cancelling long running operations. + */ + Azure::Core::Context Context; + + /** + * @brief The snapshot parameter is an opaque DateTime value that, when present, specifies the + * share snapshot to query. + */ + Azure::Core::Nullable ShareSnapshot; + + /** + * @brief Specifies the option include to delete the base share and all of its snapshots. + */ + Azure::Core::Nullable IncludeSnapshots; + }; + }}}} // namespace Azure::Storage::Files::Shares diff --git a/sdk/storage/inc/shares/share_responses.hpp b/sdk/storage/inc/shares/share_responses.hpp index 361f7af84..6880c88de 100644 --- a/sdk/storage/inc/shares/share_responses.hpp +++ b/sdk/storage/inc/shares/share_responses.hpp @@ -11,4 +11,8 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { using ListSharesSegmentResult = ServiceListSharesSegmentResponse; + // ShareClient models: + using ShareInfo = ShareCreateResponse; + using ShareDeleteInfo = ShareDeleteResponse; + }}}} // namespace Azure::Storage::Files::Shares diff --git a/sdk/storage/inc/shares/shares.hpp b/sdk/storage/inc/shares/shares.hpp index afd474e87..37175d416 100644 --- a/sdk/storage/inc/shares/shares.hpp +++ b/sdk/storage/inc/shares/shares.hpp @@ -3,4 +3,5 @@ #pragma once -#include "service_client.hpp" \ No newline at end of file +#include "service_client.hpp" +#include "share_client.hpp" diff --git a/sdk/storage/src/shares/service_client.cpp b/sdk/storage/src/shares/service_client.cpp index 44e2781b1..e145f3a20 100644 --- a/sdk/storage/src/shares/service_client.cpp +++ b/sdk/storage/src/shares/service_client.cpp @@ -11,6 +11,7 @@ #include "common/storage_version.hpp" #include "credentials/policy/policies.hpp" #include "http/curl/curl.hpp" +#include "shares/share_client.hpp" namespace Azure { namespace Storage { namespace Files { namespace Shares { ServiceClient ServiceClient::CreateFromConnectionString( @@ -18,7 +19,7 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { const ServiceClientOptions& options) { auto parsedConnectionString = Azure::Storage::Details::ParseConnectionString(connectionString); - auto serviceUri = std::move(parsedConnectionString.DataLakeServiceUri); + auto serviceUri = std::move(parsedConnectionString.FileServiceUri); if (parsedConnectionString.KeyCredential) { @@ -106,14 +107,21 @@ namespace Azure { namespace Storage { namespace Files { namespace Shares { m_pipeline = std::make_shared(policies); } + ShareClient ServiceClient::GetShareClient(const std::string& shareName) const + { + auto builder = m_serviceUri; + builder.AppendPath(shareName, true); + return ShareClient(builder, m_pipeline); + } + Azure::Core::Response ServiceClient::ListSharesSegment( const ListSharesOptions& options) const { auto protocolLayerOptions = ShareRestClient::Service::ListSharesSegmentOptions(); - protocolLayerOptions.ListSharesInclude = std::move(options.ListSharesInclude); - protocolLayerOptions.Marker = std::move(options.Marker); - protocolLayerOptions.MaxResults = std::move(options.MaxResults); - protocolLayerOptions.Prefix = std::move(options.Prefix); + protocolLayerOptions.ListSharesInclude = options.ListSharesInclude; + protocolLayerOptions.Marker = options.Marker; + protocolLayerOptions.MaxResults = options.MaxResults; + protocolLayerOptions.Prefix = options.Prefix; return ShareRestClient::Service::ListSharesSegment( m_serviceUri.ToString(), *m_pipeline, options.Context, protocolLayerOptions); } diff --git a/sdk/storage/src/shares/share_client.cpp b/sdk/storage/src/shares/share_client.cpp new file mode 100644 index 000000000..b0991aa18 --- /dev/null +++ b/sdk/storage/src/shares/share_client.cpp @@ -0,0 +1,135 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +#include "shares/share_client.hpp" + +#include "common/common_headers_request_policy.hpp" +#include "common/constants.hpp" +#include "common/crypt.hpp" +#include "common/shared_key_policy.hpp" +#include "common/storage_common.hpp" +#include "common/storage_version.hpp" +#include "credentials/policy/policies.hpp" +#include "http/curl/curl.hpp" + +namespace Azure { namespace Storage { namespace Files { namespace Shares { + + ShareClient ShareClient::CreateFromConnectionString( + const std::string& connectionString, + const std::string& shareName, + const ShareClientOptions& options) + { + auto parsedConnectionString = Azure::Storage::Details::ParseConnectionString(connectionString); + auto shareUri = std::move(parsedConnectionString.FileServiceUri); + shareUri.AppendPath(shareName, true); + + if (parsedConnectionString.KeyCredential) + { + return ShareClient(shareUri.ToString(), parsedConnectionString.KeyCredential, options); + } + else + { + return ShareClient(shareUri.ToString(), options); + } + } + + ShareClient::ShareClient( + const std::string& shareUri, + std::shared_ptr credential, + const ShareClientOptions& options) + : m_shareUri(shareUri) + { + + std::vector> policies; + policies.emplace_back(std::make_unique( + Azure::Storage::Details::c_FileServicePackageName, FileServiceVersion)); + for (const auto& p : options.PerOperationPolicies) + { + policies.emplace_back(p->Clone()); + } + policies.emplace_back( + std::make_unique(Azure::Core::Http::RetryOptions())); + for (const auto& p : options.PerRetryPolicies) + { + policies.emplace_back(p->Clone()); + } + policies.emplace_back(std::make_unique()); + policies.emplace_back(std::make_unique(credential)); + policies.emplace_back(std::make_unique( + std::make_shared())); + m_pipeline = std::make_shared(policies); + } + + ShareClient::ShareClient( + const std::string& shareUri, + std::shared_ptr credential, + const ShareClientOptions& options) + : m_shareUri(shareUri) + { + std::vector> policies; + policies.emplace_back(std::make_unique( + Azure::Storage::Details::c_FileServicePackageName, FileServiceVersion)); + for (const auto& p : options.PerOperationPolicies) + { + policies.emplace_back(p->Clone()); + } + policies.emplace_back( + std::make_unique(Azure::Core::Http::RetryOptions())); + for (const auto& p : options.PerRetryPolicies) + { + policies.emplace_back(p->Clone()); + } + policies.emplace_back(std::make_unique()); + policies.emplace_back( + std::make_unique( + credential, Azure::Storage::Details::c_StorageScope)); + policies.emplace_back(std::make_unique( + std::make_shared())); + m_pipeline = std::make_shared(policies); + } + + ShareClient::ShareClient(const std::string& shareUri, const ShareClientOptions& options) + : m_shareUri(shareUri) + { + std::vector> policies; + policies.emplace_back(std::make_unique( + Azure::Storage::Details::c_FileServicePackageName, FileServiceVersion)); + for (const auto& p : options.PerOperationPolicies) + { + policies.emplace_back(p->Clone()); + } + policies.emplace_back( + std::make_unique(Azure::Core::Http::RetryOptions())); + for (const auto& p : options.PerRetryPolicies) + { + policies.emplace_back(p->Clone()); + } + policies.emplace_back(std::make_unique()); + policies.emplace_back(std::make_unique( + std::make_shared())); + m_pipeline = std::make_shared(policies); + } + + Azure::Core::Response ShareClient::Create(const CreateShareOptions& options) const + { + auto protocolLayerOptions = ShareRestClient::Share::CreateOptions(); + protocolLayerOptions.Metadata = options.Metadata; + protocolLayerOptions.ShareQuota = options.ShareQuota; + return ShareRestClient::Share::Create( + m_shareUri.ToString(), *m_pipeline, options.Context, protocolLayerOptions); + } + + Azure::Core::Response ShareClient::Delete( + const DeleteShareOptions& options) const + { + auto protocolLayerOptions = ShareRestClient::Share::DeleteOptions(); + protocolLayerOptions.ShareSnapshot = options.ShareSnapshot; + if (options.IncludeSnapshots.HasValue() and options.IncludeSnapshots.GetValue()) + { + protocolLayerOptions.XMsDeleteSnapshots = DeleteSnapshotsOptionType::Include; + } + return ShareRestClient::Share::Delete( + m_shareUri.ToString(), *m_pipeline, options.Context, protocolLayerOptions); + } + +}}}} // namespace Azure::Storage::Files::Shares diff --git a/sdk/storage/test/CMakeLists.txt b/sdk/storage/test/CMakeLists.txt index 181a1f445..608cd845a 100644 --- a/sdk/storage/test/CMakeLists.txt +++ b/sdk/storage/test/CMakeLists.txt @@ -30,11 +30,15 @@ add_executable ( datalake/directory_client_test.hpp datalake/directory_client_test.cpp common/bearer_token_test.cpp -) + shares/service_client_test.hpp + shares/service_client_test.cpp + shares/share_client_test.cpp + shares/share_client_test.hpp + ) target_include_directories(azure-storage-test PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -target_link_libraries(azure-storage-test PUBLIC azure::storage::blob azure::storage::file::datalake) +target_link_libraries(azure-storage-test PUBLIC azure::storage::blob azure::storage::file::datalake azure::storage::file::share) if (MSVC) target_compile_options(azure-storage-test PUBLIC /wd6326 /wd26495 /wd26812) diff --git a/sdk/storage/test/shares/service_client_test.cpp b/sdk/storage/test/shares/service_client_test.cpp new file mode 100644 index 000000000..da5b2fe9b --- /dev/null +++ b/sdk/storage/test/shares/service_client_test.cpp @@ -0,0 +1,127 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +#include "service_client_test.hpp" + +#include + +namespace Azure { namespace Storage { namespace Test { + + const size_t c_SHARE_TEST_SIZE = 5; + + std::shared_ptr + FileShareServiceClientTest::m_fileShareServiceClient; + std::vector FileShareServiceClientTest::m_shareNameSetA; + std::vector FileShareServiceClientTest::m_shareNameSetB; + std::string FileShareServiceClientTest::m_sharePrefixA; + std::string FileShareServiceClientTest::m_sharePrefixB; + + void FileShareServiceClientTest::SetUpTestSuite() + { + m_fileShareServiceClient = std::make_shared( + Files::Shares::ServiceClient::CreateFromConnectionString( + StandardStorageConnectionString())); + m_sharePrefixA = LowercaseRandomString(10); + m_sharePrefixB = LowercaseRandomString(10); + for (size_t i = 0; i < c_SHARE_TEST_SIZE; ++i) + { + { + auto name = m_sharePrefixA + LowercaseRandomString(10); + m_fileShareServiceClient->GetShareClient(name).Create(); + m_shareNameSetA.emplace_back(std::move(name)); + } + { + auto name = m_sharePrefixB + LowercaseRandomString(10); + m_fileShareServiceClient->GetShareClient(name).Create(); + m_shareNameSetB.emplace_back(std::move(name)); + } + } + } + + void FileShareServiceClientTest::TearDownTestSuite() + { + for (const auto& name : m_shareNameSetA) + { + m_fileShareServiceClient->GetShareClient(name).Delete(); + } + for (const auto& name : m_shareNameSetB) + { + m_fileShareServiceClient->GetShareClient(name).Delete(); + } + } + + std::vector FileShareServiceClientTest::ListAllShares( + const std::string& prefix) + { + std::vector result; + std::string continuation; + Files::Shares::ListSharesOptions options; + if (!prefix.empty()) + { + options.Prefix = prefix; + } + do + { + auto response = m_fileShareServiceClient->ListSharesSegment(options); + result.insert(result.end(), response->ShareItems.begin(), response->ShareItems.end()); + continuation = response->NextMarker; + options.Marker = continuation; + } while (!continuation.empty()); + return result; + } + + TEST_F(FileShareServiceClientTest, ListShares) + { + { + // Normal list without prefix. + auto result = ListAllShares(); + for (const auto& name : m_shareNameSetA) + { + auto iter = std::find_if( + result.begin(), result.end(), [&name](const Files::Shares::ShareItem& share) { + return share.Name == name; + }); + EXPECT_EQ(iter->Name.substr(0U, m_sharePrefixA.size()), m_sharePrefixA); + EXPECT_NE(result.end(), iter); + } + for (const auto& name : m_shareNameSetB) + { + auto iter = std::find_if( + result.begin(), result.end(), [&name](const Files::Shares::ShareItem& share) { + return share.Name == name; + }); + EXPECT_EQ(iter->Name.substr(0U, m_sharePrefixB.size()), m_sharePrefixB); + EXPECT_NE(result.end(), iter); + } + } + { + // List prefix. + auto result = ListAllShares(m_sharePrefixA); + for (const auto& name : m_shareNameSetA) + { + auto iter = std::find_if( + result.begin(), result.end(), [&name](const Files::Shares::ShareItem& share) { + return share.Name == name; + }); + EXPECT_EQ(iter->Name.substr(0U, m_sharePrefixA.size()), m_sharePrefixA); + EXPECT_NE(result.end(), iter); + } + for (const auto& name : m_shareNameSetB) + { + auto iter = std::find_if( + result.begin(), result.end(), [&name](const Files::Shares::ShareItem& share) { + return share.Name == name; + }); + EXPECT_EQ(result.end(), iter); + } + } + { + // List max result + Files::Shares::ListSharesOptions options; + options.MaxResults = 2; + auto response = m_fileShareServiceClient->ListSharesSegment(options); + EXPECT_LE(2U, response->ShareItems.size()); + } + } + +}}} // namespace Azure::Storage::Test diff --git a/sdk/storage/test/shares/service_client_test.hpp b/sdk/storage/test/shares/service_client_test.hpp new file mode 100644 index 000000000..7db236321 --- /dev/null +++ b/sdk/storage/test/shares/service_client_test.hpp @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +#include "shares/shares.hpp" +#include "test_base.hpp" + +namespace Azure { namespace Storage { namespace Test { + + class FileShareServiceClientTest : public ::testing::Test { + protected: + static void SetUpTestSuite(); + static void TearDownTestSuite(); + + static std::vector ListAllShares( + const std::string& prefix = std::string()); + + static std::shared_ptr m_fileShareServiceClient; + static std::vector m_shareNameSetA; + static std::string m_sharePrefixA; + static std::vector m_shareNameSetB; + static std::string m_sharePrefixB; + }; + +}}} // namespace Azure::Storage::Test diff --git a/sdk/storage/test/shares/share_client_test.cpp b/sdk/storage/test/shares/share_client_test.cpp new file mode 100644 index 000000000..2cbb80b24 --- /dev/null +++ b/sdk/storage/test/shares/share_client_test.cpp @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +#include "share_client_test.hpp" + +#include + +namespace Azure { namespace Storage { namespace Test { + + std::shared_ptr FileShareClientTest::m_shareClient; + std::string FileShareClientTest::m_fileSystemName; + + void FileShareClientTest::SetUpTestSuite() + { + m_fileSystemName = LowercaseRandomString(); + m_shareClient = std::make_shared( + Files::Shares::ShareClient::CreateFromConnectionString( + StandardStorageConnectionString(), m_fileSystemName)); + m_shareClient->Create(); + } + + void FileShareClientTest::TearDownTestSuite() { m_shareClient->Delete(); } + + Files::Shares::FileShareHttpHeaders FileShareClientTest::GetInterestingHttpHeaders() + { + static Files::Shares::FileShareHttpHeaders result = []() { + Files::Shares::FileShareHttpHeaders ret; + ret.CacheControl = std::string("no-cache"); + ret.ContentDisposition = std::string("attachment"); + ret.ContentEncoding = std::string("deflate"); + ret.ContentLanguage = std::string("en-US"); + ret.ContentType = std::string("application/octet-stream"); + return ret; + }(); + return result; + } + + TEST_F(FileShareClientTest, CreateDeleteFileSystems) + { + { + // Normal create/delete. + std::vector fileSystemClient; + for (int32_t i = 0; i < 5; ++i) + { + auto client = Files::Shares::ShareClient::CreateFromConnectionString( + StandardStorageConnectionString(), LowercaseRandomString()); + EXPECT_NO_THROW(client.Create()); + fileSystemClient.emplace_back(std::move(client)); + } + for (const auto& client : fileSystemClient) + { + EXPECT_NO_THROW(client.Delete()); + } + } + } + +}}} // namespace Azure::Storage::Test diff --git a/sdk/storage/test/shares/share_client_test.hpp b/sdk/storage/test/shares/share_client_test.hpp new file mode 100644 index 000000000..2b59c28f0 --- /dev/null +++ b/sdk/storage/test/shares/share_client_test.hpp @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +#include "shares/shares.hpp" +#include "test_base.hpp" + +namespace Azure { namespace Storage { namespace Test { + + class FileShareClientTest : public ::testing::Test { + protected: + static void SetUpTestSuite(); + static void TearDownTestSuite(); + + static Files::Shares::FileShareHttpHeaders GetInterestingHttpHeaders(); + + static std::shared_ptr m_shareClient; + static std::string m_fileSystemName; + }; + +}}} // namespace Azure::Storage::Test