diff --git a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/rest_client.hpp b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/rest_client.hpp index 9118b085cd..0a58b8e565 100644 --- a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/rest_client.hpp +++ b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/rest_client.hpp @@ -26,7 +26,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { /** * The version used for the operations to Azure storage services. */ - constexpr static const char* ApiVersion = "2020-02-10"; + constexpr static const char* ApiVersion = "2021-06-08"; } // namespace _detail namespace Models { namespace _detail { @@ -92,6 +92,10 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { std::string Owner; std::string Group; std::string Permissions; + /** + * The name of the encryption scope under which the blob is encrypted. + */ + Nullable EncryptionScope; std::string ETag; }; namespace _detail { @@ -152,6 +156,16 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { * The size of the resource in bytes. */ Nullable FileSize; + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + Nullable IsServerEncrypted; + /** + * The SHA-256 hash of the encryption key used to encrypt the blob. This header is only + * returned when the blob was encrypted with a customer-provided key. + */ + Nullable> EncryptionKeySha256; }; /** * @brief Response type for #Azure::Storage::Files::DataLake::PathClient::Delete. @@ -220,6 +234,17 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { */ Nullable ContinuationToken; }; + /** + * @brief Response type for #Azure::Storage::Files::DataLake::PathClient::Undelete. + */ + struct UndeletePathResult final + { + /** + * The type of the resource. The value may be "file" or "directory". If not set, the value + * is "file". + */ + Nullable ResourceType; + }; /** * @brief Response type for * #Azure::Storage::Files::DataLake::PathClient::GetAccessControlList. @@ -267,6 +292,16 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { * The size of the resource in bytes. */ int64_t FileSize = int64_t(); + /** + * The value of this header is set to true if the contents of the request are successfully + * encrypted using the specified algorithm, and false otherwise. + */ + Nullable IsServerEncrypted; + /** + * The SHA-256 hash of the encryption key used to encrypt the blob. This header is only + * returned when the blob was encrypted with a customer-provided key. + */ + Nullable> EncryptionKeySha256; }; /** * @brief Response type for #Azure::Storage::Files::DataLake::FileClient::Append. @@ -282,7 +317,12 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { * The value of this header is set to true if the contents of the request are successfully * encrypted using the specified algorithm, and false otherwise. */ - bool IsServerEncrypted = bool(); + Nullable IsServerEncrypted; + /** + * The SHA-256 hash of the encryption key used to encrypt the blob. This header is only + * returned when the blob was encrypted with a customer-provided key. + */ + Nullable> EncryptionKeySha256; }; } // namespace Models namespace _detail { @@ -332,6 +372,14 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { ETag SourceIfNoneMatch; Nullable SourceIfModifiedSince; Nullable SourceIfUnmodifiedSince; + Nullable EncryptionKey; + Nullable> EncryptionKeySha256; + Nullable Owner; + Nullable Group; + Nullable Acl; + Nullable ProposedLeaseId; + Nullable LeaseDuration; + Nullable ExpiresOn; }; static Response Create( Core::Http::_internal::HttpPipeline& pipeline, @@ -386,6 +434,15 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { const Core::Url& url, const SetPathAccessControlListRecursiveOptions& options, const Core::Context& context); + struct UndeletePathOptions final + { + Nullable UndeleteSource; + }; + static Response Undelete( + Core::Http::_internal::HttpPipeline& pipeline, + const Core::Url& url, + const UndeletePathOptions& options, + const Core::Context& context); struct GetPathAccessControlListOptions final { Nullable Upn; @@ -419,6 +476,8 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { ETag IfNoneMatch; Nullable IfModifiedSince; Nullable IfUnmodifiedSince; + Nullable EncryptionKey; + Nullable> EncryptionKeySha256; }; static Response Flush( Core::Http::_internal::HttpPipeline& pipeline, @@ -431,6 +490,9 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { Nullable> TransactionalContentHash; Nullable> TransactionalContentCrc64; Nullable LeaseId; + Nullable EncryptionKey; + Nullable> EncryptionKeySha256; + Nullable Flush; }; static Response Append( Core::Http::_internal::HttpPipeline& pipeline, diff --git a/sdk/storage/azure-storage-files-datalake/src/rest_client.cpp b/sdk/storage/azure-storage-files-datalake/src/rest_client.cpp index a19745cfdc..2d519a9487 100644 --- a/sdk/storage/azure-storage-files-datalake/src/rest_client.cpp +++ b/sdk/storage/azure-storage-files-datalake/src/rest_client.cpp @@ -58,7 +58,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { { request.GetUrl().AppendQueryParameter("timeout", std::to_string(options.Timeout.Value())); } - request.SetHeader("x-ms-version", "2020-02-10"); + request.SetHeader("x-ms-version", "2021-06-08"); if (options.ContinuationToken.HasValue() && !options.ContinuationToken.Value().empty()) { request.GetUrl().AppendQueryParameter( @@ -110,6 +110,10 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { vectorElement2.Owner = var0["owner"].get(); vectorElement2.Group = var0["group"].get(); vectorElement2.Permissions = var0["permissions"].get(); + if (var0.count("EncryptionScope") != 0) + { + vectorElement2.EncryptionScope = var0["EncryptionScope"].get(); + } if (var0.count("etag") != 0) { vectorElement2.ETag = var0["etag"].get(); @@ -138,7 +142,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { { request.GetUrl().AppendQueryParameter("timeout", std::to_string(options.Timeout.Value())); } - request.SetHeader("x-ms-version", "2020-02-10"); + request.SetHeader("x-ms-version", "2021-06-08"); if (options.Resource.HasValue() && !options.Resource.Value().ToString().empty()) { request.GetUrl().AppendQueryParameter( @@ -238,6 +242,42 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { "x-ms-source-if-unmodified-since", options.SourceIfUnmodifiedSince.Value().ToString(Azure::DateTime::DateFormat::Rfc1123)); } + if (options.EncryptionKey.HasValue() && !options.EncryptionKey.Value().empty()) + { + request.SetHeader("x-ms-encryption-key", options.EncryptionKey.Value()); + } + if (options.EncryptionKeySha256.HasValue() + && !Core::Convert::Base64Encode(options.EncryptionKeySha256.Value()).empty()) + { + request.SetHeader( + "x-ms-encryption-key-sha256", + Core::Convert::Base64Encode(options.EncryptionKeySha256.Value())); + } + request.SetHeader("x-ms-encryption-algorithm", "AES256"); + if (options.Owner.HasValue() && !options.Owner.Value().empty()) + { + request.SetHeader("x-ms-owner", options.Owner.Value()); + } + if (options.Group.HasValue() && !options.Group.Value().empty()) + { + request.SetHeader("x-ms-group", options.Group.Value()); + } + if (options.Acl.HasValue() && !options.Acl.Value().empty()) + { + request.SetHeader("x-ms-acl", options.Acl.Value()); + } + if (options.ProposedLeaseId.HasValue() && !options.ProposedLeaseId.Value().empty()) + { + request.SetHeader("x-ms-proposed-lease-id", options.ProposedLeaseId.Value()); + } + if (options.LeaseDuration.HasValue()) + { + request.SetHeader("x-ms-lease-duration", std::to_string(options.LeaseDuration.Value())); + } + if (options.ExpiresOn.HasValue() && !options.ExpiresOn.Value().empty()) + { + request.SetHeader("x-ms-expiry-time", options.ExpiresOn.Value()); + } auto pRawResponse = pipeline.Send(request, context); auto httpStatusCode = pRawResponse->GetStatusCode(); if (httpStatusCode != Core::Http::HttpStatusCode::Created) @@ -252,6 +292,16 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { { response.FileSize = std::stoll(pRawResponse->GetHeaders().at("Content-Length")); } + if (pRawResponse->GetHeaders().count("x-ms-request-server-encrypted") != 0) + { + response.IsServerEncrypted + = pRawResponse->GetHeaders().at("x-ms-request-server-encrypted") == std::string("true"); + } + if (pRawResponse->GetHeaders().count("x-ms-encryption-key-sha256") != 0) + { + response.EncryptionKeySha256 = Core::Convert::Base64Decode( + pRawResponse->GetHeaders().at("x-ms-encryption-key-sha256")); + } return Response(std::move(response), std::move(pRawResponse)); } Response PathClient::Delete( @@ -269,7 +319,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { { request.GetUrl().AppendQueryParameter("timeout", std::to_string(options.Timeout.Value())); } - request.SetHeader("x-ms-version", "2020-02-10"); + request.SetHeader("x-ms-version", "2021-06-08"); if (options.Recursive.HasValue()) { request.GetUrl().AppendQueryParameter( @@ -361,7 +411,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { "If-Unmodified-Since", options.IfUnmodifiedSince.Value().ToString(Azure::DateTime::DateFormat::Rfc1123)); } - request.SetHeader("x-ms-version", "2020-02-10"); + request.SetHeader("x-ms-version", "2021-06-08"); auto pRawResponse = pipeline.Send(request, context); auto httpStatusCode = pRawResponse->GetStatusCode(); if (httpStatusCode != Core::Http::HttpStatusCode::Ok) @@ -408,7 +458,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { { request.SetHeader("x-ms-acl", options.Acl.Value()); } - request.SetHeader("x-ms-version", "2020-02-10"); + request.SetHeader("x-ms-version", "2021-06-08"); auto pRawResponse = pipeline.Send(request, context); auto httpStatusCode = pRawResponse->GetStatusCode(); if (httpStatusCode != Core::Http::HttpStatusCode::Ok) @@ -449,6 +499,33 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { return Response( std::move(response), std::move(pRawResponse)); } + Response PathClient::Undelete( + Core::Http::_internal::HttpPipeline& pipeline, + const Core::Url& url, + const UndeletePathOptions& options, + const Core::Context& context) + { + auto request = Core::Http::Request(Core::Http::HttpMethod::Put, url); + request.GetUrl().AppendQueryParameter("comp", "undelete"); + if (options.UndeleteSource.HasValue() && !options.UndeleteSource.Value().empty()) + { + request.SetHeader("x-ms-undelete-source", options.UndeleteSource.Value()); + } + request.SetHeader("x-ms-version", "2021-06-08"); + auto pRawResponse = pipeline.Send(request, context); + auto httpStatusCode = pRawResponse->GetStatusCode(); + if (httpStatusCode != Core::Http::HttpStatusCode::Ok) + { + throw StorageException::CreateFromResponse(std::move(pRawResponse)); + } + Models::_detail::UndeletePathResult response; + if (pRawResponse->GetHeaders().count("x-ms-resource-type") != 0) + { + response.ResourceType = pRawResponse->GetHeaders().at("x-ms-resource-type"); + } + return Response( + std::move(response), std::move(pRawResponse)); + } Response PathClient::GetAccessControlList( Core::Http::_internal::HttpPipeline& pipeline, const Core::Url& url, @@ -485,7 +562,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { "If-Unmodified-Since", options.IfUnmodifiedSince.Value().ToString(Azure::DateTime::DateFormat::Rfc1123)); } - request.SetHeader("x-ms-version", "2020-02-10"); + request.SetHeader("x-ms-version", "2021-06-08"); auto pRawResponse = pipeline.Send(request, context); auto httpStatusCode = pRawResponse->GetStatusCode(); if (httpStatusCode != Core::Http::HttpStatusCode::Ok) @@ -572,7 +649,19 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { "If-Unmodified-Since", options.IfUnmodifiedSince.Value().ToString(Azure::DateTime::DateFormat::Rfc1123)); } - request.SetHeader("x-ms-version", "2020-02-10"); + request.SetHeader("x-ms-version", "2021-06-08"); + if (options.EncryptionKey.HasValue() && !options.EncryptionKey.Value().empty()) + { + request.SetHeader("x-ms-encryption-key", options.EncryptionKey.Value()); + } + if (options.EncryptionKeySha256.HasValue() + && !Core::Convert::Base64Encode(options.EncryptionKeySha256.Value()).empty()) + { + request.SetHeader( + "x-ms-encryption-key-sha256", + Core::Convert::Base64Encode(options.EncryptionKeySha256.Value())); + } + request.SetHeader("x-ms-encryption-algorithm", "AES256"); auto pRawResponse = pipeline.Send(request, context); auto httpStatusCode = pRawResponse->GetStatusCode(); if (httpStatusCode != Core::Http::HttpStatusCode::Ok) @@ -584,6 +673,16 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { response.LastModified = DateTime::Parse( pRawResponse->GetHeaders().at("Last-Modified"), Azure::DateTime::DateFormat::Rfc1123); response.FileSize = std::stoll(pRawResponse->GetHeaders().at("Content-Length")); + if (pRawResponse->GetHeaders().count("x-ms-request-server-encrypted") != 0) + { + response.IsServerEncrypted + = pRawResponse->GetHeaders().at("x-ms-request-server-encrypted") == std::string("true"); + } + if (pRawResponse->GetHeaders().count("x-ms-encryption-key-sha256") != 0) + { + response.EncryptionKeySha256 = Core::Convert::Base64Decode( + pRawResponse->GetHeaders().at("x-ms-encryption-key-sha256")); + } return Response(std::move(response), std::move(pRawResponse)); } Response FileClient::Append( @@ -617,7 +716,23 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { { request.SetHeader("x-ms-lease-id", options.LeaseId.Value()); } - request.SetHeader("x-ms-version", "2020-02-10"); + request.SetHeader("x-ms-version", "2021-06-08"); + if (options.EncryptionKey.HasValue() && !options.EncryptionKey.Value().empty()) + { + request.SetHeader("x-ms-encryption-key", options.EncryptionKey.Value()); + } + if (options.EncryptionKeySha256.HasValue() + && !Core::Convert::Base64Encode(options.EncryptionKeySha256.Value()).empty()) + { + request.SetHeader( + "x-ms-encryption-key-sha256", + Core::Convert::Base64Encode(options.EncryptionKeySha256.Value())); + } + request.SetHeader("x-ms-encryption-algorithm", "AES256"); + if (options.Flush.HasValue()) + { + request.GetUrl().AppendQueryParameter("flush", options.Flush.Value() ? "true" : "false"); + } auto pRawResponse = pipeline.Send(request, context); auto httpStatusCode = pRawResponse->GetStatusCode(); if (httpStatusCode != Core::Http::HttpStatusCode::Accepted) @@ -639,8 +754,16 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { = Core::Convert::Base64Decode(pRawResponse->GetHeaders().at("x-ms-content-crc64")); response.TransactionalContentHash.Value().Algorithm = HashAlgorithm::Crc64; } - response.IsServerEncrypted - = pRawResponse->GetHeaders().at("x-ms-request-server-encrypted") == std::string("true"); + if (pRawResponse->GetHeaders().count("x-ms-request-server-encrypted") != 0) + { + response.IsServerEncrypted + = pRawResponse->GetHeaders().at("x-ms-request-server-encrypted") == std::string("true"); + } + if (pRawResponse->GetHeaders().count("x-ms-encryption-key-sha256") != 0) + { + response.EncryptionKeySha256 = Core::Convert::Base64Decode( + pRawResponse->GetHeaders().at("x-ms-encryption-key-sha256")); + } return Response(std::move(response), std::move(pRawResponse)); } } // namespace _detail diff --git a/sdk/storage/azure-storage-files-datalake/swagger/README.md b/sdk/storage/azure-storage-files-datalake/swagger/README.md index 0e9b87c617..5344d267a8 100644 --- a/sdk/storage/azure-storage-files-datalake/swagger/README.md +++ b/sdk/storage/azure-storage-files-datalake/swagger/README.md @@ -9,7 +9,7 @@ package-name: azure-storage-files-datalake namespace: Azure::Storage::Files::DataLake output-folder: generated clear-output-folder: true -input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/storage-main/specification/storage/data-plane/Microsoft.StorageDataLake/stable/2020-06-12/DataLakeStorage.json +input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/storage/data-plane/Azure.Storage.Files.DataLake/preview/2021-06-08/DataLakeStorage.json ``` ## ModelFour Options @@ -66,12 +66,11 @@ directive: delete $["/{filesystem}"].patch; delete $["/{filesystem}"].head; delete $["/{filesystem}"].delete; - delete $["/{filesystem}?restype=container&comp=list&hierarchy"]; delete $["/{filesystem}/{path}"].post; delete $["/{filesystem}/{path}"].get; delete $["/{filesystem}/{path}"].patch; delete $["/{filesystem}/{path}?comp=expiry"]; - delete $["/{filesystem}/{path}?comp=undelete"]; + delete $["/{filesystem}?restype=container&comp=list&hierarchy"]; ``` ### API Version @@ -89,13 +88,13 @@ directive: "name": "ApiVersion", "modelAsString": false }, - "enum": ["2020-02-10"], + "enum": ["2021-06-08"], "description": "The version used for the operations to Azure storage services." }; - from: swagger-document where: $.parameters transform: > - $.ApiVersionParameter.enum[0] = "2020-02-10"; + $.ApiVersionParameter.enum[0] = "2021-06-08"; ``` ### Rename Operations @@ -118,14 +117,70 @@ directive: } ``` +### Return Type namespace + +```yaml +directive: + - from: swagger-document + where: $ + transform: > + const operations = [ + "Path_Undelete", + ]; + for (const url in $["x-ms-paths"]) { + for (const verb in $["x-ms-paths"][url]) { + if (!operations.includes($["x-ms-paths"][url][verb].operationId)) continue; + const operation = $["x-ms-paths"][url][verb]; + + const status_codes = Object.keys(operation.responses).filter(s => s !== "default"); + status_codes.forEach((status_code, i) => { + if (!operation.responses[status_code].schema) { + const operationId = operation.operationId; + const clientName = operationId.substr(0, operationId.indexOf("_")); + const operationName = operationId.substr(operationId.indexOf("_") + 1); + let operationWords = operationName.split(/(?=[A-Z])/); + operationWords.splice(1, 0, clientName); + const defaultReturnTypeName = operationWords.join("") + "Result"; + operation.responses[status_code].schema = { + "type": "object", + "x-ms-sealed": false, + "x-ms-client-name": defaultReturnTypeName, + "x-namespace": "_detail", + "properties": { + "__placeHolder": {"type": "integer"} + } + }; + } else if (operation.responses[status_code].schema["$ref"]) { + let obj = $; + for (const p of operation.responses[status_code].schema["$ref"].split("/").slice(1)) { + obj = obj[p]; + } + obj["x-namespace"] = "_detail"; + } else { + operation.responses[status_code].schema["x-namespace"] = "_detail"; + } + }); + } + } +``` + ### Global Changes for Definitions, Types etc. ```yaml directive: + - from: swagger-document + where: $["x-ms-paths"].*.*.responses.*.headers + transform: > + for (const h in $) { + if (h === "x-ms-encryption-key-sha256") { + $[h]["format"] = "byte"; + } + } - from: swagger-document where: $.parameters transform: > $.Continuation["x-ms-client-name"] = "ContinuationToken"; + $.EncryptionKeySha256["format"] = "byte"; - from: swagger-document where: $.definitions transform: > @@ -175,6 +230,9 @@ directive: $.Path.properties["lastModified"]["format"] = "date-time-rfc1123"; $.Path.properties["contentLength"]["x-ms-client-name"] = "FileSize"; $.Path.properties["isDirectory"]["x-ms-client-default"] = false; + $.Path.properties["EncryptionScope"]["x-nullable"] = true; + delete $.Path.properties["creationTime"]; + delete $.Path.properties["expiryTime"]; $.Path.properties["etag"] = {"type": "string", "x-ms-format": "string", "x-ms-client-default": "", "x-ms-client-name": "ETag"}; delete $.Path.properties["eTag"]; $.PathList["x-namespace"] = "_detail"; @@ -192,11 +250,17 @@ directive: ```yaml directive: + - from: swagger-document + where: $["x-ms-paths"]["/{filesystem}/{path}"].put.parameters + transform: > + $ = $.filter(p => !(p["$ref"] && (p["$ref"].endsWith("#/parameters/PathExpiryOptionsOptional")))); - from: swagger-document where: $["x-ms-paths"]["/{filesystem}/{path}"].put.responses transform: > $["201"].headers["Content-Length"]["x-ms-client-name"] = "FileSize"; $["201"].headers["Content-Length"]["x-nullable"] = true; + $["201"].headers["x-ms-request-server-encrypted"]["x-nullable"] = true; + $["201"].headers["x-ms-encryption-key-sha256"]["x-nullable"] = true; delete $["201"].headers["x-ms-continuation"]; $["201"].schema = { "type": "object", @@ -208,6 +272,18 @@ directive: }; ``` + +### SetExpiry + +```yaml +directive: + - from: swagger-document + where: $.parameters + transform: > + delete $["PathExpiryOptions"]; + delete $["PathExpiryOptionsOptional"]; +``` + ### DeletePath ```yaml @@ -253,6 +329,16 @@ directive: } ``` +### UndeletePath + +```yaml +directive: + - from: swagger-document + where: $["x-ms-paths"]["/{filesystem}/{path}?comp=undelete"].put.responses + transform: > + $["200"].headers["x-ms-resource-type"]["x-nullable"] = true; +``` + ### GetPathAccessControlList ```yaml @@ -349,6 +435,8 @@ directive: $["Content-MD5"]["x-nullable"] = true; $["x-ms-content-crc64"]["x-ms-client-name"] = "TransactionalContentHash"; $["x-ms-content-crc64"]["x-nullable"] = true; + $["x-ms-request-server-encrypted"]["x-nullable"] = true; + $["x-ms-encryption-key-sha256"]["x-nullable"] = true; delete $["ETag"]; ``` @@ -360,4 +448,6 @@ directive: where: $["x-ms-paths"]["/{filesystem}/{path}?action=flush"].patch.responses["200"].headers transform: > $["Content-Length"]["x-ms-client-name"] = "FileSize"; + $["x-ms-request-server-encrypted"]["x-nullable"] = true; + $["x-ms-encryption-key-sha256"]["x-nullable"] = true; ``` \ No newline at end of file