Beispiel #1
0
 def HandleFullSizeResumableUpload(self, existingDatafile):
     """
     If the existing unverified DataFile upload is the correct size
     in staging, then we can request its verification, but no upload
     is needed.
     """
     dataFilePath = self.folderModel.GetDataFilePath(self.dataFileIndex)
     self.verificationModel\
         .SetMessage("Found unverified full-size datafile "
                     "on staging server.")
     self.verificationModel.SetStatus(
         VerificationStatus.FOUND_UNVERIFIED_FULL_SIZE)
     self.verificationsModel.MessageUpdated(self.verificationModel)
     self.folderModel.SetDataFileUploaded(self.dataFileIndex, True)
     self.foldersModel.FolderStatusUpdated(self.folderModel)
     if existingDatafile and not self.testRun:
         DataFileModel.Verify(self.settingsModel, existingDatafile.GetId())
     self.verificationsModel.SetComplete(self.verificationModel)
     wx.PostEvent(
         self.foldersController.notifyWindow,
         self.foldersController
         .foundUnverifiedDatafileEvent(
             id=self.foldersController
             .EVT_FOUND_UNVERIFIED_BUT_FULL_SIZE_DATAFILE,
             folderModel=self.folderModel,
             dataFileIndex=self.dataFileIndex,
             dataFilePath=dataFilePath))
     if self.testRun:
         message = "FOUND UNVERIFIED UPLOAD FOR: %s" \
             % self.folderModel.GetDataFileRelPath(self.dataFileIndex)
         logger.testrun(message)
Beispiel #2
0
 def GetOrCreateExperimentForFolder(folderModel, testRun=False):
     """
     See also GetExperimentForFolder, CreateExperimentForFolder
     """
     try:
         existingExperiment = \
             ExperimentModel.GetExperimentForFolder(folderModel)
         if testRun:
             message = "ADDING TO EXISTING EXPERIMENT FOR FOLDER: %s\n" \
                 "    URL: %s/%s\n" \
                 "    Title: %s\n" \
                 "    Owner: %s" \
                 % (folderModel.GetRelPath(),
                    folderModel.settingsModel.GetMyTardisUrl(),
                    existingExperiment.GetViewUri(),
                    existingExperiment.GetTitle(),
                    folderModel.GetOwner().GetUsername())
             logger.testrun(message)
         return existingExperiment
     except DoesNotExist, err:
         if err.GetModelClass() == ExperimentModel:
             return ExperimentModel.CreateExperimentForFolder(folderModel,
                                                              testRun)
         else:
             raise
Beispiel #3
0
 def GetOrCreateExperimentForFolder(folderModel, testRun=False):
     """
     See also GetExperimentForFolder, CreateExperimentForFolder
     """
     try:
         existingExperiment = \
             ExperimentModel.GetExperimentForFolder(folderModel)
         if testRun:
             message = "ADDING TO EXISTING EXPERIMENT FOR FOLDER: %s\n" \
                 "    URL: %s/%s\n" \
                 "    Title: %s\n" \
                 "    Owner: %s" \
                 % (folderModel.GetRelPath(),
                    folderModel.settingsModel.GetMyTardisUrl(),
                    existingExperiment.GetViewUri(),
                    existingExperiment.GetTitle(),
                    folderModel.GetOwner().GetUsername())
             logger.testrun(message)
         return existingExperiment
     except DoesNotExist, err:
         if err.GetModelClass() == ExperimentModel:
             return ExperimentModel.CreateExperimentForFolder(
                 folderModel, testRun)
         else:
             raise
Beispiel #4
0
    def HandleUnresumableUpload(self, existingDatafile):
        """
        We found an unverified datafile on the server for which
        there is no point in checking for a resumable partial
        upload.

        This is usually because we are uploading using the POST upload method.
        Or we could be using the STAGING method but failed to find any
        DataFileObjects on the server for the datafile.
        """
        dataFilePath = self.folderModel.GetDataFilePath(self.dataFileIndex)
        logger.debug("Found unverified datafile record for \"%s\" "
                     "on MyTardis." % dataFilePath)
        self.verificationModel.SetMessage("Found unverified datafile record.")
        self.folderModel.SetDataFileUploaded(self.dataFileIndex, True)
        self.foldersModel.FolderStatusUpdated(self.folderModel)
        if self.foldersController.uploadMethod == UploadMethod.HTTP_POST:
            self.verificationModel.SetStatus(
                VerificationStatus.FOUND_UNVERIFIED_FULL_SIZE)
            eventId = self.foldersController\
                .EVT_FOUND_UNVERIFIED_BUT_FULL_SIZE_DATAFILE
        else:
            self.verificationModel.SetStatus(
                VerificationStatus.FOUND_UNVERIFIED_NO_DFOS)
            eventId = self.foldersController\
                .EVT_FOUND_UNVERIFIED_NO_DFOS
        self.verificationsModel.MessageUpdated(self.verificationModel)
        if existingDatafile and not self.testRun:
            if existingDatafile.GetMd5Sum() == \
                    self.settingsModel.GetFakeMd5Sum():
                logger.warning("MD5(%s): %s" %
                               (dataFilePath, existingDatafile.GetMd5Sum()))
            else:
                DataFileModel.Verify(self.settingsModel, existingDatafile.GetId())
        self.verificationsModel.SetComplete(self.verificationModel)
        wx.PostEvent(
            self.foldersController.notifyWindow,
            self.foldersController
            .foundUnverifiedDatafileEvent(
                id=eventId,
                folderModel=self.folderModel,
                dataFileIndex=self.dataFileIndex,
                dataFilePath=dataFilePath))
        if self.testRun:
            message = "FOUND UNVERIFIED UPLOAD FOR: %s" \
                % self.folderModel.GetDataFileRelPath(self.dataFileIndex)
            logger.testrun(message)
Beispiel #5
0
 def StartDataUploadsForFolderWorker():
     """
     Start the data uploads in a dedicated thread.
     """
     logger.debug("Starting run() method for thread %s" %
                  threading.current_thread().name)
     logger.debug("StartDataUploadsForFolderWorker")
     wx.CallAfter(BeginBusyCursorIfRequired)
     message = "Checking for data files on MyTardis and uploading " \
         "if necessary for folder: %s" % event.folderModel.GetFolder()
     logger.info(message)
     app = wx.GetApp()
     if app.TestRunRunning():
         logger.testrun(message)
     app.DisableTestAndUploadToolbarButtons()
     wx.GetApp().SetPerformingLookupsAndUploads(True)
     app.foldersController.StartUploadsForFolder(event.folderModel)
     wx.CallAfter(EndBusyCursorIfRequired, event)
