Open bluenote10 opened 7 months ago
Hi @bluenote10 ,
Thanks a lot for bringing this to us. We'll fix it.
@EmmaZhu Thanks for looking into this issue!
We actually noticed another inconsistency, which is closely related. The reproduction snippet would be:
import time
from azure.storage.blob import BlobServiceClient
def check_write_to_blob_after_lease_expire(
blob_service_client: BlobServiceClient,
container: str,
blob_path: str,
):
print("Writing initial blob...")
blob_service_client.get_container_client(container).upload_blob(
blob_path, "original content", overwrite=True
)
print("Acquiring lease...")
blob_client = blob_service_client.get_blob_client(container, blob_path)
lease = blob_client.acquire_lease(lease_duration=15)
print("Waiting for lease to expire...")
time.sleep(20)
print("Writing to blob with lease, after lease has expired...")
blob_client.upload_blob("modified_content", lease=lease, overwrite=True)
Using Azurite this errors with a LeaseNotPresentWithBlobOperation
code:
azure.core.exceptions.HttpResponseError: A lease ID was specified, but the lease for the blob has expired.
RequestId:c7aad088-ff38-4c4b-9593-f37324bf43a1
Time:2024-02-12T16:24:08.275Z
ErrorCode:LeaseNotPresentWithBlobOperation
Content: <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Error>
<Code>LeaseNotPresentWithBlobOperation</Code>
<Message>A lease ID was specified, but the lease for the blob has expired.
RequestId:c7aad088-ff38-4c4b-9593-f37324bf43a1
Time:2024-02-12T16:24:08.275Z</Message>
</Error>
But on Azure it actually errors with code LeaseLost
:
azure.core.exceptions.HttpResponseError: A lease ID was specified, but the lease for the blob has expired.
RequestId:4cd75829-801e-004a-2cd0-5dd089000000
Time:2024-02-12T16:27:59.4300167Z
ErrorCode:LeaseLost
Content: <?xml version="1.0" encoding="utf-8"?><Error><Code>LeaseLost</Code><Message>A lease ID was specified, but the lease for the blob has expired.
RequestId:4cd75829-801e-004a-2cd0-5dd089000000
Time:2024-02-12T16:27:59.4300167Z</Message></Error>
The inconsistency in the error codes makes it awkward to handle that case in a way that works for both Azurite and real Azure. Also LeaseLost
sounds a bit more appropriate than LeaseNotPresentWithBlobOperation
(in fact the lease is present with the blob operation, and that is even the problem, because the blob would even be writable if the blob operation would omit the lease...).
@EmmaZhu Is this covered by https://github.com/Azure/Azurite/pull/2354 as well? Or do you want me to open a separate issue for that?
Which service(blob, file, queue, table) does this issue concern?
blob
Which version of the Azurite was used?
3.29.0
Where do you get Azurite? (npm, DockerHub, NuGet, Visual Studio Code Extension)
DockerHub
What's the Node.js version?
None (or the one shipped with the Docker container)
What problem was encountered?
According to Azure's Lease Blob specification, a
renew
should be rejection if the lease has expired and the blob has been modified in the meantime. This is also the behavior we can see on Azure itself, i.e., therenew
gets properly rejected with an error in this case.With Azurite however, the
renew
is not rejected, and thus, diverges from the Azure specs.Steps to reproduce the issue?
The following Python snippet can be used to replay the test scenario:
When giving the snippet a
BlobServiceClient
pointing to real Azure the output is:I.e., the renew gets rejected properly. With Azurite there is no exception, and the renewal silently passes.
I'll try to figure out how to get to the Azurite logs and attach them hopefully soon... EDIT: I'm mainly seeing just:
Have you found a mitigation/solution?
No.