Skip to content

Commit

Permalink
[Tables] Cosmos workaround for Merge/Update (Azure#17888)
Browse files Browse the repository at this point in the history
  • Loading branch information
seankane-msft authored and benbp committed Apr 19, 2021
1 parent 8920028 commit f9cc68c
Show file tree
Hide file tree
Showing 101 changed files with 10,598 additions and 5,847 deletions.
2 changes: 1 addition & 1 deletion sdk/tables/azure-data-tables/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Release History

## 12.0.0b7 (Unreleased)

* Fixed issue with Cosmos merge operations

## 12.0.0b6 (2021-04-06)
* Updated deserialization of datetime fields in entities to support preservation of the service format with additional decimal place.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
AzureSasCredentialPolicy
)

from ._common_conversion import _to_utc_datetime
from ._common_conversion import _to_utc_datetime, _is_cosmos_endpoint
from ._shared_access_signature import QueryStringConstants
from ._constants import (
STORAGE_OAUTH_SCOPE,
Expand All @@ -47,6 +47,7 @@
from ._models import LocationMode, BatchTransactionResult
from ._authentication import SharedKeyCredentialPolicy
from ._policies import (
CosmosPatchTransformPolicy,
StorageHeadersPolicy,
StorageContentValidation,
StorageRequestHook,
Expand Down Expand Up @@ -80,7 +81,7 @@
}


class StorageAccountHostsMixin(object):
class StorageAccountHostsMixin(object): # pylint: disable=too-many-instance-attributes
def __init__(
self,
parsed_url, # type: Any
Expand All @@ -92,6 +93,7 @@ def __init__(
self._location_mode = kwargs.get("_location_mode", LocationMode.PRIMARY)
self._hosts = kwargs.get("_hosts")
self.scheme = parsed_url.scheme
self._cosmos_endpoint = _is_cosmos_endpoint(parsed_url.hostname)

if service not in ["blob", "queue", "file-share", "dfs", "table"]:
raise ValueError("Invalid service: {}".format(service))
Expand Down Expand Up @@ -149,6 +151,9 @@ def __init__(
HttpLoggingPolicy(**kwargs),
]

if self._cosmos_endpoint:
self._policies.insert(0, CosmosPatchTransformPolicy())

def __enter__(self):
self._client.__enter__()
return self
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,18 @@ def _sign_string(key, string_to_sign, key_is_base64=True):
digest = signed_hmac_sha256.digest()
encoded_digest = _encode_base64(digest)
return encoded_digest


def _is_cosmos_endpoint(url):
if ".table.cosmodb." in url:
return True

if ".table.cosmos." in url:
return True

return False


def _transform_patch_to_cosmos_post(request):
request.method = "POST"
request.headers["X-HTTP-Method"] = "MERGE"
10 changes: 10 additions & 0 deletions sdk/tables/azure-data-tables/azure/data/tables/_policies.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
)
from azure.core.exceptions import AzureError, ServiceRequestError, ServiceResponseError

from ._common_conversion import _transform_patch_to_cosmos_post
from ._models import LocationMode

try:
Expand Down Expand Up @@ -750,3 +751,12 @@ def get_backoff_time(self, settings):
)
random_range_end = self.backoff + self.random_jitter_range
return random_generator.uniform(random_range_start, random_range_end)


class CosmosPatchTransformPolicy(SansIOHTTPPolicy):
"""Policy to transform PATCH requests into POST requests with the "X-HTTP-Method":"MERGE" header set."""

def on_request(self, request):
# type: (PipelineRequest) -> Union[None, Awaitable[None]]
if request.http_request.method == "PATCH":
_transform_patch_to_cosmos_post(request.http_request)
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
Dict,
)

from ._common_conversion import _is_cosmos_endpoint, _transform_patch_to_cosmos_post
from ._models import UpdateMode
from ._serialize import _get_match_headers, _add_entity_properties