Beispiel #6
0
    def UploadDatafile(self, event):
        """
        Called in response to didntFindDatafileOnServerEvent or
        unverifiedDatafileOnServerEvent.

        This method runs in the main thread, so it shouldn't do anything
        time-consuming or blocking, unless it launches another thread.
        Because this method adds upload tasks to a queue, it is important
        to note that if the queue has a maxsize set, then an attempt to
        add something to the queue could block the GUI thread, making the
        application appear unresponsive.
        """
        folderModel = event.folderModel
        dfi = event.dataFileIndex
        existingUnverifiedDatafile = \
            getattr(event, "existingUnverifiedDatafile", False)

        if self.testRun:
            if existingUnverifiedDatafile:
                message = "NEEDS RE-UPLOADING: %s" \
                    % folderModel.GetDataFileRelPath(dfi)
            else:
                message = "NEEDS UPLOADING: %s" \
                    % folderModel.GetDataFileRelPath(dfi)
            self.uploadsAcknowledged += 1
            logger.testrun(message)
            self.CountCompletedUploadsAndVerifications(event=None)
            return

        if folderModel not in self.uploadDatafileRunnable:
            self.uploadDatafileRunnable[folderModel] = {}

        bytesUploadedPreviously = getattr(event, "bytesUploadedPreviously",
                                          None)
        verificationModel = getattr(event, "verificationModel", None)
        self.uploadDatafileRunnable[folderModel][dfi] = \
            UploadDatafileRunnable(self, self.foldersModel, folderModel,
                                   dfi, self.uploadsModel,
                                   self.settingsModel,
                                   existingUnverifiedDatafile,
                                   verificationModel,
                                   bytesUploadedPreviously)
        self.uploadsQueue.put(self.uploadDatafileRunnable[folderModel][dfi])
        self.CountCompletedUploadsAndVerifications(event=None)
Beispiel #7
0
    def UploadDatafile(self, event):
        """
        Called in response to didntFindDatafileOnServerEvent or
        unverifiedDatafileOnServerEvent.

        This method runs in the main thread, so it shouldn't do anything
        time-consuming or blocking, unless it launches another thread.
        Because this method adds upload tasks to a queue, it is important
        to note that if the queue has a maxsize set, then an attempt to
        add something to the queue could block the GUI thread, making the
        application appear unresponsive.
        """
        folderModel = event.folderModel
        dfi = event.dataFileIndex
        existingUnverifiedDatafile = \
            getattr(event, "existingUnverifiedDatafile", False)

        if self.testRun:
            if existingUnverifiedDatafile:
                message = "NEEDS RE-UPLOADING: %s" \
                    % folderModel.GetDataFileRelPath(dfi)
            else:
                message = "NEEDS UPLOADING: %s" \
                    % folderModel.GetDataFileRelPath(dfi)
            self.uploadsAcknowledged += 1
            logger.testrun(message)
            self.CountCompletedUploadsAndVerifications(event=None)
            return

        if folderModel not in self.uploadDatafileRunnable:
            self.uploadDatafileRunnable[folderModel] = {}

        bytesUploadedPreviously = getattr(event, "bytesUploadedPreviously", None)
        verificationModel = getattr(event, "verificationModel", None)
        self.uploadDatafileRunnable[folderModel][dfi] = \
            UploadDatafileRunnable(self, self.foldersModel, folderModel,
                                   dfi, self.uploadsModel,
                                   self.settingsModel,
                                   existingUnverifiedDatafile,
                                   verificationModel,
                                   bytesUploadedPreviously)
        self.uploadsQueue.put(self.uploadDatafileRunnable[folderModel][dfi])
        self.CountCompletedUploadsAndVerifications(event=None)
Beispiel #8
0
 def HandleExistingVerifiedDatafile(self):
     """
     Found existing verified file on server.
     """
     dataFilePath = self.folderModel.GetDataFilePath(self.dataFileIndex)
     self.folderModel.SetDataFileUploaded(self.dataFileIndex, True)
     self.foldersModel.FolderStatusUpdated(self.folderModel)
     self.verificationsModel.SetComplete(self.verificationModel)
     wx.PostEvent(
         self.foldersController.notifyWindow,
         self.foldersController.foundVerifiedDatafileEvent(
             id=self.foldersController.EVT_FOUND_VERIFIED_DATAFILE,
             folderModel=self.folderModel,
             dataFileIndex=self.dataFileIndex,
             dataFilePath=dataFilePath))
     if self.testRun:
         message = "FOUND VERIFIED UPLOAD FOR: %s" \
             % self.folderModel.GetDataFileRelPath(self.dataFileIndex)
         logger.testrun(message)
Beispiel #9
0
 def HandleExistingVerifiedDatafile(self):
     """
     Found existing verified file on server.
     """
     dataFilePath = self.folderModel.GetDataFilePath(self.dataFileIndex)
     self.folderModel.SetDataFileUploaded(self.dataFileIndex, True)
     self.foldersModel.FolderStatusUpdated(self.folderModel)
     self.verificationsModel.SetComplete(self.verificationModel)
     wx.PostEvent(
         self.foldersController.notifyWindow,
         self.foldersController.foundVerifiedDatafileEvent(
             id=self.foldersController.EVT_FOUND_VERIFIED_DATAFILE,
             folderModel=self.folderModel,
             dataFileIndex=self.dataFileIndex,
             dataFilePath=dataFilePath))
     if self.testRun:
         message = "FOUND VERIFIED UPLOAD FOR: %s" \
             % self.folderModel.GetDataFileRelPath(self.dataFileIndex)
         logger.testrun(message)
Beispiel #10
0
 def StartDataUploadsForFolderWorker():
     """
     Start the data uploads in a dedicated thread.
     """
     logger.debug("Starting run() method for thread %s"
                  % threading.current_thread().name)
     logger.debug("StartDataUploadsForFolderWorker")
     wx.CallAfter(BeginBusyCursorIfRequired)
     message = "Checking for data files on MyTardis and uploading " \
         "if necessary for folder: %s" % event.folderModel.GetFolder()
     logger.info(message)
     app = wx.GetApp()
     if app.TestRunRunning():
         logger.testrun(message)
     app.DisableTestAndUploadToolbarButtons()
     wx.GetApp().SetPerformingLookupsAndUploads(True)
     app.foldersController.StartUploadsForFolder(
         event.folderModel)
     wx.CallAfter(EndBusyCursorIfRequired, event)
