Repository: softlayer/softlayer-python
Pull request #2083 (2023-08-28 14:52:34)

added example in order, partners and cancel in file, added force and unit test cases  in order, cancel commands.
Hi @allmightyspiff,

Fixes: #2026 

Title:
Example and some features was missing in slcli file replica-order, slcli file replica-partners, slcli file snapshot-cancel 

Description:
I have added example in order, partners and cancel in file, added force and unit test cases  in order, cancel commands.

Please find the screenshot and review it.

Screen Shot:
<img width="1284" alt="Screenshot 2023-08-28 at 8 10 39 PM" src="https://github.com/softlayer/softlayer-python/assets/125332006/ded0122f-ee86-4dab-bff1-a4e55b66023a">

Thanks,
Ramkishor Chaladi.


Patch:
diff --git a/SoftLayer/CLI/file/replication/order.py b/SoftLayer/CLI/file/replication/order.py
index 14e4ae15..ae9e517d 100644
--- a/SoftLayer/CLI/file/replication/order.py
+++ b/SoftLayer/CLI/file/replication/order.py
@@ -5,6 +5,7 @@
 import SoftLayer
 from SoftLayer.CLI import environment
 from SoftLayer.CLI import exceptions
+from SoftLayer.CLI import formatting
 from SoftLayer.CLI import helpers
 from SoftLayer import utils
 
@@ -27,21 +28,47 @@
               help='Endurance Storage Tier (IOPS per GB) of the primary'
               ' volume for which a replicant is ordered [optional]',
               type=click.Choice(['0.25', '2', '4', '10']))
+@click.option('--iops', '-i', type=int,
+              help='Performance Storage IOPs, between 100 and 6000 in multiples of 100,'
+              'if no IOPS value is specified, the IOPS value of the original volume will be used',
+              )
+@click.option('--force', default=False, is_flag=True, help="Force cancel block volume without confirmation")
 @environment.pass_env
-def cli(env, volume_id, snapshot_schedule, location, tier):
-    """Order a file storage replica volume."""
+def cli(env, volume_id, snapshot_schedule, location, tier, iops, force):
+    """Order a file storage replica volume.
+
+    Example::
+        slcli file replica-order 12345678 -s DAILY -d dal09 --tier 4 --os-type LINUX
+        This command orders a replica for volume with ID 12345678, which performs DAILY
+        replication, is located at dal09, tier level is 4, OS type is Linux.
+    """
     file_manager = SoftLayer.FileStorageManager(env.client)
     file_volume_id = helpers.resolve_id(file_manager.resolve_ids, volume_id, 'File Storage')
 
     if tier is not None:
         tier = float(tier)
 
+    if iops is not None:
+        if iops < 100 or iops > 6000:
+            raise exceptions.CLIHalt("-i|--iops must be between 100 and 6000, inclusive. "
+                                     "Run 'slcli block volume-options' to check available options.")
+
+        if iops % 100 != 0:
+            raise exceptions.CLIHalt("-i|--iops must be a multiple of 100. "
+                                     "Run 'slcli block volume-options' to check available options.")
+
+    if not force:
+        if not (env.skip_confirmations or
+                formatting.confirm(f"This will Order a file storage replica volume: {volume_id} "
+                                   "and cannot be undone. Continue?")):
+            raise exceptions.CLIAbort('Aborted.')
+
     try:
         order = file_manager.order_replicant_volume(
             file_volume_id,
             snapshot_schedule=snapshot_schedule,
             location=location,
-            tier=tier,
+            tier=tier, iops=iops,
         )
     except ValueError as ex:
         raise exceptions.ArgumentError(str(ex))
diff --git a/SoftLayer/CLI/file/replication/partners.py b/SoftLayer/CLI/file/replication/partners.py
index e4eb971d..6305cbf7 100644
--- a/SoftLayer/CLI/file/replication/partners.py
+++ b/SoftLayer/CLI/file/replication/partners.py
@@ -21,7 +21,12 @@
               default=','.join(DEFAULT_COLUMNS))
 @environment.pass_env
 def cli(env, columns, sortby, volume_id):
-    """List existing replicant volumes for a file volume."""
+    """List existing replicant volumes for a file volume.
+
+    Example::
+        slcli file replica-partners 12345678
+        This command lists existing replicant volumes for block volume with ID 12345678.
+    """
     file_storage_manager = SoftLayer.FileStorageManager(env.client)
 
     legal_volumes = file_storage_manager.get_replication_partners(
diff --git a/SoftLayer/CLI/file/snapshot/cancel.py b/SoftLayer/CLI/file/snapshot/cancel.py
index d2b9f815..ea78f138 100644
--- a/SoftLayer/CLI/file/snapshot/cancel.py
+++ b/SoftLayer/CLI/file/snapshot/cancel.py
@@ -16,14 +16,21 @@
               is_flag=True,
               help="Cancels the snapshot space immediately instead "
                    "of on the billing anniversary")
+@click.option('--force', default=False, is_flag=True, help="Force cancel block volume without confirmation")
 @environment.pass_env
-def cli(env, volume_id, reason, immediate):
-    """Cancel existing snapshot space for a given volume."""
+def cli(env, volume_id, reason, immediate, force):
+    """Cancel existing snapshot space for a given volume.
+
+    Example::
+        slcli file snapshot-cancel 12345678 --immediate -f
+        This command cancels snapshot with ID 12345678 immediately without asking for confirmation.
+    """
 
     file_storage_manager = SoftLayer.FileStorageManager(env.client)
 
-    if not (env.skip_confirmations or formatting.no_going_back(volume_id)):
-        raise exceptions.CLIAbort('Aborted')
+    if not force:
+        if not (env.skip_confirmations or formatting.no_going_back(volume_id)):
+            raise exceptions.CLIAbort('Aborted.')
 
     cancelled = file_storage_manager.cancel_snapshot_space(
         volume_id, reason, immediate)


Test patch:
diff --git a/tests/CLI/modules/file_tests.py b/tests/CLI/modules/file_tests.py
index b9222574..a1749e7f 100644
--- a/tests/CLI/modules/file_tests.py
+++ b/tests/CLI/modules/file_tests.py
@@ -828,3 +828,25 @@ def test_modify_order_no_force(self, confirm_mock):
 
         self.assertEqual(2, result.exit_code)
         self.assertEqual('Aborted', result.exception.message)
+
+    def test_file_replica_order_iops(self):
+        result_1 = self.run_command(['file', 'replica-order', '4917309', '-s', 'HOURLY', '-l', 'dal09', '-i', '121'])
+        self.assertEqual("-i|--iops must be a multiple of 100. "
+                         "Run 'slcli block volume-options' to check available options.\n", result_1.output)
+        result_2 = self.run_command(['file', 'replica-order', '4917309', '-s', 'HOURLY', '-l', 'dal09', '-i', '90'])
+        self.assertEqual("-i|--iops must be between 100 and 6000, inclusive. "
+                         "Run 'slcli block volume-options' to check available options.\n", result_2.output)
+
+    @mock.patch('SoftLayer.CLI.formatting.confirm')
+    def test_file_replica_order_force(self, confirm_mock):
+        confirm_mock.return_value = False
+        result = self.run_command(['file', 'replica-order', '4917309', '-s', 'HOURLY', '-l', 'dal09'])
+        self.assertEqual(2, result.exit_code)
+        self.assertEqual('Aborted.', result.exception.message)
+
+    @mock.patch('SoftLayer.CLI.formatting.confirm')
+    def test_file_snapshot_cancel_force(self, confirm_mock):
+        confirm_mock.return_value = False
+        result = self.run_command(['file', 'snapshot-cancel', '4917309'])
+        self.assertEqual(2, result.exit_code)
+        self.assertEqual('Aborted.', result.exception.message)