New Function: Pretty Display Firmware

This update provides a new feature to display firmware nicely by using
the "firmware print" or "firmware list" commands. This will greatly
improve readability when retrieving firmware information from the BMC.

Signed-off-by: Justin Thaler thalerj@us.ibm.com
diff --git a/thalerj/openbmctool.py b/thalerj/openbmctool.py
index f21fd13..6f1550a 100644
--- a/thalerj/openbmctool.py
+++ b/thalerj/openbmctool.py
@@ -1919,9 +1919,119 @@
         
         d['imageID'] = newversionID
         return activateFWImage(host, args, session)
-    
-    
 
+def getFWInventoryAttributes(rawFWInvItem, ID):
+    """
+         gets and lists all of the firmware in the system. 
+           
+         @return: returns a dictionary containing the image attributes
+    """
+    reqActivation = rawFWInvItem["RequestedActivation"].split('.')[-1]
+    pendingActivation = ""
+    if reqActivation == "None":
+        pendingActivation = "No"
+    else:
+        pendingActivation = "Yes"
+    firmwareAttr = {ID: {
+        "Purpose": rawFWInvItem["Purpose"].split('.')[-1],
+        "Version": rawFWInvItem["Version"],
+        "RequestedActivation": pendingActivation,
+        "ID": ID}}
+        
+    if "ExtendedVersion" in rawFWInvItem:
+        firmwareAttr[ID]['ExtendedVersion'] = rawFWInvItem['ExtendedVersion'].split(',')
+    else: 
+        firmwareAttr[ID]['ExtendedVersion'] = ""
+    return firmwareAttr
+
+def parseFWdata(firmwareDict):
+    """
+         creates a dictionary with parsed firmware data 
+           
+         @return: returns a dictionary containing the image attributes
+    """
+    firmwareInfoDict = {"Functional": {}, "Activated":{}, "NeedsActivated":{}}
+    for key in firmwareDict['data']:
+        #check for valid endpoint
+        if "Purpose" in firmwareDict['data'][key]:
+            id = key.split('/')[-1]
+            if firmwareDict['data'][key]['Activation'].split('.')[-1] == "Active":
+                fwActivated = True
+            else:
+                fwActivated = False
+            if firmwareDict['data'][key]['Priority'] == 0:
+                firmwareInfoDict['Functional'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
+            elif firmwareDict['data'][key]['Priority'] >= 0 and fwActivated:
+                firmwareInfoDict['Activated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
+            else:
+                firmwareInfoDict['Activated'].update(getFWInventoryAttributes(firmwareDict['data'][key], id))
+    emptySections = []
+    for key in firmwareInfoDict:
+        if len(firmwareInfoDict[key])<=0:
+            emptySections.append(key)
+    for key in emptySections:
+        del firmwareInfoDict[key]
+    return firmwareInfoDict
+    
+def displayFWInvenory(firmwareInfoDict, args):
+    """
+         gets and lists all of the firmware in the system. 
+           
+         @return: returns a string containing all of the firmware information
+    """
+    output = ""
+    if not args.json:
+        for key in firmwareInfoDict:
+            for subkey in firmwareInfoDict[key]:
+                firmwareInfoDict[key][subkey]['ExtendedVersion'] = str(firmwareInfoDict[key][subkey]['ExtendedVersion'])
+        if not args.verbose:
+            output = "---Running Images---\n"               
+            colNames = ["Purpose", "Version", "ID"]
+            keylist = ["Purpose", "Version", "ID"]
+            output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
+            if "Activated" in firmwareInfoDict:
+                output += "\n---Available Images---\n" 
+                output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
+            if "NeedsActivated" in firmwareInfoDict:
+                output += "\n---Needs Activated Images---\n" 
+                output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
+             
+        else:
+            output = "---Running Images---\n"               
+            colNames = ["Purpose", "Version", "ID", "Pending Activation", "Extended Version"]
+            keylist = ["Purpose", "Version", "ID", "RequestedActivation", "ExtendedVersion"]
+            output += tableDisplay(keylist, colNames, firmwareInfoDict["Functional"])
+            if "Activated" in firmwareInfoDict:
+                output += "\n---Available Images---\n" 
+                output += tableDisplay(keylist, colNames, firmwareInfoDict["Activated"])
+            if "NeedsActivated" in firmwareInfoDict:
+                output += "\n---Needs Activated Images---\n" 
+                output += tableDisplay(keylist, colNames, firmwareInfoDict["NeedsActivated"])
+        return output
+    else:
+        return str(json.dumps(firmwareInfoDict, sort_keys=True, indent=4, separators=(',', ': '), ensure_ascii=False))
+
+def firmwareList(host, args, session):    
+    """
+         gets and lists all of the firmware in the system. 
+           
+         @return: returns a string containing all of the firmware information
+    """
+    httpHeader = {'Content-Type':'application/json'}
+    url="https://{hostname}/xyz/openbmc_project/software/enumerate".format(hostname=host)
+    try:
+        res = session.get(url, headers=httpHeader, verify=False, timeout=40)
+    except(requests.exceptions.Timeout):
+        return(connectionErrHandler(args.json, "Timeout", None))
+    firmwareDict = json.loads(res.text)
+    
+    #sort the received information
+    firmwareInfoDict = parseFWdata(firmwareDict)
+    
+    #display the information
+    return displayFWInvenory(firmwareInfoDict, args)
+    
+    
 def createCommandParser():
     """
          creates the parser for the command line along with help for each command and subcommand
@@ -2086,6 +2196,13 @@
     fwActivateStatus = fwflash_subproc.add_parser('activation_status', help="Check Status of activations")
     fwActivateStatus.set_defaults(func=activateStatus)
 
+    fwList = fwflash_subproc.add_parser('list', help="List all of the installed firmware")
+    fwList.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
+    fwList.set_defaults(func=firmwareList)
+    
+    fwprint = fwflash_subproc.add_parser('print', help="List all of the installed firmware")
+    fwprint.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
+    fwprint.set_defaults(func=firmwareList)
     
     return parser