From a898fd819aa0fa987358f751f246f4d8a8b85157 Mon Sep 17 00:00:00 2001 From: Kan Tang Date: Wed, 30 Sep 2020 01:13:37 -0700 Subject: [PATCH] Added SetExpiry DataLake convenience layer. (#696) --- .../files/datalake/datalake_file_client.hpp | 12 ++++++ .../files/datalake/datalake_options.hpp | 26 ++++++++++++ .../files/datalake/datalake_responses.hpp | 6 +++ .../src/datalake_file_client.cpp | 25 +++++++++++ .../src/datalake_path_client.cpp | 2 + .../test/datalake_file_client_test.cpp | 41 +++++++++++++++++++ 6 files changed, 112 insertions(+) diff --git a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_file_client.hpp b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_file_client.hpp index 636c3d8aa..da8dbfad6 100644 --- a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_file_client.hpp +++ b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_file_client.hpp @@ -227,6 +227,18 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { const std::string& file, const DownloadFileToOptions& options = DownloadFileToOptions()) const; + /** + * @brief Schedules the file for deletion. + * @param expiryOrigin Specify the origin of expiry. + * @param options Optional parameters to schedule the file for deletion. + * @return Azure::Core::Response containing the information and + * content returned when schedule the file for deletion. + * @remark This request is sent to blob endpoint. + */ + Azure::Core::Response ScheduleDeletion( + ScheduleFileExpiryOriginType expiryOrigin, + const ScheduleFileDeletionOptions& options = ScheduleFileDeletionOptions()) const; + private: Blobs::BlockBlobClient m_blockBlobClient; diff --git a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_options.hpp b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_options.hpp index cda3dc856..d123b055c 100644 --- a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_options.hpp +++ b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_options.hpp @@ -681,6 +681,32 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { int Concurrency = 1; }; + using ScheduleFileExpiryOriginType = Blobs::ScheduleBlobExpiryOriginType; + + /** + * @brief Optional parameters for FileClient::UploadFromBuffer and FileClient::UploadFromFile + */ + struct ScheduleFileDeletionOptions + { + /** + * @brief Context for cancelling long running operations. + */ + Azure::Core::Context Context; + + /** + * @brief The expiry time from the specified origin. Only work if ExpiryOrigin is + * ScheduleFileExpiryOriginType::RelativeToCreation or + * ScheduleFileExpiryOriginType::RelativeToNow. + */ + Azure::Core::Nullable TimeToExpireInMs; + + /** + * @brief The expiry time in RFC1123 format. Only work if ExpiryOrigin is + * ScheduleFileExpiryOriginType::Absolute. + */ + Azure::Core::Nullable ExpiresOn; + }; + /** * @brief Optional parameters for FileClient::DownloadToBuffer and FileClient::DownloadToFile. */ diff --git a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_responses.hpp b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_responses.hpp index 4e6be0ec1..40353a5ff 100644 --- a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_responses.hpp +++ b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_responses.hpp @@ -93,6 +93,8 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { Azure::Core::Nullable CopyStatus; Azure::Core::Nullable CopyProgress; Azure::Core::Nullable CopyCompletionTime; + Azure::Core::Nullable ExpiryTime; + Azure::Core::Nullable LastAccessTime; }; struct GetPathAccessControlResult @@ -128,6 +130,7 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { using UploadFileFromResult = Blobs::UploadBlockBlobResult; using AppendFileDataResult = PathAppendDataResult; using FlushFileDataResult = PathFlushDataResult; + using ScheduleFileDeletionResult = Blobs::SetBlobExpiryResult; struct ReadFileResult { @@ -143,6 +146,9 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { LeaseStatusType LeaseStatus = LeaseStatusType::Unknown; Azure::Core::Nullable ContentMd5; std::map Metadata; + std::string CreationTime; + Azure::Core::Nullable ExpiryTime; + Azure::Core::Nullable LastAccessTime; }; struct RenameFileResult diff --git a/sdk/storage/azure-storage-files-datalake/src/datalake_file_client.cpp b/sdk/storage/azure-storage-files-datalake/src/datalake_file_client.cpp index 27a1ac78b..0f15619f6 100644 --- a/sdk/storage/azure-storage-files-datalake/src/datalake_file_client.cpp +++ b/sdk/storage/azure-storage-files-datalake/src/datalake_file_client.cpp @@ -323,6 +323,9 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { ? FromBlobLeaseStatus(result->LeaseStatus.GetValue()) : ret.LeaseStatus; ret.Metadata = std::move(result->Metadata); + ret.CreationTime = std::move(result->CreationTime); + ret.ExpiryTime = std::move(result->ExpiryTime); + ret.LastAccessTime = std::move(result->LastAccessTime); return Azure::Core::Response(std::move(ret), result.ExtractRawResponse()); } @@ -386,4 +389,26 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { return Azure::Core::Response(std::move(ret), result.ExtractRawResponse()); } + Azure::Core::Response FileClient::ScheduleDeletion( + ScheduleFileExpiryOriginType expiryOrigin, + const ScheduleFileDeletionOptions& options) const + { + Blobs::BlobRestClient::Blob::SetBlobExpiryOptions protocolLayerOptions; + protocolLayerOptions.ExpiryOrigin = expiryOrigin; + if (options.ExpiresOn.HasValue() && options.TimeToExpireInMs.HasValue()) + { + throw std::runtime_error("ExpiresOn and TimeToExpireInMs should be mutually exlusive."); + } + if (options.ExpiresOn.HasValue()) + { + protocolLayerOptions.ExpiryTime = options.ExpiresOn; + } + else if (options.TimeToExpireInMs.HasValue()) + { + protocolLayerOptions.ExpiryTime = std::to_string(options.TimeToExpireInMs.GetValue()); + } + return Blobs::BlobRestClient::Blob::ScheduleDeletion( + options.Context, *m_pipeline, m_blobClient.m_blobUrl, protocolLayerOptions); + } + }}}} // namespace Azure::Storage::Files::DataLake diff --git a/sdk/storage/azure-storage-files-datalake/src/datalake_path_client.cpp b/sdk/storage/azure-storage-files-datalake/src/datalake_path_client.cpp index a110e1c28..d469abf7f 100644 --- a/sdk/storage/azure-storage-files-datalake/src/datalake_path_client.cpp +++ b/sdk/storage/azure-storage-files-datalake/src/datalake_path_client.cpp @@ -303,6 +303,8 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { ret.CopyStatus = std::move(result->CopyStatus); ret.CopyProgress = std::move(result->CopyProgress); ret.CopyCompletionTime = std::move(result->CopyCompletionTime); + ret.ExpiryTime = std::move(result->ExpiryTime); + ret.LastAccessTime = std::move(result->LastAccessTime); return Azure::Core::Response( std::move(ret), result.ExtractRawResponse()); } diff --git a/sdk/storage/azure-storage-files-datalake/test/datalake_file_client_test.cpp b/sdk/storage/azure-storage-files-datalake/test/datalake_file_client_test.cpp index 19091512e..5b28af2aa 100644 --- a/sdk/storage/azure-storage-files-datalake/test/datalake_file_client_test.cpp +++ b/sdk/storage/azure-storage-files-datalake/test/datalake_file_client_test.cpp @@ -377,4 +377,45 @@ namespace Azure { namespace Storage { namespace Test { } } + TEST_F(DataLakeFileClientTest, ScheduleForDeletion) + { + { + auto client = m_fileSystemClient->GetFileClient(LowercaseRandomString()); + EXPECT_NO_THROW(client.Create()); + EXPECT_NO_THROW( + client.ScheduleDeletion(Files::DataLake::ScheduleFileExpiryOriginType::NeverExpire)); + } + { + auto client = m_fileSystemClient->GetFileClient(LowercaseRandomString()); + EXPECT_NO_THROW(client.Create()); + Files::DataLake::ScheduleFileDeletionOptions options; + EXPECT_THROW( + client.ScheduleDeletion( + Files::DataLake::ScheduleFileExpiryOriginType::RelativeToNow, options), + StorageError); + options.TimeToExpireInMs = 1000; + EXPECT_NO_THROW(client.ScheduleDeletion( + Files::DataLake::ScheduleFileExpiryOriginType::RelativeToNow, options)); + } + { + auto client = m_fileSystemClient->GetFileClient(LowercaseRandomString()); + EXPECT_NO_THROW(client.Create()); + Files::DataLake::ScheduleFileDeletionOptions options; + EXPECT_THROW( + client.ScheduleDeletion(Files::DataLake::ScheduleFileExpiryOriginType::Absolute, options), + StorageError); + options.TimeToExpireInMs = 1000; + EXPECT_THROW( + client.ScheduleDeletion(Files::DataLake::ScheduleFileExpiryOriginType::Absolute, options), + StorageError); + options.ExpiresOn = "Tue, 29 Sep 2100 09:53:03 GMT"; + EXPECT_THROW( + client.ScheduleDeletion(Files::DataLake::ScheduleFileExpiryOriginType::Absolute, options), + std::runtime_error); + options.TimeToExpireInMs = Azure::Core::Nullable(); + EXPECT_NO_THROW(client.ScheduleDeletion( + Files::DataLake::ScheduleFileExpiryOriginType::Absolute, options)); + } + } + }}} // namespace Azure::Storage::Test