Expand Down Expand Up @@ -467,6 +468,8 @@ def _batch_merge_entity(
request = self._client._client.patch( # pylint: disable=protected-access
url, query_parameters, header_parameters, **body_content_kwargs
)
if _is_cosmos_endpoint(url):
_transform_patch_to_cosmos_post(request)
self._requests.append(request)

_batch_merge_entity.metadata = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
from .._generated.aio._configuration import AzureTableConfiguration
from .._models import BatchErrorException, BatchTransactionResult
from .._policies import (
CosmosPatchTransformPolicy,
StorageContentValidation,
StorageRequestHook,
StorageHosts,
Expand Down Expand Up @@ -106,7 +107,6 @@ def _configure_policies(self, **kwargs):

kwargs.setdefault("connection_timeout", CONNECTION_TIMEOUT)
kwargs.setdefault("read_timeout", READ_TIMEOUT)

self._policies = [
StorageHeadersPolicy(**kwargs),
ProxyPolicy(**kwargs),
Expand All @@ -124,6 +124,9 @@ def _configure_policies(self, **kwargs):
HttpLoggingPolicy(**kwargs),
]

if self._cosmos_endpoint:
self._policies.insert(0, CosmosPatchTransformPolicy())

async def _batch_send(
self,
entities, # type: List[TableEntity]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from azure.core.pipeline import PipelineResponse


from .._common_conversion import _is_cosmos_endpoint, _transform_patch_to_cosmos_post
from .._models import UpdateMode
from .._serialize import (
_get_match_headers,
Expand Down Expand Up @@ -458,6 +458,8 @@ def _batch_merge_entity(
request = self._client._client.patch( # pylint: disable=protected-access
url, query_parameters, header_parameters, **body_content_kwargs
)
if _is_cosmos_endpoint(url):
_transform_patch_to_cosmos_post(request)
self._requests.append(request)

_batch_merge_entity.metadata = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from azure.core.tracing.decorator_async import distributed_trace_async

from .._base_client import parse_connection_str
from .._common_conversion import _is_cosmos_endpoint
from .._constants import CONNECTION_TIMEOUT
from .._entity import TableEntity
from .._generated.aio import AzureTable
Expand Down Expand Up @@ -71,6 +72,9 @@ def __init__(
**kwargs
)
loop = kwargs.pop("loop", None)

self._cosmos_endpoint = _is_cosmos_endpoint(account_url)

super(TableClient, self).__init__(
account_url,
table_name=table_name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ interactions:
DataServiceVersion:
- '3.0'
Date:
- Mon, 05 Apr 2021 20:52:56 GMT
- Wed, 07 Apr 2021 22:25:39 GMT
User-Agent:
- azsdk-python-data-tables/12.0.0b6 Python/3.7.4 (Windows-10-10.0.19041-SP0)
- azsdk-python-data-tables/12.0.0b7 Python/3.9.0rc1 (Windows-10-10.0.19041-SP0)
x-ms-date:
- Mon, 05 Apr 2021 20:52:56 GMT
- Wed, 07 Apr 2021 22:25:39 GMT
x-ms-version:
- '2019-02-02'
method: POST
Expand All @@ -33,7 +33,7 @@ interactions:
content-type:
- application/json;odata=minimalmetadata;streaming=true;charset=utf-8
date:
- Mon, 05 Apr 2021 20:52:59 GMT
- Wed, 07 Apr 2021 22:25:39 GMT
location:
- https://fake_table_account.table.core.windows.net/Tables('uttablee75e13f0')
server:
Expand Down Expand Up @@ -63,26 +63,26 @@ interactions:
DataServiceVersion:
- '3.0'
Date:
- Mon, 05 Apr 2021 20:52:56 GMT
- Wed, 07 Apr 2021 22:25:39 GMT
User-Agent:
- azsdk-python-data-tables/12.0.0b6 Python/3.7.4 (Windows-10-10.0.19041-SP0)
- azsdk-python-data-tables/12.0.0b7 Python/3.9.0rc1 (Windows-10-10.0.19041-SP0)
x-ms-date:
- Mon, 05 Apr 2021 20:52:56 GMT
- Wed, 07 Apr 2021 22:25:39 GMT
x-ms-version:
- '2019-02-02'
method: POST
uri: https://fake_table_account.table.core.windows.net/Tables
response:
body:
string: '{"odata.error":{"code":"TableAlreadyExists","message":{"lang":"en-US","value":"The
table specified already exists.\nRequestId:3a9bd1f0-0002-000c-7e5d-2a4d2c000000\nTime:2021-04-05T20:53:02.8814645Z"}}}'
table specified already exists.\nRequestId:4faf3acc-6002-00a3-01fc-2bbfe1000000\nTime:2021-04-07T22:25:41.7333309Z"}}}'
headers:
cache-control:
- no-cache
content-type:
- application/json;odata=minimalmetadata;streaming=true;charset=utf-8
date:
- Mon, 05 Apr 2021 20:53:02 GMT
- Wed, 07 Apr 2021 22:25:40 GMT
server:
- Windows-Azure-Table/1.0 Microsoft-HTTPAPI/2.0
transfer-encoding:
Expand All @@ -106,11 +106,11 @@ interactions:
Content-Length:
- '0'
Date:
- Mon, 05 Apr 2021 20:53:03 GMT
- Wed, 07 Apr 2021 22:25:41 GMT
User-Agent:
- azsdk-python-data-tables/12.0.0b6 Python/3.7.4 (Windows-10-10.0.19041-SP0)
- azsdk-python-data-tables/12.0.0b7 Python/3.9.0rc1 (Windows-10-10.0.19041-SP0)
x-ms-date:
- Mon, 05 Apr 2021 20:53:03 GMT
- Wed, 07 Apr 2021 22:25:41 GMT
x-ms-version:
- '2019-02-02'
method: DELETE
Expand All @@ -124,7 +124,7 @@ interactions:
content-length:
- '0'
date:
- Mon, 05 Apr 2021 20:53:03 GMT
- Wed, 07 Apr 2021 22:25:41 GMT
server:
- Windows-Azure-Table/1.0 Microsoft-HTTPAPI/2.0
x-content-type-options:
Expand All @@ -146,26 +146,26 @@ interactions:
Content-Length:
- '0'
Date:
- Mon, 05 Apr 2021 20:53:03 GMT
- Wed, 07 Apr 2021 22:25:41 GMT
User-Agent:
- azsdk-python-data-tables/12.0.0b6 Python/3.7.4 (Windows-10-10.0.19041-SP0)
- azsdk-python-data-tables/12.0.0b7 Python/3.9.0rc1 (Windows-10-10.0.19041-SP0)
x-ms-date:
- Mon, 05 Apr 2021 20:53:03 GMT
- Wed, 07 Apr 2021 22:25:41 GMT
x-ms-version:
- '2019-02-02'
method: DELETE
uri: https://fake_table_account.table.core.windows.net/Tables('uttablee75e13f0')
response:
body:
string: '{"odata.error":{"code":"ResourceNotFound","message":{"lang":"en-US","value":"The
specified resource does not exist.\nRequestId:3a9bd24c-0002-000c-4e5d-2a4d2c000000\nTime:2021-04-05T20:53:03.7921084Z"}}}'
specified resource does not exist.\nRequestId:4faf3af7-6002-00a3-26fc-2bbfe1000000\nTime:2021-04-07T22:25:42.0355353Z"}}}'
headers:
cache-control:
- no-cache
content-type:
- application/json;odata=minimalmetadata;streaming=true;charset=utf-8
date:
- Mon, 05 Apr 2021 20:53:03 GMT
- Wed, 07 Apr 2021 22:25:41 GMT
server:
- Windows-Azure-Table/1.0 Microsoft-HTTPAPI/2.0
transfer-encoding:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ interactions:
DataServiceVersion:
- '3.0'
Date:
- Mon, 05 Apr 2021 20:53:04 GMT
- Wed, 07 Apr 2021 22:32:50 GMT
User-Agent:
- azsdk-python-data-tables/12.0.0b6 Python/3.7.4 (Windows-10-10.0.19041-SP0)
- azsdk-python-data-tables/12.0.0b7 Python/3.9.0rc1 (Windows-10-10.0.19041-SP0)
x-ms-date:
- Mon, 05 Apr 2021 20:53:04 GMT
- Wed, 07 Apr 2021 22:32:50 GMT
x-ms-version:
- '2019-02-02'
method: POST
Expand All @@ -33,7 +33,7 @@ interactions:
content-type:
- application/json;odata=minimalmetadata;streaming=true;charset=utf-8
date:
- Mon, 05 Apr 2021 20:53:04 GMT
- Wed, 07 Apr 2021 22:32:51 GMT
location:
- https://fake_table_account.table.core.windows.net/Tables('uttable270d0f94')
server:
Expand Down Expand Up @@ -63,26 +63,26 @@ interactions:
DataServiceVersion:
- '3.0'
Date:
- Mon, 05 Apr 2021 20:53:04 GMT
- Wed, 07 Apr 2021 22:32:50 GMT
User-Agent:
- azsdk-python-data-tables/12.0.0b6 Python/3.7.4 (Windows-10-10.0.19041-SP0)
- azsdk-python-data-tables/12.0.0b7 Python/3.9.0rc1 (Windows-10-10.0.19041-SP0)
x-ms-date:
- Mon, 05 Apr 2021 20:53:04 GMT
- Wed, 07 Apr 2021 22:32:50 GMT
x-ms-version:
- '2019-02-02'
method: POST
uri: https://fake_table_account.table.core.windows.net/Tables
response:
body:
string: '{"odata.error":{"code":"TableAlreadyExists","message":{"lang":"en-US","value":"The
table specified already exists.\nRequestId:71db8f83-4002-0032-1b5d-2ada53000000\nTime:2021-04-05T20:53:22.8853531Z"}}}'
table specified already exists.\nRequestId:0451134d-a002-0077-1dfd-2b0fb0000000\nTime:2021-04-07T22:33:07.4938348Z"}}}'
headers:
cache-control:
- no-cache
content-type:
- application/json;odata=minimalmetadata;streaming=true;charset=utf-8
date:
- Mon, 05 Apr 2021 20:53:22 GMT
- Wed, 07 Apr 2021 22:33:07 GMT
server:
- Windows-Azure-Table/1.0 Microsoft-HTTPAPI/2.0
transfer-encoding:
Expand All @@ -106,11 +106,11 @@ interactions:
Content-Length:
- '0'
Date:
- Mon, 05 Apr 2021 20:53:23 GMT
- Wed, 07 Apr 2021 22:33:07 GMT
User-Agent:
- azsdk-python-data-tables/12.0.0b6 Python/3.7.4 (Windows-10-10.0.19041-SP0)
- azsdk-python-data-tables/12.0.0b7 Python/3.9.0rc1 (Windows-10-10.0.19041-SP0)
x-ms-date:
- Mon, 05 Apr 2021 20:53:23 GMT
- Wed, 07 Apr 2021 22:33:07 GMT
x-ms-version:
- '2019-02-02'
method: DELETE
Expand All @@ -124,7 +124,7 @@ interactions:
content-length:
- '0'
date:
- Mon, 05 Apr 2021 20:53:22 GMT
- Wed, 07 Apr 2021 22:33:07 GMT
server:
- Windows-Azure-Table/1.0 Microsoft-HTTPAPI/2.0
x-content-type-options:
Expand All @@ -146,26 +146,26 @@ interactions:
Content-Length:
- '0'
Date:
- Mon, 05 Apr 2021 20:53:23 GMT
- Wed, 07 Apr 2021 22:33:07 GMT
User-Agent:
- azsdk-python-data-tables/12.0.0b6 Python/3.7.4 (Windows-10-10.0.19041-SP0)
- azsdk-python-data-tables/12.0.0b7 Python/3.9.0rc1 (Windows-10-10.0.19041-SP0)
x-ms-date:
- Mon, 05 Apr 2021 20:53:23 GMT
- Wed, 07 Apr 2021 22:33:07 GMT
x-ms-version:
- '2019-02-02'
method: DELETE
uri: https://fake_table_account.table.core.windows.net/Tables('uttable270d0f94')
response:
body:
string: '{"odata.error":{"code":"ResourceNotFound","message":{"lang":"en-US","value":"The
specified resource does not exist.\nRequestId:71db9005-4002-0032-195d-2ada53000000\nTime:2021-04-05T20:53:23.8910718Z"}}}'
specified resource does not exist.\nRequestId:0451138c-a002-0077-5afd-2b0fb0000000\nTime:2021-04-07T22:33:07.7860414Z"}}}'
headers:
cache-control:
- no-cache
content-type:
- application/json;odata=minimalmetadata;streaming=true;charset=utf-8
date:
- Mon, 05 Apr 2021 20:53:23 GMT
- Wed, 07 Apr 2021 22:33:07 GMT
server:
- Windows-Azure-Table/1.0 Microsoft-HTTPAPI/2.0
transfer-encoding:
Expand Down
Loading

0 comments on commit f9cc68c

Please sign in to comment.