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

[Storage][STG75]Lease on Get/Set Tags & Find Blob by Tags #15090

Merged
merged 2 commits into from
Dec 1, 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
12 changes: 12 additions & 0 deletions sdk/storage/azure-storage-blob/azure/storage/blob/_blob_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2372,10 +2372,12 @@ def set_premium_page_blob_tier(self, premium_page_blob_tier, **kwargs):
def _set_blob_tags_options(self, tags=None, **kwargs):
# type: (Optional[Dict[str, str]], **Any) -> Dict[str, Any]
tags = serialize_blob_tags(tags)
access_conditions = get_access_conditions(kwargs.pop('lease', None))
mod_conditions = get_modify_conditions(kwargs)

options = {
'tags': tags,
'lease_access_conditions': access_conditions,
'modified_access_conditions': mod_conditions,
'cls': return_response_headers}
options.update(kwargs)
Expand Down Expand Up @@ -2410,6 +2412,10 @@ def set_blob_tags(self, tags=None, **kwargs):
blob.
:keyword str if_tags_match_condition:
Specify a SQL where clause on blob tags to operate only on destination blob with a matching value.
:keyword lease:
Required if the blob has an active lease. Value can be a BlobLeaseClient object
or the lease ID as a string.
:paramtype lease: ~azure.storage.blob.BlobLeaseClient or str
:keyword int timeout:
The timeout parameter is expressed in seconds.
:returns: Blob-updated property dict (Etag and last modified)
Expand All @@ -2423,11 +2429,13 @@ def set_blob_tags(self, tags=None, **kwargs):

def _get_blob_tags_options(self, **kwargs):
# type: (**Any) -> Dict[str, str]
access_conditions = get_access_conditions(kwargs.pop('lease', None))
mod_conditions = get_modify_conditions(kwargs)

options = {
'version_id': kwargs.pop('version_id', None),
'snapshot': self.snapshot,
'lease_access_conditions': access_conditions,
'modified_access_conditions': mod_conditions,
'timeout': kwargs.pop('timeout', None),
'cls': return_headers_and_deserialized}
Expand All @@ -2446,6 +2454,10 @@ def get_blob_tags(self, **kwargs):
value that, when present, specifies the version of the blob to add tags to.
:keyword str if_tags_match_condition:
Specify a SQL where clause on blob tags to operate only on destination blob with a matching value.
:keyword lease:
Required if the blob has an active lease. Value can be a BlobLeaseClient object
or the lease ID as a string.
:paramtype lease: ~azure.storage.blob.BlobLeaseClient or str
:keyword int timeout:
The timeout parameter is expressed in seconds.
:returns: Key value pairs of blob tags.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
from ._generated.models import StorageErrorException, StorageServiceProperties, KeyInfo
from ._container_client import ContainerClient
from ._blob_client import BlobClient
from ._models import ContainerPropertiesPaged, FilteredBlobPaged
from ._models import ContainerPropertiesPaged
from ._list_blobs_helper import FilteredBlobPaged
from ._serialize import get_api_version
from ._deserialize import service_stats_deserialize, service_properties_deserialize

Expand All @@ -47,6 +48,7 @@
CorsRule,
RetentionPolicy,
StaticWebsite,
FilteredBlob
)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
# --------------------------------------------------------------------------

from azure.core.paging import PageIterator, ItemPaged
from azure.storage.blob._deserialize import get_blob_properties_from_generated_code
from ._generated.models import StorageErrorException, BlobItemInternal, BlobPrefix as GenBlobPrefix
from ._models import BlobProperties
from ._deserialize import get_blob_properties_from_generated_code, parse_tags
from ._generated.models import StorageErrorException, BlobItemInternal, BlobPrefix as GenBlobPrefix, FilterBlobItem
from ._models import BlobProperties, FilteredBlob
from ._shared.models import DictMixin
from ._shared.response_handlers import return_context_and_deserialized, process_storage_error

Expand Down Expand Up @@ -164,3 +164,72 @@ def __init__(self, *args, **kwargs):
self.container = kwargs.get('container')
self.delimiter = kwargs.get('delimiter')
self.location_mode = kwargs.get('location_mode')


class FilteredBlobPaged(PageIterator):
"""An Iterable of Blob properties.

:ivar str service_endpoint: The service URL.
:ivar str prefix: A blob name prefix being used to filter the list.
:ivar str marker: The continuation token of the current page of results.
:ivar int results_per_page: The maximum number of results retrieved per API call.
:ivar str continuation_token: The continuation token to retrieve the next page of results.
:ivar str location_mode: The location mode being used to list results. The available
options include "primary" and "secondary".
:ivar current_page: The current page of listed results.
:vartype current_page: list(~azure.storage.blob.FilteredBlob)
:ivar str container: The container that the blobs are listed from.

:param callable command: Function to retrieve the next page of items.
:param str container: The name of the container.
:param int results_per_page: The maximum number of blobs to retrieve per
call.
:param str continuation_token: An opaque continuation token.
:param location_mode: Specifies the location the request should be sent to.
This mode only applies for RA-GRS accounts which allow secondary read access.
Options include 'primary' or 'secondary'.
"""
def __init__(
self, command,
container=None,
results_per_page=None,
continuation_token=None,
location_mode=None):
super(FilteredBlobPaged, self).__init__(
get_next=self._get_next_cb,
extract_data=self._extract_data_cb,
continuation_token=continuation_token or ""
)
self._command = command
self.service_endpoint = None
self.marker = continuation_token
self.results_per_page = results_per_page
self.container = container
self.current_page = None
self.location_mode = location_mode

