This is an automated email from the ASF dual-hosted git repository. tomaz pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/libcloud.git
commit d9f6268a2ec0211219e21b1e4f56813d265e62f1 Author: Tomaz Muraus <to...@tomaz.me> AuthorDate: Fri Aug 4 15:40:38 2023 +0200 Implement timeout based guard for list_volumes(). This way we don't end up in an infinite loop due to the bug in the code, invalid server response or similar. --- libcloud/compute/drivers/azure_arm.py | 10 +++++++- ...oft_Compute_disks_PAGINATION_INFINITE_LOOP.json | 30 ++++++++++++++++++++++ libcloud/test/compute/test_azure_arm.py | 8 ++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/libcloud/compute/drivers/azure_arm.py b/libcloud/compute/drivers/azure_arm.py index b9a83c9a9..75e1b7020 100644 --- a/libcloud/compute/drivers/azure_arm.py +++ b/libcloud/compute/drivers/azure_arm.py @@ -71,6 +71,9 @@ VM_SIZE_API_VERSION = "2015-06-15" # this API is deprecated # etc). LIST_NODES_PAGINATION_TIMEOUT = 300 +# Pagination timeout for list_volumes() method. +LIST_VOLUMES_PAGINATION_TIMEOUT = 300 + class AzureImage(NodeImage): """Represents a Marketplace node image that an Azure VM can boot from.""" @@ -1032,11 +1035,16 @@ class AzureNodeDriver(NodeDriver): subscription_id=self.subscription_id, resource_group=ex_resource_group ) params = {"api-version": DISK_API_VERSION} + + now_ts = int(time.time()) + deadline_ts = now_ts + LIST_VOLUMES_PAGINATION_TIMEOUT + volumes = [] - while True: + while time.time() < deadline_ts: response = self.connection.request(action, method="GET", params=params) volumes.extend(self._to_volume(volume) for volume in response.object["value"]) if not response.object.get("nextLink"): + # No next page break parsed_next_link = urlparse.urlparse(response.object["nextLink"]) params.update({k: v[0] for k, v in parse_qs(parsed_next_link.query).items()}) diff --git a/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_providers_Microsoft_Compute_disks_PAGINATION_INFINITE_LOOP.json b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_providers_Microsoft_Compute_disks_PAGINATION_INFINITE_LOOP.json new file mode 100644 index 000000000..abe8380f8 --- /dev/null +++ b/libcloud/test/compute/fixtures/azure_arm/_subscriptions_99999999_providers_Microsoft_Compute_disks_PAGINATION_INFINITE_LOOP.json @@ -0,0 +1,30 @@ +{ + "value": [ + { + "properties": { + "osType": "Linux", + "creationData": { + "createOption": "FromImage", + "imageReference": { + "id": "/Subscriptions/99999999-9999-9999-9999-999999999999/Providers/Microsoft.Compute/Locations/eastus/Publishers/OpenLogic/ArtifactTypes/VMImage/Offers/CentOS/Skus/7.3/Versions/latest" + } + }, + "diskSizeGB": 1500, + "timeCreated": "2017-03-09T10:12:37.0256203+00:00", + "ownerId": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/REVIZOR/providers/Microsoft.Compute/virtualMachines/test-vm-2", + "provisioningState": "Succeeded", + "diskState": "Attached" + }, + "sku": { + "name": "Standard_LRS", + "tier": "Standard" + }, + "type": "Microsoft.Compute/disks", + "location": "eastus", + "tags": {}, + "id": "/subscriptions/99999999-9999-9999-9999-999999999999/resourceGroups/000000/providers/Microsoft.Compute/disks/test-disk-4", + "name": "test-disk-4", + "zones": ["1", "2", "3"] + } + ] +} \ No newline at end of file diff --git a/libcloud/test/compute/test_azure_arm.py b/libcloud/test/compute/test_azure_arm.py index 66992ff96..a8ec7539b 100644 --- a/libcloud/test/compute/test_azure_arm.py +++ b/libcloud/test/compute/test_azure_arm.py @@ -591,6 +591,14 @@ class AzureNodeDriverTests(LibcloudTestCase): self.assertEqual(volumes[0].extra["properties"]["diskState"], "Unattached") self.assertEqual(volumes[0].state, StorageVolumeState.AVAILABLE) + @mock.patch("libcloud.compute.drivers.azure_arm.LIST_NODES_PAGINATION_TIMEOUT", 1) + def test_list_volumes_pagination_timeout(self): + # Verify we don't end up in an infinite loop in case server returns a bad response or + # similar + AzureMockHttp.type = "PAGINATION_INFINITE_LOOP" + volumes = self.driver.list_volumes() + self.assertTrue(len(volumes) >= 1) + def test_attach_volume(self): volumes = self.driver.list_volumes() node = self.driver.list_nodes()[0]