Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hns soft delete #3963

Merged
merged 7 commits into from
Sep 29, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ namespace Azure { namespace Storage { namespace Blobs {
friend class BlobServiceClient;
friend class BlobLeaseClient;
friend class BlobContainerBatch;
friend class Files::DataLake::DataLakeFileSystemClient;
};

}}} // namespace Azure::Storage::Blobs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,21 @@ namespace Azure { namespace Storage { namespace Blobs {
const std::string& ToString() const { return m_value; }
AZ_STORAGE_BLOBS_DLLEXPORT const static EncryptionAlgorithmType Aes256;

private:
std::string m_value;
microzchang marked this conversation as resolved.
Show resolved Hide resolved
};
/**
* @brief Include this parameter to specify one or more datasets to include in the response.
*/
class ListBlobsShowOnlyType final {
public:
ListBlobsShowOnlyType() = default;
explicit ListBlobsShowOnlyType(std::string value) : m_value(std::move(value)) {}
bool operator==(const ListBlobsShowOnlyType& other) const { return m_value == other.m_value; }
bool operator!=(const ListBlobsShowOnlyType& other) const { return !(*this == other); }
const std::string& ToString() const { return m_value; }
AZ_STORAGE_BLOBS_DLLEXPORT const static ListBlobsShowOnlyType Deleted;

private:
std::string m_value;
};
Expand Down Expand Up @@ -1365,6 +1380,10 @@ namespace Azure { namespace Storage { namespace Blobs {
* Type of the blob.
*/
Models::BlobType BlobType;
/**
* The deletion ID associated with the deleted path.
*/
Nullable<std::string> DeletionId;
};
} // namespace _detail
/**
Expand Down Expand Up @@ -3447,6 +3466,7 @@ namespace Azure { namespace Storage { namespace Blobs {
Nullable<std::string> Marker;
Nullable<int32_t> MaxResults;
Nullable<Models::ListBlobsIncludeFlags> Include;
Nullable<std::string> ShowOnly;
};
static Response<Models::_detail::ListBlobsByHierarchyResult> ListBlobsByHierarchy(
Core::Http::_internal::HttpPipeline& pipeline,
Expand Down
24 changes: 24 additions & 0 deletions sdk/storage/azure-storage-blobs/src/rest_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ std::string ListBlobsIncludeFlagsToString(
namespace Azure { namespace Storage { namespace Blobs {
namespace Models {
const EncryptionAlgorithmType EncryptionAlgorithmType::Aes256("AES256");
const ListBlobsShowOnlyType ListBlobsShowOnlyType::Deleted("deleted");
const BlockType BlockType::Committed("Committed");
const BlockType BlockType::Uncommitted("Uncommitted");
const BlockType BlockType::Latest("Latest");
Expand Down Expand Up @@ -2310,6 +2311,7 @@ namespace Azure { namespace Storage { namespace Blobs {
kHasVersionsOnly,
kContentLength,
kBlobType,
kDeletionId,
};
const std::unordered_map<std::string, XmlTagEnum> XmlTagEnumMap{
{"EnumerationResults", XmlTagEnum::kEnumerationResults},
Expand Down Expand Up @@ -2370,6 +2372,7 @@ namespace Azure { namespace Storage { namespace Blobs {
{"HasVersionsOnly", XmlTagEnum::kHasVersionsOnly},
{"Content-Length", XmlTagEnum::kContentLength},
{"BlobType", XmlTagEnum::kBlobType},
{"DeletionId", XmlTagEnum::kDeletionId},
};
std::vector<XmlTagEnum> xmlPath;
Models::_detail::BlobItem vectorElement1;
Expand Down Expand Up @@ -2807,6 +2810,13 @@ namespace Azure { namespace Storage { namespace Blobs {
{
vectorElement1.BlobType = Models::BlobType(node.Value);
}
else if (
xmlPath.size() == 4 && xmlPath[0] == XmlTagEnum::kEnumerationResults
&& xmlPath[1] == XmlTagEnum::kBlobs && xmlPath[2] == XmlTagEnum::kBlob
&& xmlPath[3] == XmlTagEnum::kDeletionId)
{
vectorElement1.DeletionId = node.Value;
}
}
else if (node.Type == _internal::XmlNodeType::Attribute)
{
Expand Down Expand Up @@ -2908,6 +2918,11 @@ namespace Azure { namespace Storage { namespace Blobs {
ListBlobsIncludeFlagsToString(options.Include.Value())));
}
request.SetHeader("x-ms-version", "2021-04-10");
if (options.ShowOnly.HasValue() && !options.ShowOnly.Value().empty())
{
request.GetUrl().AppendQueryParameter(
"showonly", _internal::UrlEncodeQueryParameter(options.ShowOnly.Value()));
}
auto pRawResponse = pipeline.Send(request, context);
auto httpStatusCode = pRawResponse->GetStatusCode();
if (httpStatusCode != Core::Http::HttpStatusCode::Ok)
Expand Down Expand Up @@ -2981,6 +2996,7 @@ namespace Azure { namespace Storage { namespace Blobs {
kHasVersionsOnly,
kContentLength,
kBlobType,
kDeletionId,
kBlobPrefix,
};
const std::unordered_map<std::string, XmlTagEnum> XmlTagEnumMap{
Expand Down Expand Up @@ -3043,6 +3059,7 @@ namespace Azure { namespace Storage { namespace Blobs {
{"HasVersionsOnly", XmlTagEnum::kHasVersionsOnly},
{"Content-Length", XmlTagEnum::kContentLength},
{"BlobType", XmlTagEnum::kBlobType},
{"DeletionId", XmlTagEnum::kDeletionId},
{"BlobPrefix", XmlTagEnum::kBlobPrefix},
};
std::vector<XmlTagEnum> xmlPath;
Expand Down Expand Up @@ -3488,6 +3505,13 @@ namespace Azure { namespace Storage { namespace Blobs {
{
vectorElement1.BlobType = Models::BlobType(node.Value);
}
else if (
xmlPath.size() == 4 && xmlPath[0] == XmlTagEnum::kEnumerationResults
&& xmlPath[1] == XmlTagEnum::kBlobs && xmlPath[2] == XmlTagEnum::kBlob
&& xmlPath[3] == XmlTagEnum::kDeletionId)
{
vectorElement1.DeletionId = node.Value;
}
else if (
xmlPath.size() == 4 && xmlPath[0] == XmlTagEnum::kEnumerationResults
&& xmlPath[1] == XmlTagEnum::kBlobs && xmlPath[2] == XmlTagEnum::kBlobPrefix
Expand Down
26 changes: 26 additions & 0 deletions sdk/storage/azure-storage-blobs/swagger/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,15 @@ directive:
{"value": "legalhold", "name": "LegalHold"},
{"value": "deletedwithversions", "name": "DeletedWithVersions"}
];
$["ListBlobsShowOnly"]= {
"name": "showonly",
"x-ms-client-name": "ShowOnly",
"in": "query",
"required": false,
"type": "string",
"x-ms-parameter-location": "method",
"description": "Include this parameter to specify one or more datasets to include in the response."
};
$.DeleteSnapshots["x-ms-enum"]["name"] = "DeleteSnapshotsOption";
$.DeleteSnapshots["x-ms-enum"]["values"] = [{"value": "include", "name": "IncludeSnapshots"},{"value":"only", "name": "OnlySnapshots"}];
$.BlobExpiryOptions["x-ms-enum"]["name"] = "ScheduleBlobExpiryOriginType";
Expand Down Expand Up @@ -303,6 +312,17 @@ directive:
"x-ms-export": true,
"description": "The algorithm used to produce the encryption key hash. Currently, the only accepted value is \"AES256\". Must be provided if the x-ms-encryption-key header is provided."
};
$.ListBlobsShowOnly = {
"type": "string",
"enum": ["deleted"],
"x-ms-enum": {
"name": "ListBlobsShowOnlyType",
"modelAsString": false,
"values": [{"value": "__placeHolder", "name": "__placeHolder"}, {"value": "deleted", "name": "Deleted"}]
},
"x-ms-export": true,
"description": "Include this parameter to specify one or more datasets to include in the response."
};
$.BlockType = {
"type": "string",
"enum": ["Committed", "Uncommitted", "Latest"],
Expand Down Expand Up @@ -829,6 +849,7 @@ directive:
$.BlobItemInternal.properties["BlobType"] = $.BlobPropertiesInternal.properties["BlobType"];
$.BlobItemInternal.properties["BlobType"]["x-ms-xml"] = {"name": "Properties/BlobType"};
delete $.BlobPropertiesInternal.properties["BlobType"];
$.BlobItemInternal.properties["DeletionId"] = {"type": "string"};
$.BlobItemInternal.required.push("BlobType", "BlobSize");
$.BlobItemInternal.properties["Name"].description = "Blob name.";
$.BlobItemInternal.properties["Deleted"].description = "Indicates whether this blob was deleted.";
Expand All @@ -837,6 +858,7 @@ directive:
$.BlobItemInternal.properties["IsCurrentVersion"].description = "Indicates if this is the current version of the blob.";
$.BlobItemInternal.properties["BlobType"].description = "Type of the blob.";
$.BlobItemInternal.properties["HasVersionsOnly"].description = "Indicates that this root blob has been deleted, but it has versions that are active.";
$.BlobItemInternal.properties["DeletionId"].description = "The deletion ID associated with the deleted path.";

$.BlobPropertiesInternal.properties["Etag"]["x-ms-client-name"] = "ETag";
$.BlobPropertiesInternal["x-ms-client-name"] = "BlobItemDetails";
Expand Down Expand Up @@ -916,6 +938,10 @@ directive:
delete $.ListBlobsHierarchySegmentResponse.properties["Segment"];
delete $.ListBlobsHierarchySegmentResponse.required;
$.ListBlobsHierarchySegmentResponse.properties["NextMarker"]["x-nullable"] = true;
- from: swagger-document
where: $["x-ms-paths"]["/{containerName}?restype=container&comp=list&hierarchy"].get.parameters
transform: >
$.push({"$ref": "#/parameters/ListBlobsShowOnly"});
```

### DownloadBlob
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,31 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
const RenameDirectoryOptions& options = RenameDirectoryOptions(),
const Azure::Core::Context& context = Azure::Core::Context()) const;

/**
* @brief Gets the paths that have recently been soft deleted in this file system.
* @param options Optional parameters to list deleted paths.
* @param context Context for cancelling long running operations.
* @return Azure::Response<DataLakePathClient> The client targets the restored path.
* @remark This request is sent to Blob endpoint.
*/
ListDeletedPathsPagedResponse ListDeletedPaths(
const ListDeletedPathsOptions& options = ListDeletedPathsOptions(),
const Azure::Core::Context& context = Azure::Core::Context()) const;

/**
* @brief Restores a soft deleted path.
* @param deletedPath The path of the deleted path.
* @param deletionId The deletion ID associated with the soft deleted path. You can get soft
* deleted paths and their assocaited deletion IDs with ListDeletedPaths.
* @param context Context for cancelling long running operations.
* @return Azure::Response<DataLakePathClient> The client targets the restored path.
* @remark This request is sent to Blob endpoint.
*/
Azure::Response<DataLakePathClient> Undelete(
microzchang marked this conversation as resolved.
Show resolved Hide resolved
const std::string& deletedPath,
const std::string& deletionId,
microzchang marked this conversation as resolved.
Show resolved Hide resolved
const Azure::Core::Context& context = Azure::Core::Context()) const;

private:
Azure::Core::Url m_fileSystemUrl;
Blobs::BlobContainerClient m_blobContainerClient;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,31 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
Azure::Nullable<int32_t> PageSizeHint;
};

