diff --git a/sdk/keyvault/azure-keyvault-certificates/azure/keyvault/certificates/_shared/exceptions.py b/sdk/keyvault/azure-keyvault-certificates/azure/keyvault/certificates/_shared/exceptions.py new file mode 100644 index 000000000000..2deaf2168b7c --- /dev/null +++ b/sdk/keyvault/azure-keyvault-certificates/azure/keyvault/certificates/_shared/exceptions.py @@ -0,0 +1,37 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +import functools +from typing import TYPE_CHECKING + +from azure.core.exceptions import DecodeError, ResourceExistsError, ResourceNotFoundError +from azure.core.pipeline.policies import ContentDecodePolicy + +if TYPE_CHECKING: + # pylint:disable=unused-import,ungrouped-imports + from typing import Type + from azure.core.exceptions import AzureError + from azure.core.pipeline.transport import HttpResponse + + +def get_exception_for_key_vault_error(cls, response): + # type: (Type[AzureError], HttpResponse) -> AzureError + try: + body = ContentDecodePolicy.deserialize_from_http_generics(response) + message = "({}) {}".format(body["error"]["code"], body["error"]["message"]) + except (DecodeError, KeyError): + # Key Vault error response bodies have the expected shape and should be deserializable. + # If we somehow land here, we'll take HttpResponse's default message. + message = None + + return cls(message=message, response=response) + + +_code_to_core_error = {404: ResourceNotFoundError, 409: ResourceExistsError} + +# map status codes to callables returning appropriate azure-core errors +error_map = { + status_code: functools.partial(get_exception_for_key_vault_error, cls) + for status_code, cls in _code_to_core_error.items() +} diff --git a/sdk/keyvault/azure-keyvault-certificates/azure/keyvault/certificates/aio/client.py b/sdk/keyvault/azure-keyvault-certificates/azure/keyvault/certificates/aio/client.py index c4b7f5b4ddfd..55a455a6db0a 100644 --- a/sdk/keyvault/azure-keyvault-certificates/azure/keyvault/certificates/aio/client.py +++ b/sdk/keyvault/azure-keyvault-certificates/azure/keyvault/certificates/aio/client.py @@ -29,6 +29,7 @@ ) from ._polling_async import CreateCertificatePollerAsync from .._shared import AsyncKeyVaultClientBase +from .._shared.exceptions import error_map class CertificateClient(AsyncKeyVaultClientBase): @@ -148,7 +149,9 @@ async def get_certificate_with_policy( :param str name: The name of the certificate in the given vault. :returns: An instance of Certificate :rtype: ~azure.keyvault.certificates.models.Certificate - :raises: :class:`~azure.core.exceptions.HttpResponseError` + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the certificate doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_examples_certificates_async.py @@ -162,6 +165,7 @@ async def get_certificate_with_policy( vault_base_url=self.vault_url, certificate_name=name, certificate_version="", + error_map=error_map, **kwargs ) return Certificate._from_certificate_bundle(certificate_bundle=bundle) @@ -182,7 +186,9 @@ async def get_certificate( :param str version: The version of the certificate. :returns: An instance of Certificate :rtype: ~azure.keyvault.certificates.models.Certificate - :raises: :class:`~azure.core.exceptions.HttpResponseError` + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the certificate doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_examples_certificates_async.py @@ -196,6 +202,7 @@ async def get_certificate( vault_base_url=self.vault_url, certificate_name=name, certificate_version=version, + error_map=error_map, **kwargs ) return Certificate._from_certificate_bundle(certificate_bundle=bundle) @@ -212,7 +219,9 @@ async def delete_certificate(self, name: str, **kwargs: "**Any") -> DeletedCerti :param str name: The name of the certificate. :returns: The deleted certificate :rtype: ~azure.keyvault.certificates.models.DeletedCertificate - :raises: :class:`~azure.core.exceptions.HttpResponseError` + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the certificate doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_examples_certificates_async.py @@ -225,6 +234,7 @@ async def delete_certificate(self, name: str, **kwargs: "**Any") -> DeletedCerti bundle = await self._client.delete_certificate( vault_base_url=self.vault_url, certificate_name=name, + error_map=error_map, **kwargs ) return DeletedCertificate._from_deleted_certificate_bundle(deleted_certificate_bundle=bundle) @@ -235,13 +245,15 @@ async def get_deleted_certificate(self, name: str, **kwargs: "**Any") -> Deleted Retrieves the deleted certificate information plus its attributes, such as retention interval, scheduled permanent deletion, and the - current deletion recovery level. This operaiton requires the certificates/ + current deletion recovery level. This operation requires the certificates/ get permission. :param str name: The name of the certificate. :return: The deleted certificate :rtype: ~azure.keyvault.certificates.models.DeletedCertificate - :raises: :class:`~azure.core.exceptions.HttpResponseError` + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the certificate doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_examples_certificates_async.py @@ -254,6 +266,7 @@ async def get_deleted_certificate(self, name: str, **kwargs: "**Any") -> Deleted bundle = await self._client.get_deleted_certificate( vault_base_url=self.vault_url, certificate_name=name, + error_map=error_map, **kwargs ) return DeletedCertificate._from_deleted_certificate_bundle(deleted_certificate_bundle=bundle) @@ -467,7 +480,9 @@ async def backup_certificate(self, name: str, **kwargs: "**Any") -> bytes: :param str name: The name of the certificate. :return: the backup blob containing the backed up certificate. :rtype: bytes - :raises: :class:`~azure.core.exceptions.HttpResponseError` + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the certificate doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_examples_certificates_async.py @@ -480,6 +495,7 @@ async def backup_certificate(self, name: str, **kwargs: "**Any") -> bytes: backup_result = await self._client.backup_certificate( vault_base_url=self.vault_url, certificate_name=name, + error_map=error_map, **kwargs ) return backup_result.value @@ -710,12 +726,15 @@ async def get_certificate_operation(self, name: str, **kwargs: "**Any") -> Certi :param str name: The name of the certificate. :returns: The created CertificateOperation :rtype: ~azure.keyvault.certificates.models.CertificateOperation - :raises: :class:`~azure.core.exceptions.HttpResponseError` + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the certificate doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors """ bundle = await self._client.get_certificate_operation( vault_base_url=self.vault_url, certificate_name=name, + error_map=error_map, **kwargs ) return CertificateOperation._from_certificate_operation_bundle(certificate_operation_bundle=bundle) @@ -731,11 +750,14 @@ async def delete_certificate_operation(self, name: str, **kwargs: "**Any") -> Ce :param str name: The name of the certificate. :return: The deleted CertificateOperation :rtype: ~azure.keyvault.certificates.models.CertificateOperation - :raises: :class:`~azure.core.exceptions.HttpResponseError` + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the operation doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors """ bundle = await self._client.delete_certificate_operation( vault_base_url=self.vault_url, certificate_name=name, + error_map=error_map, **kwargs ) return CertificateOperation._from_certificate_operation_bundle(certificate_operation_bundle=bundle) @@ -775,7 +797,6 @@ async def get_pending_certificate_signing_request( :rtype: str :raises: :class:`~azure.core.exceptions.HttpResponseError` """ - error_map = kwargs.pop("error_map", None) vault_base_url = self.vault_url # Construct URL url = '/certificates/{certificate-name}/pending' @@ -874,7 +895,9 @@ async def get_issuer(self, name: str, **kwargs: "**Any") -> Issuer: :param str name: The name of the issuer. :return: The specified certificate issuer. :rtype: ~azure.keyvault.certificates.models.Issuer - :raises: :class:`~azure.core.exceptions.HttpResponseError` + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the issuer doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_examples_certificates_async.py @@ -887,6 +910,7 @@ async def get_issuer(self, name: str, **kwargs: "**Any") -> Issuer: issuer_bundle = await self._client.get_certificate_issuer( vault_base_url=self.vault_url, issuer_name=name, + error_map=error_map, **kwargs ) return Issuer._from_issuer_bundle(issuer_bundle=issuer_bundle) diff --git a/sdk/keyvault/azure-keyvault-certificates/azure/keyvault/certificates/client.py b/sdk/keyvault/azure-keyvault-certificates/azure/keyvault/certificates/client.py index 757b46a85175..193360979efb 100644 --- a/sdk/keyvault/azure-keyvault-certificates/azure/keyvault/certificates/client.py +++ b/sdk/keyvault/azure-keyvault-certificates/azure/keyvault/certificates/client.py @@ -11,6 +11,7 @@ from azure.core.tracing.decorator import distributed_trace from ._shared import KeyVaultClientBase +from ._shared.exceptions import error_map from .models import ( Certificate, CertificateBase, @@ -58,7 +59,7 @@ def create_certificate( policy=None, # type: Optional[CertificatePolicy] enabled=None, # type: Optional[bool] tags=None, # type: Optional[Dict[str, str]] - **kwargs # type: **Any + **kwargs # type: Any ): # type: (...) -> CertificateOperation """Creates a new certificate. @@ -154,7 +155,9 @@ def get_certificate_with_policy(self, name, **kwargs): :param str name: The name of the certificate in the given vault. :returns: An instance of Certificate :rtype: ~azure.keyvault.certificates.models.Certificate - :raises: :class:`~azure.core.exceptions.HttpResponseError` + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the certificate doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_examples_certificates.py @@ -168,6 +171,7 @@ def get_certificate_with_policy(self, name, **kwargs): vault_base_url=self.vault_url, certificate_name=name, certificate_version="", + error_map=error_map, **kwargs ) return Certificate._from_certificate_bundle(certificate_bundle=bundle) @@ -184,7 +188,9 @@ def get_certificate(self, name, version, **kwargs): :param str version: The version of the certificate. :returns: An instance of Certificate :rtype: ~azure.keyvault.certificates.models.Certificate - :raises: :class:`~azure.core.exceptions.HttpResponseError` + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the certificate doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_examples_certificates.py @@ -198,6 +204,7 @@ def get_certificate(self, name, version, **kwargs): vault_base_url=self.vault_url, certificate_name=name, certificate_version=version, + error_map=error_map, **kwargs ) return Certificate._from_certificate_bundle(certificate_bundle=bundle) @@ -215,7 +222,9 @@ def delete_certificate(self, name, **kwargs): :param str name: The name of the certificate. :returns: The deleted certificate :rtype: ~azure.keyvault.certificates.models.DeletedCertificate - :raises: :class:`~azure.core.exceptions.HttpResponseError` + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the certificate doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_examples_certificates.py @@ -228,6 +237,7 @@ def delete_certificate(self, name, **kwargs): bundle = self._client.delete_certificate( vault_base_url=self.vault_url, certificate_name=name, + error_map=error_map, **kwargs ) return DeletedCertificate._from_deleted_certificate_bundle(deleted_certificate_bundle=bundle) @@ -239,13 +249,15 @@ def get_deleted_certificate(self, name, **kwargs): Retrieves the deleted certificate information plus its attributes, such as retention interval, scheduled permanent deletion, and the - current deletion recovery level. This operaiton requires the certificates/ + current deletion recovery level. This operation requires the certificates/ get permission. :param str name: The name of the certificate. :return: The deleted certificate :rtype: ~azure.keyvault.certificates.models.DeletedCertificate - :raises: :class:`~azure.core.exceptions.HttpResponseError` + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the certificate doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_examples_certificates.py @@ -258,6 +270,7 @@ def get_deleted_certificate(self, name, **kwargs): bundle = self._client.get_deleted_certificate( vault_base_url=self.vault_url, certificate_name=name, + error_map=error_map, **kwargs ) return DeletedCertificate._from_deleted_certificate_bundle(deleted_certificate_bundle=bundle) @@ -475,7 +488,9 @@ def backup_certificate(self, name, **kwargs): :param str name: The name of the certificate. :return: the backup blob containing the backed up certificate. :rtype: bytes - :raises: :class:`~azure.core.exceptions.HttpResponseError` + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the certificate doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_examples_certificates.py @@ -488,6 +503,7 @@ def backup_certificate(self, name, **kwargs): backup_result = self._client.backup_certificate( vault_base_url=self.vault_url, certificate_name=name, + error_map=error_map, **kwargs ) return backup_result.value @@ -709,12 +725,15 @@ def get_certificate_operation(self, name, **kwargs): :param str name: The name of the certificate. :returns: The created CertificateOperation :rtype: ~azure.keyvault.certificates.models.CertificateOperation - :raises: :class:`~azure.core.exceptions.HttpResponseError` + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the certificate doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors """ bundle = self._client.get_certificate_operation( vault_base_url=self.vault_url, certificate_name=name, + error_map=error_map, **kwargs ) return CertificateOperation._from_certificate_operation_bundle(certificate_operation_bundle=bundle) @@ -821,7 +840,6 @@ def get_pending_certificate_signing_request( :rtype: str :raises: :class:`~azure.core.exceptions.HttpResponseError` """ - error_map = kwargs.pop("error_map", None) vault_base_url = self.vault_url # Construct URL url = '/certificates/{certificate-name}/pending' @@ -876,7 +894,9 @@ def get_issuer(self, name, **kwargs): :param str name: The name of the issuer. :return: The specified certificate issuer. :rtype: ~azure.keyvault.certificates.models.Issuer - :raises: :class:`~azure.core.exceptions.HttpResponseError` + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the issuer doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_examples_certificates.py @@ -889,6 +909,7 @@ def get_issuer(self, name, **kwargs): issuer_bundle = self._client.get_certificate_issuer( vault_base_url=self.vault_url, issuer_name=name, + error_map=error_map, **kwargs ) return Issuer._from_issuer_bundle(issuer_bundle=issuer_bundle) diff --git a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_shared/exceptions.py b/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_shared/exceptions.py new file mode 100644 index 000000000000..2deaf2168b7c --- /dev/null +++ b/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/_shared/exceptions.py @@ -0,0 +1,37 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +import functools +from typing import TYPE_CHECKING + +from azure.core.exceptions import DecodeError, ResourceExistsError, ResourceNotFoundError +from azure.core.pipeline.policies import ContentDecodePolicy + +if TYPE_CHECKING: + # pylint:disable=unused-import,ungrouped-imports + from typing import Type + from azure.core.exceptions import AzureError + from azure.core.pipeline.transport import HttpResponse + + +def get_exception_for_key_vault_error(cls, response): + # type: (Type[AzureError], HttpResponse) -> AzureError + try: + body = ContentDecodePolicy.deserialize_from_http_generics(response) + message = "({}) {}".format(body["error"]["code"], body["error"]["message"]) + except (DecodeError, KeyError): + # Key Vault error response bodies have the expected shape and should be deserializable. + # If we somehow land here, we'll take HttpResponse's default message. + message = None + + return cls(message=message, response=response) + + +_code_to_core_error = {404: ResourceNotFoundError, 409: ResourceExistsError} + +# map status codes to callables returning appropriate azure-core errors +error_map = { + status_code: functools.partial(get_exception_for_key_vault_error, cls) + for status_code, cls in _code_to_core_error.items() +} diff --git a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/aio/client.py b/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/aio/client.py index 6a59bcdf9370..2e90738689f9 100644 --- a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/aio/client.py +++ b/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/aio/client.py @@ -5,21 +5,21 @@ from datetime import datetime from typing import Any, AsyncIterable, Optional, Dict, List, Union -from azure.core.exceptions import ResourceExistsError, ResourceNotFoundError from azure.core.tracing.decorator import distributed_trace from azure.core.tracing.decorator_async import distributed_trace_async from azure.keyvault.keys.models import DeletedKey, JsonWebKey, Key, KeyBase from azure.keyvault.keys._shared import AsyncKeyVaultClientBase +from .._shared.exceptions import error_map from ..crypto.aio import CryptographyClient class KeyClient(AsyncKeyVaultClientBase): """A high-level asynchronous interface for managing a vault's keys. + :param str vault_url: URL of the vault the client will access :param credential: An object which can provide an access token for the vault, such as a credential from :mod:`azure.identity.aio` - :param str vault_url: URL of the vault the client will access Example: .. literalinclude:: ../tests/test_samples_keys_async.py @@ -33,6 +33,18 @@ class KeyClient(AsyncKeyVaultClientBase): # pylint:disable=protected-access def get_cryptography_client(self, key: Union[Key, str], **kwargs: Any) -> CryptographyClient: + """ + Get a :class:`~azure.keyvault.keys.crypto.aio.CryptographyClient` capable of performing cryptographic operations + with a key. + + :param key: + Either a :class:`~azure.keyvault.keys.Key` instance as returned by + :func:`~azure.keyvault.keys.aio.KeyClient.get_key`, or a string. If a string, the value must be the full + identifier of an Azure Key Vault key with a version. + :type key: str or :class:`~azure.keyvault.keys.Key` + :rtype: :class:`~azure.keyvault.keys.crypto.aio.CryptographyClient` + """ + # the initializer requires a credential but won't actually use it in this case because we pass in this # KeyClient's generated client, whose pipeline (and auth policy) is fully configured credential = object() @@ -69,6 +81,7 @@ async def create_key( :type curve: ~azure.keyvault.keys.enums.KeyCurveName or str :returns: The created key :rtype: ~azure.keyvault.keys.models.Key + :raises: :class:`~azure.core.exceptions.HttpResponseError` Example: .. literalinclude:: ../tests/test_samples_keys_async.py @@ -123,6 +136,7 @@ async def create_rsa_key( :param dict tags: (optional) Application specific metadata in the form of key-value pairs :returns: The created key :rtype: ~azure.keyvault.keys.models.Key + :raises: :class:`~azure.core.exceptions.HttpResponseError` Example: .. literalinclude:: ../tests/test_samples_keys_async.py @@ -174,6 +188,7 @@ async def create_ec_key( :param dict tags: (optional) Application specific metadata in the form of key-value pairs :returns: The created key :rtype: ~azure.keyvault.keys.models.Key + :raises: :class:`~azure.core.exceptions.HttpResponseError` Example: .. literalinclude:: ../tests/test_samples_keys_async.py @@ -204,7 +219,9 @@ async def delete_key(self, name: str, **kwargs: "**Any") -> DeletedKey: :param str name: The name of the key to delete. :returns: The deleted key :rtype: ~azure.keyvault.keys.models.DeletedKey - :raises: :class:`~azure.core.exceptions.ResourceNotFoundError` if the key doesn't exist + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the key doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_keys_async.py @@ -214,7 +231,7 @@ async def delete_key(self, name: str, **kwargs: "**Any") -> DeletedKey: :caption: Delete a key :dedent: 8 """ - bundle = await self._client.delete_key(self.vault_url, name, error_map={404: ResourceNotFoundError}, **kwargs) + bundle = await self._client.delete_key(self.vault_url, name, error_map=error_map, **kwargs) return DeletedKey._from_deleted_key_bundle(bundle) @distributed_trace_async @@ -225,7 +242,9 @@ async def get_key(self, name: str, version: Optional[str] = None, **kwargs: "**A :param str version: (optional) A specific version of the key to get. If not specified, gets the latest version of the key. :rtype: ~azure.keyvault.keys.models.Key - :raises: :class:`~azure.core.exceptions.ResourceNotFoundError` if the key doesn't exist + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the key doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_keys_async.py @@ -238,9 +257,7 @@ async def get_key(self, name: str, version: Optional[str] = None, **kwargs: "**A if version is None: version = "" - bundle = await self._client.get_key( - self.vault_url, name, version, error_map={404: ResourceNotFoundError}, **kwargs - ) + bundle = await self._client.get_key(self.vault_url, name, version, error_map=error_map, **kwargs) return Key._from_key_bundle(bundle) @distributed_trace_async @@ -251,6 +268,9 @@ async def get_deleted_key(self, name: str, **kwargs: "**Any") -> DeletedKey: :param str name: The name of the key :returns: The deleted key :rtype: ~azure.keyvault.keys.models.DeletedKey + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the key doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_keys_async.py @@ -260,9 +280,7 @@ async def get_deleted_key(self, name: str, **kwargs: "**Any") -> DeletedKey: :caption: Get a deleted key :dedent: 8 """ - bundle = await self._client.get_deleted_key( - self.vault_url, name, error_map={404: ResourceNotFoundError}, **kwargs - ) + bundle = await self._client.get_deleted_key(self.vault_url, name, error_map=error_map, **kwargs) return DeletedKey._from_deleted_key_bundle(bundle) @distributed_trace @@ -286,7 +304,7 @@ def list_deleted_keys(self, **kwargs: "**Any") -> AsyncIterable[DeletedKey]: self.vault_url, maxresults=max_results, cls=lambda objs: [DeletedKey._from_deleted_key_item(x) for x in objs], - **kwargs + **kwargs, ) @distributed_trace @@ -306,10 +324,7 @@ def list_keys(self, **kwargs: "**Any") -> AsyncIterable[KeyBase]: """ max_results = kwargs.get("max_page_size") return self._client.get_keys( - self.vault_url, - maxresults=max_results, - cls=lambda objs: [KeyBase._from_key_item(x) for x in objs], - **kwargs + self.vault_url, maxresults=max_results, cls=lambda objs: [KeyBase._from_key_item(x) for x in objs], **kwargs ) @distributed_trace @@ -334,7 +349,7 @@ def list_key_versions(self, name: str, **kwargs: "**Any") -> AsyncIterable[KeyBa name, maxresults=max_results, cls=lambda objs: [KeyBase._from_key_item(x) for x in objs], - **kwargs + **kwargs, ) @distributed_trace_async @@ -346,6 +361,7 @@ async def purge_deleted_key(self, name: str, **kwargs: "**Any") -> None: :param str name: The name of the key :returns: None + :raises: :class:`~azure.core.exceptions.HttpResponseError` Example: .. code-block:: python @@ -368,6 +384,7 @@ async def recover_deleted_key(self, name: str, **kwargs: "**Any") -> Key: :param str name: The name of the deleted key :returns: The recovered key :rtype: ~azure.keyvault.keys.models.Key + :raises: :class:`~azure.core.exceptions.HttpResponseError` Example: .. literalinclude:: ../tests/test_samples_keys_async.py @@ -405,7 +422,9 @@ async def update_key( :param dict tags: (optional) Application specific metadata in the form of key-value pairs :returns: The updated key :rtype: ~azure.keyvault.keys.models.Key - :raises: :class:`~azure.core.exceptions.ResourceNotFoundError` if the key doesn't exist + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the key doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_keys_async.py @@ -427,7 +446,7 @@ async def update_key( key_ops=key_operations, tags=tags, key_attributes=attributes, - error_map={404: ResourceNotFoundError}, + error_map=error_map, **kwargs, ) return Key._from_key_bundle(bundle) @@ -443,7 +462,9 @@ async def backup_key(self, name: str, **kwargs: "**Any") -> bytes: :param str name: The name of the key :returns: The raw bytes of the key backup :rtype: bytes - :raises: :class:`~azure.core.exceptions.ResourceNotFoundError` if the key doesn't exist + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the key doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_keys_async.py @@ -453,9 +474,7 @@ async def backup_key(self, name: str, **kwargs: "**Any") -> bytes: :caption: Get a key backup :dedent: 8 """ - backup_result = await self._client.backup_key( - self.vault_url, name, error_map={404: ResourceNotFoundError}, **kwargs - ) + backup_result = await self._client.backup_key(self.vault_url, name, error_map=error_map, **kwargs) return backup_result.value @distributed_trace_async @@ -469,7 +488,9 @@ async def restore_key(self, backup: bytes, **kwargs: "**Any") -> Key: :param bytes backup: The raw bytes of the key backup :returns: The restored key :rtype: ~azure.keyvault.keys.models.Key - :raises: :class:`~azure.core.exceptions.ResourceExistsError` if the backed up key's name is already in use + :raises: + :class:`~azure.core.exceptions.ResourceExistsError` if the backed up key's name is already in use, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_keys_async.py @@ -479,7 +500,7 @@ async def restore_key(self, backup: bytes, **kwargs: "**Any") -> Key: :caption: Restore a key backup :dedent: 8 """ - bundle = await self._client.restore_key(self.vault_url, backup, error_map={409: ResourceExistsError}, **kwargs) + bundle = await self._client.restore_key(self.vault_url, backup, error_map=error_map, **kwargs) return Key._from_key_bundle(bundle) @distributed_trace_async @@ -507,6 +528,7 @@ async def import_key( :param dict tags: (optional) Application specific metadata in the form of key-value pairs :returns: The imported key :rtype: ~azure.keyvault.keys.models.Key + :raises: :class:`~azure.core.exceptions.HttpResponseError` """ if enabled is not None or not_before is not None or expires is not None: diff --git a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/client.py b/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/client.py index 0f73ee1b2cfe..8ca607a6e3e2 100644 --- a/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/client.py +++ b/sdk/keyvault/azure-keyvault-keys/azure/keyvault/keys/client.py @@ -2,10 +2,10 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. # ------------------------------------ -from azure.core.exceptions import ResourceExistsError, ResourceNotFoundError from azure.core.tracing.decorator import distributed_trace from ._shared import KeyVaultClientBase +from ._shared.exceptions import error_map from .crypto import CryptographyClient from .models import Key, KeyBase, DeletedKey @@ -24,9 +24,9 @@ class KeyClient(KeyVaultClientBase): """A high-level interface for managing a vault's keys. + :param str vault_url: URL of the vault the client will access :param credential: An object which can provide an access token for the vault, such as a credential from :mod:`azure.identity` - :param str vault_url: URL of the vault the client will access Example: .. literalinclude:: ../tests/test_samples_keys.py @@ -41,6 +41,17 @@ class KeyClient(KeyVaultClientBase): def get_cryptography_client(self, key, **kwargs): # type: (Union[Key, str], **Any) -> CryptographyClient + """ + Get a :class:`~azure.keyvault.keys.crypto.CryptographyClient` capable of performing cryptographic operations + with a key. + + :param key: + Either a :class:`~azure.keyvault.keys.Key` instance as returned by + :func:`~azure.keyvault.keys.KeyClient.get_key`, or a string. If a string, the value must be the full + identifier of an Azure Key Vault key with a version. + :type key: str or :class:`~azure.keyvault.keys.Key` + :rtype: :class:`~azure.keyvault.keys.crypto.CryptographyClient` + """ # the initializer requires a credential but won't actually use it in this case because we pass in this # KeyClient's generated client, whose pipeline (and auth policy) is fully configured @@ -59,7 +70,7 @@ def create_key( not_before=None, # type: Optional[datetime] tags=None, # type: Optional[Dict[str, str]] curve=None, # type: Optional[str] - **kwargs # type: **Any + **kwargs # type: Any ): # type: (...) -> Key """Create a key. If ``name`` is already in use, create a new version of the key. Requires the keys/create @@ -79,6 +90,7 @@ def create_key( :type curve: ~azure.keyvault.keys.enums.KeyCurveName or str :returns: The created key :rtype: ~azure.keyvault.keys.models.Key + :raises: :class:`~azure.core.exceptions.HttpResponseError` Example: .. literalinclude:: ../tests/test_samples_keys.py @@ -117,7 +129,7 @@ def create_rsa_key( expires=None, # type: Optional[datetime] not_before=None, # type: Optional[datetime] tags=None, # type: Optional[Dict[str, str]] - **kwargs # type: **Any + **kwargs # type: Any ): # type: (...) -> Key """Create a new RSA key. If ``name`` is already in use, create a new version of the key. Requires the @@ -134,6 +146,7 @@ def create_rsa_key( :param dict tags: (optional) Application specific metadata in the form of key-value pairs :returns: The created key :rtype: ~azure.keyvault.keys.models.Key + :raises: :class:`~azure.core.exceptions.HttpResponseError` Example: .. literalinclude:: ../tests/test_samples_keys.py @@ -168,7 +181,7 @@ def create_ec_key( expires=None, # type: Optional[datetime] not_before=None, # type: Optional[datetime] tags=None, # type: Optional[Dict[str, str]] - **kwargs # type: **Any + **kwargs # type: Any ): # type: (...) -> Key """Create a new elliptic curve key. If ``name`` is already in use, create a new version of the key. Requires @@ -186,6 +199,7 @@ def create_ec_key( :param dict tags: (optional) Application specific metadata in the form of key-value pairs :returns: The created key :rtype: ~azure.keyvault.keys.models.Key + :raises: :class:`~azure.core.exceptions.HttpResponseError` Example: .. literalinclude:: ../tests/test_samples_keys.py @@ -218,7 +232,9 @@ def delete_key(self, name, **kwargs): :param str name: The name of the key to delete. :returns: The deleted key :rtype: ~azure.keyvault.keys.models.DeletedKey - :raises: :class:`~azure.core.exceptions.ResourceNotFoundError` if the key doesn't exist + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the key doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_keys.py @@ -228,7 +244,7 @@ def delete_key(self, name, **kwargs): :caption: Delete a key :dedent: 8 """ - bundle = self._client.delete_key(self.vault_url, name, error_map={404: ResourceNotFoundError}, **kwargs) + bundle = self._client.delete_key(self.vault_url, name, error_map=error_map, **kwargs) return DeletedKey._from_deleted_key_bundle(bundle) @distributed_trace @@ -240,7 +256,9 @@ def get_key(self, name, version=None, **kwargs): :param str version: (optional) A specific version of the key to get. If not specified, gets the latest version of the key. :rtype: ~azure.keyvault.keys.models.Key - :raises: :class:`~azure.core.exceptions.ResourceNotFoundError` if the key doesn't exist + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the key doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_keys.py @@ -250,9 +268,7 @@ def get_key(self, name, version=None, **kwargs): :caption: Get a key :dedent: 8 """ - bundle = self._client.get_key( - self.vault_url, name, key_version=version or "", error_map={404: ResourceNotFoundError}, **kwargs - ) + bundle = self._client.get_key(self.vault_url, name, key_version=version or "", error_map=error_map, **kwargs) return Key._from_key_bundle(bundle) @distributed_trace @@ -264,6 +280,9 @@ def get_deleted_key(self, name, **kwargs): :param str name: The name of the key :returns: The deleted key :rtype: ~azure.keyvault.keys.models.DeletedKey + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the key doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_keys.py @@ -274,7 +293,7 @@ def get_deleted_key(self, name, **kwargs): :dedent: 8 """ # TODO: which exception is raised when soft-delete is not enabled - bundle = self._client.get_deleted_key(self.vault_url, name, error_map={404: ResourceNotFoundError}, **kwargs) + bundle = self._client.get_deleted_key(self.vault_url, name, error_map=error_map, **kwargs) return DeletedKey._from_deleted_key_bundle(bundle) @distributed_trace @@ -362,6 +381,7 @@ def purge_deleted_key(self, name, **kwargs): :param str name: The name of the key :returns: None + :raises: :class:`~azure.core.exceptions.HttpResponseError` Example: .. code-block:: python @@ -371,11 +391,7 @@ def purge_deleted_key(self, name, **kwargs): key_client.purge_deleted_key("key-name") """ - self._client.purge_deleted_key( - vault_base_url=self.vault_url, - key_name=name, - **kwargs - ) + self._client.purge_deleted_key(vault_base_url=self.vault_url, key_name=name, **kwargs) @distributed_trace def recover_deleted_key(self, name, **kwargs): @@ -389,6 +405,7 @@ def recover_deleted_key(self, name, **kwargs): :param str name: The name of the deleted key :returns: The recovered key :rtype: ~azure.keyvault.keys.models.Key + :raises: :class:`~azure.core.exceptions.HttpResponseError` Example: .. literalinclude:: ../tests/test_samples_keys.py @@ -398,11 +415,7 @@ def recover_deleted_key(self, name, **kwargs): :caption: Recover a deleted key :dedent: 8 """ - bundle = self._client.recover_deleted_key( - vault_base_url=self.vault_url, - key_name=name, - **kwargs - ) + bundle = self._client.recover_deleted_key(vault_base_url=self.vault_url, key_name=name, **kwargs) return Key._from_key_bundle(bundle) @distributed_trace @@ -415,7 +428,7 @@ def update_key( expires=None, # type: Optional[datetime] not_before=None, # type: Optional[datetime] tags=None, # type: Optional[Dict[str, str]] - **kwargs # type: **Any + **kwargs # type: Any ): # type: (...) -> Key """Change attributes of a key. Cannot change a key's cryptographic material. Requires the keys/update @@ -431,7 +444,9 @@ def update_key( :param dict tags: (optional) Application specific metadata in the form of key-value pairs :returns: The updated key :rtype: ~azure.keyvault.keys.models.Key - :raises: :class:`~azure.core.exceptions.ResourceNotFoundError` if the key doesn't exist + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the key doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_keys.py @@ -452,7 +467,7 @@ def update_key( key_ops=key_operations, tags=tags, key_attributes=attributes, - error_map={404: ResourceNotFoundError}, + error_map=error_map, **kwargs ) return Key._from_key_bundle(bundle) @@ -469,7 +484,9 @@ def backup_key(self, name, **kwargs): :param str name: The name of the key :returns: The raw bytes of the key backup :rtype: bytes - :raises: :class:`~azure.core.exceptions.ResourceNotFoundError` if the key doesn't exist + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the key doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_keys.py @@ -479,7 +496,7 @@ def backup_key(self, name, **kwargs): :caption: Get a key backup :dedent: 8 """ - backup_result = self._client.backup_key(self.vault_url, name, error_map={404: ResourceNotFoundError}, **kwargs) + backup_result = self._client.backup_key(self.vault_url, name, error_map=error_map, **kwargs) return backup_result.value @distributed_trace @@ -494,7 +511,9 @@ def restore_key(self, backup, **kwargs): :param bytes backup: The raw bytes of the key backup :returns: The restored key :rtype: ~azure.keyvault.keys.models.Key - :raises: :class:`~azure.core.exceptions.ResourceExistsError` if the backed up key's name is already in use + :raises: + :class:`~azure.core.exceptions.ResourceExistsError` if the backed up key's name is already in use, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_keys.py @@ -504,7 +523,7 @@ def restore_key(self, backup, **kwargs): :caption: Restore a key backup :dedent: 8 """ - bundle = self._client.restore_key(self.vault_url, backup, error_map={409: ResourceExistsError}, **kwargs) + bundle = self._client.restore_key(self.vault_url, backup, error_map=error_map, **kwargs) return Key._from_key_bundle(bundle) @distributed_trace @@ -517,7 +536,7 @@ def import_key( not_before=None, # type: Optional[datetime] expires=None, # type: Optional[datetime] tags=None, # type: Optional[Dict[str, str]] - **kwargs # type: **Any + **kwargs # type: Any ): # type: (...) -> Key """Import an externally created key. If ``name`` is already in use, import the key as a new version. Requires @@ -533,6 +552,7 @@ def import_key( :param dict tags: (optional) Application specific metadata in the form of key-value pairs :returns: The imported key :rtype: ~azure.keyvault.keys.models.Key + :raises: :class:`~azure.core.exceptions.HttpResponseError` """ if enabled is not None or not_before is not None or expires is not None: diff --git a/sdk/keyvault/azure-keyvault-secrets/HISTORY.md b/sdk/keyvault/azure-keyvault-secrets/HISTORY.md index f5a9864a7a98..5805d539d570 100644 --- a/sdk/keyvault/azure-keyvault-secrets/HISTORY.md +++ b/sdk/keyvault/azure-keyvault-secrets/HISTORY.md @@ -1,4 +1,9 @@ # Release History + +## 4.0.0b4 +### Fixes and improvements +- `list_secrets` and `list_secret_versions` return the correct type + ## 4.0.0b3 (2019-09-11) This release includes only internal changes. diff --git a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_shared/exceptions.py b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_shared/exceptions.py new file mode 100644 index 000000000000..2deaf2168b7c --- /dev/null +++ b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/_shared/exceptions.py @@ -0,0 +1,37 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +import functools +from typing import TYPE_CHECKING + +from azure.core.exceptions import DecodeError, ResourceExistsError, ResourceNotFoundError +from azure.core.pipeline.policies import ContentDecodePolicy + +if TYPE_CHECKING: + # pylint:disable=unused-import,ungrouped-imports + from typing import Type + from azure.core.exceptions import AzureError + from azure.core.pipeline.transport import HttpResponse + + +def get_exception_for_key_vault_error(cls, response): + # type: (Type[AzureError], HttpResponse) -> AzureError + try: + body = ContentDecodePolicy.deserialize_from_http_generics(response) + message = "({}) {}".format(body["error"]["code"], body["error"]["message"]) + except (DecodeError, KeyError): + # Key Vault error response bodies have the expected shape and should be deserializable. + # If we somehow land here, we'll take HttpResponse's default message. + message = None + + return cls(message=message, response=response) + + +_code_to_core_error = {404: ResourceNotFoundError, 409: ResourceExistsError} + +# map status codes to callables returning appropriate azure-core errors +error_map = { + status_code: functools.partial(get_exception_for_key_vault_error, cls) + for status_code, cls in _code_to_core_error.items() +} diff --git a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/aio/client.py b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/aio/client.py index 1cc520edb3d0..15ef646862a4 100644 --- a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/aio/client.py +++ b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/aio/client.py @@ -16,9 +16,9 @@ class SecretClient(AsyncKeyVaultClientBase): """A high-level asynchronous interface for managing a vault's secrets. + :param str vault_url: URL of the vault the client will access :param credential: An object which can provide an access token for the vault, such as a credential from :mod:`azure.identity.aio` - :param str vault_url: URL of the vault the client will access Example: .. literalinclude:: ../tests/test_samples_secrets_async.py @@ -38,7 +38,9 @@ async def get_secret(self, name: str, version: Optional[str] = None, **kwargs: " :param str name: The name of the secret :param str version: (optional) Version of the secret to get. If unspecified, gets the latest version. :rtype: ~azure.keyvault.secrets.models.Secret - :raises: :class:`~azure.core.exceptions.ResourceNotFoundError` if the secret doesn't exist + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the secret doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_secrets_async.py @@ -76,6 +78,7 @@ async def set_secret( :param datetime.datetime expires: (optional) Expiry date of the secret in UTC :param dict tags: (optional) Application specific metadata in the form of key-value pairs :rtype: ~azure.keyvault.secrets.models.Secret + :raises: :class:`~azure.core.exceptions.HttpResponseError` Example: .. literalinclude:: ../tests/test_samples_secrets_async.py @@ -118,7 +121,9 @@ async def update_secret( :param datetime.datetime expires: (optional) Expiry date of the secret in UTC. :param dict(str, str) tags: (optional) Application specific metadata in the form of key-value pairs. :rtype: ~azure.keyvault.secrets.models.SecretAttributes - :raises: :class:`~azure.core.exceptions.ResourceNotFoundError` if the secret doesn't exist + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the secret doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_secrets_async.py @@ -201,7 +206,9 @@ async def backup_secret(self, name: str, **kwargs: "**Any") -> bytes: :param str name: Name of the secret :returns: The raw bytes of the secret backup :rtype: bytes - :raises: :class:`~azure.core.exceptions.ResourceNotFoundError` if the secret doesn't exist + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the secret doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_secrets_async.py @@ -223,7 +230,9 @@ async def restore_secret(self, backup: bytes, **kwargs: "**Any") -> SecretAttrib :param bytes backup: The raw bytes of the secret backup :returns: The restored secret :rtype: ~azure.keyvault.secrets.models.SecretAttributes - :raises: :class:`~azure.core.exceptions.ResourceExistsError` if the secret's name is already in use + :raises: + :class:`~azure.core.exceptions.ResourceExistsError` if the secret's name is already in use, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_secrets_async.py @@ -244,7 +253,9 @@ async def delete_secret(self, name: str, **kwargs: "**Any") -> DeletedSecret: :param str name: Name of the secret :rtype: ~azure.keyvault.secrets.models.DeletedSecret - :raises: :class:`~azure.core.exceptions.ResourceNotFoundError` if the secret doesn't exist + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the secret doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_secrets_async.py @@ -266,7 +277,9 @@ async def get_deleted_secret(self, name: str, **kwargs: "**Any") -> DeletedSecre :param str name: Name of the secret :rtype: ~azure.keyvault.secrets.models.DeletedSecret - :raises: :class:`~azure.core.exceptions.ResourceNotFoundError` if the deleted secret doesn't exist + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the deleted secret doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_secrets_async.py @@ -314,6 +327,7 @@ async def purge_deleted_secret(self, name: str, **kwargs: "**Any") -> None: :param str name: Name of the secret :returns: None + :raises: :class:`~azure.core.exceptions.HttpResponseError` Example: .. code-block:: python @@ -333,6 +347,7 @@ async def recover_deleted_secret(self, name: str, **kwargs: "**Any") -> SecretAt :param str name: Name of the secret :returns: The recovered secret :rtype: ~azure.keyvault.secrets.models.SecretAttributes + :raises: :class:`~azure.core.exceptions.HttpResponseError` Example: .. literalinclude:: ../tests/test_samples_secrets_async.py diff --git a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/client.py b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/client.py index 3170d8949e5c..eec72bd95699 100644 --- a/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/client.py +++ b/sdk/keyvault/azure-keyvault-secrets/azure/keyvault/secrets/client.py @@ -23,9 +23,9 @@ class SecretClient(KeyVaultClientBase): """A high-level interface for managing a vault's secrets. + :param str vault_url: URL of the vault the client will access :param credential: An object which can provide an access token for the vault, such as a credential from :mod:`azure.identity` - :param str vault_url: URL of the vault the client will access Example: .. literalinclude:: ../tests/test_samples_secrets.py @@ -46,7 +46,9 @@ def get_secret(self, name, version=None, **kwargs): :param str name: The name of the secret :param str version: (optional) Version of the secret to get. If unspecified, gets the latest version. :rtype: ~azure.keyvault.secrets.models.Secret - :raises: :class:`~azure.core.exceptions.ResourceNotFoundError` if the secret doesn't exist + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the secret doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_secrets.py @@ -89,6 +91,7 @@ def set_secret( :param datetime.datetime expires: (optional) Expiry date of the secret in UTC :param dict tags: (optional) Application specific metadata in the form of key-value pairs :rtype: ~azure.keyvault.secrets.models.Secret + :raises: :class:`~azure.core.exceptions.HttpResponseError` Example: .. literalinclude:: ../tests/test_samples_secrets.py @@ -139,7 +142,9 @@ def update_secret( :param datetime.datetime expires: (optional) Expiry date of the secret in UTC. :param dict tags: (optional) Application specific metadata in the form of key-value pairs :rtype: ~azure.keyvault.secrets.models.SecretAttributes - :raises: :class:`~azure.core.exceptions.ResourceNotFoundError` if the secret doesn't exist + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the secret doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_secrets.py @@ -188,7 +193,7 @@ def list_secrets(self, **kwargs): return self._client.get_secrets( self._vault_url, maxresults=max_page_size, - cls=lambda objs: [DeletedSecret._from_secret_item(x) for x in objs], + cls=lambda objs: [SecretAttributes._from_secret_item(x) for x in objs], **kwargs ) @@ -216,7 +221,7 @@ def list_secret_versions(self, name, **kwargs): self._vault_url, name, maxresults=max_page_size, - cls=lambda objs: [DeletedSecret._from_secret_item(x) for x in objs], + cls=lambda objs: [SecretAttributes._from_secret_item(x) for x in objs], **kwargs ) @@ -228,7 +233,9 @@ def backup_secret(self, name, **kwargs): :param str name: Name of the secret :returns: The raw bytes of the secret backup :rtype: bytes - :raises: :class:`~azure.core.exceptions.ResourceNotFoundError` if the secret doesn't exist + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the secret doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_secrets.py @@ -252,7 +259,9 @@ def restore_secret(self, backup, **kwargs): :param bytes backup: The raw bytes of the secret backup :returns: The restored secret :rtype: ~azure.keyvault.secrets.models.SecretAttributes - :raises: :class:`~azure.core.exceptions.ResourceExistsError` if the secret's name is already in use + :raises: + :class:`~azure.core.exceptions.ResourceExistsError` if the secret's name is already in use, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_secrets.py @@ -273,7 +282,9 @@ def delete_secret(self, name, **kwargs): :param str name: Name of the secret :rtype: ~azure.keyvault.secrets.models.DeletedSecret - :raises: :class:`~azure.core.exceptions.ResourceNotFoundError` if the secret doesn't exist + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the secret doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_secrets.py @@ -295,7 +306,9 @@ def get_deleted_secret(self, name, **kwargs): :param str name: Name of the secret :rtype: ~azure.keyvault.secrets.models.DeletedSecret - :raises: :class:`~azure.core.exceptions.ResourceNotFoundError` if the deleted secret doesn't exist + :raises: + :class:`~azure.core.exceptions.ResourceNotFoundError` if the deleted secret doesn't exist, + :class:`~azure.core.exceptions.HttpResponseError` for other errors Example: .. literalinclude:: ../tests/test_samples_secrets.py @@ -345,6 +358,7 @@ def purge_deleted_secret(self, name, **kwargs): :param str name: Name of the secret :returns: None + :raises: :class:`~azure.core.exceptions.HttpResponseError` Example: .. code-block:: python @@ -365,6 +379,7 @@ def recover_deleted_secret(self, name, **kwargs): :param str name: Name of the secret :returns: The recovered secret :rtype: ~azure.keyvault.secrets.models.SecretAttributes + :raises: :class:`~azure.core.exceptions.HttpResponseError` Example: .. literalinclude:: ../tests/test_samples_secrets.py diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/authentication.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/authentication.py index 41e002c29ef9..6806bf922584 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/authentication.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/authentication.py @@ -117,9 +117,6 @@ def _add_authorization_header(self, request, string_to_sign): raise _wrap_exception(ex, AzureSigningError) def on_request(self, request): - if not 'content-type' in request.http_request.headers: - request.http_request.headers['content-type'] = 'application/xml; charset=utf-8' - string_to_sign = \ self._get_verb(request) + \ self._get_headers( diff --git a/sdk/storage/azure-storage-file/azure/storage/file/_shared/authentication.py b/sdk/storage/azure-storage-file/azure/storage/file/_shared/authentication.py index 41e002c29ef9..6806bf922584 100644 --- a/sdk/storage/azure-storage-file/azure/storage/file/_shared/authentication.py +++ b/sdk/storage/azure-storage-file/azure/storage/file/_shared/authentication.py @@ -117,9 +117,6 @@ def _add_authorization_header(self, request, string_to_sign): raise _wrap_exception(ex, AzureSigningError) def on_request(self, request): - if not 'content-type' in request.http_request.headers: - request.http_request.headers['content-type'] = 'application/xml; charset=utf-8' - string_to_sign = \ self._get_verb(request) + \ self._get_headers( diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/authentication.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/authentication.py index 41e002c29ef9..6806bf922584 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/authentication.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/authentication.py @@ -117,9 +117,6 @@ def _add_authorization_header(self, request, string_to_sign): raise _wrap_exception(ex, AzureSigningError) def on_request(self, request): - if not 'content-type' in request.http_request.headers: - request.http_request.headers['content-type'] = 'application/xml; charset=utf-8' - string_to_sign = \ self._get_verb(request) + \ self._get_headers(