2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2025-05-29 17:23:08 +00:00

Merge pull request #4645 from xuweibj/rflash_python

rflash for openbmc on python, including options a|c|l|delete|u
This commit is contained in:
zet809 2018-01-23 16:13:30 +08:00 committed by GitHub
commit 0982cdf282
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 823 additions and 124 deletions

View File

@ -1,18 +1,63 @@
from xcatagent import base
import os
import time
import sys
import gevent
import utils
import xcat_exception
import rest
import openbmc_rest
HTTP_PROTOCOL = "https://"
PROJECT_URL = "/xyz/openbmc_project"
RESULT_OK = 'ok'
RESULT_FAIL = 'fail'
DEBUGMODE = False
VERBOSE = False
all_nodes_result = {}
# global variables of rflash
RFLASH_OPTIONS = {
"-a" : "activate",
"--activate" : "activate",
"-c" : "check",
"--check" : "check",
"-d" : "direcory",
"--delete" : "delete",
"-l" : "list",
"--list" : "list",
"-u" : "upload",
"--upload" : "upload",
}
RFLASH_URLS = {
"activate" : {
"url" : PROJECT_URL + "/software/#ACTIVATE_ID#/attr/RequestedActivation",
"field" : "xyz.openbmc_project.Software.Activation.RequestedActivations.Active",
},
"delete" : {
"url" : PROJECT_URL + "/software/#DELETE_ID#/action/Delete",
"field" : [],
},
"upload" : {
"url" : "/upload/image/",
},
"priority" : {
"url" : PROJECT_URL + "/software/#PRIORITY_ID#/attr/Priority",
"field" : False,
}
}
XCAT_LOG_DIR = "/var/log/xcat"
XCAT_LOG_RFLASH_DIR = XCAT_LOG_DIR + "/rflash/"
# global variable of firmware information
FIRM_URL = PROJECT_URL + "/software/enumerate"
# global variables of rpower
POWER_SET_OPTIONS = ('on', 'off', 'bmcreboot', 'softoff')
POWER_GET_OPTIONS = ('bmcstate', 'state', 'stat', 'status')
@ -68,21 +113,383 @@ class OpenBMC(base.BaseDriver):
def __init__(self, messager, name, node_info):
super(OpenBMC, self).__init__(messager)
self.node = name
for key, value in node_info.items() :
for key, value in node_info.items():
setattr(self, key, value)
global DEBUGMODE
self.client = rest.RestSession(messager, DEBUGMODE)
self.client = openbmc_rest.OpenBMCRest(name, messager, DEBUGMODE)
def _login(self) :
def _login(self):
""" Login
:raise: error message if failed
"""
url = HTTP_PROTOCOL + self.bmcip + '/login'
data = { "data": [ self.username, self.password ] }
self.client.request('POST', url, OpenBMC.headers, data, self.node, 'login')
self.client.request('POST', url, OpenBMC.headers, data, 'login')
return RESULT_OK
def _set_power_onoff(self, subcommand) :
def _msg_process_rflash (self, msg, update_dict, checkv):
"""deal with msg during rflash
:param msg: the msg want to process
"""
if not checkv:
self.messager.info('%s: %s' % (self.node, msg))
elif VERBOSE:
self.messager.info('%s: %s' % (self.node, msg))
self.rflash_log_handle.writelines(msg + '\n')
self.rflash_log_handle.flush()
if update_dict:
utils.update2Ddict(update_dict, self.node, 'result', [msg])
def _firm_info(self, status):
"""List firmware information including additional
called by rflash check and rinv firm
:returns: firmware information
"""
firm_output = []
try:
(has_functional, firm_info) = self._get_firm_info(status)
except (xcat_exception.SelfServerException,
xcat_exception.SelfClientException) as e:
firm_output.append(e.message)
return firm_output
keys = firm_info.keys()
keys.sort()
for key in keys:
flag = ''
if 'is_functional' in firm_info[key]:
flag = '*'
elif ('Priority' in firm_info[key] and
firm_info[key]['Priority'] == '0'):
if not has_functional:
flag = '*'
else:
flag = '+'
if not flag and not VERBOSE:
continue
firm_output.append('%s Firmware Product: %s (%s)%s' %
(firm_info[key]['Purpose'],
firm_info[key]['Version'],
firm_info[key]['Activation'], flag))
if 'ExtendedVersion' in firm_info[key]:
extendeds = firm_info[key]['ExtendedVersion'].split(',')
extendeds.sort()
for extended in extendeds:
firm_output.append('%s Firmware Product: ' \
'-- additional info: %s' % \
(firm_info[key]['Purpose'], extended))
return firm_output
def _get_firm_info(self, status):
"""get firmware information
:param status: current status
:returns: firmware version information
"""
firm_info = {}
has_functional = False
url = HTTP_PROTOCOL + self.bmcip + FIRM_URL
response = self.client.request('GET', url, OpenBMC.headers, '', status)
functional_url = PROJECT_URL + '/software/functional'
for key in response['data']:
key_id = key.split('/')[-1]
if key_id == 'functional':
for endpoint in response['data'][key]['endpoints']:
purpose = response['data'][endpoint]['Purpose'].split('.')[-1]
key_sort = purpose + '-' + endpoint.split('/')[-1]
utils.update2Ddict(firm_info, key_sort, 'is_functional', True)
has_functional = True
if 'Version' in response['data'][key]:
purpose = response['data'][key]['Purpose'].split('.')[-1]
key_sort = purpose + '-' + key_id
if (functional_url in response['data'] and
key in response['data'][functional_url]['endpoints']):
utils.update2Ddict(firm_info, key_sort, 'is_functional', True)
utils.update2Ddict(firm_info, key_sort, 'Version',
response['data'][key]['Version'])
utils.update2Ddict(firm_info, key_sort, 'Purpose', purpose)
utils.update2Ddict(firm_info, key_sort, 'Activation',
response['data'][key]['Activation'].split('.')[-1])
if 'Priority' in response['data'][key]:
utils.update2Ddict(firm_info, key_sort, 'Priority',
str(response['data'][key]['Priority']))
if 'ExtendedVersion' in response['data'][key]:
utils.update2Ddict(firm_info, key_sort, 'ExtendedVersion',
response['data'][key]['ExtendedVersion'])
if 'Progress' in response['data'][key]:
utils.update2Ddict(firm_info, key_sort, 'Progress',
response['data'][key]['Progress'])
return (has_functional, firm_info)
def _get_firm_id(self, firm_list):
"""get firmware id
:param firm_list: the list of firmware versions
:return: result and info list
"""
firm_ids = []
url = HTTP_PROTOCOL + self.bmcip + FIRM_URL
for i in range(6):
try:
response = self.client.request('GET', url, OpenBMC.headers,
'', 'rflash_check_id')
except (xcat_exception.SelfServerException,
xcat_exception.SelfClientException) as e:
self._msg_process_rflash(e.message, all_nodes_result, False)
return (RESULT_FAIL, [])
for key in response['data']:
if 'Version' in response['data'][key]:
if response['data'][key]['Version'] in firm_list:
firm_id = key.split('/')[-1]
upload_msg = 'Firmware upload successful. ' \
'Attempting to activate firmware: ' \
'%s (ID: %s)' % \
(response['data'][key]['Version'], firm_id)
self._msg_process_rflash(upload_msg, {}, False)
firm_ids.append(firm_id)
firm_list.remove(response['data'][key]['Version'])
if firm_list:
for firm_ver in firm_list:
retry_msg = 'Could not find ID for firmware %s to '\
'activate, waiting %d seconds and retry...' \
% (firm_ver, 10)
self._msg_process_rflash(upload_msg, {}, True)
gevent.sleep( 10 )
else:
break
if firm_list:
for firm_ver in firm_list:
error = 'Could not find firmware %s after waiting %d seconds.' \
% (firm_ver, 10*6)
self._msg_process_rflash(upload_msg, {}, False)
error_list.append(error)
utils.update2Ddict(all_nodes_result, self.node, 'result', error_list)
return (RESULT_FAIL, [])
return (RESULT_OK, firm_ids)
def _check_id_status(self, firm_id_list):
"""check firm id status
:param firm_id_list: list of firm ids want to check
:return: result
"""
result = RESULT_OK
set_priority_ids = []
process_status = {}
failed_msg = []
for i in range(80):
try:
(has_functional, firm_info) = self._get_firm_info('rflash_check_status')
except (xcat_exception.SelfServerException,
xcat_exception.SelfClientException) as e:
self._msg_process_rflash(e.message, all_nodes_result, False)
return (RESULT_FAIL, set_priority_ids)
activation_num = 0
for key in firm_info:
firm_id = key.split('-')[-1]
if firm_id in firm_id_list:
activation_state = firm_info[key]['Activation']
firm_version = firm_info[key]['Version']
if activation_state == 'Failed':
activation_msg = 'Firmware %s activation failed.' % (firm_version)
self._msg_process_rflash(activation_msg, {}, False)
failed_msg.append(activation_msg)
result = RESULT_FAIL
firm_id_list.rempove(firm_id)
if activation_state == 'Active':
activation_msg = 'Firmware %s activation successful.' % (firm_version)
self._msg_process_rflash(activation_msg, {}, False)
firm_id_list.remove(firm_id)
priority = firm_info[key]['Priority']
if priority != '0':
set_priority_ids.append(firm_id)
if activation_state == 'Activating':
activating_progress_msg = 'Activating %s ... %s%%' \
% (firm_version, firm_info[key]['Progress'])
self._msg_process_rflash(activating_progress_msg, {}, True)
process_status[firm_id] = activating_progress_msg
if not firm_id_list:
break
gevent.sleep( 15 )
if firm_id_list:
result = RESULT_FAIL
for firm_id in firm_id_list:
if firm_id in process_status:
failed_msg.append('After %d seconds check the current status is %s' \
% (80*15, process_status[firm_id]))
if failed_msg:
utils.update2Ddict(all_nodes_result, self.node, 'result', [failed_msg])
return (result, set_priority_ids)
def _set_priority(self, priority_ids):
"""set firmware priority to 0
:param priority_ids: list of firmware ids
:return ok if success
:return error msg if failed
"""
for priority_id in priority_ids:
url = (HTTP_PROTOCOL + self.bmcip +
RFLASH_URLS['priority']['url'].replace('#PRIORITY_ID#', priority_id))
data = { "data": RFLASH_URLS['priority']['field'] }
try:
response = self.client.request('PUT', url, OpenBMC.headers,
data, 'rflash_set_priority')
except (xcat_exception.SelfServerException,
xcat_exception.SelfClientException) as e:
return e.message
return RESULT_OK
def _rflash_activate_id(self, activate_id):
"""rflash activate id
:param activate_id: the id want to activate
:raise: error message if failed
"""
url = (HTTP_PROTOCOL + self.bmcip +
RFLASH_URLS['activate']['url'].replace('#ACTIVATE_ID#', activate_id))
data = { "data": RFLASH_URLS['activate']['field'] }
try:
response = self.client.request('PUT', url, OpenBMC.headers,
data, 'rflash_activate')
except xcat_exception.SelfServerException as e:
return e.message
except xcat_exception.SelfClientException as e:
code = e.code
if code == 403:
return 'Error: Invalid ID provided to activate. ' \
'Use the -l option to view valid firmware IDs.'
return e.message
return RESULT_OK
def _rflash_activate(self, activate_arg):
"""ACTIVATE firmware
called by rflash activate
:param activate_arg: firmware tar ball or firmware id
:return: ok if success
:raise: error message if failed
"""
activate_id = activate_version = ''
if 'activate_id' in activate_arg:
activate_id = activate_arg['activate_id']
if 'update_file' in activate_arg:
result = self._rflash_upload(activate_arg['update_file'])
if result != RESULT_OK:
self._msg_process_rflash(result, all_nodes_result, False)
return
activate_version = activate_arg['activate_version']
(result, info) = self._get_firm_id([activate_version])
if result == RESULT_OK:
activate_id = info.pop(0)
else:
return
result = self._rflash_activate_id(activate_id)
if result != RESULT_OK:
self._msg_process_rflash(result, all_nodes_result, False)
return
else:
flash_started_msg = 'rflash %s started, please wait...' % activate_version
self._msg_process_rflash(flash_started_msg, {}, False)
firm_id_list = [activate_id]
(result, priority_ids) = self._check_id_status(firm_id_list)
if result == RESULT_OK:
utils.update2Ddict(all_nodes_result, self.node, 'result', 'OK')
if priority_ids:
self._set_priority(priority_ids)
def _rflash_delete(self, delete_id):
"""Delete firmware on OpenBMC
called by rflash delete
:param delete_id: firmware id want to delete
:returns: ok if success
:raise: error message if failed
"""
url = (HTTP_PROTOCOL + self.bmcip +
RFLASH_URLS['delete']['url'].replace('#DELETE_ID#', delete_id))
data = { "data": RFLASH_URLS['delete']['field'] }
try:
response = self.client.request('POST', url, OpenBMC.headers,
data, 'rflash_delete')
except xcat_exception.SelfServerException as e:
return e.message
except xcat_exception.SelfClientException as e:
code = e.code
if code == 404:
return 'Error: Invalid ID provided to delete. ' \
'Use the -l option to view valid firmware IDs.'
return e.message
return RESULT_OK
def _rflash_list(self):
"""List firmware information
called by rflash list
:returns: firmware version if success
:raise: error message if failed
"""
firm_output = []
try:
(has_functional, firm_info) = self._get_firm_info('rflash_list')
except (xcat_exception.SelfServerException,
xcat_exception.SelfClientException) as e:
firm_output.append(e.message)
return firm_output
firm_output.append('%-8s %-7s %-10s %-s' % ('ID', 'Purpose', 'State', 'Version'))
firm_output.append('-' * 55)
for key in firm_info:
status = firm_info[key]['Activation']
if 'is_functional' in firm_info[key]:
status += '(*)'
elif 'Priority' in firm_info[key] and firm_info[key]['Priority'] == '0':
if not has_functional:
status += '(*)'
else:
status += '(+)'
firm_output.append('%-8s %-7s %-10s %-s' % (key.split('-')[-1],
firm_info[key]['Purpose'], status, firm_info[key]['Version']))
return firm_output
def _rflash_upload(self, upload_file):
""" Upload *.tar file to OpenBMC server
:param upload_file: file to upload
"""
url = HTTP_PROTOCOL + self.bmcip + RFLASH_URLS['upload']['url']
headers = {'Content-Type': 'application/octet-stream'}
uploading_msg = 'Uploading %s ...' % upload_file
self._msg_process_rflash(uploading_msg, {}, True)
try:
self.client.request_upload('PUT', url, headers,
upload_file, 'rflash_upload')
except (xcat_exception.SelfServerException,
xcat_exception.SelfClientException) as e:
result = e.message
return result
return RESULT_OK
def _set_power_onoff(self, subcommand):
""" Set power on/off/softoff/bmcreboot
:param subcommand: subcommand for rpower
:returns: ok if success
@ -90,17 +497,19 @@ class OpenBMC(base.BaseDriver):
"""
url = HTTP_PROTOCOL + self.bmcip + RPOWER_URLS[subcommand]['url']
data = { "data": RPOWER_URLS[subcommand]['field'] }
try :
response = self.client.request('PUT', url, OpenBMC.headers, data, self.node, 'rpower_' + subcommand)
try:
response = self.client.request('PUT', url, OpenBMC.headers,
data, 'rpower_' + subcommand)
except (xcat_exception.SelfServerException,
xcat_exception.SelfClientException) as e :
xcat_exception.SelfClientException) as e:
if subcommand != 'bmcreboot':
result = e.message
return result
return RESULT_OK
def _get_power_state(self, subcommand) :
def _get_power_state(self, subcommand):
""" Get power current state
:param subcommand: state/stat/status/bmcstate
:returns: current state if success
@ -109,61 +518,62 @@ class OpenBMC(base.BaseDriver):
result = ''
bmc_not_ready = 'NotReady'
url = HTTP_PROTOCOL + self.bmcip + RPOWER_URLS['state']['url']
try :
response = self.client.request('GET', url, OpenBMC.headers, '', self.node, 'rpower_' + subcommand)
except xcat_exception.SelfServerException, e :
try:
response = self.client.request('GET', url, OpenBMC.headers,
'', 'rpower_' + subcommand)
except xcat_exception.SelfServerException, e:
if subcommand == 'bmcstate':
result = bmc_not_ready
else :
else:
result = e.message
except xcat_exception.SelfClientException, e :
except xcat_exception.SelfClientException, e:
result = e.message
if result :
if result:
return result
for key in response['data'] :
for key in response['data']:
key_type = key.split('/')[-1]
if key_type == 'bmc0' :
if key_type == 'bmc0':
bmc_current_state = response['data'][key]['CurrentBMCState'].split('.')[-1]
if key_type == 'chassis0' :
if key_type == 'chassis0':
chassis_current_state = response['data'][key]['CurrentPowerState'].split('.')[-1]
if key_type == 'host0' :
if key_type == 'host0':
host_current_state = response['data'][key]['CurrentHostState'].split('.')[-1]
if subcommand == 'bmcstate' :
if bmc_current_state == 'Ready' :
if subcommand == 'bmcstate':
if bmc_current_state == 'Ready':
return bmc_current_state
else :
else:
return bmc_not_ready
if chassis_current_state == 'Off' :
if chassis_current_state == 'Off':
return chassis_current_state
elif chassis_current_state == 'On' :
if host_current_state == 'Off' :
elif chassis_current_state == 'On':
if host_current_state == 'Off':
return 'chassison'
elif host_current_state == 'Quiesced' :
elif host_current_state == 'Quiesced':
return host_current_state
elif host_current_state == 'Running' :
elif host_current_state == 'Running':
return host_current_state
else :
else:
return 'Unexpected chassis state=' + host_current_state
else :
else:
return 'Unexpected chassis state=' + chassis_current_state
def _rpower_boot(self) :
def _rpower_boot(self):
"""Power boot
:returns: 'reset' if success
:raise: error message if failed
"""
result = self._set_power_onoff('off')
if result != RESULT_OK :
if result != RESULT_OK:
return result
self.messager.update_node_attributes('status', self.node, POWER_STATE_DB['off'])
start_timeStamp = int(time.time())
for i in range (0,30) :
for i in range (0,30):
status = self._get_power_state('state')
if status in RPOWER_STATE and RPOWER_STATE[status] == 'off':
break
@ -173,64 +583,128 @@ class OpenBMC(base.BaseDriver):
if status not in RPOWER_STATE or RPOWER_STATE[status] != 'off':
wait_time = str(end_timeStamp - start_timeStamp)
result = 'Error: Sent power-off command but state did not change to off after waiting ' + wait_time + ' seconds. (State=' + status + ').'
result = 'Error: Sent power-off command but state did not change ' \
'to off after waiting %s seconds. (State= %s).' % (wait_time, status)
return result
result = self._set_power_onoff('on')
return result
def rflash(self, args):
"""handle rflash command
:param args: subcommands and parameters for rflash
"""
subcommand = args[0]
if subcommand == 'activate' or subcommand == 'upload':
self.rflash_log_file = XCAT_LOG_RFLASH_DIR + '/' + self.node + '.log'
self.rflash_log_handle = open(self.rflash_log_file, 'a')
def rpower(self, args) :
try:
result = self._login()
except (xcat_exception.SelfServerException,
xcat_exception.SelfClientException) as e:
result = e.message
if result != RESULT_OK:
self.messager.info('%s: %s'% (self.node,result))
if subcommand == 'activate' or subcommand == 'upload':
self.rflash_log_handle.writelines(result + '\n')
self.rflash_log_handle.flush()
if subcommand == 'activate':
utils.update2Ddict(all_nodes_result, self.node, 'result', [result])
return
if subcommand == 'activate':
activate_arg = args[1]
self._rflash_activate(activate_arg)
if subcommand == 'check':
firm_info = self._firm_info('rflash_check')
for i in firm_info:
result = '%s: %s' % (self.node, i)
self.messager.info(result)
if subcommand == 'delete':
firmware_id = args[1]
result = self._rflash_delete(firmware_id)
if result == RESULT_OK:
result = '%s: [%s] Firmware removed' % (self.node, firmware_id)
self.messager.info(result)
else:
result = '%s: %s' % (self.node, result)
self.messager.info(result)
if subcommand == 'list':
firm_info = self._rflash_list()
for i in firm_info:
result = '%s: %s' % (self.node, i)
self.messager.info(result)
if subcommand == 'upload':
upload_file = args[1]
result = self._rflash_upload(upload_file)
if result == RESULT_OK:
result = 'Firmware upload successful. Use -l option to list.'
self._msg_process_rflash(result, {}, False)
else:
self._msg_process_rflash(result, {}, False)
if subcommand == 'activate' or subcommand == 'upload':
self.rflash_log_handle.close()
def rpower(self, args):
"""handle rpower command
:param args: subcommands for rpower
"""
subcommand = args[0]
try :
try:
result = self._login()
except xcat_exception.SelfServerException as e :
if subcommand == 'bmcstate' :
except xcat_exception.SelfServerException as e:
if subcommand == 'bmcstate':
result = '%s: %s' % (self.node, RPOWER_STATE['NotReady'])
else :
else:
result = '%s: %s' % (self.node, e.message)
except xcat_exception.SelfClientException as e :
except xcat_exception.SelfClientException as e:
result = '%s: %s' % (self.node, e.message)
if result != RESULT_OK :
if result != RESULT_OK:
self.messager.info(result)
self._update2Ddict(node_rst, self.node, 'rst', result)
return
new_status = ''
if subcommand in POWER_SET_OPTIONS :
if subcommand in POWER_SET_OPTIONS:
result = self._set_power_onoff(subcommand)
if result == RESULT_OK :
if result == RESULT_OK:
result = RPOWER_STATE[subcommand]
new_status = POWER_STATE_DB.get(subcommand, '')
if subcommand in POWER_GET_OPTIONS :
if subcommand in POWER_GET_OPTIONS:
tmp_result = self._get_power_state(subcommand)
result = RPOWER_STATE.get(tmp_result, tmp_result)
if subcommand == 'boot' :
if subcommand == 'boot':
result = self._rpower_boot()
if result == RESULT_OK :
if result == RESULT_OK:
result = RPOWER_STATE[subcommand]
new_status = POWER_STATE_DB.get(subcommand, '')
if subcommand == 'reset' :
if subcommand == 'reset':
status = self._get_power_state('state')
if status == 'Off' or status == 'chassison':
result = RPOWER_STATE['Off']
else :
else:
result = self._rpower_boot()
if result == RESULT_OK :
if result == RESULT_OK:
result = RPOWER_STATE[subcommand]
new_status = POWER_STATE_DB.get(subcommand, '')
message = '%s: %s' % (self.node, result)
self.messager.info(message)
if new_status :
if new_status:
self.messager.update_node_attributes('status', self.node, new_status)
class OpenBMCManager(base.BaseManager):
def __init__(self, messager, cwd, nodes, envs):
super(OpenBMCManager, self).__init__(messager, cwd)
@ -238,5 +712,101 @@ class OpenBMCManager(base.BaseManager):
global DEBUGMODE
DEBUGMODE = envs['debugmode']
def _get_full_path(self,file_path):
if type(self.cwd) == 'unicode':
dir_path = self.cwd
else:
dir_path = self.cwd[0]
return '%s/%s' % (dir_path,file_path)
def _check_verbose(self, args):
verbose_list = ('-V', '--verbose')
for i in verbose_list:
if i in args:
global VERBOSE
VERBOSE = True
args.remove(i)
def _summary(self, nodes_num, title):
if all_nodes_result:
success_num = failed_num = 0
failed_list = []
for key in all_nodes_result:
if all_nodes_result[key]['result'] == 'OK':
success_num += 1
else:
failed_num += 1
for errors in all_nodes_result[key]['result']:
for error in errors:
failed_list.append('%s: %s' % (key, error))
self.messager.info('-' * 55)
self.messager.info('%s complete: Total=%d Success=%d Failed=%d' % \
(title, nodes_num, success_num, failed_num))
if failed_list:
for i in failed_list:
self.messager.info(i)
self.messager.info('-' * 55)
def rflash(self, nodeinfo, args):
if not os.path.exists(XCAT_LOG_RFLASH_DIR):
os.makedirs(XCAT_LOG_RFLASH_DIR)
nodes_num = len(self.nodes)
self._check_verbose(args)
for key,value in RFLASH_OPTIONS.items():
if key in args:
args.remove(key)
args.insert(0, value)
break
upload_file = None
activate_arg = {}
args_num = len(args)
subcommand = args[0]
if (subcommand == 'upload' or subcommand == 'activate' or
(subcommand == 'check' and args_num > 1)):
arg_type = args[1].split('.')[-1]
if arg_type == 'tar':
upload_file = args[1]
if not os.path.isabs(upload_file):
upload_file = self._get_full_path(upload_file)
if (not os.access(upload_file, os.F_OK) or
not os.access(upload_file, os.R_OK)):
error = 'Error: Cannot access %s. Check the management ' \
'node and/or service nodes.' % upload_file
self.messager.error(error)
return
activate_arg['update_file'] = upload_file
else:
activate_arg['activate_id'] = args[1]
if (subcommand == 'check' or subcommand == 'activate') and upload_file:
grep_cmd = '/usr/bin/grep -a'
version_cmd = grep_cmd + ' ^version= ' + upload_file
purpose_cmd = grep_cmd + ' purpose= ' + upload_file
firmware_ver = os.popen(version_cmd).readlines()[0].split('=')[-1].strip()
purpose_ver = os.popen(purpose_cmd).readlines()[0].split('=')[-1].strip()
if subcommand == 'check':
self.messager.info('TAR %s Firmware Product Version: %s' \
% (purpose_ver,firmware_ver))
else:
activate_arg['activate_version'] = firmware_ver
activate_arg['purpose'] = purpose_ver.split('.')[-1]
if subcommand == 'activate':
args[1] = activate_arg
if subcommand == 'upload':
args[1] = upload_file
if subcommand == 'upload' or subcommand == 'activate' and upload_file:
self.messager.info('Attempting to upload %s, please wait...' % upload_file)
super(OpenBMCManager, self).process_nodes_worker('openbmc', 'OpenBMC',
self.nodes, nodeinfo, 'rflash', args)
self._summary(nodes_num, 'Firmware update')
def rpower(self, nodeinfo, args):
super(OpenBMCManager, self).process_nodes_worker('openbmc', 'OpenBMC', self.nodes, nodeinfo, 'rpower', args)
super(OpenBMCManager, self).process_nodes_worker('openbmc', 'OpenBMC',
self.nodes, nodeinfo, 'rpower', args)

View File

@ -0,0 +1,113 @@
#!/usr/bin/env python
import requests
import json
import time
import rest
import xcat_exception
class OpenBMCRest:
def __init__(self, name, messager, debugmode):
self.session = rest.RestSession()
self.name = name
self.messager = messager
self.debugmode = debugmode
def _print_record_log (self, log_string, status):
if self.debugmode :
localtime = time.asctime( time.localtime(time.time()) )
log = self.name + ': [openbmc_debug] ' + status + ' ' + log_string
self.messager.info(localtime + ' ' + log)
self.messager.syslog(log)
def _request_log (self, method, url, headers, data, files):
log_string = 'curl -k -c cjar -b cjar'
log_string += ' -X %s' % method
for key,value in headers.items():
header_data = key + ": " + value
log_string += ' -H "' + header_data + '"'
log_string += ' %s' % url
if data:
log_string += ' -d \'%s\'' % data
if files:
log_string += ' -T \'%s\'' % files
return log_string
def _response_check (self, response, response_dict, status):
if response.status_code != requests.codes.ok:
description = ''.join(response_dict['data']['description'])
error = 'Error: [%d] %s' % (response.status_code, description)
self._print_record_log(error, status)
code = response.status_code
raise xcat_exception.SelfClientException(error, code)
else:
self._print_record_log(response_dict['message'], status)
def request (self, method, url, headers, in_data, status):
data = log_data = ''
if in_data:
data = json.dumps(in_data)
log_data = data
if status == 'login':
in_data['data'][1] = 'xxxxxx'
log_data = json.dumps(in_data)
log_string = self._request_log(method, url, headers, log_data, '')
self._print_record_log(log_string, status)
try:
response = self.session.request(method, url, headers, data)
except xcat_exception.SelfServerException as e:
self._print_record_log(e.message, status)
raise xcat_exception.SelfServerException(e.message)
try:
response_dict = response.json()
except ValueError:
error = 'Error: Received wrong format response: %s' % response
self._print_record_log(error, status)
raise xcat_exception.SelfServerException(error)
self._response_check(response, response_dict, status)
return response_dict
def request_upload (self, method, url, headers, files, status):
for key,value in headers.items():
header_data = key + ': ' + value
request_cmd_log = 'curl -k -c cjar -b cjar -H "%s" -X %s -T %s %s -s' \
% (header_data, method, files, url)
log_string = self._request_log(method, url, headers, '', files)
self._print_record_log(log_string, status)
response = self.session.request_upload(method, url, header_data, files)
if not response:
error = 'Error: Did not receive response from OpenBMC after ' \
'running command form \'%s\'' % request_cmd_log
raise xcat_exception.SelfServerException(error)
try:
response_dict = json.loads(response)
except ValueError:
error = 'Error: Received wrong format response: %s: %s' % \
(request_cmd_log, response)
self._print_record_log(error, status)
raise xcat_exception.SelfServerException(error)
if response_dict['message'] != '200 OK':
error = 'Error: Failed to upload update file %s : %s-%s' % \
(files, response_dict['message'], \
''.join(response_dict['data']['description']))
self._print_record_log(error, status)
raise xcat_exception.SelfClientException(error, code)
self._print_record_log(response_dict['message'], status)
return

View File

@ -1,7 +1,6 @@
#!/usr/bin/env python
import requests
import json
import time
from gevent.subprocess import Popen, PIPE
import urllib3
urllib3.disable_warnings()
@ -9,76 +8,34 @@ import xcat_exception
class RestSession :
def __init__(self, messager, debugmode) :
def __init__(self):
self.session = requests.Session()
self.messager = messager
self.debugmode = debugmode
self.cookies = None
def _print_record_log (self, node, log_string, status) :
if self.debugmode :
localtime = time.asctime( time.localtime(time.time()) )
log = node + ': [openbmc_debug] ' + status + ' ' + log_string
self.messager.info(localtime + ' ' + log)
self.messager.syslog(log)
def _request_log (self, method, url, headers, data):
log_string = 'curl -k -c cjar'
log_string += ' -X %s' % method
for key,value in headers.items() :
header_data = key + ": " + value
log_string += ' -H "' + header_data + '"'
log_string += ' %s' % url
if data :
log_string += ' -d \'%s\'' % data
return log_string
def request (self, method, url, headers, in_data, node, status) :
if in_data :
data = json.dumps(in_data)
else :
data = ''
if status == 'login' :
in_data['data'][1] = 'xxxxxx'
log_data = json.dumps(in_data)
else :
log_data = data
log_string = self._request_log(method, url, headers, log_data)
self._print_record_log(node, log_string, status)
response = ''
error = ''
try :
def request (self, method, url, headers, data):
try:
response = self.session.request(method, url,
data=data,
headers=headers,
verify=False,
timeout=30)
except requests.exceptions.ConnectionError :
error = 'Error: BMC did not respond. Validate BMC configuration and retry the command.'
except requests.exceptions.Timeout :
error = 'Error: Timeout to connect to server'
data=data,
headers=headers,
verify=False,
timeout=30)
except requests.exceptions.ConnectionError:
raise xcat_exception.SelfServerException(
'Error: BMC did not respond. ' \
'Validate BMC configuration and retry the command.')
except requests.exceptions.Timeout:
raise xcat_exception.SelfServerException('Error: Timeout to connect to server')
if error :
self._print_record_log(node, error, status)
raise xcat_exception.SelfServerException(error)
if not self.cookies:
self.cookies = requests.utils.dict_from_cookiejar(self.session.cookies)
try :
response_dict = response.json()
except ValueError :
error = 'Error: Received wrong format response:' + response_dict
self._print_record_log(node, error, status)
raise xcat_exception.SelfServerException(error)
return response
if response.status_code != requests.codes.ok :
description = ''.join(response_dict['data']['description'])
error = 'Error: [%d] %s' % (response.status_code, description)
self._print_record_log(node, error, status)
raise xcat_exception.SelfClientException(error)
else :
self._print_record_log(node, response_dict['message'], status)
return response_dict
def request_upload (self, method, url, headers, files):
request_cmd = 'curl -k -b sid=%s -H "%s" -X %s -T %s %s -s' % \
(self.cookies['sid'], headers, method, files, url)
sub = Popen(request_cmd, stdout=PIPE, shell=True)
response, err = sub.communicate()
return response

View File

@ -39,3 +39,11 @@ def recv_all(sock, size):
buf_size += len(buf_part)
buf = ''.join(buf_parts)
return buf
def update2Ddict(updata_dict, key_a, key_b, value):
if key_a in updata_dict:
updata_dict[key_a].update({key_b: value})
else:
updata_dict.update({key_a: {key_b: value}})

View File

@ -4,4 +4,6 @@ class SelfServerException(Exception) :
pass
class SelfClientException(Exception) :
pass
def __init__(self, message, code) :
super(Exception, self).__init__(message)
self.code = code

View File

@ -30,6 +30,7 @@ use xCAT::OPENBMC;
sub handled_commands {
return {
rflash => 'nodehm:mgt=openbmc',
rpower => 'nodehm:mgt=openbmc',
};
}
@ -136,13 +137,61 @@ sub parse_args {
my $noderange = shift;
my $subcommand = undef;
if (scalar(@ARGV) != 1 and ($command =~ /rpower/)) {
if (scalar(@ARGV) >= 2 and ($command =~ /rpower/)) {
return ([ 1, "Only one option is supported at the same time for $command" ]);
} elsif (scalar(@ARGV) == 0 and $command =~ /rpower|rflash/) {
return ([ 1, "No option specified for $command" ]);
} else {
$subcommand = $ARGV[0];
}
if ($command eq "rpower") {
if ($command eq "rflash") {
my $verbose;
my ($activate, $check, $delete, $directory, $list, $upload) = (0) x 6;
my $no_host_reboot;
GetOptions(
'a|activate' => \$activate,
'c|check' => \$check,
'delete' => \$delete,
'd' => \$directory,
'l|list' => \$list,
'u|upload' => \$upload,
'V|verbose' => \$verbose,
'no-host-reboot' => \$no_host_reboot,
);
my $option_num = $activate+$check+$delete+$directory+$list+$upload;
if ($option_num >= 2) {
return ([ 1, "Multiple options are not supported."]);
} elsif ($option_num == 0) {
return ([ 1, "No options specified."]);
}
if ($activate or $check or $delete or $upload) {
return ([ 1, "More than one firmware specified is not supported."]) if ($#ARGV >= 1);
if ($check) {
return ([ 1, "Invalid firmware specified with '-c|--check'."]) if (@ARGV and ($ARGV[0] !~ /.*\.tar$/i or $#ARGV >= 1));
}
if ($activate or $delete or $upload) {
my $option = "-a|--activate";
if ($upload) {
$option = "-u|--upload";
} elsif ($delete) {
$option = "--delete"
}
return ([ 1, "Invalid firmware specified with '$option'"]) if (!@ARGV);
my $param = $ARGV[0];
return ([ 1, "Invalid firmware specified with '$option': $param"]) if (($delete and $param !~ /^[[:xdigit:]]+$/i)
or ($activate and $param !~ /^[[:xdigit:]]+$/i and $param !~ /.*\.tar$/i) or ($upload and $param !~ /.*\.tar$/i));
}
}
if ($directory) {
return ([ 1, "Unsupported command: $command '-d'" ]);
return ([ 1, "More than one directory specified is not supported."]) if ($#ARGV >= 1);
return ([ 1, "Invalid option specified with '-d'."]) if (!@ARGV);
}
if ($list) {
return ([ 1, "Invalid option specified with '-l|--list'."]) if (@ARGV);
}
} elsif ($command eq "rpower") {
unless ($subcommand =~ /^on$|^off$|^softoff$|^reset$|^boot$|^bmcreboot$|^bmcstate$|^status$|^stat$|^state$/) {
return ([ 1, "Unsupported command: $command $subcommand" ]);
}