def _get_next_cb(self, continuation_token):
try:
return self._command(
marker=continuation_token or None,
maxresults=self.results_per_page,
cls=return_context_and_deserialized,
use_location=self.location_mode)
except StorageErrorException as error:
process_storage_error(error)

def _extract_data_cb(self, get_next_return):
self.location_mode, self._response = get_next_return
self.service_endpoint = self._response.service_endpoint
self.marker = self._response.next_marker
self.current_page = [self._build_item(item) for item in self._response.blobs]

return self._response.next_marker or None, self.current_page

@staticmethod
def _build_item(item):
if isinstance(item, FilterBlobItem):
tags = parse_tags(item.tags)
blob = FilteredBlob(name=item.name, container_name=item.container_name, tags=tags)
return blob
return item
73 changes: 4 additions & 69 deletions sdk/storage/azure-storage-blob/azure/storage/blob/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from enum import Enum

from azure.core.paging import PageIterator
from azure.storage.blob._generated.models import FilterBlobItem, ArrowField
from ._generated.models import ArrowField

from ._shared import decode_base64_to_text
from ._shared.response_handlers import return_context_and_deserialized, process_storage_error
Expand Down Expand Up @@ -565,78 +565,13 @@ class FilteredBlob(DictMixin):
:type name: str
:ivar container_name: Container name.
:type container_name: str
:ivar tags: Key value pairs of blob tags.
:type tags: Dict[str, str]
"""
def __init__(self, **kwargs):
self.name = kwargs.get('name', None)
self.container_name = kwargs.get('container_name', None)


class FilteredBlobPaged(PageIterator):
"""An Iterable of Blob properties.

:ivar str service_endpoint: The service URL.
:ivar str prefix: A blob name prefix being used to filter the list.
:ivar str marker: The continuation token of the current page of results.
:ivar int results_per_page: The maximum number of results retrieved per API call.
:ivar str continuation_token: The continuation token to retrieve the next page of results.
:ivar str location_mode: The location mode being used to list results. The available
options include "primary" and "secondary".
:ivar current_page: The current page of listed results.
:vartype current_page: list(~azure.storage.blob.FilteredBlob)
:ivar str container: The container that the blobs are listed from.

:param callable command: Function to retrieve the next page of items.
:param str container: The name of the container.
:param int results_per_page: The maximum number of blobs to retrieve per
call.
:param str continuation_token: An opaque continuation token.
:param location_mode: Specifies the location the request should be sent to.
This mode only applies for RA-GRS accounts which allow secondary read access.
Options include 'primary' or 'secondary'.
"""
def __init__(
self, command,
container=None,
results_per_page=None,
continuation_token=None,
location_mode=None):
super(FilteredBlobPaged, self).__init__(
get_next=self._get_next_cb,
extract_data=self._extract_data_cb,
continuation_token=continuation_token or ""
)
self._command = command
self.service_endpoint = None
self.marker = continuation_token
self.results_per_page = results_per_page
self.container = container
self.current_page = None
self.location_mode = location_mode

def _get_next_cb(self, continuation_token):
try:
return self._command(
marker=continuation_token or None,
maxresults=self.results_per_page,
cls=return_context_and_deserialized,
use_location=self.location_mode)
except StorageErrorException as error:
process_storage_error(error)

def _extract_data_cb(self, get_next_return):
self.location_mode, self._response = get_next_return
self.service_endpoint = self._response.service_endpoint
self.marker = self._response.next_marker
self.current_page = [self._build_item(item) for item in self._response.blobs]

return self._response.next_marker or None, self.current_page

@staticmethod
def _build_item(item):
if isinstance(item, FilterBlobItem):
blob = FilteredBlob(name=item.name, container_name=item.container_name) # pylint: disable=protected-access
return blob
return item
self.tags = kwargs.get('tags', None)


class LeaseProperties(DictMixin):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1527,6 +1527,10 @@ async def set_blob_tags(self, tags=None, **kwargs):
:keyword str if_tags_match_condition:
Specify a SQL where clause on blob tags to operate only on blob with a matching value.
eg. "\"tagname\"='my tag'"
:keyword lease:
Required if the blob has an active lease. Value can be a BlobLeaseClient object
or the lease ID as a string.
:paramtype lease: ~azure.storage.blob.BlobLeaseClient or str
:keyword int timeout:
The timeout parameter is expressed in seconds.
:returns: Blob-updated property dict (Etag and last modified)
Expand All @@ -1552,6 +1556,10 @@ async def get_blob_tags(self, **kwargs):
:keyword str if_tags_match_condition:
Specify a SQL where clause on blob tags to operate only on blob with a matching value.
eg. "\"tagname\"='my tag'"
:keyword lease:
Required if the blob has an active lease. Value can be a BlobLeaseClient object
or the lease ID as a string.
:paramtype lease: ~azure.storage.blob.BlobLeaseClient or str
:keyword int timeout:
The timeout parameter is expressed in seconds.
:returns: Key value pairs of blob tags.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
# pylint: disable=super-init-not-called, too-many-lines

from azure.core.async_paging import AsyncPageIterator
from .._deserialize import parse_tags

from .._models import ContainerProperties, FilteredBlob
from .._shared.response_handlers import return_context_and_deserialized, process_storage_error
Expand Down Expand Up @@ -136,6 +137,7 @@ async def _extract_data_cb(self, get_next_return):
@staticmethod
def _build_item(item):
if isinstance(item, FilterBlobItem):
blob = FilteredBlob(name=item.name, container_name=item.container_name) # pylint: disable=protected-access
tags = parse_tags(item.tags)
blob = FilteredBlob(name=item.name, container_name=item.container_name, tags=tags)
return blob
return item
Loading