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

Share Lease Feature #13567

Merged
merged 43 commits into from
Oct 1, 2020
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
4023b8c
added needed parameters for shares
tasherif-msft Sep 4, 2020
89bd0b9
added async methods
tasherif-msft Sep 4, 2020
b869c88
added more methods for interacting with the API
tasherif-msft Sep 4, 2020
c82d692
fixed small mistake with elif
tasherif-msft Sep 10, 2020
1df00f3
added tests and access conditions
tasherif-msft Sep 10, 2020
95642ec
added more tests for leases
tasherif-msft Sep 11, 2020
cc9a1ff
fixed tests
tasherif-msft Sep 11, 2020
9391ee6
async changes
tasherif-msft Sep 11, 2020
86e2afc
added await
tasherif-msft Sep 11, 2020
9a71f09
corrected import
tasherif-msft Sep 11, 2020
c0509d8
fixed async imports and wrote all tests
tasherif-msft Sep 11, 2020
1393a4d
linting
tasherif-msft Sep 11, 2020
fde4b0d
share renaming
tasherif-msft Sep 11, 2020
c96f6d0
added file lease sample
tasherif-msft Sep 15, 2020
98d516f
added sample for share
tasherif-msft Sep 15, 2020
1457d32
fixed samples
tasherif-msft Sep 15, 2020
8f1733c
added docs
tasherif-msft Sep 24, 2020
2bfb563
removed checks
tasherif-msft Sep 24, 2020
d2ad99d
lease change
tasherif-msft Sep 24, 2020
d7a2e71
lease change
tasherif-msft Sep 24, 2020
e11d418
added correct lease durations
tasherif-msft Sep 24, 2020
bf66330
removed spacing
tasherif-msft Sep 24, 2020
3c03bc1
version correction
tasherif-msft Sep 24, 2020
83a70f1
fixed snapshot
tasherif-msft Sep 25, 2020
f3df73e
added snapshot tests
tasherif-msft Sep 25, 2020
f5ea020
added snapshot tests
tasherif-msft Sep 25, 2020
b72cc88
changed version
tasherif-msft Sep 25, 2020
5350e11
test
tasherif-msft Sep 25, 2020
5e4c34d
test
tasherif-msft Sep 25, 2020
98c4ea4
more docstrings
tasherif-msft Sep 25, 2020
40651b4
fixed docstrings
tasherif-msft Sep 26, 2020
3c5cc0c
more docstring changes
tasherif-msft Sep 26, 2020
725ba49
removed etag
tasherif-msft Sep 26, 2020
84d86e7
added exta check on test
tasherif-msft Sep 26, 2020
a94c9e9
fixed tests
tasherif-msft Sep 28, 2020
d524b59
added more tests for file
tasherif-msft Sep 28, 2020
b11489d
added tests for list shares
tasherif-msft Sep 29, 2020
4920a90
unused import
tasherif-msft Sep 29, 2020
e12f3f1
Merge branch 'feature/storage-stg74' into share-lease
xiafu-msft Sep 30, 2020
5677bd5
changed method signitures
tasherif-msft Sep 30, 2020
c03fba4
Merge branch 'share-lease' of github.com:tasherif-msft/azure-sdk-for-…
tasherif-msft Sep 30, 2020
60b263e
fixed kwargs
tasherif-msft Oct 1, 2020
8e83837
linter
tasherif-msft Oct 1, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ def from_connection_string(

@distributed_trace
def acquire_lease(self, lease_id=None, **kwargs):
# type: (int, Optional[str], **Any) -> BlobLeaseClient
# type: (Optional[str], **Any) -> ShareLeaseClient
tasherif-msft marked this conversation as resolved.
Show resolved Hide resolved
"""Requests a new lease.

If the file does not have an active lease, the File
Expand All @@ -283,12 +283,12 @@ def acquire_lease(self, lease_id=None, **kwargs):

.. admonition:: Example:

.. literalinclude:: ../samples/blob_samples_common.py
:start-after: [START acquire_lease_on_blob]
:end-before: [END acquire_lease_on_blob]
.. literalinclude:: ../samples/file_samples_client.py
:start-after: [START acquire_and_release_lease_on_file]
:end-before: [END acquire_and_release_lease_on_file]
:language: python
:dedent: 8
:caption: Acquiring a lease on a blob.
:dedent: 12
:caption: Acquiring a lease on a file.
"""
lease = ShareLeaseClient(self, lease_id=lease_id) # type: ignore
lease.acquire(**kwargs)
Expand Down
115 changes: 96 additions & 19 deletions sdk/storage/azure-storage-file-share/azure/storage/fileshare/_lease.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,25 @@
import uuid

from typing import ( # pylint: disable=unused-import
Optional, Any, TypeVar, TYPE_CHECKING
Union, Optional, Any, TypeVar, TYPE_CHECKING
)

from azure.core.tracing.decorator import distributed_trace

from ._shared.response_handlers import return_response_headers, process_storage_error
from ._generated.models import StorageErrorException
from ._generated.operations import FileOperations

if TYPE_CHECKING:
from datetime import datetime
ShareFileClient = TypeVar("ShareFileClient")
ShareClient = TypeVar("ShareClient")


class ShareLeaseClient(object):
"""Creates a new ShareLeaseClient.

This client provides lease operations on a ShareFileClient.
This client provides lease operations on a ShareClient or ShareFileClient.

:ivar str id:
The ID of the lease currently being maintained. This will be `None` if no
Expand All @@ -36,23 +38,28 @@ class ShareLeaseClient(object):
This will be `None` if no lease has yet been acquired or modified.

:param client:
The client of the file to lease.
:type client: ~azure.storage.fileshare.ShareFileClient
The client of the file or share to lease.
:type client: ~azure.storage.fileshare.ShareFileClient or
~azure.storage.fileshare.ShareClient
:param str lease_id:
A string representing the lease ID of an existing lease. This value does not
need to be specified in order to acquire a new lease, or break one.
"""
def __init__(
self, client, lease_id=None
): # pylint: disable=missing-client-constructor-parameter-credential,missing-client-constructor-parameter-kwargs
# type: (ShareFileClient, Optional[str]) -> None
# type: (Union[ShareFileClient, ShareClient], Optional[str]) -> None
self.id = lease_id or str(uuid.uuid4())
self.last_modified = None
self.etag = None
if hasattr(client, 'file_name'):
self._client = client._client.file # type: ignore # pylint: disable=protected-access
self.snapshot = None
elif hasattr(client, 'share_name'):
self._client = client._client.share
self.snapshot = client.snapshot
else:
raise TypeError("Lease must use ShareFileClient.")
raise TypeError("Lease must use ShareFileClient or ShareClient.")

def __enter__(self):
return self
Expand All @@ -61,17 +68,23 @@ def __exit__(self, *args):
self.release()

@distributed_trace
def acquire(self, **kwargs):
def acquire(self, lease_duration=-1, **kwargs):
tasherif-msft marked this conversation as resolved.
Show resolved Hide resolved
# type: (int, **Any) -> None
"""Requests a new lease. This operation establishes and manages a lock on a
file for write and delete operations. If the file does not have an active lease,
the File service creates a lease on the file. If the file has an active lease,
file or share for write and delete operations. If the file or share does not have an active lease,
the File or Share service creates a lease on the file or share. If the file has an active lease,
you can only request a new lease using the active lease ID.


If the file does not have an active lease, the File service creates a
If the file or share does not have an active lease, the File or Share service creates a
lease on the file and returns a new lease ID.

:param int lease_duration:
Specifies the duration of the lease, in seconds, or negative one
(-1) for a lease that never expires. File leases never expire. A non-infinite share lease can be
between 15 and 60 seconds. A share lease duration cannot be changed
using renew or change. Default is -1 (infinite share lease).

:keyword int timeout:
The timeout parameter is expressed in seconds.
:rtype: None
Expand All @@ -82,24 +95,68 @@ def acquire(self, **kwargs):
duration=-1,
proposed_lease_id=self.id,
cls=return_response_headers,
**kwargs) if isinstance(self._client, FileOperations) \
else self._client.acquire_lease(
timeout=kwargs.pop('timeout', None),
duration=lease_duration,
sharesnapshot=self.snapshot,
proposed_lease_id=self.id,
cls=return_response_headers,
**kwargs)

except StorageErrorException as error:
process_storage_error(error)
self.id = response.get('lease_id') # type: str
self.last_modified = response.get('last_modified') # type: datetime
self.etag = response.get('etag') # type: str

@distributed_trace
def release(self, **kwargs):
def renew(self, **kwargs):
# type: (Any) -> None
"""Releases the lease. The lease may be released if the lease ID specified on the request matches
that associated with the file. Releasing the lease allows another client to immediately acquire the lease
for the file as soon as the release is complete.
"""Renews the share lease.

The share lease can be renewed if the lease ID specified in the
lease client matches that associated with the share. Note that
the lease may be renewed even if it has expired as long as the share
has not been leased again since the expiration of that lease. When you
renew a lease, the lease duration clock resets.

:keyword str etag:
An ETag value, or the wildcard character (*). Used to check if the resource has changed,
and act according to the condition specified by the `match_condition` parameter.
:keyword ~azure.core.MatchConditions match_condition:
The match condition to use upon the etag.
:keyword str if_tags_match_condition
tasherif-msft marked this conversation as resolved.
Show resolved Hide resolved
Specify a SQL where clause on share tags to operate only on share with a matching value.
eg. "\"tagname\"='my tag'"

The lease may be released if the client lease id specified matches
that associated with the file. Releasing the lease allows another client
to immediately acquire the lease for the file as soon as the release is complete.
.. versionadded:: 12.4.0

:keyword int timeout:
The timeout parameter is expressed in seconds.
:return: None
"""
if isinstance(self._client, FileOperations):
tasherif-msft marked this conversation as resolved.
Show resolved Hide resolved
raise TypeError("Lease renewal operations are only valid for ShareClient.")
try:
response = self._client.renew_lease(
lease_id=self.id,
timeout=kwargs.pop('timeout', None),
sharesnapshot=self.snapshot,
cls=return_response_headers,
**kwargs)
except StorageErrorException as error:
process_storage_error(error)
self.etag = response.get('etag') # type: str
self.id = response.get('lease_id') # type: str
self.last_modified = response.get('last_modified') # type: datetime

@distributed_trace
def release(self, **kwargs):
# type: (Any) -> None
"""Releases the lease. The lease may be released if the lease ID specified on the request matches
that associated with the share or file. Releasing the lease allows another client to immediately acquire
the lease for the share or file as soon as the release is complete.

:keyword int timeout:
The timeout parameter is expressed in seconds.
Expand All @@ -110,7 +167,14 @@ def release(self, **kwargs):
lease_id=self.id,
timeout=kwargs.pop('timeout', None),
cls=return_response_headers,
**kwargs) if isinstance(self._client, FileOperations) \
else self._client.renew_lease(
lease_id=self.id,
timeout=kwargs.pop('timeout', None),
sharesnapshot=self.snapshot,
cls=return_response_headers,
tasherif-msft marked this conversation as resolved.
Show resolved Hide resolved
**kwargs)

except StorageErrorException as error:
process_storage_error(error)
self.etag = response.get('etag') # type: str
Expand All @@ -125,7 +189,7 @@ def change(self, proposed_lease_id, **kwargs):


:param str proposed_lease_id:
Proposed lease ID, in a GUID string format. The File service returns 400
Proposed lease ID, in a GUID string format. The File or Share service returns 400
tasherif-msft marked this conversation as resolved.
Show resolved Hide resolved
(Invalid request) if the proposed lease ID is not in the correct format.
:keyword int timeout:
The timeout parameter is expressed in seconds.
Expand All @@ -137,7 +201,15 @@ def change(self, proposed_lease_id, **kwargs):
proposed_lease_id=proposed_lease_id,
timeout=kwargs.pop('timeout', None),
cls=return_response_headers,
**kwargs) if isinstance(self._client, FileOperations) \
else self._client.change_lease(
lease_id=self.id,
proposed_lease_id=proposed_lease_id,
timeout=kwargs.pop('timeout', None),
sharesnapshot=self.snapshot,
cls=return_response_headers,
**kwargs)
tasherif-msft marked this conversation as resolved.
Show resolved Hide resolved

except StorageErrorException as error:
process_storage_error(error)
self.etag = response.get('etag') # type: str
Expand All @@ -147,7 +219,7 @@ def change(self, proposed_lease_id, **kwargs):
@distributed_trace
def break_lease(self, **kwargs):
# type: (Optional[int], Any) -> int
"""Force breaks the lease if the file has an active lease. Any authorized request can break the lease;
"""Force breaks the lease if the file or share has an active lease. Any authorized request can break the lease;
the request is not required to specify a matching lease ID. An infinite lease breaks immediately.

Once a lease is broken, it cannot be changed. Any authorized request can break the lease;
Expand All @@ -164,6 +236,11 @@ def break_lease(self, **kwargs):
response = self._client.break_lease(
timeout=kwargs.pop('timeout', None),
cls=return_response_headers,
**kwargs) if isinstance(self._client, FileOperations) \
else self._client.break_lease(
timeout=kwargs.pop('timeout', None),
sharesnapshot=self.snapshot,
cls=return_response_headers,
**kwargs)
except StorageErrorException as error:
process_storage_error(error)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ def __init__(self, **kwargs):
self.provisioned_egress_mbps = kwargs.get('x-ms-share-provisioned-egress-mbps')
self.provisioned_ingress_mbps = kwargs.get('x-ms-share-provisioned-ingress-mbps')
self.provisioned_iops = kwargs.get('x-ms-share-provisioned-iops')
self.lease = LeaseProperties(**kwargs)

@classmethod
def _from_generated(cls, generated):
Expand All @@ -322,6 +323,7 @@ def _from_generated(cls, generated):
props.provisioned_egress_mbps = generated.properties.provisioned_egress_mbps
props.provisioned_ingress_mbps = generated.properties.provisioned_ingress_mbps
props.provisioned_iops = generated.properties.provisioned_iops
props.lease = LeaseProperties._from_generated(generated) # pylint: disable=protected-access
return props


Expand Down