Beispiel #11
0
    def HandleUnresumableUpload(self, existingDatafile):
        """
        We found an unverified datafile on the server for which
        there is no point in checking for a resumable partial
        upload.

        This is usually because we are uploading using the POST upload method.
        Or we could be using the STAGING method but failed to find any
        DataFileObjects on the server for the datafile.
        """
        dataFilePath = self.folderModel.GetDataFilePath(self.dataFileIndex)
        logger.debug("Found unverified datafile record for \"%s\" "
                     "on MyTardis." % dataFilePath)
        self.verificationModel.SetMessage("Found unverified datafile record.")
        self.folderModel.SetDataFileUploaded(self.dataFileIndex, True)
        self.foldersModel.FolderStatusUpdated(self.folderModel)
        if self.foldersController.uploadMethod == UploadMethod.HTTP_POST:
            self.verificationModel.SetStatus(
                VerificationStatus.FOUND_UNVERIFIED_FULL_SIZE)
            eventId = self.foldersController\
                .EVT_FOUND_UNVERIFIED_BUT_FULL_SIZE_DATAFILE
        else:
            self.verificationModel.SetStatus(
                VerificationStatus.FOUND_UNVERIFIED_NO_DFOS)
            eventId = self.foldersController\
                .EVT_FOUND_UNVERIFIED_NO_DFOS
        self.verificationsModel.MessageUpdated(self.verificationModel)
        if existingDatafile and not self.testRun:
            DataFileModel.Verify(self.settingsModel, existingDatafile.GetId())
        self.verificationsModel.SetComplete(self.verificationModel)
        wx.PostEvent(
            self.foldersController.notifyWindow,
            self.foldersController
            .foundUnverifiedDatafileEvent(
                id=eventId,
                folderModel=self.folderModel,
                dataFileIndex=self.dataFileIndex,
                dataFilePath=dataFilePath))
        if self.testRun:
            message = "FOUND UNVERIFIED UPLOAD FOR: %s" \
                % self.folderModel.GetDataFileRelPath(self.dataFileIndex)
            logger.testrun(message)
Beispiel #12
0
 def HandleFullSizeResumableUpload(self, existingDatafile):
     """
     If the existing unverified DataFile upload is the correct size
     in staging, then we can request its verification, but no upload
     is needed.
     """
     dataFilePath = self.folderModel.GetDataFilePath(self.dataFileIndex)
     self.verificationModel\
         .SetMessage("Found unverified full-size datafile "
                     "on staging server.")
     self.verificationModel.SetStatus(
         VerificationStatus.FOUND_UNVERIFIED_FULL_SIZE)
     self.verificationsModel.MessageUpdated(self.verificationModel)
     self.folderModel.SetDataFileUploaded(self.dataFileIndex, True)
     self.foldersModel.FolderStatusUpdated(self.folderModel)
     if existingDatafile and not self.testRun:
         if existingDatafile.GetMd5Sum() == \
                 self.settingsModel.GetFakeMd5Sum():
             logger.warning("MD5(%s): %s" %
                            (dataFilePath, existingDatafile.GetMd5Sum()))
         else:
             DataFileModel.Verify(self.settingsModel, existingDatafile.GetId())
     self.verificationsModel.SetComplete(self.verificationModel)
     wx.PostEvent(
         self.foldersController.notifyWindow,
         self.foldersController
         .foundUnverifiedDatafileEvent(
             id=self.foldersController
             .EVT_FOUND_UNVERIFIED_BUT_FULL_SIZE_DATAFILE,
             folderModel=self.folderModel,
             dataFileIndex=self.dataFileIndex,
             dataFilePath=dataFilePath))
     if self.testRun:
         message = "FOUND UNVERIFIED UPLOAD FOR: %s" \
             % self.folderModel.GetDataFileRelPath(self.dataFileIndex)
         logger.testrun(message)
Beispiel #13
0
    def ShutDownUploadThreads(self, event=None):
        # pylint: disable=too-many-branches
        if self.IsShuttingDown():
            return
        if hasattr(wx.GetApp(), "SetPerformingLookupsAndUploads"):
            if not wx.GetApp().PerformingLookupsAndUploads():
                EndBusyCursorIfRequired()
                return
        self.SetShuttingDown(True)
        message = "Shutting down upload threads..."
        logger.info(message)
        if hasattr(wx.GetApp(), "GetMainFrame"):
            wx.GetApp().GetMainFrame().SetStatusMessage(message)
        if hasattr(event, "failed") and event.failed:
            self.SetFailed()
            self.uploadsModel.CancelRemaining()
        elif hasattr(event, "completed") and event.completed:
            self.SetCompleted()
        else:
            self.SetCanceled()
            self.uploadsModel.CancelRemaining()
        logger.debug("Shutting down FoldersController upload worker threads.")
        for _ in range(self.numUploadWorkerThreads):
            self.uploadsQueue.put(None)
        for thread in self.uploadWorkerThreads:
            thread.join()
        logger.debug("Shutting down FoldersController verification "
                     "worker threads.")
        for _ in range(self.numVerificationWorkerThreads):
            self.verificationsQueue.put(None)
        for thread in self.verificationWorkerThreads:
            thread.join()

        self.verifyDatafileRunnable = {}
        self.uploadDatafileRunnable = {}

        if sys.platform == 'darwin':
            sshControlMasterPool = \
                OPENSSH.GetSshControlMasterPool(createIfMissing=False)
            if sshControlMasterPool:
                sshControlMasterPool.ShutDown()

        if self.testRun:
            numVerificationsCompleted = \
                self.verificationsModel.GetCompletedCount()
            numVerifiedUploads = \
                self.verificationsModel.GetFoundVerifiedCount()
            numFilesNotFoundOnServer = \
                self.verificationsModel.GetNotFoundCount()
            numFullSizeUnverifiedUploads = \
                self.verificationsModel.GetFoundUnverifiedFullSizeCount()
            numIncompleteUploads = \
                self.verificationsModel.GetFoundUnverifiedNotFullSizeCount()
            numFailedLookups = self.verificationsModel.GetFailedCount()
            logger.testrun("")
            logger.testrun("SUMMARY")
            logger.testrun("")
            logger.testrun("Files looked up on server: %s" %
                           numVerificationsCompleted)
            logger.testrun("Files verified on server: %s" % numVerifiedUploads)
            logger.testrun("Files not found on server: %s" %
                           numFilesNotFoundOnServer)
            logger.testrun("Files unverified (but full size) on server: %s" %
                           numFullSizeUnverifiedUploads)
            logger.testrun("Files unverified (and incomplete) on server: %s" %
                           numIncompleteUploads)
            logger.testrun("Failed lookups: %s" % numFailedLookups)
            logger.testrun("")

        if self.Failed():
            message = "Data scans and uploads failed."
        elif self.Canceled():
            message = "Data scans and uploads were canceled."
        elif self.uploadsModel.GetFailedCount() > 0:
            message = \
                "Data scans and uploads completed with " \
                "%d failed upload(s)." % self.uploadsModel.GetFailedCount()
        elif self.Completed():
            message = "Data scans and uploads completed successfully."
        else:
            message = "Data scans and uploads appear to have " \
                "completed successfully."
        logger.info(message)
        if hasattr(wx.GetApp(), "GetMainFrame"):
            wx.GetApp().GetMainFrame().SetStatusMessage(message)
        if self.testRun:
            logger.testrun(message)

        app = wx.GetApp()
        if hasattr(app, "toolbar"):
            app.EnableTestAndUploadToolbarButtons()
            app.SetShouldAbort(False)
            if self.testRun:
                app.testRunFrame.saveButton.Enable()
        if hasattr(wx.GetApp(), "SetPerformingLookupsAndUploads"):
            wx.GetApp().SetPerformingLookupsAndUploads(False)
        self.SetShuttingDown(False)
        if hasattr(app, "SetTestRunRunning"):
            app.SetTestRunRunning(False)

        EndBusyCursorIfRequired()

        logger.debug("")