/**
* @brief Optional parameters for #Azure::Storage::Files::DataLake::FileSystemClient::ListPaths.
*/
struct ListDeletedPathsOptions final
{
/**
* Gets the paths that have recently been soft deleted in this file system.
*/
Azure::Nullable<std::string> PathPrefix;
microzchang marked this conversation as resolved.
Show resolved Hide resolved

/**
* The number of paths returned with each invocation is limited. If the number of paths to be
* returned exceeds this limit, a continuation token is returned in the response header
* x-ms-continuation. When a continuation token is returned in the response, it must be
* specified in a subsequent invocation of the list operation to continue listing the paths.
*/
Azure::Nullable<std::string> ContinuationToken;

/**
* An optional value that specifies the maximum number of items to return. If omitted or greater
* than 5,000, the response will include up to 5,000 items.
*/
Azure::Nullable<int32_t> PageSizeHint;
};

/**
* @brief Optional parameters for
* #Azure::Storage::Files::DataLake::FileSystemClient::GetAccessPolicy.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,32 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {

using SetPathPermissionsResult = SetPathAccessControlListResult;

/**
* @brief A path that has been soft deleted.
*/
struct PathDeletedItem final
{
/**
* The name of the path.
*/
std::string Name;

/**
* The deletion ID associated with the deleted path.
*/
Azure::Nullable<std::string> DeletionId;
microzchang marked this conversation as resolved.
Show resolved Hide resolved

/**
* When the path was deleted.
*/
Azure::Nullable<DateTime> DeletedOn;

/**
* The number of days left before the soft deleted path will be permanently deleted.
*/
Azure::Nullable<int64_t> RemainingRetentionDays;
};

