integ/bmc/redfishtool/files/v1.1.8/redfishtoollib/Systems.py

991 lines
49 KiB
Python

# Copyright Notice:
# Copyright 2016 DMTF. All rights reserved.
# License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/Redfishtool/blob/main/LICENSE.md
# redfishtool: Systems.py
#
# contains Systems related subCommands and access functions
#
# Class RfSystemsMain
# - functions init, displayUsage, displayHelp, displayOperations,
# - runOperation - Systems command table, dispatch of operation eg get, reset
# - SystemsMain - called from redfishMain, enforce legal option combinations,
# and call runOperation to run System operation (sub-sub-command)
#
# Class RfSystemsOperations
# All of the Systems sub-command operations eg: Systems reset, setIndicatorLed, etc
# - hello - test cmd
# - getCollection - return the Systems collection
# - get - get a member of a collection -or property of the member
# - list - show of list of collection members and key idetifying properties
# (Id, AssetTag, UriPath)
# - patch - raw subcommand to patch a System Member, with etag support
# - reset --reset a system instance
# - setAssetTag -- patches the assetTag of system instance w/ etag support
# - setIndicatorLed --sets id LED to a specified value w/ etag support
# - setBootOverride -set boot override enable, and target to valid values
# with proper checking for valid values...
# - getProcessors - get Processors collection, processor instance, or all
# - getInventory - get inventory of Processors, Memory, Fans, Power Supplies
# - getEnetInterfaces - get Ethernet collection, instance, all
# - getSimpleStorage - get SimpleStorage collection, instance, all
# - getLogService - get LogService collection, instance, all
# - clearLog -- clears a specified log (not implemented yet)
# - examples --prints some example apis
#
from .redfishtoolTransport import RfTransport
import requests
import json
import getopt
import re
import sys
from .ServiceRoot import RfServiceRoot
from urllib.parse import urljoin
class RfSystemsMain():
def __init__(self):
# operation string and remaining args
self.operation=None
self.args=None
self.argnum=0
self.nonIdCommands=None
def displayUsage(self,rft):
if(rft.quiet): return(0)
print(" Usage:")
print(" {} [OPTNS] Systems <operation> [<args>] -- perform <operation> on the system specified ".format(rft.program))
def displayHelp(self,rft):
self.displayUsage(rft)
self.displayOperations(rft)
print("")
def displayOperations(self,rft):
print(" <operations>:")
print(" [collection] -- get the main Systems collection. (Default operation if no member specified)")
print(" [get] -- get the computerSystem object. (Default operation if collection member specified)")
print(" list -- list information about the Systems collection members(\"Id\", URI, and AssetTag)")
print(" patch {A: B,C: D,...} -- patch the json-formatted {prop: value...} data to the object")
print(" reset <resetType> -- reset a system. <resetType>= On, GracefulShutdown, GracefulRestart, ")
print(" ForceRestart, ForceOff, ForceOn, Nmi, PushPowerButton, PowerCycle")
print(" setAssetTag <assetTag> -- set the system's asset tag ")
print(" setIndicatorLed <state> -- set the indicator LED. <state>=redfish defined values: Off, Lit, Blinking")
print(" setBootOverride <enabledVal> <targetVal> -- set Boot Override properties. <enabledVal>=Disabled|Once|Continuous")
print(" -- <targetVal> =None|Pxe|Floppy|Cd|Usb|Hdd|BiosSetup|Utilities|Diags|UefiTarget|")
print(" Processors [list] -- get the \"Processors\" collection, or list \"id\" and URI of members.")
print(" Processors [IDOPTN] -- get the member specified by IDOPTN: -i<id>, -m<prop>:<val>, -l<link>, -a #all")
print(" Inventory [list] -- get the \"Inventory\" collection, or list \"id\" and URI of members.")
print("")
print(" EthernetInterfaces [list] -- get the \"EthernetInterfaces\" collection, or list \"id\" and URI of members.")
print(" EthernetInterfaces [IDOPTN]-- get the member specified by IDOPTN: -i<id>, -m<prop>:<val>, -l<link>, -a #all")
print("")
print(" SimpleStorage [list] -- get the ComputerSystem \"SimpleStorage\" collection, or list \"id\" and URI of members.")
print(" SimpleStorage [IDOPTN] -- get the member specified by IDOPTN: -i<id>, -m<prop>:<val>, -l<link>, -a #all")
print("")
print(" Logs [list] -- get the ComputerSystem \"LogServices\" collection , or list \"id\" and URI of members.")
print(" Logs [IDOPTN] -- get the member specified by IDOPTN: -i<id>, -m<prop>:<val>, -l<link>, -a #all")
print(" clearLog <id> -- clears the log defined by <id>")
print(" examples -- example commands with syntax")
print(" hello -- Systems hello -- debug command")
return(0)
def runOperation(self,rft):
# instantiate SystemsOperations class
op=RfSystemsOperations()
# dispatch table for each subcommand: "cmdName": cmdClass.cmdFunction"
operationTable = {
"collection": op.getCollection,
"get": op.get,
"list": op.list,
"patch": op.patch,
"reset": op.reset,
"setAssetTag": op.setAssetTag,
"setIndicatorLed": op.setIndicatorLed,
"setBootOverride": op.setBootOverride,
"Processors": op.getProcessors,
"Inventory": op.getInventory,
"EthernetInterfaces": op.getEnetInterfaces,
"SimpleStorage": op.getSimpleStorage,
"Logs": op.getLogService,
"-clearLog": op.clearLog,
"hello": op.hello,
"examples": op.examples
}
rft.printVerbose(5,"Systems:runOperation: operation: {}".format(self.operation))
rft.printVerbose(5,"Systems:runOperation: args: {}".format(self.args))
if self.operation in operationTable:
rft.printVerbose(5,"Systems:runOperation: found Oper: {} in table. executing".format(rft.subcommand))
rc,r,j,d=operationTable[self.operation](self, op, rft, cmdTop=True)
return(rc,r,j,d)
else: # invalid operation
rft.printErr("Systems: Invalid operation: {}".format(self.operation))
return(2,None,False,None)
def SystemsMain(self,rft,cmdTop=False):
rft.printVerbose(4,"SystemsMain: subcommand: {}".format(rft.subcommand))
if( rft.help ):
self.displayHelp(rft)
return(0,None,False,None)
# we will validate usage of -P and -a in action processing
# actually, if a non 'get' action is specified, -P and -a are just ignored :)
args=rft.subcommandArgv[0:]
#if no args, then if no member Id was specified (with -I|-M|-1|-F) then assume it is a "collection" operation
# if a -IM1F was specified, then assume it is a "get" operation for that member
if( len(args) < 2 ):
if( rft.IdOptnCount==0 ):
self.operation="collection"
else:
self.operation="get"
self.args= None
else:
self.operation=args[1]
self.args = args[1:] # now args points to the 1st argument
self.argnum =len(self.args)
rft.printVerbose(5,"Systems: operation={}, args={}".format(self.operation,self.args))
# check if the command requires a collection member target -I|-M|-L|-1|-F eg sysIdoptn
nonIdCommands = ["collection", "list", "examples", "hello"]
if( ( not self.operation in nonIdCommands ) and (rft.IdOptnCount==0) ):
# default to --One if no Id option specified
rft.oneOptn = True
rft.IdOptnCount += 1
# now execute the operation.
rc,r,j,d = self.runOperation(rft)
if(rc !=0 ):
rft.printVerbose(5,"Systems: operation returned with error: rc={}".format(rc))
return(rc,r,False,None)
#else, if here, the subcommand executed without error. Return with 0 exit code
rft.printVerbose(5,"Systems: operation exited OK")
return(rc,r,j,d)
#
# contains operations related to the Systems subCommand
#
class RfSystemsOperations():
def __init__(self):
self.systemsPath=None
self.systemsCollectionDict=None
def hello(self,sc,op,rft,cmdTop=False):
rft.printVerbose(4,"in hello")
rft.printVerbose(4," subcmd:{}, operation:{}, args:{}".format(rft.subcommand,sc.operation,sc.args))
print("hello world from Systems")
return(0,None,False,None)
def getCollection(self,sc,op,rft,cmdTop=False, prop=None):
rft.printVerbose(4,"{}:{}: in getCollection".format(rft.subcommand,sc.operation))
# 1st get serviceRoot
svcRoot=RfServiceRoot()
rc,r,j,d = svcRoot.getServiceRoot(rft)
if( rc != 0 ):
rft.printErr("getCollection: Error getting service root, aborting")
return(rc,r,False,None)
# get the link to the Systems collection
# need to test we got good data
if (("Systems" in d) and ("@odata.id" in d["Systems"])):
systemsLink=d["Systems"]["@odata.id"]
else:
rft.printErr("Error: service root does not have a Systems link")
return(4)
rft.printVerbose(4,"Systems:getCollection: link is: {}".format(systemsLink))
# if a -a option was entered with "Systems" or "Systems collection" operation,
# then return all members of the Systems collection expanded
if((cmdTop is True) and (rft.allOptn is True) ):
collName="Systems"
rft.printVerbose(4,"Expand Systems collection to return ALL Systems collection members fully expanded in response")
rc,r,j,d=rft.getAllCollectionMembers(rft, r.url, relPath=systemsLink)
if(rc==0):
rft.printVerbose(1," Get ALL {} Collection Members".format(collName,skip1=True, printV12=cmdTop))
# otherwise, just return the collection
# now read the /Systems collection
# use the returned url as the base url to read the systems collection
else:
if cmdTop is True: prop=rft.prop
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', r.url, relPath=systemsLink, prop=prop)
if(rc==0):
rft.printVerbose(1," Systems Collection:",skip1=True, printV12=cmdTop)
return(rc,r,j,d)
def get(self,sc,op,rft, cmdTop=False, prop=None):
rft.printVerbose(4,"{}:{}: in operation".format(rft.subcommand,sc.operation))
# getCollection
rc,r,j,d=op.getCollection(sc,op, rft)
if( rc != 0): return(rc,r,False,None)
collUrl=r.url
# search collection to find path to system
sysPath,rc,r,j,d=rft.getPathBy(rft, r, d)
if( rc !=0 ): #if a path was not found, its an error
return(rc,r,j,d)
rft.printVerbose(4,"SystemsOperations:get: got a path, now get entries")
if cmdTop is True: prop=rft.prop
#if here, rc=0
#if sysPath returned a response but we need to extract the property do it here
if( (r is not None) and (prop is not None) ):
rc,r,j,d=rft.getPropFromDict(rft,r,d,prop)
# otherwise, we need to do a GET to get the system, if -P show property, else show full response
elif( r is None ):
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', collUrl, relPath=sysPath, prop=prop)
if(rc==0): rft.printVerbose(1," Systems Resource:",skip1=True, printV12=cmdTop)
return(rc,r,j,d)
def list(self,sc,op,rft, cmdTop=False, prop=None):
rft.printVerbose(4,"{}:{}: in operation".format(rft.subcommand,sc.operation))
# getCollection
collName="Systems"
rc,r,j,d=op.getCollection(sc,op, rft)
if( rc != 0): return(rc,r,False,None)
#loop through the members and create the list sub-operation response
rc,r,j,d=rft.listCollection(rft, r, d, prop="AssetTag")
if(rc==0):
rft.printVerbose(1," list {} Collection member info: Id, URI, AssetTag".format(collName,skip1=True, printV12=cmdTop))
return(rc,r,j,d)
def iterate_op(self, run_single, sc, op, rft, cmdTop=False, prop=None):
# Wrapper method to handle issuing commands to a single system or to all systems in the collection
if rft.allOptn:
# Issue command to all systems in collection
# get the list of systems
rc, r, j, d = op.list(sc, op, rft, cmdTop=cmdTop, prop=prop)
if rc != 0 or not j or d is None or not isinstance(d, dict) or 'Members' not in d:
rft.printErr("Unable to get list of Systems; return code = {}, list data = {}".format(rc, d))
return rc, r, j, d
# save existing rft options
saved_allOptn = rft.allOptn
saved_Link = rft.Link
saved_gotIdOptn = rft.gotIdOptn
saved_IdOptnCount = rft.IdOptnCount
# set rft options to process a single item
rft.allOptn = False
rft.gotIdOptn = True
rft.IdOptnCount = 1
# iterate through systems and run operation on each based on the link (@odata.id value)
members = d.get('Members')
rc, r, j, d = 8, None, False, None
for member in members:
if '@odata.id' in member:
link = member.get('@odata.id')
# set rft.Link to point to the target system
rft.Link = link
# perform the operation
rc, r, j, d = run_single(sc, op, rft, cmdTop=cmdTop, prop=prop)
else:
rft.printErr("No '@odata.id' found in system member: {}".format(member))
# restore existing rft options
rft.allOptn = saved_allOptn
rft.Link = saved_Link
rft.gotIdOptn = saved_gotIdOptn
rft.IdOptnCount = saved_IdOptnCount
return rc, r, j, d
else:
# Issue command to single specified system
return run_single(sc, op, rft, cmdTop=cmdTop, prop=prop)
def patch_single(self,sc,op,rft,cmdTop=False, prop=None, patchData=None, r=None):
rft.printVerbose(4,"{}:{}: in operation".format(rft.subcommand,sc.operation))
# verify we have got an argument which is the patch structure
# its in form '{ "AssetTag": <val>, "IndicatorLed": <val> }'
##print("patchData: {}".format(patchData))
if( len( sc.args) == 2):
##print("data:{}".format(sc.args[1]))
try:
patchData=json.loads(sc.args[1])
except ValueError:
rft.printErr("Patch: invalid Json input data:{}".format(sc.args[1]))
return(5,None,False,None)
##print("patchData: {}".format(patchData))
else:
rft.printErr("Patch: error: invalid argument format")
rft.printErr(" : args={}".format(sc.args))
rft.printErr(" : expect: Systems patch \"{ <prop>: <value> }\"")
return(4,None,False,None)
# read the system resource
# this is used by the generic rft.patchResource() function to see if there is an etag in the response
# if an etag is in response hdr, then we must include the etag on the patch, so this get is required
# note: the format of etag header for redfish is: ETag: W/"<string>" or "<string"
rc,r,j,d=op.get(sc,op,rft)
if( rc != 0):
return(rc,r,False,None)
# now call the generic patch function to send the patch
rc,r,j,d=rft.patchResource(rft, r, patchData)
if(rc==0): rft.printVerbose(1," Systems Patch:",skip1=True, printV12=cmdTop)
return(rc,r,j,d)
def patch(self, sc, op, rft, cmdTop=False, prop=None):
return op.iterate_op(op.patch_single, sc, op, rft, cmdTop=cmdTop, prop=prop)
def reset_single(self,sc,op,rft,cmdTop=False, prop=None):
# this operation has argument syntaxes below:
# ...reset <resetType>
# where <resetType> is a subset of Redfish defined redfish resetType values
# and will be validated against the allowable values read from the remote service
rft.printVerbose(4,"{}:{}: in operation".format(rft.subcommand,sc.operation))
# get the resetType from args
validResetTypes=["On","ForceOff","GracefulShutdown","ForceRestart","Nmi","GracefulRestart",
"ForceOn","PushPowerButton","PowerCycle"]
if(len(sc.args) < 2 ):
rft.printErr("Error, no resetType value specified")
return(8,None,False,None)
resetType=sc.args[1]
if not resetType in validResetTypes:
rft.printErr("Error, Invalid <resetType> value specified: {}".format(resetType))
return(8,None,False,None)
#now read remote service to find out if specified resetType is one of the allowable values for this rhost
rc,r,j,d=op.get(sc,op,rft,prop="Actions")
if(rc != 0):
print("Error, can't read Actions properties from remote service")
return(8,None,False,None)
if( (j is True) and ("Actions" in d) and ("#ComputerSystem.Reset" in d["Actions"])):
resetProps=d["Actions"]["#ComputerSystem.Reset"]
if( "ResetType@Redfish.AllowableValues" in resetProps ):
supportedResetTypes=resetProps["ResetType@Redfish.AllowableValues"]
if not resetType in supportedResetTypes:
rft.printErr("Error, the resetType specified is not supported by the remote service (via @Redfish.AllowableValues)")
return(8,None,False,None)
elif "@Redfish.ActionInfo" in resetProps:
action_info_path = resetProps["@Redfish.ActionInfo"]
supportedResetTypes = rft.getActionInfoAllowableValues(rft, r, action_info_path, "ResetType")
if supportedResetTypes is not None and resetType not in supportedResetTypes:
rft.printErr("Error, the resetType specified is not supported by the remote service (via @Redfish.ActionInfo)")
return(8,None,False,None)
else: # rhost didn't return any AllowableValues, but it isn't required, so allow the action
rft.printVerbose(2, "The remote service does not have a ResetType@Redfish.AllowableValues or @Redfish.ActionInfo prop")
else:
rft.printErr("Error, the remote service does not have an Actions: ComputerSystem.Reset property")
return(8,None,False,None)
# now get the target URI from the remote host
if( not "target" in resetProps ):
rft.printErr("Error, the remote service doesnt have a Reset Target property (the reset path)")
return(8,None,False,None)
resetPath=resetProps["target"]
resetData={"ResetType": resetType }
#since we already did a get, we have the path and can just execute the post directly.
#output the post data in json to send over the network
reqPostData=json.dumps(resetData)
# send post to rhost. Use the resetPath as the relative path
rft.printVerbose(1, 'Posting reset command to target {}'.format(resetPath))
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'POST', r.url, relPath=resetPath,
reqData=reqPostData)
if(rc==0):
rft.printVerbose(1," Systems reset: ", resetType, skip1=True, printV12=cmdTop)
resetd=None
return(rc,r,False,resetd)
else: return(rc,r,False,None)
def reset(self, sc, op, rft, cmdTop=False, prop=None):
return op.iterate_op(op.reset_single, sc, op, rft, cmdTop=cmdTop, prop=prop)
def setAssetTag_single(self,sc,op,rft,cmdTop=False, prop=None):
rft.printVerbose(4,"{}:{}: in operation".format(rft.subcommand,sc.operation))
propName="AssetTag"
# get the asset tag from args
if(len(sc.args) < 2 ):
rft.printErr("Error, no assetTag value specified")
rft.printErr("Syntax: {} [options] Systems setAssetTag \"string\" ".format(rft.program))
return(8,None,False,None)
assetTag=sc.args[1]
patchData={propName: assetTag}
# get the resource to verify it includes AssetTag,
# the response will also be used by Patch() to check for etag
rc,r,j,d=op.get(sc,op,rft)
if( rc != 0): return(rc,r,False,None)
if( not propName in d ):
rft.printErr("System resource does not have a {} property.".format(propName))
return(8,r,False,None)
rc,r,j,d=rft.patchResource(rft, r, patchData)
if(rc==0):
rft.printVerbose(1," Systems setAssetTag:",skip1=True, printV12=cmdTop)
assetTag={propName: d[propName]}
return(rc,r,j,assetTag)
else: return(rc,r,False,None)
def setAssetTag(self, sc, op, rft, cmdTop=False, prop=None):
return op.iterate_op(op.setAssetTag_single, sc, op, rft, cmdTop=cmdTop, prop=prop)
def setIndicatorLed_single(self,sc,op,rft,cmdTop=False, prop=None):
rft.printVerbose(4,"{}:{}: in operation".format(rft.subcommand,sc.operation))
propName="IndicatorLED"
# get the asset tag from args
validLedStates=["Lit","Blinking","Off"]
if(len(sc.args) < 2 ):
rft.printErr("Error, no ledState value specified")
rft.printErr("Syntax: {} [options] Systems setIndicatorLed <Lit|Off|Blinking>".format(rft.program))
return(8,None,False,None)
targLedState=sc.args[1]
if not targLedState in validLedStates:
rft.printErr("Error, invalid LED state specified")
return(8,None,False,None)
patchData={propName: targLedState}
# get the resource to verify it includes IndicatorLED,
# the response will also be used by Patch() to check for etag
rc,r,j,d=op.get(sc,op,rft)
if( rc != 0): return(rc,r,False,None)
if( not propName in d ):
rft.printErr("System resource does not have a {} property.".format(propName))
return(8,r,False,None)
#ststststst rc,r,j,d=op.patch(sc,op, rft, patchData=patchData, r=r)
rc,r,j,d=rft.patchResource(rft, r, patchData)
if(rc==0):
rft.printVerbose(1," Systems setIndicatorLed:",skip1=True, printV12=cmdTop)
ledState={"IndicatorLED": d["IndicatorLED"]}
return(rc,r,j,ledState)
else: return(rc,r,False,None)
def setIndicatorLed(self, sc, op, rft, cmdTop=False, prop=None):
return op.iterate_op(op.setIndicatorLed_single, sc, op, rft, cmdTop=cmdTop, prop=prop)
def setBootOverride_single(self,sc,op,rft,cmdTop=False, prop=None):
# this operation has argument syntaxes below:
# ...setBootOverride <enabledVal> [<targetVal>]
# where <targetVal> is not required if enabledVal==Disabled
# ...setBootOverride Once <targetVal>
# ...setBootOverride Continuous <targetVal>
# ...setBootOverride Disabled
# where TargetValue is subset of Redfish defined targets supported by rhost
rft.printVerbose(4,"{}:{}: in operation".format(rft.subcommand,sc.operation))
# get the next boot value from args
validTargetVals=("None","Pxe","Floppy","Cd","Usb","Hdd",
"BiosSetup","Utilities","Diags","UefiTarget")
validEnabledVals=("Once","Disabled","Continuous")
if(len(sc.args) < 2 ):
rft.printErr("Error, no bootSourceOverrideEnabled value specified")
rft.printErr("Syntax: {} [options] Systems setBootOverride <enableVal> [<targetVal>]".format(rft.program))
rft.printErr(" <enableVal>=Disabled|Once|Continuous, <targetVal>=None,Pxe,BiosSetup...")
return(8,None,False,None)
enabledVal=sc.args[1]
if not enabledVal in validEnabledVals:
rft.printErr("Error, Invalid <Enabled> value specified: {}".format(enabledVal))
rft.printErr("Syntax: {} [options] Systems setBootOverride <enableVal> [<targetVal>]".format(rft.program))
rft.printErr(" <enableVal>=Disabled|Once|Continuous, <targetVal>=None,Pxe,BiosSetup...")
return(8,None,False,None)
#now read target,
# we will need to check that the properties we are patching are there, and chk for etag hdr
# and to see if the value specified is one of the allowable values for this rhost
rc,r,j,d=op.get(sc,op,rft,prop="Boot")
if(rc != 0):
print("Error, can't read boot properties from remote service")
return(8,None,False,None)
# verify that they have a BootSourceOverrideEnabled prop
bootRes=d["Boot"]
if( not "BootSourceOverrideEnabled" in bootRes ):
rft.printErr("Error, the service does not have BootSourceOverrideEnabled property")
return(8,None,False,None)
if( enabledVal=="Disabled"):
#just patch rhost to set OverrideEnabled=Disabled
patchData={"Boot": {"BootSourceOverrideEnabled": enabledVal} }
rc,r,j,d=rft.patchResource(rft, r, patchData)
else: # we are enabling bootOverride and also need to set the target
if(len(sc.args) < 3):
rft.printErr("Error, no bootSourceOverrideTarget specified")
return(8,None,False,None)
targetVal=sc.args[2]
if not targetVal in validTargetVals:
rft.printErr("Error, invalid BootSourceOverrideTarget value specified: {}".format(targetVal))
rft.printErr("Syntax: {} [options] Systems setBootOverride <enableVal> [<targetVal>]".format(rft.program))
rft.printErr(" <enableVal>=Disabled|Once|Continuous, <targetVal>=None,Pxe,BiosSetup...")
return(8,None,False,None)
if( (j is True) and ("Boot" in d) ):
if "BootSourceOverrideTarget@Redfish.AllowableValues" in d["Boot"]:
rhostSupportedTargets=d["Boot"]["BootSourceOverrideTarget@Redfish.AllowableValues"]
if not targetVal in rhostSupportedTargets:
rft.printErr("Error, the boot target specified is not supported by the remote service (via @Redfish.AllowableValues)")
return(8,None,False,None)
elif "@Redfish.ActionInfo" in d["Boot"]:
action_info_path = d["Boot"]["@Redfish.ActionInfo"]
rhostSupportedTargets = rft.getActionInfoAllowableValues(rft, r, action_info_path, "BootSourceOverrideTarget")
if rhostSupportedTargets is not None and targetVal not in rhostSupportedTargets:
rft.printErr("Error, the boot target specified is not supported by the remote service (via @Redfish.ActionInfo)")
return (8, None, False, None)
else: # rhost didn't return any AllowableValues, but it isn't required, so allow the action
rft.printVerbose(2, "The remote service does not have a BootSourceOverrideTarget@Redfish.AllowableValues or @Redfish.ActionInfo prop")
else:
rft.printErr("Error, the remote service does not have a Boot prop")
return (8, None, False, None)
# verify that they have a BootSourceOverrideEnabled and BootSourceOverrideTarget prop
if( not "BootSourceOverrideTarget" in bootRes ):
rft.printErr("Error, the service does not have oneOf BootSourceOverride..Enabled or ..Target property")
return(8,None,False,None)
#form the patch data
# Get the value of "BootSourceOverrideTarget" property and pass it in the patch request.
# Some HW vendors need this property to be passed explicitly.
if "BootSourceOverrideMode" in d["Boot"]:
patchData={"Boot": {"BootSourceOverrideEnabled": enabledVal, "BootSourceOverrideTarget": targetVal, "BootSourceOverrideMode": d["Boot"]["BootSourceOverrideMode"] } }
else:
patchData={"Boot": {"BootSourceOverrideEnabled": enabledVal, "BootSourceOverrideTarget": targetVal } }
#call the generic patch command to send the patch. This takes care of etag support
rc,r,j,d=rft.patchResource(rft, r, patchData)
if(rc==0):
rft.printVerbose(1," Systems setBootOverride:",skip1=True, printV12=cmdTop)
bootd={"Boot": d["Boot"]}
return(rc,r,j,bootd)
else: return(rc,r,False,None)
def setBootOverride(self, sc, op, rft, cmdTop=False, prop=None):
return op.iterate_op(op.setBootOverride_single, sc, op, rft, cmdTop=cmdTop, prop=prop)
def getProcessors(self,sc,op, rft, cmdTop=False, prop=None):
rft.printVerbose(4,"{}:{}: in operation: getProcessorColl".format(rft.subcommand,sc.operation))
# get the system resource
rc,r,j,d=op.get(sc,op, rft)
if( rc != 0): return(rc,r,False,None)
collName="Processors"
# get the link to the Processors collection
if ((collName in d) and ("@odata.id" in d[collName])):
procsLink=d[collName]["@odata.id"]
else:
rft.printErr("Error: computer system resource does not have a {} link".format(collName))
return(6,None,False,None)
if cmdTop is True: prop=rft.prop
# check if there is a list arg for the operation
if( sc.argnum > 1 and sc.args[1] == 'list' ):
#get the collection
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', r.url, relPath=procsLink)
#loop through the members and create the list sub-operation response
rc,r,j,d=rft.listCollection(rft, r, d, prop="Socket")
if(rc==0):
rft.printVerbose(1," list {} Collection member info: Id, URI, Socket".format(collName,skip1=True, printV12=cmdTop))
# else: check if no proc was specified. If not, return the collection
elif(rft.IdLevel2OptnCount==0):
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', r.url, relPath=procsLink, prop=prop)
if(rc==0):
rft.printVerbose(1," {} Collection ".format(collName,skip1=True, printV12=cmdTop))
# else: check if the -a (all) option is set. If not, return the proc specific by -i or -m
# search collection to find path using getPath2
elif( rft.allOptn is not True ):
# get the processor collection
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', r.url, relPath=procsLink, prop=prop)
collUrl=r.url
# now search for 2nd level resource and return
path2,rc,r,j,d=rft.getLevel2ResourceById(rft,r,d)
if(rc!=0):
return(rc,r,j,d)
# so rc=0
#if sysPath returned a response but we need to extract the property do it here
if( (r is not None) and (prop is not None) ):
rc,r,j,d=rft.getPropFromDict(rft,r,d,prop)
# otherwise, we need to do a GET to get the processor, if -P show property, else show full response
elif( r is None ):
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', collUrl, relPath=path2, prop=prop)
if(rc==0):
rft.printVerbose(1," {} Collection Member ".format(collName,skip1=True, printV12=cmdTop))
# else, return ALL of the processor members
else:
rft.printVerbose(4,"getting expanded Processor Collection")
rc,r,j,d=rft.getAllCollectionMembers(rft, r.url, relPath=procsLink)
if(rc==0):
rft.printVerbose(1," Get ALL {} Collection Members".format(collName,skip1=True, printV12=cmdTop))
return(rc,r,j,d)
def getInventory(self,sc,op, rft, cmdTop=False, prop=None):
rft.printVerbose(4,"{}:{}: in operation: getInventory".format(rft.subcommand,sc.operation))
sys.stdout.write("%-20s %2s %-20s %2s %-10s\n" % ("Component","|","Present","|","Functional"))
# Get Processor and Memory Inventory
collection = ['Processors','Memory']
for collName in collection:
rc,r,j,d=op.get(sc,op, rft)
if( rc != 0): return(rc,r,False,None)
# get the link to the Processors collection
if ((collName in d) and ("@odata.id" in d[collName])):
Link=d[collName]["@odata.id"]
else:
rft.printErr("Error: computer system resource does not have a {} link".format(collName))
return(6,None,False,None)
if cmdTop is True: prop=rft.prop
rc,r,j,d=rft.getAllCollectionMembers(rft, r.url, relPath=Link)
if(rc==0):
rft.printVerbose(1," Get ALL {} Collection Members".format(collName,skip1=True, printV12=cmdTop))
# check if there is a list arg for the operation
if( sc.argnum > 1 and sc.args[1] == 'list' ):
output=json.dumps(d,indent=4)
print(output)
else:
numOfLinks=len(d["Members"])
for i in range (0,numOfLinks):
collName="Members"
sys.stdout.write("%-20s %2s %-20s %2s %-10s\n" % (d[collName][i]["Id"], "|", d[collName][i].get("Status", {}).get("State","N/A"), "|", d[collName][i].get("Status",{}).get("Health","N/A")))
# get the system resource
rc,r,j,d=op.get(sc,op, rft)
if( rc != 0): return(rc,r,False,None)
# get Fan inventory
jsonData=True
rc1,r1,j1,d1=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET',r.url, relPath=d["Links"]["Chassis"][0]["@odata.id"]+"/Thermal", prop=prop,jsonData=jsonData)
# check if there is a list arg for the operation
if( sc.argnum > 1 and sc.args[1] == 'list' ):
output=json.dumps(d1,indent=4)
print(output)
else:
numOfLinks=len(d1["Fans"])
for i in range (0,numOfLinks):
collName="Fans"
sys.stdout.write("%-20s %2s %-20s %2s %-10s\n" % (d1[collName][i]["Name"], "|", d1[collName][i].get("Status",{}).get("State","N/A"), "|", d1[collName][i].get("Status",{}).get("Health", "N/A")))
# get Power Supply inventory
rc1,r1,j1,d1=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET',r.url, relPath=d["Links"]["Chassis"][0]["@odata.id"]+"/Power", prop=prop,jsonData=jsonData)
# check if there is a list arg for the operation
if( sc.argnum > 1 and sc.args[1] == 'list' ):
output=json.dumps(d1,indent=4)
print(output)
else:
numOfLinks=len(d1["PowerSupplies"])
for i in range (0,numOfLinks):
collName="PowerSupplies"
sys.stdout.write("%-20s %2s %-20s %2s %-10s\n" % (d1[collName][i]["Name"], "|", d1[collName][i].get("Status",{}).get("State", "N/A"), "|", d1[collName][i].get("Status",{}).get("Health","N/A")))
return(0,None,False,None)
def getEnetInterfaces(self,sc,op,rft,cmdTop=False, prop=None):
rft.printVerbose(4,"{}:{}: in operation".format(rft.subcommand,sc.operation))
# get the system resource
rc,r,j,d=op.get(sc,op, rft)
if( rc != 0): return(rc,r,False,None)
collName="EthernetInterfaces"
# get the link to the EthernetInterfaces collection
if ((collName in d) and ("@odata.id" in d[collName])):
nicLink=d[collName]["@odata.id"]
else:
rft.printErr("Error: EthernetInterfaces resource does not have a {} link".format(collName))
return(6,None,False,None)
if cmdTop is True: prop=rft.prop
# check if there is a list arg for the operation
if( sc.argnum > 1 and sc.args[1] == 'list' ):
#get the collection
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', r.url, relPath=nicLink)
#loop through the members and create the list sub-operation response
rc,r,j,d=rft.listCollection(rft, r, d, prop="Name")
if(rc==0):
rft.printVerbose(1," list {} Collection member info: Id, URI, Name".format(collName,skip1=True, printV12=cmdTop))
# else: check if no NIC was specified. If not, return the collection
elif(rft.IdLevel2OptnCount==0):
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', r.url, relPath=nicLink, prop=prop)
if(rc==0):
rft.printVerbose(1," {} Collection ".format(collName,skip1=True, printV12=cmdTop))
# else: check if the -a (all) option is set. If not, return the proc specific by -i or -m
# search collection to find path using getPath2
elif( rft.allOptn is not True ):
# get the EthernetInterfaces collection
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', r.url, relPath=nicLink, prop=prop)
collUrl=r.url
# now search for 2nd level resource and return
path2,rc,r,j,d=rft.getLevel2ResourceById(rft,r,d)
if(rc!=0):
return(rc,r,j,d)
# so rc=0
#if sysPath returned a response but we need to extract the property do it here
if( (r is not None) and (prop is not None) ):
rc,r,j,d=rft.getPropFromDict(rft,r,d,prop)
# otherwise, we need to do a GET to get the EthernetInterfaces, if -P show property, else show full response
elif( r is None ):
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', collUrl, relPath=path2, prop=prop)
if(rc==0):
rft.printVerbose(1," {} Collection Member ".format(collName,skip1=True, printV12=cmdTop))
# else, return ALL of the EthernetInterfaces members
else:
rft.printVerbose(4,"getting expanded EthernetInterfaces Collection")
rc,r,j,d=rft.getAllCollectionMembers(rft, r.url, relPath=nicLink)
if(rc==0):
rft.printVerbose(1," Get ALL {} Collection Members".format(collName,skip1=True, printV12=cmdTop))
return(rc,r,j,d)
def getSimpleStorage(self,sc,op,rft,cmdTop=False, prop=None):
rft.printVerbose(4,"{}:{}: in operation".format(rft.subcommand,sc.operation))
# get the system resource
rc,r,j,d=op.get(sc,op, rft)
if( rc != 0): return(rc,r,False,None)
collName="SimpleStorage"
# get the link to the SimpleStorage collection
if ((collName in d) and ("@odata.id" in d[collName])):
cntlrLink=d[collName]["@odata.id"]
else:
rft.printErr("Error: computer system resource does not have a {} link".format(collName))
return(6,None,False,None)
if cmdTop is True: prop=rft.prop
# check if there is a list arg for the operation
if( sc.argnum > 1 and sc.args[1] == 'list' ):
#get the collection
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', r.url, relPath=cntlrLink)
#loop through the members and create the list sub-operation response
rc,r,j,d=rft.listCollection(rft, r, d, prop="Name" )
if(rc==0):
rft.printVerbose(1," list {} Collection member info: Id, URI, Name".format(collName,skip1=True, printV12=cmdTop))
# else: check if no SimpleStorage controller was specified. If not, return the collection
elif(rft.IdLevel2OptnCount==0):
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', r.url, relPath=cntlrLink, prop=prop)
if(rc==0):
rft.printVerbose(1," {} Collection ".format(collName,skip1=True, printV12=cmdTop))
# else: check if the -a (all) option is set. If not, return the proc specific by -i or -m
# search collection to find path using getPath2
elif( rft.allOptn is not True ):
# get the SimpleStorage collection
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', r.url, relPath=cntlrLink, prop=prop)
collUrl=r.url
# now search for 2nd level resource and return
path2,rc,r,j,d=rft.getLevel2ResourceById(rft,r,d)
if(rc!=0):
return(rc,r,j,d)
# so rc=0
#if sysPath returned a response but we need to extract the property do it here
if( (r is not None) and (prop is not None) ):
rc,r,j,d=rft.getPropFromDict(rft,r,d,prop)
# otherwise, we need to do a GET to get the SimpleStorage, if -P show property, else show full response
elif( r is None ):
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', collUrl, relPath=path2, prop=prop)
if(rc==0):
rft.printVerbose(1," {} Collection Member ".format(collName,skip1=True, printV12=cmdTop))
# else, return ALL of the SimpleStorage members
else:
rft.printVerbose(4,"getting expanded SimpleStorage Collection")
rc,r,j,d=rft.getAllCollectionMembers(rft, r.url, relPath=cntlrLink)
if(rc==0):
rft.printVerbose(1," Get ALL {} Collection Members".format(collName,skip1=True, printV12=cmdTop))
return(rc,r,j,d)
def getLogService(self,sc,op,rft,cmdTop=False, prop=None):
rft.printVerbose(4,":{}:{}: in operation".format(rft.subcommand,sc.operation))
# get the system resource
rc,r,j,d=op.get(sc,op, rft)
if( rc != 0): return(rc,r,False,None)
collName="LogServices"
# get the link to the LogServices collection
if ((collName in d) and ("@odata.id" in d[collName])):
logLink=d[collName]["@odata.id"]
else:
rft.printErr("Error: computer system resource does not have a {} link".format(collName))
return(6,None,False,None)
if cmdTop is True: prop=rft.prop
# check if there is a list arg for the operation
if( sc.argnum > 1 and sc.args[1] == 'list' ):
#get the collection
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', r.url, relPath=logLink)
#loop through the members and create the list sub-operation response
rc,r,j,d=rft.listCollection(rft, r, d, prop="Name")
if(rc==0):
rft.printVerbose(1," list {} Collection member info: Id, URI, Name".format(collName,skip1=True, printV12=cmdTop))
# else: check if no Log was specified. If not, return the collection
elif(rft.IdLevel2OptnCount==0):
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', r.url, relPath=logLink, prop=prop)
if(rc==0):
rft.printVerbose(1," {} Collection ".format(collName,skip1=True, printV12=cmdTop))
# else: check if the -a (all) option is set. If not, return the proc specific by -i or -m
# search collection to find path using getPath2
elif( rft.allOptn is not True ):
# get the LogServices collection
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', r.url, relPath=logLink, prop=prop)
collUrl=r.url
# now search for 2nd level resource and return
path2,rc,r,j,d=rft.getLevel2ResourceById(rft,r,d)
if(rc!=0):
return(rc,r,j,d)
# so rc=0
#if sysPath returned a response but we need to extract the property do it here
if( (r is not None) and (prop is not None) ):
rc,r,j,d=rft.getPropFromDict(rft,r,d,prop)
# otherwise, we need to do a GET to get the LogServices, if -P show property, else show full response
elif( r is None ):
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', collUrl, relPath=path2, prop=prop)
if(rc==0):
rft.printVerbose(1," {} Collection Member ".format(collName,skip1=True, printV12=cmdTop))
# If '--Entries' specified, get "Entries" nav link and read it
if rc == 0 and rft.gotEntriesOptn:
if r is not None and j and isinstance(d, dict):
rft.printVerbose(1, 'getLogService: attempting to get Entries for Logs')
entries = d.get('Entries')
if entries is not None and isinstance(entries, dict):
entries_uri = entries.get('@odata.id')
if entries_uri is not None:
rc, r, j, d = rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', r.url,
relPath=entries_uri, prop=prop)
else:
rft.printErr('getLogService: @odata.id not found in "Entries" property')
else:
rft.printErr('getLogService: "Entries" property not found in JSON payload')
else:
rft.printErr(
'Unable to fetch Entries property from previous response: response = {}, is_json = {}, type(json) = {}'
.format(r, j, type(d)))
# else, client specified the -a option requesting ALL of the LogServices members
# for logs, we will not support this. Its too much data.
else:
rft.printErr("Error: -a option not supported for LogServices")
return(6,None,False,None)
return(rc,r,j,d)
def clearLog(self,sc,op,rft,cmdTop=False, prop=None):
rft.printVerbose(4,"{}:{}: in operation".format(rft.subcommand,sc.operation))
return(8,None,False,None)
def examples(self,sc,op,rft,cmdTop=False,prop=None):
rft.printVerbose(4,"{}:{}: in operation".format(rft.subcommand,sc.operation))
print(" {} -r<ip> Systems # shows the systems collection".format(rft.program))
print(" {} -r<ip> Systems list # lists Id, Uri, AssetTag for all systems".format(rft.program))
print(" {} -r<ip> Systems -I <id> # gets the system with Id=<d>".format(rft.program))
print(" {} -r<ip> Systems -M AssetTag:12345 # gets the system with AssetTag=12345".format(rft.program))
print(" {} -r<ip> Systems -L <sysUrl> # gets the system at URI=<systemUrl".format(rft.program))
print(" {} -r<ip> Systems -F # get the First system returned (for debug)".format(rft.program))
print(" {} -r<ip> Systems -1 # get the first system and verify that there is only one system".format(rft.program))
print(" {} -r<ip> Systems -I <id> patch {{A: B,C: D,...}} # patch the json-formatted {{prop: value...}} data to the object".format(rft.program))
print(" {} -r<ip> Systems -I <id> reset <resetType> # reset a system. <resetType>=the redfish-defined values: On, Off, gracefulOff...".format(rft.program))
print(" {} -r<ip> Systems -I <id> setAssetTag <assetTag> # set the system's asset tag ".format(rft.program))
print(" {} -r<ip> Systems -I <id> setIndicatorLed <state> # set the indicator LED. <state>=redfish defined values: Off, Lit, Blinking".format(rft.program))
print(" {} -r<ip> Systems -I <id> setBootOverride <enabledVal> <targetVal> #-- set Boot Override properties. <enabledVal>=Disabled|Once|Continuous".format(rft.program))
print(" {} -r<ip> Systems -I<Id> Processors # get the processors Collection".format(rft.program))
print(" {} -r<ip> Systems -I<Id> Processors list # lists Id, Uri, and Socket for all processors in system with Id=<Id>".format(rft.program))
print(" {} -r<ip> Systems -I<Id> Processors -i 1 # get the processor with id=1 in system with Id=<Id>".format(rft.program))
print(" {} -r<ip> Systems -L <sysUrl> Processors -m Socket:CPU_1 # get processor with property Socket=CPU_1, on system at url <sysUrl>".format(rft.program))
return(0,None,False,None)
'''
TODO:
1. clearlog not implemented
2. handling segmented response to collections not tested (but code is there)
'''