Keyvault full backup/restore support (#5744)
* first build pass * move models Refactor KeyVault backup/restore client This commit represents a significant refactoring of the Azure Security KeyVault Administration client library, transitioning from a generic `KeyVaultClient` to a more specialized `BackupRestoreClient`. The refactoring includes: - Renaming `KeyVaultClient` to `BackupRestoreClient` in both `backup_restore_client.hpp` and `backup_restore_client.cpp` to better reflect the focused functionality on backup and restore operations. - Moving model definitions from `backup_restore_client.hpp` to `rest_client_models.hpp`, including structures for errors, full backup, restore, and selective key restore operations, along with their options. This change centralizes model definitions for improved maintainability and reuse across the client library. - Updating method implementations in `backup_restore_client.cpp` to align with the `BackupRestoreClient` class name and its specialized backup and restore operations. These changes aim to provide clearer separation of concerns within the library, making it more manageable and focused on backup and restore functionalities for Azure KeyVault. * Add BackupRestoreClient with tests and options This commit introduces the BackupRestoreClient for Azure Key Vault backup and restore operations, along with BackupRestoreClientOptions for configuration. Significant refactoring within the Azure::Security::KeyVault::Administration namespace simplifies namespace usage by directly using `using namespace Models;`. The BackupRestoreClient has been enhanced with a new constructor accepting `vaultUrl`, a `TokenCredential` shared pointer, and optionally `BackupRestoreClientOptions`. Additionally, a copy constructor and a default destructor have been added, alongside a private member `m_apiVersion` for API version management. The BackupRestoreClientOptions struct extends Azure::Core::_internal::ClientOptions with an `ApiVersion` member initialized to "7.5". Changes in the implementation file include additional headers for internal use and authentication, and updates to the constructor for initializing member variables and setting up the HTTP pipeline. Test infrastructure has been enhanced with modifications in `CMakeLists.txt` to include test source files, the introduction of a base test class `BackupRestoreClientTest` for setup, and a test case `CreateClient1` demonstrating client creation. These changes collectively enhance the Azure Key Vault Administration library by adding a new client for backup and restore operations, improving code organization, and setting up a testing framework. * Enhance BackupRestoreClient and tests This commit significantly updates the BackupRestoreClient and its associated models, introducing new features for backup and restore operations, and improving error handling with a new Error model. The `BackupRestoreClient` class has been marked as `final` to prevent inheritance, and several new methods such as `FullBackup`, `FullBackupStatus`, `FullRestore`, `RestoreStatus`, and `SelectiveKeyRestore` have been added, along with corresponding data models in `rest_client_models.hpp`. These changes enhance the client's functionality and API clarity. Additionally, the test infrastructure has seen substantial improvements, including refactoring in `backup_restore_client_base_test.hpp` for better encapsulation and updated utility methods for more effective testing. The practical application of these enhancements is demonstrated in `backup_restore_client_test.cpp` through the `CreateClient1` test case, showcasing the use of the `FullBackup` method. Overall, these updates bolster the Azure Key Vault Backup and Restore client library's capabilities and test support. * Enhance BackupRestoreClient for Azure backups - Updated `BackupRestoreClient` to support full backups and restores using Azure blob storage SAS tokens, including changes to method signatures for SAS token and job identifier parameters. - Introduced nullable types for `StatusDetails` and `Error` in operation models to handle optional response fields. - Removed `FullBackupOptions`, `FullRestoreOperationOptions`, and `RestoreStatusOptions` structures in favor of direct parameter usage in methods. - Refined HTTP request construction to include necessary headers and dynamically set API version. - Updated JSON parsing logic to handle nullable fields and adapt to changed response JSON structure. - Enhanced test infrastructure with methods for creating test-configured `BackupRestoreClient` and generating SAS tokens for backups. Added new tests for full backup, backup status, full restore, and restore status functionalities. - Adjusted URL path construction and query parameter setting in HTTP requests for updated API endpoints and parameters compatibility. * Refine SelectiveKeyRestore API and tests This commit overhauls the SelectiveKeyRestore function in the Azure Key Vault Backup and Restore client library. The function signature in `backup_restore_client.hpp` has been updated to replace the `SelectiveKeyRestoreOperationOptions` parameter with two distinct parameters: `keyName` (std::string) and `restoreBlobDetails` (SelectiveKeyRestoreOperationParameters). This change enhances the API's clarity and usability by explicitly requiring the key name and restore blob details for the operation. Additionally, the `SelectiveKeyRestoreOperationOptions` structure has been removed from `rest_client_models.hpp`, aligning with the shift towards using direct parameters for the selective key restore operation. Corresponding implementation adjustments in `backup_restore_client.cpp` include changes to request URL and JSON body construction, as well as improved error handling in response parsing. The test suite in `backup_restore_client_test.cpp` has also been updated. The `CreateClient1` test case was removed, and a new test case, `RestoreSelectiveStatus`, was added to demonstrate the updated API's functionality through a full backup and selective key restore operation scenario. These changes collectively improve the API's intuitiveness and demonstrate its practical application through updated test cases. * oops * fds * negative tests Enhance backup/restore tests and cleanups - Added a new test case `BackupFullErrorStatus` to the `BackupRestoreClientTest` suite to simulate a full backup operation with an invalid URI and verify the transition of backup status from "InProgress" to "Failed" with detailed error status. - Refined the `RestoreFull` test case by removing unnecessary line breaks, improving code formatting without affecting functionality. - Adjusted formatting in the `RestoreFullStatus` test by removing unnecessary braces and line breaks, streamlining the code. - Improved readability in the `RestoreSelectiveStatus` test by adding a space after a comma. - Introduced a new test case `RestoreSelectiveInvalidKeyStatus` to test the system's handling of invalid key restore requests, ensuring error reporting is accurate when keys or their versions are not found. * recordings and pipeline * linux build issues * comment * parse the error type * fix paths * ewrwe * fdss * reencode ansi * fdsfsd * Enhance samples and refine project structure - Adjusted `CMakeLists.txt` for better project clarity, moving `BUILD_SAMPLES_HSM` from `test/samples` to `samples` and adding new sample directories for backup and restore functionalities. - Updated `sample1_administration.cpp` to use `Azure::Core::_internal::Environment::GetVariable` for environment variable access and removed settings management code to focus on specific functionalities. - Added new sample applications `sample2_full_backup_restore.cpp` and `sample3_backup_selective_restore.cpp` demonstrating full and selective backup and restore operations using the Azure Key Vault administration client library, including detailed steps and error handling. - Included `CMakeLists.txt` for each new sample, specifying C++ standards and linking necessary libraries, with a focus on ease of use and configuration through the inclusion of `get-env-helper`. * restore sample 1 * attempt reformat doc * gfddgdf * attempt 2 * are you serious ? * treter * docs * typo * changelog * doc * KHlAAAAAAAAAAANg said Kirk * error check * Updates to API * clangs * test new macro use in cmake file * clang again * missing include * update1 * LROs * clang 11 * attempt2 * fhkwerjhfkj * documentation * attempt++ * separating the op in its own files * clang * docs ++ * docc +++ * clang * typo * slkjlkdsjflks * rename to backupclient * hoping it's building * PR comments * address magic param check * assets update
This commit is contained in:
parent
ce0e7ced1d
commit
ec6a66d53e
@ -2,5 +2,5 @@
|
||||
"AssetsRepo": "Azure/azure-sdk-assets",
|
||||
"AssetsRepoPrefixPath": "cpp",
|
||||
"TagPrefix": "cpp/keyvault",
|
||||
"Tag": "cpp/keyvault_b43656c9a5"
|
||||
"Tag": "cpp/keyvault_e1582c490f"
|
||||
}
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
|
||||
### Features Added
|
||||
|
||||
- Add support for Backup/Restore operations for Key Vault HSM.
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
### Bugs Fixed
|
||||
|
||||
@ -48,6 +48,8 @@ endif()
|
||||
set(
|
||||
AZURE_SECURITY_KEYVAULT_ADMINISTRATION_HEADER
|
||||
inc/azure/keyvault/administration.hpp
|
||||
inc/azure/keyvault/administration/backup_client.hpp
|
||||
inc/azure/keyvault/administration/backup_operation.hpp
|
||||
inc/azure/keyvault/administration/dll_import_export.hpp
|
||||
inc/azure/keyvault/administration/rest_client_models.hpp
|
||||
inc/azure/keyvault/administration/rtti.hpp
|
||||
@ -57,6 +59,8 @@ set(
|
||||
|
||||
set(
|
||||
AZURE_SECURITY_KEYVAULT_ADMINISTRATION_SOURCE
|
||||
src/backup_client.cpp
|
||||
src/backup_operation.cpp
|
||||
src/keyvault_settings_common_request.cpp
|
||||
src/private/administration_constants.hpp
|
||||
src/private/keyvault_settings_common_request.hpp
|
||||
@ -106,8 +110,8 @@ if (BUILD_PERFORMANCE_TESTS)
|
||||
#add_subdirectory(test/perf)
|
||||
endif()
|
||||
|
||||
if(BUILD_SAMPLES_HSM)
|
||||
add_subdirectory(test/samples)
|
||||
if(BUILD_SAMPLES)
|
||||
add_subdirectory(samples)
|
||||
endif()
|
||||
|
||||
az_vcpkg_export(
|
||||
|
||||
@ -130,6 +130,115 @@ To update the value of any of the the available settings, we will call the Updat
|
||||
Setting updatedSetting
|
||||
= settingsClient.UpdateSetting(settingsList.Value[0].Name, options).Value;
|
||||
```
|
||||
## Creating a BackupClient
|
||||
|
||||
To create a new `BackupClient` to perform these operations, you need the endpoint to an Azure Key Vault HSM and credentials.
|
||||
|
||||
Key Vault BackupClient client for C++ currently supports any `TokenCredential` for authenticating.
|
||||
|
||||
```cpp
|
||||
auto credential
|
||||
= std::make_shared<Azure::Identity::DefaultAzureCredential>();
|
||||
```
|
||||
|
||||
Then, in the sample below, you can set `keyVaultUrl` based on an environment variable, configuration setting, or any way that works for your application.
|
||||
|
||||
```cpp
|
||||
// create client
|
||||
BackupClient client(std::getenv("AZURE_KEYVAULT_HSM_URL"), credential);
|
||||
```
|
||||
## Create the SasTokenParameter
|
||||
|
||||
Since these operations require a blob storage for the backup/restore operations, a SAS token is required for the connection between the services(Key Vault and Storage).
|
||||
|
||||
In this sample we rely on a couple of extra environment variables.
|
||||
|
||||
```cpp
|
||||
SasTokenParameter sasTokenParameter;
|
||||
// the backup/restore needs a SAS token to access the storage account
|
||||
sasTokenParameter.Token
|
||||
= Azure::Core::_internal::Environment::GetVariable("AZURE_KEYVAULT_BACKUP_TOKEN");
|
||||
// the backup/restore needs a url to a blob storage resource
|
||||
Azure::Core::Url blobUrl
|
||||
= Azure::Core::Url(Azure::Core::_internal::Environment::GetVariable("AZURE_KEYVAULT_BACKUP_URL"));
|
||||
```
|
||||
|
||||
## The Backup operation
|
||||
|
||||
Since this is a long running operation the service provides endpoints to determine the status while the opperation is running.
|
||||
|
||||
### Starting the backup operation
|
||||
|
||||
```cpp
|
||||
// Create a full backup using a user-provided SAS token to an Azure blob storage container.
|
||||
auto backupResponse = client.FullBackup(blobUrl, sasTokenParameter).Value;
|
||||
|
||||
std::cout << "Backup Job Id: " << backupResponse.Value().JobId << std::endl
|
||||
<< "Backup Status: " << backupResponse.Value().Status << std::endl;
|
||||
```
|
||||
|
||||
### Backup operation waiting
|
||||
|
||||
In order to wait for the operation to complete we will call the polling method.
|
||||
|
||||
```cpp
|
||||
// Wait for the operation to complete.
|
||||
auto backupStatus = backupResponse.PollUntilDone(10s);
|
||||
|
||||
std::cout << "Backup Job Id: " << backupStatus.Value.JobId << std::endl
|
||||
<< "Backup Status: " << backupStatus.Value.Status << std::endl;
|
||||
```
|
||||
|
||||
## The FullRestore operation
|
||||
|
||||
Similar to the backup operation after we initialize the operation we can check the status.
|
||||
|
||||
### Starting the restore operation
|
||||
|
||||
the restore operation requires a folder where a backup was previously performed along side the SAS token parameter.
|
||||
```cpp
|
||||
// Restore the full backup using a user-provided SAS token to an Azure blob storage container.
|
||||
std::cout << "Folder to restore: " << folderToRestore << std::endl;
|
||||
auto restoreResponse = client.FullRestore(blobUrl, folderToRestore, sasTokenParameter).Value;
|
||||
std::cout << "Restore Job Id: " << restoreResponse.Value().JobId << std::endl
|
||||
<< "Restore Status: " << restoreResponse.Value().Status << std::endl;
|
||||
```
|
||||
|
||||
### FullRestore operation waiting
|
||||
|
||||
```cpp
|
||||
// Wait for the operation to complete.
|
||||
auto restoreStatus = restoreResponse.PollUntilDone(10s);
|
||||
std::cout << "Restore Job Id: " << restoreStatus.Value.JobId << std::endl
|
||||
<< "Restore Status: " << restoreStatus.Value.Status << std::endl;
|
||||
```
|
||||
|
||||
## The SelectiveRestore operation
|
||||
|
||||
Similar to the backup operation after we initialize the operation we can check the status.
|
||||
|
||||
### Starting the restore operation
|
||||
|
||||
The selective restore operation requires a folder where a backup was previously performed along side the SAS token parameter.
|
||||
|
||||
```cpp
|
||||
// Restore the full backup using a user-provided SAS token to an Azure blob storage container.
|
||||
std::string folderToRestore = ...;
|
||||
std::cout << "Folder to restore: " << restoreBlobDetails.FolderToRestore << std::endl;
|
||||
auto selectiveRestore = client.SelectiveKeyRestore("keyName", blobUrl, folderToRestore, sasTokenParameter);
|
||||
std::cout << "Restore Job Id: " << restoreResponse.Value.JobId << std::endl
|
||||
<< "Restore Status: " << restoreResponse.Value.Status << std::endl;
|
||||
```
|
||||
|
||||
### Selective restore operation completion
|
||||
|
||||
```cpp
|
||||
// Wait for the operation to complete.
|
||||
auto selectiveStatus = selectiveRestore.PollUntilDone(10s);
|
||||
std::cout << "Selective Restore Job Id: " << selectiveStatus.Value.JobId << std::endl
|
||||
<< "Selective Restore Status: " << selectiveStatus.Value.Status << std::endl;
|
||||
```
|
||||
|
||||
|
||||
## Contributing
|
||||
For details on contributing to this repository, see the [contributing guide][azure_sdk_for_cpp_contributing].
|
||||
|
||||
@ -8,6 +8,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "azure/keyvault/administration/backup_client.hpp"
|
||||
#include "azure/keyvault/administration/backup_operation.hpp"
|
||||
#include "azure/keyvault/administration/dll_import_export.hpp"
|
||||
#include "azure/keyvault/administration/rest_client_models.hpp"
|
||||
#include "azure/keyvault/administration/rtti.hpp"
|
||||
|
||||
@ -0,0 +1,138 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
// Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
|
||||
#pragma once
|
||||
#include "azure/keyvault/administration/backup_operation.hpp"
|
||||
#include "azure/keyvault/administration/rest_client_models.hpp"
|
||||
|
||||
#include <azure/core/context.hpp>
|
||||
#include <azure/core/datetime.hpp>
|
||||
#include <azure/core/internal/http/pipeline.hpp>
|
||||
#include <azure/core/internal/json/json.hpp>
|
||||
#include <azure/core/nullable.hpp>
|
||||
#include <azure/core/operation.hpp>
|
||||
#include <azure/core/operation_status.hpp>
|
||||
#include <azure/core/response.hpp>
|
||||
#include <azure/core/url.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
using namespace Azure::Security::KeyVault::Administration::Models;
|
||||
|
||||
namespace Azure { namespace Security { namespace KeyVault { namespace Administration {
|
||||
/**
|
||||
* @brief Backup restore client.
|
||||
*
|
||||
*/
|
||||
class BackupClient final {
|
||||
public:
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*
|
||||
*/
|
||||
virtual ~BackupClient() = default;
|
||||
|
||||
/**
|
||||
* @brief Construct a new BackupClient object
|
||||
*
|
||||
* @param vaultUrl The URL address where the client will send the requests to.
|
||||
* @param credential The authentication method to use.
|
||||
* @param options The options to customize the client behavior.
|
||||
*/
|
||||
explicit BackupClient(
|
||||
std::string const& vaultUrl,
|
||||
std::shared_ptr<Core::Credentials::TokenCredential const> credential,
|
||||
BackupClientOptions options = BackupClientOptions());
|
||||
|
||||
/**
|
||||
* @brief Creates a full backup using a user-provided SAS token to an Azure blob storage
|
||||
* container.
|
||||
*
|
||||
* @param blobContainerUrl The URL for the blob storage resource.
|
||||
* @param sasToken Azure blob shared access signature token pointing to a
|
||||
* valid Azure blob container where full backup needs to be
|
||||
* stored. This token needs to be valid for at least next 24
|
||||
* hours from the time of making this call.
|
||||
* @param context The context for the operation can be used for request cancellation.
|
||||
* @return A backup restore operation.
|
||||
*/
|
||||
Response<BackupOperation> FullBackup(
|
||||
Azure::Core::Url const& blobContainerUrl,
|
||||
SasTokenParameter const& sasToken,
|
||||
Core::Context const& context = {});
|
||||
|
||||
/**
|
||||
* @brief Returns the status of full backup operation.
|
||||
*
|
||||
* @param jobId Identifier for the full backup operation.
|
||||
* @param context The context for the operation can be used for request cancellation.
|
||||
* @return Backup restore operation status.
|
||||
*/
|
||||
Response<BackupOperationStatus> FullBackupStatus(
|
||||
std::string const& jobId = "",
|
||||
Core::Context const& context = {});
|
||||
|
||||
/**
|
||||
* @brief Restores all key materials using the SAS token pointing to a previously stored Azure
|
||||
* Blob storage backup folder.
|
||||
*
|
||||
* @param blobContainerUrl The URL for the blob storage resource, including the path to the blob
|
||||
* @param folderToRestore The path to the blob container where the backup resides.
|
||||
* @param sasToken Azure blob shared access signature token pointing to a valid Azure blob
|
||||
* container where full backup needs to be stored. This token needs to be valid for at least
|
||||
* next 24 hours from the time of making this call.
|
||||
* @param context The context for the operation can be used for request cancellation.
|
||||
* @return A backup restore operation.
|
||||
*/
|
||||
Response<BackupOperation> FullRestore(
|
||||
Azure::Core::Url const& blobContainerUrl,
|
||||
std::string folderToRestore,
|
||||
SasTokenParameter const& sasToken,
|
||||
Core::Context const& context = {});
|
||||
|
||||
/**
|
||||
* @brief Returns the status of restore operation.
|
||||
*
|
||||
* @param jobId Identifier for the restore operation.
|
||||
* @param context The context for the operation can be used for request cancellation.
|
||||
* @return A backup restore operation status.
|
||||
*/
|
||||
Response<BackupOperationStatus> RestoreStatus(
|
||||
std::string const& jobId = "",
|
||||
Core::Context const& context = {});
|
||||
|
||||
/**
|
||||
* @brief Restores all key versions of a given key using user supplied SAS token pointing to a
|
||||
* previously stored Azure Blob storage backup folder.
|
||||
*
|
||||
* @param keyName The name of the key to be restored from the user supplied backup.
|
||||
* @param blobContainerUrl The URL for the blob storage resource, including the path to the blob
|
||||
* @param folderToRestore The path to the blob container where the backup resides.
|
||||
* @param sasToken Azure blob shared access signature token pointing to a valid Azure blob
|
||||
* container where full backup needs to be stored. This token needs to be valid for at least
|
||||
* next 24 hours from the time of making this call.
|
||||
* @param context The context for the operation can be used for request cancellation.
|
||||
* @return A backup restore operation.
|
||||
*/
|
||||
Response<BackupOperation> SelectiveKeyRestore(
|
||||
std::string const& keyName,
|
||||
Azure::Core::Url const& blobContainerUrl,
|
||||
std::string folderToRestore,
|
||||
SasTokenParameter const& sasToken,
|
||||
Core::Context const& context = {});
|
||||
|
||||
private:
|
||||
std::shared_ptr<Core::Http::_internal::HttpPipeline> m_pipeline;
|
||||
Azure::Core::Url m_vaultBaseUrl;
|
||||
std::string m_apiVersion;
|
||||
KeyVaultServiceError DeserializeKeyVaultServiceError(
|
||||
Azure::Core::Json::_internal::json errorFragment);
|
||||
BackupOperationStatus DeserializeBackupOperationStatus(
|
||||
Azure::Core::Http::RawResponse const& rawResponse);
|
||||
};
|
||||
|
||||
}}}} // namespace Azure::Security::KeyVault::Administration
|
||||
@ -0,0 +1,121 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
// Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
|
||||
#pragma once
|
||||
#include "azure/keyvault/administration/rest_client_models.hpp"
|
||||
|
||||
#include <azure/core/context.hpp>
|
||||
#include <azure/core/datetime.hpp>
|
||||
#include <azure/core/operation.hpp>
|
||||
#include <azure/core/operation_status.hpp>
|
||||
#include <azure/core/response.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
using namespace Azure::Security::KeyVault::Administration::Models;
|
||||
|
||||
namespace Azure { namespace Security { namespace KeyVault { namespace Administration {
|
||||
class BackupClient;
|
||||
|
||||
/**
|
||||
* @brief BackupOperation : The backup / restore long running operation.
|
||||
* @remark Used to handle both backup and restore operations due to the similarity in patterns
|
||||
* and return values.
|
||||
*/
|
||||
class BackupOperation final : public Azure::Core::Operation<BackupOperationStatus> {
|
||||
private:
|
||||
/* BackupOperation can be constructed only by friends classes (internal
|
||||
* creation). The constructor is private and requires internal components.*/
|
||||
friend class Azure::Security::KeyVault::Administration::BackupClient;
|
||||
|
||||
std::shared_ptr<BackupClient> m_backupClient;
|
||||
BackupOperationStatus m_value;
|
||||
std::string m_continuationToken;
|
||||
bool m_isBackupOperation = true;
|
||||
|
||||
std::unique_ptr<Azure::Core::Http::RawResponse> PollInternal(
|
||||
Azure::Core::Context const& context) override;
|
||||
|
||||
Azure::Response<BackupOperationStatus> PollUntilDoneInternal(
|
||||
std::chrono::milliseconds period,
|
||||
Azure::Core::Context& context) override;
|
||||
|
||||
/**
|
||||
* @brief Only friend classes are permitted to construct a RecoverDeletedKeyOperation. This is
|
||||
* because a KeyVaultPipelne is required and it is not exposed to customers.
|
||||
*
|
||||
* @param backupClient A #BackupClient that is used for getting status updates.
|
||||
* @param status A BackupOperationStatus object.
|
||||
* @param isBackupOperation A boolean indicating if the operation is a backup operation or a
|
||||
* restore.
|
||||
*/
|
||||
BackupOperation(
|
||||
std::shared_ptr<BackupClient> const& backupClient,
|
||||
BackupOperationStatus const& status,
|
||||
bool isBackupOperation)
|
||||
: m_backupClient{backupClient}, m_value{status}, m_continuationToken{status.JobId},
|
||||
m_isBackupOperation{isBackupOperation} {};
|
||||
/**
|
||||
* @brief Only friend classes are permitted to construct a RecoverDeletedKeyOperation. This is
|
||||
* because a KeyVaultPipelne is required and it is not exposed to customers.
|
||||
* @param backupClient A BackupClient that is used for getting status updates.
|
||||
* @param continuationToken A string that is used to resume the operation.
|
||||
* @param isBackupOperation A boolean indicating if the operation is a backup operation or a
|
||||
* restore.
|
||||
*/
|
||||
BackupOperation(
|
||||
std::shared_ptr<BackupClient> const& backupClient,
|
||||
std::string const& continuationToken,
|
||||
bool isBackupOperation)
|
||||
: m_backupClient{backupClient}, m_continuationToken{continuationToken},
|
||||
m_isBackupOperation{isBackupOperation} {};
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Get the BackupOperationStatus object.
|
||||
*
|
||||
* @remark The status contains the current progress result at the time of the call.
|
||||
*
|
||||
* @return A BackupOperationStatus object.
|
||||
*/
|
||||
BackupOperationStatus Value() const override { return m_value; }
|
||||
|
||||
/**
|
||||
* @brief Get the continuation token used for further status inquiries
|
||||
*
|
||||
* @return std::string
|
||||
*/
|
||||
std::string GetResumeToken() const override { return m_continuationToken; }
|
||||
|
||||
/**
|
||||
* @brief Create a BackupOperation from the \p resumeToken fetched from
|
||||
* another `Operation<T>`, updated to the the latest operation status.
|
||||
*
|
||||
* @remark After the operation is initialized, it is used to poll the last update from the
|
||||
* server using the \p context.
|
||||
*
|
||||
* @param resumeToken A previously generated token used to resume the polling of the
|
||||
* operation.
|
||||
* @param client A BackupClient that is used for getting status updates.
|
||||
* @param isBackupOperation A boolean indicating if the operation is a backup operation if
|
||||
* false it is considered a restore operation.
|
||||
* @param context A Azure::Core::Context controlling the request lifetime.
|
||||
* @return BackupOperation
|
||||
*/
|
||||
static BackupOperation CreateFromResumeToken(
|
||||
std::string const& resumeToken,
|
||||
BackupClient const& client,
|
||||
bool isBackupOperation,
|
||||
Azure::Core::Context const& context = Azure::Core::Context())
|
||||
{
|
||||
BackupOperation operation(
|
||||
std::make_shared<BackupClient>(client), resumeToken, isBackupOperation);
|
||||
operation.Poll(context);
|
||||
return operation;
|
||||
}
|
||||
};
|
||||
}}}} // namespace Azure::Security::KeyVault::Administration
|
||||
@ -74,4 +74,111 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Administra
|
||||
std::vector<Setting> Value;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Define the options to create an SDK Keys client.
|
||||
*
|
||||
*/
|
||||
struct BackupClientOptions final : public Azure::Core::_internal::ClientOptions
|
||||
{
|
||||
/**
|
||||
* @brief Service Version used.
|
||||
*
|
||||
*/
|
||||
const std::string ApiVersion{"7.5"};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief KeyVault Service Error model.
|
||||
*
|
||||
*/
|
||||
struct KeyVaultServiceError final
|
||||
{
|
||||
/**
|
||||
* @brief The error code.
|
||||
*
|
||||
*/
|
||||
std::string Code;
|
||||
/**
|
||||
* @brief The error message.
|
||||
*
|
||||
*/
|
||||
std::string Message;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The full backup operation.
|
||||
*
|
||||
*/
|
||||
struct BackupOperationStatus final
|
||||
{
|
||||
/**
|
||||
* @brief Status of the backup operation.
|
||||
*
|
||||
*/
|
||||
std::string Status;
|
||||
/**
|
||||
* @brief The status details of backup operation.
|
||||
*
|
||||
*/
|
||||
Azure::Nullable<std::string> StatusDetails;
|
||||
/**
|
||||
* @brief Error encountered, if any, during the full backup operation.
|
||||
*
|
||||
*/
|
||||
Azure::Nullable<KeyVaultServiceError> Error;
|
||||
/**
|
||||
* @brief The start time of the backup operation in UTC.
|
||||
*
|
||||
*/
|
||||
DateTime StartTime;
|
||||
/**
|
||||
* @brief The end time of the backup operation in UTC.
|
||||
*
|
||||
*/
|
||||
Nullable<DateTime> EndTime;
|
||||
/**
|
||||
* @brief Identifier for the full backup operation.
|
||||
*
|
||||
*/
|
||||
std::string JobId;
|
||||
/**
|
||||
* @brief The Azure blob storage container Uri which contains the full backup.
|
||||
*
|
||||
*/
|
||||
std::string AzureStorageBlobContainerUri;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Sas token parameter for backup and restore operations.
|
||||
*
|
||||
*/
|
||||
struct SasTokenParameter final
|
||||
{
|
||||
/**
|
||||
* @brief The SAS token pointing to an Azure Blob storage container.
|
||||
*
|
||||
*/
|
||||
Nullable<std::string> Token;
|
||||
/**
|
||||
* @brief Indicates which authentication method should be used. If set to true, Managed HSM
|
||||
* will use the configured user-assigned managed identity to authenticate with Azure Storage.
|
||||
* Otherwise, a SAS token has to be specified.
|
||||
*
|
||||
*/
|
||||
Nullable<bool> UseManagedIdentity;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Full backup status options.
|
||||
*
|
||||
*/
|
||||
struct FullBackupStatusOptions final
|
||||
{
|
||||
/**
|
||||
* @brief Identifier for the full backup operation.
|
||||
*
|
||||
*/
|
||||
std::string JobId;
|
||||
};
|
||||
|
||||
}}}}} // namespace Azure::Security::KeyVault::Administration::Models
|
||||
|
||||
@ -4,4 +4,6 @@
|
||||
cmake_minimum_required (VERSION 3.13)
|
||||
|
||||
add_subdirectory(sample1-basic-operations)
|
||||
add_subdirectory(sample2-full-backup-restore)
|
||||
add_subdirectory(sample3-backup-selective-restore)
|
||||
|
||||
@ -24,7 +24,8 @@ int main()
|
||||
auto credential = std::make_shared<Azure::Identity::DefaultAzureCredential>();
|
||||
|
||||
// create client
|
||||
SettingsClient settingsClient(std::getenv("AZURE_KEYVAULT_HSM_URL"), credential);
|
||||
SettingsClient settingsClient(
|
||||
Azure::Core::_internal::Environment::GetVariable("AZURE_KEYVAULT_HSM_URL"), credential);
|
||||
|
||||
try
|
||||
{
|
||||
@ -55,4 +55,4 @@ Call UpdateSetting to modify an existing setting. Create an options object and i
|
||||
## Source
|
||||
|
||||
To see the full example source, see:
|
||||
[Source Code](https://github.com/Azure/azure-sdk-for-cpp/tree/main/sdk/keyvault/azure-security-keyvault-administration/test/samples/sample1-basic-operations)
|
||||
[Source Code](https://github.com/Azure/azure-sdk-for-cpp/tree/main/sdk/keyvault/azure-security-keyvault-administration/samples/sample1-basic-operations)
|
||||
|
||||
@ -0,0 +1,16 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# Licensed under the MIT License.
|
||||
|
||||
cmake_minimum_required (VERSION 3.13)
|
||||
|
||||
project (sample2-full-backup-restore LANGUAGES CXX)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
add_executable (
|
||||
sample2-full-backup-restore
|
||||
sample2_full_backup_restore.cpp
|
||||
)
|
||||
create_per_service_target_build_for_sample(keyvault sample2-full-backup-restore)
|
||||
|
||||
target_link_libraries(sample2-full-backup-restore PRIVATE azure-security-keyvault-administration azure-identity get-env-helper)
|
||||
@ -0,0 +1,82 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/**
|
||||
* @brief This sample provides the code implementation to use the Key Vault Settings SDK client for
|
||||
* C++ to get one or more settings, and update a setting value.
|
||||
*
|
||||
* @remark The following environment variables must be set before running the sample.
|
||||
* - AZURE_KEYVAULT_HSM_URL: To the Key Vault HSM URL.
|
||||
* - AZURE_KEYVAULT_BACKUP_TOKEN : The SAS token to access the blob storage account for
|
||||
* backup/restore
|
||||
* - AZURE_KEYVAULT_BACKUP_URL : The URL to the blob storage account
|
||||
*
|
||||
*/
|
||||
|
||||
#include <azure/identity.hpp>
|
||||
#include <azure/keyvault/administration.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
using namespace Azure::Security::KeyVault::Administration;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
int main()
|
||||
{
|
||||
auto credential = std::make_shared<Azure::Identity::DefaultAzureCredential>();
|
||||
|
||||
// create client
|
||||
BackupClient client(
|
||||
Azure::Core::_internal::Environment::GetVariable("AZURE_KEYVAULT_HSM_URL"), credential);
|
||||
SasTokenParameter sasTokenParameter;
|
||||
// the backup/restore needs a SAS token to access the storage account
|
||||
sasTokenParameter.Token
|
||||
= Azure::Core::_internal::Environment::GetVariable("AZURE_KEYVAULT_BACKUP_TOKEN");
|
||||
// the backup/restore needs a url to a blob storage resource
|
||||
Azure::Core::Url blobUrl = Azure::Core::Url(
|
||||
Azure::Core::_internal::Environment::GetVariable("AZURE_KEYVAULT_BACKUP_URL"));
|
||||
|
||||
try
|
||||
{
|
||||
// Create a full backup using a user-provided SAS token to an Azure blob storage container.
|
||||
auto backupResponse = client.FullBackup(blobUrl, sasTokenParameter).Value;
|
||||
|
||||
std::cout << "Backup Job Id: " << backupResponse.Value().JobId << std::endl
|
||||
<< "Backup Status: " << backupResponse.Value().Status << std::endl;
|
||||
// Wait for the operation to complete.
|
||||
auto backupStatus = backupResponse.PollUntilDone(10s);
|
||||
|
||||
std::cout << "Backup Job Id: " << backupStatus.Value.JobId << std::endl
|
||||
<< "Backup Status: " << backupStatus.Value.Status << std::endl;
|
||||
|
||||
// Restore the full backup using a user-provided SAS token to an Azure blob storage container.
|
||||
Azure::Core::Url url(backupStatus.Value.AzureStorageBlobContainerUri);
|
||||
auto subPath = url.GetPath();
|
||||
std::string folderToRestore = subPath.substr(7, subPath.size() - 1);
|
||||
|
||||
std::cout << "Folder to restore: " << folderToRestore << std::endl;
|
||||
auto restoreResponse = client.FullRestore(blobUrl, folderToRestore, sasTokenParameter).Value;
|
||||
std::cout << "Restore Job Id: " << restoreResponse.Value().JobId << std::endl
|
||||
<< "Restore Status: " << restoreResponse.Value().Status << std::endl;
|
||||
|
||||
// Wait for the operation to complete.
|
||||
auto restoreStatus = restoreResponse.PollUntilDone(10s);
|
||||
std::cout << "Restore Job Id: " << restoreStatus.Value.JobId << std::endl
|
||||
<< "Restore Status: " << restoreStatus.Value.Status << std::endl;
|
||||
}
|
||||
catch (Azure::Core::Credentials::AuthenticationException const& e)
|
||||
{
|
||||
std::cout << "Authentication Exception happened:" << std::endl << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (Azure::Core::RequestFailedException const& e)
|
||||
{
|
||||
std::cout << "Key Vault Settings Client Exception happened:" << std::endl
|
||||
<< e.Message << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
# Getting, updating, settings
|
||||
|
||||
This sample demonstrates how to perform full backup and full restore for an Azure Key Vault HSM.
|
||||
To get started, you'll need a URI to an Azure Key Vault HSM.
|
||||
|
||||
## Creating a BackupClient
|
||||
|
||||
To create a new `BackupClient` to perform these operations, you need the endpoint to an Azure Key Vault HSM and credentials.
|
||||
|
||||
Key Vault BackupClient client for C++ currently supports any `TokenCredential` for authenticating.
|
||||
|
||||
```cpp
|
||||
auto credential
|
||||
= std::make_shared<Azure::Identity::DefaultAzureCredential>();
|
||||
```
|
||||
|
||||
Then, in the sample below, you can set `keyVaultUrl` based on an environment variable, configuration setting, or any way that works for your application.
|
||||
|
||||
```cpp
|
||||
// create client
|
||||
BackupClient client(std::getenv("AZURE_KEYVAULT_HSM_URL"), credential);
|
||||
```
|
||||
## Create the SasTokenParameter
|
||||
|
||||
Since these operations require a blob storage for the backup/restore operations, a SAS token is required for the connection between the services(Key Vault and Storage).
|
||||
|
||||
In this sample we rely on a couple of extra environment variables.
|
||||
|
||||
```cpp
|
||||
SasTokenParameter sasTokenParameter;
|
||||
// the backup/restore needs a SAS token to access the storage account
|
||||
sasTokenParameter.Token
|
||||
= Azure::Core::_internal::Environment::GetVariable("AZURE_KEYVAULT_BACKUP_TOKEN");
|
||||
// the backup/restore needs a url to a blob storage resource
|
||||
Azure::Core::Url blobUrl = Azure::Core::Url(
|
||||
Azure::Core::_internal::Environment::GetVariable("AZURE_KEYVAULT_BACKUP_URL"));
|
||||
```
|
||||
|
||||
## The Backup operation
|
||||
|
||||
Since this is a long running operation the service provides endpoints to determine the status while the opperation is running.
|
||||
|
||||
### Starting the backup operation
|
||||
|
||||
```cpp
|
||||
// Create a full backup using a user-provided SAS token to an Azure blob storage container.
|
||||
auto backupResponse = client.FullBackup(blobUrl, sasTokenParameter).Value;
|
||||
|
||||
std::cout << "Backup Job Id: " << backupResponse.Value().JobId << std::endl
|
||||
<< "Backup Status: " << backupResponse.Value().Status << std::endl;
|
||||
```
|
||||
|
||||
### Backup operation waiting
|
||||
|
||||
In order to wait for the operation to complete we will call the polling method.
|
||||
|
||||
```cpp
|
||||
// Wait for the operation to complete.
|
||||
auto backupStatus = backupResponse.PollUntilDone(10s);
|
||||
|
||||
std::cout << "Backup Job Id: " << backupStatus.Value.JobId << std::endl
|
||||
<< "Backup Status: " << backupStatus.Value.Status << std::endl;
|
||||
```
|
||||
|
||||
## The FullRestore operation
|
||||
|
||||
Similar to the backup operation after we initialize the operation we can check the status.
|
||||
|
||||
### Starting the restore operation
|
||||
|
||||
the restore operation requires a folder where a backup was previously performed along side the SAS token parameter.
|
||||
```cpp
|
||||
// Restore the full backup using a user-provided SAS token to an Azure blob storage container.
|
||||
std::cout << "Folder to restore: " << folderToRestore << std::endl;
|
||||
auto restoreResponse = client.FullRestore(blobUrl, folderToRestore, sasTokenParameter).Value;
|
||||
std::cout << "Restore Job Id: " << restoreResponse.Value().JobId << std::endl
|
||||
<< "Restore Status: " << restoreResponse.Value().Status << std::endl;
|
||||
```
|
||||
|
||||
### FullRestore operation waiting
|
||||
|
||||
```cpp
|
||||
// Wait for the operation to complete.
|
||||
auto restoreStatus = restoreResponse.PollUntilDone(10s);
|
||||
std::cout << "Restore Job Id: " << restoreStatus.Value.JobId << std::endl
|
||||
<< "Restore Status: " << restoreStatus.Value.Status << std::endl;
|
||||
```
|
||||
## Source
|
||||
|
||||
To see the full example source, see:
|
||||
[Source Code](https://github.com/Azure/azure-sdk-for-cpp/tree/main/sdk/keyvault/azure-security-keyvault-administration/samples/sample2-full-backup-restore)
|
||||
@ -0,0 +1,16 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
# Licensed under the MIT License.
|
||||
|
||||
cmake_minimum_required (VERSION 3.13)
|
||||
|
||||
project (sample3-backup-selective-restore LANGUAGES CXX)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
add_executable (
|
||||
sample3-backup-selective-restore
|
||||
sample3_backup_selective_restore.cpp
|
||||
)
|
||||
create_per_service_target_build_for_sample(keyvault sample3-backup-selective-restore)
|
||||
|
||||
target_link_libraries(sample3-backup-selective-restore PRIVATE azure-security-keyvault-administration azure-identity get-env-helper)
|
||||
@ -0,0 +1,84 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/**
|
||||
* @brief This sample provides the code implementation to use the Key Vault Settings SDK client for
|
||||
* C++ to get one or more settings, and update a setting value.
|
||||
*
|
||||
* @remark The following environment variables must be set before running the sample.
|
||||
* - AZURE_KEYVAULT_HSM_URL: To the Key Vault HSM URL.
|
||||
* - AZURE_KEYVAULT_BACKUP_TOKEN : The SAS token to access the blob storage account for
|
||||
* backup/restore
|
||||
* - AZURE_KEYVAULT_BACKUP_URL : The URL to the blob storage account
|
||||
*
|
||||
*/
|
||||
|
||||
#include <azure/identity.hpp>
|
||||
#include <azure/keyvault/administration.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
using namespace Azure::Security::KeyVault::Administration;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
int main()
|
||||
{
|
||||
auto credential = std::make_shared<Azure::Identity::DefaultAzureCredential>();
|
||||
|
||||
// create client
|
||||
BackupClient client(
|
||||
Azure::Core::_internal::Environment::GetVariable("AZURE_KEYVAULT_HSM_URL"), credential);
|
||||
SasTokenParameter sasTokenParameter;
|
||||
// the backup/restore needs a SAS token to access the storage account
|
||||
sasTokenParameter.Token
|
||||
= Azure::Core::_internal::Environment::GetVariable("AZURE_KEYVAULT_BACKUP_TOKEN");
|
||||
// the backup/restore needs a url to a blob storage resource
|
||||
Azure::Core::Url blobUrl = Azure::Core::Url(
|
||||
Azure::Core::_internal::Environment::GetVariable("AZURE_KEYVAULT_BACKUP_URL"));
|
||||
// the key name to restore from backup
|
||||
const std::string keyName = "trytry";
|
||||
try
|
||||
{
|
||||
// Create a full backup using a user-provided SAS token to an Azure blob storage container.
|
||||
auto backupResponse = client.FullBackup(blobUrl, sasTokenParameter).Value;
|
||||
|
||||
std::cout << "Backup Job Id: " << backupResponse.Value().JobId << std::endl
|
||||
<< "Backup Status: " << backupResponse.Value().Status << std::endl;
|
||||
// Wait for the operation to complete.
|
||||
auto backupStatus = backupResponse.PollUntilDone(10s);
|
||||
|
||||
std::cout << "Backup Job Id: " << backupStatus.Value.JobId << std::endl
|
||||
<< "Backup Status: " << backupStatus.Value.Status << std::endl;
|
||||
// Restore a selected key from the backup using a user-provided SAS token to an Azure blob
|
||||
// storage container.
|
||||
Azure::Core::Url url(backupStatus.Value.AzureStorageBlobContainerUri);
|
||||
auto subPath = url.GetPath();
|
||||
std::string folderToRestore = subPath.substr(7, subPath.size() - 1);
|
||||
|
||||
std::cout << "Folder to restore: " << folderToRestore << std::endl;
|
||||
auto selectiveRestore
|
||||
= client.SelectiveKeyRestore("trytry", blobUrl, folderToRestore, sasTokenParameter).Value;
|
||||
std::cout << "Selective Restore Job Id: " << selectiveRestore.Value().JobId << std::endl
|
||||
<< "Selective Restore Status: " << selectiveRestore.Value().Status << std::endl;
|
||||
|
||||
// Wait for the operation to complete.
|
||||
auto selectiveStatus = selectiveRestore.PollUntilDone(10s);
|
||||
std::cout << "Selective Restore Job Id: " << selectiveStatus.Value.JobId << std::endl
|
||||
<< "Selective Restore Status: " << selectiveStatus.Value.Status << std::endl;
|
||||
}
|
||||
catch (Azure::Core::Credentials::AuthenticationException const& e)
|
||||
{
|
||||
std::cout << "Authentication Exception happened:" << std::endl << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (Azure::Core::RequestFailedException const& e)
|
||||
{
|
||||
std::cout << "Key Vault Settings Client Exception happened:" << std::endl
|
||||
<< e.Message << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
# Getting, updating, settings
|
||||
|
||||
This sample demonstrates how to perform full backup and full restore for an Azure Key Vault HSM.
|
||||
To get started, you'll need a URI to an Azure Key Vault HSM.
|
||||
|
||||
## Creating a BackupClient
|
||||
|
||||
To create a new `BackupClient` to perform these operations, you need the endpoint to an Azure Key Vault HSM and credentials.
|
||||
|
||||
Key Vault BackupClient client for C++ currently supports any `TokenCredential` for authenticating.
|
||||
|
||||
```cpp
|
||||
auto credential
|
||||
= std::make_shared<Azure::Identity::DefaultAzureCredential>();
|
||||
```
|
||||
|
||||
Then, in the sample below, you can set `keyVaultUrl` based on an environment variable, configuration setting, or any way that works for your application.
|
||||
|
||||
```cpp
|
||||
// create client
|
||||
BackupClient client(std::getenv("AZURE_KEYVAULT_HSM_URL"), credential);
|
||||
```
|
||||
## Create the SasTokenParameter
|
||||
|
||||
Since these operations require a blob storage for the backup/restore operations, a SAS token is required for the connection between the services(Key Vault and Storage).
|
||||
|
||||
In this sample we rely on a couple of extra environment variables.
|
||||
|
||||
```cpp
|
||||
SasTokenParameter sasTokenParameter;
|
||||
// the backup/restore needs a SAS token to access the storage account
|
||||
sasTokenParameter.Token
|
||||
= Azure::Core::_internal::Environment::GetVariable("AZURE_KEYVAULT_BACKUP_TOKEN");
|
||||
// the backup/restore needs a url to a blob storage resource
|
||||
Azure::Core::Url blobUrl
|
||||
= Azure::Core::Url(Azure::Core::_internal::Environment::GetVariable("AZURE_KEYVAULT_BACKUP_URL"));
|
||||
```
|
||||
|
||||
## The Backup operation
|
||||
|
||||
Since this is a long running operation the service provides endpoints to determine the status while the opperation is running.
|
||||
|
||||
### Starting the backup operation
|
||||
|
||||
```cpp
|
||||
// Create a full backup using a user-provided SAS token to an Azure blob storage container.
|
||||
auto backupResponse = client.FullBackup(blobUrl, sasTokenParameter).Value;
|
||||
|
||||
std::cout << "Backup Job Id: " << backupResponse.Value().JobId << std::endl
|
||||
<< "Backup Status: " << backupResponse.Value().Status << std::endl;
|
||||
```
|
||||
|
||||
### Backup operation waiting
|
||||
|
||||
In order to wait for the operation to complete we will call the polling method.
|
||||
|
||||
```cpp
|
||||
// Wait for the operation to complete.
|
||||
auto backupStatus = backupResponse.PollUntilDone(10s);
|
||||
|
||||
std::cout << "Backup Job Id: " << backupStatus.Value.JobId << std::endl
|
||||
<< "Backup Status: " << backupStatus.Value.Status << std::endl;
|
||||
```
|
||||
|
||||
## The SelectiveRestore operation
|
||||
|
||||
Similar to the backup operation after we initialize the operation we can check the status.
|
||||
|
||||
### Starting the restore operation
|
||||
|
||||
The selective restore operation requires a folder where a backup was previously performed along side the SAS token parameter.
|
||||
|
||||
```cpp
|
||||
// Restore the full backup using a user-provided SAS token to an Azure blob storage container.
|
||||
std::string folderToRestore = ...;
|
||||
std::cout << "Folder to restore: " << restoreBlobDetails.FolderToRestore << std::endl;
|
||||
auto selectiveRestore = client.SelectiveKeyRestore("keyName", blobUrl, folderToRestore, sasTokenParameter);
|
||||
std::cout << "Restore Job Id: " << restoreResponse.Value.JobId << std::endl
|
||||
<< "Restore Status: " << restoreResponse.Value.Status << std::endl;
|
||||
```
|
||||
|
||||
### Selective restore operation completion
|
||||
|
||||
```cpp
|
||||
// Wait for the operation to complete.
|
||||
auto selectiveStatus = selectiveRestore.PollUntilDone(10s);
|
||||
std::cout << "Selective Restore Job Id: " << selectiveStatus.Value.JobId << std::endl
|
||||
<< "Selective Restore Status: " << selectiveStatus.Value.Status << std::endl;
|
||||
```
|
||||
## Source
|
||||
|
||||
To see the full example source, see:
|
||||
[Source Code](https://github.com/Azure/azure-sdk-for-cpp/tree/main/sdk/keyvault/azure-security-keyvault-administration/samples/sample3-backup-selective-restore)
|
||||
@ -0,0 +1,329 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
// Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
|
||||
#include "azure/keyvault/administration/backup_client.hpp"
|
||||
|
||||
#include "private/administration_constants.hpp"
|
||||
#include "private/package_version.hpp"
|
||||
|
||||
#include <azure/core/exception.hpp>
|
||||
#include <azure/core/http/http.hpp>
|
||||
#include <azure/core/http/http_status_code.hpp>
|
||||
#include <azure/core/http/policies/policy.hpp>
|
||||
#include <azure/core/internal/http/pipeline.hpp>
|
||||
#include <azure/core/internal/json/json.hpp>
|
||||
#include <azure/core/io/body_stream.hpp>
|
||||
#include <azure/keyvault/shared/keyvault_challenge_based_auth.hpp>
|
||||
#include <azure/keyvault/shared/keyvault_shared.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
using namespace Azure::Security::KeyVault::Administration;
|
||||
using namespace Azure::Core::Http;
|
||||
using namespace Azure::Core::Http::Policies;
|
||||
using namespace Azure::Core::Http::Policies::_internal;
|
||||
using namespace Azure::Core::Http::_internal;
|
||||
|
||||
BackupClient::BackupClient(
|
||||
std::string const& vaultUrl,
|
||||
std::shared_ptr<Core::Credentials::TokenCredential const> credential,
|
||||
BackupClientOptions options)
|
||||
: m_vaultBaseUrl(vaultUrl), m_apiVersion(options.ApiVersion)
|
||||
{
|
||||
std::vector<std::unique_ptr<HttpPolicy>> perRetrypolicies;
|
||||
{
|
||||
Azure::Core::Credentials::TokenRequestContext tokenContext;
|
||||
tokenContext.Scopes = {_internal::UrlScope::GetScopeFromUrl(m_vaultBaseUrl)};
|
||||
|
||||
perRetrypolicies.emplace_back(
|
||||
std::make_unique<_internal::KeyVaultChallengeBasedAuthenticationPolicy>(
|
||||
credential, std::move(tokenContext)));
|
||||
}
|
||||
std::vector<std::unique_ptr<HttpPolicy>> perCallpolicies;
|
||||
|
||||
m_pipeline = std::make_shared<Azure::Core::Http::_internal::HttpPipeline>(
|
||||
options,
|
||||
_detail::KeyVaultServicePackageName,
|
||||
_detail::PackageVersion::ToString(),
|
||||
std::move(perRetrypolicies),
|
||||
std::move(perCallpolicies));
|
||||
}
|
||||
|
||||
Azure::Response<BackupOperation> BackupClient::FullBackup(
|
||||
Azure::Core::Url const& blobContainerUrl,
|
||||
SasTokenParameter const& sasToken,
|
||||
Core::Context const& context)
|
||||
{
|
||||
auto url = m_vaultBaseUrl;
|
||||
url.AppendPath("backup");
|
||||
|
||||
url.SetQueryParameters({{"api-version", m_apiVersion}});
|
||||
|
||||
std::string jsonBody;
|
||||
{
|
||||
auto jsonRoot = Core::Json::_internal::json::object();
|
||||
|
||||
jsonRoot["storageResourceUri"] = blobContainerUrl.GetAbsoluteUrl();
|
||||
|
||||
if (sasToken.Token.HasValue())
|
||||
{
|
||||
jsonRoot["token"] = sasToken.Token.Value();
|
||||
}
|
||||
|
||||
if (sasToken.UseManagedIdentity.HasValue())
|
||||
{
|
||||
jsonRoot["useManagedIdentity"] = sasToken.UseManagedIdentity.Value();
|
||||
}
|
||||
|
||||
jsonBody = jsonRoot.dump();
|
||||
}
|
||||
|
||||
Core::IO::MemoryBodyStream requestBody(
|
||||
reinterpret_cast<std::uint8_t const*>(jsonBody.data()), jsonBody.length());
|
||||
|
||||
Core::Http::Request request(Core::Http::HttpMethod::Post, url, &requestBody);
|
||||
|
||||
request.SetHeader(HttpShared::ContentType, HttpShared::ApplicationJson);
|
||||
request.SetHeader(HttpShared::Accept, HttpShared::ApplicationJson);
|
||||
request.SetHeader("Content-Length", std::to_string(requestBody.Length()));
|
||||
|
||||
auto rawResponse = m_pipeline->Send(request, context);
|
||||
auto const httpStatusCode = rawResponse->GetStatusCode();
|
||||
|
||||
if (httpStatusCode != Core::Http::HttpStatusCode::Accepted)
|
||||
{
|
||||
throw Core::RequestFailedException(rawResponse);
|
||||
}
|
||||
|
||||
BackupOperationStatus response = DeserializeBackupOperationStatus(*rawResponse);
|
||||
BackupOperation operation(std::make_shared<BackupClient>(*this), std::move(response), true);
|
||||
return Response<BackupOperation>(std::move(operation), std::move(rawResponse));
|
||||
}
|
||||
|
||||
Azure::Response<BackupOperationStatus> BackupClient::FullBackupStatus(
|
||||
std::string const& jobId,
|
||||
Core::Context const& context)
|
||||
{
|
||||
auto url = m_vaultBaseUrl;
|
||||
url.AppendPath("backup");
|
||||
url.AppendPath(Core::Url::Encode(jobId));
|
||||
url.AppendPath("pending");
|
||||
|
||||
url.SetQueryParameters({{"api-version", m_apiVersion}});
|
||||
|
||||
Core::Http::Request request(Core::Http::HttpMethod::Get, url);
|
||||
request.SetHeader(HttpShared::ContentType, HttpShared::ApplicationJson);
|
||||
request.SetHeader(HttpShared::Accept, HttpShared::ApplicationJson);
|
||||
|
||||
auto rawResponse = m_pipeline->Send(request, context);
|
||||
auto const httpStatusCode = rawResponse->GetStatusCode();
|
||||
|
||||
if (httpStatusCode != Core::Http::HttpStatusCode::Ok)
|
||||
{
|
||||
throw Core::RequestFailedException(rawResponse);
|
||||
}
|
||||
|
||||
BackupOperationStatus response
|
||||
|
||||
= DeserializeBackupOperationStatus(*rawResponse);
|
||||
|
||||
return Response<BackupOperationStatus>(std::move(response), std::move(rawResponse));
|
||||
}
|
||||
|
||||
Azure::Response<BackupOperation> BackupClient::FullRestore(
|
||||
Azure::Core::Url const& blobContainerUrl,
|
||||
std::string folderToRestore,
|
||||
SasTokenParameter const& sasToken,
|
||||
Core::Context const& context)
|
||||
{
|
||||
auto url = m_vaultBaseUrl;
|
||||
url.AppendPath("restore");
|
||||
|
||||
url.SetQueryParameters({{"api-version", m_apiVersion}});
|
||||
|
||||
std::string jsonBody;
|
||||
{
|
||||
auto jsonRoot = Core::Json::_internal::json::object();
|
||||
|
||||
jsonRoot["sasTokenParameters"]["storageResourceUri"] = blobContainerUrl.GetAbsoluteUrl();
|
||||
|
||||
if (sasToken.Token.HasValue())
|
||||
{
|
||||
jsonRoot["sasTokenParameters"]["token"] = sasToken.Token.Value();
|
||||
}
|
||||
|
||||
if (sasToken.UseManagedIdentity.HasValue())
|
||||
{
|
||||
jsonRoot["sasTokenParameters"]["useManagedIdentity"] = sasToken.UseManagedIdentity.Value();
|
||||
}
|
||||
|
||||
jsonRoot["folderToRestore"] = folderToRestore;
|
||||
|
||||
jsonBody = jsonRoot.dump();
|
||||
}
|
||||
|
||||
Core::IO::MemoryBodyStream requestBody(
|
||||
reinterpret_cast<std::uint8_t const*>(jsonBody.data()), jsonBody.length());
|
||||
|
||||
Core::Http::Request request(Core::Http::HttpMethod::Put, url, &requestBody);
|
||||
|
||||
request.SetHeader("Content-Type", "application/json");
|
||||
request.SetHeader("Content-Length", std::to_string(requestBody.Length()));
|
||||
|
||||
auto rawResponse = m_pipeline->Send(request, context);
|
||||
auto const httpStatusCode = rawResponse->GetStatusCode();
|
||||
|
||||
if (httpStatusCode != Core::Http::HttpStatusCode::Accepted)
|
||||
{
|
||||
throw Core::RequestFailedException(rawResponse);
|
||||
}
|
||||
|
||||
BackupOperationStatus response = DeserializeBackupOperationStatus(*rawResponse);
|
||||
BackupOperation operation(std::make_shared<BackupClient>(*this), std::move(response), false);
|
||||
return Response<BackupOperation>(std::move(operation), std::move(rawResponse));
|
||||
}
|
||||
|
||||
Azure::Response<BackupOperationStatus> BackupClient::RestoreStatus(
|
||||
std::string const& jobId,
|
||||
Core::Context const& context)
|
||||
{
|
||||
auto url = m_vaultBaseUrl;
|
||||
url.AppendPath("restore");
|
||||
url.AppendPath(Core::Url::Encode(jobId));
|
||||
url.AppendPath("pending");
|
||||
|
||||
url.SetQueryParameters({{"api-version", "7.5"}});
|
||||
|
||||
Core::Http::Request request(Core::Http::HttpMethod::Get, url);
|
||||
|
||||
auto rawResponse = m_pipeline->Send(request, context);
|
||||
auto const httpStatusCode = rawResponse->GetStatusCode();
|
||||
|
||||
if (httpStatusCode != Core::Http::HttpStatusCode::Ok)
|
||||
{
|
||||
throw Core::RequestFailedException(rawResponse);
|
||||
}
|
||||
|
||||
BackupOperationStatus response = DeserializeBackupOperationStatus(*rawResponse);
|
||||
|
||||
return Response<BackupOperationStatus>(std::move(response), std::move(rawResponse));
|
||||
}
|
||||
|
||||
Azure::Response<BackupOperation> BackupClient::SelectiveKeyRestore(
|
||||
std::string const& keyName,
|
||||
Azure::Core::Url const& blobContainerUrl,
|
||||
std::string folderToRestore,
|
||||
SasTokenParameter const& sasToken,
|
||||
Core::Context const& context)
|
||||
{
|
||||
auto url = m_vaultBaseUrl;
|
||||
url.AppendPath("keys");
|
||||
url.AppendPath(Core::Url::Encode(keyName));
|
||||
url.AppendPath("restore");
|
||||
|
||||
url.SetQueryParameters({{"api-version", "7.5"}});
|
||||
|
||||
std::string jsonBody;
|
||||
{
|
||||
auto jsonRoot = Core::Json::_internal::json::object();
|
||||
|
||||
jsonRoot["sasTokenParameters"]["storageResourceUri"] = blobContainerUrl.GetAbsoluteUrl();
|
||||
|
||||
if (sasToken.Token.HasValue())
|
||||
{
|
||||
jsonRoot["sasTokenParameters"]["token"] = sasToken.Token.Value();
|
||||
}
|
||||
|
||||
if (sasToken.UseManagedIdentity.HasValue())
|
||||
{
|
||||
jsonRoot["sasTokenParameters"]["useManagedIdentity"] = sasToken.UseManagedIdentity.Value();
|
||||
}
|
||||
|
||||
jsonRoot["folder"] = folderToRestore;
|
||||
|
||||
jsonBody = jsonRoot.dump();
|
||||
}
|
||||
|
||||
Core::IO::MemoryBodyStream requestBody(
|
||||
reinterpret_cast<std::uint8_t const*>(jsonBody.data()), jsonBody.length());
|
||||
|
||||
Core::Http::Request request(Core::Http::HttpMethod::Put, url, &requestBody);
|
||||
|
||||
request.SetHeader("Content-Type", "application/json");
|
||||
request.SetHeader("Content-Length", std::to_string(requestBody.Length()));
|
||||
|
||||
auto rawResponse = m_pipeline->Send(request, context);
|
||||
auto const httpStatusCode = rawResponse->GetStatusCode();
|
||||
|
||||
if (httpStatusCode != Core::Http::HttpStatusCode::Accepted)
|
||||
{
|
||||
throw Core::RequestFailedException(rawResponse);
|
||||
}
|
||||
|
||||
BackupOperationStatus response = DeserializeBackupOperationStatus(*rawResponse);
|
||||
BackupOperation operation(std::make_shared<BackupClient>(*this), std::move(response), false);
|
||||
return Response<BackupOperation>(std::move(operation), std::move(rawResponse));
|
||||
}
|
||||
|
||||
BackupOperationStatus BackupClient::DeserializeBackupOperationStatus(
|
||||
Azure::Core::Http::RawResponse const& rawResponse)
|
||||
{
|
||||
BackupOperationStatus response{};
|
||||
auto const& responseBody = rawResponse.GetBody();
|
||||
if (responseBody.size() > 0)
|
||||
{
|
||||
auto const jsonRoot
|
||||
= Core::Json::_internal::json::parse(responseBody.begin(), responseBody.end());
|
||||
|
||||
response.Status = jsonRoot["status"].get<std::string>();
|
||||
|
||||
if (jsonRoot.contains("statusDetails") && !jsonRoot["statusDetails"].is_null())
|
||||
{
|
||||
response.StatusDetails = jsonRoot["statusDetails"].get<std::string>();
|
||||
}
|
||||
|
||||
response.StartTime = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
|
||||
jsonRoot["startTime"].is_string() ? std::stoll(jsonRoot["startTime"].get<std::string>())
|
||||
: jsonRoot["startTime"].get<std::int64_t>());
|
||||
|
||||
if (jsonRoot.contains("endTime") && !jsonRoot["endTime"].is_null())
|
||||
{
|
||||
response.EndTime = Core::_internal::PosixTimeConverter::PosixTimeToDateTime(
|
||||
jsonRoot["endTime"].is_string() ? std::stoll(jsonRoot["endTime"].get<std::string>())
|
||||
: jsonRoot["endTime"].get<std::int64_t>());
|
||||
}
|
||||
|
||||
response.JobId = jsonRoot["jobId"].get<std::string>();
|
||||
|
||||
if (jsonRoot.contains("azureStorageBlobContainerUri")
|
||||
&& !jsonRoot["azureStorageBlobContainerUri"].is_null())
|
||||
{
|
||||
response.AzureStorageBlobContainerUri
|
||||
= jsonRoot["azureStorageBlobContainerUri"].get<std::string>();
|
||||
}
|
||||
|
||||
if (jsonRoot.contains("error") && !jsonRoot["error"].is_null())
|
||||
{
|
||||
response.Error = DeserializeKeyVaultServiceError(jsonRoot["error"]);
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
KeyVaultServiceError BackupClient::DeserializeKeyVaultServiceError(
|
||||
Azure::Core::Json::_internal::json errorFragment)
|
||||
{
|
||||
KeyVaultServiceError result;
|
||||
if (errorFragment.contains("code"))
|
||||
{
|
||||
result.Code = errorFragment["code"].get<std::string>();
|
||||
}
|
||||
if (errorFragment.contains("message"))
|
||||
{
|
||||
result.Message = errorFragment["message"].get<std::string>();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
// Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
|
||||
#include "azure/keyvault/administration/backup_operation.hpp"
|
||||
|
||||
#include "azure/keyvault/administration/backup_client.hpp"
|
||||
|
||||
using namespace Azure::Security::KeyVault::Administration;
|
||||
|
||||
std::unique_ptr<Azure::Core::Http::RawResponse> BackupOperation::PollInternal(
|
||||
Azure::Core::Context const& context)
|
||||
{
|
||||
std::unique_ptr<Azure::Core::Http::RawResponse> rawResponse;
|
||||
try
|
||||
{
|
||||
Azure::Response<BackupOperationStatus> response = m_isBackupOperation
|
||||
? m_backupClient->FullBackupStatus(m_continuationToken, context)
|
||||
: m_backupClient->RestoreStatus(m_continuationToken, context);
|
||||
|
||||
m_value = response.Value;
|
||||
m_continuationToken = response.Value.JobId;
|
||||
rawResponse = std::move(response.RawResponse);
|
||||
if (response.Value.Status == "InProgress")
|
||||
{
|
||||
m_status = Azure::Core::OperationStatus::Running;
|
||||
}
|
||||
else if (response.Value.Status == "Succeeded")
|
||||
{
|
||||
m_status = Azure::Core::OperationStatus::Succeeded;
|
||||
}
|
||||
else if (response.Value.Status == "Failed")
|
||||
{
|
||||
m_status = Azure::Core::OperationStatus::Failed;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw Azure::Core::RequestFailedException(response.RawResponse);
|
||||
}
|
||||
}
|
||||
catch (Azure::Core::RequestFailedException& error)
|
||||
{
|
||||
rawResponse = std::move(error.RawResponse);
|
||||
}
|
||||
|
||||
return rawResponse;
|
||||
}
|
||||
|
||||
Azure::Response<BackupOperationStatus> BackupOperation::PollUntilDoneInternal(
|
||||
std::chrono::milliseconds period,
|
||||
Azure::Core::Context& context)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// Poll will update the raw response.
|
||||
Poll(context);
|
||||
if (IsDone())
|
||||
{
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(period);
|
||||
}
|
||||
|
||||
return Azure::Response<BackupOperationStatus>(
|
||||
m_value, std::make_unique<Azure::Core::Http::RawResponse>(*m_rawResponse));
|
||||
}
|
||||
@ -17,10 +17,11 @@ add_compile_definitions(AZURE_TEST_RECORDING_DIR="${CMAKE_CURRENT_LIST_DIR}")
|
||||
|
||||
add_executable (
|
||||
azure-security-keyvault-administration-test
|
||||
backup_restore_client_base_test.hpp
|
||||
backup_restore_client_test.cpp
|
||||
macro_guard.cpp
|
||||
settings_client_base_test.hpp
|
||||
settings_client_test.cpp
|
||||
)
|
||||
settings_client_test.cpp)
|
||||
|
||||
target_compile_definitions(azure-security-keyvault-administration-test PRIVATE _azure_BUILDING_TESTS)
|
||||
|
||||
|
||||
@ -0,0 +1,115 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief The base class to construct and init a Key Vault client.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <azure/core/test/test_base.hpp>
|
||||
#include <azure/identity/client_secret_credential.hpp>
|
||||
#include <azure/keyvault/administration.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace Azure {
|
||||
namespace Security {
|
||||
namespace KeyVault {
|
||||
namespace Administration {
|
||||
namespace Test {
|
||||
|
||||
class BackupRestoreClientTest : public Azure::Core::Test::TestBase,
|
||||
public ::testing::WithParamInterface<int> {
|
||||
|
||||
public:
|
||||
BackupRestoreClientTest() { TestBase::SetUpTestSuiteLocal(AZURE_TEST_ASSETS_DIR); }
|
||||
void CreateHSMClientForTest(std::string hsmUrl = "")
|
||||
{
|
||||
BackupClientOptions options;
|
||||
m_client = InitTestClient<
|
||||
Azure::Security::KeyVault::Administration::BackupClient,
|
||||
Azure::Security::KeyVault::Administration::Models::BackupClientOptions>(
|
||||
hsmUrl.length() == 0 ? m_keyVaultHsmUrl : hsmUrl, m_credential, options);
|
||||
}
|
||||
|
||||
SasTokenParameter GetSasTokenBackup(bool managedIdentity = false)
|
||||
{
|
||||
SasTokenParameter sasTokenParameter;
|
||||
// the backup/restore needs a SAS token to access the storage account
|
||||
sasTokenParameter.Token = GetEnv("AZURE_KEYVAULT_BACKUP_TOKEN");
|
||||
// the backup/restore needs a url to a blob storage resource
|
||||
m_blobUrl = Azure::Core::Url(GetEnv("AZURE_KEYVAULT_BACKUP_URL"));
|
||||
|
||||
sasTokenParameter.UseManagedIdentity = managedIdentity;
|
||||
return sasTokenParameter;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Azure::Security::KeyVault::Administration::BackupClient> m_client;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Azure::Core::Credentials::TokenCredential> m_credential;
|
||||
std::string m_keyVaultUrl;
|
||||
std::string m_keyVaultHsmUrl;
|
||||
Azure::Core::Url m_blobUrl;
|
||||
std::chrono::milliseconds m_testPollingIntervalMs = std::chrono::seconds(1);
|
||||
|
||||
// Reads the current test instance name.
|
||||
// Name gets also sanitized (special chars are removed) to avoid issues when recording or
|
||||
// creating. This also return the name with suffix if the "AZURE_LIVE_TEST_SUFFIX" exists.
|
||||
std::string GetTestName(bool sanitize = true)
|
||||
{
|
||||
auto output = m_keyVaultUrl.compare(m_keyVaultHsmUrl) == 0 ? "Same" : "NotSame";
|
||||
std::cout << "\n Keyvault and HSM are" << output;
|
||||
return Azure::Core::Test::TestBase::GetTestNameSuffix(sanitize);
|
||||
}
|
||||
|
||||
Azure::Security::KeyVault::Administration::BackupClient& GetClientForTest(
|
||||
std::string const& testName)
|
||||
{
|
||||
// set the interceptor for the current test
|
||||
m_testContext.RenameTest(testName);
|
||||
return *m_client;
|
||||
}
|
||||
|
||||
// Create
|
||||
virtual void SetUp() override
|
||||
{
|
||||
Azure::Core::Test::TestBase::SetUpTestBase(AZURE_TEST_RECORDING_DIR);
|
||||
m_keyVaultUrl = GetEnv("AZURE_KEYVAULT_URL");
|
||||
m_keyVaultHsmUrl = GetEnv("AZURE_KEYVAULT_HSM_URL");
|
||||
|
||||
// Options and credential for the client
|
||||
BackupClientOptions options;
|
||||
m_credential = GetTestCredential();
|
||||
|
||||
// `InitTestClient` takes care of setting up Record&Playback.
|
||||
m_client = InitTestClient<
|
||||
Azure::Security::KeyVault::Administration::BackupClient,
|
||||
Azure::Security::KeyVault::Administration::Models::BackupClientOptions>(
|
||||
m_keyVaultUrl, m_credential, options);
|
||||
|
||||
UpdateWaitingTime(m_testPollingIntervalMs);
|
||||
}
|
||||
|
||||
public:
|
||||
template <class T>
|
||||
static inline void CheckValidResponse(
|
||||
Azure::Response<T>& response,
|
||||
Azure::Core::Http::HttpStatusCode expectedCode = Azure::Core::Http::HttpStatusCode::Ok)
|
||||
{
|
||||
auto const& rawResponse = response.RawResponse;
|
||||
EXPECT_EQ(
|
||||
static_cast<typename std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
|
||||
rawResponse->GetStatusCode()),
|
||||
static_cast<typename std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
|
||||
expectedCode));
|
||||
}
|
||||
|
||||
static inline std::string GetUniqueName() { return Azure::Core::Uuid::CreateUuid().ToString(); }
|
||||
};
|
||||
}}}}} // namespace Azure::Security::KeyVault::Administration::Test
|
||||
@ -0,0 +1,310 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include "azure/keyvault/administration/backup_client.hpp"
|
||||
#include "backup_restore_client_base_test.hpp"
|
||||
|
||||
#include <azure/core/base64.hpp>
|
||||
#include <azure/identity/client_secret_credential.hpp>
|
||||
#include <azure/keyvault/administration/rest_client_models.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace Azure::Security::KeyVault::Administration;
|
||||
using namespace Azure::Security::KeyVault::Administration::Models;
|
||||
using namespace Azure::Security::KeyVault::Administration::Test;
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
TEST_F(BackupRestoreClientTest, BackupFull_RECORDEDONLY_)
|
||||
{
|
||||
if (m_keyVaultHsmUrl != m_keyVaultUrl)
|
||||
{
|
||||
auto testName = "BackupFull";
|
||||
CreateHSMClientForTest();
|
||||
auto& client = GetClientForTest(testName);
|
||||
SasTokenParameter sasTokenParameter = GetSasTokenBackup();
|
||||
|
||||
auto response = client.FullBackup(m_blobUrl, sasTokenParameter).Value;
|
||||
EXPECT_EQ(response.Value().Status, "InProgress");
|
||||
EXPECT_TRUE(response.Value().StartTime > response.Value().StartTime.min());
|
||||
EXPECT_FALSE(response.Value().EndTime.HasValue());
|
||||
EXPECT_FALSE(response.Value().Error.HasValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
SkipTest();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BackupRestoreClientTest, BackupFullStatus_RECORDEDONLY_)
|
||||
{
|
||||
if (m_keyVaultHsmUrl != m_keyVaultUrl)
|
||||
{
|
||||
auto testName = "BackupFullStatus";
|
||||
CreateHSMClientForTest();
|
||||
auto& client = GetClientForTest(testName);
|
||||
SasTokenParameter sasTokenParameter = GetSasTokenBackup();
|
||||
|
||||
auto response = client.FullBackup(m_blobUrl, sasTokenParameter).Value;
|
||||
|
||||
EXPECT_EQ(response.Value().Status, "InProgress");
|
||||
EXPECT_TRUE(response.Value().StartTime > response.Value().StartTime.min());
|
||||
EXPECT_FALSE(response.Value().EndTime.HasValue());
|
||||
EXPECT_FALSE(response.Value().Error.HasValue());
|
||||
auto response2 = response.PollUntilDone(m_testPollingIntervalMs);
|
||||
EXPECT_EQ(response2.Value.Status, "Succeeded");
|
||||
EXPECT_TRUE(response2.Value.EndTime.Value() > response2.Value.StartTime);
|
||||
EXPECT_FALSE(response2.Value.Error.HasValue());
|
||||
EXPECT_EQ(response.Value().JobId, response2.Value.JobId);
|
||||
}
|
||||
else
|
||||
{
|
||||
SkipTest();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BackupRestoreClientTest, BackupFullStatusEmptyJobId_RECORDEDONLY_)
|
||||
{
|
||||
if (m_keyVaultHsmUrl != m_keyVaultUrl)
|
||||
{
|
||||
auto testName = "BackupFullStatusEmptyJobId";
|
||||
CreateHSMClientForTest();
|
||||
auto& client = GetClientForTest(testName);
|
||||
SasTokenParameter sasTokenParameter = GetSasTokenBackup();
|
||||
|
||||
try
|
||||
{
|
||||
auto response2 = client.FullBackupStatus().Value;
|
||||
}
|
||||
catch (Azure::Core::RequestFailedException& e)
|
||||
{
|
||||
EXPECT_EQ(e.RawResponse->GetStatusCode(), Azure::Core::Http::HttpStatusCode::NotFound);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SkipTest();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BackupRestoreClientTest, RestoreStatusEmptyJobId_RECORDEDONLY_)
|
||||
{
|
||||
if (m_keyVaultHsmUrl != m_keyVaultUrl)
|
||||
{
|
||||
auto testName = "RestoreStatusEmptyJobId";
|
||||
CreateHSMClientForTest();
|
||||
auto& client = GetClientForTest(testName);
|
||||
SasTokenParameter sasTokenParameter = GetSasTokenBackup();
|
||||
|
||||
try
|
||||
{
|
||||
auto response2 = client.RestoreStatus().Value;
|
||||
}
|
||||
catch (Azure::Core::RequestFailedException& e)
|
||||
{
|
||||
EXPECT_EQ(e.RawResponse->GetStatusCode(), Azure::Core::Http::HttpStatusCode::NotFound);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SkipTest();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BackupRestoreClientTest, BackupFullErrorStatus_RECORDEDONLY_)
|
||||
{
|
||||
if (m_keyVaultHsmUrl != m_keyVaultUrl)
|
||||
{
|
||||
auto testName = "BackupFullErrorStatus";
|
||||
CreateHSMClientForTest();
|
||||
auto& client = GetClientForTest(testName);
|
||||
SasTokenParameter sasTokenParameter = GetSasTokenBackup();
|
||||
Azure::Core::Url defectiveUrl(
|
||||
m_blobUrl.GetScheme() + "://" + m_blobUrl.GetHost()); // invalid uri
|
||||
auto response = client.FullBackup(defectiveUrl, sasTokenParameter).Value;
|
||||
|
||||
EXPECT_EQ(response.Value().Status, "InProgress");
|
||||
EXPECT_TRUE(response.Value().StartTime > response.Value().StartTime.min());
|
||||
EXPECT_FALSE(response.Value().EndTime.HasValue());
|
||||
EXPECT_FALSE(response.Value().Error.HasValue());
|
||||
|
||||
response.PollUntilDone(m_testPollingIntervalMs);
|
||||
EXPECT_EQ(response.Value().Status, "Failed");
|
||||
EXPECT_TRUE(response.Value().EndTime.Value() > response.Value().StartTime);
|
||||
EXPECT_EQ(response.Value().StatusDetails.Value(), "InvalidQueryParameterValue");
|
||||
EXPECT_EQ(response.Value().Error.Value().Code, "InvalidQueryParameterValue");
|
||||
}
|
||||
else
|
||||
{
|
||||
SkipTest();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BackupRestoreClientTest, RestoreFull_RECORDEDONLY_)
|
||||
{
|
||||
if (m_keyVaultHsmUrl != m_keyVaultUrl)
|
||||
{
|
||||
auto testName = "RestoreFull";
|
||||
CreateHSMClientForTest();
|
||||
auto& client = GetClientForTest(testName);
|
||||
SasTokenParameter sasTokenParameter = GetSasTokenBackup();
|
||||
|
||||
auto response = client.FullBackup(m_blobUrl, sasTokenParameter).Value;
|
||||
|
||||
EXPECT_EQ(response.Value().Status, "InProgress");
|
||||
EXPECT_TRUE(response.Value().StartTime > response.Value().StartTime.min());
|
||||
EXPECT_FALSE(response.Value().EndTime.HasValue());
|
||||
EXPECT_FALSE(response.Value().Error.HasValue());
|
||||
auto response2 = response.PollUntilDone(m_testPollingIntervalMs);
|
||||
EXPECT_EQ(response2.Value.Status, "Succeeded");
|
||||
EXPECT_TRUE(response2.Value.EndTime.Value() > response2.Value.StartTime);
|
||||
EXPECT_FALSE(response2.Value.Error.HasValue());
|
||||
EXPECT_EQ(response.Value().JobId, response2.Value.JobId);
|
||||
|
||||
Azure::Core::Url url(response2.Value.AzureStorageBlobContainerUri);
|
||||
auto subPath = url.GetPath();
|
||||
std::string folderToRestore = subPath.substr(7, subPath.size() - 1);
|
||||
|
||||
auto response3 = client.FullRestore(m_blobUrl, folderToRestore, sasTokenParameter).Value;
|
||||
EXPECT_EQ(response3.Value().Status, "InProgress");
|
||||
EXPECT_TRUE(response3.Value().StartTime > response3.Value().StartTime.min());
|
||||
EXPECT_FALSE(response3.Value().EndTime.HasValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
SkipTest();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BackupRestoreClientTest, RestoreFullStatus_RECORDEDONLY_)
|
||||
{
|
||||
if (m_keyVaultHsmUrl != m_keyVaultUrl)
|
||||
{
|
||||
auto testName = "RestoreFullStatus";
|
||||
CreateHSMClientForTest();
|
||||
auto& client = GetClientForTest(testName);
|
||||
SasTokenParameter sasTokenParameter = GetSasTokenBackup();
|
||||
|
||||
auto response = client.FullBackup(m_blobUrl, sasTokenParameter).Value;
|
||||
|
||||
EXPECT_EQ(response.Value().Status, "InProgress");
|
||||
EXPECT_TRUE(response.Value().StartTime > response.Value().StartTime.min());
|
||||
EXPECT_FALSE(response.Value().EndTime.HasValue());
|
||||
EXPECT_FALSE(response.Value().Error.HasValue());
|
||||
auto response2 = response.PollUntilDone(m_testPollingIntervalMs);
|
||||
EXPECT_EQ(response2.Value.Status, "Succeeded");
|
||||
EXPECT_TRUE(response2.Value.EndTime.Value() > response2.Value.StartTime);
|
||||
EXPECT_FALSE(response2.Value.Error.HasValue());
|
||||
EXPECT_EQ(response.Value().JobId, response2.Value.JobId);
|
||||
|
||||
Azure::Core::Url url(response2.Value.AzureStorageBlobContainerUri);
|
||||
auto subPath = url.GetPath();
|
||||
std::string folderToRestore = subPath.substr(7, subPath.size() - 1);
|
||||
|
||||
auto response3 = client.FullRestore(m_blobUrl, folderToRestore, sasTokenParameter).Value;
|
||||
EXPECT_EQ(response3.Value().Status, "InProgress");
|
||||
EXPECT_TRUE(response3.Value().StartTime > response3.Value().StartTime.min());
|
||||
EXPECT_FALSE(response3.Value().EndTime.HasValue());
|
||||
auto response4 = response3.PollUntilDone(m_testPollingIntervalMs);
|
||||
EXPECT_EQ(response4.Value.Status, "Succeeded");
|
||||
EXPECT_TRUE(response4.Value.EndTime.Value() > response4.Value.StartTime);
|
||||
EXPECT_FALSE(response4.Value.Error.HasValue());
|
||||
EXPECT_EQ(response3.Value().JobId, response4.Value.JobId);
|
||||
}
|
||||
else
|
||||
{
|
||||
SkipTest();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BackupRestoreClientTest, RestoreSelectiveStatus_RECORDEDONLY_)
|
||||
{
|
||||
if (m_keyVaultHsmUrl != m_keyVaultUrl)
|
||||
{
|
||||
auto testName = "RestoreSelectiveStatus";
|
||||
CreateHSMClientForTest();
|
||||
auto& client = GetClientForTest(testName);
|
||||
SasTokenParameter sasTokenParameter = GetSasTokenBackup();
|
||||
|
||||
auto response = client.FullBackup(m_blobUrl, sasTokenParameter).Value;
|
||||
|
||||
EXPECT_EQ(response.Value().Status, "InProgress");
|
||||
EXPECT_TRUE(response.Value().StartTime > response.Value().StartTime.min());
|
||||
EXPECT_FALSE(response.Value().EndTime.HasValue());
|
||||
EXPECT_FALSE(response.Value().Error.HasValue());
|
||||
auto response2 = response.PollUntilDone(m_testPollingIntervalMs);
|
||||
EXPECT_EQ(response2.Value.Status, "Succeeded");
|
||||
EXPECT_TRUE(response2.Value.EndTime.Value() > response2.Value.StartTime);
|
||||
EXPECT_FALSE(response2.Value.Error.HasValue());
|
||||
EXPECT_EQ(response.Value().JobId, response2.Value.JobId);
|
||||
|
||||
Azure::Core::Url url(response2.Value.AzureStorageBlobContainerUri);
|
||||
auto subPath = url.GetPath();
|
||||
std::string folderToRestore = subPath.substr(7, subPath.size() - 1);
|
||||
|
||||
auto response3
|
||||
= client.SelectiveKeyRestore("trytry", m_blobUrl, folderToRestore, sasTokenParameter).Value;
|
||||
EXPECT_EQ(response3.Value().Status, "InProgress");
|
||||
EXPECT_TRUE(response3.Value().StartTime > response3.Value().StartTime.min());
|
||||
EXPECT_FALSE(response3.Value().EndTime.HasValue());
|
||||
auto response4 = response3.PollUntilDone(m_testPollingIntervalMs);
|
||||
EXPECT_EQ(response4.Value.Status, "Succeeded");
|
||||
EXPECT_TRUE(response4.Value.EndTime.Value() > response4.Value.StartTime);
|
||||
EXPECT_FALSE(response4.Value.Error.HasValue());
|
||||
EXPECT_EQ(response3.Value().JobId, response4.Value.JobId);
|
||||
}
|
||||
else
|
||||
{
|
||||
SkipTest();
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(BackupRestoreClientTest, RestoreSelectiveInvalidKeyStatus_RECORDEDONLY_)
|
||||
{
|
||||
if (m_keyVaultHsmUrl != m_keyVaultUrl)
|
||||
{
|
||||
auto testName = "RestoreSelectiveInvalidKeyStatus";
|
||||
CreateHSMClientForTest();
|
||||
auto& client = GetClientForTest(testName);
|
||||
SasTokenParameter sasTokenParameter = GetSasTokenBackup();
|
||||
|
||||
auto response = client.FullBackup(m_blobUrl, sasTokenParameter).Value;
|
||||
|
||||
EXPECT_EQ(response.Value().Status, "InProgress");
|
||||
EXPECT_TRUE(response.Value().StartTime > response.Value().StartTime.min());
|
||||
EXPECT_FALSE(response.Value().EndTime.HasValue());
|
||||
EXPECT_FALSE(response.Value().Error.HasValue());
|
||||
auto response2 = response.PollUntilDone(m_testPollingIntervalMs);
|
||||
EXPECT_EQ(response2.Value.Status, "Succeeded");
|
||||
EXPECT_TRUE(response2.Value.EndTime.Value() > response2.Value.StartTime);
|
||||
EXPECT_FALSE(response2.Value.Error.HasValue());
|
||||
EXPECT_EQ(response.Value().JobId, response2.Value.JobId);
|
||||
|
||||
Azure::Core::Url url(response2.Value.AzureStorageBlobContainerUri);
|
||||
auto subPath = url.GetPath();
|
||||
std::string folderToRestore = subPath.substr(7, subPath.size() - 1);
|
||||
|
||||
auto response3
|
||||
= client.SelectiveKeyRestore("trytry2", m_blobUrl, folderToRestore, sasTokenParameter)
|
||||
.Value;
|
||||
EXPECT_EQ(response3.Value().Status, "InProgress");
|
||||
EXPECT_TRUE(response3.Value().StartTime > response3.Value().StartTime.min());
|
||||
EXPECT_FALSE(response3.Value().EndTime.HasValue());
|
||||
auto response4 = response3.PollUntilDone(m_testPollingIntervalMs);
|
||||
EXPECT_EQ(response4.Value.Status, "Failed");
|
||||
EXPECT_TRUE(response4.Value.EndTime.Value() > response4.Value.StartTime);
|
||||
EXPECT_EQ(response4.Value.StatusDetails.Value(), "The given key or its versions NOT found");
|
||||
EXPECT_EQ(response3.Value().JobId, response4.Value.JobId);
|
||||
EXPECT_EQ(response4.Value.Error.Value().Message, "The given key or its versions NOT found");
|
||||
EXPECT_EQ(response4.Value.Error.Value().Code, "No key versions are updated");
|
||||
}
|
||||
else
|
||||
{
|
||||
SkipTest();
|
||||
}
|
||||
}
|
||||
@ -77,6 +77,10 @@ extends:
|
||||
Value: "debug"
|
||||
- Name: LOGGING__LOGLEVEL__MICROSOFT
|
||||
Value: "debug"
|
||||
- Name: AZURE_KEYVAULT_BACKUP_TOKEN
|
||||
Value: "Sanitized"
|
||||
- Name: AZURE_KEYVAULT_BACKUP_URL
|
||||
Value: "https://non-real-account.blob.core.windows.net/backup"
|
||||
CMakeTestOptions:
|
||||
- Name: Default
|
||||
Value: ''
|
||||
|
||||
Loading…
Reference in New Issue
Block a user