// FileClient models:

using UploadFileFromResult = Blobs::Models::UploadBlockBlobResult;
Expand Down Expand Up @@ -712,6 +738,28 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
friend class Azure::Core::PagedResponse<ListPathsPagedResponse>;
};

/**
* @brief Response type for
* #Azure::Storage::Files::DataLake::DataLakeFileSystemClient::ListDeletedPaths.
*/
class ListDeletedPathsPagedResponse final
: public Azure::Core::PagedResponse<ListDeletedPathsPagedResponse> {
public:
/**
* Path items.
*/
std::vector<Models::PathDeletedItem> DeletedPaths;

private:
void OnNextPage(const Azure::Core::Context& context);

std::shared_ptr<DataLakeFileSystemClient> m_fileSystemClient;
ListDeletedPathsOptions m_operationOptions;

friend class DataLakeFileSystemClient;
friend class Azure::Core::PagedResponse<ListDeletedPathsPagedResponse>;
};

/**
* @brief Response type for
* #Azure::Storage::Files::DataLake::DataLakePathClient::SetAccessControlListRecursive.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -425,4 +425,71 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake {
std::move(renamedDirectoryClient), std::move(result.RawResponse));
}

ListDeletedPathsPagedResponse DataLakeFileSystemClient::ListDeletedPaths(
const ListDeletedPathsOptions& options,
const Azure::Core::Context& context) const
{
Blobs::_detail::BlobContainerClient::ListBlobContainerBlobsByHierarchyOptions
protocolLayerOptions;
protocolLayerOptions.Prefix = options.PathPrefix;
protocolLayerOptions.MaxResults = options.PageSizeHint;
protocolLayerOptions.Marker = options.ContinuationToken;
protocolLayerOptions.ShowOnly = Blobs::Models::ListBlobsShowOnlyType::Deleted.ToString();
auto result = Blobs::_detail::BlobContainerClient::ListBlobsByHierarchy(
*m_pipeline, m_blobContainerClient.m_blobContainerUrl, protocolLayerOptions, context);

ListDeletedPathsPagedResponse pagedResponse;
for (auto& item : result.Value.Items)
{
Models::PathDeletedItem pathDeletedItem;
if (item.Name.Encoded)
{
pathDeletedItem.Name = Core::Url::Decode(item.Name.Content);
}
else
{
pathDeletedItem.Name = std::move(item.Name.Content);
}
pathDeletedItem.DeletedOn = item.Details.DeletedOn;
pathDeletedItem.DeletionId = item.DeletionId;
pathDeletedItem.RemainingRetentionDays = item.Details.RemainingRetentionDays.Value();

pagedResponse.DeletedPaths.push_back(pathDeletedItem);
microzchang marked this conversation as resolved.
Show resolved Hide resolved
}
pagedResponse.m_operationOptions = options;
pagedResponse.m_fileSystemClient = std::make_shared<DataLakeFileSystemClient>(*this);
pagedResponse.CurrentPageToken = options.ContinuationToken.ValueOr(std::string());
pagedResponse.NextPageToken = result.Value.ContinuationToken;
pagedResponse.RawResponse = std::move(result.RawResponse);

return pagedResponse;
}

Azure::Response<DataLakePathClient> DataLakeFileSystemClient::Undelete(
const std::string& deletedPath,
const std::string& deletionId,
const Azure::Core::Context& context) const
{
std::string undeleteSource = std::string("?") + _detail::DataLakeDeletionId + "=" + deletionId;

auto blobUrl = m_blobContainerClient.m_blobContainerUrl;
blobUrl.AppendPath(_internal::UrlEncodePath(deletedPath));

_detail::PathClient::UndeletePathOptions options;
options.UndeleteSource = undeleteSource;
microzchang marked this conversation as resolved.
Show resolved Hide resolved
auto result = _detail::PathClient::Undelete(*m_pipeline, blobUrl, options, context);

if (result.Value.ResourceType.HasValue()
&& result.Value.ResourceType.Value() == Models::PathResourceType::Directory.ToString())
{
return Azure::Response<DataLakePathClient>(
std::move(GetDirectoryClient(deletedPath)), std::move(result.RawResponse));
}
else
{
return Azure::Response<DataLakePathClient>(
std::move(GetFileClient(deletedPath)), std::move(result.RawResponse));
}
}

}}}} // namespace Azure::Storage::Files::DataLake
Loading