Skip to content

Commit

Permalink
Merge pull request #647 from softlayer/issues644
Browse files Browse the repository at this point in the history
Updated the firmware update example.
  • Loading branch information
allmightyspiff authored Jan 22, 2024
2 parents 46350e9 + 64aa2ee commit 81a76c9
Showing 1 changed file with 122 additions and 41 deletions.
163 changes: 122 additions & 41 deletions content/python/update_firmware.py.md
Original file line number Diff line number Diff line change
@@ -1,61 +1,142 @@
---
title: "update_firmware.py"
description: "update_firmware.py"
title: "Update Firmware"
description: "An explanation of how to update the firmware on a bare metal server using the Python SDK."
date: "2017-11-23"
classes:
- "SoftLayer_Hardware_Server"
tags:
- "baremetalservers"
- "server"
---

This example shows how to update the firmware on a given server. Primarily this script calls [SoftLayer_Hardware_Server::createFirmwareUpdateTransaction](/reference/services/SoftLayer_Hardware_Server/createFirmwareUpdateTransaction/), which has options for what specific bits of firmware you want to update. Currently you can choose to update the following:
- IPMI
- Raid Controller
- BIOS
- Hard Drives
- Network Card

```
"""
Update the firmware in a BareMetal server

The script makes a single call to SoftLayer_Hardware_Server::createFirmwareUpdateTransaction
method to update the firmware in a bare metal server. It will bring your server offline for
approximately 20 minutes while the updates are in progress.
*NOTE* The server will need to be offline for about 20 minutes this update to happen, so be aware of that.

See below for more details
*NOTE* The [`slcli hardware update-firmware`](https://softlayer-python.readthedocs.io/en/latest/cli/hardware/#hardware-update-firmware) and [`ibmcloud sl hardware update-firmware`](https://cloud.ibm.com/docs/cli?topic=cli-sl-manage-bare-metal#sl_hardware_update_firmware) commands have this feature as well. Although they simply update all firmware and do not allow for selecting a specific bit to update.

Important manual pages:
http://sldn.softlayer.com/reference/services/SoftLayer_Hardware_Server/createFirmwareUpdateTransaction
## Example

License: http://sldn.softlayer.com/article/License
Author: SoftLayer Technologies, Inc. <[email protected]>
```python
"""
import SoftLayer.API
from pprint import pprint as pp
@author Christopher Gallo
# Your SoftLayer API username and key.
API_USERNAME = 'set-me'
Updates the firmware of the specified serverid. Server must be offline to be updated.
Script requried
Python 3.7+
click 8.0+ - For making this script a CLI command easily
rich - To make the output look nice
"""

# Generate one at https://control.softlayer.com/account/users
API_KEY = 'set-me'
# Click is used to make this script support CLI arguments
import click
# Used for details table output
from rich.console import Console
from rich.table import Table
from rich.prompt import Confirm
from rich.live import Live
from rich import print
# The SoftLayer SDK
import SoftLayer
# Used for time.sleep() to wait for a server to power off
import time

# Declare the API client
client = SoftLayer.create_client_from_env(username=API_USERNAME, api_key=API_KEY)
hardwareServerService = client['SoftLayer_Hardware_Server']

# The if of the bare metal server you wish to update the firmware
hardwareId = 284776
class SLSDK():
"""Class used to manage making API calls to the SL API"""
def __init__(self):
"""SoftLayer Client Initialization"""
self.client = SoftLayer.Client()
# This part allows printing out the exact API calls used
debugger = SoftLayer.DebugTransport(self.client.transport)
self.client.transport = debugger

"""
The firmware to update
set the values with "1" to update and "0" skip
"""
ipmi = 1
raidController = 1
bios = 1
hardDrive = 0
try:
result = hardwareServerService.createFirmwareUpdateTransaction(ipmi, raidController, bios, hardDrive, id=hardwareId)
pp(result)
except SoftLayer.SoftLayerAPIError as e:
print("Unable to update the firmware: \nfaultCode= %s, \nfaultString= %s"
% (e.faultCode, e.faultString))
exit(1)
def resolveServerId(self, serverid: int) -> str:
"""Gets the Fully Qualified Domain Name for a server"""
fqdnMask = "mask[id,fullyQualifiedDomainName]"
fqdn = self.client.call('SoftLayer_Hardware_Server', 'getObject', id=serverid, mask=fqdnMask)
return fqdn.get('fullyQualifiedDomainName', '')

