#!/usr/bin/env python """ Usage: %(scriptName)s [options] command object options: -h | --help : this help message -d | --debug : run with debug mode -f | --force : ignore error during installation or clean command: install : install drivers and generate related sysfs nodes clean : uninstall drivers and remove related sysfs nodes switch-pddf : switch to pddf mode, installing pddf drivers and generating sysfs nodes switch-nonpddf : switch to per platform, non-pddf mode """ import logging import getopt import os import shutil import subprocess import sys from sonic_py_common import device_info import pddfparse PLATFORM_ROOT_PATH = '/usr/share/sonic/device' SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen' HWSKU_KEY = 'DEVICE_METADATA.localhost.hwsku' PLATFORM_KEY = 'DEVICE_METADATA.localhost.platform' PROJECT_NAME = 'PDDF' version = '1.1' verbose = False DEBUG = False args = [] ALL_DEVICE = {} FORCE = 0 kos = [] perm_kos = [] devs = [] # Instantiate the class pddf_obj try: pddf_obj = pddfparse.PddfParse() except Exception as e: print("%s" % str(e)) sys.exit() if DEBUG == True: print(sys.argv[0]) print('ARGV :', sys.argv[1:]) def main(): global DEBUG global args global FORCE global kos if len(sys.argv)<2: show_help() options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help', 'debug', 'force', ]) if DEBUG == True: print(options) print(args) print(len(sys.argv)) # generate the KOS list from pddf device JSON file if 'std_perm_kos' in pddf_obj.data['PLATFORM'].keys(): kos.extend(pddf_obj.data['PLATFORM']['std_perm_kos']) perm_kos.extend(pddf_obj.data['PLATFORM']['std_perm_kos']) kos.extend(pddf_obj.data['PLATFORM']['std_kos']) kos.extend(pddf_obj.data['PLATFORM']['pddf_kos']) kos = ['modprobe '+i for i in kos] if 'custom_kos' in pddf_obj.data['PLATFORM']: custom_kos = pddf_obj.data['PLATFORM']['custom_kos'] kos.extend(['modprobe -f '+i for i in custom_kos]) for opt, arg in options: if opt in ('-h', '--help'): show_help() elif opt in ('-d', '--debug'): DEBUG = True logging.basicConfig(level=logging.INFO) elif opt in ('-f', '--force'): FORCE = 1 else: logging.info('no option') for arg in args: if arg == 'install': do_install() elif arg == 'clean': do_uninstall() elif arg == 'switch-pddf': do_switch_pddf() elif arg == 'switch-nonpddf': do_switch_nonpddf() else: show_help() return 0 def show_help(): print(__doc__ % {'scriptName' : sys.argv[0].split("/")[-1]}) sys.exit(0) def my_log(txt): if DEBUG == True: print("[PDDF]"+txt) return def log_os_system(cmd, show): logging.info('Run :'+cmd) status, output = subprocess.getstatusoutput(cmd) my_log (cmd +"with result:" + str(status)) my_log (" output:"+output) if status: logging.info('Failed :'+cmd) if show: print('Failed :'+cmd) return status, output def driver_check(): ret, lsmod = log_os_system("lsmod| grep pddf", 0) if ret: return False logging.info('mods:'+lsmod) if len(lsmod) ==0: return False return True def get_path_to_device(): # Get platform and hwsku (platform, hwsku) = device_info.get_platform_and_hwsku() # Load platform module from source platform_path = "/".join([PLATFORM_ROOT_PATH, platform]) return platform_path def get_path_to_pddf_plugin(): pddf_path = "/".join([PLATFORM_ROOT_PATH, "pddf/plugins"]) return pddf_path def config_pddf_utils(): device_path = get_path_to_device() pddf_path = get_path_to_pddf_plugin() # ########################################################################## SONIC_PLATFORM_BSP_WHL_PKG = "/".join([device_path, 'sonic_platform-1.0-py3-none-any.whl']) SONIC_PLATFORM_PDDF_WHL_PKG = "/".join([device_path, 'pddf', 'sonic_platform-1.0-py3-none-any.whl']) SONIC_PLATFORM_BSP_WHL_PKG_BK = "/".join([device_path, 'sonic_platform-1.0-py3-none-any.whl.orig']) status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 1) if status: if os.path.exists(SONIC_PLATFORM_PDDF_WHL_PKG): # Platform API 2.0 is supported if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG): # bsp whl pkg is present but not installed on host if not os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_BK): log_os_system('mv '+SONIC_PLATFORM_BSP_WHL_PKG+' '+SONIC_PLATFORM_BSP_WHL_PKG_BK, 1) # PDDF whl package exist ... this must be the whl package created from # PDDF 2.0 ref API classes and some changes on top of it ... install it log_os_system('sync', 1) shutil.copy(SONIC_PLATFORM_PDDF_WHL_PKG, SONIC_PLATFORM_BSP_WHL_PKG) log_os_system('sync', 1) print("Attemting to install the PDDF sonic_platform wheel package ...") if os.path.getsize(SONIC_PLATFORM_BSP_WHL_PKG) != 0: status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG, 1) if status: print("Error: Failed to install {}".format(SONIC_PLATFORM_BSP_WHL_PKG)) return status else: print("Successfully installed {} package".format(SONIC_PLATFORM_BSP_WHL_PKG)) else: print("Error: Failed to copy {} properly. Exiting ...".format(SONIC_PLATFORM_PDDF_WHL_PKG)) return -1 else: # PDDF with platform APIs 1.5 must be supported device_plugin_path = "/".join([device_path, "plugins"]) backup_path = "/".join([device_plugin_path, "orig"]) print("Loading PDDF generic plugins (1.0)") if os.path.exists(backup_path) is False: os.mkdir(backup_path) log_os_system("mv "+device_plugin_path+"/*.*"+" "+backup_path, 0) for item in os.listdir(pddf_path): shutil.copy(pddf_path+"/"+item, device_plugin_path+"/"+item) shutil.copy('/usr/local/bin/pddfparse.py', device_plugin_path+"/pddfparse.py") else: # sonic_platform whl pkg is installed 2 possibilities, 1) bsp 2.0 classes # are installed, 2) system rebooted and either pddf/bsp 2.0 classes are already installed if os.path.exists(SONIC_PLATFORM_PDDF_WHL_PKG): if not os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_BK): # bsp 2.0 classes are installed. Take a backup and copy pddf 2.0 whl pkg log_os_system('mv '+SONIC_PLATFORM_BSP_WHL_PKG+' '+SONIC_PLATFORM_BSP_WHL_PKG_BK, 1) shutil.copy(SONIC_PLATFORM_PDDF_WHL_PKG, SONIC_PLATFORM_BSP_WHL_PKG) # uninstall the existing bsp whl pkg status, output = log_os_system("pip3 uninstall sonic-platform -y &> /dev/null", 1) if status: print("Error: Unable to uninstall BSP sonic-platform whl package") return status print("Attempting to install the PDDF sonic_platform wheel package ...") if os.path.getsize(SONIC_PLATFORM_BSP_WHL_PKG) != 0: status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG, 1) if status: print("Error: Failed to install {}".format(SONIC_PLATFORM_BSP_WHL_PKG)) return status else: print("Successfully installed {} package".format(SONIC_PLATFORM_BSP_WHL_PKG)) else: print("Error: Failed to copy {} properly. Exiting ...".format(SONIC_PLATFORM_PDDF_WHL_PKG)) return -1 else: # system rebooted in pddf mode print("System rebooted in PDDF mode, hence keeping the PDDF 2.0 classes") else: # pddf whl package doesnt exist print("Error: PDDF 2.0 classes doesnt exist. PDDF mode can not be enabled") sys.exit(1) # ########################################################################## # Take a backup of orig fancontrol if os.path.exists(device_path+"/fancontrol"): log_os_system("mv "+device_path+"/fancontrol"+" "+device_path+"/fancontrol.bak", 0) # Create a link to fancontrol of PDDF if os.path.exists(device_path+"/pddf/fancontrol") and not os.path.exists(device_path+"/fancontrol"): shutil.copy(device_path+"/pddf/fancontrol",device_path+"/fancontrol") # BMC support f_sensors="/usr/bin/sensors" f_sensors_org="/usr/bin/sensors.org" f_pddf_sensors="/usr/local/bin/pddf_sensors" if os.path.exists(f_pddf_sensors) is True: if os.path.exists(f_sensors_org) is False: shutil.copy(f_sensors, f_sensors_org) shutil.copy(f_pddf_sensors, f_sensors) return 0 def cleanup_pddf_utils(): device_path = get_path_to_device() SONIC_PLATFORM_BSP_WHL_PKG = "/".join([device_path, 'sonic_platform-1.0-py3-none-any.whl']) SONIC_PLATFORM_PDDF_WHL_PKG = "/".join([device_path, 'pddf', 'sonic_platform-1.0-py3-none-any.whl']) SONIC_PLATFORM_BSP_WHL_PKG_BK = "/".join([device_path, 'sonic_platform-1.0-py3-none-any.whl.orig']) # ########################################################################## status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 1) if status: # PDDF Platform API 2.0 is not supported but system is in PDDF mode, hence PDDF 1.0 plugins are present device_plugin_path = "/".join([device_path, "plugins"]) backup_path = "/".join([device_plugin_path, "orig"]) if os.path.exists(backup_path) is True: for item in os.listdir(device_plugin_path): if os.path.isdir(device_plugin_path+"/"+item) is False: os.remove(device_plugin_path+"/"+item) log_os_system("mv "+backup_path+"/*"+" "+device_plugin_path, 1) os.rmdir(backup_path) else: print("\nERR: Unable to locate original device files...\n") else: # PDDF 2.0 apis are supported and PDDF whl package is installed if os.path.exists(SONIC_PLATFORM_PDDF_WHL_PKG): if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_BK): # platform is 2.0 compliant and original bsp 2.0 whl package exist log_os_system('mv '+SONIC_PLATFORM_BSP_WHL_PKG_BK+' '+SONIC_PLATFORM_BSP_WHL_PKG, 1) status, output = log_os_system("pip3 uninstall sonic-platform -y &> /dev/null", 1) if status: print("Error: Unable to uninstall PDDF sonic-platform whl package") return status print("Attemting to install the BSP sonic_platform wheel package ...") status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG, 1) if status: print("Error: Failed to install {}".format(SONIC_PLATFORM_BSP_WHL_PKG)) return status else: print("Successfully installed {} package".format(SONIC_PLATFORM_BSP_WHL_PKG)) else: # platform doesnt support 2.0 APIs but PDDF is 2.0 based # remove and uninstall the PDDF whl package if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG): os.remove(SONIC_PLATFORM_BSP_WHL_PKG) status, output = log_os_system("pip3 uninstall sonic-platform -y &> /dev/null", 1) if status: print("Error: Unable to uninstall PDDF sonic-platform whl package") return status else: # something seriously wrong. System is in PDDF mode but pddf whl pkg is not present print("Error: Fatal error as the system is in PDDF mode but the pddf .whl original is not present") # ################################################################################################################ if os.path.exists(device_path+"/fancontrol"): os.remove(device_path+"/fancontrol") if os.path.exists(device_path+"/fancontrol.bak"): log_os_system("mv "+device_path+"/fancontrol.bak"+" "+device_path+"/fancontrol", 0) # BMC support f_sensors="/usr/bin/sensors" f_sensors_org="/usr/bin/sensors.org" if os.path.exists(f_sensors_org) is True: shutil.copy(f_sensors_org, f_sensors) return 0 def create_pddf_log_files(): if not os.path.exists('/var/log/pddf'): log_os_system("sudo mkdir /var/log/pddf", 1) log_os_system("sudo touch /var/log/pddf/led.txt", 1) log_os_system("sudo touch /var/log/pddf/psu.txt", 1) log_os_system("sudo touch /var/log/pddf/fan.txt", 1) log_os_system("sudo touch /var/log/pddf/xcvr.txt", 1) log_os_system("sudo touch /var/log/pddf/sysstatus.txt", 1) log_os_system("sudo touch /var/log/pddf/cpld.txt", 1) log_os_system("sudo touch /var/log/pddf/cpldmux.txt", 1) log_os_system("sudo touch /var/log/pddf/client.txt", 1) log_os_system("sudo touch /var/log/pddf/mux.txt", 1) def driver_install(): global FORCE # check for pre_driver_install script if os.path.exists('/usr/local/bin/pddf_pre_driver_install.sh'): status, output = log_os_system('/usr/local/bin/pddf_pre_driver_install.sh', 1) if status: print("Error: pddf_pre_driver_install script failed with error %d"%status) return status # For debug print(output) # Removes the perm_kos first, then reload them in a proper sequence for mod in perm_kos: cmd = "modprobe -rq " + mod status, output = log_os_system(cmd, 1) if status: print("driver_install: Unable to unload {}".format(mod)) # Don't exit but continue log_os_system("depmod", 1) for i in range(0,len(kos)): status, output = log_os_system(kos[i], 1) if status: print("driver_install() failed with error %d"%status) if FORCE == 0: return status output = config_pddf_utils() if output: print("config_pddf_utils() failed with error %d"%output) # check for post_driver_install script if os.path.exists('/usr/local/bin/pddf_post_driver_install.sh'): status, output = log_os_system('/usr/local/bin/pddf_post_driver_install.sh', 1) if status: print("Error: pddf_post_driver_install script failed with error %d"%status) return status # Useful for debugging print(output) return 0 def driver_uninstall(): global FORCE status = cleanup_pddf_utils() if status: print("cleanup_pddf_utils() failed with error %d"%status) for i in range(0,len(kos)): # if it is in perm_kos, do not remove if (kos[-(i+1)].split())[-1] in perm_kos or 'i2c-i801' in kos[-(i+1)]: continue rm = kos[-(i+1)].replace("modprobe", "modprobe -rq") rm = rm.replace("insmod", "rmmod") status, output = log_os_system(rm, 1) if status: print("driver_uninstall() failed with error %d"%status) if FORCE == 0: return status return 0 def device_install(): global FORCE # check for pre_device_creation script if os.path.exists('/usr/local/bin/pddf_pre_device_create.sh'): status, output = log_os_system('/usr/local/bin/pddf_pre_device_create.sh', 1) if status: print("Error: pddf_pre_device_create script failed with error %d"%status) return status # trigger the pddf_obj script for FAN, PSU, CPLD, MUX, etc status = pddf_obj.create_pddf_devices() if status: print("Error: create_pddf_devices() failed with error %d"%status) if FORCE == 0: return status # check for post_device_create script if os.path.exists('/usr/local/bin/pddf_post_device_create.sh'): status, output = log_os_system('/usr/local/bin/pddf_post_device_create.sh', 1) if status: print("Error: pddf_post_device_create script failed with error %d"%status) return status # Useful for debugging print(output) return def device_uninstall(): global FORCE # Trigger the paloparse script for deletion of FAN, PSU, OPTICS, CPLD clients status = pddf_obj.delete_pddf_devices() if status: print("Error: delete_pddf_devices() failed with error %d"%status) if FORCE == 0: return status return def do_install(): print("Checking system....") if not os.path.exists('/usr/share/sonic/platform/pddf_support'): print(PROJECT_NAME.upper() +" mode is not enabled") return if driver_check()== False : print(PROJECT_NAME.upper() +" has no PDDF driver installed....") create_pddf_log_files() print("Installing ...") status = driver_install() if status: return status else: print(PROJECT_NAME.upper() +" drivers detected....") print("Creating devices ...") status = device_install() if status: return status return def do_uninstall(): print("Checking system....") if not os.path.exists('/usr/share/sonic/platform/pddf_support'): print(PROJECT_NAME.upper() +" mode is not enabled") return if os.path.exists('/var/log/pddf'): print("Remove pddf log files.....") log_os_system("sudo rm -rf /var/log/pddf", 1) print("Remove all the devices...") status = device_uninstall() if status: return status if driver_check()== False : print(PROJECT_NAME.upper() +" has no PDDF driver installed....") else: print("Removing installed driver....") status = driver_uninstall() if status: if FORCE == 0: return status return def do_switch_pddf(): try: import pddf_switch_svc except ImportError: print("Unable to find pddf_switch_svc.py. PDDF might not be supported on this platform") sys.exit() print("Check the pddf support...") status = pddf_switch_svc.check_pddf_support() if not status: print("PDDF is not supported on this platform") return status print("Checking system....") if os.path.exists('/usr/share/sonic/platform/pddf_support'): print(PROJECT_NAME.upper() +" system is already in pddf mode....") else: print("Check if the native sonic-platform whl package is installed in the pmon docker") status, output = log_os_system("docker exec -it pmon pip3 show sonic-platform", 1) if not status: # Need to remove this whl module status, output = log_os_system("docker exec -it pmon pip3 uninstall sonic-platform -y", 1) if not status: print("Successfully uninstalled the native sonic-platform whl pkg from pmon container") else: print("Error: Unable to uninstall the sonic-platform whl pkg from pmon container." " Do it manually before moving to nonpddf mode") return status print("Stopping the pmon service ...") status, output = log_os_system("systemctl stop pmon.service", 1) if status: print("Pmon stop failed") if FORCE==0: return status print("Stopping the platform services..") status = pddf_switch_svc.stop_platform_svc() if not status: if FORCE==0: return status print("Creating the pddf_support file...") if os.path.exists('/usr/share/sonic/platform'): log_os_system("touch /usr/share/sonic/platform/pddf_support", 1) else: print("/usr/share/sonic/platform path doesn't exist. Unable to set pddf mode") return -1 print("Starting the PDDF platform service...") status = pddf_switch_svc.start_platform_pddf() if not status: if FORCE==0: return status print("Restart the pmon service ...") status, output = log_os_system("systemctl start pmon.service", 1) if status: print("Pmon restart failed") if FORCE==0: return status return def do_switch_nonpddf(): try: import pddf_switch_svc except ImportError: print("Unable to find pddf_switch_svc.py. PDDF might not be supported on this platform") sys.exit() print("Checking system....") if not os.path.exists('/usr/share/sonic/platform/pddf_support'): print(PROJECT_NAME.upper() +" system is already in non-pddf mode....") else: print("Check if the sonic-platform whl package is installed in the pmon docker") status, output = log_os_system("docker exec -it pmon pip3 show sonic-platform", 1) if not status: # Need to remove this whl module status, output = log_os_system("docker exec -it pmon pip3 uninstall sonic-platform -y", 1) if not status: print("Successfully uninstalled the sonic-platform whl pkg from pmon container") else: print("Error: Unable to uninstall the sonic-platform whl pkg from pmon container." " Do it manually before moving to nonpddf mode") return status print("Stopping the pmon service ...") status, output = log_os_system("systemctl stop pmon.service", 1) if status: print("Stopping pmon service failed") if FORCE==0: return status print("Stopping the PDDF platform service...") status = pddf_switch_svc.stop_platform_pddf() if not status: if FORCE==0: return status print("Removing the pddf_support file...") if os.path.exists('/usr/share/sonic/platform'): log_os_system("rm -f /usr/share/sonic/platform/pddf_support", 1) else: print("/usr/share/sonic/platform path doesnt exist. Unable to set non-pddf mode") return -1 print("Starting the platform services...") status = pddf_switch_svc.start_platform_svc() if not status: if FORCE==0: return status print("Restart the pmon service ...") status, output = log_os_system("systemctl start pmon.service", 1) if status: print("Restarting pmon service failed") if FORCE==0: return status return if __name__ == "__main__": main()