def unloadchifhandle(self, lib): """Release a handle on the chif hprest library :param lib: The library handle provided by loading the chif library. :type lib: library handle. """ BlobStore2.unloadchifhandle(lib)
def __init__(self, base_url, default_prefix='/rest/v1', username=None, \ password=None, sessionkey=None, is_redfish=False, \ cache=False, proxy=None): """Initialize Blobstore2RestClient :param base_url: The url of the remote system :type base_url: str :param username: The username used for authentication :type username: str :param password: The password used for authentication :type password: str :param default_prefix: The default root point :type default_prefix: str :param biospassword: biospassword for base_url if needed :type biospassword: str :param sessionkey: sessionkey for the current login of base_url :type sessionkey: str :param is_redfish: flag for checking redfish :type is_redfish: bool """ self.is_redfish = is_redfish self.creds = not cache try: if not cache: correctcreds = BlobStore2.initializecreds(username=username, \ password=password) bs2 = BlobStore2() if not correctcreds: security_state = int(bs2.get_security_state()) raise SecurityStateError(security_state) except Blob2SecurityError: raise InvalidCredentialsError(0) except HpIloChifPacketExchangeError as excp: LOGGER.info("Exception: %s", str(excp)) raise ChifDriverMissingOrNotFound() except Exception as excp: if excp.message == 'chif': raise ChifDriverMissingOrNotFound() else: raise super(Blobstore2RestClient, self).__init__(base_url, \ username=username, password=password, \ default_prefix=default_prefix, sessionkey=sessionkey,\ cache=cache, is_redfish=is_redfish)
def create_new_chif_for_upload(self, user, passwrd): dll = BlobStore2.gethprestchifhandle() dll.ChifInitialize(None) # Enable Security Flag in Chif dll.ChifEnableSecurity() fhandle = c_void_p() dll.ChifCreate.argtypes = [c_void_p] dll.ChifCreate.restype = c_uint32 status = dll.ChifCreate(byref(fhandle)) if status != BlobReturnCodes.SUCCESS: raise HpIloInitialError( "Error %s occurred while trying to create a channel." % status) dll.initiate_credentials.argtypes = [c_char_p, c_char_p] dll.initiate_credentials.restype = POINTER(c_ubyte) usernew = create_string_buffer(user.encode('utf-8')) passnew = create_string_buffer(passwrd.encode('utf-8')) dll.initiate_credentials(usernew, passnew) status = dll.ChifPing(fhandle) if status != BlobReturnCodes.SUCCESS: raise HpIloInitialError( "Error %s occurred while trying to create a channel." % status) dll.ChifSetRecvTimeout(fhandle, 60000) credreturn = dll.ChifVerifyCredentials() if not credreturn == BlobReturnCodes.SUCCESS: if credreturn == BlobReturnCodes.CHIFERR_AccessDenied: raise Blob2SecurityError() else: raise HpIloInitialError("Error %s occurred while trying " \ "to open a channel to iLO" % credreturn) return dll, fhandle
def preparefwpkg(self, pkgfile): """ Prepare fwpkg file for flashing :param pkgfile: Location of the .fwpkg file :type pkgfile: string. :returns: returns the files needed to flash, directory they are located in, and type of file. :rtype: string, string, string """ files = [] imagefiles = [] payloaddata = None tempdir = tempfile.mkdtemp() try: zfile = zipfile.ZipFile(pkgfile) zfile.extractall(tempdir) zfile.close() except Exception as excp: raise InvalidFileInputError("Unable to unpack file. " + str(excp)) files = os.listdir(tempdir) if 'payload.json' in files: with open(os.path.join(tempdir, 'payload.json'), "r") as pfile: data = pfile.read() payloaddata = json.loads(data) else: raise InvalidFileInputError( "Unable to find payload.json in fwpkg file.") comptype = _get_comp_type(payloaddata) if comptype == 'C': imagefiles = [self.type_c_change(tempdir, pkgfile)] else: results = self._rdmc.app.getprops(selector="UpdateService.", \ props=['Oem/Hpe/Capabilities']) for device in payloaddata['Devices']['Device']: for firmwareimage in device['FirmwareImages']: if firmwareimage['FileName'] not in imagefiles: imagefiles.append(firmwareimage['FileName']) if comptype in ['A','B'] and results and 'UpdateFWPKG' in results[0]['Oem']['Hpe']\ ['Capabilities']: dll = BlobStore2.gethprestchifhandle() dll.isFwpkg20.argtypes = [c_char_p, c_int] dll.isFwpkg20.restype = c_bool with open(pkgfile, 'rb') as fwpkgfile: fwpkgdata = fwpkgfile.read() fwpkg_buffer = ctypes.create_string_buffer(fwpkgdata) if dll.isFwpkg20(fwpkg_buffer, 2048): imagefiles = [pkgfile] tempdir = '' return imagefiles, tempdir, comptype
def gethprestchifhandle(self): """ Load the chif hprest library """ try: lib = BlobStore2.gethprestchifhandle() except Exception as excp: lib = None return lib
def updatecredentials(self): """update credentials for high security if needed """ if not self.creds: user = self._RestClientBase__username password = self._RestClientBase__password try: correctcreds = BlobStore2.initializecreds(username=user, \ password=password) if not correctcreds: security_state = int(BlobStore2().get_security_state()) raise SecurityStateError(security_state) except Blob2SecurityError: raise InvalidCredentialsError(0) except Exception: raise self.creds = True
def get_client_instance(base_url=None, username=None, password=None, \ default_prefix='/rest/v1', biospassword=None, \ sessionkey=None, is_redfish=False, cache=False, \ proxy=None): """Create and return appropriate RESTful/REDFISH client instance. Instantiates appropriate Rest/Redfish object based on existing configuration. Use this to retrieve a pre-configured Rest object :param base_url: rest host or ip address. :type base_url: str. :param username: username required to login to server :type: str :param password: password credentials required to login :type password: str :param default_prefix: default root to extract tree :type default_prefix: str :param biospassword: BIOS password for the server if set :type biospassword: str :param sessionkey: session key credential for current login :type sessionkey: str :param is_redfish: If True, a Redfish specific header (OData) will be added to every request :type is_redfish: boolean :returns: a client object. Either HTTP or Blobstore. """ if not base_url or base_url.startswith('blobstore://'): if platform.system() == 'Windows': lib = BlobStore2.gethprestchifhandle() BlobStore2.unloadchifhandle(lib) else: if not os.path.isdir('/dev/hpilo') and \ not os.path.exists('/dev/char/vmkdriver/hpilo-d0ccb0'): raise ChifDriverMissingOrNotFound() return Blobstore2RestClient(base_url=base_url, \ default_prefix=default_prefix, username=username, \ password=password, sessionkey=sessionkey, \ is_redfish=is_redfish, cache=cache, proxy=proxy) else: return HttpClient(base_url=base_url, username=username, \ password=password, default_prefix=default_prefix, \ biospassword=biospassword, sessionkey=sessionkey, \ is_redfish=is_redfish, cache=cache, proxy=proxy)
def _init_connection(self, **kwargs): """Initiate blobstore connection""" # mixed security modes require a password at all times username = kwargs.pop('username', 'nousername') password = kwargs.pop('password', 'nopassword') try: correctcreds = BlobStore2.initializecreds(username=username, password=password) bs2 = BlobStore2() if not correctcreds: security_state = int(bs2.get_security_state()) raise SecurityStateError(security_state) except Blob2SecurityError: raise InvalidCredentialsError(0) except HpIloChifPacketExchangeError as excp: LOGGER.info("Exception: %s", str(excp)) raise ChifDriverMissingOrNotFound() except Exception as excp: if str(excp) == 'chif': raise ChifDriverMissingOrNotFound() else: raise else: self._conn = bs2
def getpaths(self): """ Get paths for ipprofiles command """ if not all( iter([ self.path, self.ipjobs, self.running_jobs, self.hvt_output ])): dll = BlobStore2.gethprestchifhandle() profiles_path = create_string_buffer(50) jobs_path = create_string_buffer(50) running_jobs_path = create_string_buffer(50) hvt_output_path = create_string_buffer(50) dll.get_ip_profiles(profiles_path) dll.get_ip_jobs(jobs_path) dll.get_running_jobs(running_jobs_path) dll.get_hvt_output(hvt_output_path) self.path = profiles_path.value self.ipjobs = jobs_path.value self.running_jobs = running_jobs_path.value self.hvt_output = hvt_output_path.value
def uploadlocally(self, filelist, options=None): """Upload component locally :param filelist: List of files to upload. :type filelist: list. :param options: command line options :type options: list. """ new_chif_needed = False upload_failed = False if not options.update_target: options.upload_srs = False if options.update_srs: if options.user and options.password: new_chif_needed = True else: self.rdmc.ui.error("ERROR: --update_srs option needs to be passed with "\ "--username and --password options, upload failed\n") return ReturnCodes.FAILED_TO_UPLOAD_COMPONENT try: dll = self.rdmc.app.current_client.connection._conn.channel.dll multiupload = False if new_chif_needed: # Backup old chif channel dll_bk = dll dll = None user = options.user passwrd = options.password dll, fhandle = self.create_new_chif_for_upload(user, passwrd) dll.uploadComponent.argtypes = [ c_char_p, c_char_p, c_char_p, c_uint32 ] dll.uploadComponent.restype = c_int for item in filelist: ilo_upload_filename = item[0] componentpath = item[1] compsigpath = item[2] if not compsigpath: compsigpath = self.findcompsig(componentpath) _, filename = os.path.split(componentpath) # 0x00000001 // FUM_WRITE_NAND # 0x00000002 // FUM_USE_NAND # 0x00000004 // FUM_NO_FLASH # 0x00000008 // FUM_FORCE # 0x00000010 // FUM_SIDECAR # 0x00000020 // FUM_APPEND # 0x40 // FUM_UPDATE_RECOVERY # 0x00000080 //FUM_RECOVERY # 0x00000100 // FUM_TASK # 0x00000200 //FUM_RECO_PRIV if not compsigpath and options.update_target: # Just update the firmware if options.update_srs: dispatchflag = ctypes.c_uint32(0x00000000 | 0x40) else: dispatchflag = ctypes.c_uint32(0x00000000) elif not compsigpath and not options.update_target and \ options.update_repository: # uploading a secuare flash binary image onto the NAND if options.update_srs: dispatchflag = ctypes.c_uint32(0x00000001 | 0x00000004 | 0x40) else: dispatchflag = ctypes.c_uint32(0x00000001 | 0x00000004) else: # Uploading a component with a side car file. if options.update_srs: dispatchflag = ctypes.c_uint32(0x00000001 | 0x00000004 | 0x00000010 | 0x40) else: dispatchflag = ctypes.c_uint32(0x00000001 | 0x00000004 | 0x00000010) if multiupload: # For second upload to append if the component is > 32MB in size if options.update_srs: dispatchflag = ctypes.c_uint32(0x00000001 | 0x00000004 | \ 0x00000010 | 0x00000020 | 0x40) else: dispatchflag = ctypes.c_uint32(0x00000001 | 0x00000004 | \ 0x00000010 | 0x00000020) self.rdmc.ui.printer("Uploading component " + filename + "\n") ret = dll.uploadComponent(\ ctypes.create_string_buffer(compsigpath.encode('utf-8')), ctypes.create_string_buffer(componentpath.encode('utf-8')), ctypes.create_string_buffer(ilo_upload_filename.encode('utf-8')), dispatchflag) upload_failed = False if ret != 0: self.rdmc.ui.error("Component " + filename + " upload failed\n") upload_failed = True else: self.rdmc.ui.printer("Component " + filename + " uploaded successfully\n") multiupload = True if new_chif_needed: dll.ChifTerminate() dll.ChifClose(fhandle) fhandle = None BlobStore2.unloadchifhandle(dll) # Restore old chif channel dll = dll_bk except Exception as excep: raise excep if upload_failed: return ReturnCodes.FAILED_TO_UPLOAD_COMPONENT else: return ReturnCodes.SUCCESS
def _rest_request(self, path='', method="GET", args=None, body=None, headers=None, optionalpassword=None, providerheader=None): """Rest request for blob store client :param path: path within tree :type path: str :param method: method to be implemented :type method: str :param args: the arguments for method :type args: dict :param body: body payload for the rest call :type body: dict :param headers: provide additional headers :type headers: dict :param optionalpassword: provide password for authentication :type optionalpassword: str :param provideheader: provider id for the header :type providerheader: str :return: returns a RestResponse object """ self.updatecredentials() headers = self._get_req_headers(headers, providerheader, \ optionalpassword) reqpath = path.replace('//', '/') oribody = body if body is not None: if isinstance(body, (dict, list)): headers['Content-Type'] = 'application/json' body = json.dumps(body) else: headers['Content-Type'] = 'application/x-www-form-urlencoded' body = urlencode(body) if method == 'PUT': resp = self._rest_request(path=path) try: if resp.getheader('content-encoding') == 'gzip': buf = StringIO() gfile = gzip.GzipFile(mode='wb', fileobj=buf) try: gfile.write(str(body)) finally: gfile.close() compresseddata = buf.getvalue() if compresseddata: data = bytearray() data.extend(memoryview(compresseddata)) body = data except BaseException as excp: LOGGER.error('Error occur while compressing body: %s', excp) raise headers['Content-Length'] = len(body) if args: if method == 'GET': reqpath += '?' + urlencode(args) elif method == 'PUT' or method == 'POST' or method == 'PATCH': headers['Content-Type'] = 'application/x-www-form-urlencoded' body = urlencode(args) str1 = '{} {} {}\r\n'.format(method, reqpath, \ Blobstore2RestClient._http_vsn_str) str1 += 'Host: \r\n' str1 += 'Accept-Encoding: identity\r\n' for header, value in headers.items(): str1 += '{}: {}\r\n'.format(header, value) str1 += '\r\n' if body and len(body) > 0: if isinstance(body, bytearray): str1 = str1.encode("ASCII") + body else: str1 += body bs2 = BlobStore2() if not isinstance(str1, bytearray): str1 = str1.encode("ASCII") if LOGGER.isEnabledFor(logging.DEBUG): try: logbody = None if body: if body[0] == '{': logbody = body else: raise if method in ['POST', 'PATCH']: debugjson = json.loads(body) if 'Password' in debugjson.keys(): debugjson['Password'] = '******' if 'OldPassword' in debugjson.keys(): debugjson['OldPassword'] = '******' if 'NewPassword' in debugjson.keys(): debugjson['NewPassword'] = '******' logbody = json.dumps(debugjson) LOGGER.debug('Blobstore REQUEST: %s\n\tPATH: %s\n\tHEADERS: '\ '%s\n\tBODY: %s', method, str(headers), path, logbody) except: LOGGER.debug('Blobstore REQUEST: %s\n\tPATH: %s\n\tHEADERS: '\ '%s\n\tBODY: %s', method, str(headers), path, 'binary body') inittime = time.time() for idx in range(5): try: resp_txt = bs2.rest_immediate(str1) break except Blob2OverrideError as excp: if idx == 4: raise Blob2OverrideError(2) else: continue endtime = time.time() bs2.channel.close() LOGGER.info("iLO Response Time to %s: %s secs.", path, str(endtime-inittime)) #Dummy response to support a bad host response if len(resp_txt) == 0: resp_txt = "HTTP/1.1 500 Not Found\r\nAllow: " \ "GET\r\nCache-Control: no-cache\r\nContent-length: " \ "0\r\nContent-type: text/html\r\nDate: Tues, 1 Apr 2025 " \ "00:00:01 GMT\r\nServer: " \ "HP-iLO-Server/1.30\r\nX_HP-CHRP-Service-Version: 1.0.3\r\n\r\n\r\n" restreq = RestRequest(path, method, data=body, url=self.base_url) rest_response = RisRestResponse(restreq, resp_txt) if rest_response.status in range(300, 399) and \ rest_response.status != 304: newloc = rest_response.getheader("location") newurl = urlparse(newloc) rest_response = self._rest_request(newurl.path, method, args, \ oribody, headers, optionalpassword, \ providerheader) try: if rest_response.getheader('content-encoding') == 'gzip': if hasattr(gzip, "decompress"): rest_response.read = gzip.decompress(rest_response.ori) else: compressedfile = StringIO(rest_response.ori) decompressedfile = gzip.GzipFile(fileobj=compressedfile) rest_response.read = decompressedfile.read() except Exception: pass if LOGGER.isEnabledFor(logging.DEBUG): headerstr = '' headerget = rest_response.getheaders() for header in headerget: headerstr += '\t' + header + ': ' + headerget[header] + '\n' try: LOGGER.debug('Blobstore RESPONSE for %s:\nCode: %s\nHeaders:'\ '\n%s\nBody of %s: %s', rest_response.request.path,\ str(rest_response._http_response.status)+ ' ' + \ rest_response._http_response.reason, \ headerstr, rest_response.request.path, \ rest_response.read) except: LOGGER.debug('Blobstore RESPONSE for %s:\nCode:%s', \ rest_response.request.path, rest_response) return rest_response
def _rest_request(self, path='', method="GET", args=None, body=None, headers=None, optionalpassword=None, providerheader=None): """Rest request for blob store client :param path: path within tree :type path: str :param method: method to be implemented :type method: str :param args: the arguments for method :type args: dict :param body: body payload for the rest call :type body: dict :param headers: provide additional headers :type headers: dict :param optionalpassword: provide password for authentication :type optionalpassword: str :param provideheader: provider id for the header :type providerheader: str :return: returns a RestResponse object """ headers = self._get_req_headers(headers, providerheader, \ optionalpassword) reqpath = path.replace('//', '/') oribody = body if body is not None: if isinstance(body, dict) or isinstance(body, list): headers['Content-Type'] = u'application/json' body = json.dumps(body) else: headers['Content-Type'] = u'application/x-www-form-urlencoded' body = urllib.urlencode(body) if method == 'PUT': resp = self._rest_request(path=path) try: if resp.getheader('content-encoding') == 'gzip': buf = StringIO() gfile = gzip.GzipFile(mode='wb', fileobj=buf) try: gfile.write(str(body)) finally: gfile.close() compresseddata = buf.getvalue() if compresseddata: data = bytearray() data.extend(buffer(compresseddata)) body = data except BaseException as excp: LOGGER.error('Error occur while compressing body: %s', excp) raise headers['Content-Length'] = len(body) if args: if method == 'GET': reqpath += '?' + urllib.urlencode(args) elif method == 'PUT' or method == 'POST' or method == 'PATCH': headers['Content-Type'] = u'application/x-www-form-urlencoded' body = urllib.urlencode(args) str1 = '%s %s %s\r\n' % (method, reqpath, \ Blobstore2RestClient._http_vsn_str) str1 += 'Host: \r\n' str1 += 'Accept-Encoding: identity\r\n' for header, value in headers.iteritems(): str1 += '%s: %s\r\n' % (header, value) str1 += '\r\n' if body and len(body) > 0: if isinstance(body, bytearray): str1 = str1.encode("ASCII") + body else: str1 += body bs2 = BlobStore2() if not isinstance(str1, bytearray): str1 = str1.encode("ASCII") if logging.getLogger().isEnabledFor(logging.DEBUG): try: LOGGER.debug('Blobstore REQUEST: %s\n\tPATH: %s\n\tBODY: %s'% \ (method, path, body)) except: LOGGER.debug('Blobstore REQUEST: %s\n\tPATH: %s\n\tBODY: %s'% \ (method, path, 'binary body')) inittime = time.clock() resp_txt = bs2.rest_immediate(str1) endtime = time.clock() bs2.channel.close() LOGGER.info("iLO Response Time to %s: %s secs."% \ (path, str(endtime-inittime))) #Dummy response to support a bad host response if len(resp_txt) == 0: resp_txt = "HTTP/1.1 500 Not Found\r\nAllow: " \ "GET\r\nCache-Control: no-cache\r\nContent-length: " \ "0\r\nContent-type: text/html\r\nDate: Tues, 1 Apr 2025 " \ "00:00:01 GMT\r\nServer: " \ "HP-iLO-Server/1.30\r\nX_HP-CHRP-Service-Version: 1.0.3\r\n\r\n\r\n" restreq = RestRequest(reqpath, method=method, body=body) rest_response = RisRestResponse(restreq, resp_txt) if rest_response.status in range(300, 399) and \ rest_response.status != 304: newloc = rest_response.getheader("location") newurl = urlparse2.urlparse(newloc) rest_response = self._rest_request(newurl.path, method, args, \ oribody, headers, optionalpassword, providerheader) try: if rest_response.getheader('content-encoding') == 'gzip': compressedfile = StringIO(rest_response.text) decompressedfile = gzip.GzipFile(fileobj=compressedfile) rest_response.text = decompressedfile.read() except StandardError: pass if logging.getLogger().isEnabledFor(logging.DEBUG): headerstr = '' for header in rest_response._http_response.msg.headers: headerstr += '\t' + header.rstrip() + '\n' try: LOGGER.debug('Blobstore RESPONSE for %s:\nCode: %s\nHeaders:\n%s'\ '\nBody of %s: %s'%\ (rest_response.request.path,\ str(rest_response._http_response.status)+ ' ' + \ rest_response._http_response.reason, \ headerstr, rest_response.request.path, rest_response.read)) except: LOGGER.debug('Blobstore RESPONSE for %s:\nCode:%s'% \ (rest_response.request.path, rest_response)) return rest_response