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

393 lines
16 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: rawMain.py
#
# contains raw subCommands and access functions
#
# Class RfRawMain
# - functions init, displayUsage, displayHelp, displayOperations,
# - runOperation - raw subcommand table, dispatch of operations: get, patch, post..
# - RfRawMain - called from redfishMain, enforce legal option combinations,
# and call runOperation to run System operation (sub-sub-command)
#
# Class RfRawOperations
# All of the Systems sub-command operations eg: Systems reset, setIndicatorLed, etc
# - hello - test cmd
# - httpGet -- send GET method
# - httpPatch -- send GET method
# - httpPost -- send GET method
# - httpDelete -- send GET method
# - httpHead -- send GET method
# - httpPut -- send GET method (not implemented in 0.9)
# - 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, urlparse, urlunparse
class RfRawMain():
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] raw <method> <path> ".format(rft.program))
print("")
print(" {} raw -h # for help".format(rft.program))
print(" {} raw examples #for example commands".format(rft.program))
print("")
print(" <method> is one of: GET, PATCH, POST, DELETE, HEAD, PUT")
print(" <path> is full URI path to a redfish resource--the full path following <ipaddr:port>, starting with forward slash /")
print("")
print(" Common OPTNS:")
print(" -u <user>, --user=<usernm> -- username used for remote redfish authentication")
print(" -p <passwd>, --password=<passwd> -- password used for remote redfish authentication")
print(" -t <token>, --token=<token> - redfish auth session token-for sessions across multiple calls")
print("")
print(" -r <rhost>, --rhost=<rhost> -- remote redfish service hostname or IP:port")
print(" -X <method> --request=<method> -- the http method to use. <method>={GET,PATCH,POST,DELETE,HEAD,PUT}. Default=GET")
print(" -d <data> --data=<data> -- the http request \"data\" to send on PATCH,POST,or PUT requests")
print(" -H <hdrs>, --Headers=<hdrs> -- Specify the request header list--overrides defaults. Format \"{ A:B, C:D...}\" ")
print(" -S <Secure>, --Secure=<Secure> -- When to use https: (Note: doesn't stop rhost from redirect http to https)")
def displayHelp(self,rft):
self.displayUsage(rft)
self.displayOperations(rft)
print("")
def displayOperations(self,rft):
print(" <operations / methods>:")
print(" GET -- HTTP GET method")
print(" PATCH -- HTTP PATCH method")
print(" POST -- HTTP POST method")
print(" DELETE -- HTTP DELETE method")
print(" HEAD -- HTTP HEAD method")
print(" PUT -- HTTP PUT method")
print(" examples -- example raw commands with syntax")
print(" hello -- raw hello -- debug command")
return(0)
def runOperation(self,rft):
# instantiate SystemsOperations class
op=RfRawOperations()
# dispatch table for each subcommand: "cmdName": cmdClass.cmdFunction"
operationTable = {
"GET": op.httpGet,
"PATCH": op.httpPatch,
"POST": op.httpPost,
"DELETE": op.httpDelete,
"HEAD": op.httpHead,
"PUT": op.httpPut,
"hello": op.hello,
"examples": op.examples
}
rft.printVerbose(5,"raw: runOperation: operation: {}".format(self.operation))
rft.printVerbose(5,"raw:runOperation: args: {}".format(self.args))
if self.operation in operationTable:
rft.printVerbose(5,"raw: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("raw: Invalid operation: {}".format(self.operation))
return(2,None,False,None)
def RawMain(self,rft,cmdTop=False):
rft.printVerbose(4,"RawMain: subcommand: {}".format(rft.subcommand))
if( rft.help ):
self.displayHelp(rft)
return(2,None,False,None)
args=rft.subcommandArgv[0:]
# if 2 args, only operations are: hello and examples
nonMethodOperations=("hello","examples")
if( len(args)==2):
nonMethodOp=args[1]
if( not nonMethodOp in nonMethodOperations):
rft.printErr("Syntax error: \"raw\" subcommands require 2 arguments\n")
rft.printErr("")
self.displayHelp(rft)
return(2,None,False,None)
# else all operations require two args <method> <path>
elif( len(args) < 3 ):
rft.printErr("Syntax error: \"raw\" subcommands require 2 arguments\n")
self.displayHelp(rft)
return(2,None,False,None)
self.operation=args[1] # for raw subcommand, this is the http method (eg GET)
self.args = args[1:] # now args points to the 1st argument
self.argnum =len(self.args)
rft.printVerbose(5,"raw: operation={}, args={}".format(self.operation,self.args))
# now execute the operation.
rc,r,j,d = self.runOperation(rft)
if(rc !=0 ):
rft.printVerbose(5,"raw: 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,"raw: operation exited OK")
return(rc,r,j,d)
#
# contains operations related to the Systems subCommand
#
class RfRawOperations():
def __init__(self):
self.systemsPath=None
self.systemsCollectionDict=None
# function to return API type: authenticated or unauthenticated
# authenticated APIs require authentication
# unauthenticated APIs are /redfish, /redfish/v1, /redfish/v1/odata, /redfish/v1/$metadata
def getApiType(self,rft,uri):
unauthenticatedAPIs=("/redfish", "/redfish/v1", "/redfish/v1/", "/redfish/v1/odata", "/redfish/v1/$metadata")
if not uri in unauthenticatedAPIs:
return( rft.AUTHENTICATED_API )
else:
return( rft.UNAUTHENTICATED_API )
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 raw subcommand")
return(0,None,False,None)
def httpGet(self,sc,op,rft,cmdTop=False, prop=None):
rft.printVerbose(4,"{}:{}: in raw".format(rft.subcommand,sc.operation))
# we verified that we had two args in RawMain(), so we can just read the <uri> arg here
path=sc.args[1]
method="GET"
rft.printVerbose(4,"raw: GET: method:{} path:{}".format(method,path))
apiType=self.getApiType(rft,path) # UNAUTHENTICATED API or Authenticated API
# calculate rootUrl--with correct scheme, root path, and rhost IP (w/o querying rhost)
scheme=rft.getApiScheme(apiType)
scheme_tuple=[scheme, rft.rhost, "/redfish", "","",""]
rootUrl=urlunparse(scheme_tuple) # so rootUrl="http[s]://<rhost>[:<port>]/redfish"
if cmdTop is True: prop=rft.prop
jsonData=True
if (path=="/redfish/v1/$metadata"): jsonData=False
rc,r,j,d=rft.rftSendRecvRequest(apiType, method, rootUrl, relPath=path, prop=prop,jsonData=jsonData)
if(rc==0):
rft.printVerbose(1," raw GET:",skip1=True, printV12=cmdTop)
return(rc,r,j,d)
else:
rft.printErr("raw: Error getting response")
return(rc,r,False,None)
def httpHead(self,sc,op,rft,cmdTop=False, prop=None):
rft.printVerbose(4,"{}:{}: in raw".format(rft.subcommand,sc.operation))
# we verified that we had two args in RawMain(), so we can just read the <uri> arg here
path=sc.args[1]
method="HEAD"
rft.printVerbose(4,"raw: HEAD: method:{} path:{}".format(method,path))
apiType=self.getApiType(rft,path) # UNAUTHENTICATED API or Authenticated API
# calculate rootUrl--with correct scheme, root path, and rhost IP (w/o querying rhost)
scheme=rft.getApiScheme(apiType)
scheme_tuple=[scheme, rft.rhost, "/redfish", "","",""]
rootUrl=urlunparse(scheme_tuple) # so rootUrl="http[s]://<rhost>[:<port>]/redfish"
rc,r,j,d=rft.rftSendRecvRequest(apiType, method, rootUrl, relPath=path)
if(rc==0):
rft.printVerbose(1," raw HEAD:",skip1=True, printV12=cmdTop)
return(rc,r,False,None)
else:
rft.printErr("raw: Error getting response")
return(rc,r,False,None)
def httpPatch(self,sc,op,rft,cmdTop=False, prop=None):
rft.printVerbose(4,"{}:{}: in raw".format(rft.subcommand,sc.operation))
# load patch data--verify its good json
# get the patchData from rft.requestData readin on commandline via: -d <patchData>
try:
patchData=json.loads(rft.requestData)
except ValueError:
rft.printErr("Patch: invalid Json input data:{}".format(rft.requestData))
return(5,None,False,None)
##print("patchData: {}".format(patchData))
# we verified that we had two args in RawMain(), so we can just read the <uri> arg here
path=sc.args[1]
method="PATCH"
rft.printVerbose(4,"raw: PATCH: method:{} path:{}".format(method,path))
apiType=self.getApiType(rft,path) # UNAUTHENTICATED API or Authenticated API
# calculate rootUrl--with correct scheme, root path, and rhost IP (w/o querying rhost)
scheme=rft.getApiScheme(apiType)
scheme_tuple=[scheme, rft.rhost, "/redfish", "","",""]
rootUrl=urlunparse(scheme_tuple) # so rootUrl="http[s]://<rhost>[:<port>]/redfish"
#read the resource--the generic patch command needs it to get the etag
rc,r,j,d=rft.rftSendRecvRequest(apiType, "GET", rootUrl, relPath=path)
if(rc!=0):
rft.printErr("raw: Error getting resource prior to patching it, aborting")
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 httpPost(self,sc,op,rft,cmdTop=False, prop=None):
rft.printVerbose(4,"{}:{}: in raw".format(rft.subcommand,sc.operation))
# load post data--verify its good json
# get the postData from rft.requestData readin on commandline via: -d <patchData>
try:
postData=json.loads(rft.requestData)
except ValueError:
rft.printErr("Post: invalid Json input data:{}".format(rft.requestData))
return(5,None,False,None)
##print("postData: {}".format(postData))
# we verified that we had two args in RawMain(), so we can just read the <uri> arg here
path=sc.args[1]
method="POST"
rft.printVerbose(4,"raw: POST: method:{} path:{}".format(method,path))
apiType=self.getApiType(rft,path) # UNAUTHENTICATED API or Authenticated API
# calculate rootUrl--with correct scheme, root path, and rhost IP (w/o querying rhost)
scheme=rft.getApiScheme(apiType)
scheme_tuple=[scheme, rft.rhost, "/redfish", "","",""]
rootUrl=urlunparse(scheme_tuple) # so rootUrl="http[s]://<rhost>[:<port>]/redfish"
#output the post data in json to send over the network
reqPostData=json.dumps(postData)
#Post the data
rc,r,j,d=rft.rftSendRecvRequest(apiType, method, rootUrl, relPath=path, reqData=reqPostData)
if(rc!=0):
rft.printErr("raw: Error sending POST to resource, aborting")
return(rc,r,False,None)
if(rc==0): rft.printVerbose(1," raw POST:",skip1=True, printV12=cmdTop)
return(rc,r,j,d)
def httpPut(self,sc,op,rft,cmdTop=False, prop=None):
rft.printVerbose(4,"{}:{}: in raw".format(rft.subcommand,sc.operation))
# load put data--verify its good json
# get the postData from rft.requestData readin on commandline via: -d <patchData>
try:
putData=json.loads(rft.requestData)
except ValueError:
rft.printErr("Put: invalid Json input data:{}".format(rft.requestData))
return(5,None,False,None)
##print("postData: {}".format(postData))
# we verified that we had two args in RawMain(), so we can just read the <uri> arg here
path=sc.args[1]
method="PUT"
rft.printVerbose(4,"raw: POST: method:{} path:{}".format(method,path))
apiType=self.getApiType(rft,path) # UNAUTHENTICATED API or Authenticated API
# calculate rootUrl--with correct scheme, root path, and rhost IP (w/o querying rhost)
scheme=rft.getApiScheme(apiType)
scheme_tuple=[scheme, rft.rhost, "/redfish", "","",""]
rootUrl=urlunparse(scheme_tuple) # so rootUrl="http[s]://<rhost>[:<port>]/redfish"
#output the post data in json to send over the network
reqPutData=json.dumps(putData)
#Put the data
rc,r,j,d=rft.rftSendRecvRequest(apiType, method, rootUrl, relPath=path, reqData=reqPutData)
if(rc!=0):
rft.printErr("raw: Error sending PUT to resource, aborting")
return(rc,r,False,None)
if(rc==0): rft.printVerbose(1," raw PUT:",skip1=True, printV12=cmdTop)
return(rc,r,j,d)
def httpDelete(self,sc,op,rft,cmdTop=False, prop=None):
rft.printVerbose(4,"{}:{}: in raw".format(rft.subcommand,sc.operation))
# we verified that we had two args in RawMain(), so we can just read the <uri> arg here
path=sc.args[1]
method="DELETE"
rft.printVerbose(4,"raw: DELETE: method:{} path:{}".format(method,path))
apiType=self.getApiType(rft,path) # UNAUTHENTICATED API or Authenticated API
# calculate rootUrl--with correct scheme, root path, and rhost IP (w/o querying rhost)
scheme=rft.getApiScheme(apiType)
scheme_tuple=[scheme, rft.rhost, "/redfish", "","",""]
rootUrl=urlunparse(scheme_tuple) # so rootUrl="http[s]://<rhost>[:<port>]/redfish"
#send DELETE to the resource path specified
rc,r,j,d=rft.rftSendRecvRequest(apiType, method, rootUrl, relPath=path)
if(rc!=0):
rft.printErr("raw: Error sending DELETE to resource, aborting")
return(rc,r,False,None)
if(rc==0): rft.printVerbose(1," raw DELETE:",skip1=True, printV12=cmdTop)
return(rc,r,j,d)
def examples(self,sc,op,rft,cmdTop=False,prop=None):
rft.printVerbose(4,"{}:{}: in operation".format(rft.subcommand,sc.operation))
print(" {} -r<ip> raw GET /redfish/v1/ # returns the root collection".format(rft.program))
return(0,None,False,None)
'''
TODO:
1. need to handle case where no patch or post data (no -d)
2. add raw PUT
CHANGES:
0.9.2: no longer call /redfish and /redfish/v1 before executing the raw api
'''