def do_POST(self): ctype, pdict = cgi.parse_header(self.headers['content-type']) if ctype == 'multipart/form-data': postvars = cgi.parse_multipart(self.rfile, pdict) elif ctype == 'application/x-www-form-urlencoded': length = int(self.headers['content-length']) postvars = cgi.parse_qs(self.rfile.read(length), keep_blank_values=1) else: postvars = {} outputFileName = None start_time = datetime.now() requestSucceeded = False try: self.serviceMetrics.TotalRequests = self.serviceMetrics.TotalRequests + 1 self.rootLogger.info('<<STATS>> ' + self.serviceMetrics.getMetrics()) # Parse Input Parameters sasKeyStr = str(postvars[b'saskey'][0], encoding='UTF-8') operationId, mode, modeMajorSkipTo, modeMinorSkipTo, storageAcctName, container_blob_name, storageUrl = self.ParseUrlArguments(self.path, sasKeyStr) self.rootLogger.info('Starting service request for <Operation Id=' + operationId + ', Mode=' + mode + ', Url=' + self.path + '>') # Invoke LibGuestFS Wrapper for prorcessing with KeepAliveThread(self.rootLogger, self, threading.current_thread().getName()) as kpThread: with GuestFishWrapper(self.rootLogger, self, storageUrl, OUTPUTDIRNAME, operationId, mode, modeMajorSkipTo, modeMinorSkipTo, kpThread) as gfWrapper: # Upload the ZIP file if gfWrapper.outputFileName: outputFileName = gfWrapper.outputFileName outputFileSize = round(os.path.getsize(outputFileName) / 1024, 2) self.rootLogger.info('Uploading: ' + outputFileName + ' (' + str(outputFileSize) + 'kb)') self.uploadFile(gfWrapper.metadata_pairs, outputFileName, kpThread.wasTimeout, gfWrapper.osType) self.rootLogger.info('Upload completed.') successElapsed = datetime.now() - start_time self.serviceMetrics.SuccessRequests = self.serviceMetrics.SuccessRequests + 1 self.serviceMetrics.TotalSuccessServiceTime = self.serviceMetrics.TotalSuccessServiceTime + successElapsed.total_seconds() self.serviceMetrics.ConsecutiveErrors = 0 requestSucceeded = True self.rootLogger.info('Request completed succesfully in ' + str(successElapsed.total_seconds()) + "s.") else: self.rootLogger.error('Failed to create zip package.') except ValueError as ex: self.rootLogger.error(str(ex)) self.send_error(500, str(ex)) except (IndexError, FileNotFoundError) as ex: self.rootLogger.exception('Exception: IndexError or FileNotFound error') self.send_error(404, 'Not Found') except Exception as ex: self.rootLogger.exception('Exception: ' + str(ex)) self.send_error(500, str(ex)) finally: if (not requestSucceeded): self.serviceMetrics.ConsecutiveErrors = self.serviceMetrics.ConsecutiveErrors + 1 if (self.serviceMetrics.ConsecutiveErrors > 10): self.rootLogger.error('FATAL FAILURE: More than 10 consecutive requests failed to be serviced. Shutting down.') os._exit(1) self.rootLogger.info('Ending service request.') self.rootLogger.info('<<STATS>> ' + self.serviceMetrics.getMetrics())
def do_POST(self): ctype, pdict = cgi.parse_header(self.headers['content-type']) if ctype == 'multipart/form-data': postvars = cgi.parse_multipart(self.rfile, pdict) elif ctype == 'application/x-www-form-urlencoded': length = int(self.headers['content-length']) postvars = cgi.parse_qs(self.rfile.read(length), keep_blank_values=1) else: postvars = {} outputFileName = None start_time = datetime.now() requestSucceeded = False unexpectedError = False # certain exception should not affect view of server health failureResultCode = 500 telemetryException = None failureStatusText = None fatal_exit = False try: self.serviceMetrics.TotalRequests = self.serviceMetrics.TotalRequests + 1 self.telemetryLogger.info('<<STATS>> ' + self.serviceMetrics.getMetrics()) sasKeyStr = str(postvars[b'saskey'][0], encoding='UTF-8') operationId, mode, modeMajorSkipTo, modeMinorSkipTo, storageAcctName, container_blob_name, storageUrl = self.ParseUrlArguments(self.path, sasKeyStr) if b'credscan' in postvars: credscanStr = str(postvars[b'credscan'][0], encoding='UTF-8') runWithCredscan = (credscanStr == "true") else: runWithCredscan = False timeoutInMinsStr = str(DEFAULT_TIMEOUT_IN_MINS) if b'timeout' in postvars: timeoutInputStr = str(postvars[b'timeout'][0], encoding='UTF-8') if timeoutInputStr.isdecimal() and int(timeoutInputStr) > 0 and int(timeoutInputStr) < 120 : timeoutInMinsStr = timeoutInputStr else: self.telemetryLogger.info('WARNING: Received timeout override is invalid: {0}. Default will be used.'.format(timeoutInMinsStr)) timeoutInMins = int(timeoutInMinsStr) self.telemetryLogger.info('Using timeout value: ' + str(timeoutInMins)+ ' min(s)') # update the fields in the telemetry client for h in self.telemetryLogger.handlers: if h.__class__.__name__ == 'LoggingHandler': h.client.context.session.id = operationId self.telemetryClient.context.session.id = operationId self.telemetryLogger.info('Starting service request for <Operation Id=' + operationId + ', Mode=' + mode + ', Url=' + self.path + '>') if ("error" in self.hostMetadata): self.hostMetadata = getHostMetadata() customProperties = {"HOSTNAME": os.environ['HOSTNAME'] if 'HOSTNAME' in os.environ else "", 'mode' : mode, 'operationId': operationId, 'MajorSkipTo' : modeMajorSkipTo, 'MinorSkipTo' : modeMinorSkipTo, 'containerName' : self.containerId, 'containerVersion' : self.containerVersion, 'HostMetadata' : self.hostMetadata, 'HttpMethod':'POST' } roleInstance = self.getInstanceNameFromMetadata() # Hack: we cram this data into a global context available in the Python AppInsights SDK # which will be sent by the logger in a field that the Geneva connector will pickup, and we post-process during cook self.telemetryClient.context.user.id = os.environ['HOSTNAME'] + "/" + roleInstance # Invoke LibGuestFS Wrapper for prorcessing with KeepAliveThread(self.telemetryLogger, self, threading.current_thread().getName(), timeoutInMins) as kpThread: with GuestFishWrapper(self.telemetryLogger, self, storageUrl, OUTPUTDIRNAME, operationId, mode, modeMajorSkipTo, modeMinorSkipTo, kpThread, runWithCredscan) as gfWrapper: gfWrapper.start() # Upload the ZIP file if gfWrapper.outputFileName: kpThread.avoidSendingKeepAlive = True # stop KeepAlive while we send the zip to avoid corruption issue outputFileName = gfWrapper.outputFileName outputFileSize = round(os.path.getsize(outputFileName) / 1024, 2) self.telemetryLogger.info('Uploading: ' + outputFileName + ' (' + str(outputFileSize) + 'kb)') gfWrapper.metadata_pairs[ResponseHeaderMetadata.KEEPALIVETHREAD_TIMEOUT_IN_MINS] = timeoutInMins self.uploadFile(gfWrapper.metadata_pairs, outputFileName, kpThread.wasTimeout, gfWrapper.osType) self.telemetryLogger.info('Upload completed.') successElapsed = datetime.now() - start_time self.serviceMetrics.SuccessRequests = self.serviceMetrics.SuccessRequests + 1 self.serviceMetrics.TotalSuccessServiceTime = self.serviceMetrics.TotalSuccessServiceTime + successElapsed.total_seconds() self.serviceMetrics.ConsecutiveErrors = 0 requestSucceeded = True self.telemetryLogger.info('Request completed succesfully in ' + str(successElapsed.total_seconds()) + "s.") # Capture info discovered about the VHD for telemetry for metadata in gfWrapper.metadata_pairs: metadata_value = str(gfWrapper.metadata_pairs[metadata]) if len( metadata_value ) > 0: customProperties[metadata] = metadata_value # track request and metrics self.telemetryClient.track_request('Request Success', self.path, requestSucceeded, start_time.isoformat(), successElapsed.total_seconds() * 1000, 200, 'POST', customProperties) self.telemetryClient.track_metric("HttpResponseCode", 200, count=1, properties={"HOSTNAME": os.environ['HOSTNAME'], 'StatusText':'OK', 'Method':'POST'}) self.telemetryClient.track_metric("Request Success Duration", successElapsed.total_seconds(), count=1, properties={"HOSTNAME": os.environ['HOSTNAME'], 'StatusText':'OK', 'Method':'POST'}) else: error_string = 'Failed to create zip package.' self.telemetryLogger.error(error_string) self.send_error(500, error_string) self.telemetryClient.track_metric("HttpResponseCode", 500, count=1, properties={"HOSTNAME": os.environ['HOSTNAME'], 'StatusText':'INTERNAL_SERVER_ERROR', 'Method':'POST'}) self.telemetryClient.track_request(error_string, self.path, requestSucceeded, start_time.isoformat(), successElapsed.total_seconds() * 1000, 500, 'POST', customProperties) except InvalidVhdNotFoundException as ex: unexpectedError = False failureResultCode = 404 telemetryException = ex failureStatusText = 'Vhd not found' self.telemetryLogger.error(failureStatusText) # don't raise exception except InvalidStorageAccountException as ex: unexpectedError = False failureResultCode = 400 telemetryException = ex failureStatusText = 'Invalid storage account' self.telemetryLogger.error(failureStatusText) # don't raise exception except InvalidSasException as ex: unexpectedError = False failureResultCode = 400 telemetryException = ex failureStatusText = 'Invalid SAS uri' self.telemetryLogger.error(failureStatusText) # don't raise exception except ValueError as ex: unexpectedError = True telemetryException = ex self.logException(ex, customProperties) failureStatusText = 'ValueError' except (IndexError, FileNotFoundError) as ex: unexpectedError = True failureResultCode = 404 telemetryException = ex self.logException(ex, customProperties) failureStatusText = 'Not Found' except BrokenPipeError as ex: unexpectedError = False telemetryException = ex self.logException(ex, customProperties) failureStatusText = 'BrokenPipe error' except Exception as ex: unexpectedError = True telemetryException = ex self.logException(ex, customProperties) failureStatusText = 'Server Error' finally: if (not requestSucceeded): self.send_error(failureResultCode, "%s: %s" % (failureStatusText, str(telemetryException))) self.telemetryClient.track_metric("HttpResponseCode", failureResultCode, count=1, properties={"HOSTNAME": os.environ['HOSTNAME'], 'StatusText':failureStatusText, 'Method':'POST'}) self.telemetryClient.track_request('POST ' + failureStatusText, self.path, requestSucceeded, start_time.isoformat(), (datetime.now() - start_time).total_seconds() * 1000, 500, 'POST', customProperties) failedElapsed = datetime.now() - start_time self.telemetryClient.track_metric("Request Failure Duration", failedElapsed.total_seconds()) if unexpectedError: self.serviceMetrics.ConsecutiveErrors = self.serviceMetrics.ConsecutiveErrors + 1 if (self.serviceMetrics.ConsecutiveErrors > 10): self.telemetryLogger.error('FATAL FAILURE: More than 10 consecutive requests failed to be serviced. Shutting down.') self.telemetryClient.track_metric("Fatal Failure", 1) fatal_exit = True # set a flag so that the telemetry clients are flushed prior to exit self.telemetryLogger.info('Ending service request.') self.telemetryLogger.info('<<STATS>> ' + self.serviceMetrics.getMetrics()) # Make sure the telemetry is flushed into its channels self.telemetryClient.flush() for h in self.telemetryLogger.handlers: if h.__class__.__name__ == 'LoggingHandler': h.flush() h.client.context.session.id = None self.telemetryClient.context.session.id = None if (fatal_exit): os._exit(1)
def do_POST(self): ctype, pdict = cgi.parse_header(self.headers['content-type']) if ctype == 'multipart/form-data': postvars = cgi.parse_multipart(self.rfile, pdict) elif ctype == 'application/x-www-form-urlencoded': length = int(self.headers['content-length']) postvars = cgi.parse_qs(self.rfile.read(length), keep_blank_values=1) else: postvars = {} outputFileName = None start_time = datetime.now() requestSucceeded = False unexpectedError = False # certain exception should not affect view of server health failureResultCode = 500 telemetryException = None failureStatusText = None fatal_exit = False try: self.serviceMetrics.TotalRequests = self.serviceMetrics.TotalRequests + 1 self.telemetryLogger.info('<<STATS>> ' + self.serviceMetrics.getMetrics()) sasKeyStr = str(postvars[b'saskey'][0], encoding='UTF-8') operationId, mode, modeMajorSkipTo, modeMinorSkipTo, storageAcctName, container_blob_name, storageUrl = self.ParseUrlArguments( self.path, sasKeyStr) self.telemetryLogger.info( 'Starting service request for <Operation Id=' + operationId + ', Mode=' + mode + ', Url=' + self.path + '>') # update the fields in the telemetry client for h in self.telemetryLogger.handlers: if h.__class__.__name__ == 'LoggingHandler': h.client.context.session.id = operationId self.telemetryClient.context.session.id = operationId if ("error" in self.hostMetadata): self.hostMetadata = getHostMetadata() customProperties = { "HOSTNAME": os.environ['HOSTNAME'] if 'HOSTNAME' in os.environ else "", 'mode': mode, 'operationId': operationId, 'MajorSkipTo': modeMajorSkipTo, 'MinorSkipTo': modeMinorSkipTo, 'containerName': self.containerId, 'containerVersion': self.containerVersion, 'HostMetadata': self.hostMetadata, 'HttpMethod': 'POST' } # Invoke LibGuestFS Wrapper for prorcessing with KeepAliveThread( self.telemetryLogger, self, threading.current_thread().getName()) as kpThread: with GuestFishWrapper(self.telemetryLogger, self, storageUrl, OUTPUTDIRNAME, operationId, mode, modeMajorSkipTo, modeMinorSkipTo, kpThread) as gfWrapper: gfWrapper.start() # Upload the ZIP file if gfWrapper.outputFileName: outputFileName = gfWrapper.outputFileName outputFileSize = round( os.path.getsize(outputFileName) / 1024, 2) self.telemetryLogger.info('Uploading: ' + outputFileName + ' (' + str(outputFileSize) + 'kb)') self.uploadFile(gfWrapper.metadata_pairs, outputFileName, kpThread.wasTimeout, gfWrapper.osType) self.telemetryLogger.info('Upload completed.') successElapsed = datetime.now() - start_time self.serviceMetrics.SuccessRequests = self.serviceMetrics.SuccessRequests + 1 self.serviceMetrics.TotalSuccessServiceTime = self.serviceMetrics.TotalSuccessServiceTime + successElapsed.total_seconds( ) self.serviceMetrics.ConsecutiveErrors = 0 requestSucceeded = True self.telemetryLogger.info( 'Request completed succesfully in ' + str(successElapsed.total_seconds()) + "s.") # Capture info discovered about the VHD for telemetry for metadata in gfWrapper.metadata_pairs: metadata_value = str( gfWrapper.metadata_pairs[metadata]) if len(metadata_value) > 0: customProperties[metadata] = metadata_value # track request and metrics self.telemetryClient.track_request( 'Request Success', self.path, requestSucceeded, start_time.isoformat(), successElapsed.total_seconds() * 1000, 200, 'POST', customProperties) self.telemetryClient.track_metric("HttpResponseCode", 200, count=1, properties={ 'StatusText': 'OK', 'Method': 'POST' }) self.telemetryClient.track_metric( "Request Success Duration", successElapsed.total_seconds()) else: error_string = 'Failed to create zip package.' self.telemetryLogger.error(error_string) self.send_error(500, error_string) self.telemetryClient.track_metric( "HttpResponseCode", 500, count=1, properties={ 'StatusText': 'INTERNAL_SERVER_ERROR', 'Method': 'POST' }) self.telemetryClient.track_request( error_string, self.path, requestSucceeded, start_time.isoformat(), successElapsed.total_seconds() * 1000, 500, 'POST', customProperties) except InvalidVhdNotFoundException as ex: unexpectedError = False telemetryException = ex failureStatusText = 'Vhd not found' self.telemetryLogger.error( failureStatusText) # don't raise exception except InvalidStorageAccountException as ex: unexpectedError = False telemetryException = ex failureStatusText = 'Invalid storage account' self.telemetryLogger.error( failureStatusText) # don't raise exception except InvalidSasException as ex: unexpectedError = False telemetryException = ex failureStatusText = 'Invalid SAS uri' self.telemetryLogger.error( failureStatusText) # don't raise exception except ValueError as ex: unexpectedError = True telemetryException = ex self.logException(ex, customProperties) failureStatusText = 'ValueError' except (IndexError, FileNotFoundError) as ex: unexpectedError = True failureResultCode = 404 telemetryException = ex self.logException(ex, customProperties) failureStatusText = 'Not Found' except Exception as ex: unexpectedError = True telemetryException = ex self.logException(ex, customProperties) failureStatusText = 'Server Error' finally: if (not requestSucceeded): self.send_error( failureResultCode, "%s: %s" % (failureStatusText, str(telemetryException))) self.telemetryClient.track_metric("HttpResponseCode", failureResultCode, count=1, properties={ 'StatusText': failureStatusText, 'Method': 'POST' }) self.telemetryClient.track_request( 'POST ' + failureStatusText, self.path, requestSucceeded, start_time.isoformat(), (datetime.now() - start_time).total_seconds() * 1000, 500, 'POST', customProperties) failedElapsed = datetime.now() - start_time self.telemetryClient.track_metric( "Request Failure Duration", failedElapsed.total_seconds()) if unexpectedError: self.serviceMetrics.ConsecutiveErrors = self.serviceMetrics.ConsecutiveErrors + 1 if (self.serviceMetrics.ConsecutiveErrors > 10): self.telemetryLogger.error( 'FATAL FAILURE: More than 10 consecutive requests failed to be serviced. Shutting down.' ) self.telemetryClient.track_metric("Fatal Failure", 1) fatal_exit = True # set a flag so that the telemetry clients are flushed prior to exit self.telemetryLogger.info('Ending service request.') self.telemetryLogger.info('<<STATS>> ' + self.serviceMetrics.getMetrics()) # Make sure the telemetry is flushed into its channels self.telemetryClient.flush() for h in self.telemetryLogger.handlers: if h.__class__.__name__ == 'LoggingHandler': h.flush() h.client.context.session.id = None self.telemetryClient.context.session.id = None if (fatal_exit): os._exit(1)