def powerOff(self, serverid: int) -> None:
"""Powers off serverid"""
self.client.call('SoftLayer_Hardware_Server', 'powerOff', id=serverid)

def powerOn(self, serverid: int) -> None:
"""Powers on serverid"""
self.client.call('SoftLayer_Hardware_Server', 'powerOn', id=serverid)

def update(self, serverid: int, ipmi: bool, raid: bool, bios: bool, harddrive: bool, network: bool) -> bool:
"""Updates firmware for serverID for the specified devices"""
result = self.client.call('SoftLayer_Hardware_Server', 'createFirmwareUpdateTransaction',
ipmi, raid, bios, harddrive, network, id=serverid)
return result


def waitForReboot(seconds: int) -> str:
return f"Wait {seconds} for server to reboot..."

@click.command()
@click.argument('serverid')
@click.option('-f', '--force', is_flag=True, help="Skips the confirmation dialog prompts")
@click.option('-i', '--ipmi', is_flag=True, help="Update IPMI firmware")
@click.option('-r', '--raid', is_flag=True, help="Update RAID firmware")
@click.option('-b', '--bios', is_flag=True, help="Update BIOS firmware")
@click.option('-d', '--harddrive', is_flag=True, help="Update Hard Drives firmware")
@click.option('-n', '--network', is_flag=True, help="Update Network Card firmware")
def updateFirmware(serverid, force, ipmi, raid, bios, harddrive, network):
# init the SDK Class
sdk = SLSDK()
# Take the serverId and get a FQDN from it
try:
fqdn = sdk.resolveServerId(serverid)
except SoftLayer.SoftLayerError as e:
print(f"[red]Failed to get server [underline]{serverid}[/underline]. Error: [underline]{e}[/underline]")
raise click.Abort()

# Make sure the user knows what is about to happen to their server
if not force:
prompt = f"You are about to reboot server [red]{fqdn}[/red] and update its firmware, continue?"
if not Confirm.ask(prompt):
raise click.Abort()

# Shutdown the server, wait a few seconds for that to processes
print(f"Shutting down and updating [red]{fqdn}[/red] now...")
sdk.powerOff(serverid)
waitFor = 15
# This bit is just to be fancy and have an update-in-place counter
with Live(waitForReboot(waitFor), refresh_per_second=1) as live:
for second in range(waitFor):
time.sleep(1)
live.update(waitForReboot(waitFor - second))

# Actually do the firmware update. This might return an exception if no firmwares were requested to be udpated.
try:
sdk.update(serverid, ipmi, raid, bios, harddrive, network)
print(f"[green]Successfully updated [underline]{fqdn}[/underline]")
except SoftLayer.SoftLayerError as e:
print(f"[red]Failed to update server [underline]{fqdn}[/underline]. Error: [underline]{e}[/underline]")
raise click.Abort()


if __name__ == "__main__":
updateFirmware()
```



## Output

```
$> python testFirmwareUpdate.py 3332650 -f -i -r -b -d -n
Calling: SoftLayer_Hardware_Server::getObject(id=3332650, mask='mask[id,fullyQualifiedDomainName]', filter='None', args=(), limit=None, offset=None)
Shutting down and updating ibmtesttest01.ibmtest.com now...
Calling: SoftLayer_Hardware_Server::powerOff(id=3332650, mask='', filter='None', args=(), limit=None, offset=None)
Wait 1 for server to reboot...
Calling: SoftLayer_Hardware_Server::createFirmwareUpdateTransaction(id=3332650, mask='', filter='None', args=(True, True, True, True, True), limit=None, offset=None)
Successfully updated ibmtesttest01.ibmtest.com
```

0 comments on commit 81a76c9

Please sign in to comment.