Skip to content
Open
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
20 changes: 15 additions & 5 deletions barman/cloud_providers/azure_blob_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -658,14 +658,24 @@ def _take_snapshot(self, backup_info, resource_group, location, disk_name, disk_
"""
snapshot_name = "%s-%s" % (disk_name, backup_info.backup_id.lower())
_logger.info("Taking snapshot '%s' of disk '%s'", snapshot_name, disk_name)
# azure-mgmt-compute 38.0.0 tightened its request deserializer and rejects
# the flat-dict payload barman previously sent: `incremental` and
# `creation_data` live under `properties.*` in the wire format. Build the
# request with the Snapshot/CreationData model objects so it works on both
# the lenient and strict deserializer tracks. See issue #1186.
compute = import_azure_mgmt_compute()
snapshot_model = compute.models.Snapshot(
location=location,
incremental=True,
creation_data=compute.models.CreationData(
create_option="Copy",
source_uri=disk_id,
),
)
resp = self.client.snapshots.begin_create_or_update(
resource_group,
snapshot_name,
{
"location": location,
"incremental": True,
"creation_data": {"create_option": "Copy", "source_uri": disk_id},
},
snapshot_model,
)

_logger.info("Waiting for snapshot '%s' completion", snapshot_name)
Expand Down
24 changes: 15 additions & 9 deletions tests/test_cloud_snapshot_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -1649,22 +1649,28 @@ def test_take_snapshot(self, caplog):
)

# THEN begin_create_or_update is called on the SnapshotsOperations with the
# expected args
# expected args. The payload is built with the azure-mgmt-compute model
# objects (Snapshot / CreationData) so the strict deserializer in
# azure-mgmt-compute 38+ accepts it.
expected_disk_id = self.azure_disks[0]["id"]
expected_disk_name = self.azure_disks[0]["name"]
expected_location = self.azure_disks[0]["location"]
expected_snapshot_name = self._get_snapshot_name(expected_disk_name)
mock_snapshot_model = self._mock_azure_mgmt_compute.models.Snapshot
mock_creation_data_model = self._mock_azure_mgmt_compute.models.CreationData
mock_creation_data_model.assert_called_once_with(
create_option="Copy",
source_uri=expected_disk_id,
)
mock_snapshot_model.assert_called_once_with(
location=expected_location,
incremental=True,
creation_data=mock_creation_data_model.return_value,
)
mock_snapshot_operations.begin_create_or_update.assert_called_once_with(
self.azure_resource_group,
expected_snapshot_name,
{
"location": expected_location,
"incremental": True,
"creation_data": {
"create_option": "Copy",
"source_uri": expected_disk_id,
},
},
mock_snapshot_model.return_value,
)
# AND wait() was called on the response to await completion of the snapshot
mock_resp.wait.assert_called_once()
Expand Down