Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Implement full vault backup and restore #13525

Merged
merged 5 commits into from
Sep 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't think this typing would render properly

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right you are. I copied it from the generated model. Fixing it depends on how we expose the error. I made this part of #13575.

: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
)