Added convenience layer for datalake service (#178)

This commit is contained in:
Kan Tang 2020-06-21 10:55:41 +08:00 committed by GitHub
parent 90e57362bf
commit a8a200ef26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 8275 additions and 3058 deletions

View File

@ -1,7 +1,7 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# SPDX-License-Identifier: MIT
cmake_minimum_required (VERSION 3.12)
cmake_minimum_required (VERSION 3.15)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake-modules")
# Compile Options

View File

@ -10,7 +10,7 @@ To get started with a specific library, see the **README.md** file located in th
### Prerequisites
> CMake version 3.12 is required to build these libraries
> CMake version 3.15 is required to build these libraries
## Latest Release

View File

@ -1,7 +1,7 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# SPDX-License-Identifier: MIT
cmake_minimum_required (VERSION 3.12)
cmake_minimum_required (VERSION 3.15)
project (azure-storage LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 14)
@ -30,8 +30,23 @@ set (AZURE_STORAGE_BLOB_HEADER
)
set (AZURE_STORAGE_DATALAKE_HEADER
external/json.hpp
inc/common/storage_common.hpp
inc/common/xml_wrapper.hpp
inc/common/storage_error.hpp
inc/common/storage_credential.hpp
inc/common/storage_url_builder.hpp
inc/common/common_headers_request_policy.hpp
inc/common/shared_key_policy.hpp
inc/common/token_credential_policy.hpp
inc/common/crypt.hpp
inc/common/constant.hpp
inc/blobs/internal/protocol/blob_rest_client.hpp
inc/datalake/protocol/datalake_rest_client.hpp
inc/datalake/datalake_options.hpp
inc/datalake/datalake_utilities.hpp
inc/datalake/service_client.hpp
inc/datalake/file_system_client.hpp
inc/datalake/path_client.hpp
)
set (AZURE_STORAGE_BLOB_SOURCE
@ -39,6 +54,7 @@ set (AZURE_STORAGE_BLOB_SOURCE
src/common/storage_url_builder.cpp
src/common/common_headers_request_policy.cpp
src/common/shared_key_policy.cpp
src/common/storage_error.cpp
src/common/crypt.cpp
src/common/xml_wrapper.cpp
src/blobs/blob_service_client.cpp
@ -50,6 +66,11 @@ set (AZURE_STORAGE_BLOB_SOURCE
)
set (AZURE_STORAGE_DATALAKE_SOURCE
src/common/storage_credential.cpp
src/datalake/service_client.cpp
src/datalake/file_system_client.cpp
src/datalake/path_client.cpp
src/datalake/datalake_utilities.cpp
)
set(AZURE_STORAGE_HEADER
@ -66,13 +87,15 @@ add_library(azure-storage ${AZURE_STORAGE_HEADER} ${AZURE_STORAGE_SOURCE})
find_package(LibXml2 REQUIRED)
target_include_directories(azure-storage PUBLIC ${LIBXML2_INCLUDE_DIR} $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc> $<INSTALL_INTERFACE:include/azure_storage>)
target_include_directories(azure-storage PUBLIC ${LIBXML2_INCLUDE_DIR} $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/external> $<INSTALL_INTERFACE:include/azure_storage>)
target_link_libraries(azure-storage azure-core ${LIBXML2_LIBRARIES})
if(MSVC)
target_link_libraries(azure-storage bcrypt)
target_compile_definitions(azure-storage PRIVATE NOMINMAX)
# C28020 and C28204 are introduced by nlohmann/json
target_compile_options(azure-storage PUBLIC /wd28204 /wd28020)
else()
find_package(OpenSSL REQUIRED)
target_link_libraries(azure-storage OpenSSL::SSL OpenSSL::Crypto)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#pragma once
namespace Azure { namespace Storage { namespace Details {
constexpr static const char* c_ConnectionStringTagAccountName = "AccountName";
constexpr static const char* c_ConnectionStringTagAccountKey = "AccountKey";
constexpr static const char* c_ConnectionStringTagBlobEndpoint = "BlobEndpoint";
constexpr static const char* c_ConnectionStringTagDataLakeEndpoint = "AdlsEndpoint";
constexpr static const char* c_ConnectionStringTagEndpointSuffix = "EndpointSuffix";
constexpr static const char* c_ConnectionStringTagDefaultEndpointsProtocol
= "DefaultEndpointsProtocol";
constexpr static const char* c_DfsEndpointIdentifier = "dfs";
}}} // namespace Azure::Storage::Details

View File

@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#pragma once
#include "context.hpp"
namespace Azure { namespace Storage {
struct SharedRequestOptions
{
/**
* @brief An optional operation timeout value in seconds. The period begins
* when the request is received by the service. If the timeout value
* elapses before the operation completes, the operation fails.
*/
int32_t Timeout = 0; // TODO: This is going to be changed into Nullable.
/**
* @brief Context for cancelling long running operations.
*/
Azure::Core::Context Context;
};
}} // namespace Azure::Storage

View File

@ -9,6 +9,8 @@
namespace Azure { namespace Storage {
class TokenCredentialPolicy;
struct TokenCredential
{
explicit TokenCredential(std::string token) : Token(std::move(token)) {}
@ -25,6 +27,7 @@ namespace Azure { namespace Storage {
std::lock_guard<std::mutex> guard(Mutex);
return Token;
}
friend class TokenCredentialPolicy;
std::mutex Mutex;
std::string Token;
};

View File

@ -0,0 +1,38 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#pragma once
#include <map>
#include <stdexcept>
#include <string>
namespace Azure { namespace Core { namespace Http {
class Response;
}}} // namespace Azure::Core::Http
namespace Azure { namespace Storage {
struct StorageError : public std::runtime_error
{
explicit StorageError(const std::string& message)
: std::runtime_error(message), StatusCode(), RequestId()
{
}
explicit StorageError(const std::string& message, std::string errorCode)
: std::runtime_error(message), StatusCode(std::move(errorCode)), RequestId()
{
}
explicit StorageError(const std::string& message, std::string errorCode, std::string requestId)
: std::runtime_error(message), StatusCode(std::move(errorCode)),
RequestId(std::move(requestId))
{
}
std::string StatusCode;
std::string RequestId;
std::map<std::string, std::string> Details;
static StorageError CreateFromResponse(/* const */ Azure::Core::Http::Response& response);
};
}} // namespace Azure::Storage

View File

@ -57,7 +57,7 @@ namespace Azure { namespace Storage {
}
void RemoveQuery(const std::string& key) { m_query.erase(key); }
const std::map<std::string, std::string>& GetQuery() const { return m_query; }
void SetFragment(const std::string& fragment, bool do_encoding = false)
@ -67,6 +67,8 @@ namespace Azure { namespace Storage {
std::string to_string() const;
std::string GetHost() const { return m_host; }
private:
static std::string EncodeHost(const std::string& host);
static std::string EncodePath(const std::string& path);

View File

@ -0,0 +1,35 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#pragma once
#include "common/storage_credential.hpp"
#include "http/policy.hpp"
namespace Azure { namespace Storage {
class TokenCredentialPolicy : public Core::Http::HttpPolicy {
public:
explicit TokenCredentialPolicy(std::shared_ptr<TokenCredential> credential)
: m_credential(std::move(credential))
{
}
~TokenCredentialPolicy() override {}
HttpPolicy* Clone() const override { return new TokenCredentialPolicy(m_credential); }
std::unique_ptr<Core::Http::Response> Send(
Core::Context& ctx,
Core::Http::Request& request,
Core::Http::NextHttpPolicy nextHttpPolicy) const override
{
request.AddHeader("Authorization", "Bearer " + m_credential->GetToken());
return nextHttpPolicy.Send(ctx, request);
}
private:
std::shared_ptr<TokenCredential> m_credential;
};
}} // namespace Azure::Storage

View File

@ -0,0 +1,9 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#pragma once
#include "datalake/datalake_utilities.hpp"
#include "datalake/file_system_client.hpp"
#include "datalake/path_client.hpp"
#include "datalake/service_client.hpp"

View File

@ -0,0 +1,943 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#pragma once
#include "common/shared_request_options.hpp"
#include "protocol/datalake_rest_client.hpp"
#include <memory>
#include <string>
namespace Azure { namespace Storage { namespace DataLake {
/**
* @brief Service client options used to initalize DataLakeServiceClient.
*/
struct ServiceClientOptions
{
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
};
/**
* @brief File system client options used to initalize DataLakeFileSystemClient.
*/
struct FileSystemClientOptions
{
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
};
/**
* @brief Path client options used to initalize DataLakePathClient.
*/
struct PathClientOptions
{
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
};
/**
* @brief Optional parameters for DataLakeServiceClient::ListFilesSystems
*/
struct ListFileSystemsOptions : public SharedRequestOptions
{
/**
* @brief Filters results to filesystems within the specified prefix.
*/
std::string Prefix;
/**
* @brief The number of filesystems returned with each invocation is
* limited. If the number of filesystems 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 filesystems.
*/
std::string Continuation;
/**
* @brief 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.
*/
int32_t MaxResults = 0;
};
/**
* @brief Optional parameters for DataLakeFileSystemClient::Create
*/
struct FileSystemCreateOptions : public SharedRequestOptions
{
/**
* @brief User-defined metadata to be stored with the filesystem.
* Note that the string may only contain ASCII characters in the
* ISO-8859-1 character set.
*/
std::map<std::string, std::string> Metadata;
};
/**
* @brief Optional parameters for DataLakeFileSystemClient::Delete
*/
struct FileSystemDeleteOptions : public SharedRequestOptions
{
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the resource has been modified since the
( specified date and time.
*/
std::string IfModifiedSince;
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the resource has not been modified since
* the specified date and time.
*/
std::string IfUnmodifiedSince;
};
/**
* @brief Optional parameters for DataLakeFileSystemClient::GetMetadata
*/
struct FileSystemGetMetadataOptions : public SharedRequestOptions
{
};
/**
* @brief Optional parameters for DataLakeFileSystemClient::SetMetadata
*/
struct FileSystemSetMetadataOptions : public SharedRequestOptions
{
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the resource has been modified since the
( specified date and time.
*/
std::string IfModifiedSince;
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the resource has not been modified since
* the specified date and time.
*/
std::string IfUnmodifiedSince;
};
/**
* @brief Optional parameters for DataLakeFileSystemClient::ListPaths
*/
struct ListPathsOptions : public SharedRequestOptions
{
/**
* @brief Valid only when Hierarchical Namespace is enabled for the account.
* If "true", the user identity values returned in the owner and group
* fields of each list entry will be transformed from Azure Active Directory
* Object IDs to User Principal Names. If "false", the values will be
* returned as Azure Active Directory Object IDs. The default value is false.
* Note that group and application Object IDs are not translated because they
* do not have unique friendly names.
*/
bool Upn = bool();
/**
* @brief 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.
*/
std::string Continuation;
/**
* @brief 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.
*/
int32_t MaxResults = 0;
/**
* @brief Filters results to paths within the specified directory. An error occurs
* if the directory does not exist.
*/
std::string Directory;
};
/**
* @brief Optional parameters for DataLakePathClient::AppendData
*/
struct PathAppendDataOptions : public SharedRequestOptions
{
/**
* @brief Specify the transactional md5 for the body, to be validated by the service.
*/
std::string ContentMD5;
/**
* @brief The lease ID must be specified if there is an active lease.
*/
std::string LeaseId;
};
/**
* @brief Optional parameters for DataLakePathClient::FlushData
*/
struct PathFlushDataOptions : public SharedRequestOptions
{
/**
* @brief If "true", uncommitted data is retained after the flush operation completes;
* otherwise, the uncommitted data is deleted after the flush operation. The
* default is false. Data at offsets less than the specified position are
* written to the file when flush succeeds, but this optional parameter allows
* data after the flush position to be retained for a future flush operation.
*/
bool RetainUncommittedData = bool();
/**
* @brief Azure Storage Events allow applications to receive notifications when files
* change. When Azure Storage Events are enabled, a file changed event is raised.
* This event has a property indicating whether this is the final change to distinguish
* the difference between an intermediate flush to a file stream and the final close of
* a file stream. The close query parameter is valid only when the action is "flush"
* and change notifications are enabled. If the value of close is "true" and the
* flush operation completes successfully, the service raises a file change notification
* with a property indicating that this is the final update (the file stream has been
* closed). If "false" a change notification is raised indicating the file has changed.
* The default is false. This query parameter is set to true by the Hadoop ABFS driver to
* indicate that the file stream has been closed."
*/
bool Close = bool();
/**
* @brief The service stores this value and includes it in the "Content-Md5" response header for
* "Read & Get Properties" operations. If this property is not specified on the request,
* then the property will be cleared for the file. Subsequent calls to "Read & Get
* Properties" will not return this property unless it is explicitly set on that file
* again.
*/
std::string ContentMD5;
/**
* @brief The lease ID must be specified if there is an active lease.
*/
std::string LeaseId;
/**
* @brief Sets the path's cache control. If specified, this property is stored with the
* path and returned with a read request.
*/
std::string CacheControl;
/**
* @brief Sets the path's content type. If specified, this property is stored
* with the path and returned with a read request.
*/
std::string ContentType;
/**
* @brief Sets the path's Content-Disposition header.
*/
std::string ContentDisposition;
/**
* @brief Sets the path's content encoding. If specified, this property is stored with
* the path and returned with a read request.
*/
std::string ContentEncoding;
/**
* @brief Set the path's content language. If specified, this property is stored with
* the path and returned with a read request.
*/
std::string ContentLanguage;
/**
* @brief Specify an ETag value to operate only on path with a matching value.
*/
std::string IfMatch;
/**
* @brief Specify an ETag value to operate only on path without a matching value.
*/
std::string IfNoneMatch;
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the resource has been modified since the
( specified date and time.
*/
std::string IfModifiedSince;
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the resource has not been modified since
* the specified date and time.
*/
std::string IfUnmodifiedSince;
};
/**
* @brief Optional parameters for DataLakePathClient::SetAccessControl
*/
struct SetAccessControlOptions : public SharedRequestOptions
{
/**
* @brief The lease ID must be specified if there is an active lease.
*/
std::string LeaseId;
/**
* @brief The owner of the path or directory.
*/
std::string Owner;
/**
* @brief The owning group of the path or directory.
*/
std::string Group;
/**
* @brief only valid if Hierarchical Namespace is enabled for the account. Sets POSIX
* access permissions for the file owner, the file owning group, and others.
* Each class may be granted read, write, or execute permission.
* The sticky bit is also supported. Both symbolic (rwxrw-rw-) and 4-digit octal
* notation (e.g. 0766) are supported.
*/
std::string Permissions;
/**
* @brief Sets POSIX access control rights on files and directories. The value is a
* comma-separated list of access control entries. Each access control entry (ACE)
* consists of a scope, a type, a user or group identifier, and permissions in the
* format "[scope:][type]:[id]:[permissions]".
*/
std::string Acl;
/**
* @brief Specify an ETag value to operate only on path with a matching value.
*/
std::string IfMatch;
/**
* @brief Specify an ETag value to operate only on path without a matching value.
*/
std::string IfNoneMatch;
/**
* @brief Specify this header value to operate only on a path if it has been modified
* since the specified date/time.
*/
std::string IfModifiedSince;
/**
* @brief Specify this header value to operate only on a path if it has not been modified
* since the specified date/time.
*/
std::string IfUnmodifiedSince;
};
/**
* @brief Optional parameters for DataLakePathClient::SetAccessControlRecursive
*/
struct SetAccessControlRecursiveOptions : public SharedRequestOptions
{
/**
* @brief When performing setAccessControlRecursive on a directory, the number of paths that
* are processed with each invocation is limited. If the number of paths to be processed
* exceeds this limit, a continuation token is returned in this response header. When a
* continuation token is returned in the response, it must be specified in a subsequent
* invocation of the setAccessControlRecursive operation to continue the
* setAccessControlRecursive operation on the directory.
*/
std::string Continuation;
/**
* @brief It specifies the maximum number of files or directories on which the acl change will
* be applied. If omitted or greater than 2,000, the request will process up to 2,000
* items.
*/
int32_t MaxRecords = int32_t();
/**
* @brief Sets POSIX access control rights on files and directories. The value is a
* comma-separated list of access control entries. Each access control entry (ACE)
* consists of a scope, a type, a user or group identifier, and permissions in the format
* "[scope:][type]:[id]:[permissions]".
*/
std::string Acl;
};
/**
* @brief Optional parameters for DataLakePathClient::SetProperties
*/
struct SetPathPropertiesOptions : public SharedRequestOptions
{
/**
* @brief User-defined metadata to be stored with the filesystem.
* Note that the string may only contain ASCII characters in the
* ISO-8859-1 character set.
*/
std::map<std::string, std::string> Metadata;
/**
* @brief Sets the path's cache control. If specified, this property is stored with the
* path and returned with a read request.
*/
std::string CacheControl;
/**
* @brief Sets the path's content type. If specified, this property is stored
* with the path and returned with a read request.
*/
std::string ContentType;
/**
* @brief Sets the path's Content-Disposition header.
*/
std::string ContentDisposition;
/**
* @brief Sets the path's content encoding. If specified, this property is stored with
* the path and returned with a read request.
*/
std::string ContentEncoding;
/**
* @brief Set the path's content language. If specified, this property is stored with
* the path and returned with a read request.
*/
std::string ContentLanguage;
/**
* @brief Specify an ETag value to operate only on path with a matching value.
*/
std::string IfMatch;
/**
* @brief Specify an ETag value to operate only on path without a matching value.
*/
std::string IfNoneMatch;
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the resource has been modified since the
( specified date and time.
*/
std::string IfModifiedSince;
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the resource has not been modified since
* the specified date and time.
*/
std::string IfUnmodifiedSince;
};
/**
* @brief Optional parameters for DataLakePathClient::Create
* @remark Some optional parameter is mandatory in certain combination.
* More details:
* https://docs.microsoft.com/en-us/rest/api/storageservices/datalakestoragegen2/path/create
*/
struct PathCreateOptions : public SharedRequestOptions
{
/**
* @brief Required only for Create File and Create Directory. The value must be
* PathResourceType::File or PathResourceType::Directory.
*/
PathResourceType Resource = PathResourceType::Unknown;
/**
* @brief Sets the path's cache control. If specified, this property is stored with the
* path and returned with a read request.
*/
std::string CacheControl;
/**
* @brief Sets the path's content type. If specified, this property is stored
* with the path and returned with a read request.
*/
std::string ContentType;
/**
* @brief Sets the path's Content-Disposition header.
*/
std::string ContentDisposition;
/**
* @brief Sets the path's content encoding. If specified, this property is stored with
* the path and returned with a read request.
*/
std::string ContentEncoding;
/**
* @brief Set the path's content language. If specified, this property is stored with
* the path and returned with a read request.
*/
std::string ContentLanguage;
/**
* @brief If specified, the operation only succeeds if the resource's lease is active and
* matches this ID.
*/
std::string LeaseId;
/**
* @brief Specify an ETag value to operate only on path with a matching value.
*/
std::string IfMatch;
/**
* @brief Specify an ETag value to operate only on path without a matching value.
*/
std::string IfNoneMatch;
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the resource has been modified since the
( specified date and time.
*/
std::string IfModifiedSince;
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the resource has not been modified since
* the specified date and time.
*/
std::string IfUnmodifiedSince;
/**
* @brief User-defined metadata to be stored with the path. Note that the string may only
* contain ASCII characters in the ISO-8859-1 character set. If the filesystem exists,
* any metadata not included in the list will be removed. All metadata are removed
* if the header is omitted. To merge new and existing metadata, first get all
* existing metadata and the current E-Tag, then make a conditional request with the
* E-Tag and include values for all metadata.
*/
std::map<std::string, std::string> Metadata;
/**
* @brief Only valid if Hierarchical Namespace is enabled for the account. When creating
* a file or directory and the parent folder does not have a default ACL, the umask
* restricts the permissions of the file or directory to be created. The resulting
* permission is given by p bitwise and not u, where p is the permission and u is
* the umask. For example, if p is 0777 and u is 0057, then the resulting permission
* is 0720. The default permission is 0777 for a directory and 0666 for a file.
* The default umask is 0027. The umask must be specified in 4-digit octal
* notation (e.g. 0766).
*/
std::string Umask;
/**
* @brief only valid if Hierarchical Namespace is enabled for the account. Sets POSIX
* access permissions for the file owner, the file owning group, and others.
* Each class may be granted read, write, or execute permission.
* The sticky bit is also supported. Both symbolic (rwxrw-rw-) and 4-digit octal
* notation (e.g. 0766) are supported.
*/
std::string Permissions;
};
/**
* @brief Optional parameters for DataLakePathClient::Create
* @remark Some optional parameter is mandatory in certain combination.
* More details:
* https://docs.microsoft.com/en-us/rest/api/storageservices/datalakestoragegen2/path/create
*/
struct PathRenameOptions : public SharedRequestOptions
{
/**
* @brief Required only for Create File and Create Directory. The value must be
* PathResourceType::File or PathResourceType::Directory.
*/
PathResourceType Resource = PathResourceType::Unknown;
/**
* @brief When renaming a directory, the number of paths that are renamed with each
* invocation is limited. If the number of paths to be renamed exceeds this limit,
* a continuation token is returned in this response header. When a continuation token
* is returned in the response, it must be specified in a subsequent invocation of the
* rename operation to continue renaming the directory.
*/
std::string Continuation;
/**
* @brief Valid only when namespace is enabled. This parameter determines the behavior of the
* rename operation. The value must be PathRenameMode::Legacy or PathRenameMode::Posix,
* and the default value will be PathRenameMode::Posix.
*/
PathRenameMode Mode = PathRenameMode::Posix;
/**
* @brief Sets the path's cache control. If specified, this property is stored with the
* path and returned with a read request.
*/
std::string CacheControl;
/**
* @brief Sets the path's content type. If specified, this property is stored
* with the path and returned with a read request.
*/
std::string ContentType;
/**
* @brief Sets the path's Content-Disposition header.
*/
std::string ContentDisposition;
/**
* @brief Sets the path's content encoding. If specified, this property is stored with
* the path and returned with a read request.
*/
std::string ContentEncoding;
/**
* @brief Set the path's content language. If specified, this property is stored with
* the path and returned with a read request.
*/
std::string ContentLanguage;
/**
* @brief If specified, the operation only succeeds if the resource's lease is active and
* matches this ID.
*/
std::string LeaseId;
/**
* @brief An optional file or directory to be renamed. The value must have the following
* format: "/{filesystem}/{path}". If Properties is specified, the properties
* will overwrite the existing properties; otherwise, the existing properties will
* be preserved. This value must be a URL percent-encoded string. Note that the string
* may only contain ASCII characters in the ISO-8859-1 character set.
*/
std::string RenameSource;
/**
* @brief A lease ID for the source path. If specified, the source path must have an active
* lease and the leaase ID must match.
*/
std::string SourceLeaseId;
/**
* @brief Specify an ETag value to operate only on path with a matching value.
*/
std::string IfMatch;
/**
* @brief Specify an ETag value to operate only on path without a matching value.
*/
std::string IfNoneMatch;
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the resource has been modified since the
( specified date and time.
*/
std::string IfModifiedSince;
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the resource has not been modified since
* the specified date and time.
*/
std::string IfUnmodifiedSince;
/**
* @brief User-defined metadata to be stored with the path. Note that the string may only
* contain ASCII characters in the ISO-8859-1 character set. If the filesystem exists,
* any metadata not included in the list will be removed. All metadata are removed
* if the header is omitted. To merge new and existing metadata, first get all
* existing metadata and the current E-Tag, then make a conditional request with the
* E-Tag and include values for all metadata.
*/
std::map<std::string, std::string> Metadata;
/**
* @brief Only valid if Hierarchical Namespace is enabled for the account. When creating
* a file or directory and the parent folder does not have a default ACL, the umask
* restricts the permissions of the file or directory to be created. The resulting
* permission is given by p bitwise and not u, where p is the permission and u is
* the umask. For example, if p is 0777 and u is 0057, then the resulting permission
* is 0720. The default permission is 0777 for a directory and 0666 for a file.
* The default umask is 0027. The umask must be specified in 4-digit octal
* notation (e.g. 0766).
*/
std::string Umask;
/**
* @brief only valid if Hierarchical Namespace is enabled for the account. Sets POSIX
* access permissions for the file owner, the file owning group, and others.
* Each class may be granted read, write, or execute permission.
* The sticky bit is also supported. Both symbolic (rwxrw-rw-) and 4-digit octal
* notation (e.g. 0766) are supported.
*/
std::string Permissions;
/**
* @brief Specify an ETag value to operate only on source path with a matching value.
*/
std::string SourceIfMatch;
/**
* @brief Specify an ETag value to operate only on source path without a matching value.
*/
std::string SourceIfNoneMatch;
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the source resource has been modified since the
( specified date and time.
*/
std::string SourceIfModifiedSince;
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the source resource has not been modified since
* the specified date and time.
*/
std::string SourceIfUnmodifiedSince;
};
/**
* @brief Optional parameters for DataLakePathClient::Delete
* @remark Some optional parameter is mandatory in certain combination.
* More details:
* https://docs.microsoft.com/en-us/rest/api/storageservices/datalakestoragegen2/path/delete
*/
struct PathDeleteOptions : public SharedRequestOptions
{
/**
* @brief When deleting a directory, the number of paths that are deleted with each invocation
* is limited. If the number of paths to be deleted exceeds this limit, a continuation
* token is returned in this response header. When a continuation token is returned in
* the response, it must be specified in a subsequent invocation of the delete operation
* to continue deleting the directory.
*/
std::string Continuation;
/**
* @brief Required and valid only when the resource is a directory. If "true", all paths beneath
* the directory will be deleted. If "false" and the directory is non-empty, an error
* occurs.
*/
bool RecursiveOptional = bool();
/**
* @brief If specified, the operation only succeeds if the resource's lease is active and
* matches this ID.
*/
std::string LeaseId;
/**
* @brief Specify an ETag value to operate only on path with a matching value.
*/
std::string IfMatch;
/**
* @brief Specify an ETag value to operate only on path without a matching value.
*/
std::string IfNoneMatch;
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the resource has been modified since the
( specified date and time.
*/
std::string IfModifiedSince;
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the resource has not been modified since
* the specified date and time.
*/
std::string IfUnmodifiedSince;
};
/**
* @brief Optional parameters for DataLakePathClient::GetProperties
* @remark Some optional parameter is mandatory in certain combination.
* More details:
* https://docs.microsoft.com/en-us/rest/api/storageservices/datalakestoragegen2/path/getproperties
*/
struct PathGetPropertiesOptions : public SharedRequestOptions
{
/**
* @brief If the value is PathGetPropertiesAction::GetStatus only the system defined properties
* for the path are returned. If the value is PathGetPropertiesAction::GetAccessControl
* the access control list is returned in the response headers (Hierarchical Namespace
* must be enabled for the account), otherwise the properties are returned.
*/
PathGetPropertiesAction Action = PathGetPropertiesAction::Unknown;
/**
* @brief Valid only when Hierarchical Namespace is enabled for the account. If "true",
* the user identity values returned in the x-ms-owner, x-ms-group, and x-ms-acl
* response headers will be transformed from Azure Active Directory Object IDs to
* User Principal Names. If "false", the values will be returned as Azure Active
* Directory Object IDs. The default value is false. Note that group and application
* Object IDs are not translated because they do not have unique friendly names.
*/
bool UserPrincipalName = bool();
/**
* @brief If specified, the operation only succeeds if the resource's lease is active and
* matches this ID.
*/
std::string LeaseId;
/**
* @brief Specify an ETag value to operate only on path with a matching value.
*/
std::string IfMatch;
/**
* @brief Specify an ETag value to operate only on path without a matching value.
*/
std::string IfNoneMatch;
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the resource has been modified since the
( specified date and time.
*/
std::string IfModifiedSince;
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the resource has not been modified since
* the specified date and time.
*/
std::string IfUnmodifiedSince;
};
/**
* @brief Optional parameters for DataLakePathClient::Lease
* @remark Some optional parameter is mandatory in certain combination.
* More details:
* https://docs.microsoft.com/en-us/rest/api/storageservices/datalakestoragegen2/path/lease
*/
struct PathLeaseOptions : public SharedRequestOptions
{
/**
* @brief There are five lease actions: PathLeaseAction::Acquire, PathLeaseAction::Break,
* PathLeaseAction::Change, PathLeaseAction::Renew, and PathLeaseAction::Release.
* Use PathLeaseAction::Acquire and specify the ProposedLeaseId and LeaseDuration
* to acquire a new lease. Use PathLeaseAction::Break to break an existing lease.
* When a lease is broken, the lease break period is allowed to elapse, during
* which time no lease operation except break and release can be performed on the file.
* When a lease is successfully broken, the response indicates the interval in seconds
* until a new lease can be acquired. Use PathLeaseAction::Change and specify the current
* lease ID in LeaseId and the new lease ID in ProposedLeaseId to change the lease ID of
* an active lease. Use PathLeaseAction::Renew and specify the LeaseId to renew an
* existing lease. Use PathLeaseAction::Release and specify the LeaseId to release a
* lease.
*/
PathLeaseAction LeaseAction;
/**
* @brief Proposed lease ID, in a GUID string format. The DataLake service returns 400
* (Invalid request) if the proposed lease ID is not in the correct format.
* See Guid Constructor (String) for a list of valid GUID string formats.
*/
std::string ProposedLeaseId;
/**
* @brief The lease duration is required to acquire a lease, and specifies the duration
* of the lease in seconds. The lease duration must be between 15 and 60 seconds
* or -1 for infinite lease.
*/
int32_t LeaseDuration = int32_t();
/**
* @brief The lease break period duration is optional to break a lease, and specifies the
* break period of the lease in seconds. The lease break duration must be between
* 0 and 60 seconds.
*/
int32_t LeaseBreakPeriod = int32_t();
/**
* @brief If specified, the operation only succeeds if the resource's lease is active and
* matches this ID.
*/
std::string LeaseId;
/**
* @brief Specify an ETag value to operate only on path with a matching value.
*/
std::string IfMatch;
/**
* @brief Specify an ETag value to operate only on path without a matching value.
*/
std::string IfNoneMatch;
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the resource has been modified since the
( specified date and time.
*/
std::string IfModifiedSince;
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the resource has not been modified since
* the specified date and time.
*/
std::string IfUnmodifiedSince;
};
/**
* @brief Optional parameters for DataLakePathClient::Read
* @remark Some optional parameter is mandatory in certain combination.
* More details:
* https://docs.microsoft.com/en-us/rest/api/storageservices/datalakestoragegen2/path/read
*/
struct PathReadOptions : public SharedRequestOptions
{
/**
* @brief The HTTP Range request header specifies one or more byte ranges of the resource
* to be retrieved.
*/
std::string Range;
/**
* @brief When this header is set to "true" and specified together with the Range header,
* the service returns the MD5 hash for the range, as long as the range is less than
* or equal to 4MB in size. If this header is specified without the Range header,
* the service returns status code 400 (Bad Request). If this header is set to true
* when the range exceeds 4 MB in size, the service returns status code 400 (Bad
* Request).
*/
bool RangeGetContentMd5 = bool();
/**
* @brief If specified, the operation only succeeds if the resource's lease is active and
* matches this ID.
*/
std::string LeaseId;
/**
* @brief Specify an ETag value to operate only on path with a matching value.
*/
std::string IfMatch;
/**
* @brief Specify an ETag value to operate only on path without a matching value.
*/
std::string IfNoneMatch;
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the resource has been modified since the
( specified date and time.
*/
std::string IfModifiedSince;
/**
* @brief A date and time value. Specify this header to perform the
* operation only if the resource has not been modified since
* the specified date and time.
*/
std::string IfUnmodifiedSince;
};
}}} // namespace Azure::Storage::DataLake

View File

@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#pragma once
#include "common/storage_url_builder.hpp"
#include <map>
#include <string>
namespace Azure { namespace Storage { namespace DataLake {
namespace Details {
UrlBuilder GetBlobUriFromDfsUri(const UrlBuilder& dfsUri);
} // namespace Details
std::map<std::string, std::string> DeserializeMetadata(
const std::string& dataLakePropertiesString);
std::string SerializeMetadata(const std::map<std::string, std::string>& dataLakePropertiesMap);
}}} // namespace Azure::Storage::DataLake

View File

@ -0,0 +1,140 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#pragma once
#include "common/storage_credential.hpp"
#include "common/storage_url_builder.hpp"
#include "datalake/service_client.hpp"
#include "datalake_options.hpp"
#include "http/pipeline.hpp"
#include "protocol/datalake_rest_client.hpp"
#include <memory>
#include <string>
namespace Azure { namespace Storage { namespace DataLake {
class PathClient;
struct FileSystemGetMetadataResponse
{
std::string Date;
std::string ETag;
std::string LastModified;
std::string RequestId;
std::string Version;
std::map<std::string, std::string> Metadata;
bool NamespaceEnabled;
};
typedef FileSystemSetPropertiesResponse FileSystemSetMetadataResponse;
class FileSystemClient {
public:
/**
* @brief Create from connection string
* @param connectionString Azure Storage connection string.
* @param fileSystemName The name of a file system.
* @param options Optional parameters used to initialize the client.
* @return FileSystemClient
*/
static FileSystemClient CreateFromConnectionString(
const std::string& connectionString,
const std::string& fileSystemName,
const FileSystemClientOptions& options = FileSystemClientOptions());
/**
* @brief Shared key authentication client.
* @param fileSystemUri The URI of the file system 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 FileSystemClient(
const std::string& fileSystemUri,
std::shared_ptr<SharedKeyCredential> credential,
const FileSystemClientOptions& options = FileSystemClientOptions());
/**
* @brief Bearer token authentication client.
* @param fileSystemUri The URI of the file system 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 FileSystemClient(
const std::string& fileSystemUri,
std::shared_ptr<TokenCredential> credential,
const FileSystemClientOptions& options = FileSystemClientOptions());
/**
* @brief Anonymous/SAS/customized pipeline auth.
* @param fileSystemUri The URI of the file system this client's request targets.
* @param options Optional parameters used to initialize the client.
*/
explicit FileSystemClient(
const std::string& fileSystemUri,
const FileSystemClientOptions& options = FileSystemClientOptions());
/**
* @brief Create a PathClient from current FileSystemClient
* @param path Path of the resource within the file system.
* @return PathClient
*/
PathClient GetPathClient(const std::string& path) const;
/**
* @brief Creates the file system.
* @param options Optional parameters to create this file system.
* @return FileSystemCreateResponse
*/
FileSystemCreateResponse Create(
const FileSystemCreateOptions& options = FileSystemCreateOptions()) const;
/**
* @brief Deletes the file system.
* @param options Optional parameters to delete this file system.
* @return FileSystemDeleteResponse
*/
FileSystemDeleteResponse Delete(
const FileSystemDeleteOptions& options = FileSystemDeleteOptions()) const;
/**
* @brief Gets the metadata of file system.
* @param options Optional parameters to get the metadata of this file system.
* @return FileSystemGetMetadataResponse
*/
FileSystemGetMetadataResponse GetMetadata(
const FileSystemGetMetadataOptions& options = FileSystemGetMetadataOptions()) const;
/**
* @brief Sets the metadata of file system.
* @param metadata User-defined metadata to be stored with the filesystem. Note that the string
* may only contain ASCII characters in the ISO-8859-1 character set.
* @param options Optional parameters to set the metadata to this file system.
* @return FileSystemSetMetadataResponse
*/
FileSystemSetMetadataResponse SetMetadata(
const std::map<std::string, std::string>& metadata,
const FileSystemSetMetadataOptions& options = FileSystemSetMetadataOptions()) const;
/**
* @brief List the paths in this file system.
* @param recursive If "true", all paths are listed; otherwise, only paths at the root of the
* filesystem are listed. If "directory" is specified, the list will only
* include paths that share the same root.
* @param options Optional parameters to list the paths in file system.
* @return FileSystemListPathsResponse
*/
FileSystemListPathsResponse ListPaths(
bool recursive,
const ListPathsOptions& options = ListPathsOptions()) const;
private:
UrlBuilder m_dfsUri;
UrlBuilder m_blobUri;
std::shared_ptr<Azure::Core::Http::HttpPipeline> m_pipeline;
FileSystemClient() = default;
friend class ServiceClient;
};
}}} // namespace Azure::Storage::DataLake

View File

@ -0,0 +1,249 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#pragma once
#include "common/storage_credential.hpp"
#include "common/storage_url_builder.hpp"
#include "datalake/file_system_client.hpp"
#include "datalake_options.hpp"
#include "http/pipeline.hpp"
#include "protocol/datalake_rest_client.hpp"
#include <memory>
#include <string>
namespace Azure { namespace Storage { namespace DataLake {
struct ReadPathResponse
{
Azure::Core::Http::BodyStream* Body;
std::string AcceptRanges;
std::string CacheControl;
std::string ContentDisposition;
std::string ContentEncoding;
std::string ContentLanguage;
int64_t ContentLength = int64_t();
std::string ContentRange;
std::string ContentType;
std::string ContentMD5;
std::string Date;
std::string ETag;
std::string LastModified;
std::string RequestId;
std::string Version;
std::string ResourceType;
std::string LeaseDuration;
std::string LeaseState;
std::string LeaseStatus;
std::string ContentMd5;
std::map<std::string, std::string> Metadata;
};
struct GetPathPropertiesResponse
{
std::string AcceptRanges;
std::string CacheControl;
std::string ContentDisposition;
std::string ContentEncoding;
std::string ContentLanguage;
int64_t ContentLength = int64_t();
std::string ContentRange;
std::string ContentType;
std::string ContentMD5;
std::string Date;
std::string ETag;
std::string LastModified;
std::string RequestId;
std::string Version;
std::string ResourceType;
std::string Owner;
std::string Group;
std::string Permissions;
std::string ACL;
std::string LeaseDuration;
std::string LeaseState;
std::string LeaseStatus;
std::map<std::string, std::string> Metadata;
};
typedef PathCreateResponse PathRenameResponse;
class PathClient {
public:
/**
* @brief Create from connection string
* @param connectionString Azure Storage connection string.
* @param fileSystemName The name of a file system.
* @param path The path of a resource within the file system.
* @param options Optional parameters used to initialize the client.
* @return PathClient
*/
static PathClient CreateFromConnectionString(
const std::string& connectionString,
const std::string& fileSystemName,
const std::string& path,
const PathClientOptions& options = PathClientOptions());
/**
* @brief Shared key authentication client.
* @param pathUri The URI of the file system 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 PathClient(
const std::string& pathUri,
std::shared_ptr<SharedKeyCredential> credential,
const PathClientOptions& options = PathClientOptions());
/**
* @brief Bearer token authentication client.
* @param pathUri The URI of the file system 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 PathClient(
const std::string& pathUri,
std::shared_ptr<TokenCredential> credential,
const PathClientOptions& options = PathClientOptions());
/**
* @brief Anonymous/SAS/customized pipeline auth.
* @param pathUri The URI of the file system this client's request targets.
* @param options Optional parameters used to initialize the client.
*/
explicit PathClient(
const std::string& pathUri,
const PathClientOptions& options = PathClientOptions());
/**
* @brief Uploads data to be appended to a file. Data can only be appended to a file.
* @param data The data to be appended.
* @param offset This parameter allows the caller to upload data in parallel and control
* the order in which it is appended to the file.
* The value must be the offset where the data is to be appended.
* Uploaded data is not immediately flushed, or written, to the file. To flush,
* the previously uploaded data must be contiguous, the offset parameter must
* be specified and equal to the length of the file after all data has been
* written, and there must not be a request entity body included with the
* request.
* @param options Optional parameters to append data to the resource the path points to.
* @return PathAppendDataResponse
*/
PathAppendDataResponse AppendData(
Azure::Core::Http::BodyStream* stream,
int64_t offset,
const PathAppendDataOptions& options = PathAppendDataOptions()) const;
/**
* @brief Flushes previous uploaded data to a file.
* @param offset This parameter allows the caller to upload data in parallel and control
* the order in which it is appended to the file.
* The value must be the offset where the data is to be appended.
* Uploaded data is not immediately flushed, or written, to the file. To flush,
* the previously uploaded data must be contiguous, the offset parameter must
* be specified and equal to the length of the file after all data has been
* written, and there must not be a request entity body included with the
* request.
* @param options Optional parameters to flush data to the resource the path points to.
* @return PathFlushDataResponse
*/
PathFlushDataResponse FlushData(
int64_t offset,
const PathFlushDataOptions& options = PathFlushDataOptions()) const;
/**
* @brief Sets the owner, group, permissions, or access control list for a file or directory.
* Note that Hierarchical Namespace must be enabled for the account in order to use
* access control. Also note that the Access Control List (ACL) includes permissions for
* the owner, owning group, and others, so the x-ms-permissions and x-ms-acl request
* headers are mutually exclusive.
* @param options Optional parameters to set an access control to the resource the path points
* to.
* @return PathFlushDataResponse
*/
PathSetAccessControlResponse SetAccessControl(
const SetAccessControlOptions& options = SetAccessControlOptions()) const;
/**
* @brief Sets POSIX access control rights on files and directories under given path
* recursively.
* @param mode Mode PathSetAccessControlRecursiveMode::Set sets POSIX access control rights on
* files and directories, PathSetAccessControlRecursiveMode::Modify modifies one or
* more POSIX access control rights that pre-exist on files and directories,
* PathSetAccessControlRecursiveMode::Remove removes one or more POSIX access
* control rights that were present earlier on files and directories
* @param options Optional parameters to set an access control recursively to the resource the
* path points to.
* @return PathSetAccessControlRecursiveResponse
*/
PathSetAccessControlRecursiveResponse SetAccessControlRecursive(
PathSetAccessControlRecursiveMode mode,
const SetAccessControlRecursiveOptions& options = SetAccessControlRecursiveOptions()) const;
/**
* @brief Sets the properties of a resource the path points to.
* @param options Optional parameters to set the properties to the resource the path points to.
* @return PathUpdateResponse
*/
PathUpdateResponse SetProperties(
const SetPathPropertiesOptions& options = SetPathPropertiesOptions()) const;
/**
* @brief Creates a file or directory. By default, the destination is overwritten and
* if the destination already exists and has a lease the lease is broken.
* @param options Optional parameters to create the resource the path points to.
* @return PathCreateResponse
*/
PathCreateResponse Create(const PathCreateOptions& options = PathCreateOptions()) const;
/**
* @brief Renames a file or directory. By default, the destination is overwritten and
* if the destination already exists and has a lease the lease is broken.
* @param options Optional parameters to rename a resource to the resource the path points to.
* @return PathRenameResponse
*/
PathRenameResponse Rename(const PathRenameOptions& options = PathRenameOptions()) const;
/**
* @brief Deletes the file or directory.
* @param options Optional parameters to delete the resource the path points to.
* @return PathDeleteResponse
*/
PathDeleteResponse Delete(const PathDeleteOptions& options = PathDeleteOptions()) const;
/**
* @brief Get Properties returns all system and user defined properties for a path. Get Status
* returns all system defined properties for a path. Get Access Control List returns the
* access control list for a path.
* @param options Optional parameters to get the properties from the resource the path points
* to.
* @return GetPathPropertiesResponse
*/
GetPathPropertiesResponse GetProperties(
const PathGetPropertiesOptions& options = PathGetPropertiesOptions()) const;
/**
* @brief Create and manage a lease to restrict write and delete access to the path.
* @param options Optional parameters to create or manage a lease on the resource the path
* points to.
* @return PathLeaseResponse
*/
PathLeaseResponse Lease(const PathLeaseOptions& options = PathLeaseOptions()) const;
/**
* @brief Read the contents of a file. For read operations, range requests are supported.
* @param options Optional parameters to read the content from the resource the path points to.
* @return ReadPathResponse
*/
ReadPathResponse Read(const PathReadOptions& options = PathReadOptions()) const;
private:
UrlBuilder m_dfsUri;
UrlBuilder m_blobUri;
std::shared_ptr<Azure::Core::Http::HttpPipeline> m_pipeline;
PathClient() = default;
friend class FileSystemClient;
};
}}} // namespace Azure::Storage::DataLake

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,82 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#pragma once
#include "common/storage_credential.hpp"
#include "common/storage_url_builder.hpp"
#include "datalake_options.hpp"
#include "http/pipeline.hpp"
#include "protocol/datalake_rest_client.hpp"
#include <memory>
#include <string>
namespace Azure { namespace Storage { namespace DataLake {
class FileSystemClient;
class ServiceClient {
public:
/**
* @brief Create from connection string
* @param connectionString Azure Storage connection string.
* @param options Optional parameters used to initialize the client.
* @return ServiceClient
*/
static ServiceClient CreateFromConnectionString(
const std::string& connectionString,
const ServiceClientOptions& options = ServiceClientOptions());
/**
* @brief Shared key authentication client.
* @param serviceUri The service URI 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 ServiceClient(
const std::string& serviceUri,
std::shared_ptr<SharedKeyCredential> credential,
const ServiceClientOptions& options = ServiceClientOptions());
/**
* @brief Bearer token authentication client.
* @param serviceUri The service URI 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 ServiceClient(
const std::string& serviceUri,
std::shared_ptr<TokenCredential> credential,
const ServiceClientOptions& options = ServiceClientOptions());
/**
* @brief Anonymous/SAS/customized pipeline auth.
* @param serviceUri The service URI this client's request targets.
* @param options Optional parameters used to initialize the client.
*/
explicit ServiceClient(
const std::string& serviceUri,
const ServiceClientOptions& options = ServiceClientOptions());
/**
* @brief Create a FileSystemClient from current ServiceClient
* @param fileSystemName The name of the file system.
* @return FileSystemClient
*/
FileSystemClient GetFileSystemClient(const std::string& fileSystemName) const;
/**
* @brief List the file systems from the service.
* @param options Optional parameters to list the file systems.
* @return ServiceListFileSystemsResponse
*/
ServiceListFileSystemsResponse ListFileSystems(
const ListFileSystemsOptions& options = ListFileSystemsOptions()) const;
private:
UrlBuilder m_dfsUri;
UrlBuilder m_blobUri;
std::shared_ptr<Azure::Core::Http::HttpPipeline> m_pipeline;
};
}}} // namespace Azure::Storage::DataLake

View File

@ -1,13 +1,14 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# SPDX-License-Identifier: MIT
cmake_minimum_required (VERSION 3.12)
cmake_minimum_required (VERSION 3.15)
if (BUILD_CURL_TRANSPORT)
add_executable (
azure-storage-sample
blob_getting_started.cpp
# blob_getting_started.cpp
datalake_getting_started.cpp
)
target_link_libraries(azure-storage-sample PRIVATE azure-storage)

View File

@ -1,3 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include "datalake/datalake.hpp"
#include <fstream>
#include <iostream>
int main()
{
using namespace Azure::Storage::DataLake;
auto client = ServiceClient::CreateFromConnectionString("");
auto response = client.ListFileSystems();
return 0;
}

View File

@ -0,0 +1,95 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include "common/storage_error.hpp"
#include "common/xml_wrapper.hpp"
#include "http/http.hpp"
namespace Azure { namespace Storage {
StorageError StorageError::CreateFromResponse(/* const */ Azure::Core::Http::Response& response)
{
auto bodyBuffer
= Azure::Core::Http::Response::ConstructBodyBufferFromStream(response.GetBodyStream());
auto xmlReader
= XmlReader(reinterpret_cast<const char*>(bodyBuffer->data()), bodyBuffer->size());
enum class XmlTagName
{
c_Error,
c_Code,
c_Message,
c_Details,
};
std::vector<XmlTagName> path;
std::string code;
std::string message;
std::map<std::string, std::string> details;
while (true)
{
auto node = xmlReader.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, "Error") == 0)
{
path.emplace_back(XmlTagName::c_Error);
}
else if (std::strcmp(node.Name, "Code") == 0)
{
path.emplace_back(XmlTagName::c_Code);
}
else if (std::strcmp(node.Name, "Message") == 0)
{
path.emplace_back(XmlTagName::c_Message);
}
else
{
path.emplace_back(XmlTagName::c_Details);
}
}
else if (node.Type == XmlNodeType::Text)
{
if (path.size() == 2 && path[0] == XmlTagName::c_Error && path[1] == XmlTagName::c_Code)
{
code = node.Value;
}
else if (
path.size() == 2 && path[0] == XmlTagName::c_Error && path[1] == XmlTagName::c_Message)
{
message = node.Value;
}
else if (
path.size() == 2 && path[0] == XmlTagName::c_Error && path[1] == XmlTagName::c_Details)
{
details[node.Name] = node.Value;
}
}
}
StorageError result = StorageError(message, code);
if (response.GetHeaders().find("x-ms-request-id") != response.GetHeaders().end())
{
result.RequestId = response.GetHeaders().at("x-ms-request-id");
}
result.Details = std::move(details);
return result;
}
}} // namespace Azure::Storage

View File

@ -0,0 +1,72 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include "datalake/datalake_utilities.hpp"
#include "common/crypt.hpp"
#include "datalake/protocol/datalake_rest_client.hpp"
#include <regex>
namespace Azure { namespace Storage { namespace DataLake {
namespace Details {
UrlBuilder GetBlobUriFromDfsUri(const UrlBuilder& dfsUri)
{
UrlBuilder result = dfsUri;
if (std::regex_match(
dfsUri.GetHost(), std::regex(std::string(".*") + Details::c_PathDnsSuffixDefault)))
{
result.SetHost(std::regex_replace(result.GetHost(), std::regex(".dfs."), ".blob."));
}
return result;
}
} // namespace Details
std::map<std::string, std::string> DeserializeMetadata(
const std::string& dataLakePropertiesString)
{
std::map<std::string, std::string> result;
std::string::const_iterator cur = dataLakePropertiesString.begin();
auto getSubstrTillDelimiter
= [](char delimiter, const std::string& string, std::string::const_iterator& cur) {
auto begin = cur;
auto end = std::find(cur, string.end(), delimiter);
cur = end;
if (cur != string.end())
{
++cur;
}
return std::string(begin, end);
};
while (cur != dataLakePropertiesString.end())
{
std::string key = getSubstrTillDelimiter('=', dataLakePropertiesString, cur);
std::string val = getSubstrTillDelimiter(',', dataLakePropertiesString, cur);
if (!key.empty() || !val.empty())
{
result[std::move(key)] = Base64Decode(val);
}
}
return result;
}
inline std::string SerializeMetadata(
const std::map<std::string, std::string>& dataLakePropertiesMap)
{
std::string result;
for (const auto& pair : dataLakePropertiesMap)
{
result.append(pair.first + "=" + Base64Encode(pair.second) + ",");
}
if (!result.empty())
{
result.pop_back();
}
return result;
}
}}} // namespace Azure::Storage::DataLake

View File

@ -0,0 +1,235 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include "datalake/file_system_client.hpp"
#include "blobs/internal/protocol/blob_rest_client.hpp"
#include "common/common_headers_request_policy.hpp"
#include "common/constant.hpp"
#include "common/crypt.hpp"
#include "common/shared_key_policy.hpp"
#include "common/storage_common.hpp"
#include "common/token_credential_policy.hpp"
#include "datalake/datalake_utilities.hpp"
#include "datalake/path_client.hpp"
#include "http/curl/curl.hpp"
namespace Azure { namespace Storage { namespace DataLake {
FileSystemClient FileSystemClient::CreateFromConnectionString(
const std::string& connectionString,
const std::string& fileSystemName,
const FileSystemClientOptions& options)
{
auto parsedConnectionString = ParseConnectionString(connectionString);
std::string accountName;
std::string accountKey;
std::string blobEndpoint;
std::string datalakeEndpoint;
std::string EndpointSuffix;
std::string defaultEndpointsProtocol = Details::c_PathDnsSuffixDefault;
auto ite
= parsedConnectionString.find(Azure::Storage::Details::c_ConnectionStringTagAccountName);
if (ite != parsedConnectionString.end())
{
accountName = ite->second;
}
ite = parsedConnectionString.find(Azure::Storage::Details::c_ConnectionStringTagAccountKey);
if (ite != parsedConnectionString.end())
{
accountKey = ite->second;
}
ite = parsedConnectionString.find(
Azure::Storage::Details::c_ConnectionStringTagDataLakeEndpoint);
if (ite != parsedConnectionString.end())
{
datalakeEndpoint = ite->second;
}
else
{
// Blob endpoint should also work due to interop. But honor DFS endpoint first.
ite = parsedConnectionString.find(Azure::Storage::Details::c_ConnectionStringTagBlobEndpoint);
if (ite != parsedConnectionString.end())
{
blobEndpoint
= ("." + (Azure::Storage::Details::c_DfsEndpointIdentifier + ("." + ite->second)));
}
}
ite = parsedConnectionString.find(Azure::Storage::Details::c_ConnectionStringTagEndpointSuffix);
if (ite != parsedConnectionString.end())
{
EndpointSuffix = ite->second;
}
ite = parsedConnectionString.find(
Azure::Storage::Details::c_ConnectionStringTagDefaultEndpointsProtocol);
if (ite != parsedConnectionString.end())
{
defaultEndpointsProtocol = ite->second;
}
UrlBuilder builder;
builder.SetScheme(defaultEndpointsProtocol);
if (!datalakeEndpoint.empty())
{
builder = UrlBuilder(datalakeEndpoint);
}
else if (!blobEndpoint.empty())
{
builder = UrlBuilder(blobEndpoint);
}
else if (!accountName.empty())
{
builder.SetHost(accountName + ".dfs." + EndpointSuffix);
}
else
{
throw std::runtime_error("invalid connection string");
}
builder.AppendPath(fileSystemName, true);
auto credential = std::make_shared<SharedKeyCredential>(accountName, accountKey);
return FileSystemClient(builder.to_string(), credential, options);
}
FileSystemClient::FileSystemClient(
const std::string& fileSystemUri,
std::shared_ptr<SharedKeyCredential> credential,
const FileSystemClientOptions& options)
: m_dfsUri(fileSystemUri)
{
m_blobUri = Details::GetBlobUriFromDfsUri(m_dfsUri);
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
for (const auto& p : options.policies)
{
policies.emplace_back(std::unique_ptr<Azure::Core::Http::HttpPolicy>(p->Clone()));
}
policies.emplace_back(std::make_unique<CommonHeadersRequestPolicy>());
policies.emplace_back(std::make_unique<SharedKeyPolicy>(credential));
policies.emplace_back(std::make_unique<Azure::Core::Http::TransportPolicy>(
std::make_shared<Azure::Core::Http::CurlTransport>()));
m_pipeline = std::make_shared<Azure::Core::Http::HttpPipeline>(policies);
}
FileSystemClient::FileSystemClient(
const std::string& fileSystemUri,
std::shared_ptr<TokenCredential> credential,
const FileSystemClientOptions& options)
: m_dfsUri(fileSystemUri)
{
m_blobUri = Details::GetBlobUriFromDfsUri(m_dfsUri);
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
for (const auto& p : options.policies)
{
policies.emplace_back(std::unique_ptr<Azure::Core::Http::HttpPolicy>(p->Clone()));
}
policies.emplace_back(std::make_unique<CommonHeadersRequestPolicy>());
policies.emplace_back(std::make_unique<TokenCredentialPolicy>(credential));
policies.emplace_back(std::make_unique<Azure::Core::Http::TransportPolicy>(
std::make_shared<Azure::Core::Http::CurlTransport>()));
m_pipeline = std::make_shared<Azure::Core::Http::HttpPipeline>(policies);
}
FileSystemClient::FileSystemClient(
const std::string& fileSystemUri,
const FileSystemClientOptions& options)
: m_dfsUri(fileSystemUri)
{
m_blobUri = Details::GetBlobUriFromDfsUri(m_dfsUri);
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
for (const auto& p : options.policies)
{
policies.emplace_back(std::unique_ptr<Azure::Core::Http::HttpPolicy>(p->Clone()));
}
policies.emplace_back(std::make_unique<CommonHeadersRequestPolicy>());
policies.emplace_back(std::make_unique<Azure::Core::Http::TransportPolicy>(
std::make_shared<Azure::Core::Http::CurlTransport>()));
m_pipeline = std::make_shared<Azure::Core::Http::HttpPipeline>(policies);
}
PathClient FileSystemClient::GetPathClient(const std::string& path) const
{
PathClient client = PathClient();
auto builder = m_dfsUri;
builder.AppendPath(path, true);
client.m_dfsUri = std::move(builder);
client.m_blobUri = Details::GetBlobUriFromDfsUri(builder);
client.m_pipeline = m_pipeline;
return client;
}
FileSystemCreateResponse FileSystemClient::Create(const FileSystemCreateOptions& options) const
{
DataLakeRestClient::FileSystem::CreateOptions protocolLayerOptions;
// TODO: Add null check here when Nullable<T> is supported
protocolLayerOptions.Properties = SerializeMetadata(options.Metadata);
protocolLayerOptions.Timeout = options.Timeout;
return DataLakeRestClient::FileSystem::Create(
m_dfsUri.to_string(), *m_pipeline, options.Context, protocolLayerOptions);
}
FileSystemDeleteResponse FileSystemClient::Delete(const FileSystemDeleteOptions& options) const
{
DataLakeRestClient::FileSystem::DeleteOptions protocolLayerOptions;
// TODO: Add null check here when Nullable<T> is supported
protocolLayerOptions.IfModifiedSince = options.IfModifiedSince;
protocolLayerOptions.IfUnmodifiedSince = options.IfUnmodifiedSince;
protocolLayerOptions.Timeout = options.Timeout;
return DataLakeRestClient::FileSystem::Delete(
m_dfsUri.to_string(), *m_pipeline, options.Context, protocolLayerOptions);
}
FileSystemGetMetadataResponse FileSystemClient::GetMetadata(
const FileSystemGetMetadataOptions& options) const
{
DataLakeRestClient::FileSystem::GetPropertiesOptions protocolLayerOptions;
// TODO: Add null check here when Nullable<T> is supported
protocolLayerOptions.Timeout = options.Timeout;
auto result = DataLakeRestClient::FileSystem::GetProperties(
m_dfsUri.to_string(), *m_pipeline, options.Context, protocolLayerOptions);
return FileSystemGetMetadataResponse{
std::move(result.Date),
std::move(result.ETag),
std::move(result.LastModified),
std::move(result.RequestId),
std::move(result.Version),
DeserializeMetadata(result.Properties),
result.NamespaceEnabled == "true" ? true : false};
}
FileSystemSetPropertiesResponse FileSystemClient::SetMetadata(
const std::map<std::string, std::string>& metadata,
const FileSystemSetMetadataOptions& options) const
{
DataLakeRestClient::FileSystem::SetPropertiesOptions protocolLayerOptions;
// TODO: Add null check here when Nullable<T> is supported
protocolLayerOptions.Properties = SerializeMetadata(metadata);
protocolLayerOptions.IfModifiedSince = options.IfModifiedSince;
protocolLayerOptions.IfUnmodifiedSince = options.IfUnmodifiedSince;
protocolLayerOptions.Timeout = options.Timeout;
return DataLakeRestClient::FileSystem::SetProperties(
m_dfsUri.to_string(), *m_pipeline, options.Context, protocolLayerOptions);
}
FileSystemListPathsResponse FileSystemClient::ListPaths(
bool recursive,
const ListPathsOptions& options) const
{
DataLakeRestClient::FileSystem::ListPathsOptions protocolLayerOptions;
// TODO: Add null check here when Nullable<T> is supported
protocolLayerOptions.Upn = options.Upn;
protocolLayerOptions.Continuation = options.Continuation;
protocolLayerOptions.MaxResults = options.MaxResults;
protocolLayerOptions.Directory = options.Directory;
protocolLayerOptions.RecursiveRequired = recursive;
protocolLayerOptions.Timeout = options.Timeout;
return DataLakeRestClient::FileSystem::ListPaths(
m_dfsUri.to_string(), *m_pipeline, options.Context, protocolLayerOptions);
}
}}} // namespace Azure::Storage::DataLake

View File

@ -0,0 +1,414 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include "datalake/path_client.hpp"
#include "common/common_headers_request_policy.hpp"
#include "common/constant.hpp"
#include "common/crypt.hpp"
#include "common/shared_key_policy.hpp"
#include "common/storage_common.hpp"
#include "common/token_credential_policy.hpp"
#include "datalake/datalake_utilities.hpp"
#include "http/curl/curl.hpp"
namespace Azure { namespace Storage { namespace DataLake {
PathClient PathClient::CreateFromConnectionString(
const std::string& connectionString,
const std::string& fileSystemName,
const std::string& path,
const PathClientOptions& options)
{
auto parsedConnectionString = ParseConnectionString(connectionString);
std::string accountName;
std::string accountKey;
std::string blobEndpoint;
std::string datalakeEndpoint;
std::string EndpointSuffix;
std::string defaultEndpointsProtocol = Details::c_PathDnsSuffixDefault;
auto ite
= parsedConnectionString.find(Azure::Storage::Details::c_ConnectionStringTagAccountName);
if (ite != parsedConnectionString.end())
{
accountName = ite->second;
}
ite = parsedConnectionString.find(Azure::Storage::Details::c_ConnectionStringTagAccountKey);
if (ite != parsedConnectionString.end())
{
accountKey = ite->second;
}
ite = parsedConnectionString.find(
Azure::Storage::Details::c_ConnectionStringTagDataLakeEndpoint);
if (ite != parsedConnectionString.end())
{
datalakeEndpoint = ite->second;
}
else
{
// Blob endpoint should also work due to interop. But honor DFS endpoint first.
ite = parsedConnectionString.find(Azure::Storage::Details::c_ConnectionStringTagBlobEndpoint);
if (ite != parsedConnectionString.end())
{
blobEndpoint
= ("." + (Azure::Storage::Details::c_DfsEndpointIdentifier + ("." + ite->second)));
}
}
ite = parsedConnectionString.find(Azure::Storage::Details::c_ConnectionStringTagEndpointSuffix);
if (ite != parsedConnectionString.end())
{
EndpointSuffix = ite->second;
}
ite = parsedConnectionString.find(
Azure::Storage::Details::c_ConnectionStringTagDefaultEndpointsProtocol);
if (ite != parsedConnectionString.end())
{
defaultEndpointsProtocol = ite->second;
}
UrlBuilder builder;
builder.SetScheme(defaultEndpointsProtocol);
if (!datalakeEndpoint.empty())
{
builder = UrlBuilder(datalakeEndpoint);
}
else if (!blobEndpoint.empty())
{
builder = UrlBuilder(blobEndpoint);
}
else if (!accountName.empty())
{
builder.SetHost(accountName + ".dfs." + EndpointSuffix);
}
else
{
throw std::runtime_error("invalid connection string");
}
builder.AppendPath(fileSystemName, true);
builder.AppendPath(path, true);
auto credential = std::make_shared<SharedKeyCredential>(accountName, accountKey);
return PathClient(builder.to_string(), credential, options);
}
PathClient::PathClient(
const std::string& pathUri,
std::shared_ptr<SharedKeyCredential> credential,
const PathClientOptions& options)
: m_dfsUri(pathUri)
{
m_blobUri = Details::GetBlobUriFromDfsUri(m_dfsUri);
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
for (const auto& p : options.policies)
{
policies.emplace_back(std::unique_ptr<Azure::Core::Http::HttpPolicy>(p->Clone()));
}
policies.emplace_back(std::make_unique<CommonHeadersRequestPolicy>());
policies.emplace_back(std::make_unique<SharedKeyPolicy>(credential));
policies.emplace_back(std::make_unique<Azure::Core::Http::TransportPolicy>(
std::make_shared<Azure::Core::Http::CurlTransport>()));
m_pipeline = std::make_shared<Azure::Core::Http::HttpPipeline>(policies);
}
PathClient::PathClient(
const std::string& pathUri,
std::shared_ptr<TokenCredential> credential,
const PathClientOptions& options)
: m_dfsUri(pathUri)
{
m_blobUri = Details::GetBlobUriFromDfsUri(m_dfsUri);
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
for (const auto& p : options.policies)
{
policies.emplace_back(std::unique_ptr<Azure::Core::Http::HttpPolicy>(p->Clone()));
}
policies.emplace_back(std::make_unique<CommonHeadersRequestPolicy>());
policies.emplace_back(std::make_unique<TokenCredentialPolicy>(credential));
policies.emplace_back(std::make_unique<Azure::Core::Http::TransportPolicy>(
std::make_shared<Azure::Core::Http::CurlTransport>()));
m_pipeline = std::make_shared<Azure::Core::Http::HttpPipeline>(policies);
}
PathClient::PathClient(const std::string& pathUri, const PathClientOptions& options)
: m_dfsUri(pathUri)
{
m_blobUri = Details::GetBlobUriFromDfsUri(m_dfsUri);
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
for (const auto& p : options.policies)
{
policies.emplace_back(std::unique_ptr<Azure::Core::Http::HttpPolicy>(p->Clone()));
}
policies.emplace_back(std::make_unique<CommonHeadersRequestPolicy>());
policies.emplace_back(std::make_unique<Azure::Core::Http::TransportPolicy>(
std::make_shared<Azure::Core::Http::CurlTransport>()));
m_pipeline = std::make_shared<Azure::Core::Http::HttpPipeline>(policies);
}
PathAppendDataResponse PathClient::AppendData(
Azure::Core::Http::BodyStream* stream,
int64_t offset,
const PathAppendDataOptions& options) const
{
DataLakeRestClient::Path::AppendDataOptions protocolLayerOptions;
// TODO: Add null check here when Nullable<T> is supported
protocolLayerOptions.Body = stream;
protocolLayerOptions.Position = offset;
protocolLayerOptions.ContentLength = stream->Length();
protocolLayerOptions.TransactionalContentMD5 = options.ContentMD5;
protocolLayerOptions.LeaseIdOptional = options.LeaseId;
protocolLayerOptions.Timeout = options.Timeout;
return DataLakeRestClient::Path::AppendData(
m_dfsUri.to_string(), *m_pipeline, options.Context, protocolLayerOptions);
}
PathFlushDataResponse PathClient::FlushData(int64_t offset, const PathFlushDataOptions& options)
const
{
DataLakeRestClient::Path::FlushDataOptions protocolLayerOptions;
// TODO: Add null check here when Nullable<T> is supported
protocolLayerOptions.Position = offset;
protocolLayerOptions.RetainUncommittedData = options.RetainUncommittedData;
protocolLayerOptions.Close = options.Close;
protocolLayerOptions.ContentLength = 0;
protocolLayerOptions.ContentMD5 = options.ContentMD5;
protocolLayerOptions.LeaseIdOptional = options.LeaseId;
protocolLayerOptions.CacheControl = options.CacheControl;
protocolLayerOptions.ContentType = options.ContentType;
protocolLayerOptions.ContentDisposition = options.ContentDisposition;
protocolLayerOptions.ContentEncoding = options.ContentEncoding;
protocolLayerOptions.ContentLanguage = options.ContentLanguage;
protocolLayerOptions.IfMatch = options.IfMatch;
protocolLayerOptions.IfNoneMatch = options.IfNoneMatch;
protocolLayerOptions.IfModifiedSince = options.IfModifiedSince;
protocolLayerOptions.IfUnmodifiedSince = options.IfUnmodifiedSince;
protocolLayerOptions.Timeout = options.Timeout;
return DataLakeRestClient::Path::FlushData(
m_dfsUri.to_string(), *m_pipeline, options.Context, protocolLayerOptions);
}
PathSetAccessControlResponse PathClient::SetAccessControl(
const SetAccessControlOptions& options) const
{
DataLakeRestClient::Path::SetAccessControlOptions protocolLayerOptions;
// TODO: Add null check here when Nullable<T> is supported
protocolLayerOptions.LeaseIdOptional = options.LeaseId;
protocolLayerOptions.Owner = options.Owner;
protocolLayerOptions.Group = options.Group;
protocolLayerOptions.Permissions = options.Permissions;
protocolLayerOptions.Acl = options.Acl;
protocolLayerOptions.IfMatch = options.IfMatch;
protocolLayerOptions.IfNoneMatch = options.IfNoneMatch;
protocolLayerOptions.IfModifiedSince = options.IfModifiedSince;
protocolLayerOptions.IfUnmodifiedSince = options.IfUnmodifiedSince;
protocolLayerOptions.Timeout = options.Timeout;
return DataLakeRestClient::Path::SetAccessControl(
m_dfsUri.to_string(), *m_pipeline, options.Context, protocolLayerOptions);
}
PathSetAccessControlRecursiveResponse PathClient::SetAccessControlRecursive(
PathSetAccessControlRecursiveMode mode,
const SetAccessControlRecursiveOptions& options) const
{
DataLakeRestClient::Path::SetAccessControlRecursiveOptions protocolLayerOptions;
// TODO: Add null check here when Nullable<T> is supported
protocolLayerOptions.Mode = mode;
protocolLayerOptions.Continuation = options.Continuation;
protocolLayerOptions.MaxRecords = options.MaxRecords;
protocolLayerOptions.Acl = options.Acl;
protocolLayerOptions.Timeout = options.Timeout;
return DataLakeRestClient::Path::SetAccessControlRecursive(
m_dfsUri.to_string(), *m_pipeline, options.Context, protocolLayerOptions);
}
PathUpdateResponse PathClient::SetProperties(const SetPathPropertiesOptions& options) const
{
DataLakeRestClient::Path::UpdateOptions protocolLayerOptions;
// TODO: Add null check here when Nullable<T> is supported
protocolLayerOptions.Action = PathUpdateAction::SetProperties;
protocolLayerOptions.CacheControl = options.CacheControl;
protocolLayerOptions.ContentType = options.ContentType;
protocolLayerOptions.ContentDisposition = options.ContentDisposition;
protocolLayerOptions.ContentEncoding = options.ContentEncoding;
protocolLayerOptions.ContentLanguage = options.ContentLanguage;
protocolLayerOptions.IfMatch = options.IfMatch;
protocolLayerOptions.IfNoneMatch = options.IfNoneMatch;
protocolLayerOptions.IfModifiedSince = options.IfModifiedSince;
protocolLayerOptions.IfUnmodifiedSince = options.IfUnmodifiedSince;
protocolLayerOptions.Properties = SerializeMetadata(options.Metadata);
protocolLayerOptions.Timeout = options.Timeout;
return DataLakeRestClient::Path::Update(
m_dfsUri.to_string(), *m_pipeline, options.Context, protocolLayerOptions);
}
PathCreateResponse PathClient::Create(const PathCreateOptions& options) const
{
DataLakeRestClient::Path::CreateOptions protocolLayerOptions;
// TODO: Add null check here when Nullable<T> is supported
protocolLayerOptions.Resource = options.Resource;
protocolLayerOptions.LeaseIdOptional = options.LeaseId;
protocolLayerOptions.CacheControl = options.CacheControl;
protocolLayerOptions.ContentType = options.ContentType;
protocolLayerOptions.ContentDisposition = options.ContentDisposition;
protocolLayerOptions.ContentEncoding = options.ContentEncoding;
protocolLayerOptions.ContentLanguage = options.ContentLanguage;
protocolLayerOptions.IfMatch = options.IfMatch;
protocolLayerOptions.IfNoneMatch = options.IfNoneMatch;
protocolLayerOptions.IfModifiedSince = options.IfModifiedSince;
protocolLayerOptions.IfUnmodifiedSince = options.IfUnmodifiedSince;
protocolLayerOptions.Properties = SerializeMetadata(options.Metadata);
protocolLayerOptions.Umask = options.Umask;
protocolLayerOptions.Permissions = options.Permissions;
protocolLayerOptions.Timeout = options.Timeout;
return DataLakeRestClient::Path::Create(
m_dfsUri.to_string(), *m_pipeline, options.Context, protocolLayerOptions);
}
PathRenameResponse PathClient::Rename(const PathRenameOptions& options) const
{
DataLakeRestClient::Path::CreateOptions protocolLayerOptions;
// TODO: Add null check here when Nullable<T> is supported
protocolLayerOptions.Resource = options.Resource;
protocolLayerOptions.Continuation = options.Continuation;
protocolLayerOptions.Mode = options.Mode;
protocolLayerOptions.SourceLeaseId = options.SourceLeaseId;
protocolLayerOptions.LeaseIdOptional = options.LeaseId;
protocolLayerOptions.CacheControl = options.CacheControl;
protocolLayerOptions.ContentType = options.ContentType;
protocolLayerOptions.ContentDisposition = options.ContentDisposition;
protocolLayerOptions.ContentEncoding = options.ContentEncoding;
protocolLayerOptions.ContentLanguage = options.ContentLanguage;
protocolLayerOptions.IfMatch = options.IfMatch;
protocolLayerOptions.IfNoneMatch = options.IfNoneMatch;
protocolLayerOptions.IfModifiedSince = options.IfModifiedSince;
protocolLayerOptions.IfUnmodifiedSince = options.IfUnmodifiedSince;
protocolLayerOptions.SourceIfMatch = options.SourceIfMatch;
protocolLayerOptions.SourceIfNoneMatch = options.SourceIfNoneMatch;
protocolLayerOptions.SourceIfModifiedSince = options.SourceIfModifiedSince;
protocolLayerOptions.SourceIfUnmodifiedSince = options.SourceIfUnmodifiedSince;
protocolLayerOptions.Properties = SerializeMetadata(options.Metadata);
protocolLayerOptions.Umask = options.Umask;
protocolLayerOptions.RenameSource = options.RenameSource;
protocolLayerOptions.Permissions = options.Permissions;
protocolLayerOptions.Timeout = options.Timeout;
return DataLakeRestClient::Path::Create(
m_dfsUri.to_string(), *m_pipeline, options.Context, protocolLayerOptions);
}
PathDeleteResponse PathClient::Delete(const PathDeleteOptions& options) const
{
DataLakeRestClient::Path::DeleteOptions protocolLayerOptions;
// TODO: Add null check here when Nullable<T> is supported
protocolLayerOptions.Continuation = options.Continuation;
protocolLayerOptions.LeaseIdOptional = options.LeaseId;
protocolLayerOptions.IfMatch = options.IfMatch;
protocolLayerOptions.IfNoneMatch = options.IfNoneMatch;
protocolLayerOptions.IfModifiedSince = options.IfModifiedSince;
protocolLayerOptions.IfUnmodifiedSince = options.IfUnmodifiedSince;
protocolLayerOptions.RecursiveOptional = options.RecursiveOptional;
protocolLayerOptions.Timeout = options.Timeout;
return DataLakeRestClient::Path::Delete(
m_dfsUri.to_string(), *m_pipeline, options.Context, protocolLayerOptions);
}
GetPathPropertiesResponse PathClient::GetProperties(const PathGetPropertiesOptions& options) const
{
DataLakeRestClient::Path::GetPropertiesOptions protocolLayerOptions;
// TODO: Add null check here when Nullable<T> is supported
protocolLayerOptions.Action = options.Action;
protocolLayerOptions.Upn = options.UserPrincipalName;
protocolLayerOptions.LeaseIdOptional = options.LeaseId;
protocolLayerOptions.IfMatch = options.IfMatch;
protocolLayerOptions.IfNoneMatch = options.IfNoneMatch;
protocolLayerOptions.IfModifiedSince = options.IfModifiedSince;
protocolLayerOptions.IfUnmodifiedSince = options.IfUnmodifiedSince;
protocolLayerOptions.Timeout = options.Timeout;
auto result = DataLakeRestClient::Path::GetProperties(
m_dfsUri.to_string(), *m_pipeline, options.Context, protocolLayerOptions);
return GetPathPropertiesResponse{
std::move(result.AcceptRanges),
std::move(result.CacheControl),
std::move(result.ContentDisposition),
std::move(result.ContentEncoding),
std::move(result.ContentLanguage),
result.ContentLength,
std::move(result.ContentRange),
std::move(result.ContentType),
std::move(result.ContentMD5),
std::move(result.Date),
std::move(result.ETag),
std::move(result.LastModified),
std::move(result.RequestId),
std::move(result.Version),
std::move(result.ResourceType),
std::move(result.Owner),
std::move(result.Group),
std::move(result.Permissions),
std::move(result.ACL),
std::move(result.LeaseDuration),
std::move(result.LeaseState),
std::move(result.LeaseStatus),
DeserializeMetadata(result.Properties)};
}
PathLeaseResponse PathClient::Lease(const PathLeaseOptions& options) const
{
DataLakeRestClient::Path::LeaseOptions protocolLayerOptions;
// TODO: Add null check here when Nullable<T> is supported
protocolLayerOptions.XMsLeaseAction = options.LeaseAction;
protocolLayerOptions.ProposedLeaseIdOptional = options.ProposedLeaseId;
protocolLayerOptions.XMsLeaseDuration = options.LeaseDuration;
protocolLayerOptions.XMsLeaseBreakPeriod = options.LeaseBreakPeriod;
protocolLayerOptions.LeaseIdOptional = options.LeaseId;
protocolLayerOptions.IfMatch = options.IfMatch;
protocolLayerOptions.IfNoneMatch = options.IfNoneMatch;
protocolLayerOptions.IfModifiedSince = options.IfModifiedSince;
protocolLayerOptions.IfUnmodifiedSince = options.IfUnmodifiedSince;
protocolLayerOptions.Timeout = options.Timeout;
return DataLakeRestClient::Path::Lease(
m_dfsUri.to_string(), *m_pipeline, options.Context, protocolLayerOptions);
}
ReadPathResponse PathClient::Read(const PathReadOptions& options) const
{
DataLakeRestClient::Path::ReadOptions protocolLayerOptions;
// TODO: Add null check here when Nullable<T> is supported
protocolLayerOptions.Range = options.Range;
protocolLayerOptions.XMsRangeGetContentMd5 = options.RangeGetContentMd5;
protocolLayerOptions.LeaseIdOptional = options.LeaseId;
protocolLayerOptions.IfMatch = options.IfMatch;
protocolLayerOptions.IfNoneMatch = options.IfNoneMatch;
protocolLayerOptions.IfModifiedSince = options.IfModifiedSince;
protocolLayerOptions.IfUnmodifiedSince = options.IfUnmodifiedSince;
protocolLayerOptions.Timeout = options.Timeout;
auto result = DataLakeRestClient::Path::Read(
m_dfsUri.to_string(), *m_pipeline, options.Context, protocolLayerOptions);
return ReadPathResponse{
result.BodyStream,
std::move(result.AcceptRanges),
std::move(result.CacheControl),
std::move(result.ContentDisposition),
std::move(result.ContentEncoding),
std::move(result.ContentLanguage),
std::move(result.ContentLength),
std::move(result.ContentRange),
std::move(result.ContentType),
std::move(result.ContentMD5),
std::move(result.Date),
std::move(result.ETag),
std::move(result.LastModified),
std::move(result.RequestId),
std::move(result.Version),
std::move(result.ResourceType),
std::move(result.LeaseDuration),
std::move(result.LeaseState),
std::move(result.LeaseStatus),
std::move(result.XMsContentMd5),
DeserializeMetadata(result.Properties)};
}
}}} // namespace Azure::Storage::DataLake

View File

@ -0,0 +1,174 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include "datalake/service_client.hpp"
#include "blobs/internal/protocol/blob_rest_client.hpp"
#include "common/common_headers_request_policy.hpp"
#include "common/constant.hpp"
#include "common/shared_key_policy.hpp"
#include "common/storage_common.hpp"
#include "common/token_credential_policy.hpp"
#include "datalake/datalake_utilities.hpp"
#include "datalake/file_system_client.hpp"
#include "http/curl/curl.hpp"
namespace Azure { namespace Storage { namespace DataLake {
ServiceClient ServiceClient::CreateFromConnectionString(
const std::string& connectionString,
const ServiceClientOptions& options)
{
auto parsedConnectionString = ParseConnectionString(connectionString);
std::string accountName;
std::string accountKey;
std::string blobEndpoint;
std::string datalakeEndpoint;
std::string EndpointSuffix;
std::string defaultEndpointsProtocol = Details::c_PathDnsSuffixDefault;
auto ite
= parsedConnectionString.find(Azure::Storage::Details::c_ConnectionStringTagAccountName);
if (ite != parsedConnectionString.end())
{
accountName = ite->second;
}
ite = parsedConnectionString.find(Azure::Storage::Details::c_ConnectionStringTagAccountKey);
if (ite != parsedConnectionString.end())
{
accountKey = ite->second;
}
ite = parsedConnectionString.find(
Azure::Storage::Details::c_ConnectionStringTagDataLakeEndpoint);
if (ite != parsedConnectionString.end())
{
datalakeEndpoint = ite->second;
}
else
{
// Blob endpoint should also work due to interop. But honor DFS endpoint first.
ite = parsedConnectionString.find(Azure::Storage::Details::c_ConnectionStringTagBlobEndpoint);
if (ite != parsedConnectionString.end())
{
blobEndpoint
= ("." + (Azure::Storage::Details::c_DfsEndpointIdentifier + ("." + ite->second)));
}
}
ite = parsedConnectionString.find(Azure::Storage::Details::c_ConnectionStringTagEndpointSuffix);
if (ite != parsedConnectionString.end())
{
EndpointSuffix = ite->second;
}
ite = parsedConnectionString.find(
Azure::Storage::Details::c_ConnectionStringTagDefaultEndpointsProtocol);
if (ite != parsedConnectionString.end())
{
defaultEndpointsProtocol = ite->second;
}
UrlBuilder builder;
builder.SetScheme(defaultEndpointsProtocol);
if (!datalakeEndpoint.empty())
{
builder = UrlBuilder(datalakeEndpoint);
}
else if (!blobEndpoint.empty())
{
builder = UrlBuilder(blobEndpoint);
}
else if (!accountName.empty())
{
builder.SetHost(accountName + ".dfs." + EndpointSuffix);
}
else
{
throw std::runtime_error("invalid connection string");
}
auto credential = std::make_shared<SharedKeyCredential>(accountName, accountKey);
return ServiceClient(builder.to_string(), credential, options);
}
ServiceClient::ServiceClient(
const std::string& serviceUri,
std::shared_ptr<SharedKeyCredential> credential,
const ServiceClientOptions& options)
: m_dfsUri(serviceUri)
{
m_blobUri = Details::GetBlobUriFromDfsUri(m_dfsUri);
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
for (const auto& p : options.policies)
{
policies.emplace_back(std::unique_ptr<Azure::Core::Http::HttpPolicy>(p->Clone()));
}
policies.emplace_back(std::make_unique<CommonHeadersRequestPolicy>());
policies.emplace_back(std::make_unique<SharedKeyPolicy>(credential));
policies.emplace_back(std::make_unique<Azure::Core::Http::TransportPolicy>(
std::make_shared<Azure::Core::Http::CurlTransport>()));
m_pipeline = std::make_shared<Azure::Core::Http::HttpPipeline>(policies);
}
ServiceClient::ServiceClient(
const std::string& serviceUri,
std::shared_ptr<TokenCredential> credential,
const ServiceClientOptions& options)
: m_dfsUri(serviceUri)
{
m_blobUri = Details::GetBlobUriFromDfsUri(m_dfsUri);
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
for (const auto& p : options.policies)
{
policies.emplace_back(std::unique_ptr<Azure::Core::Http::HttpPolicy>(p->Clone()));
}
policies.emplace_back(std::make_unique<CommonHeadersRequestPolicy>());
policies.emplace_back(std::make_unique<TokenCredentialPolicy>(credential));
policies.emplace_back(std::make_unique<Azure::Core::Http::TransportPolicy>(
std::make_shared<Azure::Core::Http::CurlTransport>()));
m_pipeline = std::make_shared<Azure::Core::Http::HttpPipeline>(policies);
}
ServiceClient::ServiceClient(const std::string& serviceUri, const ServiceClientOptions& options)
: m_dfsUri(serviceUri)
{
m_blobUri = Details::GetBlobUriFromDfsUri(m_dfsUri);
std::vector<std::unique_ptr<Azure::Core::Http::HttpPolicy>> policies;
for (const auto& p : options.policies)
{
policies.emplace_back(std::unique_ptr<Azure::Core::Http::HttpPolicy>(p->Clone()));
}
policies.emplace_back(std::make_unique<CommonHeadersRequestPolicy>());
policies.emplace_back(std::make_unique<Azure::Core::Http::TransportPolicy>(
std::make_shared<Azure::Core::Http::CurlTransport>()));
m_pipeline = std::make_shared<Azure::Core::Http::HttpPipeline>(policies);
}
FileSystemClient ServiceClient::GetFileSystemClient(const std::string& fileSystemName) const
{
FileSystemClient client = FileSystemClient();
auto builder = m_dfsUri;
builder.AppendPath(fileSystemName, true);
client.m_dfsUri = std::move(builder);
client.m_blobUri = Details::GetBlobUriFromDfsUri(builder);
client.m_pipeline = m_pipeline;
return client;
}
ServiceListFileSystemsResponse ServiceClient::ListFileSystems(
const ListFileSystemsOptions& options) const
{
DataLakeRestClient::Service::ListFileSystemsOptions protocolLayerOptions;
// TODO: Add null check here when Nullable<T> is supported
protocolLayerOptions.Prefix = options.Prefix;
protocolLayerOptions.Continuation = options.Continuation;
protocolLayerOptions.MaxResults = options.MaxResults;
protocolLayerOptions.Timeout = options.Timeout;
return DataLakeRestClient::Service::ListFileSystems(
m_dfsUri.to_string(), *m_pipeline, options.Context, protocolLayerOptions);
}
}}} // namespace Azure::Storage::DataLake

View File

@ -1,7 +1,7 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# SPDX-License-Identifier: MIT
cmake_minimum_required (VERSION 3.12)
cmake_minimum_required (VERSION 3.15)
if (MSVC)
# There will be many const conparisons in test code.