diff --git a/SoftLayer/managers/block.py b/SoftLayer/managers/block.py index 74b5fb423..b1efd033c 100644 --- a/SoftLayer/managers/block.py +++ b/SoftLayer/managers/block.py @@ -510,6 +510,10 @@ def cancel_block_volume(self, volume_id, block_volume = self.get_block_volume_details( volume_id, mask='mask[id,billingItem[id,hourlyFlag]]') + + if 'billingItem' not in block_volume: + raise exceptions.SoftLayerError("Block Storage was already cancelled") + billing_item_id = block_volume['billingItem']['id'] if utils.lookup(block_volume, 'billingItem', 'hourlyFlag'): diff --git a/tests/managers/block_tests.py b/tests/managers/block_tests.py index 6f2e5eb6f..fa5dacb2b 100644 --- a/tests/managers/block_tests.py +++ b/tests/managers/block_tests.py @@ -41,33 +41,72 @@ def test_cancel_block_volume_immediately_hourly_billing(self): identifier=449, ) + def test_cancel_block_volume_exception_billing_item_not_found(self): + mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') + mock.return_value = { + 'capacityGb': 20, + 'createDate': '2017-06-20T14:24:21-06:00', + 'nasType': 'ISCSI', + 'storageTypeId': '7', + 'serviceResourceName': 'PerfStor Aggr aggr_staasdal0601_pc01' + } + exception = self.assertRaises( + exceptions.SoftLayerError, + self.block.cancel_block_volume, + 12345, + immediate=True + ) + self.assertEqual( + 'Block Storage was already cancelled', + str(exception) + ) + + def test_cancel_block_volume_billing_item_found(self): + mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') + mock.return_value = { + 'capacityGb': 20, + 'createDate': '2017-06-20T14:24:21-06:00', + 'nasType': 'ISCSI', + 'storageTypeId': '7', + 'serviceResourceName': 'PerfStor Aggr aggr_staasdal0601_pc01', + 'billingItem': {'hourlyFlag': True, 'id': 449}, + } + self.block.cancel_block_volume(123, immediate=False) + + self.assert_called_with( + 'SoftLayer_Billing_Item', + 'cancelItem', + args=(True, True, 'No longer needed'), + identifier=449, + ) + def test_get_block_volume_details(self): result = self.block.get_block_volume_details(100) self.assertEqual(fixtures.SoftLayer_Network_Storage.getObject, result) - expected_mask = 'id,'\ - 'username,'\ - 'password,'\ - 'capacityGb,'\ - 'snapshotCapacityGb,'\ - 'parentVolume.snapshotSizeBytes,'\ - 'storageType.keyName,'\ - 'serviceResource.datacenter[name],'\ - 'serviceResourceBackendIpAddress,'\ - 'storageTierLevel,'\ - 'provisionedIops,'\ - 'lunId,'\ - 'originalVolumeName,'\ - 'originalSnapshotName,'\ - 'originalVolumeSize,'\ - 'activeTransactionCount,'\ - 'activeTransactions.transactionStatus[friendlyName],'\ - 'replicationPartnerCount,'\ - 'replicationStatus,'\ - 'replicationPartners[id,username,'\ - 'serviceResourceBackendIpAddress,'\ - 'serviceResource[datacenter[name]],'\ + expected_mask = 'id,' \ + 'username,' \ + 'password,' \ + 'capacityGb,' \ + 'snapshotCapacityGb,' \ + 'parentVolume.snapshotSizeBytes,' \ + 'storageType.keyName,' \ + 'serviceResource.datacenter[name],' \ + 'serviceResourceBackendIpAddress,' \ + 'storageTierLevel,' \ + 'provisionedIops,' \ + 'lunId,' \ + 'originalVolumeName,' \ + 'originalSnapshotName,' \ + 'originalVolumeSize,' \ + 'activeTransactionCount,' \ + 'activeTransactions.transactionStatus[friendlyName],' \ + 'replicationPartnerCount,' \ + 'replicationStatus,' \ + 'replicationPartners[id,username,' \ + 'serviceResourceBackendIpAddress,' \ + 'serviceResource[datacenter[name]],' \ 'replicationSchedule[type[keyname]]]' self.assert_called_with( @@ -75,7 +114,7 @@ def test_get_block_volume_details(self): 'getObject', identifier=100, mask='mask[%s]' % expected_mask - ) + ) def test_list_block_volumes(self): result = self.block.list_block_volumes() @@ -96,14 +135,14 @@ def test_list_block_volumes(self): } } - expected_mask = 'id,'\ - 'username,'\ - 'lunId,'\ - 'capacityGb,'\ - 'bytesUsed,'\ - 'serviceResource.datacenter[name],'\ - 'serviceResourceBackendIpAddress,'\ - 'activeTransactionCount,'\ + expected_mask = 'id,' \ + 'username,' \ + 'lunId,' \ + 'capacityGb,' \ + 'bytesUsed,' \ + 'serviceResource.datacenter[name],' \ + 'serviceResourceBackendIpAddress,' \ + 'activeTransactionCount,' \ 'replicationPartnerCount' self.assert_called_with( @@ -138,14 +177,14 @@ def test_list_block_volumes_with_additional_filters(self): } } - expected_mask = 'id,'\ - 'username,'\ - 'lunId,'\ - 'capacityGb,'\ - 'bytesUsed,'\ - 'serviceResource.datacenter[name],'\ - 'serviceResourceBackendIpAddress,'\ - 'activeTransactionCount,'\ + expected_mask = 'id,' \ + 'username,' \ + 'lunId,' \ + 'capacityGb,' \ + 'bytesUsed,' \ + 'serviceResource.datacenter[name],' \ + 'serviceResourceBackendIpAddress,' \ + 'activeTransactionCount,' \ 'replicationPartnerCount' self.assert_called_with( @@ -357,22 +396,22 @@ def test_order_block_volume_performance(self): 'SoftLayer_Product_Order', 'placeOrder', args=({ - 'complexType': 'SoftLayer_Container_Product_Order_' - 'Network_Storage_AsAService', - 'packageId': 759, - 'prices': [ - {'id': 189433}, - {'id': 189443}, - {'id': 190113}, - {'id': 190173} - ], - 'volumeSize': 1000, - 'quantity': 1, - 'location': 449494, - 'iops': 2000, - 'useHourlyPricing': False, - 'osFormatType': {'keyName': 'LINUX'} - },) + 'complexType': 'SoftLayer_Container_Product_Order_' + 'Network_Storage_AsAService', + 'packageId': 759, + 'prices': [ + {'id': 189433}, + {'id': 189443}, + {'id': 190113}, + {'id': 190173} + ], + 'volumeSize': 1000, + 'quantity': 1, + 'location': 449494, + 'iops': 2000, + 'useHourlyPricing': False, + 'osFormatType': {'keyName': 'LINUX'} + },) ) def test_order_block_volume_endurance(self): @@ -401,21 +440,21 @@ def test_order_block_volume_endurance(self): 'SoftLayer_Product_Order', 'placeOrder', args=({ - 'complexType': 'SoftLayer_Container_Product_Order_' - 'Network_Storage_AsAService', - 'packageId': 759, - 'prices': [ - {'id': 189433}, - {'id': 189443}, - {'id': 194763}, - {'id': 194703} - ], - 'volumeSize': 1000, - 'quantity': 1, - 'location': 449494, - 'useHourlyPricing': False, - 'osFormatType': {'keyName': 'LINUX'} - },) + 'complexType': 'SoftLayer_Container_Product_Order_' + 'Network_Storage_AsAService', + 'packageId': 759, + 'prices': [ + {'id': 189433}, + {'id': 189443}, + {'id': 194763}, + {'id': 194703} + ], + 'volumeSize': 1000, + 'quantity': 1, + 'location': 449494, + 'useHourlyPricing': False, + 'osFormatType': {'keyName': 'LINUX'} + },) ) def test_authorize_host_to_volume(self): @@ -525,17 +564,17 @@ def test_order_block_snapshot_space_upgrade(self): 'SoftLayer_Product_Order', 'placeOrder', args=({ - 'complexType': 'SoftLayer_Container_Product_Order_Network_' - 'Storage_Enterprise_SnapshotSpace_Upgrade', - 'packageId': 759, - 'prices': [ - {'id': 193853} - ], - 'quantity': 1, - 'location': 449500, - 'volumeId': 102, - 'useHourlyPricing': False - },) + 'complexType': 'SoftLayer_Container_Product_Order_Network_' + 'Storage_Enterprise_SnapshotSpace_Upgrade', + 'packageId': 759, + 'prices': [ + {'id': 193853} + ], + 'quantity': 1, + 'location': 449500, + 'volumeId': 102, + 'useHourlyPricing': False + },) ) def test_order_block_snapshot_space(self): @@ -554,17 +593,17 @@ def test_order_block_snapshot_space(self): 'SoftLayer_Product_Order', 'placeOrder', args=({ - 'complexType': 'SoftLayer_Container_Product_Order_Network_' - 'Storage_Enterprise_SnapshotSpace', - 'packageId': 759, - 'prices': [ - {'id': 193613} - ], - 'quantity': 1, - 'location': 449500, - 'volumeId': 102, - 'useHourlyPricing': False - },) + 'complexType': 'SoftLayer_Container_Product_Order_Network_' + 'Storage_Enterprise_SnapshotSpace', + 'packageId': 759, + 'prices': [ + {'id': 193613} + ], + 'quantity': 1, + 'location': 449500, + 'volumeId': 102, + 'useHourlyPricing': False + },) ) def test_order_block_replicant_os_type_not_found(self): @@ -610,26 +649,26 @@ def test_order_block_replicant_performance_os_type_given(self): 'SoftLayer_Product_Order', 'placeOrder', args=({ - 'complexType': 'SoftLayer_Container_Product_Order_' - 'Network_Storage_AsAService', - 'packageId': 759, - 'prices': [ - {'id': 189433}, - {'id': 189443}, - {'id': 189993}, - {'id': 190053}, - {'id': 191193}, - {'id': 192033} - ], - 'volumeSize': 500, - 'quantity': 1, - 'location': 449494, - 'iops': 1000, - 'originVolumeId': 102, - 'originVolumeScheduleId': 978, - 'useHourlyPricing': False, - 'osFormatType': {'keyName': 'XEN'} - },) + 'complexType': 'SoftLayer_Container_Product_Order_' + 'Network_Storage_AsAService', + 'packageId': 759, + 'prices': [ + {'id': 189433}, + {'id': 189443}, + {'id': 189993}, + {'id': 190053}, + {'id': 191193}, + {'id': 192033} + ], + 'volumeSize': 500, + 'quantity': 1, + 'location': 449494, + 'iops': 1000, + 'originVolumeId': 102, + 'originVolumeScheduleId': 978, + 'useHourlyPricing': False, + 'osFormatType': {'keyName': 'XEN'} + },) ) def test_order_block_replicant_endurance(self): @@ -651,25 +690,25 @@ def test_order_block_replicant_endurance(self): 'SoftLayer_Product_Order', 'placeOrder', args=({ - 'complexType': 'SoftLayer_Container_Product_Order_' - 'Network_Storage_AsAService', - 'packageId': 759, - 'prices': [ - {'id': 189433}, - {'id': 189443}, - {'id': 193433}, - {'id': 193373}, - {'id': 193613}, - {'id': 194693} - ], - 'volumeSize': 500, - 'quantity': 1, - 'location': 449494, - 'originVolumeId': 102, - 'originVolumeScheduleId': 978, - 'useHourlyPricing': False, - 'osFormatType': {'keyName': 'LINUX'} - },) + 'complexType': 'SoftLayer_Container_Product_Order_' + 'Network_Storage_AsAService', + 'packageId': 759, + 'prices': [ + {'id': 189433}, + {'id': 189443}, + {'id': 193433}, + {'id': 193373}, + {'id': 193613}, + {'id': 194693} + ], + 'volumeSize': 500, + 'quantity': 1, + 'location': 449494, + 'originVolumeId': 102, + 'originVolumeScheduleId': 978, + 'useHourlyPricing': False, + 'osFormatType': {'keyName': 'LINUX'} + },) ) def test_order_block_duplicate_origin_os_type_not_found(self): @@ -709,23 +748,23 @@ def test_order_block_duplicate_performance_no_duplicate_snapshot(self): 'SoftLayer_Product_Order', 'placeOrder', args=({ - 'complexType': 'SoftLayer_Container_Product_Order_' - 'Network_Storage_AsAService', - 'packageId': 759, - 'prices': [ - {'id': 189433}, - {'id': 189443}, - {'id': 189993}, - {'id': 190053} - ], - 'volumeSize': 500, - 'quantity': 1, - 'location': 449500, - 'duplicateOriginVolumeId': 102, - 'osFormatType': {'keyName': 'LINUX'}, - 'iops': 1000, - 'useHourlyPricing': False - },)) + 'complexType': 'SoftLayer_Container_Product_Order_' + 'Network_Storage_AsAService', + 'packageId': 759, + 'prices': [ + {'id': 189433}, + {'id': 189443}, + {'id': 189993}, + {'id': 190053} + ], + 'volumeSize': 500, + 'quantity': 1, + 'location': 449500, + 'duplicateOriginVolumeId': 102, + 'osFormatType': {'keyName': 'LINUX'}, + 'iops': 1000, + 'useHourlyPricing': False + },)) def test_order_block_duplicate_performance(self): mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') @@ -743,7 +782,7 @@ def test_order_block_duplicate_performance(self): duplicate_iops=2000, duplicate_tier_level=None, duplicate_snapshot_size=10 - ) + ) self.assertEqual(fixtures.SoftLayer_Product_Order.placeOrder, result) @@ -751,25 +790,25 @@ def test_order_block_duplicate_performance(self): 'SoftLayer_Product_Order', 'placeOrder', args=({ - 'complexType': 'SoftLayer_Container_Product_Order_' - 'Network_Storage_AsAService', - 'packageId': 759, - 'prices': [ - {'id': 189433}, - {'id': 189443}, - {'id': 190113}, - {'id': 190173}, - {'id': 191193} - ], - 'volumeSize': 1000, - 'quantity': 1, - 'location': 449500, - 'duplicateOriginVolumeId': 102, - 'osFormatType': {'keyName': 'LINUX'}, - 'duplicateOriginSnapshotId': 470, - 'iops': 2000, - 'useHourlyPricing': False - },)) + 'complexType': 'SoftLayer_Container_Product_Order_' + 'Network_Storage_AsAService', + 'packageId': 759, + 'prices': [ + {'id': 189433}, + {'id': 189443}, + {'id': 190113}, + {'id': 190173}, + {'id': 191193} + ], + 'volumeSize': 1000, + 'quantity': 1, + 'location': 449500, + 'duplicateOriginVolumeId': 102, + 'osFormatType': {'keyName': 'LINUX'}, + 'duplicateOriginSnapshotId': 470, + 'iops': 2000, + 'useHourlyPricing': False + },)) def test_order_block_duplicate_endurance_no_duplicate_snapshot(self): mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') @@ -789,22 +828,22 @@ def test_order_block_duplicate_endurance_no_duplicate_snapshot(self): 'SoftLayer_Product_Order', 'placeOrder', args=({ - 'complexType': 'SoftLayer_Container_Product_Order_' - 'Network_Storage_AsAService', - 'packageId': 759, - 'prices': [ - {'id': 189433}, - {'id': 189443}, - {'id': 193433}, - {'id': 193373} - ], - 'volumeSize': 500, - 'quantity': 1, - 'location': 449500, - 'duplicateOriginVolumeId': 102, - 'osFormatType': {'keyName': 'LINUX'}, - 'useHourlyPricing': False - },)) + 'complexType': 'SoftLayer_Container_Product_Order_' + 'Network_Storage_AsAService', + 'packageId': 759, + 'prices': [ + {'id': 189433}, + {'id': 189443}, + {'id': 193433}, + {'id': 193373} + ], + 'volumeSize': 500, + 'quantity': 1, + 'location': 449500, + 'duplicateOriginVolumeId': 102, + 'osFormatType': {'keyName': 'LINUX'}, + 'useHourlyPricing': False + },)) def test_order_block_duplicate_endurance(self): mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') @@ -821,7 +860,7 @@ def test_order_block_duplicate_endurance(self): duplicate_iops=None, duplicate_tier_level=4, duplicate_snapshot_size=10 - ) + ) self.assertEqual(fixtures.SoftLayer_Product_Order.placeOrder, result) @@ -829,24 +868,24 @@ def test_order_block_duplicate_endurance(self): 'SoftLayer_Product_Order', 'placeOrder', args=({ - 'complexType': 'SoftLayer_Container_Product_Order_' - 'Network_Storage_AsAService', - 'packageId': 759, - 'prices': [ - {'id': 189433}, - {'id': 189443}, - {'id': 194763}, - {'id': 194703}, - {'id': 194943} - ], - 'volumeSize': 1000, - 'quantity': 1, - 'location': 449500, - 'duplicateOriginVolumeId': 102, - 'osFormatType': {'keyName': 'LINUX'}, - 'duplicateOriginSnapshotId': 470, - 'useHourlyPricing': False - },)) + 'complexType': 'SoftLayer_Container_Product_Order_' + 'Network_Storage_AsAService', + 'packageId': 759, + 'prices': [ + {'id': 189433}, + {'id': 189443}, + {'id': 194763}, + {'id': 194703}, + {'id': 194943} + ], + 'volumeSize': 1000, + 'quantity': 1, + 'location': 449500, + 'duplicateOriginVolumeId': 102, + 'osFormatType': {'keyName': 'LINUX'}, + 'duplicateOriginSnapshotId': 470, + 'useHourlyPricing': False + },)) def test_order_block_modified_performance(self): mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects')