Repository: softlayer/softlayer-python
Pull request #1106 (2019-02-27 02:08:50)

Firmware reflash
This allows users to reflash hardware firmware directly from the CLI.


Patch:
diff --git a/SoftLayer/CLI/hardware/reflash_firmware.py b/SoftLayer/CLI/hardware/reflash_firmware.py
new file mode 100644
index 00000000..40d33416
--- /dev/null
+++ b/SoftLayer/CLI/hardware/reflash_firmware.py
@@ -0,0 +1,26 @@
+"""Reflash firmware."""
+# :license: MIT, see LICENSE for more details.
+
+import click
+
+import SoftLayer
+from SoftLayer.CLI import environment
+from SoftLayer.CLI import exceptions
+from SoftLayer.CLI import formatting
+from SoftLayer.CLI import helpers
+
+
+@click.command()
+@click.argument('identifier')
+@environment.pass_env
+def cli(env, identifier):
+    """Reflash server firmware."""
+
+    mgr = SoftLayer.HardwareManager(env.client)
+    hw_id = helpers.resolve_id(mgr.resolve_ids, identifier, 'hardware')
+    if not (env.skip_confirmations or
+            formatting.confirm('This will power off the server with id %s and '
+                               'reflash device firmware. Continue?' % hw_id)):
+        raise exceptions.CLIAbort('Aborted.')
+
+    mgr.reflash_firmware(hw_id)
diff --git a/SoftLayer/CLI/routes.py b/SoftLayer/CLI/routes.py
index cc6a86ab..f03b1e17 100644
--- a/SoftLayer/CLI/routes.py
+++ b/SoftLayer/CLI/routes.py
@@ -240,6 +240,7 @@
     ('hardware:reload', 'SoftLayer.CLI.hardware.reload:cli'),
     ('hardware:credentials', 'SoftLayer.CLI.hardware.credentials:cli'),
     ('hardware:update-firmware', 'SoftLayer.CLI.hardware.update_firmware:cli'),
+    ('hardware:reflash-firmware', 'SoftLayer.CLI.hardware.reflash_firmware:cli'),
     ('hardware:rescue', 'SoftLayer.CLI.hardware.power:rescue'),
     ('hardware:ready', 'SoftLayer.CLI.hardware.ready:cli'),
     ('hardware:toggle-ipmi', 'SoftLayer.CLI.hardware.toggle_ipmi:cli'),
diff --git a/SoftLayer/fixtures/SoftLayer_Hardware_Server.py b/SoftLayer/fixtures/SoftLayer_Hardware_Server.py
index 9a9587b8..72838692 100644
--- a/SoftLayer/fixtures/SoftLayer_Hardware_Server.py
+++ b/SoftLayer/fixtures/SoftLayer_Hardware_Server.py
@@ -81,6 +81,7 @@
 rebootDefault = True
 rebootHard = True
 createFirmwareUpdateTransaction = True
+createFirmwareReflashTransaction = True
 setUserMetadata = ['meta']
 reloadOperatingSystem = 'OK'
 getReverseDomainRecords = [
diff --git a/SoftLayer/managers/hardware.py b/SoftLayer/managers/hardware.py
index 9f97a1d3..77c4e604 100644
--- a/SoftLayer/managers/hardware.py
+++ b/SoftLayer/managers/hardware.py
@@ -613,6 +613,31 @@ def update_firmware(self,
         return self.hardware.createFirmwareUpdateTransaction(
             bool(ipmi), bool(raid_controller), bool(bios), bool(hard_drive), id=hardware_id)
 
+    def reflash_firmware(self,
+                         hardware_id,
+                         ipmi=True,
+                         raid_controller=True,
+                         bios=True):
+        """Reflash hardware firmware.
+
+        This will cause the server to be unavailable for ~60 minutes.
+        The firmware will not be upgraded but rather reflashed to the version installed.
+
+        :param int hardware_id: The ID of the hardware to have its firmware
+                                reflashed.
+        :param bool ipmi: Reflash the ipmi firmware.
+        :param bool raid_controller: Reflash the raid controller firmware.
+        :param bool bios: Reflash the bios firmware.
+
+        Example::
+
+            # Check the servers active transactions to see progress
+            result = mgr.reflash_firmware(hardware_id=1234)
+        """
+
+        return self.hardware.createFirmwareReflashTransaction(
+            bool(ipmi), bool(raid_controller), bool(bios), id=hardware_id)
+
     def wait_for_ready(self, instance_id, limit=14400, delay=10, pending=False):
         """Determine if a Server is ready.
 


Test patch:
diff --git a/tests/CLI/modules/server_tests.py b/tests/CLI/modules/server_tests.py
index c9e03077..75e2cd78 100644
--- a/tests/CLI/modules/server_tests.py
+++ b/tests/CLI/modules/server_tests.py
@@ -482,6 +482,17 @@ def test_update_firmware(self, confirm_mock):
                                 'createFirmwareUpdateTransaction',
                                 args=((1, 1, 1, 1)), identifier=1000)
 
+    @mock.patch('SoftLayer.CLI.formatting.confirm')
+    def test_reflash_firmware(self, confirm_mock):
+        confirm_mock.return_value = True
+        result = self.run_command(['server', 'reflash-firmware', '1000'])
+
+        self.assert_no_fail(result)
+        self.assertEqual(result.output, "")
+        self.assert_called_with('SoftLayer_Hardware_Server',
+                                'createFirmwareReflashTransaction',
+                                args=((1, 1, 1)), identifier=1000)
+
     def test_edit(self):
         result = self.run_command(['server', 'edit',
                                    '--domain=example.com',
diff --git a/tests/managers/hardware_tests.py b/tests/managers/hardware_tests.py
index b3c95a1d..030d808d 100644
--- a/tests/managers/hardware_tests.py
+++ b/tests/managers/hardware_tests.py
@@ -392,6 +392,24 @@ def test_update_firmware_selective(self):
                                 'createFirmwareUpdateTransaction',
                                 identifier=100, args=(0, 1, 1, 0))
 
+    def test_reflash_firmware(self):
+        result = self.hardware.reflash_firmware(100)
+
+        self.assertEqual(result, True)
+        self.assert_called_with('SoftLayer_Hardware_Server',
+                                'createFirmwareReflashTransaction',
+                                identifier=100, args=(1, 1, 1))
+
+    def test_reflash_firmware_selective(self):
+        result = self.hardware.reflash_firmware(100,
+                                                raid_controller=False,
+                                                bios=False)
+
+        self.assertEqual(result, True)
+        self.assert_called_with('SoftLayer_Hardware_Server',
+                                'createFirmwareReflashTransaction',
+                                identifier=100, args=(1, 0, 0))
+
 
 class HardwareHelperTests(testing.TestCase):
     def test_get_extra_price_id_no_items(self):