From 6b5eaf9ec8c731aec710ede7dcd5f752d56cda54 Mon Sep 17 00:00:00 2001 From: Sunil Rajput Date: Mon, 31 Jul 2017 11:32:05 -0500 Subject: [PATCH 1/7] Add File and Block hourly billing feature changes --- SoftLayer/CLI/block/order.py | 23 +++++++- SoftLayer/CLI/file/order.py | 23 +++++++- SoftLayer/managers/block.py | 29 +++++++--- SoftLayer/managers/file.py | 29 +++++++--- SoftLayer/managers/storage_utils.py | 19 +++++- tests/CLI/modules/block_tests.py | 90 +++++++++++++++++++++++++++++ tests/CLI/modules/file_tests.py | 86 +++++++++++++++++++++++++++ 7 files changed, 273 insertions(+), 26 deletions(-) diff --git a/SoftLayer/CLI/block/order.py b/SoftLayer/CLI/block/order.py index 865a38e23..34271e3ff 100644 --- a/SoftLayer/CLI/block/order.py +++ b/SoftLayer/CLI/block/order.py @@ -56,13 +56,28 @@ 'storage_as_a_service', 'enterprise', 'performance'])) +@click.option('--billing', + type=click.Choice(['hourly', 'monthly']), + default='monthly', + show_default=True, + help="Optional parameter for Billing rate. Default to monthly") @environment.pass_env def cli(env, storage_type, size, iops, tier, os_type, - location, snapshot_size, service_offering): + location, snapshot_size, service_offering, billing): """Order a block storage volume.""" block_manager = SoftLayer.BlockStorageManager(env.client) storage_type = storage_type.lower() + hourly_billing_flag = False + if billing.lower() == "hourly": + hourly_billing_flag = True + + if hourly_billing_flag and service_offering != 'storage_as_a_service': + raise exceptions.CLIAbort( + 'Hourly billing is only available for the storage_as_a_service ' + 'service offering' + ) + if storage_type == 'performance': if iops is None: raise exceptions.CLIAbort( @@ -87,7 +102,8 @@ def cli(env, storage_type, size, iops, tier, os_type, iops=iops, os_type=os_type, snapshot_size=snapshot_size, - service_offering=service_offering + service_offering=service_offering, + hourly_billing_flag=hourly_billing_flag ) except ValueError as ex: raise exceptions.ArgumentError(str(ex)) @@ -107,7 +123,8 @@ def cli(env, storage_type, size, iops, tier, os_type, tier_level=float(tier), os_type=os_type, snapshot_size=snapshot_size, - service_offering=service_offering + service_offering=service_offering, + hourly_billing_flag=hourly_billing_flag ) except ValueError as ex: raise exceptions.ArgumentError(str(ex)) diff --git a/SoftLayer/CLI/file/order.py b/SoftLayer/CLI/file/order.py index c9ba4abcd..bd2731f17 100644 --- a/SoftLayer/CLI/file/order.py +++ b/SoftLayer/CLI/file/order.py @@ -44,13 +44,28 @@ 'storage_as_a_service', 'enterprise', 'performance'])) +@click.option('--billing', + type=click.Choice(['hourly', 'monthly']), + default='monthly', + show_default=True, + help="Optional parameter for Billing rate. Default to monthly") @environment.pass_env def cli(env, storage_type, size, iops, tier, - location, snapshot_size, service_offering): + location, snapshot_size, service_offering, billing): """Order a file storage volume.""" file_manager = SoftLayer.FileStorageManager(env.client) storage_type = storage_type.lower() + hourly_billing_flag = False + if billing.lower() == "hourly": + hourly_billing_flag = True + + if hourly_billing_flag and service_offering != 'storage_as_a_service': + raise exceptions.CLIAbort( + 'Hourly billing is only available for the storage_as_a_service ' + 'service offering' + ) + if storage_type == 'performance': if iops is None: raise exceptions.CLIAbort( @@ -74,7 +89,8 @@ def cli(env, storage_type, size, iops, tier, size=size, iops=iops, snapshot_size=snapshot_size, - service_offering=service_offering + service_offering=service_offering, + hourly_billing_flag=hourly_billing_flag ) except ValueError as ex: raise exceptions.ArgumentError(str(ex)) @@ -93,7 +109,8 @@ def cli(env, storage_type, size, iops, tier, size=size, tier_level=float(tier), snapshot_size=snapshot_size, - service_offering=service_offering + service_offering=service_offering, + hourly_billing_flag=hourly_billing_flag ) except ValueError as ex: raise exceptions.ArgumentError(str(ex)) diff --git a/SoftLayer/managers/block.py b/SoftLayer/managers/block.py index eb6d49264..3ffcbd5c8 100644 --- a/SoftLayer/managers/block.py +++ b/SoftLayer/managers/block.py @@ -234,9 +234,10 @@ def order_replicant_volume(self, volume_id, snapshot_schedule, :return: Returns a SoftLayer_Container_Product_Order_Receipt """ - block_mask = 'billingItem[activeChildren],storageTierLevel,osType,'\ - 'staasVersion,hasEncryptionAtRest,snapshotCapacityGb,'\ - 'schedules,hourlySchedule,dailySchedule,weeklySchedule,'\ + block_mask = 'billingItem[activeChildren,hourlyFlag],'\ + 'storageTierLevel,osType,staasVersion,'\ + 'hasEncryptionAtRest,snapshotCapacityGb,schedules,'\ + 'hourlySchedule,dailySchedule,weeklySchedule,'\ 'storageType[keyName],provisionedIops' block_volume = self.get_block_volume_details(volume_id, mask=block_mask) @@ -308,7 +309,8 @@ def delete_snapshot(self, snapshot_id): def order_block_volume(self, storage_type, location, size, os_type, iops=None, tier_level=None, snapshot_size=None, - service_offering='storage_as_a_service'): + service_offering='storage_as_a_service', + hourly_billing_flag=False): """Places an order for a block volume. :param storage_type: 'performance' or 'endurance' @@ -321,10 +323,12 @@ def order_block_volume(self, storage_type, location, size, os_type, if snapshot space should also be ordered (None if not ordered) :param service_offering: Requested offering package to use in the order ('storage_as_a_service', 'enterprise', or 'performance') + :param hourly_billing_flag: Billing type, monthly (False) + or hourly (True), default to monthly. """ order = storage_utils.prepare_volume_order_object( self, storage_type, location, size, iops, tier_level, - snapshot_size, service_offering, 'block' + snapshot_size, service_offering, 'block', hourly_billing_flag ) order['osFormatType'] = {'keyName': os_type} @@ -352,8 +356,9 @@ def order_snapshot_space(self, volume_id, capacity, tier, :param boolean upgrade: Flag to indicate if this order is an upgrade :return: Returns a SoftLayer_Container_Product_Order_Receipt """ - block_mask = 'id,billingItem[location],storageType[keyName],'\ - 'storageTierLevel,provisionedIops,staasVersion,hasEncryptionAtRest' + block_mask = 'id,billingItem[location,hourlyFlag],'\ + 'storageType[keyName],storageTierLevel,provisionedIops,'\ + 'staasVersion,hasEncryptionAtRest' block_volume = self.get_block_volume_details(volume_id, mask=block_mask, **kwargs) @@ -376,7 +381,7 @@ def cancel_snapshot_space(self, volume_id, block_volume = self.get_block_volume_details( volume_id, - mask='mask[id,billingItem[activeChildren]]') + mask='mask[id,billingItem[activeChildren,hourlyFlag]]') if 'activeChildren' not in block_volume['billingItem']: raise exceptions.SoftLayerError( @@ -394,6 +399,9 @@ def cancel_snapshot_space(self, volume_id, raise exceptions.SoftLayerError( 'No snapshot space found to cancel') + if utils.lookup(block_volume, 'billingItem', 'hourlyFlag'): + immediate = True + return self.client['Billing_Item'].cancelItem( immediate, True, @@ -456,9 +464,12 @@ def cancel_block_volume(self, volume_id, """ block_volume = self.get_block_volume_details( volume_id, - mask='mask[id,billingItem[id]]') + mask='mask[id,billingItem[id,hourlyFlag]]') billing_item_id = block_volume['billingItem']['id'] + if utils.lookup(block_volume, 'billingItem', 'hourlyFlag'): + immediate = True + return self.client['Billing_Item'].cancelItem( immediate, True, diff --git a/SoftLayer/managers/file.py b/SoftLayer/managers/file.py index 7f12a7bf4..3350e11e4 100644 --- a/SoftLayer/managers/file.py +++ b/SoftLayer/managers/file.py @@ -213,9 +213,10 @@ def order_replicant_volume(self, volume_id, snapshot_schedule, :return: Returns a SoftLayer_Container_Product_Order_Receipt """ - file_mask = 'billingItem[activeChildren],storageTierLevel,'\ - 'staasVersion,hasEncryptionAtRest,snapshotCapacityGb,'\ - 'schedules,hourlySchedule,dailySchedule,weeklySchedule,'\ + file_mask = 'billingItem[activeChildren,hourlyFlag],'\ + 'storageTierLevel,staasVersion,'\ + 'hasEncryptionAtRest,snapshotCapacityGb,schedules,'\ + 'hourlySchedule,dailySchedule,weeklySchedule,'\ 'storageType[keyName],provisionedIops' file_volume = self.get_file_volume_details(volume_id, mask=file_mask) @@ -288,7 +289,8 @@ def delete_snapshot(self, snapshot_id): def order_file_volume(self, storage_type, location, size, iops=None, tier_level=None, snapshot_size=None, - service_offering='storage_as_a_service'): + service_offering='storage_as_a_service', + hourly_billing_flag=False): """Places an order for a file volume. :param storage_type: 'performance' or 'endurance' @@ -300,10 +302,12 @@ def order_file_volume(self, storage_type, location, size, if snapshot space should also be ordered (None if not ordered) :param service_offering: Requested offering package to use in the order ('storage_as_a_service', 'enterprise', or 'performance') + :param hourly_billing_flag: Billing type, monthly (False) + or hourly (True), default to monthly. """ order = storage_utils.prepare_volume_order_object( self, storage_type, location, size, iops, tier_level, - snapshot_size, service_offering, 'file' + snapshot_size, service_offering, 'file', hourly_billing_flag ) return self.client.call('Product_Order', 'placeOrder', order) @@ -367,8 +371,9 @@ def order_snapshot_space(self, volume_id, capacity, tier, :param boolean upgrade: Flag to indicate if this order is an upgrade :return: Returns a SoftLayer_Container_Product_Order_Receipt """ - file_mask = 'id,billingItem[location],storageType[keyName],'\ - 'storageTierLevel,provisionedIops,staasVersion,hasEncryptionAtRest' + file_mask = 'id,billingItem[location,hourlyFlag],'\ + 'storageType[keyName],storageTierLevel,provisionedIops,'\ + 'staasVersion,hasEncryptionAtRest' file_volume = self.get_file_volume_details(volume_id, mask=file_mask, **kwargs) @@ -391,7 +396,7 @@ def cancel_snapshot_space(self, volume_id, file_volume = self.get_file_volume_details( volume_id, - mask='mask[id,billingItem[activeChildren]]') + mask='mask[id,billingItem[activeChildren,hourlyFlag]]') if 'activeChildren' not in file_volume['billingItem']: raise exceptions.SoftLayerError( @@ -409,6 +414,9 @@ def cancel_snapshot_space(self, volume_id, raise exceptions.SoftLayerError( 'No snapshot space found to cancel') + if utils.lookup(file_volume, 'billingItem', 'hourlyFlag'): + immediate = True + return self.client['Billing_Item'].cancelItem( immediate, True, @@ -438,9 +446,12 @@ def cancel_file_volume(self, volume_id, """ file_volume = self.get_file_volume_details( volume_id, - mask='mask[id,billingItem[id]]') + mask='mask[id,billingItem[id,hourlyFlag]]') billing_item_id = file_volume['billingItem']['id'] + if utils.lookup(file_volume, 'billingItem', 'hourlyFlag'): + immediate = True + return self.client['Billing_Item'].cancelItem( immediate, True, diff --git a/SoftLayer/managers/storage_utils.py b/SoftLayer/managers/storage_utils.py index 14ae573a7..f7b47d124 100644 --- a/SoftLayer/managers/storage_utils.py +++ b/SoftLayer/managers/storage_utils.py @@ -581,6 +581,11 @@ def prepare_snapshot_order_object(manager, volume, capacity, tier, upgrade): complex_type = 'SoftLayer_Container_Product_Order_'\ 'Network_Storage_Enterprise_SnapshotSpace' + # Determine if hourly billing should be used + hourly_billing_flag = utils.lookup(volume, 'billingItem', 'hourlyFlag') + if hourly_billing_flag is None: + hourly_billing_flag = False + # Build and return the order object snapshot_space_order = { 'complexType': complex_type, @@ -588,7 +593,8 @@ def prepare_snapshot_order_object(manager, volume, capacity, tier, upgrade): 'prices': prices, 'quantity': 1, 'location': volume['billingItem']['location']['id'], - 'volumeId': volume['id'] + 'volumeId': volume['id'], + 'useHourlyPricing': hourly_billing_flag } return snapshot_space_order @@ -596,7 +602,8 @@ def prepare_snapshot_order_object(manager, volume, capacity, tier, upgrade): def prepare_volume_order_object(manager, storage_type, location, size, iops, tier, snapshot_size, - service_offering, volume_type): + service_offering, volume_type, + hourly_billing_flag): """Prepare the order object which is submitted to the placeOrder() method :param manager: The File or Block manager calling this function @@ -608,6 +615,7 @@ def prepare_volume_order_object(manager, storage_type, location, size, :param snapshot_size: The size of snapshot space for the volume (optional) :param service_offering: Requested offering package to use for the order :param volume_type: The type of the volume to order ('file' or 'block') + :param hourly_billing_flag: Billing type, monthly (False) or hourly (True) :return: Returns the order object for the Product_Order service's placeOrder() method """ @@ -689,6 +697,7 @@ def prepare_volume_order_object(manager, storage_type, location, size, 'prices': prices, 'quantity': 1, 'location': location_id, + 'useHourlyPricing': hourly_billing_flag } if order_type_is_saas: @@ -847,6 +856,11 @@ def prepare_replicant_order_object(manager, snapshot_schedule, location, find_ent_space_price(package, 'replication', volume_size, tier) ] + # Determine if hourly billing should be used + hourly_billing_flag = utils.lookup(volume, 'billingItem', 'hourlyFlag') + if hourly_billing_flag is None: + hourly_billing_flag = False + # Build and return the order object replicant_order = { 'complexType': complex_type, @@ -856,6 +870,7 @@ def prepare_replicant_order_object(manager, snapshot_schedule, location, 'location': location_id, 'originVolumeId': volume['id'], 'originVolumeScheduleId': snapshot_schedule_id, + 'useHourlyPricing': hourly_billing_flag } if order_type_is_saas: diff --git a/tests/CLI/modules/block_tests.py b/tests/CLI/modules/block_tests.py index b535a50a7..99db71241 100644 --- a/tests/CLI/modules/block_tests.py +++ b/tests/CLI/modules/block_tests.py @@ -181,6 +181,50 @@ def test_volume_order_performance(self, order_mock): ' > 0.25 IOPS per GB\n > 20 GB Storage Space\n' ' > 10 GB Storage Space (Snapshot Space)\n') + @mock.patch('SoftLayer.BlockStorageManager.order_block_volume') + def test_volume_order_performance_hourly_billing_not_available( + self, order_mock): + order_mock.return_value = {} + result = self.run_command(['block', 'volume-order', + '--storage-type=performance', '--size=20', + '--os-type=linux', '--location=dal10', + '--service-offering=enterprise', + '--billing=hourly', '--iops=200']) + + self.assertEqual(2, result.exit_code) + self.assertEqual(result.output, + '--billing : hourly billing is only available ' + 'for storage_as_a_service ') + + @mock.patch('SoftLayer.BlockStorageManager.order_block_volume') + def test_volume_order_performance_hourly(self, order_mock): + + order_mock.return_value = { + 'placedOrder': { + 'id': 10983646, + 'items': [ + {'description': 'Storage as a Service'}, + {'description': 'Block Storage'}, + {'description': '20 GBs'}, + {'description': '200 IOPS'}, + {'description': '0.25 IOPS per GB'}] + } + } + + result = self.run_command(['block', 'volume-order', + '--storage-type=performance', '--size=20', + '--os-type=linux', + '--location=dal10', + '--service-offering=storage_as_a_service', + '--billing=hourly', '--iops=200']) + self.assert_no_fail(result) + self.assertEqual(result.output, + 'Order #10983646 placed successfully!\n' + ' > Storage as a Service' + ' > Block Storage\n' + ' > 20 GBs \n' + ' > 200 IOPS \n') + def test_volume_order_endurance_tier_not_given(self): result = self.run_command(['block', 'volume-order', '--storage-type=endurance', '--size=20', @@ -228,6 +272,52 @@ def test_volume_order_order_not_placed(self, order_mock): 'Order could not be placed! Please verify ' 'your options and try again.\n') + + @mock.patch('SoftLayer.BlockStorageManager.order_block_volume') + def test_volume_order_endurance_hourly_billing_not_available( + self, order_mock): + order_mock.return_value = {} + result = self.run_command(['block', 'volume-order', + '--storage-type=endurance', '--size=20', + '--tier=0.25', '--os-type=linux', + '--location=dal10', + '--service-offering enterprise', + '--billing hourly', '--iops 200']) + + self.assertEqual(2, result.exit_code) + self.assertEqual(result.output, + '--billing : hourly billing is only available ' + 'for storage_as_a_service ') + + @mock.patch('SoftLayer.BlockStorageManager.order_block_volume') + def test_volume_order_endurance_hourly(self, order_mock): + + order_mock.return_value = { + 'placedOrder': { + 'id': 10983647, + 'items': [ + {'description': 'Storage as a Service'}, + {'description': 'Block Storage'}, + {'description': '20 GBs'}, + {'description': '200 IOPS'}] + } + } + + result = self.run_command(['block', 'volume-order', + '--storage-type=endurance', '--size=20', + '--tier=0.25', '--os-type=linux', + '--location=dal10', + '--service-offering storage_as_a_service', + '--billing hourly', '--iops 200']) + self.assert_no_fail(result) + self.assertEqual(result.output, + 'Order #10983647 placed successfully!\n' + ' > Storage as a Service' + ' > Block Storage\n' + ' > 20 GBs \n' + ' > 200 IOPS \n') + + @mock.patch('SoftLayer.BlockStorageManager.order_block_volume') def test_volume_order_performance_manager_error(self, order_mock): order_mock.side_effect = ValueError('failure!') diff --git a/tests/CLI/modules/file_tests.py b/tests/CLI/modules/file_tests.py index df38ae531..e30fb9118 100644 --- a/tests/CLI/modules/file_tests.py +++ b/tests/CLI/modules/file_tests.py @@ -157,6 +157,50 @@ def test_volume_order_performance_snapshot_error(self): self.assertEqual(2, result.exit_code) + @mock.patch('SoftLayer.FileStorageManager.order_file_volume') + def test_volume_order_performance_hourly_billing_not_available( + self, order_mock): + order_mock.return_value = {} + result = self.run_command(['file', 'volume-order', + '--storage-type=performance', '--size=20', + '--os-type=linux', '--location=dal10', + '--service-offering=enterprise', + '--billing=hourly', '--iops=200']) + + self.assertEqual(2, result.exit_code) + self.assertEqual(result.output, + '--billing : hourly billing is only available ' + 'for storage_as_a_service ') + + + @mock.patch('SoftLayer.FileStorageManager.order_file_volume') + def test_volume_order_performance_hourly_billing(self, order_mock): + order_mock.return_value = { + 'placedOrder': { + 'id': 479, + 'items': [ + {'description': 'Performance Storage'}, + {'description': 'File Storage'}, + {'description': '0.25 IOPS per GB'}, + {'description': '20 GB Storage Space'}, + {'description': '10 GB Storage Space (Snapshot Space)'}] + } + } + + result = self.run_command(['file', 'volume-order', + '--storage-type=performance', '--size=20', + '--iops=100', '--location=dal05', + '--service-offering=storage_as_a_service', + '--snapshot-size=10']) + + self.assert_no_fail(result) + self.assertEqual(result.output, + 'Order #478 placed successfully!\n' + ' > Performance Storage\n > File Storage\n' + ' > 0.25 IOPS per GB\n > 20 GB Storage Space\n' + ' > 10 GB Storage Space (Snapshot Space)\n') + + @mock.patch('SoftLayer.FileStorageManager.order_file_volume') def test_volume_order_performance(self, order_mock): order_mock.return_value = { @@ -190,6 +234,48 @@ def test_volume_order_endurance_tier_not_given(self): self.assertEqual(2, result.exit_code) + @mock.patch('SoftLayer.FileStorageManager.order_file_volume') + def test_volume_order_endurance_hourly_billing_not_available( + self, order_mock): + order_mock.return_value = {} + result = self.run_command(['file', 'volume-order', + '--storage-type=endurance', '--size=20', + '--os-type=linux', '--location=dal10', + '--service-offering enterprise', + '--billing hourly', '--iops 200']) + + self.assertEqual(2, result.exit_code) + self.assertEqual(result.output, + '--billing : hourly billing is only available ' + 'for storage_as_a_service ') + + @mock.patch('SoftLayer.FileStorageManager.order_file_volume') + def test_volume_order_endurance_hourly_billing(self, order_mock): + order_mock.return_value = { + 'placedOrder': { + 'id': 479, + 'items': [ + {'description': 'Endurance Storage'}, + {'description': 'File Storage'}, + {'description': '0.25 IOPS per GB'}, + {'description': '20 GB Storage Space'}, + {'description': '10 GB Storage Space (Snapshot Space)'}] + } + } + + result = self.run_command(['file', 'volume-order', + '--storage-type=endurance', '--size=20', + '--iops=100', '--location=dal05', + '--service-offering storage_as_a_service', + '--snapshot-size=10']) + + self.assert_no_fail(result) + self.assertEqual(result.output, + 'Order #478 placed successfully!\n' + ' > Performance Storage\n > File Storage\n' + ' > 0.25 IOPS per GB\n > 20 GB Storage Space\n' + ' > 10 GB Storage Space (Snapshot Space)\n') + @mock.patch('SoftLayer.FileStorageManager.order_file_volume') def test_volume_order_endurance(self, order_mock): order_mock.return_value = { From b5f3e9d47e44db2077a6c7593c8ec1fec5178a0c Mon Sep 17 00:00:00 2001 From: David Pickle Date: Fri, 11 Aug 2017 19:32:02 -0500 Subject: [PATCH 2/7] Fix unit tests and add additional tests to improve coverage --- .../fixtures/SoftLayer_Network_Storage.py | 1 + tests/CLI/modules/block_tests.py | 75 ++------- tests/CLI/modules/file_tests.py | 122 +++++---------- tests/managers/block_tests.py | 46 +++++- tests/managers/file_tests.py | 54 ++++++- tests/managers/storage_utils_tests.py | 145 ++++++++++++++---- 6 files changed, 254 insertions(+), 189 deletions(-) diff --git a/SoftLayer/fixtures/SoftLayer_Network_Storage.py b/SoftLayer/fixtures/SoftLayer_Network_Storage.py index f8dfae898..b4dd0b751 100644 --- a/SoftLayer/fixtures/SoftLayer_Network_Storage.py +++ b/SoftLayer/fixtures/SoftLayer_Network_Storage.py @@ -10,6 +10,7 @@ }], 'cancellationDate': '', 'categoryCode': 'storage_as_a_service', + 'hourlyFlag': None, 'id': 454, 'location': {'id': 449500} }, diff --git a/tests/CLI/modules/block_tests.py b/tests/CLI/modules/block_tests.py index 99db71241..e39f79404 100644 --- a/tests/CLI/modules/block_tests.py +++ b/tests/CLI/modules/block_tests.py @@ -181,50 +181,6 @@ def test_volume_order_performance(self, order_mock): ' > 0.25 IOPS per GB\n > 20 GB Storage Space\n' ' > 10 GB Storage Space (Snapshot Space)\n') - @mock.patch('SoftLayer.BlockStorageManager.order_block_volume') - def test_volume_order_performance_hourly_billing_not_available( - self, order_mock): - order_mock.return_value = {} - result = self.run_command(['block', 'volume-order', - '--storage-type=performance', '--size=20', - '--os-type=linux', '--location=dal10', - '--service-offering=enterprise', - '--billing=hourly', '--iops=200']) - - self.assertEqual(2, result.exit_code) - self.assertEqual(result.output, - '--billing : hourly billing is only available ' - 'for storage_as_a_service ') - - @mock.patch('SoftLayer.BlockStorageManager.order_block_volume') - def test_volume_order_performance_hourly(self, order_mock): - - order_mock.return_value = { - 'placedOrder': { - 'id': 10983646, - 'items': [ - {'description': 'Storage as a Service'}, - {'description': 'Block Storage'}, - {'description': '20 GBs'}, - {'description': '200 IOPS'}, - {'description': '0.25 IOPS per GB'}] - } - } - - result = self.run_command(['block', 'volume-order', - '--storage-type=performance', '--size=20', - '--os-type=linux', - '--location=dal10', - '--service-offering=storage_as_a_service', - '--billing=hourly', '--iops=200']) - self.assert_no_fail(result) - self.assertEqual(result.output, - 'Order #10983646 placed successfully!\n' - ' > Storage as a Service' - ' > Block Storage\n' - ' > 20 GBs \n' - ' > 200 IOPS \n') - def test_volume_order_endurance_tier_not_given(self): result = self.run_command(['block', 'volume-order', '--storage-type=endurance', '--size=20', @@ -272,33 +228,24 @@ def test_volume_order_order_not_placed(self, order_mock): 'Order could not be placed! Please verify ' 'your options and try again.\n') - - @mock.patch('SoftLayer.BlockStorageManager.order_block_volume') - def test_volume_order_endurance_hourly_billing_not_available( - self, order_mock): - order_mock.return_value = {} + def test_volume_order_hourly_billing_not_available(self): result = self.run_command(['block', 'volume-order', '--storage-type=endurance', '--size=20', '--tier=0.25', '--os-type=linux', - '--location=dal10', - '--service-offering enterprise', - '--billing hourly', '--iops 200']) + '--location=dal10', '--billing=hourly', + '--service-offering=enterprise']) self.assertEqual(2, result.exit_code) - self.assertEqual(result.output, - '--billing : hourly billing is only available ' - 'for storage_as_a_service ') @mock.patch('SoftLayer.BlockStorageManager.order_block_volume') - def test_volume_order_endurance_hourly(self, order_mock): - + def test_volume_order_hourly_billing(self, order_mock): order_mock.return_value = { 'placedOrder': { 'id': 10983647, 'items': [ {'description': 'Storage as a Service'}, {'description': 'Block Storage'}, - {'description': '20 GBs'}, + {'description': '20 GB Storage Space'}, {'description': '200 IOPS'}] } } @@ -306,17 +253,15 @@ def test_volume_order_endurance_hourly(self, order_mock): result = self.run_command(['block', 'volume-order', '--storage-type=endurance', '--size=20', '--tier=0.25', '--os-type=linux', - '--location=dal10', - '--service-offering storage_as_a_service', - '--billing hourly', '--iops 200']) + '--location=dal10', '--billing=hourly', + '--service-offering=storage_as_a_service']) self.assert_no_fail(result) self.assertEqual(result.output, 'Order #10983647 placed successfully!\n' - ' > Storage as a Service' + ' > Storage as a Service\n' ' > Block Storage\n' - ' > 20 GBs \n' - ' > 200 IOPS \n') - + ' > 20 GB Storage Space\n' + ' > 200 IOPS\n') @mock.patch('SoftLayer.BlockStorageManager.order_block_volume') def test_volume_order_performance_manager_error(self, order_mock): diff --git a/tests/CLI/modules/file_tests.py b/tests/CLI/modules/file_tests.py index e30fb9118..34dce01a7 100644 --- a/tests/CLI/modules/file_tests.py +++ b/tests/CLI/modules/file_tests.py @@ -158,26 +158,10 @@ def test_volume_order_performance_snapshot_error(self): self.assertEqual(2, result.exit_code) @mock.patch('SoftLayer.FileStorageManager.order_file_volume') - def test_volume_order_performance_hourly_billing_not_available( - self, order_mock): - order_mock.return_value = {} - result = self.run_command(['file', 'volume-order', - '--storage-type=performance', '--size=20', - '--os-type=linux', '--location=dal10', - '--service-offering=enterprise', - '--billing=hourly', '--iops=200']) - - self.assertEqual(2, result.exit_code) - self.assertEqual(result.output, - '--billing : hourly billing is only available ' - 'for storage_as_a_service ') - - - @mock.patch('SoftLayer.FileStorageManager.order_file_volume') - def test_volume_order_performance_hourly_billing(self, order_mock): + def test_volume_order_performance(self, order_mock): order_mock.return_value = { 'placedOrder': { - 'id': 479, + 'id': 478, 'items': [ {'description': 'Performance Storage'}, {'description': 'File Storage'}, @@ -190,7 +174,6 @@ def test_volume_order_performance_hourly_billing(self, order_mock): result = self.run_command(['file', 'volume-order', '--storage-type=performance', '--size=20', '--iops=100', '--location=dal05', - '--service-offering=storage_as_a_service', '--snapshot-size=10']) self.assert_no_fail(result) @@ -200,121 +183,90 @@ def test_volume_order_performance_hourly_billing(self, order_mock): ' > 0.25 IOPS per GB\n > 20 GB Storage Space\n' ' > 10 GB Storage Space (Snapshot Space)\n') + def test_volume_order_endurance_tier_not_given(self): + result = self.run_command(['file', 'volume-order', + '--storage-type=endurance', '--size=20', + '--location=dal05']) + + self.assertEqual(2, result.exit_code) @mock.patch('SoftLayer.FileStorageManager.order_file_volume') - def test_volume_order_performance(self, order_mock): + def test_volume_order_endurance(self, order_mock): order_mock.return_value = { 'placedOrder': { 'id': 478, 'items': [ - {'description': 'Performance Storage'}, + {'description': 'Endurance Storage'}, {'description': 'File Storage'}, {'description': '0.25 IOPS per GB'}, {'description': '20 GB Storage Space'}, {'description': '10 GB Storage Space (Snapshot Space)'}] - } + } } result = self.run_command(['file', 'volume-order', - '--storage-type=performance', '--size=20', - '--iops=100', '--location=dal05', + '--storage-type=endurance', '--size=20', + '--tier=0.25', '--location=dal05', '--snapshot-size=10']) self.assert_no_fail(result) self.assertEqual(result.output, 'Order #478 placed successfully!\n' - ' > Performance Storage\n > File Storage\n' + ' > Endurance Storage\n > File Storage\n' ' > 0.25 IOPS per GB\n > 20 GB Storage Space\n' ' > 10 GB Storage Space (Snapshot Space)\n') - def test_volume_order_endurance_tier_not_given(self): - result = self.run_command(['file', 'volume-order', - '--storage-type=endurance', '--size=20', - '--location=dal05']) - - self.assertEqual(2, result.exit_code) - @mock.patch('SoftLayer.FileStorageManager.order_file_volume') - def test_volume_order_endurance_hourly_billing_not_available( - self, order_mock): + def test_volume_order_order_not_placed(self, order_mock): order_mock.return_value = {} + result = self.run_command(['file', 'volume-order', '--storage-type=endurance', '--size=20', - '--os-type=linux', '--location=dal10', - '--service-offering enterprise', - '--billing hourly', '--iops 200']) + '--tier=0.25', '--location=dal05']) - self.assertEqual(2, result.exit_code) + self.assert_no_fail(result) self.assertEqual(result.output, - '--billing : hourly billing is only available ' - 'for storage_as_a_service ') - - @mock.patch('SoftLayer.FileStorageManager.order_file_volume') - def test_volume_order_endurance_hourly_billing(self, order_mock): - order_mock.return_value = { - 'placedOrder': { - 'id': 479, - 'items': [ - {'description': 'Endurance Storage'}, - {'description': 'File Storage'}, - {'description': '0.25 IOPS per GB'}, - {'description': '20 GB Storage Space'}, - {'description': '10 GB Storage Space (Snapshot Space)'}] - } - } + 'Order could not be placed! Please verify ' + 'your options and try again.\n') + def test_volume_order_hourly_billing_not_available(self): result = self.run_command(['file', 'volume-order', '--storage-type=endurance', '--size=20', - '--iops=100', '--location=dal05', - '--service-offering storage_as_a_service', - '--snapshot-size=10']) + '--tier=0.25', '--location=dal10', + '--billing=hourly', + '--service-offering=enterprise']) - self.assert_no_fail(result) - self.assertEqual(result.output, - 'Order #478 placed successfully!\n' - ' > Performance Storage\n > File Storage\n' - ' > 0.25 IOPS per GB\n > 20 GB Storage Space\n' - ' > 10 GB Storage Space (Snapshot Space)\n') + self.assertEqual(2, result.exit_code) @mock.patch('SoftLayer.FileStorageManager.order_file_volume') - def test_volume_order_endurance(self, order_mock): + def test_volume_order_hourly_billing(self, order_mock): order_mock.return_value = { 'placedOrder': { - 'id': 478, + 'id': 479, 'items': [ - {'description': 'Endurance Storage'}, + {'description': 'Storage as a Service'}, {'description': 'File Storage'}, - {'description': '0.25 IOPS per GB'}, {'description': '20 GB Storage Space'}, + {'description': '0.25 IOPS per GB'}, {'description': '10 GB Storage Space (Snapshot Space)'}] - } + } } result = self.run_command(['file', 'volume-order', '--storage-type=endurance', '--size=20', '--tier=0.25', '--location=dal05', - '--snapshot-size=10']) + '--service-offering=storage_as_a_service', + '--billing=hourly', '--snapshot-size=10']) self.assert_no_fail(result) self.assertEqual(result.output, - 'Order #478 placed successfully!\n' - ' > Endurance Storage\n > File Storage\n' - ' > 0.25 IOPS per GB\n > 20 GB Storage Space\n' + 'Order #479 placed successfully!\n' + ' > Storage as a Service\n' + ' > File Storage\n' + ' > 20 GB Storage Space\n' + ' > 0.25 IOPS per GB\n' ' > 10 GB Storage Space (Snapshot Space)\n') - @mock.patch('SoftLayer.FileStorageManager.order_file_volume') - def test_volume_order_order_not_placed(self, order_mock): - order_mock.return_value = {} - - result = self.run_command(['file', 'volume-order', - '--storage-type=endurance', '--size=20', - '--tier=0.25', '--location=dal05']) - - self.assert_no_fail(result) - self.assertEqual(result.output, - 'Order could not be placed! Please verify ' - 'your options and try again.\n') - @mock.patch('SoftLayer.FileStorageManager.order_file_volume') def test_volume_order_performance_manager_error(self, order_mock): order_mock.side_effect = ValueError('failure!') diff --git a/tests/managers/block_tests.py b/tests/managers/block_tests.py index 1c9da6d35..601bb92c6 100644 --- a/tests/managers/block_tests.py +++ b/tests/managers/block_tests.py @@ -25,6 +25,21 @@ def test_cancel_block_volume_immediately(self): identifier=449, ) + def test_cancel_block_volume_immediately_hourly_billing(self): + mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') + mock.return_value = { + '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) @@ -181,6 +196,27 @@ def test_cancel_snapshot_immediately(self): identifier=123, ) + def test_cancel_snapshot_immediately_hourly_billing(self): + mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') + mock.return_value = { + 'billingItem': { + 'activeChildren': [ + {'categoryCode': 'storage_snapshot_space', 'id': 417} + ], + 'hourlyFlag': True, + 'id': 449 + }, + } + + self.block.cancel_snapshot_space(1234, immediate=True) + + self.assert_called_with( + 'SoftLayer_Billing_Item', + 'cancelItem', + args=(True, True, 'No longer needed'), + identifier=417, + ) + def test_cancel_snapshot_exception_no_billing_item_active_children(self): mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') mock.return_value = { @@ -313,6 +349,7 @@ def test_order_block_volume_performance(self): 'quantity': 1, 'location': 449494, 'iops': 2000, + 'useHourlyPricing': False, 'osFormatType': {'keyName': 'LINUX'} },) ) @@ -357,6 +394,7 @@ def test_order_block_volume_endurance(self): 'volumeSize': 1000, 'quantity': 1, 'location': 449494, + 'useHourlyPricing': False, 'osFormatType': {'keyName': 'LINUX'} },) ) @@ -461,7 +499,8 @@ def test_order_block_snapshot_space_upgrade(self): ], 'quantity': 1, 'location': 449500, - 'volumeId': 102 + 'volumeId': 102, + 'useHourlyPricing': False },) ) @@ -491,7 +530,8 @@ def test_order_block_snapshot_space(self): ], 'quantity': 1, 'location': 449500, - 'volumeId': 102 + 'volumeId': 102, + 'useHourlyPricing': False },) ) @@ -559,6 +599,7 @@ def test_order_block_replicant_performance_os_type_given(self): 'iops': 1000, 'originVolumeId': 102, 'originVolumeScheduleId': 978, + 'useHourlyPricing': False, 'osFormatType': {'keyName': 'XEN'} },) ) @@ -600,6 +641,7 @@ def test_order_block_replicant_endurance(self): 'location': 449494, 'originVolumeId': 102, 'originVolumeScheduleId': 978, + 'useHourlyPricing': False, 'osFormatType': {'keyName': 'LINUX'} },) ) diff --git a/tests/managers/file_tests.py b/tests/managers/file_tests.py index 67daca4b0..c3dff4339 100644 --- a/tests/managers/file_tests.py +++ b/tests/managers/file_tests.py @@ -25,6 +25,21 @@ def test_cancel_file_volume_immediately(self): identifier=449, ) + def test_cancel_file_volume_immediately_hourly_billing(self): + mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') + mock.return_value = { + 'billingItem': {'hourlyFlag': True, 'id': 449}, + } + + self.file.cancel_file_volume(123, immediate=False) + + self.assert_called_with( + 'SoftLayer_Billing_Item', + 'cancelItem', + args=(True, True, 'No longer needed'), + identifier=449, + ) + def test_authorize_host_to_volume(self): result = self.file.authorize_host_to_volume( 50, @@ -166,6 +181,27 @@ def test_cancel_snapshot_immediately(self): identifier=123, ) + def test_cancel_snapshot_immediately_hourly_billing(self): + mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') + mock.return_value = { + 'billingItem': { + 'activeChildren': [ + {'categoryCode': 'storage_snapshot_space', 'id': 417} + ], + 'hourlyFlag': True, + 'id': 449 + }, + } + + self.file.cancel_snapshot_space(1234, immediate=True) + + self.assert_called_with( + 'SoftLayer_Billing_Item', + 'cancelItem', + args=(True, True, 'No longer needed'), + identifier=417, + ) + def test_cancel_snapshot_exception_no_billing_item_active_children(self): mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') mock.return_value = { @@ -385,7 +421,8 @@ def test_order_file_volume_performance(self): 'volumeSize': 1000, 'quantity': 1, 'location': 449494, - 'iops': 2000 + 'iops': 2000, + 'useHourlyPricing': False },) ) @@ -429,7 +466,8 @@ def test_order_file_volume_endurance(self): ], 'volumeSize': 1000, 'quantity': 1, - 'location': 449494 + 'location': 449494, + 'useHourlyPricing': False },) ) @@ -461,7 +499,8 @@ def test_order_file_snapshot_space_upgrade(self): ], 'quantity': 1, 'location': 449500, - 'volumeId': 102 + 'volumeId': 102, + 'useHourlyPricing': False },) ) @@ -493,7 +532,8 @@ def test_order_file_snapshot_space(self): ], 'quantity': 1, 'location': 449500, - 'volumeId': 102 + 'volumeId': 102, + 'useHourlyPricing': False },) ) @@ -536,7 +576,8 @@ def test_order_file_replicant_performance(self): 'location': 449494, 'iops': 1000, 'originVolumeId': 102, - 'originVolumeScheduleId': 978 + 'originVolumeScheduleId': 978, + 'useHourlyPricing': False },) ) @@ -578,7 +619,8 @@ def test_order_file_replicant_endurance(self): 'quantity': 1, 'location': 449494, 'originVolumeId': 102, - 'originVolumeScheduleId': 978 + 'originVolumeScheduleId': 978, + 'useHourlyPricing': False },) ) diff --git a/tests/managers/storage_utils_tests.py b/tests/managers/storage_utils_tests.py index f07e21f2d..5f5433311 100644 --- a/tests/managers/storage_utils_tests.py +++ b/tests/managers/storage_utils_tests.py @@ -2721,7 +2721,8 @@ def test_prep_snapshot_order_saas_endurance_tier_is_not_none(self): 'prices': [{'id': 193613}], 'quantity': 1, 'location': 449500, - 'volumeId': 102 + 'volumeId': 102, + 'useHourlyPricing': False } result = storage_utils.prepare_snapshot_order_object( @@ -2743,7 +2744,8 @@ def test_prep_snapshot_order_saas_endurance_upgrade(self): 'prices': [{'id': 193853}], 'quantity': 1, 'location': 449500, - 'volumeId': 102 + 'volumeId': 102, + 'useHourlyPricing': False } result = storage_utils.prepare_snapshot_order_object( @@ -2792,7 +2794,8 @@ def test_prep_snapshot_order_saas_performance(self): 'prices': [{'id': 191193}], 'quantity': 1, 'location': 449500, - 'volumeId': 102 + 'volumeId': 102, + 'useHourlyPricing': False } result = storage_utils.prepare_snapshot_order_object( @@ -2841,7 +2844,8 @@ def test_prep_snapshot_order_enterprise_tier_is_not_none(self): 'prices': [{'id': 46160}], 'quantity': 1, 'location': 449500, - 'volumeId': 100 + 'volumeId': 100, + 'useHourlyPricing': False } result = storage_utils.prepare_snapshot_order_object( @@ -2865,7 +2869,8 @@ def test_prep_snapshot_order_enterprise(self): 'prices': [{'id': 45860}], 'quantity': 1, 'location': 449500, - 'volumeId': 100 + 'volumeId': 100, + 'useHourlyPricing': False } result = storage_utils.prepare_snapshot_order_object( @@ -2874,6 +2879,33 @@ def test_prep_snapshot_order_enterprise(self): self.assertEqual(expected_object, result) + def test_prep_snapshot_order_hourly_billing(self): + mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') + mock.return_value = [fixtures.SoftLayer_Product_Package.SAAS_PACKAGE] + + mock_volume = fixtures.SoftLayer_Network_Storage.STAAS_TEST_VOLUME + prev_hourly_flag = mock_volume['billingItem']['hourlyFlag'] + mock_volume['billingItem']['hourlyFlag'] = True + + expected_object = { + 'complexType': 'SoftLayer_Container_Product_Order_' + 'Network_Storage_Enterprise_SnapshotSpace', + 'packageId': 759, + 'prices': [{'id': 193853}], + 'quantity': 1, + 'location': 449500, + 'volumeId': 102, + 'useHourlyPricing': True + } + + result = storage_utils.prepare_snapshot_order_object( + self.block, mock_volume, 20, None, False + ) + + self.assertEqual(expected_object, result) + + mock_volume['billingItem']['hourlyFlag'] = prev_hourly_flag + # --------------------------------------------------------------------- # Tests for prepare_volume_order_object() # --------------------------------------------------------------------- @@ -2882,7 +2914,7 @@ def test_prep_volume_order_invalid_storage_type(self): exceptions.SoftLayerError, storage_utils.prepare_volume_order_object, self.block, 'saxophone_cat', 'dal09', 1000, - None, 4, None, 'enterprise', 'block' + None, 4, None, 'enterprise', 'block', False ) self.assertEqual( @@ -2898,7 +2930,7 @@ def test_prep_volume_order_invalid_location(self): exceptions.SoftLayerError, storage_utils.prepare_volume_order_object, self.block, 'endurance', 'hoth01', 1000, - None, 4, None, 'enterprise', 'block' + None, 4, None, 'enterprise', 'block', False ) self.assertEqual( @@ -2915,7 +2947,7 @@ def test_prep_volume_order_enterprise_offering_invalid_storage_type(self): exceptions.SoftLayerError, storage_utils.prepare_volume_order_object, self.block, 'performance', 'dal09', 1000, - None, 4, None, 'enterprise', 'block' + None, 4, None, 'enterprise', 'block', False ) self.assertEqual( @@ -2932,7 +2964,7 @@ def test_prep_volume_order_performance_offering_invalid_storage_type(self): exceptions.SoftLayerError, storage_utils.prepare_volume_order_object, self.block, 'endurance', 'dal09', 1000, - 800, None, None, 'performance', 'block' + 800, None, None, 'performance', 'block', False ) self.assertEqual( @@ -2949,7 +2981,7 @@ def test_prep_volume_order_invalid_offering(self): exceptions.SoftLayerError, storage_utils.prepare_volume_order_object, self.block, 'endurance', 'dal09', 1000, - None, 4, None, 'jazz_penguins', 'block' + None, 4, None, 'jazz_penguins', 'block', False ) self.assertEqual( @@ -2977,12 +3009,13 @@ def test_prep_volume_order_saas_performance(self): 'quantity': 1, 'location': 29, 'volumeSize': 1000, - 'iops': 800 + 'iops': 800, + 'useHourlyPricing': False } result = storage_utils.prepare_volume_order_object( self.file, 'performance', 'dal09', 1000, - 800, None, None, 'storage_as_a_service', 'file' + 800, None, None, 'storage_as_a_service', 'file', False ) self.assertEqual(expected_object, result) @@ -3007,12 +3040,13 @@ def test_prep_volume_order_saas_performance_with_snapshot(self): 'quantity': 1, 'location': 29, 'volumeSize': 1000, - 'iops': 800 + 'iops': 800, + 'useHourlyPricing': False } result = storage_utils.prepare_volume_order_object( self.file, 'performance', 'dal09', 1000, - 800, None, 10, 'storage_as_a_service', 'file' + 800, None, 10, 'storage_as_a_service', 'file', False ) self.assertEqual(expected_object, result) @@ -3035,12 +3069,13 @@ def test_prep_volume_order_saas_endurance(self): ], 'quantity': 1, 'location': 29, - 'volumeSize': 1000 + 'volumeSize': 1000, + 'useHourlyPricing': False } result = storage_utils.prepare_volume_order_object( self.block, 'endurance', 'dal09', 1000, - None, 4, None, 'storage_as_a_service', 'block' + None, 4, None, 'storage_as_a_service', 'block', False ) self.assertEqual(expected_object, result) @@ -3064,12 +3099,13 @@ def test_prep_volume_order_saas_endurance_with_snapshot(self): ], 'quantity': 1, 'location': 29, - 'volumeSize': 1000 + 'volumeSize': 1000, + 'useHourlyPricing': False } result = storage_utils.prepare_volume_order_object( self.block, 'endurance', 'dal09', 1000, - None, 4, 10, 'storage_as_a_service', 'block' + None, 4, 10, 'storage_as_a_service', 'block', False ) self.assertEqual(expected_object, result) @@ -3092,12 +3128,13 @@ def test_prep_volume_order_perf_performance_block(self): {'id': 41562} ], 'quantity': 1, - 'location': 29 + 'location': 29, + 'useHourlyPricing': False } result = storage_utils.prepare_volume_order_object( self.block, 'performance', 'dal09', 1000, - 800, None, None, 'performance', 'block' + 800, None, None, 'performance', 'block', False ) self.assertEqual(expected_object, result) @@ -3120,12 +3157,13 @@ def test_prep_volume_order_perf_performance_file(self): {'id': 41562} ], 'quantity': 1, - 'location': 29 + 'location': 29, + 'useHourlyPricing': False } result = storage_utils.prepare_volume_order_object( self.file, 'performance', 'dal09', 1000, - 800, None, None, 'performance', 'file' + 800, None, None, 'performance', 'file', False ) self.assertEqual(expected_object, result) @@ -3149,12 +3187,13 @@ def test_prep_volume_order_ent_endurance(self): {'id': 45088} ], 'quantity': 1, - 'location': 29 + 'location': 29, + 'useHourlyPricing': False } result = storage_utils.prepare_volume_order_object( self.file, 'endurance', 'dal09', 1000, - None, 4, None, 'enterprise', 'file' + None, 4, None, 'enterprise', 'file', False ) self.assertEqual(expected_object, result) @@ -3179,12 +3218,13 @@ def test_prep_volume_order_ent_endurance_with_snapshot(self): {'id': 46170} ], 'quantity': 1, - 'location': 29 + 'location': 29, + 'useHourlyPricing': False } result = storage_utils.prepare_volume_order_object( self.block, 'endurance', 'dal09', 1000, - None, 4, 10, 'enterprise', 'block' + None, 4, 10, 'enterprise', 'block', False ) self.assertEqual(expected_object, result) @@ -3335,7 +3375,8 @@ def test_prep_replicant_order_saas_endurance(self): 'location': 51, 'originVolumeId': 102, 'originVolumeScheduleId': 978, - 'volumeSize': 500 + 'volumeSize': 500, + 'useHourlyPricing': False } result = storage_utils.prepare_replicant_order_object( @@ -3368,7 +3409,8 @@ def test_prep_replicant_order_saas_endurance_tier_is_not_none(self): 'location': 51, 'originVolumeId': 102, 'originVolumeScheduleId': 978, - 'volumeSize': 500 + 'volumeSize': 500, + 'useHourlyPricing': False } result = storage_utils.prepare_replicant_order_object( @@ -3431,7 +3473,8 @@ def test_prep_replicant_order_saas_performance(self): 'originVolumeId': 102, 'originVolumeScheduleId': 978, 'volumeSize': 500, - 'iops': 1000 + 'iops': 1000, + 'useHourlyPricing': False } result = storage_utils.prepare_replicant_order_object( @@ -3492,7 +3535,8 @@ def test_prep_replicant_order_ent_endurance(self): 'quantity': 1, 'location': 51, 'originVolumeId': 100, - 'originVolumeScheduleId': 978 + 'originVolumeScheduleId': 978, + 'useHourlyPricing': False } result = storage_utils.prepare_replicant_order_object( @@ -3526,7 +3570,8 @@ def test_prep_replicant_order_ent_endurance_tier_is_not_none(self): 'quantity': 1, 'location': 51, 'originVolumeId': 100, - 'originVolumeScheduleId': 978 + 'originVolumeScheduleId': 978, + 'useHourlyPricing': False } result = storage_utils.prepare_replicant_order_object( @@ -3535,6 +3580,44 @@ def test_prep_replicant_order_ent_endurance_tier_is_not_none(self): self.assertEqual(expected_object, result) + def test_prep_replicant_order_hourly_billing(self): + mock = self.set_mock('SoftLayer_Location_Datacenter', 'getDatacenters') + mock.return_value = [{'id': 51, 'name': 'wdc04'}] + mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') + mock.return_value = [fixtures.SoftLayer_Product_Package.SAAS_PACKAGE] + + mock_volume = fixtures.SoftLayer_Network_Storage.STAAS_TEST_VOLUME + prev_hourly_flag = mock_volume['billingItem']['hourlyFlag'] + mock_volume['billingItem']['hourlyFlag'] = True + + expected_object = { + 'complexType': 'SoftLayer_Container_Product_Order_' + 'Network_Storage_AsAService', + 'packageId': 759, + 'prices': [ + {'id': 189433}, + {'id': 189443}, + {'id': 193433}, + {'id': 193373}, + {'id': 193613}, + {'id': 194693} + ], + 'quantity': 1, + 'location': 51, + 'originVolumeId': 102, + 'originVolumeScheduleId': 978, + 'volumeSize': 500, + 'useHourlyPricing': True + } + + result = storage_utils.prepare_replicant_order_object( + self.block, 'WEEKLY', 'wdc04', None, mock_volume, 'block' + ) + + self.assertEqual(expected_object, result) + + mock_volume['billingItem']['hourlyFlag'] = prev_hourly_flag + # --------------------------------------------------------------------- # Tests for prepare_duplicate_order_object() # --------------------------------------------------------------------- From 11def41b1a9809ac5f3dedcac25a3cee3ee75546 Mon Sep 17 00:00:00 2001 From: Sunil Rajput Date: Fri, 25 Aug 2017 11:06:49 -0500 Subject: [PATCH 3/7] STORAGE-3308: File and Block Hourly billing option added for volume duplicate. --- SoftLayer/CLI/block/duplicate.py | 13 +++++++++++-- SoftLayer/CLI/block/order.py | 1 - SoftLayer/CLI/file/duplicate.py | 13 +++++++++++-- SoftLayer/CLI/file/order.py | 1 - SoftLayer/managers/block.py | 8 +++++--- SoftLayer/managers/file.py | 8 +++++--- SoftLayer/managers/storage_utils.py | 4 +++- 7 files changed, 35 insertions(+), 13 deletions(-) diff --git a/SoftLayer/CLI/block/duplicate.py b/SoftLayer/CLI/block/duplicate.py index 98ef1b793..a6aa14cc8 100644 --- a/SoftLayer/CLI/block/duplicate.py +++ b/SoftLayer/CLI/block/duplicate.py @@ -52,12 +52,20 @@ 'space size of the origin volume will be used.***\n' 'Input "0" for this parameter to order a duplicate volume ' 'with no snapshot space.') +@click.option('--billing', + type=click.Choice(['hourly', 'monthly']), + default='monthly', + help="Optional parameter for Billing rate. Default to monthly") @environment.pass_env def cli(env, origin_volume_id, origin_snapshot_id, duplicate_size, - duplicate_iops, duplicate_tier, duplicate_snapshot_size): + duplicate_iops, duplicate_tier, duplicate_snapshot_size, billing): """Order a duplicate block storage volume.""" block_manager = SoftLayer.BlockStorageManager(env.client) + hourly_billing_flag = False + if billing.lower() == "hourly": + hourly_billing_flag = True + if duplicate_tier is not None: duplicate_tier = float(duplicate_tier) @@ -68,7 +76,8 @@ def cli(env, origin_volume_id, origin_snapshot_id, duplicate_size, duplicate_size=duplicate_size, duplicate_iops=duplicate_iops, duplicate_tier_level=duplicate_tier, - duplicate_snapshot_size=duplicate_snapshot_size + duplicate_snapshot_size=duplicate_snapshot_size, + hourly_billing_flag=hourly_billing_flag ) except ValueError as ex: raise exceptions.ArgumentError(str(ex)) diff --git a/SoftLayer/CLI/block/order.py b/SoftLayer/CLI/block/order.py index 34271e3ff..089428e62 100644 --- a/SoftLayer/CLI/block/order.py +++ b/SoftLayer/CLI/block/order.py @@ -59,7 +59,6 @@ @click.option('--billing', type=click.Choice(['hourly', 'monthly']), default='monthly', - show_default=True, help="Optional parameter for Billing rate. Default to monthly") @environment.pass_env def cli(env, storage_type, size, iops, tier, os_type, diff --git a/SoftLayer/CLI/file/duplicate.py b/SoftLayer/CLI/file/duplicate.py index e02169771..d23a05ed7 100644 --- a/SoftLayer/CLI/file/duplicate.py +++ b/SoftLayer/CLI/file/duplicate.py @@ -48,12 +48,20 @@ 'space size of the origin volume will be used.***\n' 'Input "0" for this parameter to order a duplicate volume ' 'with no snapshot space.') +@click.option('--billing', + type=click.Choice(['hourly', 'monthly']), + default='monthly', + help="Optional parameter for Billing rate. Default to monthly") @environment.pass_env def cli(env, origin_volume_id, origin_snapshot_id, duplicate_size, - duplicate_iops, duplicate_tier, duplicate_snapshot_size): + duplicate_iops, duplicate_tier, duplicate_snapshot_size, billing): """Order a duplicate file storage volume.""" file_manager = SoftLayer.FileStorageManager(env.client) + hourly_billing_flag = False + if billing.lower() == "hourly": + hourly_billing_flag = True + if duplicate_tier is not None: duplicate_tier = float(duplicate_tier) @@ -64,7 +72,8 @@ def cli(env, origin_volume_id, origin_snapshot_id, duplicate_size, duplicate_size=duplicate_size, duplicate_iops=duplicate_iops, duplicate_tier_level=duplicate_tier, - duplicate_snapshot_size=duplicate_snapshot_size + duplicate_snapshot_size=duplicate_snapshot_size, + hourly_billing_flag=hourly_billing_flag ) except ValueError as ex: raise exceptions.ArgumentError(str(ex)) diff --git a/SoftLayer/CLI/file/order.py b/SoftLayer/CLI/file/order.py index bd2731f17..f1502f51e 100644 --- a/SoftLayer/CLI/file/order.py +++ b/SoftLayer/CLI/file/order.py @@ -47,7 +47,6 @@ @click.option('--billing', type=click.Choice(['hourly', 'monthly']), default='monthly', - show_default=True, help="Optional parameter for Billing rate. Default to monthly") @environment.pass_env def cli(env, storage_type, size, iops, tier, diff --git a/SoftLayer/managers/block.py b/SoftLayer/managers/block.py index 3ffcbd5c8..49c5f1940 100644 --- a/SoftLayer/managers/block.py +++ b/SoftLayer/managers/block.py @@ -262,7 +262,8 @@ def order_replicant_volume(self, volume_id, snapshot_schedule, def order_duplicate_volume(self, origin_volume_id, origin_snapshot_id=None, duplicate_size=None, duplicate_iops=None, duplicate_tier_level=None, - duplicate_snapshot_size=None): + duplicate_snapshot_size=None, + hourly_billing_flag=False): """Places an order for a duplicate block volume. :param origin_volume_id: The ID of the origin volume to be duplicated @@ -271,10 +272,11 @@ def order_duplicate_volume(self, origin_volume_id, origin_snapshot_id=None, :param duplicate_iops: The IOPS per GB for the duplicate volume :param duplicate_tier_level: Tier level for the duplicate volume :param duplicate_snapshot_size: Snapshot space size for the duplicate + :param hourly_billing_flag: Billing type, monthly (False) :return: Returns a SoftLayer_Container_Product_Order_Receipt """ - block_mask = 'id,billingItem[location],snapshotCapacityGb,'\ + block_mask = 'id,billingItem[location,hourlyFlag],snapshotCapacityGb,'\ 'storageType[keyName],capacityGb,originalVolumeSize,'\ 'provisionedIops,storageTierLevel,osType[keyName],'\ 'staasVersion,hasEncryptionAtRest' @@ -289,7 +291,7 @@ def order_duplicate_volume(self, origin_volume_id, origin_snapshot_id=None, order = storage_utils.prepare_duplicate_order_object( self, origin_volume, duplicate_iops, duplicate_tier_level, - duplicate_size, duplicate_snapshot_size, 'block' + duplicate_size, duplicate_snapshot_size, 'block',hourly_billing_flag ) order['osFormatType'] = {'keyName': os_type} diff --git a/SoftLayer/managers/file.py b/SoftLayer/managers/file.py index 3350e11e4..49c066209 100644 --- a/SoftLayer/managers/file.py +++ b/SoftLayer/managers/file.py @@ -250,7 +250,8 @@ def get_replication_locations(self, volume_id): def order_duplicate_volume(self, origin_volume_id, origin_snapshot_id=None, duplicate_size=None, duplicate_iops=None, duplicate_tier_level=None, - duplicate_snapshot_size=None): + duplicate_snapshot_size=None, + hourly_billing_flag=False): """Places an order for a duplicate file volume. :param origin_volume_id: The ID of the origin volume to be duplicated @@ -259,10 +260,11 @@ def order_duplicate_volume(self, origin_volume_id, origin_snapshot_id=None, :param duplicate_iops: The IOPS per GB for the duplicate volume :param duplicate_tier_level: Tier level for the duplicate volume :param duplicate_snapshot_size: Snapshot space size for the duplicate + :param hourly_billing_flag: Billing type, monthly (False) :return: Returns a SoftLayer_Container_Product_Order_Receipt """ - file_mask = 'id,billingItem[location],snapshotCapacityGb,'\ + file_mask = 'id,billingItem[location,hourlyFlag],snapshotCapacityGb,'\ 'storageType[keyName],capacityGb,originalVolumeSize,'\ 'provisionedIops,storageTierLevel,'\ 'staasVersion,hasEncryptionAtRest' @@ -271,7 +273,7 @@ def order_duplicate_volume(self, origin_volume_id, origin_snapshot_id=None, order = storage_utils.prepare_duplicate_order_object( self, origin_volume, duplicate_iops, duplicate_tier_level, - duplicate_size, duplicate_snapshot_size, 'file' + duplicate_size, duplicate_snapshot_size, 'file', hourly_billing_flag ) if origin_snapshot_id is not None: diff --git a/SoftLayer/managers/storage_utils.py b/SoftLayer/managers/storage_utils.py index f7b47d124..bfea98b47 100644 --- a/SoftLayer/managers/storage_utils.py +++ b/SoftLayer/managers/storage_utils.py @@ -883,7 +883,7 @@ def prepare_replicant_order_object(manager, snapshot_schedule, location, def prepare_duplicate_order_object(manager, origin_volume, iops, tier, duplicate_size, - duplicate_snapshot_size, volume_type): + duplicate_snapshot_size, volume_type, hourly_billing_flag): """Prepare the duplicate order to submit to SoftLayer_Product::placeOrder() :param manager: The File or Block manager calling this function @@ -893,6 +893,7 @@ def prepare_duplicate_order_object(manager, origin_volume, iops, tier, :param duplicate_size: The requested size for the duplicate volume :param duplicate_snapshot_size: The size for the duplicate snapshot space :param volume_type: The type of the origin volume ('file' or 'block') + :param hourly_billing_flag: Billing type, monthly (False) or hourly (True) :return: Returns the order object to be passed to the placeOrder() method of the Product_Order service """ @@ -994,6 +995,7 @@ def prepare_duplicate_order_object(manager, origin_volume, iops, tier, 'quantity': 1, 'location': location_id, 'duplicateOriginVolumeId': origin_volume['id'], + 'useHourlyPricing': hourly_billing_flag } if volume_is_performance: From e271c8f4435ebc11927ffa5fb7c465cb2c39331d Mon Sep 17 00:00:00 2001 From: Sunil Rajput Date: Fri, 25 Aug 2017 13:50:43 -0500 Subject: [PATCH 4/7] STORAGE-3308: File and Block Hourly billing option test coverage added for volume duplicate --- tests/managers/block_tests.py | 110 +++++++++++++++++++++++++++++++++ tests/managers/file_tests.py | 112 ++++++++++++++++++++++++++++++++++ 2 files changed, 222 insertions(+) diff --git a/tests/managers/block_tests.py b/tests/managers/block_tests.py index 601bb92c6..36f040e0b 100644 --- a/tests/managers/block_tests.py +++ b/tests/managers/block_tests.py @@ -217,6 +217,27 @@ def test_cancel_snapshot_immediately_hourly_billing(self): identifier=417, ) + def test_cancel_snapshot_immediately_hourly_billing_false(self): + mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') + mock.return_value = { + 'billingItem': { + 'activeChildren': [ + {'categoryCode': 'storage_snapshot_space', 'id': 417} + ], + 'hourlyFlag': True, + 'id': 449 + }, + } + + self.block.cancel_snapshot_space(1234, immediate=False) + + self.assert_called_with( + 'SoftLayer_Billing_Item', + 'cancelItem', + args=(True, True, 'No longer needed'), + identifier=417, + ) + def test_cancel_snapshot_exception_no_billing_item_active_children(self): mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') mock.return_value = { @@ -833,3 +854,92 @@ def test_setCredentialPassword(self): result = self.block.set_credential_password(access_id=102, password='AAAaaa') self.assertEqual(True, result) self.assert_called_with('SoftLayer_Network_Storage_Allowed_Host', 'setCredentialPassword') + + def test_order_block_duplicate_performance_hourly(self): + mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') + mock.return_value = [fixtures.SoftLayer_Product_Package.SAAS_PACKAGE] + + mock_volume = fixtures.SoftLayer_Network_Storage.STAAS_TEST_VOLUME + prev_storage_type_keyname = mock_volume['storageType']['keyName'] + mock_volume['storageType']['keyName'] = 'PERFORMANCE_BLOCK_STORAGE' + mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') + mock.return_value = mock_volume + + result = self.block.order_duplicate_volume( + 102, + origin_snapshot_id=470, + duplicate_size=1000, + duplicate_iops=2000, + duplicate_tier_level=None, + duplicate_snapshot_size=10 + ) + + self.assertEqual(fixtures.SoftLayer_Product_Order.placeOrder, result) + + self.assert_called_with( + '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': True + },)) + + mock_volume['storageType']['keyName'] = prev_storage_type_keyname + + def test_order_block_duplicate_endurance(self): + mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') + mock.return_value = [fixtures.SoftLayer_Product_Package.SAAS_PACKAGE] + + mock_volume = fixtures.SoftLayer_Network_Storage.STAAS_TEST_VOLUME + mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') + mock.return_value = mock_volume + + result = self.block.order_duplicate_volume( + 102, + origin_snapshot_id=470, + duplicate_size=1000, + duplicate_iops=None, + duplicate_tier_level=4, + duplicate_snapshot_size=10 + ) + + self.assertEqual(fixtures.SoftLayer_Product_Order.placeOrder, result) + + self.assert_called_with( + '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': True + },)) \ No newline at end of file diff --git a/tests/managers/file_tests.py b/tests/managers/file_tests.py index c3dff4339..97f233259 100644 --- a/tests/managers/file_tests.py +++ b/tests/managers/file_tests.py @@ -202,6 +202,27 @@ def test_cancel_snapshot_immediately_hourly_billing(self): identifier=417, ) + def test_cancel_snapshot_immediately_hourly_billing_false(self): + mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') + mock.return_value = { + 'billingItem': { + 'activeChildren': [ + {'categoryCode': 'storage_snapshot_space', 'id': 417} + ], + 'hourlyFlag': True, + 'id': 449 + }, + } + + self.file.cancel_snapshot_space(1234, immediate=False) + + self.assert_called_with( + 'SoftLayer_Billing_Item', + 'cancelItem', + args=(True, True, 'No longer needed'), + identifier=417, + ) + def test_cancel_snapshot_exception_no_billing_item_active_children(self): mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') mock.return_value = { @@ -789,3 +810,94 @@ def test_order_file_duplicate_endurance(self): },)) mock_volume['storageType']['keyName'] = prev_storage_type_keyname + + def test_order_file_duplicate_endurance_hourly(self): + mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') + mock.return_value = [fixtures.SoftLayer_Product_Package.SAAS_PACKAGE] + + mock_volume = fixtures.SoftLayer_Network_Storage.STAAS_TEST_VOLUME + prev_storage_type_keyname = mock_volume['storageType']['keyName'] + mock_volume['storageType']['keyName'] = 'ENDURANCE_FILE_STORAGE' + mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') + mock.return_value = mock_volume + + result = self.file.order_duplicate_volume( + 102, + origin_snapshot_id=470, + duplicate_size=1000, + duplicate_iops=None, + duplicate_tier_level=4, + duplicate_snapshot_size=10 + ) + + self.assertEqual(fixtures.SoftLayer_Product_Order.placeOrder, result) + + self.assert_called_with( + 'SoftLayer_Product_Order', + 'placeOrder', + args=({ + 'complexType': 'SoftLayer_Container_Product_Order_' + 'Network_Storage_AsAService', + 'packageId': 759, + 'prices': [ + {'id': 189433}, + {'id': 189453}, + {'id': 194763}, + {'id': 194703}, + {'id': 194943} + ], + 'volumeSize': 1000, + 'quantity': 1, + 'location': 449500, + 'duplicateOriginVolumeId': 102, + 'duplicateOriginSnapshotId': 470, + 'useHourlyPricing': True + },)) + + mock_volume['storageType']['keyName'] = prev_storage_type_keyname + + def test_order_file_duplicate_performance_hourly(self): + mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') + mock.return_value = [fixtures.SoftLayer_Product_Package.SAAS_PACKAGE] + + mock_volume = fixtures.SoftLayer_Network_Storage.STAAS_TEST_VOLUME + prev_storage_type_keyname = mock_volume['storageType']['keyName'] + mock_volume['storageType']['keyName'] = 'PERFORMANCE_FILE_STORAGE' + mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') + mock.return_value = mock_volume + + result = self.file.order_duplicate_volume( + 102, + origin_snapshot_id=470, + duplicate_size=1000, + duplicate_iops=2000, + duplicate_tier_level=None, + duplicate_snapshot_size=10 + ) + + self.assertEqual(fixtures.SoftLayer_Product_Order.placeOrder, result) + + self.assert_called_with( + 'SoftLayer_Product_Order', + 'placeOrder', + args=({ + 'complexType': 'SoftLayer_Container_Product_Order_' + 'Network_Storage_AsAService', + 'packageId': 759, + 'prices': [ + {'id': 189433}, + {'id': 189453}, + {'id': 190113}, + {'id': 190173}, + {'id': 191193} + ], + 'volumeSize': 1000, + 'quantity': 1, + 'location': 449500, + 'duplicateOriginVolumeId': 102, + 'duplicateOriginSnapshotId': 470, + 'iops': 2000, + 'useHourlyPricing': True + },)) + + mock_volume['storageType']['keyName'] = prev_storage_type_keyname \ No newline at end of file From f854866f55d78b507cc7663e84c8a2ea02bde226 Mon Sep 17 00:00:00 2001 From: Sunil Rajput Date: Fri, 25 Aug 2017 14:19:26 -0500 Subject: [PATCH 5/7] STORAGE-3308: File and Block Hourly billing option test coverage deification name changed. --- tests/managers/block_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/managers/block_tests.py b/tests/managers/block_tests.py index 36f040e0b..725a1b708 100644 --- a/tests/managers/block_tests.py +++ b/tests/managers/block_tests.py @@ -902,7 +902,7 @@ def test_order_block_duplicate_performance_hourly(self): mock_volume['storageType']['keyName'] = prev_storage_type_keyname - def test_order_block_duplicate_endurance(self): + def test_order_block_duplicate_endurance_hourly(self): mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') mock.return_value = [fixtures.SoftLayer_Product_Package.SAAS_PACKAGE] From d510a1e61c89abe4bb288462766197815e0ded06 Mon Sep 17 00:00:00 2001 From: Sunil Rajput Date: Fri, 25 Aug 2017 14:33:58 -0500 Subject: [PATCH 6/7] STORAGE-3308: Newly added test cases are removed for billing type option for duplicate volume. --- tests/managers/block_tests.py | 111 +--------------------------------- tests/managers/file_tests.py | 91 ---------------------------- 2 files changed, 1 insertion(+), 201 deletions(-) diff --git a/tests/managers/block_tests.py b/tests/managers/block_tests.py index 725a1b708..1299f3145 100644 --- a/tests/managers/block_tests.py +++ b/tests/managers/block_tests.py @@ -217,27 +217,6 @@ def test_cancel_snapshot_immediately_hourly_billing(self): identifier=417, ) - def test_cancel_snapshot_immediately_hourly_billing_false(self): - mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') - mock.return_value = { - 'billingItem': { - 'activeChildren': [ - {'categoryCode': 'storage_snapshot_space', 'id': 417} - ], - 'hourlyFlag': True, - 'id': 449 - }, - } - - self.block.cancel_snapshot_space(1234, immediate=False) - - self.assert_called_with( - 'SoftLayer_Billing_Item', - 'cancelItem', - args=(True, True, 'No longer needed'), - identifier=417, - ) - def test_cancel_snapshot_exception_no_billing_item_active_children(self): mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') mock.return_value = { @@ -854,92 +833,4 @@ def test_setCredentialPassword(self): result = self.block.set_credential_password(access_id=102, password='AAAaaa') self.assertEqual(True, result) self.assert_called_with('SoftLayer_Network_Storage_Allowed_Host', 'setCredentialPassword') - - def test_order_block_duplicate_performance_hourly(self): - mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') - mock.return_value = [fixtures.SoftLayer_Product_Package.SAAS_PACKAGE] - - mock_volume = fixtures.SoftLayer_Network_Storage.STAAS_TEST_VOLUME - prev_storage_type_keyname = mock_volume['storageType']['keyName'] - mock_volume['storageType']['keyName'] = 'PERFORMANCE_BLOCK_STORAGE' - mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') - mock.return_value = mock_volume - - result = self.block.order_duplicate_volume( - 102, - origin_snapshot_id=470, - duplicate_size=1000, - duplicate_iops=2000, - duplicate_tier_level=None, - duplicate_snapshot_size=10 - ) - - self.assertEqual(fixtures.SoftLayer_Product_Order.placeOrder, result) - - self.assert_called_with( - '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': True - },)) - - mock_volume['storageType']['keyName'] = prev_storage_type_keyname - - def test_order_block_duplicate_endurance_hourly(self): - mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') - mock.return_value = [fixtures.SoftLayer_Product_Package.SAAS_PACKAGE] - - mock_volume = fixtures.SoftLayer_Network_Storage.STAAS_TEST_VOLUME - mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') - mock.return_value = mock_volume - - result = self.block.order_duplicate_volume( - 102, - origin_snapshot_id=470, - duplicate_size=1000, - duplicate_iops=None, - duplicate_tier_level=4, - duplicate_snapshot_size=10 - ) - - self.assertEqual(fixtures.SoftLayer_Product_Order.placeOrder, result) - - self.assert_called_with( - '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': True - },)) \ No newline at end of file + \ No newline at end of file diff --git a/tests/managers/file_tests.py b/tests/managers/file_tests.py index 97f233259..6247b2ebd 100644 --- a/tests/managers/file_tests.py +++ b/tests/managers/file_tests.py @@ -809,95 +809,4 @@ def test_order_file_duplicate_endurance(self): 'duplicateOriginSnapshotId': 470 },)) - mock_volume['storageType']['keyName'] = prev_storage_type_keyname - - def test_order_file_duplicate_endurance_hourly(self): - mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') - mock.return_value = [fixtures.SoftLayer_Product_Package.SAAS_PACKAGE] - - mock_volume = fixtures.SoftLayer_Network_Storage.STAAS_TEST_VOLUME - prev_storage_type_keyname = mock_volume['storageType']['keyName'] - mock_volume['storageType']['keyName'] = 'ENDURANCE_FILE_STORAGE' - mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') - mock.return_value = mock_volume - - result = self.file.order_duplicate_volume( - 102, - origin_snapshot_id=470, - duplicate_size=1000, - duplicate_iops=None, - duplicate_tier_level=4, - duplicate_snapshot_size=10 - ) - - self.assertEqual(fixtures.SoftLayer_Product_Order.placeOrder, result) - - self.assert_called_with( - 'SoftLayer_Product_Order', - 'placeOrder', - args=({ - 'complexType': 'SoftLayer_Container_Product_Order_' - 'Network_Storage_AsAService', - 'packageId': 759, - 'prices': [ - {'id': 189433}, - {'id': 189453}, - {'id': 194763}, - {'id': 194703}, - {'id': 194943} - ], - 'volumeSize': 1000, - 'quantity': 1, - 'location': 449500, - 'duplicateOriginVolumeId': 102, - 'duplicateOriginSnapshotId': 470, - 'useHourlyPricing': True - },)) - - mock_volume['storageType']['keyName'] = prev_storage_type_keyname - - def test_order_file_duplicate_performance_hourly(self): - mock = self.set_mock('SoftLayer_Product_Package', 'getAllObjects') - mock.return_value = [fixtures.SoftLayer_Product_Package.SAAS_PACKAGE] - - mock_volume = fixtures.SoftLayer_Network_Storage.STAAS_TEST_VOLUME - prev_storage_type_keyname = mock_volume['storageType']['keyName'] - mock_volume['storageType']['keyName'] = 'PERFORMANCE_FILE_STORAGE' - mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') - mock.return_value = mock_volume - - result = self.file.order_duplicate_volume( - 102, - origin_snapshot_id=470, - duplicate_size=1000, - duplicate_iops=2000, - duplicate_tier_level=None, - duplicate_snapshot_size=10 - ) - - self.assertEqual(fixtures.SoftLayer_Product_Order.placeOrder, result) - - self.assert_called_with( - 'SoftLayer_Product_Order', - 'placeOrder', - args=({ - 'complexType': 'SoftLayer_Container_Product_Order_' - 'Network_Storage_AsAService', - 'packageId': 759, - 'prices': [ - {'id': 189433}, - {'id': 189453}, - {'id': 190113}, - {'id': 190173}, - {'id': 191193} - ], - 'volumeSize': 1000, - 'quantity': 1, - 'location': 449500, - 'duplicateOriginVolumeId': 102, - 'duplicateOriginSnapshotId': 470, - 'iops': 2000, - 'useHourlyPricing': True - },)) - mock_volume['storageType']['keyName'] = prev_storage_type_keyname \ No newline at end of file From ad36523dfeba486121bb21b02dab80d47d046ebc Mon Sep 17 00:00:00 2001 From: Sunil Rajput Date: Mon, 28 Aug 2017 10:30:39 -0500 Subject: [PATCH 7/7] STORAGE-3308: File and Block Hourly test cases changed. --- SoftLayer/managers/storage_utils.py | 4 +- tests/managers/block_tests.py | 61 ++++++------------------ tests/managers/file_tests.py | 73 ++++------------------------- 3 files changed, 26 insertions(+), 112 deletions(-) diff --git a/SoftLayer/managers/storage_utils.py b/SoftLayer/managers/storage_utils.py index bfea98b47..79b70cf3b 100644 --- a/SoftLayer/managers/storage_utils.py +++ b/SoftLayer/managers/storage_utils.py @@ -603,7 +603,7 @@ def prepare_snapshot_order_object(manager, volume, capacity, tier, upgrade): def prepare_volume_order_object(manager, storage_type, location, size, iops, tier, snapshot_size, service_offering, volume_type, - hourly_billing_flag): + hourly_billing_flag=False): """Prepare the order object which is submitted to the placeOrder() method :param manager: The File or Block manager calling this function @@ -883,7 +883,7 @@ def prepare_replicant_order_object(manager, snapshot_schedule, location, def prepare_duplicate_order_object(manager, origin_volume, iops, tier, duplicate_size, - duplicate_snapshot_size, volume_type, hourly_billing_flag): + duplicate_snapshot_size, volume_type, hourly_billing_flag=False): """Prepare the duplicate order to submit to SoftLayer_Product::placeOrder() :param manager: The File or Block manager calling this function diff --git a/tests/managers/block_tests.py b/tests/managers/block_tests.py index 1299f3145..e3d237ecb 100644 --- a/tests/managers/block_tests.py +++ b/tests/managers/block_tests.py @@ -25,21 +25,6 @@ def test_cancel_block_volume_immediately(self): identifier=449, ) - def test_cancel_block_volume_immediately_hourly_billing(self): - mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') - mock.return_value = { - '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) @@ -196,27 +181,6 @@ def test_cancel_snapshot_immediately(self): identifier=123, ) - def test_cancel_snapshot_immediately_hourly_billing(self): - mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') - mock.return_value = { - 'billingItem': { - 'activeChildren': [ - {'categoryCode': 'storage_snapshot_space', 'id': 417} - ], - 'hourlyFlag': True, - 'id': 449 - }, - } - - self.block.cancel_snapshot_space(1234, immediate=True) - - self.assert_called_with( - 'SoftLayer_Billing_Item', - 'cancelItem', - args=(True, True, 'No longer needed'), - identifier=417, - ) - def test_cancel_snapshot_exception_no_billing_item_active_children(self): mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') mock.return_value = { @@ -349,8 +313,8 @@ def test_order_block_volume_performance(self): 'quantity': 1, 'location': 449494, 'iops': 2000, + 'osFormatType': {'keyName': 'LINUX'}, 'useHourlyPricing': False, - 'osFormatType': {'keyName': 'LINUX'} },) ) @@ -394,8 +358,8 @@ def test_order_block_volume_endurance(self): 'volumeSize': 1000, 'quantity': 1, 'location': 449494, + 'osFormatType': {'keyName': 'LINUX'}, 'useHourlyPricing': False, - 'osFormatType': {'keyName': 'LINUX'} },) ) @@ -500,7 +464,7 @@ def test_order_block_snapshot_space_upgrade(self): 'quantity': 1, 'location': 449500, 'volumeId': 102, - 'useHourlyPricing': False + 'useHourlyPricing': False, },) ) @@ -531,7 +495,7 @@ def test_order_block_snapshot_space(self): 'quantity': 1, 'location': 449500, 'volumeId': 102, - 'useHourlyPricing': False + 'useHourlyPricing': False, },) ) @@ -599,8 +563,8 @@ def test_order_block_replicant_performance_os_type_given(self): 'iops': 1000, 'originVolumeId': 102, 'originVolumeScheduleId': 978, + 'osFormatType': {'keyName': 'XEN'}, 'useHourlyPricing': False, - 'osFormatType': {'keyName': 'XEN'} },) ) @@ -641,8 +605,8 @@ def test_order_block_replicant_endurance(self): 'location': 449494, 'originVolumeId': 102, 'originVolumeScheduleId': 978, + 'osFormatType': {'keyName': 'LINUX'}, 'useHourlyPricing': False, - 'osFormatType': {'keyName': 'LINUX'} },) ) @@ -701,7 +665,8 @@ def test_order_block_duplicate_performance_no_duplicate_snapshot(self): 'location': 449500, 'duplicateOriginVolumeId': 102, 'osFormatType': {'keyName': 'LINUX'}, - 'iops': 1000 + 'iops': 1000, + 'useHourlyPricing': False, },)) mock_volume['storageType']['keyName'] = prev_storage_type_keyname @@ -747,7 +712,8 @@ def test_order_block_duplicate_performance(self): 'duplicateOriginVolumeId': 102, 'osFormatType': {'keyName': 'LINUX'}, 'duplicateOriginSnapshotId': 470, - 'iops': 2000 + 'iops': 2000, + 'useHourlyPricing': False, },)) mock_volume['storageType']['keyName'] = prev_storage_type_keyname @@ -783,7 +749,8 @@ def test_order_block_duplicate_endurance_no_duplicate_snapshot(self): 'quantity': 1, 'location': 449500, 'duplicateOriginVolumeId': 102, - 'osFormatType': {'keyName': 'LINUX'} + 'osFormatType': {'keyName': 'LINUX'}, + 'useHourlyPricing': False, },)) def test_order_block_duplicate_endurance(self): @@ -824,7 +791,8 @@ def test_order_block_duplicate_endurance(self): 'location': 449500, 'duplicateOriginVolumeId': 102, 'osFormatType': {'keyName': 'LINUX'}, - 'duplicateOriginSnapshotId': 470 + 'duplicateOriginSnapshotId': 470, + 'useHourlyPricing': False, },)) def test_setCredentialPassword(self): @@ -833,4 +801,3 @@ def test_setCredentialPassword(self): result = self.block.set_credential_password(access_id=102, password='AAAaaa') self.assertEqual(True, result) self.assert_called_with('SoftLayer_Network_Storage_Allowed_Host', 'setCredentialPassword') - \ No newline at end of file diff --git a/tests/managers/file_tests.py b/tests/managers/file_tests.py index 6247b2ebd..157cd5d7b 100644 --- a/tests/managers/file_tests.py +++ b/tests/managers/file_tests.py @@ -25,21 +25,6 @@ def test_cancel_file_volume_immediately(self): identifier=449, ) - def test_cancel_file_volume_immediately_hourly_billing(self): - mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') - mock.return_value = { - 'billingItem': {'hourlyFlag': True, 'id': 449}, - } - - self.file.cancel_file_volume(123, immediate=False) - - self.assert_called_with( - 'SoftLayer_Billing_Item', - 'cancelItem', - args=(True, True, 'No longer needed'), - identifier=449, - ) - def test_authorize_host_to_volume(self): result = self.file.authorize_host_to_volume( 50, @@ -181,48 +166,6 @@ def test_cancel_snapshot_immediately(self): identifier=123, ) - def test_cancel_snapshot_immediately_hourly_billing(self): - mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') - mock.return_value = { - 'billingItem': { - 'activeChildren': [ - {'categoryCode': 'storage_snapshot_space', 'id': 417} - ], - 'hourlyFlag': True, - 'id': 449 - }, - } - - self.file.cancel_snapshot_space(1234, immediate=True) - - self.assert_called_with( - 'SoftLayer_Billing_Item', - 'cancelItem', - args=(True, True, 'No longer needed'), - identifier=417, - ) - - def test_cancel_snapshot_immediately_hourly_billing_false(self): - mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') - mock.return_value = { - 'billingItem': { - 'activeChildren': [ - {'categoryCode': 'storage_snapshot_space', 'id': 417} - ], - 'hourlyFlag': True, - 'id': 449 - }, - } - - self.file.cancel_snapshot_space(1234, immediate=False) - - self.assert_called_with( - 'SoftLayer_Billing_Item', - 'cancelItem', - args=(True, True, 'No longer needed'), - identifier=417, - ) - def test_cancel_snapshot_exception_no_billing_item_active_children(self): mock = self.set_mock('SoftLayer_Network_Storage', 'getObject') mock.return_value = { @@ -443,7 +386,7 @@ def test_order_file_volume_performance(self): 'quantity': 1, 'location': 449494, 'iops': 2000, - 'useHourlyPricing': False + 'useHourlyPricing': False, },) ) @@ -488,7 +431,7 @@ def test_order_file_volume_endurance(self): 'volumeSize': 1000, 'quantity': 1, 'location': 449494, - 'useHourlyPricing': False + 'useHourlyPricing': False, },) ) @@ -680,7 +623,8 @@ def test_order_file_duplicate_performance_no_duplicate_snapshot(self): 'quantity': 1, 'location': 449500, 'duplicateOriginVolumeId': 102, - 'iops': 1000 + 'iops': 1000, + 'useHourlyPricing': False },)) mock_volume['storageType']['keyName'] = prev_storage_type_keyname @@ -725,7 +669,8 @@ def test_order_file_duplicate_performance(self): 'location': 449500, 'duplicateOriginVolumeId': 102, 'duplicateOriginSnapshotId': 470, - 'iops': 2000 + 'iops': 2000, + 'useHourlyPricing': False, },)) mock_volume['storageType']['keyName'] = prev_storage_type_keyname @@ -762,7 +707,8 @@ def test_order_file_duplicate_endurance_no_duplicate_snapshot(self): 'volumeSize': 500, 'quantity': 1, 'location': 449500, - 'duplicateOriginVolumeId': 102 + 'duplicateOriginVolumeId': 102, + 'useHourlyPricing': False, },)) mock_volume['storageType']['keyName'] = prev_storage_type_keyname @@ -806,7 +752,8 @@ def test_order_file_duplicate_endurance(self): 'quantity': 1, 'location': 449500, 'duplicateOriginVolumeId': 102, - 'duplicateOriginSnapshotId': 470 + 'duplicateOriginSnapshotId': 470, + 'useHourlyPricing': False, },)) mock_volume['storageType']['keyName'] = prev_storage_type_keyname \ No newline at end of file