Beispiel #14
0
    def CreateDatasetIfNecessary(folderModel, testRun=False):
        # pylint: disable=too-many-statements
        # pylint: disable=too-many-branches
        # pylint: disable=too-many-locals
        description = folderModel.GetFolder()
        settingsModel = folderModel.settingsModel

        myTardisUrl = settingsModel.GetMyTardisUrl()
        myTardisUsername = settingsModel.GetUsername()
        myTardisApiKey = settingsModel.GetApiKey()

        experiment = folderModel.GetExperiment()
        if experiment:  # Could be None in test run
            url = myTardisUrl + "/api/v1/dataset/?format=json" + \
                "&experiments__id=" + str(experiment.GetId())
            url = url + "&description=" + urllib.quote(description)

            headers = {
                "Authorization": "ApiKey %s:%s" % (myTardisUsername,
                                                   myTardisApiKey)}

            response = requests.get(headers=headers, url=url)
            existingMatchingDatasets = response.json()
            numExistingMatchingDatasets = \
                existingMatchingDatasets['meta']['total_count']
            if numExistingMatchingDatasets == 1:
                logger.debug("Found existing dataset for folder " + description)
            elif numExistingMatchingDatasets > 1:
                logger.debug("WARNING: Found multiple datasets for folder " +
                             description)
        else:
            numExistingMatchingDatasets = 0

        if numExistingMatchingDatasets == 0:
            logger.debug("Creating dataset record for folder: " + description)

            description = folderModel.GetFolder()
            if experiment:
                experimentUri = experiment.GetResourceUri()
            else:
                experimentUri = None
            immutable = False
            datasetJson = {
                "instrument": settingsModel.GetInstrument().GetResourceUri(),
                "description": description,
                "experiments": [experimentUri],
                "immutable": immutable}
            data = json.dumps(datasetJson)
            headers = {
                "Authorization": "ApiKey %s:%s" % (myTardisUsername,
                                                   myTardisApiKey),
                "Content-Type": "application/json",
                "Accept": "application/json"}
            url = myTardisUrl + "/api/v1/dataset/"
            if testRun:
                message = "CREATING NEW DATASET FOR FOLDER: %s\n" \
                    "    Description: %s" \
                    % (folderModel.GetRelPath(),
                       description)
                if experiment:  # Could be None in test run.
                    message += "\n    In Experiment: %s/%s" \
                        % (folderModel.settingsModel.GetMyTardisUrl(),
                           experiment.GetViewUri())
                logger.testrun(message)
                return
            response = requests.post(headers=headers, url=url, data=data)
            if response.status_code >= 200 and response.status_code < 300:
                newDatasetJson = response.json()
                return DatasetModel(settingsModel, newDatasetJson)
            else:
                logger.error(url)
                logger.error("response.status_code = " +
                             str(response.status_code))
                logger.error(response.text)
                if response.status_code == 401:
                    message = "Couldn't create dataset \"%s\" " \
                              "for folder \"%s\"." \
                              % (description, folderModel.GetFolder())
                    message += "\n\n"
                    message += "Please ask your MyTardis administrator to " \
                               "check the permissions of the \"%s\" user " \
                               "account." % myTardisUsername
                    raise Unauthorized(message)
                elif response.status_code == 500:
                    message = "Couldn't create dataset \"%s\" " \
                              "for folder \"%s\"." \
                              % (description, folderModel.GetFolder())
                    message += "\n\n"
                    message += "An Internal Server Error occurred."
                    message += "\n\n"
                    message += "If running MyTardis in DEBUG mode, " \
                               "more information may be available below. " \
                               "Otherwise, please ask your MyTardis " \
                               "administrator to check in their logs " \
                               "for more information."
                    message += "\n\n"
                    try:
                        message += "ERROR: \"%s\"" \
                            % response.json()['error_message']
                    except:  # pylint: disable=bare-except
                        message += response.text
                    raise InternalServerError(message)
                raise Exception(response.text)
        else:
            existingDatasetJson = \
                existingMatchingDatasets['objects'][0]
            if testRun:
                description = existingDatasetJson['description']
                datasetId = existingDatasetJson['id']
                viewUri = "dataset/%s" % datasetId
                message = "ADDING TO EXISTING DATASET FOR FOLDER: %s\n" \
                    "    URL: %s/%s\n" \
                    "    Description: %s\n" \
                    "    In Experiment: %s/%s" \
                    % (folderModel.GetRelPath(),
                       folderModel.settingsModel.GetMyTardisUrl(),
                       viewUri,
                       description,
                       folderModel.settingsModel.GetMyTardisUrl(),
                       folderModel.GetExperiment().GetViewUri())
                logger.testrun(message)
            return DatasetModel(settingsModel,
                                existingMatchingDatasets['objects'][0])
