Skip to content

Commit

Permalink
Implement full vault backup and restore (#13525)
Browse files Browse the repository at this point in the history
  • Loading branch information
chlowell authored Sep 4, 2020
1 parent da8400a commit 27eead3
Show file tree
Hide file tree
Showing 8 changed files with 290 additions and 4 deletions.
6 changes: 5 additions & 1 deletion sdk/keyvault/azure-keyvault-administration/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Release History

## 1.0.0b1 (Unreleased)
## 4.0.0b1 (2020-09-08)
### Added
- `KeyVaultAccessControlClient` performs role-based access control operations
- `KeyVaultBackupClient` performs full vault backup and full and selective
restore operations
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,28 @@
# Licensed under the MIT License.
# ------------------------------------
from ._access_control_client import KeyVaultAccessControlClient
from ._backup_client import KeyVaultBackupClient
from ._internal.client_base import ApiVersion
from ._models import (
KeyVaultPermission, KeyVaultRoleAssignment, KeyVaultRoleDefinition, KeyVaultRoleScope
BackupOperation,
KeyVaultPermission,
KeyVaultRoleAssignment,
KeyVaultRoleDefinition,
KeyVaultRoleScope,
RestoreOperation,
SelectiveKeyRestoreOperation,
)


__all__ = [
"ApiVersion",
"BackupOperation",
"KeyVaultAccessControlClient",
"KeyVaultBackupClient",
"KeyVaultPermission",
"KeyVaultRoleAssignment",
"KeyVaultRoleDefinition",
"KeyVaultRoleScope",
"RestoreOperation",
"SelectiveKeyRestoreOperation",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# ------------------------------------
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# ------------------------------------
from typing import TYPE_CHECKING

from azure.core.polling.base_polling import LROBasePolling

from ._models import BackupOperation, RestoreOperation, SelectiveKeyRestoreOperation
from ._internal import KeyVaultClientBase
from ._internal.polling import KeyVaultBackupClientPolling

if TYPE_CHECKING:
# pylint:disable=unused-import
from typing import Any
from azure.core.polling import LROPoller


class KeyVaultBackupClient(KeyVaultClientBase):
"""Performs Key Vault backup and restore operations.
:param str vault_url: URL of the vault on which the client will operate. This is also called the vault's "DNS Name".
:param credential: an object which can provide an access token for the vault, such as a credential from
:mod:`azure.identity`
"""

# pylint:disable=protected-access
def begin_full_backup(self, blob_storage_uri, sas_token, **kwargs):
# type: (str, str, **Any) -> LROPoller[BackupOperation]
"""Begin a full backup of the Key Vault.
:param str blob_storage_uri: URI of the blob storage resource in which the backup will be stored
:param str sas_token: a Shared Access Signature (SAS) token authorizing access to the blob storage resource
:keyword str continuation_token: a continuation token to restart polling from a saved state
:returns: An instance of an LROPoller. Call `result()` on the poller object to get a :class:`BackupOperation`.
:rtype: ~azure.core.polling.LROPoller[BackupOperation]
"""
polling_interval = kwargs.pop("_polling_interval", 5)
sas_parameter = self._models.SASTokenParameter(storage_resource_uri=blob_storage_uri, token=sas_token)
return self._client.begin_full_backup(
vault_base_url=self._vault_url,
azure_storage_blob_container_uri=sas_parameter,
cls=BackupOperation._wrap_generated,
continuation_token=kwargs.pop("continuation_token", None),
polling=LROBasePolling(lro_algorithms=[KeyVaultBackupClientPolling()], timeout=polling_interval, **kwargs),
**kwargs
)

def begin_full_restore(self, blob_storage_uri, sas_token, folder_name, **kwargs):
# type: (str, str, str, **Any) -> LROPoller[RestoreOperation]
"""Restore a full backup of a Key Vault.
:param str blob_storage_uri: URI of the blob storage resource in which the backup is stored
:param str sas_token: a Shared Access Signature (SAS) token authorizing access to the blob storage resource
:param str folder_name: name of the blob container which contains the backup
:rtype: ~azure.core.polling.LROPoller[RestoreOperation]
"""
polling_interval = kwargs.pop("_polling_interval", 5)
sas_parameter = self._models.SASTokenParameter(storage_resource_uri=blob_storage_uri, token=sas_token)
restore_details = self._models.RestoreOperationParameters(
sas_token_parameters=sas_parameter, folder_to_restore=folder_name,
)
return self._client.begin_full_restore_operation(
vault_base_url=self._vault_url,
restore_blob_details=restore_details,
cls=RestoreOperation._wrap_generated,
continuation_token=kwargs.pop("continuation_token", None),
polling=LROBasePolling(lro_algorithms=[KeyVaultBackupClientPolling()], timeout=polling_interval, **kwargs),
**kwargs
)

def begin_selective_restore(self, blob_storage_uri, sas_token, folder_name, key_name, **kwargs):
# type: (str, str, str, str, **Any) -> LROPoller[SelectiveKeyRestoreOperation]
"""Restore a single key from a full Key Vault backup.
:param str blob_storage_uri: URI of the blob storage resource in which the backup is stored
:param str sas_token: a Shared Access Signature (SAS) token authorizing access to the blob storage resource
:param str folder_name: name of the blob container which contains the backup
:param str key_name: name of the key to restore from the backup
:rtype: ~azure.core.polling.LROPoller[RestoreOperation]
"""
polling_interval = kwargs.pop("_polling_interval", 5)
sas_parameter = self._models.SASTokenParameter(storage_resource_uri=blob_storage_uri, token=sas_token)
restore_details = self._models.SelectiveKeyRestoreOperationParameters(
sas_token_parameters=sas_parameter, folder=folder_name,
)
return self._client.begin_selective_key_restore_operation(
vault_base_url=self._vault_url,
key_name=key_name,
restore_blob_details=restore_details,
cls=SelectiveKeyRestoreOperation._wrap_generated,
continuation_token=kwargs.pop("continuation_token", None),
polling=LROBasePolling(lro_algorithms=[KeyVaultBackupClientPolling()], timeout=polling_interval, **kwargs),
**kwargs
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# ------------------------------------
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# ------------------------------------
from azure.core.polling.base_polling import OperationResourcePolling


class KeyVaultBackupClientPolling(OperationResourcePolling):
def __init__(self):
super(KeyVaultBackupClientPolling, self).__init__(operation_location_header="azure-asyncoperation")

def get_final_get_url(self, pipeline_response):
return None
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,61 @@ def _from_generated(cls, definition):
role_type=definition.role_type,
type=definition.type,
)


class _Operation(object):
def __init__(self, **kwargs):
self.status = kwargs.get("status", None)
self.status_details = kwargs.get("status_details", None)
self.error = kwargs.get("error", None)
self.start_time = kwargs.get("start_time", None)
self.end_time = kwargs.get("end_time", None)
self.id = kwargs.get("job_id", None)

@classmethod
def _wrap_generated(cls, response, deserialized_operation, response_headers): # pylint:disable=unused-argument
return cls(**deserialized_operation.__dict__)


class BackupOperation(_Operation):
"""A Key Vault full backup operation.
:ivar str status: status of the backup operation
:ivar str status_details: more details of the operation's status
:ivar error: Error encountered, if any, during the operation
:type error: ~key_vault_client.models.Error
:ivar datetime.datetime start_time: UTC start time of the operation
:ivar datetime.datetime end_time: UTC end time of the operation
:ivar str job_id: identifier for the operation
:ivar str azure_storage_blob_container_uri: URI of the Azure blob storage container which contains the backup
"""

def __init__(self, **kwargs):
self.azure_storage_blob_container_uri = kwargs.pop("azure_storage_blob_container_uri", None)
super(BackupOperation, self).__init__(**kwargs)


class RestoreOperation(_Operation):
"""A Key Vault restore operation.
:ivar str status: status of the operation
:ivar str status_details: more details of the operation's status
:ivar error: Error encountered, if any, during the operation
:type error: ~key_vault_client.models.Error
:ivar datetime.datetime start_time: UTC start time of the operation
:ivar datetime.datetime end_time: UTC end time of the operation
:ivar str job_id: identifier for the operation
"""


class SelectiveKeyRestoreOperation(_Operation):
"""A Key Vault operation restoring a single key.
:ivar str status: status of the operation
:ivar str status_details: more details of the operation's status
:ivar error: Error encountered, if any, during the operation
:type error: ~key_vault_client.models.Error
:ivar datetime.datetime start_time: UTC start time of the operation
:ivar datetime.datetime end_time: UTC end time of the operation
:ivar str job_id: identifier for the operation
"""
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
# Licensed under the MIT License.
# ------------------------------------

VERSION = "1.0.0b1"
VERSION = "4.0.0b1"
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
# Licensed under the MIT License.
# ------------------------------------
from ._access_control_client import KeyVaultAccessControlClient
from ._backup_client import KeyVaultBackupClient

__all__ = ["KeyVaultAccessControlClient"]
__all__ = ["KeyVaultAccessControlClient", "KeyVaultBackupClient"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# ------------------------------------
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
# ------------------------------------
from typing import TYPE_CHECKING

from azure.core.polling.async_base_polling import AsyncLROBasePolling

from .._internal import AsyncKeyVaultClientBase
from .._internal.polling import KeyVaultBackupClientPolling
from .._models import BackupOperation, RestoreOperation, SelectiveKeyRestoreOperation

if TYPE_CHECKING:
# pylint:disable=unused-import
from typing import Any
from azure.core.polling import AsyncLROPoller


class KeyVaultBackupClient(AsyncKeyVaultClientBase):
"""Performs Key Vault backup and restore operations.
:param str vault_url: URL of the vault on which the client will operate. This is also called the vault's "DNS Name".
:param credential: an object which can provide an access token for the vault, such as a credential from
:mod:`azure.identity.aio`
"""

# pylint:disable=protected-access
async def begin_full_backup(
self, blob_storage_uri: str, sas_token: str, **kwargs: "Any"
) -> "AsyncLROPoller[BackupOperation]":
"""Begin a full backup of the Key Vault.
:param str blob_storage_uri: URI of the blob storage resource in which the backup will be stored
:param str sas_token: a Shared Access Signature (SAS) token authorizing access to the blob storage resource
:keyword str continuation_token: a continuation token to restart polling from a saved state
:returns: An AsyncLROPoller. Call `result()` on this object to get a :class:`BackupOperation`.
:rtype: ~azure.core.polling.AsyncLROPoller[BackupOperation]
"""
polling_interval = kwargs.pop("_polling_interval", 5)
sas_parameter = self._models.SASTokenParameter(storage_resource_uri=blob_storage_uri, token=sas_token)
return await self._client.begin_full_backup(
vault_base_url=self._vault_url,
azure_storage_blob_container_uri=sas_parameter,
cls=BackupOperation._wrap_generated,
continuation_token=kwargs.pop("continuation_token", None),
polling=AsyncLROBasePolling(
lro_algorithms=[KeyVaultBackupClientPolling()], timeout=polling_interval, **kwargs
),
**kwargs
)

async def begin_full_restore(
self, blob_storage_uri: str, sas_token: str, folder_name: str, **kwargs: "Any"
) -> "AsyncLROPoller[RestoreOperation]":
"""Restore a full backup of a Key Vault.
:param str blob_storage_uri: URI of the blob storage resource in which the backup is stored
:param str sas_token: a Shared Access Signature (SAS) token authorizing access to the blob storage resource
:param str folder_name: name of the blob container which contains the backup
:rtype: ~azure.core.polling.AsyncLROPoller[RestoreOperation]
"""
polling_interval = kwargs.pop("_polling_interval", 5)
sas_parameter = self._models.SASTokenParameter(storage_resource_uri=blob_storage_uri, token=sas_token)
restore_details = self._models.RestoreOperationParameters(
sas_token_parameters=sas_parameter, folder_to_restore=folder_name,
)
return await self._client.begin_full_restore_operation(
vault_base_url=self._vault_url,
restore_blob_details=restore_details,
cls=RestoreOperation._wrap_generated,
continuation_token=kwargs.pop("continuation_token", None),
polling=AsyncLROBasePolling(
lro_algorithms=[KeyVaultBackupClientPolling()], timeout=polling_interval, **kwargs
),
**kwargs
)

async def begin_selective_restore(
self, blob_storage_uri: str, sas_token: str, folder_name: str, key_name: str, **kwargs: "Any"
) -> "AsyncLROPoller[SelectiveKeyRestoreOperation]":
"""Restore a single key from a full Key Vault backup.
:param str blob_storage_uri: URI of the blob storage resource in which the backup is stored
:param str sas_token: a Shared Access Signature (SAS) token authorizing access to the blob storage resource
:param str folder_name: name of the blob container which contains the backup
:param str key_name: name of the key to restore from the backup
:rtype: ~azure.core.polling.AsyncLROPoller[RestoreOperation]
"""
polling_interval = kwargs.pop("_polling_interval", 5)
sas_parameter = self._models.SASTokenParameter(storage_resource_uri=blob_storage_uri, token=sas_token)
restore_details = self._models.SelectiveKeyRestoreOperationParameters(
sas_token_parameters=sas_parameter, folder=folder_name,
)
return await self._client.begin_selective_key_restore_operation(
vault_base_url=self._vault_url,
key_name=key_name,
restore_blob_details=restore_details,
cls=SelectiveKeyRestoreOperation._wrap_generated,
continuation_token=kwargs.pop("continuation_token", None),
polling=AsyncLROBasePolling(
lro_algorithms=[KeyVaultBackupClientPolling()], timeout=polling_interval, **kwargs
),
**kwargs
)

0 comments on commit 27eead3

Please sign in to comment.