Skip to content

Commit

Permalink
[Storage] [STG 98] Added support for x-ms-file-request-intent for B…
Browse files Browse the repository at this point in the history
…lob Copy APIs (#39578)
  • Loading branch information
weirongw23-msft authored Feb 13, 2025
1 parent 2937934 commit 6b0e358
Show file tree
Hide file tree
Showing 9 changed files with 666 additions and 11 deletions.
2 changes: 1 addition & 1 deletion sdk/storage/azure-storage-blob/assets.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "python",
"TagPrefix": "python/storage/azure-storage-blob",
"Tag": "python/storage/azure-storage-blob_880ac66fab"
"Tag": "python/storage/azure-storage-blob_5c69f3f177"
}
54 changes: 51 additions & 3 deletions sdk/storage/azure-storage-blob/azure/storage/blob/_blob_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,15 @@ def upload_blob_from_url(
:keyword str source_authorization:
Authenticate as a service principal using a client secret to access a source blob. Ensure "bearer " is
the prefix of the source_authorization string.
:keyword source_token_intent:
Required when source is Azure Storage Files and using `TokenCredential` for authentication.
This is ignored for other forms of authentication.
Specifies the intent for all requests when using `TokenCredential` authentication. Possible values are:
backup - Specifies requests are intended for backup/admin type operations, meaning that all file/directory
ACLs are bypassed and full permissions are granted. User must also have required RBAC permission.
:paramtype source_token_intent: Literal['backup']
:returns: Blob-updated property Dict (Etag and last modified)
:rtype: Dict[str, Any]
"""
Expand All @@ -430,7 +439,8 @@ def upload_blob_from_url(
options = _upload_blob_from_url_options(
source_url=source_url,
metadata=metadata,
**kwargs)
**kwargs
)
try:
return cast(Dict[str, Any], self._client.block_blob.put_blob_from_url(**options))
except HttpResponseError as error:
Expand Down Expand Up @@ -1746,6 +1756,15 @@ def start_copy_from_url(
.. versionadded:: 12.9.0
:keyword source_token_intent:
Required when source is Azure Storage Files and using `TokenCredential` for authentication.
This is ignored for other forms of authentication.
Specifies the intent for all requests when using `TokenCredential` authentication. Possible values are:
backup - Specifies requests are intended for backup/admin type operations, meaning that all file/directory
ACLs are bypassed and full permissions are granted. User must also have required RBAC permission.
:paramtype source_token_intent: Literal['backup']
:keyword str encryption_scope:
A predefined encryption scope used to encrypt the data on the sync copied blob. An encryption
scope can be created using the Management API and referenced here by name. If a default
Expand All @@ -1770,7 +1789,8 @@ def start_copy_from_url(
source_url=source_url,
metadata=metadata,
incremental_copy=incremental_copy,
**kwargs)
**kwargs
)
try:
if incremental_copy:
return cast(Dict[str, Union[str, datetime]], self._client.page_blob.copy_incremental(**options))
Expand Down Expand Up @@ -2046,6 +2066,15 @@ def stage_block_from_url(
:keyword str source_authorization:
Authenticate as a service principal using a client secret to access a source blob. Ensure "bearer " is
the prefix of the source_authorization string.
:keyword source_token_intent:
Required when source is Azure Storage Files and using `TokenCredential` for authentication.
This is ignored for other forms of authentication.
Specifies the intent for all requests when using `TokenCredential` authentication. Possible values are:
backup - Specifies requests are intended for backup/admin type operations, meaning that all file/directory
ACLs are bypassed and full permissions are granted. User must also have required RBAC permission.
:paramtype source_token_intent: Literal['backup']
:returns: Blob property dict.
:rtype: dict[str, Any]
"""
Expand All @@ -2057,7 +2086,8 @@ def stage_block_from_url(
source_offset=source_offset,
source_length=source_length,
source_content_md5=source_content_md5,
**kwargs)
**kwargs
)
try:
return cast(Dict[str, Any], self._client.block_blob.stage_block_from_url(**options))
except HttpResponseError as error:
Expand Down Expand Up @@ -2919,6 +2949,15 @@ def upload_pages_from_url(
:keyword str source_authorization:
Authenticate as a service principal using a client secret to access a source blob. Ensure "bearer " is
the prefix of the source_authorization string.
:keyword source_token_intent:
Required when source is Azure Storage Files and using `TokenCredential` for authentication.
This is ignored for other forms of authentication.
Specifies the intent for all requests when using `TokenCredential` authentication. Possible values are:
backup - Specifies requests are intended for backup/admin type operations, meaning that all file/directory
ACLs are bypassed and full permissions are granted. User must also have required RBAC permission.
:paramtype source_token_intent: Literal['backup']
:returns: Response after uploading pages from specified URL.
:rtype: Dict[str, Any]
"""
Expand Down Expand Up @@ -3211,6 +3250,15 @@ def append_block_from_url(
:keyword str source_authorization:
Authenticate as a service principal using a client secret to access a source blob. Ensure "bearer " is
the prefix of the source_authorization string.
:keyword source_token_intent:
Required when source is Azure Storage Files and using `TokenCredential` for authentication.
This is ignored for other forms of authentication.
Specifies the intent for all requests when using `TokenCredential` authentication. Possible values are:
backup - Specifies requests are intended for backup/admin type operations, meaning that all file/directory
ACLs are bypassed and full permissions are granted. User must also have required RBAC permission.
:paramtype source_token_intent: Literal['backup']
:returns: Result after appending a new block.
:rtype: Dict[str, Union[str, datetime, int]]
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ def _upload_blob_from_url_options(source_url: str, **kwargs: Any) -> Dict[str, A
overwrite = kwargs.pop('overwrite', False)
content_settings = kwargs.pop('content_settings', None)
source_authorization = kwargs.pop('source_authorization', None)
source_token_intent = kwargs.pop('source_token_intent', None)
if content_settings:
kwargs['blob_http_headers'] = BlobHTTPHeaders(
blob_cache_control=content_settings.cache_control,
Expand All @@ -214,6 +215,7 @@ def _upload_blob_from_url_options(source_url: str, **kwargs: Any) -> Dict[str, A

options = {
'copy_source_authorization': source_authorization,
'file_request_intent': source_token_intent,
'content_length': 0,
'copy_source_blob_properties': kwargs.pop('include_source_blob_properties', True),
'source_content_md5': kwargs.pop('source_content_md5', None),
Expand Down Expand Up @@ -607,6 +609,7 @@ def _start_copy_from_url_options( # pylint:disable=too-many-statements
requires_sync = kwargs.pop('requires_sync', None)
encryption_scope_str = kwargs.pop('encryption_scope', None)
source_authorization = kwargs.pop('source_authorization', None)
source_token_intent = kwargs.pop('source_token_intent', None)
# If tags is a str, interpret that as copy_source_tags
copy_source_tags = isinstance(tags, str)

Expand All @@ -626,6 +629,8 @@ def _start_copy_from_url_options( # pylint:disable=too-many-statements
headers['x-ms-encryption-scope'] = encryption_scope_str
if source_authorization:
headers['x-ms-copy-source-authorization'] = source_authorization
if source_token_intent:
headers['x-ms-file-request-intent'] = source_token_intent
if copy_source_tags:
headers['x-ms-copy-source-tag-option'] = tags
else:
Expand All @@ -635,6 +640,9 @@ def _start_copy_from_url_options( # pylint:disable=too-many-statements
if source_authorization:
raise ValueError(
"Source authorization tokens are only supported for sync copy, please specify requires_sync=True")
if source_token_intent:
raise ValueError(
"Source token intent is only supported for sync copy, please specify requires_sync=True")
if copy_source_tags:
raise ValueError(
"Copying source tags is only supported for sync copy, please specify requires_sync=True")
Expand Down Expand Up @@ -729,6 +737,7 @@ def _stage_block_from_url_options(
) -> Dict[str, Any]:
source_url = _encode_source_url(source_url=source_url)
source_authorization = kwargs.pop('source_authorization', None)
source_token_intent = kwargs.pop('source_token_intent', None)
if source_length is not None and source_offset is None:
raise ValueError("Source offset value must not be None if length is set.")
if source_length is not None and source_offset is not None:
Expand All @@ -747,6 +756,7 @@ def _stage_block_from_url_options(
encryption_algorithm=cpk.algorithm)
options = {
'copy_source_authorization': source_authorization,
'file_request_intent': source_token_intent,
'block_id': block_id,
'content_length': 0,
'source_url': source_url,
Expand Down Expand Up @@ -1010,6 +1020,7 @@ def _upload_pages_from_url_options(
if_sequence_number_equal_to=kwargs.pop('if_sequence_number_eq', None)
)
source_authorization = kwargs.pop('source_authorization', None)
source_token_intent = kwargs.pop('source_token_intent', None)
access_conditions = get_access_conditions(kwargs.pop('lease', None))
mod_conditions = get_modify_conditions(kwargs)
source_mod_conditions = get_source_conditions(kwargs)
Expand All @@ -1023,6 +1034,7 @@ def _upload_pages_from_url_options(

options = {
'copy_source_authorization': source_authorization,
'file_request_intent': source_token_intent,
'source_url': source_url,
'content_length': 0,
'source_range': source_range,
Expand Down Expand Up @@ -1152,6 +1164,7 @@ def _append_block_from_url_options(
append_position=appendpos_condition
)
source_authorization = kwargs.pop('source_authorization', None)
source_token_intent = kwargs.pop('source_token_intent', None)
access_conditions = get_access_conditions(kwargs.pop('lease', None))
mod_conditions = get_modify_conditions(kwargs)
source_mod_conditions = get_source_conditions(kwargs)
Expand All @@ -1164,6 +1177,7 @@ def _append_block_from_url_options(

options = {
'copy_source_authorization': source_authorization,
'file_request_intent': source_token_intent,
'source_url': copy_source_url,
'content_length': 0,
'source_range': source_range,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,15 @@ async def upload_blob_from_url(
:keyword str source_authorization:
Authenticate as a service principal using a client secret to access a source blob. Ensure "bearer " is
the prefix of the source_authorization string.
:keyword source_token_intent:
Required when source is Azure Storage Files and using `TokenCredential` for authentication.
This is ignored for other forms of authentication.
Specifies the intent for all requests when using `TokenCredential` authentication. Possible values are:
backup - Specifies requests are intended for backup/admin type operations, meaning that all file/directory
ACLs are bypassed and full permissions are granted. User must also have required RBAC permission.
:paramtype source_token_intent: Literal['backup']
:returns: Response from creating a new block blob for a given URL.
:rtype: Dict[str, Any]
"""
Expand All @@ -420,7 +429,8 @@ async def upload_blob_from_url(
options = _upload_blob_from_url_options(
source_url=source_url,
metadata=metadata,
**kwargs)
**kwargs
)
try:
return cast(Dict[str, Any], await self._client.block_blob.put_blob_from_url(**options))
except HttpResponseError as error:
Expand Down Expand Up @@ -1650,6 +1660,15 @@ async def start_copy_from_url(
.. versionadded:: 12.9.0
:keyword source_token_intent:
Required when source is Azure Storage Files and using `TokenCredential` for authentication.
This is ignored for other forms of authentication.
Specifies the intent for all requests when using `TokenCredential` authentication. Possible values are:
backup - Specifies requests are intended for backup/admin type operations, meaning that all file/directory
ACLs are bypassed and full permissions are granted. User must also have required RBAC permission.
:paramtype source_token_intent: Literal['backup']
:keyword str encryption_scope:
A predefined encryption scope used to encrypt the data on the sync copied blob. An encryption
scope can be created using the Management API and referenced here by name. If a default
Expand All @@ -1674,7 +1693,8 @@ async def start_copy_from_url(
source_url=source_url,
metadata=metadata,
incremental_copy=incremental_copy,
**kwargs)
**kwargs
)
try:
if incremental_copy:
return cast(Dict[str, Union[str, datetime]], await self._client.page_blob.copy_incremental(**options))
Expand Down Expand Up @@ -1944,6 +1964,15 @@ async def stage_block_from_url(
:keyword str source_authorization:
Authenticate as a service principal using a client secret to access a source blob. Ensure "bearer " is
the prefix of the source_authorization string.
:keyword source_token_intent:
Required when source is Azure Storage Files and using `TokenCredential` for authentication.
This is ignored for other forms of authentication.
Specifies the intent for all requests when using `TokenCredential` authentication. Possible values are:
backup - Specifies requests are intended for backup/admin type operations, meaning that all file/directory
ACLs are bypassed and full permissions are granted. User must also have required RBAC permission.
:paramtype source_token_intent: Literal['backup']
:returns: Blob property dict.
:rtype: Dict[str, Any]
"""
Expand All @@ -1955,7 +1984,8 @@ async def stage_block_from_url(
source_offset=source_offset,
source_length=source_length,
source_content_md5=source_content_md5,
**kwargs)
**kwargs
)
try:
return cast(Dict[str, Any], await self._client.block_blob.stage_block_from_url(**options))
except HttpResponseError as error:
Expand Down Expand Up @@ -2819,6 +2849,15 @@ async def upload_pages_from_url(
:keyword str source_authorization:
Authenticate as a service principal using a client secret to access a source blob. Ensure "bearer " is
the prefix of the source_authorization string.
:keyword source_token_intent:
Required when source is Azure Storage Files and using `TokenCredential` for authentication.
This is ignored for other forms of authentication.
Specifies the intent for all requests when using `TokenCredential` authentication. Possible values are:
backup - Specifies requests are intended for backup/admin type operations, meaning that all file/directory
ACLs are bypassed and full permissions are granted. User must also have required RBAC permission.
:paramtype source_token_intent: Literal['backup']
:returns: Response after uploading pages from specified URL.
:rtype: Dict[str, Any]
"""
Expand Down Expand Up @@ -3112,6 +3151,15 @@ async def append_block_from_url(
:keyword str source_authorization:
Authenticate as a service principal using a client secret to access a source blob. Ensure "bearer " is
the prefix of the source_authorization string.
:keyword source_token_intent:
Required when source is Azure Storage Files and using `TokenCredential` for authentication.
This is ignored for other forms of authentication.
Specifies the intent for all requests when using `TokenCredential` authentication. Possible values are:
backup - Specifies requests are intended for backup/admin type operations, meaning that all file/directory
ACLs are bypassed and full permissions are granted. User must also have required RBAC permission.
:paramtype source_token_intent: Literal['backup']
:returns: Result after appending a new block.
:rtype: Dict[str, Union[str, datetime, int]]
"""
Expand Down
1 change: 1 addition & 0 deletions sdk/storage/azure-storage-blob/dev_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
-e ../../../tools/azure-sdk-tools
-e ../../core/azure-core
-e ../../identity/azure-identity
-e ../azure-storage-file-share
azure-mgmt-storage==20.1.0
aiohttp>=3.0
Loading

0 comments on commit 6b0e358

Please sign in to comment.