407 lines
18 KiB
Python
407 lines
18 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: SessionService.py
|
|
#
|
|
# contains SessionService related subCommands and access functions
|
|
#
|
|
# Class RfSessionServiceMain
|
|
# - functions init, displayUsage, displayHelp, displayOperations,
|
|
# - runOperation - SessionService command table, dispatch of operation eg get, reset
|
|
# - SessionServiceMain - called from redfishMain, enforce legal option combinations,
|
|
# and call runOperation to run SessionService operation (sub-sub-command)
|
|
#
|
|
# Class RfSessionServiceOperations
|
|
# All of the SessionService sub-command operations eg: login, logout, get sessionService, etc
|
|
# - hello - test cmd
|
|
# - get - get the session service
|
|
# - patch - raw subcommand to patch a sessionService, with etag support
|
|
# - setSessionTimeout -- patches the SessionTimeout property w/ etag support
|
|
# - Sessions - get Sessions collection, Session instance, list Sessions, get all Sessions
|
|
# - login - Session login (post to add a new session)
|
|
# - logout - Session logout (delete to delete a session)
|
|
# - 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 RfSessionServiceMain():
|
|
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] SessionService <operation> [<args>] -- perform <operation> on the SessionService ".format(rft.program))
|
|
|
|
def displayHelp(self,rft):
|
|
self.displayUsage(rft)
|
|
self.displayOperations(rft)
|
|
print("")
|
|
|
|
def displayOperations(self,rft):
|
|
print(" <operations>:")
|
|
print(" [get] -- get the sessionService object. ")
|
|
print(" patch {A: B,C: D,...} -- patch the sessionService w/ json-formatted {prop: value...} ")
|
|
print(" setSessionTimeout <timeout> -- patches the SessionTimeout property w/ etag support ")
|
|
print(" Sessions [list] -- get the \"Sessions\" collection, or list \"Id\", username, and Url ")
|
|
print(" Sessions [IDOPTN] -- get the member specified by IDOPTN: -i<Id>, -m<prop>:<val>, -l<link>, -a #all")
|
|
print(" login -- sessionLogin. post to Sessions collection to create a session")
|
|
print(" the user is -u<user>, password is -p<password>")
|
|
print(" logout -- logout or delete the session by identified by -i<SessionId> or -l<link>")
|
|
print(" where <link> is the session path returned in Location from login")
|
|
print(" examples -- example commands with syntax")
|
|
print(" hello -- Systems hello -- debug command")
|
|
return(0)
|
|
|
|
|
|
def runOperation(self,rft):
|
|
# instantiate SessionServiceOperations class
|
|
op=RfSessionServiceOperations()
|
|
|
|
# dispatch table for each subcommand: "cmdName": cmdClass.cmdFunction"
|
|
operationTable = {
|
|
"get": op.get,
|
|
"patch": op.patch,
|
|
"setSessionTimeout": op.setSessionTimeout,
|
|
"Sessions": op.getSessions,
|
|
"login": op.sessionLogin,
|
|
"logout": op.sessionLogout,
|
|
"hello": op.hello,
|
|
"examples": op.examples
|
|
}
|
|
|
|
rft.printVerbose(5,"SessionService:runOperation: operation: {}".format(self.operation))
|
|
rft.printVerbose(5,"SessionService:runOperation: args: {}".format(self.args))
|
|
|
|
if self.operation in operationTable:
|
|
rft.printVerbose(5,"SessionService: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("SessionService: Invalid operation: {}".format(self.operation))
|
|
return(2,None,False,None)
|
|
|
|
|
|
|
|
def SessionServiceMain(self,rft,cmdTop=False):
|
|
rft.printVerbose(4,"SessionServiceMain: 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, this is a getSessionService command
|
|
if( len(args) < 2 ):
|
|
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,"SessionService: operation={}, args={}".format(self.operation,self.args))
|
|
|
|
# now execute the operation.
|
|
rc,r,j,d = self.runOperation(rft)
|
|
|
|
if(rc !=0 ):
|
|
rft.printVerbose(5,"SessionService: 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,"SessionService: operation exited OK")
|
|
return(rc,r,j,d)
|
|
|
|
|
|
#
|
|
# contains operations related to the SessionService subCommand
|
|
#
|
|
class RfSessionServiceOperations():
|
|
def __init__(self):
|
|
self.SessionServicePath=None
|
|
self.SessionServiceCollectionDict=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 SessionService")
|
|
return(0,None,False,None)
|
|
|
|
|
|
|
|
def get(self,sc,op,rft, cmdTop=False, prop=None):
|
|
rft.printVerbose(4,"{}:{}: in operation".format(rft.subcommand,sc.operation))
|
|
|
|
# 1st get serviceRoot
|
|
svcRoot=RfServiceRoot()
|
|
rc,r,j,d = svcRoot.getServiceRoot(rft)
|
|
if( rc != 0 ):
|
|
rft.printErr("get SessionService: Error getting service root, aborting")
|
|
return(rc,r,False,None)
|
|
|
|
# get the link to the SessionService
|
|
# need to test we got good data
|
|
if (("SessionService" in d) and ("@odata.id" in d["SessionService"])):
|
|
sessionServiceLink=d["SessionService"]["@odata.id"]
|
|
else:
|
|
rft.printErr("Error: root does not have a SessionService link")
|
|
return(4)
|
|
|
|
rft.printVerbose(4,"SessionService: get SessionService: link is: {}".format(sessionServiceLink))
|
|
|
|
if cmdTop is True: prop=rft.prop
|
|
|
|
# do a GET to get the SessionService, if -P show property, else show full response
|
|
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', r.url, relPath=sessionServiceLink, prop=prop)
|
|
|
|
if(rc==0): rft.printVerbose(1," SessionService Resource:",skip1=True, printV12=cmdTop)
|
|
return(rc,r,j,d)
|
|
|
|
|
|
|
|
def patch(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: SessionService patch \"{ <prop>: <value> }\"")
|
|
return(4,None,False,None)
|
|
|
|
# read the sessionServiceLink 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," SessionService Patch:",skip1=True, printV12=cmdTop)
|
|
return(rc,r,j,d)
|
|
|
|
|
|
|
|
def setSessionTimeout(self,sc,op,rft,cmdTop=False, prop=None):
|
|
rft.printVerbose(4,"{}:{}: in operation".format(rft.subcommand,sc.operation))
|
|
|
|
propName="SessionTimeout"
|
|
|
|
# get the SessionTimeout from args
|
|
if(len(sc.args) < 2 ):
|
|
rft.printErr("Error, no SessionTimeout value specified")
|
|
rft.printErr("Syntax: {} [options] SessionService setSessionTimeout <timeoutInt> ".format(rft.program))
|
|
return(8,None,False,None)
|
|
sessTimeout=int(sc.args[1],0) # base 0 means int() will interpret 0x<num> as hex and <num> as decimal
|
|
patchData={propName: sessTimeout}
|
|
|
|
# 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("SessionService 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," SessionService setSessionTimeout:",skip1=True, printV12=cmdTop)
|
|
assetTag={propName: d[propName]}
|
|
return(rc,r,j,assetTag)
|
|
else: return(rc,r,False,None)
|
|
|
|
|
|
|
|
def getSessions(self,sc,op, rft, cmdTop=False, prop=None):
|
|
rft.printVerbose(4,"{}:{}: in operation: getSessions collection".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="Sessions"
|
|
# get the link to the Sessions collection
|
|
if ((collName in d) and ("@odata.id" in d[collName])):
|
|
sessionsLink=d[collName]["@odata.id"]
|
|
else:
|
|
rft.printErr("Error: SessionService 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=sessionsLink)
|
|
#loop through the members and create the list sub-operation response
|
|
rc,r,j,d=rft.listCollection(rft, r, d, prop="UserName")
|
|
if(rc==0):
|
|
rft.printVerbose(1," list {} Collection member info: Id, URI, Socket".format(collName,skip1=True, printV12=cmdTop))
|
|
|
|
# else: check if no session was specified. If not, return the collection
|
|
elif(rft.IdLevel2OptnCount==0):
|
|
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', r.url, relPath=sessionsLink, 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 session specific by -i or -m or -l
|
|
# search collection to find path using getPath2
|
|
elif( rft.allOptn is not True ):
|
|
# get the Sessions collection
|
|
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', r.url, relPath=sessionsLink, 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 session, 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 Sessions members
|
|
else:
|
|
rft.printVerbose(4,"getting expanded Sessions Collection")
|
|
rc,r,j,d=rft.getAllCollectionMembers(rft, r.url, relPath=sessionsLink)
|
|
if(rc==0):
|
|
rft.printVerbose(1," Get ALL {} Collection Members".format(collName,skip1=True, printV12=cmdTop))
|
|
|
|
return(rc,r,j,d)
|
|
|
|
|
|
|
|
|
|
#SessionService -u <username> -p <passwd> login, returns authToken and sessionId
|
|
def sessionLogin(self,sc,op,rft,cmdTop=False, prop=None):
|
|
rft.printVerbose(4,"{}:{}: in operation".format(rft.subcommand,sc.operation))
|
|
|
|
#note that <username> and <password> were passed-in in -u and -p options and are stores in
|
|
# rft.user and rft.password
|
|
|
|
# 1st get serviceRoot
|
|
svcRoot=RfServiceRoot()
|
|
rc,r,j,d = svcRoot.getServiceRoot(rft)
|
|
if( rc != 0 ):
|
|
rft.printErr("SessionService: login: Error getting service root, aborting")
|
|
return(rc,r,False,None)
|
|
|
|
#call rfSessionLogin in transport class to login
|
|
rc,r,j,d=rft.rfSessionLogin(rft,cleanupOnExit=False)
|
|
if(rc == 0):
|
|
# return sessionId and authToken
|
|
respData={"SessionId": rft.sessionId, "SessionLocation": rft.sessionLink, "X-Auth-Token": rft.authToken}
|
|
rft.printVerbose(1," SessionLogin: {}".format(respData, skip1=True, printV12=cmdTop))
|
|
return(rc,r,j,respData)
|
|
else:
|
|
return(rc,r,j,d)
|
|
|
|
|
|
#SessionService -t<token> logout [-i<sessionId>|-l<sessionLink>], returns 204 no content
|
|
def sessionLogout(self,sc,op,rft,cmdTop=False, prop=None):
|
|
rft.printVerbose(4,"{}:{}: in operation".format(rft.subcommand,sc.operation))
|
|
|
|
if( (rft.linkLevel2 is None) and( rft.IdLevel2 is None) ):
|
|
rft.printErr("Error, logout: no sessionId or sessionLink specified")
|
|
rft.printErr("Syntax: {} [options] [SessionService] logout [-i<sessionId> | -l <sessionLink>]".format(rft.program))
|
|
return(8,None,False,None)
|
|
|
|
# 1st get serviceRoot
|
|
svcRoot=RfServiceRoot()
|
|
rc,r,j,d = svcRoot.getServiceRoot(rft)
|
|
if( rc != 0 ):
|
|
rft.printErr("SessionService: login: Error getting service root, aborting")
|
|
return(rc,r,False,None)
|
|
|
|
#find Sessions collection
|
|
if( ("Links" in d) and ("Sessions" in d["Links"]) and ("@odata.id" in d["Links"]["Sessions"]) ):
|
|
sessionsLink=rft.rootResponseDict["Links"]["Sessions"]["@odata.id"]
|
|
#print("loginUri:{}".format(loginUri))
|
|
else:
|
|
rft.printErr("Error: the rootService response does not have a login link: \"Links\":\"Sessions\":{{\"@odata.id\": <uri>}")
|
|
return(4,None,False,None)
|
|
|
|
# get the Sessions collection
|
|
rc,r,j,d=rft.rftSendRecvRequest(rft.AUTHENTICATED_API, 'GET', r.url, relPath=sessionsLink, prop=prop)
|
|
if(rc != 0):
|
|
rft.printErr("Error: logout: can't read sessions collection")
|
|
return(6,None,False,None)
|
|
# now search for 2nd level resource and return
|
|
path2,rc,r,j,d=rft.getLevel2ResourceById(rft,r,d)
|
|
if(rc!=0):
|
|
rft.printErr("Error: the specified sessionId or sessionLink was not a valid Sessions collection entry")
|
|
return(rc,r,j,d)
|
|
|
|
#path2 is the path the the session we want to delete
|
|
rc,r,j,d=rft.rfSessionDelete(rft,sessionLink=path2)
|
|
if(rc!=0):
|
|
rft.printErr("Error: Logout: the session delete failed")
|
|
return(rc,r,j,d)
|
|
else:
|
|
rft.printVerbose(1," SessionLogout successful".format(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> SessionService # gets the sessionService".format(rft.program))
|
|
print(" {} -r<ip> SessionService setSessionTimeout <timeout> # sets the session timeout property".format(rft.program))
|
|
print(" {} -r<ip> SessionService Sessions # gets Sessions collection".format(rft.program))
|
|
print(" {} -r<ip> SessionService Sessions -l<sessUrl> # gets the session at URI=<sessUrl".format(rft.program))
|
|
print(" {} -r<ip> SessionService Sessions -i<sessId> # gets the session with session Id <sessId>".format(rft.program))
|
|
print(" {} -r<ip> SessionService patch {{A: B,C: D,...}} # patch the json-formatted {{prop: value...}} data to the sessionService object".format(rft.program))
|
|
print(" {} -r<ip> SessionService login <usernm> <passwd> # login (create session)".format(rft.program))
|
|
print(" {} -r<ip> SessionService logout <sessionId> # logout (delete session <sessId>".format(rft.program))
|
|
return(0,None,False,None)
|
|
|
|
|
|
|
|
'''
|
|
TODO:
|
|
1. e
|
|
|
|
'''
|
|
|
|
|
|
|
|
|