Beispiel #15
0
    def CreateExperimentForFolder(folderModel, testRun=False):
        # pylint: disable=too-many-branches
        # pylint: disable=too-many-locals
        # pylint: disable=too-many-statements
        settingsModel = folderModel.GetSettingsModel()
        userFolderName = folderModel.GetUserFolderName()
        hostname = settingsModel.GetUploaderModel().GetHostname()
        location = folderModel.GetLocation()
        groupFolderName = folderModel.GetGroupFolderName()
        owner = folderModel.GetOwner()
        ownerUsername = folderModel.GetOwner().GetUsername()
        # pylint: disable=bare-except
        try:
            ownerUserId = folderModel.GetOwner().GetJson()['id']
        except:
            ownerUserId = None

        uploaderName = settingsModel.GetUploaderModel().GetName()
        uploaderUuid = settingsModel.GetUploaderModel().GetUuid()
        experimentTitle = folderModel.GetExperimentTitle()

        myTardisUrl = settingsModel.GetMyTardisUrl()
        myTardisDefaultUsername = settingsModel.GetUsername()
        myTardisDefaultUserApiKey = settingsModel.GetApiKey()

        if userFolderName:
            message = "Creating experiment for uploader '%s', " \
                "user folder '%s'." % (uploaderName, userFolderName)
            if groupFolderName:
                message += ", group folder : '%s'" % groupFolderName
        elif groupFolderName:
            message = "Creating experiment for uploader '%s', " \
                "user group folder '%s'." % (uploaderName, groupFolderName)
        else:
            message = "Creating experiment for uploader '%s'" % uploaderName
        logger.info(message)
        if userFolderName:
            description = ("Uploader: %s\n"
                           "User folder name: %s\n"
                           "Uploaded from: %s:%s"
                           % (uploaderName, userFolderName, hostname, location))
            if groupFolderName:
                description += "\nGroup folder name: %s" % groupFolderName
        else:
            description = ("Uploader: %s\n"
                           "Group folder name: %s\n"
                           "Uploaded from: %s:%s"
                           % (uploaderName, groupFolderName, hostname, location))

        if testRun:
            message = "CREATING NEW EXPERIMENT FOR FOLDER: %s\n" \
                "    Title: %s\n" \
                "    Description: \n" \
                "        Uploader: %s\n" \
                "        User folder name: %s\n" \
                "    Owner: %s" \
                % (folderModel.GetRelPath(),
                   experimentTitle, uploaderName, userFolderName,
                   ownerUsername)
            logger.testrun(message)
            return

        experimentJson = {
            "title": experimentTitle,
            "description": description,
            "immutable": False,
            "parameter_sets": [{
                "schema": "http://mytardis.org/schemas"
                          "/mydata/defaultexperiment",
                "parameters": [{"name": "uploader",
                                "value": uploaderUuid},
                               {"name": "user_folder_name",
                                "value": userFolderName}]}]}
        if groupFolderName:
            experimentJson["parameter_sets"][0]["parameters"].append(
                {"name": "group_folder_name", "value": groupFolderName})
        headers = {
            "Authorization": "ApiKey %s:%s" % (myTardisDefaultUsername,
                                               myTardisDefaultUserApiKey),
            "Content-Type": "application/json",
            "Accept": "application/json"}
        url = myTardisUrl + "/api/v1/mydata_experiment/"

        response = requests.post(headers=headers, url=url,
                                 data=json.dumps(experimentJson))
        # pylint: disable=bare-except
        try:
            createdExperimentJson = response.json()
            createdExperiment = ExperimentModel(settingsModel,
                                                createdExperimentJson)
            logger.debug(url)
        except:
            logger.error(url)
            logger.error(response.text)
            logger.error("response.status_code = " +
                         str(response.status_code))
            if response.status_code == 401:
                message = "Couldn't create experiment \"%s\" " \
                          "for folder \"%s\"." \
                          % (experimentTitle, folderModel.GetFolder())
                message += "\n\n"
                message += "Please ask your MyTardis administrator to " \
                           "check the permissions of the \"%s\" user " \
                           "account." % myTardisDefaultUsername
                raise Unauthorized(message)
            elif response.status_code == 404:
                message = "Couldn't create experiment \"%s\" " \
                          "for folder \"%s\"." \
                          % (experimentTitle, folderModel.GetFolder())
                message += "\n\n"
                message += "A 404 (Not Found) error occurred while " \
                           "attempting to create the experiment.\n\n" \
                           "Please ask your MyTardis administrator to " \
                           "check that a User Profile record exists " \
                           "for the \"%s\" user account." \
                           % myTardisDefaultUsername
                raise DoesNotExist(message)
            raise
        if response.status_code == 201:
            message = "Succeeded in creating experiment '%s' for uploader " \
                "\"%s\" and user folder \"%s\"" \
                % (experimentTitle, uploaderName, userFolderName)
            if groupFolderName:
                message += " and group folder \"%s\"" % groupFolderName
            logger.debug(message)

            facilityManagersGroup = settingsModel.GetFacility().GetManagerGroup()
            ObjectAclModel.ShareExperimentWithGroup(createdExperiment,
                                                    facilityManagersGroup)
            # Avoid creating a duplicate ObjectACL if the user folder's
            # username matches the facility manager's username.
            # Don't attempt to create an ObjectACL record for an
            # invalid user (without a MyTardis user ID).
            if myTardisDefaultUsername != ownerUsername and \
                    ownerUserId is not None:
                ObjectAclModel.ShareExperimentWithUser(createdExperiment,
                                                       owner)
            if folderModel.GetGroup() is not None and \
                    folderModel.GetGroup().GetId() != \
                    facilityManagersGroup.GetId():
                ObjectAclModel.ShareExperimentWithGroup(createdExperiment,
                                                        folderModel.GetGroup())
        else:
            message = "Failed to create experiment for uploader " \
                "\"%s\" and user folder \"%s\"" \
                % (uploaderName, userFolderName)
            if groupFolderName:
                message += " and group folder \"%s\"" % groupFolderName
            logger.error(message)
            logger.error(headers)
            logger.error(url)
            logger.error(response.text)
            logger.error("response.status_code = " +
                         str(response.status_code))
            if response.status_code == 401:
                message = "Couldn't create experiment \"%s\" " \
                          "for folder \"%s\"." \
                          % (experimentTitle, folderModel.GetFolder())
                message += "\n\n"
                message += "Please ask your MyTardis administrator to " \
                           "check the permissions of the \"%s\" user " \
                           "account." % myTardisDefaultUsername
                raise Unauthorized(message)
            elif response.status_code == 404:
                message = "Couldn't create experiment \"%s\" " \
                          "for folder \"%s\"." \
                          % (experimentTitle, folderModel.GetFolder())
                message += "\n\n"
                modelClassOfObjectNotFound = None
                # pylint: disable=bare-except
                try:
                    errorResponse = response.json()
                    if errorResponse['error_message'] == \
                            "UserProfile matching query does not exist.":
                        modelClassOfObjectNotFound = UserProfileModel
                    elif errorResponse['error_message'] == \
                            "Schema matching query does not exist.":
                        modelClassOfObjectNotFound = SchemaModel
                    elif errorResponse['error_message'] == \
                            "Sorry, this request could not be processed. " \
                            "Please try again later.":
                        raise Exception("TASTYPIE_CANNED_ERROR")
                    message += "A 404 (Not Found) error occurred while " \
                               "attempting to create an experiment " \
                               "record:\n\n" \
                               "    %s\n\n" % errorResponse['error_message']
                except:
                    message += "A 404 (Not Found) error occurred while " \
                               "attempting to create an experiment " \
                               "record.  This could be caused by a missing " \
                               "UserProfile record for user \"%s\" or it " \
                               "could be caused by a missing Schema record " \
                               "(see https://github.com/wettenhj/" \
                               "mytardis-app-mydata/blob/master/README.md)" \
                               "\n\n" \
                               "Turning on DEBUG mode on the MyTardis " \
                               "server could help to isolate the problem." \
                               % myTardisDefaultUsername
                if modelClassOfObjectNotFound == UserProfileModel:
                    message += "Please ask your MyTardis administrator to " \
                               "ensure that a User Profile record exists " \
                               "for the \"%s\" user account." \
                               % myTardisDefaultUsername
                elif modelClassOfObjectNotFound == SchemaModel:
                    message += "Please ask your MyTardis administrator to " \
                               "create the experiment metadata schema " \
                               "described in the \"MyTardis Prerequisites\" " \
                               "section of the MyData documentation:\n\n" \
                               "http://mydata.readthedocs.org/en/latest/" \
                               "mytardis-prerequisites.html"
                raise DoesNotExist(message,
                                   modelClass=modelClassOfObjectNotFound)
        return createdExperiment
Beispiel #16
0
    def CreateExperimentForFolder(folderModel, testRun=False):
        # pylint: disable=too-many-branches
        # pylint: disable=too-many-locals
        # pylint: disable=too-many-statements
        settingsModel = folderModel.GetSettingsModel()
        userFolderName = folderModel.GetUserFolderName()
        hostname = settingsModel.GetUploaderModel().GetHostname()
        location = folderModel.GetLocation()
        groupFolderName = folderModel.GetGroupFolderName()
        owner = folderModel.GetOwner()
        ownerUsername = folderModel.GetOwner().GetUsername()
        # pylint: disable=bare-except
        try:
            ownerUserId = folderModel.GetOwner().GetJson()['id']
        except:
            ownerUserId = None

        uploaderName = settingsModel.GetUploaderModel().GetName()
        uploaderUuid = settingsModel.GetUploaderModel().GetUuid()
        experimentTitle = folderModel.GetExperimentTitle()

        myTardisUrl = settingsModel.GetMyTardisUrl()
        myTardisDefaultUsername = settingsModel.GetUsername()
        myTardisDefaultUserApiKey = settingsModel.GetApiKey()

        if userFolderName:
            message = "Creating experiment for uploader '%s', " \
                "user folder '%s'." % (uploaderName, userFolderName)
            if groupFolderName:
                message += ", group folder : '%s'" % groupFolderName
        elif groupFolderName:
            message = "Creating experiment for uploader '%s', " \
                "user group folder '%s'." % (uploaderName, groupFolderName)
        else:
            message = "Creating experiment for uploader '%s'" % uploaderName
        logger.info(message)
        if userFolderName:
            description = ("Uploader: %s\n"
                           "User folder name: %s\n"
                           "Uploaded from: %s:%s" %
                           (uploaderName, userFolderName, hostname, location))
            if groupFolderName:
                description += "\nGroup folder name: %s" % groupFolderName
        else:
            description = ("Uploader: %s\n"
                           "Group folder name: %s\n"
                           "Uploaded from: %s:%s" %
                           (uploaderName, groupFolderName, hostname, location))

        if testRun:
            message = "CREATING NEW EXPERIMENT FOR FOLDER: %s\n" \
                "    Title: %s\n" \
                "    Description: \n" \
                "        Uploader: %s\n" \
                "        User folder name: %s\n" \
                "    Owner: %s" \
                % (folderModel.GetRelPath(),
                   experimentTitle, uploaderName, userFolderName,
                   ownerUsername)
            logger.testrun(message)
            return

        experimentJson = {
            "title":
            experimentTitle,
            "description":
            description,
            "immutable":
            False,
            "parameter_sets": [{
                "schema":
                "http://mytardis.org/schemas"
                "/mydata/defaultexperiment",
                "parameters": [{
                    "name": "uploader",
                    "value": uploaderUuid
                }, {
                    "name": "user_folder_name",
                    "value": userFolderName
                }]
            }]
        }
        if groupFolderName:
            experimentJson["parameter_sets"][0]["parameters"].append({
                "name":
                "group_folder_name",
                "value":
                groupFolderName
            })
        headers = {
            "Authorization":
            "ApiKey %s:%s" %
            (myTardisDefaultUsername, myTardisDefaultUserApiKey),
            "Content-Type":
            "application/json",
            "Accept":
            "application/json"
        }
        url = myTardisUrl + "/api/v1/mydata_experiment/"

        response = requests.post(headers=headers,
                                 url=url,
                                 data=json.dumps(experimentJson))
        # pylint: disable=bare-except
        try:
            createdExperimentJson = response.json()
            createdExperiment = ExperimentModel(settingsModel,
                                                createdExperimentJson)
            logger.debug(url)
        except:
            logger.error(url)
            logger.error(response.text)
            logger.error("response.status_code = " + str(response.status_code))
            if response.status_code == 401:
                message = "Couldn't create experiment \"%s\" " \
                          "for folder \"%s\"." \
                          % (experimentTitle, folderModel.GetFolder())
                message += "\n\n"
                message += "Please ask your MyTardis administrator to " \
                           "check the permissions of the \"%s\" user " \
                           "account." % myTardisDefaultUsername
                raise Unauthorized(message)
            elif response.status_code == 404:
                message = "Couldn't create experiment \"%s\" " \
                          "for folder \"%s\"." \
                          % (experimentTitle, folderModel.GetFolder())
                message += "\n\n"
                message += "A 404 (Not Found) error occurred while " \
                           "attempting to create the experiment.\n\n" \
                           "Please ask your MyTardis administrator to " \
                           "check that a User Profile record exists " \
                           "for the \"%s\" user account." \
                           % myTardisDefaultUsername
                raise DoesNotExist(message)
            raise
        if response.status_code == 201:
            message = "Succeeded in creating experiment '%s' for uploader " \
                "\"%s\" and user folder \"%s\"" \
                % (experimentTitle, uploaderName, userFolderName)
            if groupFolderName:
                message += " and group folder \"%s\"" % groupFolderName
            logger.debug(message)

            facilityManagersGroup = settingsModel.GetFacility(
            ).GetManagerGroup()
            ObjectAclModel.ShareExperimentWithGroup(createdExperiment,
                                                    facilityManagersGroup)
            # Avoid creating a duplicate ObjectACL if the user folder's
            # username matches the facility manager's username.
            # Don't attempt to create an ObjectACL record for an
            # invalid user (without a MyTardis user ID).
            if myTardisDefaultUsername != ownerUsername and \
                    ownerUserId is not None:
                ObjectAclModel.ShareExperimentWithUser(createdExperiment,
                                                       owner)
            if folderModel.GetGroup() is not None and \
                    folderModel.GetGroup().GetId() != \
                    facilityManagersGroup.GetId():
                ObjectAclModel.ShareExperimentWithGroup(
                    createdExperiment, folderModel.GetGroup())
        else:
            message = "Failed to create experiment for uploader " \
                "\"%s\" and user folder \"%s\"" \
                % (uploaderName, userFolderName)
            if groupFolderName:
                message += " and group folder \"%s\"" % groupFolderName
            logger.error(message)
            logger.error(headers)
            logger.error(url)
            logger.error(response.text)
            logger.error("response.status_code = " + str(response.status_code))
            if response.status_code == 401:
                message = "Couldn't create experiment \"%s\" " \
                          "for folder \"%s\"." \
                          % (experimentTitle, folderModel.GetFolder())
                message += "\n\n"
                message += "Please ask your MyTardis administrator to " \
                           "check the permissions of the \"%s\" user " \
                           "account." % myTardisDefaultUsername
                raise Unauthorized(message)
            elif response.status_code == 404:
                message = "Couldn't create experiment \"%s\" " \
                          "for folder \"%s\"." \
                          % (experimentTitle, folderModel.GetFolder())
                message += "\n\n"
                modelClassOfObjectNotFound = None
                # pylint: disable=bare-except
                try:
                    errorResponse = response.json()
                    if errorResponse['error_message'] == \
                            "UserProfile matching query does not exist.":
                        modelClassOfObjectNotFound = UserProfileModel
                    elif errorResponse['error_message'] == \
                            "Schema matching query does not exist.":
                        modelClassOfObjectNotFound = SchemaModel
                    elif errorResponse['error_message'] == \
                            "Sorry, this request could not be processed. " \
                            "Please try again later.":
                        raise Exception("TASTYPIE_CANNED_ERROR")
                    message += "A 404 (Not Found) error occurred while " \
                               "attempting to create an experiment " \
                               "record:\n\n" \
                               "    %s\n\n" % errorResponse['error_message']
                except:
                    message += "A 404 (Not Found) error occurred while " \
                               "attempting to create an experiment " \
                               "record.  This could be caused by a missing " \
                               "UserProfile record for user \"%s\" or it " \
                               "could be caused by a missing Schema record " \
                               "(see https://github.com/wettenhj/" \
                               "mytardis-app-mydata/blob/master/README.md)" \
                               "\n\n" \
                               "Turning on DEBUG mode on the MyTardis " \
                               "server could help to isolate the problem." \
                               % myTardisDefaultUsername
                if modelClassOfObjectNotFound == UserProfileModel:
                    message += "Please ask your MyTardis administrator to " \
                               "ensure that a User Profile record exists " \
                               "for the \"%s\" user account." \
                               % myTardisDefaultUsername
                elif modelClassOfObjectNotFound == SchemaModel:
                    message += "Please ask your MyTardis administrator to " \
                               "create the experiment metadata schema " \
                               "described in the \"MyTardis Prerequisites\" " \
                               "section of the MyData documentation:\n\n" \
                               "http://mydata.readthedocs.org/en/latest/" \
                               "mytardis-prerequisites.html"
                raise DoesNotExist(message,
                                   modelClass=modelClassOfObjectNotFound)
        return createdExperiment
Beispiel #17
0
    def CreateDatasetIfNecessary(folderModel, testRun=False):
        # pylint: disable=too-many-statements
        # pylint: disable=too-many-branches
        # pylint: disable=too-many-locals
        description = folderModel.GetFolder()
        settingsModel = folderModel.settingsModel

        myTardisUrl = settingsModel.GetMyTardisUrl()
        myTardisUsername = settingsModel.GetUsername()
        myTardisApiKey = settingsModel.GetApiKey()

        experiment = folderModel.GetExperiment()
        if experiment:  # Could be None in test run
            url = myTardisUrl + "/api/v1/dataset/?format=json" + \
                "&experiments__id=" + str(experiment.GetId())
            url = url + "&description=" + urllib.quote(description)

            headers = {
                "Authorization":
                "ApiKey %s:%s" % (myTardisUsername, myTardisApiKey)
            }

            response = requests.get(headers=headers, url=url)
            existingMatchingDatasets = response.json()
            numExistingMatchingDatasets = \
                existingMatchingDatasets['meta']['total_count']
            if numExistingMatchingDatasets == 1:
                logger.debug("Found existing dataset for folder " +
                             description)
            elif numExistingMatchingDatasets > 1:
                logger.debug("WARNING: Found multiple datasets for folder " +
                             description)
        else:
            numExistingMatchingDatasets = 0

        if numExistingMatchingDatasets == 0:
            logger.debug("Creating dataset record for folder: " + description)

            description = folderModel.GetFolder()
            if experiment:
                experimentUri = experiment.GetResourceUri()
            else:
                experimentUri = None
            immutable = False
            datasetJson = {
                "instrument": settingsModel.GetInstrument().GetResourceUri(),
                "description": description,
                "experiments": [experimentUri],
                "immutable": immutable
            }
            data = json.dumps(datasetJson)
            headers = {
                "Authorization":
                "ApiKey %s:%s" % (myTardisUsername, myTardisApiKey),
                "Content-Type":
                "application/json",
                "Accept":
                "application/json"
            }
            url = myTardisUrl + "/api/v1/dataset/"
            if testRun:
                message = "CREATING NEW DATASET FOR FOLDER: %s\n" \
                    "    Description: %s" \
                    % (folderModel.GetRelPath(),
                       description)
                if experiment:  # Could be None in test run.
                    message += "\n    In Experiment: %s/%s" \
                        % (folderModel.settingsModel.GetMyTardisUrl(),
                           experiment.GetViewUri())
                logger.testrun(message)
                return
            response = requests.post(headers=headers, url=url, data=data)
            if response.status_code >= 200 and response.status_code < 300:
                newDatasetJson = response.json()
                return DatasetModel(settingsModel, newDatasetJson)
            else:
                logger.error(url)
                logger.error("response.status_code = " +
                             str(response.status_code))
                logger.error(response.text)
                if response.status_code == 401:
                    message = "Couldn't create dataset \"%s\" " \
                              "for folder \"%s\"." \
                              % (description, folderModel.GetFolder())
                    message += "\n\n"
                    message += "Please ask your MyTardis administrator to " \
                               "check the permissions of the \"%s\" user " \
                               "account." % myTardisUsername
                    raise Unauthorized(message)
                elif response.status_code == 500:
                    message = "Couldn't create dataset \"%s\" " \
                              "for folder \"%s\"." \
                              % (description, folderModel.GetFolder())
                    message += "\n\n"
                    message += "An Internal Server Error occurred."
                    message += "\n\n"
                    message += "If running MyTardis in DEBUG mode, " \
                               "more information may be available below. " \
                               "Otherwise, please ask your MyTardis " \
                               "administrator to check in their logs " \
                               "for more information."
                    message += "\n\n"
                    try:
                        message += "ERROR: \"%s\"" \
                            % response.json()['error_message']
                    except:  # pylint: disable=bare-except
                        message += response.text
                    raise InternalServerError(message)
                raise Exception(response.text)
        else:
            existingDatasetJson = \
                existingMatchingDatasets['objects'][0]
            if testRun:
                description = existingDatasetJson['description']
                datasetId = existingDatasetJson['id']
                viewUri = "dataset/%s" % datasetId
                message = "ADDING TO EXISTING DATASET FOR FOLDER: %s\n" \
                    "    URL: %s/%s\n" \
                    "    Description: %s\n" \
                    "    In Experiment: %s/%s" \
                    % (folderModel.GetRelPath(),
                       folderModel.settingsModel.GetMyTardisUrl(),
                       viewUri,
                       description,
                       folderModel.settingsModel.GetMyTardisUrl(),
                       folderModel.GetExperiment().GetViewUri())
                logger.testrun(message)
            return DatasetModel(settingsModel,
                                existingMatchingDatasets['objects'][0])
