Skip to content

Instantly share code, notes, and snippets.

@noslin005
Last active September 19, 2024 01:54
Show Gist options
  • Save noslin005/5e5e0f7a99f93b1cfbd58cf4570d49c0 to your computer and use it in GitHub Desktop.
Save noslin005/5e5e0f7a99f93b1cfbd58cf4570d49c0 to your computer and use it in GitHub Desktop.
Perform the BIOS/BMC update on multiple Gigabyte nodes using GbUtility.
#!/usr/bin/env python3
import argparse
import multiprocessing
import os
import shutil
import subprocess
__author__ = 'Nilson Lopes <[email protected]>'
def update_firmware(host, user, password, asset_tag, update_type, file_path, verbose):
"""
Update the BIOS or BMC on a single node.
Args:
host (str): The host of the BMC node.
user (str): The username for authentication.
password (str): The password for authentication.
asset_tag (str): The asset tag of the node.
update_type (str): The type of update (bios or bmc).
file_path (str): The path to the BIOS/BMC update file.
verbose (bool): Whether to display the command output.
Returns:
tuple: A tuple containing the asset tag and a boolean indicating
whether the update was successful (asset_tag, success).
"""
# Create a folder with the asset tag name
folder_path = os.path.join(os.getcwd(), asset_tag)
os.makedirs(folder_path, exist_ok=True)
# Copy the BIOS/BMC update file to the asset tag folder
destination_path = os.path.join(folder_path, os.path.basename(file_path))
shutil.copyfile(file_path, destination_path)
gbtutil_jar = "/opt/gsmcli/GbtUtility-2.1.60.jar"
command = (f"java -jar {gbtutil_jar} -H {host} -U {user} "
f"-P {password} update {update_type} auto {destination_path}")
process = subprocess.Popen(command,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
# Output file path for the current asset tag
output_file = os.path.join(folder_path, f"{asset_tag}.txt")
while True:
output = process.stdout.readline().decode().strip()
if output:
print(f"Node {asset_tag} is running ...")
if verbose:
print(f"Node: {asset_tag} - {output}")
with open(output_file, "a") as file:
file.write(f"{output}\n")
if process.poll() is not None:
break
if process.returncode == 0:
return asset_tag, True
else:
return asset_tag, False
def main(update_type, file_path, nodes_file, verbose):
"""
Perform the BIOS/BMC update on multiple nodes.
Args:
update_type (str): The type of update (bios or bmc).
file_path (str): The path to the BIOS/BMC update file.
nodes_file (str): The path to the file containing the list of BMC nodes.
verbose (bool): Whether to display the command output at the end.
"""
# Read the list of BMC nodes from the specified text file
with open(nodes_file, 'r') as file:
nodes = [line.strip().split() for line in file.readlines()]
pool = multiprocessing.Pool(processes=len(nodes))
results = [pool.apply_async(update_firmware,
(host,
user,
password,
asset_tag,
update_type,
file_path,
verbose))
for host, user, password, asset_tag in nodes]
pool.close()
pool.join()
success_nodes = []
failed_nodes = []
for result in results:
asset_tag, success = result.get()
if success:
success_nodes.append(asset_tag)
else:
failed_nodes.append(asset_tag)
print("\n--- Nodes updated successfully ---")
for asset_tag in success_nodes:
print(asset_tag)
print("\n--- Nodes failed to update ---")
for asset_tag in failed_nodes:
print(asset_tag)
# Display the command output if verbose mode is enabled
if verbose:
print("\n--- Command Output ---")
for asset_tag in success_nodes + failed_nodes:
output_file = os.path.join(asset_tag, f"{asset_tag}.txt")
with open(output_file, "r", encoding='utf-8') as file:
print(f"Node: {asset_tag}")
print(file.read())
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Update BIOS or BMC on multiple nodes.')
parser.add_argument('file_path',
help='Path to the BIOS/BMC update file')
parser.add_argument('-u',
'--update_type',
action='store',
choices=['bios', 'bmc'],
required=True,
help='Update type (bios or bmc)')
parser.add_argument('-l',
'--nodes_file',
default='nodes.txt',
action='store',
required=True,
help='Path to the file containing the list of'
' BMC nodes (default: nodes.txt)')
parser.add_argument('-v',
'--verbose',
action='store_true',
help='Display the command output at the end')
args = parser.parse_args()
main(args.update_type, args.file_path, args.nodes_file, args.verbose)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment