Skip to content

Commit

Permalink
delete_blob supports x_ms_delete_snapshots
Browse files Browse the repository at this point in the history
Added support to delete blobs that have associated snapshots via the
x_ms_delete_snapshots header option.

Also added support for the timeout query parameter when deleting blobs.
  • Loading branch information
pneumee committed Oct 10, 2014
1 parent 2a51558 commit bea26ea
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 13 deletions.
28 changes: 25 additions & 3 deletions azure/storage/blobservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -1835,7 +1835,8 @@ def abort_copy_blob(self, container_name, blob_name, x_ms_copy_id,
self._perform_request(request)

def delete_blob(self, container_name, blob_name, snapshot=None,
x_ms_lease_id=None):
timeout=None, x_ms_lease_id=None,
x_ms_delete_snapshots=None):
'''
Marks the specified blob or snapshot for deletion. The blob is later
deleted during garbage collection.
Expand All @@ -1848,16 +1849,37 @@ def delete_blob(self, container_name, blob_name, snapshot=None,
snapshot:
Optional. The snapshot parameter is an opaque DateTime value that,
when present, specifies the blob snapshot to delete.
timeout:
Optional. The timeout parameter is expressed in seconds.
The Blob service returns an error when the timeout interval elapses
while processing the request.
x_ms_lease_id: Required if the blob has an active lease.
x_ms_delete_snapshots:
Required if the blob has associated snapshots. Specify one of the
following two options:
include: Delete the base blob and all of its snapshots.
only: Delete only the blob's snapshots and not the blob itself.
This header should be specified only for a request against the base
blob resource. If this header is specified on a request to delete
an individual snapshot, the Blob service returns status code 400
(Bad Request). If this header is not specified on the request and
the blob has associated snapshots, the Blob service returns status
code 409 (Conflict).
'''
_validate_not_none('container_name', container_name)
_validate_not_none('blob_name', blob_name)
request = HTTPRequest()
request.method = 'DELETE'
request.host = self._get_host()
request.path = '/' + _str(container_name) + '/' + _str(blob_name) + ''
request.headers = [('x-ms-lease-id', _str_or_none(x_ms_lease_id))]
request.query = [('snapshot', _str_or_none(snapshot))]
request.headers = [
('x-ms-lease-id', _str_or_none(x_ms_lease_id)),
('x-ms-delete-snapshots', _str_or_none(x_ms_delete_snapshots))
]
request.query = [
('snapshot', _str_or_none(snapshot)),
('timeout', _int_or_none(timeout))
]
request.path, request.query = _update_request_uri_query_local_storage(
request, self.use_local_storage)
request.headers = _update_storage_blob_header(
Expand Down
51 changes: 48 additions & 3 deletions tests/test_blobservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,17 @@ def setUp(self):
credentials.getStorageServicesKey())
set_service_options(self.bs)

self.bs2 = BlobService(credentials.getRemoteStorageServicesName(),
credentials.getRemoteStorageServicesKey())
set_service_options(self.bs2)
remote_storage_service_name = credentials.getRemoteStorageServicesName()
remote_storage_service_key = credentials.getRemoteStorageServicesKey()
if remote_storage_service_key and remote_storage_service_name:
self.bs2 = BlobService(credentials.getRemoteStorageServicesName(),
credentials.getRemoteStorageServicesKey())
set_service_options(self.bs2)
else:
print "Remote Storage Account not configured. Add " \
"'remotestorageserviceskey' and 'remotestorageservicesname'" \
" to windowsazurecredentials.json to test functionality " \
"involving multiple storage accounts."

# test chunking functionality by reducing the threshold
# for chunking and the size of each chunk, otherwise
Expand Down Expand Up @@ -1887,6 +1895,43 @@ def test_delete_blob_snapshot(self):
self.assertEqual(blobs[0].name, blob_name)
self.assertEqual(blobs[0].snapshot, '')

def test_delete_blob_snapshots(self):
# Arrange
self._create_container(self.container_name)
blob_name = 'blob1'
data = b'hello world'
self.bs.put_blob(self.container_name, blob_name, data, 'BlockBlob')
self.bs.snapshot_blob(self.container_name, blob_name)
blobs = self.bs.list_blobs(self.container_name, include='snapshots')
self.assertEqual(len(blobs), 2)

# Act
self.bs.delete_blob(self.container_name, blob_name,
x_ms_delete_snapshots='only')

# Assert
blobs = self.bs.list_blobs(self.container_name, include='snapshots')
self.assertEqual(len(blobs), 1)
self.assertEqual(blobs[0].snapshot, '')

def test_delete_blob_with_snapshots(self):
# Arrange
self._create_container(self.container_name)
blob_name = 'blob1'
data = b'hello world'
self.bs.put_blob(self.container_name, blob_name, data, 'BlockBlob')
self.bs.snapshot_blob(self.container_name, blob_name)
blobs = self.bs.list_blobs(self.container_name, include='snapshots')
self.assertEqual(len(blobs), 2)

# Act
self.bs.delete_blob(self.container_name, blob_name,
x_ms_delete_snapshots='include')

# Assert
blobs = self.bs.list_blobs(self.container_name, include='snapshots')
self.assertEqual(len(blobs), 0)

def test_copy_blob_with_existing_blob(self):
# Arrange
self._create_container_and_block_blob(
Expand Down
13 changes: 6 additions & 7 deletions tests/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,15 @@ def getStorageServicesName(self):

def getRemoteStorageServicesKey(self):
''' Key for remote storage account (different location). '''
return self.ns[u'remotestorageserviceskey']
if u'remotestorageserviceskey' in self.ns:
return self.ns[u'remotestorageserviceskey']
return None

def getRemoteStorageServicesName(self):
''' Name for remote storage account (different location). '''
return self.ns[u'remotestorageservicesname']
if u'remotestorageservicesname' in self.ns:
return self.ns[u'remotestorageservicesname']
return None

def getLinuxOSVHD(self):
return self.ns[u'linuxosvhd']
Expand Down Expand Up @@ -123,11 +127,6 @@ def getUseHttplibOverride(self):
return self.ns[u'usehttpliboverride'].lower() != 'false'
return None

def getRemoteStorageServicesKey(self):
return self.ns[u'remotestorageserviceskey']

def getRemoteStorageServicesName(self):
return self.ns[u'remotestorageservicesname']

credentials = Credentials()

Expand Down

0 comments on commit bea26ea

Please sign in to comment.