Beispiel #18
0
    def ShutDownUploadThreads(self, event=None):
        # pylint: disable=too-many-branches
        if self.IsShuttingDown():
            return
        if hasattr(wx.GetApp(), "SetPerformingLookupsAndUploads"):
            if not wx.GetApp().PerformingLookupsAndUploads():
                EndBusyCursorIfRequired()
                return
        self.SetShuttingDown(True)
        message = "Shutting down upload threads..."
        logger.info(message)
        if hasattr(wx.GetApp(), "GetMainFrame"):
            wx.GetApp().GetMainFrame().SetStatusMessage(message)
        if hasattr(event, "failed") and event.failed:
            self.SetFailed()
            self.uploadsModel.CancelRemaining()
        elif hasattr(event, "completed") and event.completed:
            self.SetCompleted()
        else:
            self.SetCanceled()
            self.uploadsModel.CancelRemaining()
        logger.debug("Shutting down FoldersController upload worker threads.")
        for _ in range(self.numUploadWorkerThreads):
            self.uploadsQueue.put(None)
        if self.uploadMethod == UploadMethod.VIA_STAGING:
            # SCP can leave orphaned SSH processes which need to be
            # cleaned up.
            CleanUpSshProcesses(self.settingsModel)
        for thread in self.uploadWorkerThreads:
            thread.join()
        logger.debug("Shutting down FoldersController verification "
                     "worker threads.")
        for _ in range(self.numVerificationWorkerThreads):
            self.verificationsQueue.put(None)
        for thread in self.verificationWorkerThreads:
            thread.join()

        self.verifyDatafileRunnable = {}
        self.uploadDatafileRunnable = {}

        if self.testRun:
            numVerificationsCompleted = \
                self.verificationsModel.GetCompletedCount()
            numVerifiedUploads = \
                self.verificationsModel.GetFoundVerifiedCount()
            numFilesNotFoundOnServer = \
                self.verificationsModel.GetNotFoundCount()
            numFullSizeUnverifiedUploads = \
                self.verificationsModel.GetFoundUnverifiedFullSizeCount()
            numIncompleteUploads = \
                self.verificationsModel.GetFoundUnverifiedNotFullSizeCount()
            numFailedLookups = self.verificationsModel.GetFailedCount()
            logger.testrun("")
            logger.testrun("SUMMARY")
            logger.testrun("")
            logger.testrun("Files looked up on server: %s"
                           % numVerificationsCompleted)
            logger.testrun("Files verified on server: %s" % numVerifiedUploads)
            logger.testrun("Files not found on server: %s"
                           % numFilesNotFoundOnServer)
            logger.testrun("Files unverified (but full size) on server: %s"
                           % numFullSizeUnverifiedUploads)
            logger.testrun("Files unverified (and incomplete) on server: %s"
                           % numIncompleteUploads)
            logger.testrun("Failed lookups: %s" % numFailedLookups)
            logger.testrun("")

        if self.Failed():
            message = "Data scans and uploads failed."
        elif self.Canceled():
            message = "Data scans and uploads were canceled."
        elif self.uploadsModel.GetFailedCount() > 0:
            message = \
                "Data scans and uploads completed with " \
                "%d failed upload(s)." % self.uploadsModel.GetFailedCount()
        elif self.Completed():
            message = "Data scans and uploads completed successfully."
            elapsedTime = self.uploadsModel.GetElapsedTime()
            if elapsedTime and not self.testRun:
                averageSpeed = "%3.1f MB/s" % \
                    (float(self.uploadsModel.GetCompletedSize()) / 1000000.0 \
                     / elapsedTime.total_seconds())
                message += "  Average speed: %s" % averageSpeed
        else:
            message = "Data scans and uploads appear to have " \
                "completed successfully."
        logger.info(message)
        if hasattr(wx.GetApp(), "GetMainFrame"):
            wx.GetApp().GetMainFrame().SetStatusMessage(message)
        if self.testRun:
            logger.testrun(message)

        app = wx.GetApp()
        if hasattr(app, "toolbar"):
            app.EnableTestAndUploadToolbarButtons()
            app.SetShouldAbort(False)
            if self.testRun:
                app.testRunFrame.saveButton.Enable()
        if hasattr(wx.GetApp(), "SetPerformingLookupsAndUploads"):
            wx.GetApp().SetPerformingLookupsAndUploads(False)
        self.SetShuttingDown(False)
        if hasattr(app, "SetTestRunRunning"):
            app.SetTestRunRunning(False)

        EndBusyCursorIfRequired()

        logger.debug("")