########################################################################
#
# All Rights Reserved. Copyright (C) 2023, Hitachi, Ltd.
#
########################################################################
#
# bcmapi - This sample script is a group of functions called from
# another BCM Web API sample script.
#
# Note:
# 1) This script needs to be placed in the same directory as the calling
# source script.
# 2) The calling source script must include "import bcmapi".
#
########################################################################
import ssl
import urllib.request
import json
import pprint
import time
import base64
import configparser
import os
# global variables
cookie = ""
hostaddr = ""
servletKey = None
queueID = None
verbose = False
bcmStart = False
clistMBN = "YKAPIPRC"
# Get value from config file.
def get_config(conf,section,varName,default=None):
try:
varValue = conf.get(section,varName)
except configparser.NoOptionError as err:
if default is not None:
return default
print(err)
exit(-1)
except Exception as err:
print(err)
exit(-1)
return varValue
# Read config file.
def read_config(confpath="bcmapi.ini"):
global verbose
conf = configparser.ConfigParser()
if not os.path.exists(confpath):
print('Config file "' + confpath + '" not found.')
exit(-1)
try:
conf.read(confpath)
except Exception as err:
print(err)
exit(-1)
verbose = get_config(conf, 'bcmapi', 'verbose' , 'FALSE')
if verbose.upper() == "FALSE":
verbose = False
elif verbose.upper() == "TRUE":
verbose = True
else:
print("verbose value is invalid.")
exit(-1)
return conf
# Start TSO/E address space for BCM Web API server.
def start_tso(confpath="bcmapi.ini"):
global hostaddr, servletKey, queueID, clistMBN
# read config
conf = read_config(confpath)
startTsoPrm = \
'proc=' + get_config(conf, 'startTsoPrm', 'proc' ,'IKJACCNT') \
+ '&rsize=' + get_config(conf, 'startTsoPrm', 'rsize','50000') \
+ '&acct=' + get_config(conf, 'startTsoPrm', 'acct' ,'DEFAULT') \
+ '&chset=697&cpage=1047&rows=204&cols=160'
certFile = get_config(conf, 'zosmf', 'cert', '')
keyFile = get_config(conf, 'zosmf', 'key', '')
if certFile == "":
userid = get_config(conf, 'zosmf', 'userid')
password = input("Please input password of z/OS userid("+userid+"):")
hostaddr = get_config(conf, 'zosmf', 'hostaddr')
clistMBN = get_config(conf, 'bcmapi', 'clist', 'YKAPIPRC')
# Set SSL context
sslcontext = ssl.create_default_context()
sslcontext.check_hostname = False
sslcontext.verify_mode = ssl.CERT_NONE
if certFile != "":
try:
if keyFile == "":
sslcontext.load_cert_chain(certFile)
else:
sslcontext.load_cert_chain(certFile, keyFile)
except Exception as err:
print("Cannot load client cert file or private key file.")
exit(-1)
opener = urllib.request.build_opener(\
urllib.request.HTTPSHandler(context=sslcontext))
urllib.request.install_opener(opener)
# Set basic authentication header for z/OSMF authentication.
if certFile == "":
userpwd = userid + ':' + password
basicAuthToken = base64.b64encode(userpwd.encode()).decode()
headers = {
'Authorization': 'Basic ' + basicAuthToken,
'X-CSRF-ZOSMF-HEADER': 'yes',
'Content-Type': 'application/json'
}
else:
headers = {
'X-CSRF-ZOSMF-HEADER': 'yes',
'Content-Type': 'application/json'
}
# Send REST API of TSO/E address space creation request to z/OSMF.
url = 'https://' + hostaddr + '/zosmf/tsoApp/tso'
qsl = urllib.parse.parse_qsl(startTsoPrm)
url = url + '?' + urllib.parse.urlencode(qsl)
req = urllib.request.Request(url, None, headers, method='POST')
if verbose:
print('POST', url)
try:
with urllib.request.urlopen(req, timeout=10) as resp:
respBody = json.load(resp)
global cookie
cookie = resp.getheader('Set-Cookie')
except urllib.error.HTTPError as err:
print("Http error. Status code=",err.code)
print()
return ""
except urllib.error.URLError as err:
print("Cannot connect to z/OSMF. reason=",err.reason)
print()
return ""
except Exception as err:
print("Cannot connect to z/OSMF. ",err.args)
print()
return ""
if verbose:
print(respBody)
if 'servletKey' in respBody:
servletKey = respBody["servletKey"]
else:
servletKey = None
if 'queueID' in respBody:
queueID = respBody["queueID"]
else:
queueID = None
logonInProgress = False
logonReady = False
logonFailed = False
method = 'POST'
while not logonFailed:
if 'tsoData' in respBody:
for tsoMsg in respBody["tsoData"]:
if 'TSO MESSAGE' in tsoMsg:
msgStr = tsoMsg["TSO MESSAGE"]["DATA"]
if method!='GET':
print(msgStr)
if "LOGON IN PROGRESS AT" in msgStr:
logonInProgress = True
elif "LOGGED OFF TSO AT" in msgStr:
logonInProgress = False
elif msgStr.strip() == "READY":
logonReady = True
if 'TSO PROMPT' in tsoMsg:
if logonReady == True:
return respBody
if logonInProgress:
uri = '/zosmf/tsoApp/tso/'+ servletKey
method = 'GET'
respBody = zosmfreq(method, uri, '')
else:
logonFailed = True
else:
if 'msgData' in respBody:
for msgData in respBody["msgData"]:
if 'messageText' in msgData:
print(msgData["messageText"])
if 'timeout' in respBody:
timeout = respBody["timeout"]
if timeout==True:
print("logon timeout")
logonFailed = True
# The user will be logged out
# because the TSO/E logon validation test did not finish.
if servletKey:
uri = '/zosmf/tsoApp/tso/' + servletKey
zosmfreq('DELETE', uri, '')
return ""
# Start BCM Web API server.
def start_bcm():
global bcmStart
if not servletKey or not queueID:
return ""
uri = '/zosmf/tsoApp/app/' + servletKey + '/YKAPI'
startcmd = clistMBN + " &1 &2 " + queueID;
reqBody = '{"startcmd":"' + startcmd + '"}'
respBody = zosmfreq('POST', uri, reqBody)
if 'tsoData' in respBody:
for tsoMsg in respBody["tsoData"]:
if 'TSO MESSAGE' in tsoMsg:
msgStr = tsoMsg["TSO MESSAGE"]["DATA"]
if msgStr.split(' ')[0] == "YK7390I":
bcmStart = True
return respBody
return ""
# End BCM Web API server.
def end_bcm():
global bcmStart
if not servletKey:
return ""
bcmStart = False
uri = '/zosmf/tsoApp/app/' + servletKey + '/YKAPI'
reqBody = '{"action":"exit"}'
return zosmfreq('PUT', uri, reqBody)
# End TSO/E address space.
def end_tso():
global servletKey,bcmStart
if not servletKey:
return ""
bcmStart = False
uri = '/zosmf/tsoApp/tso/' + servletKey
servletKey = None
return zosmfreq('DELETE', uri, '')
# The z/OSMF REST API of the TSO/E address space service
# in which a BCM Web API request is embedded will be sent.
def zosmfreq(method, uri, reqBodyStr):
global cookie
# Generate header and requestbody of z/OSMF REST API.
url = 'https://' + hostaddr + uri
if not reqBodyStr:
reqBodyDict = None
else:
reqBodyDict = json.loads(reqBodyStr)
headers = {
'X-CSRF-ZOSMF-HEADER': 'yes',
'Content-Type': 'application/json'
}
req = urllib.request.Request(\
url, json.dumps(reqBodyDict).encode(), headers, method=method)
req.add_header('Cookie', cookie)
print(method, uri, reqBodyStr)
# Send the z/OSMF REST API request and parse the response.
try:
with urllib.request.urlopen(req) as resp:
respBody = json.load(resp)
except urllib.error.HTTPError as err:
print("Http error. Status code=", err.code)
print()
return ""
except urllib.error.URLError as err:
print("Cannot connect to z/OSMF. reason=",err.reason)
print()
return ""
except Exception as err:
print("Cannot connect to z/OSMF. ",err.args)
print()
return ""
if verbose:
print(respBody)
if 'tsoData' in respBody:
for tsoMsg in respBody["tsoData"]:
if 'TSO MESSAGE' in tsoMsg:
print(tsoMsg["TSO MESSAGE"]["DATA"])
return respBody
elif 'msgData' in respBody:
for msgData in respBody["msgData"]:
if 'messageText' in msgData:
print(msgData["messageText"])
return ""
return respBody
# Send BCM Web API request and receive the response.
def bcmreq(cliname, operands="", cliparms=None, *, \
offset="", limit="", fields="", interval=10):
# Generate requestbody
reqBodyStr = '{ "cliname": "' + cliname + '"'
if type(cliparms) == list:
records = ""
for record in cliparms:
if records != "":
records = records + ","
records = records + '"' + record + '"'
reqBodyStr = reqBodyStr + ', "CLIPARMS": [' + records + ']'
if offset != "":
reqBodyStr = reqBodyStr + ',"offset": ' + str(offset)
if limit != "":
reqBodyStr = reqBodyStr + ',"limit": ' + str(limit)
if fields != "":
reqBodyStr = reqBodyStr + ',"fields": "' + fields + '"'
reqBodyStr = reqBodyStr + ', "operands": "' + operands + '"' + '}'
# Send BCM Web API request to z/OSMF.
if not servletKey:
return 99,""
uri = '/zosmf/tsoApp/app/' + servletKey + '/YKAPI'
respBody = zosmfreq('PUT', uri, reqBodyStr)
if not respBody:
return 99,""
# If a timeout occurs,
# a BCM Web API response-receive request will be sent.
timeout = respBody["timeout"]
while timeout:
time.sleep(interval)
uri = '/zosmf/tsoApp/app/'+ servletKey + '/YKAPI'
respBody = zosmfreq('GET', uri, '')
if not respBody:
return 99,""
timeout = respBody["timeout"]
# Parse BCM Web API response for the appData key
# if a timeout did not occurred.
if 'appData' in respBody:
appData = respBody["appData"]
bcmapiRC = appData["rc"]
print(cliname,'ended. rc =',bcmapiRC)
for bcmMsg in appData["bcmMsg"]:
if 'msgValue' in bcmMsg.keys():
print(bcmMsg["msgText"], 'msgValue=', bcmMsg["msgValue"])
else:
print(bcmMsg["msgText"])
return bcmapiRC, appData
else:
return 99,""