From b8a489899b9117c9aa7dbaa632cd48d277c22199 Mon Sep 17 00:00:00 2001 From: XuWei Date: Mon, 19 Mar 2018 04:17:58 -0400 Subject: [PATCH] rflash in python for OpenBMC --- .../lib/python/agent/common/rest.py | 2 +- .../lib/python/agent/common/utils.py | 7 +- .../agent/hwctl/executor/openbmc_flash.py | 562 ++++++++++++++++ .../agent/hwctl/executor/openbmc_inventory.py | 27 +- .../agent/hwctl/executor/openbmc_power.py | 25 +- .../lib/python/agent/hwctl/flash.py | 54 ++ .../lib/python/agent/hwctl/inventory.py | 5 +- .../lib/python/agent/hwctl/openbmc_client.py | 51 +- .../lib/python/agent/xcatagent/openbmc.py | 629 ++---------------- .../python/agent/xcatagent/openbmc_rest.py | 113 ---- xCAT-server/lib/xcat/plugins/openbmc2.pm | 1 - 11 files changed, 751 insertions(+), 725 deletions(-) create mode 100644 xCAT-openbmc-py/lib/python/agent/hwctl/executor/openbmc_flash.py create mode 100644 xCAT-openbmc-py/lib/python/agent/hwctl/flash.py delete mode 100644 xCAT-openbmc-py/lib/python/agent/xcatagent/openbmc_rest.py diff --git a/xCAT-openbmc-py/lib/python/agent/common/rest.py b/xCAT-openbmc-py/lib/python/agent/common/rest.py index 88c836998..46a9f7b2e 100644 --- a/xCAT-openbmc-py/lib/python/agent/common/rest.py +++ b/xCAT-openbmc-py/lib/python/agent/common/rest.py @@ -122,7 +122,7 @@ class RestSession(object): response, err = sub.communicate() if not response: - error = 'Error: Did not receive response from server after ' \ + error = 'Did not receive response from server after ' \ 'running command \'%s\'' % request_cmd raise SelfServerException(error) diff --git a/xCAT-openbmc-py/lib/python/agent/common/utils.py b/xCAT-openbmc-py/lib/python/agent/common/utils.py index d05768a7d..e84bca7b1 100644 --- a/xCAT-openbmc-py/lib/python/agent/common/utils.py +++ b/xCAT-openbmc-py/lib/python/agent/common/utils.py @@ -7,7 +7,7 @@ import struct import sys import inspect -import re +import re, os import logging from logging.handlers import SysLogHandler @@ -92,6 +92,11 @@ def mask_int2str(mask_int): mask_num = (0x1 << 32) - (0x1 << (32 - mask_int)) return "%s.%s.%s.%s" % (str((mask_num >> 24) & 0xff), str((mask_num >>16)&0xff), str((mask_num >> 8) & 0xff), str(mask_num & 0xff)) +def get_full_path(cwd, directory): + if not os.path.isabs(directory): + directory = '%s/%s' % (cwd, directory) + return directory + class Messager(object): def __init__(self, name=None): self.logger = logging.getLogger(name or 'xcatagent') diff --git a/xCAT-openbmc-py/lib/python/agent/hwctl/executor/openbmc_flash.py b/xCAT-openbmc-py/lib/python/agent/hwctl/executor/openbmc_flash.py new file mode 100644 index 000000000..ecfc19f13 --- /dev/null +++ b/xCAT-openbmc-py/lib/python/agent/hwctl/executor/openbmc_flash.py @@ -0,0 +1,562 @@ +#!/usr/bin/env python +############################################################################### +# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html +############################################################################### +# -*- coding: utf-8 -*- +# +from __future__ import print_function +import gevent +import time +import os, re + +from common import utils +from common.task import ParallelNodesCommand +from common.exceptions import SelfClientException, SelfServerException +from hwctl import openbmc_client as openbmc + +import logging +logger = logging.getLogger('xcatagent') + +XCAT_LOG_DIR = "/var/log/xcat" +XCAT_LOG_RFLASH_DIR = XCAT_LOG_DIR + "/rflash/" + +class OpenBMCFlashTask(ParallelNodesCommand): + """Executor for flash-related actions.""" + activate_result = {} + firmware = {} + firmware_file = None + log_handle = {} + nodes_num = 0 + + def _msg_process(self, node, msg, msg_type='I', update_rc=False, checkv=False): + + if msg_type == 'E': + self.callback.error(msg, node) + elif not checkv: + self.callback.info('%s: %s' % (node, msg)) + elif self.verbose: + self.callback.info('%s: %s' % (node, msg)) + + if update_rc: + self.activate_result.update({node: msg}) + + if node not in self.log_handle: + log_file = XCAT_LOG_RFLASH_DIR + '/' + node + '.log' + self.log_handle.update({node: open(log_file, 'a')}) + try: + self.log_handle[node].writelines(msg + '\n') + self.log_handle[node].flush() + except Exception as e: + self.callback.error('Failed to record rflash log for node %s' % node) + + def _firmware_file_check(self, firmware_file, **kw): + + target_file = utils.get_full_path(self.cwd, firmware_file) + self.firmware_file = target_file + + if (not os.access(target_file, os.F_OK) or + not os.access(target_file, os.R_OK)): + error = 'Cannot access %s. Check the management ' \ + 'node and/or service nodes.' % target_file + self.callback.error(error) + raise Exception('Invalid firmware file %s' % target_file) + + def validate_activate_firm(self, task, activate_arg, **kw): + + if activate_arg.endswith('.tar'): + self._firmware_file_check(activate_arg) + else: + if not re.match('\A[0-9a-fA-F]+\Z', activate_arg): + self.callback.error('Invalid firmware ID %s' % activate_arg) + + def validate_delete_firm(self, task, delete_id, **kw): + + if not re.match('\A[0-9a-fA-F]+\Z', delete_id): + self.callback.error('Invalid firmware ID %s' % activate_arg) + + def validate_upload_firm(self, task, upload_file, **kw): + + self._firmware_file_check(upload_file) + + def _get_firmware_version(self, target_file): + + grep_cmd = '/usr/bin/grep -a' + version_cmd = grep_cmd + ' ^version= ' + target_file + purpose_cmd = grep_cmd + ' purpose= ' + target_file + firmware = os.popen(version_cmd).readlines()[0].split('=')[-1].strip() + purpose = os.popen(purpose_cmd).readlines()[0].split('=')[-1].strip().split('.')[-1] + return { firmware: {'purpose': purpose} } + + def pre_activate_firm(self, task, activate_arg, **kw): + + if not os.path.exists(XCAT_LOG_RFLASH_DIR): + os.makedirs(XCAT_LOG_RFLASH_DIR) + + if activate_arg.endswith('.tar'): + version = self._get_firmware_version() + self.firmware.update(version) + self.callback.info('Attempting to upload %s, please wait...' % self.firmware_file) + else: + self.callback.info('Attempting to activate ID=%s, please wait..' % activate_arg) + self.nodes_num = len(self.inventory) + + def pre_delete_firm(self, task, delete_id, **kw): + + self.callback.info('Attempting to delete ID=%s, please wait..' % delete_id) + + def pre_flash_process(self, task, directory, no_host_reboot, **kw): + + if not os.path.exists(XCAT_LOG_RFLASH_DIR): + os.makedirs(XCAT_LOG_RFLASH_DIR) + + directory = utils.get_full_path(self.cwd, directory) + tmp_dict = {'BMC': [], 'Host': []} + for filename in os.listdir(directory): + if filename.endswith('.tar'): + filename = os.path.join(directory, filename) + try: + version = self._get_firmware_version(filename) + except Exception as e: + continue + self.firmware.update(version) + for key, value in version.items(): + tmp_dict[ value['purpose'] ].append(filename) + self.firmware[key].update({'file': filename}) + + bmc_file_num = len(tmp_dict['BMC']) + host_file_num = len(tmp_dict['Host']) + error = None + if not bmc_file_num: + error = 'No BMC tar file found in %s' % directory + elif not host_file_num: + error = 'No HOST tar file found in %s' % directory + elif bmc_file_num > 1: + error = 'More than 1 BMC tar file %s found in %s' \ + % (' '.join(tmp_dict['BMC']), directory) + elif host_file_num > 1: + error = 'More than 1 HOST tar file %s found in %s' \ + % (' '.join(tmp_dict['Host']), directory) + if error: + self.callback.error(error) + raise Exception('No or More tar file found') + + self.callback.info('Attempting to upload %s and %s, please wait..' \ + % (tmp_dict['BMC'][0], tmp_dict['Host'][0])) + self.nodes_num = len(self.inventory) + + def pre_upload_firm(self, task, upload_arg, **kw): + + if not os.path.exists(XCAT_LOG_RFLASH_DIR): + os.makedirs(XCAT_LOG_RFLASH_DIR) + self.callback.info('Attempting to upload %s, please wait...' % self.firmware_file) + + def _get_firm_id(self, obmc, node): + + mapping_ids = [] + if self.firmware: + version_list = self.firmware.keys() + else: + return [] + + for i in range(6): + try: + has_functional, firm_obj_dict = obmc.list_firmware() + except (SelfServerException, SelfClientException) as e: + self._msg_process(node, e.message, msg_type='E', update_rc=True) + return [] + + for key, value in firm_obj_dict.items(): + if value.version and value.version in version_list: + firm_id = key.split('-')[-1] + mapping_ids.append(firm_id) + msg = 'Firmware upload successful. ' \ + 'Attempting to activate firmware: %s (ID: %s)' \ + % (value.version, firm_id) + self._msg_process(node, msg, update_rc=True) + version_list.remove(value.version) + + if not version_list: + return mapping_ids + for i in version_list: + msg = 'Could not find ID for firmware %s to '\ + 'activate, waiting %d seconds and retry...' \ + % (i, 10) + self._msg_process(node, msg, update_rc=True, checkv=True) + gevent.sleep ( 10 ) + + error = [] + for i in version_list: + msg = 'Could not find firmware %s after waiting %d seconds.' % (i, 10*6) + error.qppend(msg) + self._msg_process(node, msg, msg_type='E') + + if error: + msg = ' '.join(error) + self.activate_result.update({node: msg}) + return [] + + def _check_id_status(self, obmc, check_ids, node, only_act=True): + + firm_ids = check_ids + priority_ids = [] + process_status = {} + for i in range(80): + try: + has_functional, firm_obj_dict = obmc.list_firmware() + except (SelfServerException, SelfClientException) as e: + return self._msg_process(node, e.message, msg_type='E', update_rc=True) + + for key, value in firm_obj_dict.items(): + key_id = key.split('-')[-1] + if key_id in firm_ids: + activation_state = value.active + firm_version = value.version + if activation_state == 'Failed': + activation_msg = 'Firmware %s activation failed.' % (firm_version) + self._msg_process(node, activation_msg, msg_type='E', update_rc=True) + firm_ids.remove(key_id) + if activation_state == 'Active': + activation_msg = 'Firmware %s activation successful.' % (firm_version) + self._msg_process(node, activation_msg, update_rc=True) + firm_ids.remove(key_id) + if value.priority != 0: + priority_ids.append(key_id) + if activation_state == 'Activating': + activating_progress_msg = 'Activating %s ... %s%%' \ + % (firm_version, value.progress) + process_status[key_id] = activating_progress_msg + self._msg_process(node, activating_progress_msg, checkv=True) + + if not firm_ids: + break + gevent.sleep( 15 ) + + error = [] + for i in firm_ids: + msg = 'After %d seconds check the firmware id %s current status is "%s"' \ + % (80*15, process_status[i], i) + error.append(msg) + self._msg_process(node, msg, msg_type='E') + + if error: + msg = ' '.join(error) + self.activate_result.update({node: msg}) + return + + for i in priority_ids: + try: + obmc.set_priority(i) + except (SelfServerException, SelfClientException) as e: + msg = e.message + error.append(msg) + self._msg_process(node, msg, msg_type='E') + + if error: + msg = ' '.join(error) + self.activate_result.update({node: msg}) + return + + self.activate_result.update({node: 'SUCCESS'}) + + def _reboot_to_effect(self, obmc, no_host_reboot, node): + + self._msg_process(node, 'Firmware will be flashed on reboot, deleting all BMC diagnostics...') + try: + obmc.clear_dump('all') + except (SelfServerException, SelfClientException) as e: + self.callback.warn('%s: Could not clear BMC diagnostics successfully %s, ignoring...' % (node, e.message)) + + try: + obmc.reboot_bmc() + except (SelfServerException, SelfClientException) as e: + return self._msg_process(node, e.message, msg_type='E', update_rc=True) + + self._msg_process(node, openbmc.RPOWER_STATES['bmcreboot'], update_rc=True) + + gevent.sleep( 10 ) + + bmc_state = None + for i in range(20): + try: + obmc.login() + state = obmc.get_bmc_state() + bmc_state = state.get('bmc') + + if bmc_state == 'Ready': + break + except (SelfServerException, SelfClientException) as e: + self._msg_process(node, e.message, checkv=True) + + self._msg_process(node, 'Retry BMC state, wait for 15 seconds ...', update_rc=True) + gevent.sleep( 15 ) + + if bmc_state != 'Ready': + error = 'Sent bmcreboot but state did not change to BMC Ready after ' \ + 'waiting %s seconds. (State=BMC %s).' % (20*15, bmc_state) + return self._msg_process(node, error, msg_type='E', update_rc=True) + + self._msg_process(node, 'BMC %s' % bmc_state, update_rc=True) + + if no_host_reboot: + self.activate_result.update({node: 'SUCCESS'}) + return + + try: + obmc.set_power_state('off') + self.callback.update_node_attributes('status', node, 'powering-off') + + off_flag = False + start_timeStamp = int(time.time()) + for i in range (0, 30): + states = obmc.list_power_states() + state = obmc.get_host_state(states) + if openbmc.RPOWER_STATES.get(state) == 'off': + off_flag = True + break + gevent.sleep( 2 ) + + end_timeStamp = int(time.time()) + + if not off_flag: + error = 'Error: Sent power-off command but state did not change ' \ + 'to off after waiting %s seconds. (State= %s).' % (end_timeStamp - start_timeStamp, status) + return self._msg_process(node, error, update_rc=True) + + ret = obmc.set_power_state('on') + self.callback.update_node_attributes('status', node, 'powering-on') + + self._msg_process(node, 'reset') + self.activate_result.update({node: 'SUCCESS'}) + except (SelfServerException, SelfClientException) as e: + self._msg_process(node, e.message, update_rc=True) + + def activate_firm(self, activate_arg, **kw): + + node = kw['node'] + obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback, + debugmode=self.debugmode, verbose=self.verbose) + + try: + obmc.login() + except (SelfServerException, SelfClientException) as e: + return self._msg_process(node, e.message, msg_type='E', update_rc=True) + + firmware_version = '' + if self.firmware_file: + firmware_version = self.firmware.keys()[0] + try: + obmc.upload_firmware(self.firmware_file) + except (SelfServerException, SelfClientException) as e: + return self._msg_process(node, e.message, msg_type='E', update_rc=True) + + activate_ids = self._get_firm_id(obmc, node) + if not activate_ids: + return + activate_id = activate_ids[0] + else: + activate_id = activate_arg + + error = '' + try: + obmc.activate_firmware(activate_id) + except SelfServerException as e: + error = e.message + except SelfClientException as e: + if e.code == 403: + error = 'Invalid ID provided to activate. ' \ + 'Use the -l option to view valid firmware IDs.' + else: + error = e.message + if error: + return self._msg_process(node, error, msg_type='E', update_rc=True) + + msg = 'rflash %s started, please wait...' % firmware_version + self._msg_process(node, msg, checkv=True) + + check_ids = [activate_id] + self._check_id_status(obmc, check_ids, node) + + def delete_firm(self, delete_id, **kw): + + node = kw['node'] + obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback, + debugmode=self.debugmode, verbose=self.verbose) + + error = '' + try: + obmc.login() + except (SelfServerException, SelfClientException) as e: + return self.callback.error(e.message, node) + + try: + has_functional, firm_obj_dict = obmc.list_firmware() + except (SelfServerException, SelfClientException) as e: + return self.callback.error(e.message, node) + + host_flag = False + for key, value in firm_obj_dict.items(): + key_id = key.split('-')[-1] + if key_id != delete_id: + continue + if value.functional or (value.priority == 0 and not has_functional): + if value.purpose == 'BMC': + return self.callback.error('Deleting currently active BMC firmware' \ + ' is not supported', node) + elif value.purpose == 'Host': + host_flag = True + break + else: + self.callback.error('Unable to determine the purpose of the ' \ + 'firmware to delete', node) + + if host_flag: + try: + states = obmc.list_power_states() + state = obmc.get_host_state(states) + if openbmc.RPOWER_STATES.get(state) == 'on': + return self.callback.error('Deleting currently active firmware on' \ + ' powered on host is not supported', node) + except (SelfServerException, SelfClientException) as e: + return self.callback.error(e.message, node) + + try: + obmc.delete_firmware(delete_id) + except SelfServerException as e: + error = e.message + except SelfClientException as e: + if e.code == 404: + error = 'Invalid ID provided to delete. ' \ + 'Use the -l option to view valid firmware IDs.' + else: + error = e.message + + if error: + self.callback.error(error, node) + else: + self.callback.info('%s: [%s] Firmware removed' % (node, delete_id)) + + def flash_process(self, directory, no_host_reboot, **kw): + + node = kw['node'] + obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback, + debugmode=self.debugmode, verbose=self.verbose) + + try: + obmc.login() + except (SelfServerException, SelfClientException) as e: + return self._msg_process(node, e.message, msg_type='E', update_rc=True) + + try: + for key, value in self.firmware.items(): + obmc.upload_firmware(value['file']) + except (SelfServerException, SelfClientException) as e: + return self._msg_process(node, e.message, msg_type='E', update_rc=True) + + activate_ids = self._get_firm_id(obmc, node) + if not activate_ids: + return + + for i in activate_ids: + error = '' + try: + obmc.activate_firmware(i) + except SelfServerException as e: + error = e.message + except SelfClientException as e: + if e.code == 403: + error = 'Invalid ID %s provided to activate. Use the -l option ' \ + 'to view valid firmware IDs.' % i + else: + error = e.message + if error: + return self._msg_process(node, error, msg_type='E', update_rc=True) + + for key in self.firmware: + msg = 'rflash %s started, please wait...' % key + self._msg_process(node, msg, checkv=True) + + self._check_id_status(obmc, activate_ids, node, only_act=False) + + self._reboot_to_effect(obmc, no_host_reboot, node) + + def list_firm_info(self, **kw): + + node = kw['node'] + obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback, + debugmode=self.debugmode, verbose=self.verbose) + + firm_info = [] + try: + obmc.login() + has_functional, firm_obj_dict = obmc.list_firmware() + + except (SelfServerException, SelfClientException) as e: + return self.callback.error(e.message, node) + + firm_info.append('%-8s %-7s %-10s %-s' % ('ID', 'Purpose', 'State', 'Version')) + firm_info.append('-' * 55) + + for key, value in firm_obj_dict.items(): + status = value.active + if value.functional: + status += '(*)' + elif value.priority == 0: + if not has_functional: + status += '(*)' + else: + status += '(+)' + + firm_info.append('%-8s %-7s %-10s %-s' % (key.split('-')[-1], + value.purpose, status, value.version)) + + for info in firm_info: + self.callback.info('%s: %s' % (node, info)) + + return firm_info + + def upload_firm(self, upload_file, **kw): + + node = kw['node'] + obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback, + debugmode=self.debugmode, verbose=self.verbose) + + try: + obmc.login() + except (SelfServerException, SelfClientException) as e: + return self._msg_process(node, e.message, msg_type='E') + + try: + obmc.upload_firmware(self.firmware_file) + self._msg_process(node, 'Firmware upload successful. Use -l option to list.') + except (SelfServerException, SelfClientException) as e: + return self._msg_process(node, e.message, msg_type='E') + + def _flash_summary(self): + + if not self.activate_result: + return self.callback.error('No summary infomation') + + success_num = failed_num = 0 + failed_list = [] + for key, value in self.activate_result.items(): + if value == 'SUCCESS': + success_num += 1 + else: + failed_num += 1 + failed_list.append('%s: %s' % (key, value)) + + self.callback.info('-' * 55) + self.callback.info('%s complete: Total=%d Success=%d Failed=%d' % \ + ('Firmware update', self.nodes_num, success_num, failed_num)) + + for i in failed_list: + self.callback.info(i) + self.callback.info('-' * 55) + + def post_activate_firm(self, task, activate_arg, **kw): + + self._flash_summary() + + def post_flash_process(self, task, directory, no_host_reboot, **kw): + + self._flash_summary() diff --git a/xCAT-openbmc-py/lib/python/agent/hwctl/executor/openbmc_inventory.py b/xCAT-openbmc-py/lib/python/agent/hwctl/executor/openbmc_inventory.py index 4ff829b46..6cd2ea871 100644 --- a/xCAT-openbmc-py/lib/python/agent/hwctl/executor/openbmc_inventory.py +++ b/xCAT-openbmc-py/lib/python/agent/hwctl/executor/openbmc_inventory.py @@ -8,6 +8,7 @@ from __future__ import print_function import gevent import time +import os from common.task import ParallelNodesCommand from common.exceptions import SelfClientException, SelfServerException @@ -20,6 +21,30 @@ logger = logging.getLogger('xcatagent') class OpenBMCInventoryTask(ParallelNodesCommand): """Executor for inventory-related actions.""" + def pre_get_firm_info(self, task, target_file=None, **kw): + + if not target_file: + return + + target_file = utils.get_full_path(self.cwd, target_file) + + grep_cmd = '/usr/bin/grep -a' + version_cmd = grep_cmd + ' ^version= ' + target_file + purpose_cmd = grep_cmd + ' purpose= ' + target_file + purpose_ver = os.popen(purpose_cmd).readlines() + firmware_ver = os.popen(version_cmd).readlines() + if purpose_ver: + purpose_ver = purpose_ver[0].split('=')[-1].strip() + else: + purpose_ver = '' + if firmware_ver: + firmware_ver = firmware_ver[0].split('=')[-1].strip() + else: + firmware_ver = '' + + self.callback.info('TAR %s Firmware Product Version: %s' \ + % (purpose_ver,firmware_ver)) + def _get_firm_info(self, firm_info_list): (has_functional, firm_obj_dict) = firm_info_list firm_info = [] @@ -97,7 +122,7 @@ class OpenBMCInventoryTask(ParallelNodesCommand): return inventory_info - def get_firm_info(self, **kw): + def get_firm_info(self, target_file=None, **kw): node = kw['node'] obmc = openbmc.OpenBMCRest(name=node, nodeinfo=kw['nodeinfo'], messager=self.callback, diff --git a/xCAT-openbmc-py/lib/python/agent/hwctl/executor/openbmc_power.py b/xCAT-openbmc-py/lib/python/agent/hwctl/executor/openbmc_power.py index 024f455cf..ae3d8fd8c 100644 --- a/xCAT-openbmc-py/lib/python/agent/hwctl/executor/openbmc_power.py +++ b/xCAT-openbmc-py/lib/python/agent/hwctl/executor/openbmc_power.py @@ -26,25 +26,6 @@ POWER_STATE_DB = { class OpenBMCPowerTask(ParallelNodesCommand): """Executor for power-related actions.""" - def _determine_state(self, states): - - chassis_state = states.get('chassis') - host_state = states.get('host') - state = 'Unknown' - if chassis_state == 'Off': - state = chassis_state - - elif chassis_state == 'On': - if host_state == 'Off': - state = 'chassison' - elif host_state in ['Quiesced', 'Running']: - state = host_state - else: - state = 'Unexpected host state=%s' % host_state - else: - state = 'Unexpected chassis state=%s' % chassis_state - return state - def get_state(self, **kw): node = kw['node'] @@ -54,7 +35,7 @@ class OpenBMCPowerTask(ParallelNodesCommand): try: obmc.login() states = obmc.list_power_states() - state = self._determine_state(states) + state = obmc.get_host_state(states) self.callback.info('%s: %s' % (node, openbmc.RPOWER_STATES.get(state, state))) except (SelfServerException, SelfClientException) as e: @@ -115,7 +96,7 @@ class OpenBMCPowerTask(ParallelNodesCommand): try: obmc.login() states = obmc.list_power_states() - status = self._determine_state(states) + status = obmc.get_host_state(states) new_status ='' if optype == 'reset' and status in ['Off', 'chassison']: @@ -130,7 +111,7 @@ class OpenBMCPowerTask(ParallelNodesCommand): start_timeStamp = int(time.time()) for i in range (0, 30): states = obmc.list_power_states() - status = self._determine_state(states) + status = obmc.get_host_state(states) if openbmc.RPOWER_STATES.get(status) == 'off': off_flag = True break diff --git a/xCAT-openbmc-py/lib/python/agent/hwctl/flash.py b/xCAT-openbmc-py/lib/python/agent/hwctl/flash.py new file mode 100644 index 000000000..8f30612ca --- /dev/null +++ b/xCAT-openbmc-py/lib/python/agent/hwctl/flash.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +############################################################################### +# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html +############################################################################### +# -*- coding: utf-8 -*- +# + +class FlashInterface(object): + """Interface for flash-related actions.""" + interface_type = 'flash' + version = '1.0' + + def activate_firm(self, task, activate_arg): + """Activate firmware. + + :param task: a Task instance containing the nodes to act on. + :activate_arg: arg for activate + """ + return task.run('activate_firm', activate_arg) + + def delete_firm(self, task, delete_id): + """Delete firmware. + + :param task: a Task instance containing the nodes to act on. + :param delete_id: firmware id want to delete + """ + return task.run('delete_firm', delete_id) + + def flash_process(self, task, directory, no_host_reboot): + """Upload and activate firmware + + :param task: a Task instance containing the nodes to act on. + :directory: firmware directory + """ + return task.run('flash_process', directory, no_host_reboot) + + def list_firm_info(self, task): + """List firmware + + :param task: a Task instance containing the nodes to act on. + """ + return task.run('list_firm_info') + + def upload_firm(self, task, upload_file): + """Upload firmware file. + + :param task: a Task instance containing the nodes to act on. + :param upload_file: the file want to upload + """ + return task.run('upload_firm', upload_file) + +class DefaultFlashManager(FlashInterface): + """Interface for flash-related actions.""" + pass diff --git a/xCAT-openbmc-py/lib/python/agent/hwctl/inventory.py b/xCAT-openbmc-py/lib/python/agent/hwctl/inventory.py index 9a85daa09..9709f1659 100644 --- a/xCAT-openbmc-py/lib/python/agent/hwctl/inventory.py +++ b/xCAT-openbmc-py/lib/python/agent/hwctl/inventory.py @@ -19,13 +19,14 @@ class InventoryInterface(object): """ return task.run('get_info', inventory_type) - def get_firm_info(self, task): + def get_firm_info(self, task, target_arg=None): """Return the firm info of the task's nodes. :param task: a Task instance containing the nodes to act on. + :param check_arg: firmware file to check, for rflash check :return firm info list """ - return task.run('get_firm_info') + return task.run('get_firm_info', target_arg) class DefaultInventoryManager(InventoryInterface): """Interface for inventory-related actions.""" diff --git a/xCAT-openbmc-py/lib/python/agent/hwctl/openbmc_client.py b/xCAT-openbmc-py/lib/python/agent/hwctl/openbmc_client.py index b1654a884..da347fa82 100644 --- a/xCAT-openbmc-py/lib/python/agent/hwctl/openbmc_client.py +++ b/xCAT-openbmc-py/lib/python/agent/hwctl/openbmc_client.py @@ -145,15 +145,15 @@ BOOTSOURCE_SET_STATE = { FIRM_URLS = { "activate" : { - "path" : "/software/%(id)s/attr/RequestedActivation", - "field" : "Software.Activation.RequestedActivations.Active", + "path" : "/software/%s/attr/RequestedActivation", + "field" : "xyz.openbmc_project.Software.Activation.RequestedActivations.Active", }, "delete" : { - "path" : "/software/%(id)s/action/Delete", + "path" : "/software/%s/action/Delete", "field" : [], }, "priority" : { - "path" : "/software/%(id)s/attr/Priority", + "path" : "/software/%s/attr/Priority", "field" : False, }, "list" : { @@ -426,6 +426,25 @@ class OpenBMCRest(object): # TODO: Need special handling for bmc reset, as it is normal bmc may return error pass + def get_host_state(self, states): + + chassis_state = states.get('chassis') + host_state = states.get('host') + state = 'Unknown' + if chassis_state == 'Off': + state = chassis_state + + elif chassis_state == 'On': + if host_state == 'Off': + state = 'chassison' + elif host_state in ['Quiesced', 'Running']: + state = host_state + else: + state = 'Unexpected host state=%s' % host_state + else: + state = 'Unexpected chassis state=%s' % chassis_state + return state + def set_one_time_boot_enable(self, enabled): payload = { "data": enabled } @@ -542,6 +561,18 @@ class OpenBMCRest(object): error = 'Received wrong format response: %s' % inventory_data raise SelfServerException(error) + def activate_firmware(self, activate_id): + + payload = { "data": FIRM_URLS['activate']['field'] } + url = FIRM_URLS['activate']['path'] % activate_id + return self.request('PUT', url, payload=payload, cmd='activate_firmware') + + def delete_firmware(self, delete_id): + + payload = { "data": FIRM_URLS['delete']['field'] } + url = FIRM_URLS['delete']['path'] % delete_id + return self.request('POST', url, payload=payload, cmd='delete_firmware') + def list_firmware(self): data = self.request('GET', FIRM_URLS['list']['path'], cmd='list_firmware') @@ -564,6 +595,18 @@ class OpenBMCRest(object): return bool(func_list), fw_dict + def upload_firmware(self, upload_file): + + headers = {'Content-Type': 'application/octet-stream'} + path = HTTP_PROTOCOL + self.bmcip + '/upload/image/' + self.upload('PUT', path, upload_file, headers=headers, cmd='upload_firmware') + + def set_priority(self, firm_id): + + payload = { "data": FIRM_URLS['priority']['field'] } + url = FIRM_URLS['priority']['path'] % firm_id + return self.request('PUT', url, payload=payload, cmd='set_priority') + # Extract all eventlog info and parse it def get_eventlog_info(self): diff --git a/xCAT-openbmc-py/lib/python/agent/xcatagent/openbmc.py b/xCAT-openbmc-py/lib/python/agent/xcatagent/openbmc.py index 6d382d140..6dff2526f 100644 --- a/xCAT-openbmc-py/lib/python/agent/xcatagent/openbmc.py +++ b/xCAT-openbmc-py/lib/python/agent/xcatagent/openbmc.py @@ -16,6 +16,7 @@ from common import utils from common import exceptions as xcat_exception from hwctl.executor.openbmc_beacon import OpenBMCBeaconTask from hwctl.executor.openbmc_setboot import OpenBMCBootTask +from hwctl.executor.openbmc_flash import OpenBMCFlashTask from hwctl.executor.openbmc_inventory import OpenBMCInventoryTask from hwctl.executor.openbmc_power import OpenBMCPowerTask from hwctl.executor.openbmc_sensor import OpenBMCSensorTask @@ -23,6 +24,7 @@ from hwctl.executor.openbmc_bmcconfig import OpenBMCBmcConfigTask from hwctl.executor.openbmc_eventlog import OpenBMCEventlogTask from hwctl.beacon import DefaultBeaconManager from hwctl.setboot import DefaultBootManager +from hwctl.flash import DefaultFlashManager from hwctl.inventory import DefaultInventoryManager from hwctl.power import DefaultPowerManager from hwctl.sensor import DefaultSensorManager @@ -30,7 +32,6 @@ from hwctl.bmcconfig import DefaultBmcConfigManager from hwctl.eventlog import DefaultEventlogManager from xcatagent import base -import openbmc_rest import logging logger = logging.getLogger('xcatagent') if not logger.handlers: @@ -50,38 +51,6 @@ all_nodes_result = {} # global variables of rbeacon BEACON_SET_OPTIONS = ('on', 'off') -# 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, - } -} - RSPCONFIG_GET_OPTIONS = ['ip','ipsrc','netmask','gateway','vlan','ntpservers','hostname','bootmode','autoreboot','powersupplyredundancy','powerrestorepolicy'] RSPCONFIG_SET_OPTIONS = { 'ip':'.*', @@ -126,12 +95,6 @@ The supported attributes and its values to set are: powerrestorepolicy={always_on|always_off|restore} """ % RSPCONFIG_GET_OPTIONS -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 rinv INVENTORY_OPTIONS = ('all', 'cpu', 'dimm', 'firm', 'model', 'serial') @@ -151,452 +114,6 @@ VITALS_OPTIONS = ('all', 'altitude', 'fanspeed', 'leds', 'power', # global variables of reventlog EVENTLOG_OPTIONS = ('list', 'clear', 'resolved') -class OpenBMC(base.BaseDriver): - - headers = {'Content-Type': 'application/json'} - - def __init__(self, messager, name, node_info): - super(OpenBMC, self).__init__(messager) - self.node = name - for key, value in node_info.items(): - setattr(self, key, value) - global DEBUGMODE - self.client = openbmc_rest.OpenBMCRest(name, messager, DEBUGMODE) - - 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, 'login') - return RESULT_OK - - 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 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') - - 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() - - class OpenBMCManager(base.BaseManager): def __init__(self, messager, cwd, nodes=None, envs=None): super(OpenBMCManager, self).__init__(messager, cwd) @@ -642,6 +159,51 @@ class OpenBMCManager(base.BaseManager): runner = OpenBMCBeaconTask(nodesinfo, callback=self.messager, debugmode=self.debugmode, verbose=self.verbose) DefaultBeaconManager().set_beacon_state(runner, beacon_state=action) + def rflash(self, nodesinfo, args): + + # 1, parse agrs + rflash_usage = """ + Usage: + rflash [[-a|--activate ] | [-c|--check ] | [-d [--no-host-reboot]] | [--delete ] | [-l|--list] | [-u|--upload ]] [-V|--verbose] + + Options: + -V,--verbose Show verbose message + -a,--activate Activate firmware + -c,--check Check firmware info + -d Upload and activate all firmware files under directory + -l,--list List firmware info + -u,--upload Upload firmware file + --delete Delete firmware + --no-host-reboot Not reboot host after activate + """ + + try: + opts = docopt(rflash_usage, argv=args) + self.verbose = opts.pop('--verbose') + except Exception as e: + self.messager.error("Failed to parse arguments for rflash: %s" % args) + return + + if opts['--check']: + check_arg = None + if opts['']: + check_arg = opts[''] + runner = runner = OpenBMCInventoryTask(nodesinfo, callback=self.messager, debugmode=self.debugmode, verbose=self.verbose, cwd=self.cwd[0]) + DefaultInventoryManager().get_firm_info(runner, check_arg) + return + + runner = OpenBMCFlashTask(nodesinfo, callback=self.messager, debugmode=self.debugmode, verbose=self.verbose, cwd=self.cwd[0]) + if opts['--activate']: + DefaultFlashManager().activate_firm(runner, opts['--activate'][0]) + elif opts['--list']: + DefaultFlashManager().list_firm_info(runner) + elif opts['-d']: + DefaultFlashManager().flash_process(runner, opts['-d'], opts['--no-host-reboot']) + elif opts['--delete']: + DefaultFlashManager().delete_firm(runner, opts['--delete']) + elif opts['--upload']: + DefaultFlashManager().upload_firm(runner, opts['--upload'][0]) + def rinv(self, nodesinfo, args): # 1, parse agrs @@ -715,6 +277,7 @@ class OpenBMCManager(base.BaseManager): DefaultPowerManager().reboot(runner, optype=action) else: DefaultPowerManager().set_power_state(runner, power_state=action) + def rspconfig(self, nodesinfo, args): try: opts=docopt(RSPCONFIG_USAGE, argv=args) @@ -768,6 +331,7 @@ class OpenBMCManager(base.BaseManager): DefaultBmcConfigManager().set_attributes(runner, opts['']) else: self.messager.error("Failed to deal with rspconfig: %s" % args) + def rsetboot(self, nodesinfo, args): # 1, parse args @@ -884,98 +448,3 @@ class OpenBMCManager(base.BaseManager): else: DefaultEventlogManager().get_eventlog_info(runner, "all") - 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') - diff --git a/xCAT-openbmc-py/lib/python/agent/xcatagent/openbmc_rest.py b/xCAT-openbmc-py/lib/python/agent/xcatagent/openbmc_rest.py deleted file mode 100644 index 9dcf8c99e..000000000 --- a/xCAT-openbmc-py/lib/python/agent/xcatagent/openbmc_rest.py +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env python -import requests -import json -import time - -from common import rest -from common import exceptions as 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 diff --git a/xCAT-server/lib/xcat/plugins/openbmc2.pm b/xCAT-server/lib/xcat/plugins/openbmc2.pm index ea84911e0..50cd4d039 100644 --- a/xCAT-server/lib/xcat/plugins/openbmc2.pm +++ b/xCAT-server/lib/xcat/plugins/openbmc2.pm @@ -231,7 +231,6 @@ sub parse_args { } } 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); }