e8418fd2da
Why I did it Requirements from Microsoft for fwutil update all state that all firmwares which support this upgrade flow must support upgrade within a single boot cycle. This conflicted with a number of Mellanox upgrade flows which have been revised to safely meet this requirement. How I did it Added --no-power-cycle flags to SSD and ONIE firmware scripts Modified Platform API to call firmware upgrade flows with this new flag during fwutil update all Added a script to our reboot plugin to handle installing firmwares in the correct order with prior to reboot How to verify it Populate platform_components.json with firmware for CPLD / BIOS / ONIE / SSD Execute fwutil update all fw --boot cold CPLD will burn / ONIE and BIOS images will stage / SSD will schedule for reboot Reboot the switch SSD will install / CPLD will refresh / switch will power cycle into ONIE ONIE installer will upgrade ONIE and BIOS / switch will reboot back into SONiC In SONiC run fwutil show status to check that all firmware upgrades were successful
100 lines
3.4 KiB
Python
Executable File
100 lines
3.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
#
|
|
# Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES.
|
|
# Apache-2.0
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#
|
|
|
|
import os
|
|
|
|
from fwutil.lib import ComponentStatusProvider, PlatformComponentsParser
|
|
from sonic_platform.component import ComponentCPLD, MPFAManager
|
|
|
|
# Globals
|
|
FW_STATUS_SCHEDULED = "scheduled"
|
|
CPLD_FLAG = False
|
|
|
|
# Init platform chassis helper classes
|
|
csp = ComponentStatusProvider()
|
|
pcp = PlatformComponentsParser(csp.is_modular_chassis())
|
|
|
|
# Parse update status file
|
|
update_status = csp.read_au_status_file_if_exists()
|
|
|
|
if update_status is None:
|
|
exit(0)
|
|
|
|
# Parse platform components file
|
|
try:
|
|
pcp.parse_platform_components()
|
|
except Exception as e:
|
|
print("Error parsing platform components. Firmware update failed: {}".format(str(e)))
|
|
print("System will reboot in 10 seconds please fix issue and run update command again.")
|
|
time.sleep(10)
|
|
exit(-1)
|
|
|
|
# Iterate each component in the status file
|
|
comp_install = []
|
|
files = []
|
|
|
|
for boot_type, components in update_status.items():
|
|
for comp in components:
|
|
|
|
# Skip if fw isn't scheduled for install at reboot
|
|
if comp["info"] != FW_STATUS_SCHEDULED: continue
|
|
|
|
# Get component object and target firmware file
|
|
key = comp["comp"]
|
|
comp_path = key.split("/")
|
|
|
|
if len(comp_path) == 3:
|
|
# Module component
|
|
_, parent_name, comp_name = comp_path
|
|
fw_file = pcp.module_component_map[parent_name][comp_name]["firmware"]
|
|
component = csp.module_component_map[parent_name][comp_name]
|
|
else:
|
|
# Chassis component
|
|
parent_name, comp_name = comp_path
|
|
fw_file = pcp.chassis_component_map[parent_name][comp_name]["firmware"]
|
|
component = csp.chassis_component_map[parent_name][comp_name]
|
|
|
|
# Install firmware. If CPLD flag to be installed last due to force reboot during refresh
|
|
if type(component) == ComponentCPLD:
|
|
if CPLD_FLAG:
|
|
# Only need one refresh
|
|
continue
|
|
mpfa = MPFAManager(fw_file)
|
|
mpfa.extract()
|
|
if not mpfa.get_metadata().has_option('firmware', 'refresh'):
|
|
print("Failed to get CPLD refresh firmware. Skipping.")
|
|
continue
|
|
CPLD_FLAG = True
|
|
refresh_firmware = mpfa.get_metadata().get('firmware', 'refresh')
|
|
comp_install = comp_install + [component]
|
|
files = files + [os.path.join(mpfa.get_path(), refresh_firmware)]
|
|
else:
|
|
comp_install = [component] + comp_install
|
|
files = [fw_file] + files
|
|
|
|
# Do install
|
|
for i, c in enumerate(comp_install):
|
|
try:
|
|
if type(c) == ComponentCPLD:
|
|
c.install_firmware(files[i])
|
|
else:
|
|
c.install_firmware(files[i], allow_reboot=False)
|
|
except Exception as e:
|
|
print("Firmware install for {} FAILED with: {}".format(c.get_name(),e))
|
|
|