Пример #1
0
    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())
Пример #2
0
    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)