Example #1
0
    def addNode2Looper(self, node, position, looper_pos=0):
        ''' Add a looper child node to a looper node.
        '''
        if not self.nodes:
            raise PsysmonError('No collection nodes available.')

        cur_node = self.nodes[position]
        if isinstance(cur_node,
                      psysmon.core.packageNodes.LooperCollectionNode):
            # Add the node to the looper node.
            node.parentCollection = self
            cur_node.add_child(node, position=looper_pos)
        else:
            raise PsysmonError(
                'The selected collection node is not a looper node.')
Example #2
0
    def removeNodeFromCollection(self, position):
        '''Remove a node from the active collection.

        Parameters
        ----------
        position : Integer
            The position of the node to remove.

        Raises
        ------
        PsysmonError : :class:`PsysmonError` 
            Error raised when no active collection is present.
        '''
        if self.activeCollection:
            self.activeCollection.popNode(position)
        else:
            raise PsysmonError('No active collection found!')
Example #3
0
    def executeNode(self, position):
        '''Execute the node at *position* of the active collection.

        Executing a node means calling the :meth:`~psysmon.core.packageNodes.CollectionNode.execute` method of the 
        :class:`~psysmon.core.packageNodes.CollectionNode` instance.

        Parameters
        ----------
        position : Integer
            The position of the node to edit.

        Raises
        ------
        PsysmonError : :class:`PsysmonError` 
            Error raised when no active collection is present.
        '''
        if self.activeCollection:
            self.activeCollection.executeNode(position)
        else:
            raise PsysmonError('No active collection found!')
Example #4
0
    def getNodeFromCollection(self, position):
        '''Get the node at *position* from the active collection.

        Parameters
        ----------
        position : Integer
            The position of the node to get.

        Returns
        -------
        collectionNode : :class:`~psysmon.core.packageNodes.Collection` 
            The collection node at *position* in the active collection.

        Raises
        ------
        PsysmonError : :class:`PsysmonError` 
            Error raised when no active collection is present.
        '''
        if self.activeCollection:
            return self.activeCollection[position]
        else:
            raise PsysmonError('No active collection found!')
Example #5
0
    def addNode2Collection(self, node, position):
        '''Add a collection node to the active collection.

        The *node* is added to the currently active collection at *position* 
        using the :meth:`~psysmon.core.base.Collection.addNode` method of the 
        :class:`~psysmon.core.base.Collection` class.

        Parameters
        ----------
        nodeTemplate : :class:`~psysmon.core.packageNodes.CollectionNode`
            The node to be added to the collection.
        position : Integer
            The position before which to add the node to the 
            collection. -1 to add it at the end of the collection (default).

        Raises
        ------
        PsysmonError : :class:`~psysmon.core.util.PsysmonError` 
            Error raised when no active collection is present.
        '''
        if self.activeCollection:
            self.activeCollection.addNode(node, position)
        else:
            raise PsysmonError('No active collection found!')
Example #6
0
    def createPsysmonProject(self, name, base_dir, db_host, user_name, user_pwd,
                             author_name, author_uri, agency_name, agency_uri):
        '''Create a pSysmon project.

        The pSysmon project is the starting point when working with pSysmon.
        After creating an instance of the :class:`~psysmon.core.project.Project` 
        class, the project is initialized by the following steps:

        - Connect to the database. If this fails, a PsysmonError is raised.
        - Create the project directory structure in the project base directory.
        - Create the project database structure.
        - Initialize the project for the currently active user.
        - Save the project.

        Parameters
        ----------
        name : String
            The name of the project.
        baseDir : String
            The base directory of the pSysmon project. Inside the 
            base directory, the pSysmon project directory is created.
        dbHost : String
            The database host on which the mysql server for the 
            project is running.
        user : String
            The pSysmon user related to the project as the *admin*.
        userPwd : String
            The password of *user*.

        Returns
        -------
        projectCreated : Boolean
            Indicates if the project has been created succesfully.
            (True: project created; False: project not created)

        Raises
        ------
        PsysmonError : :class:`~psysmon.core.util.PsysmonError`
            Error while connecting to the database.
        '''

        # Create the admin user for the project.
        admin_user = psysmon.core.project.User(user_name = user_name, 
                                               user_mode = 'admin',
                                               user_pwd = user_pwd,
                                               author_name = author_name,
                                               author_uri = author_uri,
                                               agency_name = agency_name,
                                               agency_uri = agency_uri
                                              )

        # Create the project instance.
        self.project = psysmon.core.project.Project(psybase = self,
                                                    name = name,
                                                    user = admin_user,
                                                    base_dir = base_dir,
                                                    dbHost = db_host)

        # When creating a project, set the active user to the user creating 
        # the project (which is the *admin* user).
        self.project.activeUser = self.project.user[0]
        try:
            self.project.connect2Db() 
        except Exception as e:
            msg = "Can't connect to the database.\n The database returned the following message:\n%s" % e
            raise PsysmonError(msg)     # If the connection fails, don't go on with the project creation.

        self.project.createDirectoryStructure()
        self.project.createDatabaseStructure(self.packageMgr.packages)

        # By default add a psysmon Database waveclient with the name 'main
        # client'. Add the waveclient only, if the required packages are
        # present.
        required_packages = ['obspyImportWaveform', 'geometry']
        available_packages = [x for x in self.packageMgr.packages.keys() if x in required_packages]
        if required_packages == available_packages:
            waveclient = PsysmonDbWaveClient('db client', self.project)
            self.project.addWaveClient(waveclient)
            self.project.defaultWaveclient = 'db client'

        self.project.save_json()

        return True
Example #7
0
    def executeCollection(self, project):
        '''Execute the active collection.

        Start a new process to execute the currently active collection.
        A deep copy of the collection instance is create and this copy 
        is executed. This is done to prevent runtime interactions 
        when editing the collection node properties after a collection 
        has been executed.

        The start of the execution is logged and a state.collection.execution 
        message is sent to notify eventual listeners of the starting of 
        the execution.

        Parameters
        ----------
        project : :class:`Project`
            The pSysmon project.

        Raises
        ------
        PsysmonError : :class:`PsysmonError` 
            Error raised when no active collection is present.
        '''
        def processChecker(process, procName):
            from time import sleep

            # The time interval to check for process messages [s].
            checkInterval = 2

            # The timeout limit. After this timeout the process is
            # marked as "not responding". The timeout interval should
            # be larger than the process's heartbeat interval. [s]
            timeout = 10

            procRunning = True
            isZombie = False
            self.logger.debug("Checking process...")
            lastResponse = 0
            while procRunning:
                #self.logger.debug("Waiting for message...")

                procStatus = proc.poll()

                #self.logger.debug('procStatus: %s', procStatus)

                if procStatus != None:
                    procRunning = False
                    #self.logger.debug('Process %d has stopped with return code %s.', proc.pid, procStatus)
                    msgTopic = 'state.collection.execution'
                    msg['state'] = 'stopped'
                    msg['pid'] = proc.pid
                    msg['procName'] = procName
                    msg['curTime'] = datetime.now()
                    CallAfter(pub.sendMessage, msgTopic, msg=msg)

                else:
                    #self.logger.debug('Process %d is still running.', proc.pid)
                    msgTopic = 'state.collection.execution'
                    msg['state'] = 'running'
                    msg['pid'] = proc.pid
                    msg['procName'] = procName
                    msg['curTime'] = datetime.now()
                    CallAfter(pub.sendMessage, msgTopic, msg=msg)

                sleep(checkInterval)

                # Here is some code using the pipe and the heartbeat of the
                # collection. I think this caused some unexpected crashes of
                # the GUI. Might be some event loop race conditions.

                #if parentEnd.poll(checkInterval):
                #msg = parentEnd.recv()
                ##print msg
                #self.logger.debug("Received message: [%s]: %s" % (msg['state'], msg['msg']))
#
# # Send the message to the system.
#msgTopic = "state.collection.execution"
# msg['isError'] = False
##pub.sendMessage(msgTopic, msg)

#lastResponse = 0
#if msg['state'] == 'stopped':
#    procRunning = False
# else:
#lastResponse += checkInterval
# self.logger.debug("No message received.")

#if lastResponse > timeout:
#procRunning = False
# isZombie = True

#self.logger.debug("End checking process %d.", proc.pid)

        if self.activeCollection:
            if not project.threadMutex:
                project.threadMutex = thread.allocate_lock()

            col2Proc = copy.deepcopy(self.activeCollection)
            curTime = datetime.now()
            timeStampString = datetime.strftime(curTime, '%Y%m%d_%H%M%S_%f')
            processName = col2Proc.name + "_" + timeStampString
            col2Proc.procName = col2Proc.name + "_" + timeStampString

            msg = "Executing collection " + col2Proc.name + "with process name: " + processName + "."
            self.logger.info(msg)

            msgTopic = "state.collection.execution"
            msg = {}
            msg['state'] = 'starting'
            msg['startTime'] = curTime
            msg['isError'] = False
            msg['pid'] = None
            msg['procName'] = col2Proc.procName
            pub.sendMessage(msgTopic, msg=msg)

            #(parentEnd, childEnd) = multiprocessing.Pipe()
            self.logger.debug("process name: %s" % col2Proc.procName)
            #thread.start_new_thread(processChecker, (p, parentEnd, project.threadMutex))

            # Store all the needed data in a temporary file.
            #import tempfile
            import shelve
            #tmpDir = tempfile.gettempdir()
            filename = os.path.join(
                project.tmpDir, col2Proc.procName +
                '.ced')  # ced for Collection Execution Data

            db = shelve.open(filename, flag='n')
            db['project'] = project
            db['collection'] = col2Proc
            db['package_directories'] = project.psybase.packageMgr.packageDirectories
            db['waveclient'] = [(x.name, x.mode, x.pickle_attributes)
                                for x in project.waveclient.itervalues()]
            db['project_server'] = project.psybase.project_server
            db.close()

            # Start the collection using the cecClient as a subprocess.
            cecPath = os.path.dirname(os.path.abspath(psysmon.core.__file__))
            #proc = subprocess.Popen([sys.executable, os.path.join(cecPath, 'cecSubProcess.py'), filename, col2Proc.procName],
            #                        stdout=subprocess.PIPE)
            proc = subprocess.Popen([
                sys.executable,
                os.path.join(cecPath, 'cecSubProcess.py'), filename,
                col2Proc.procName
            ])

            msgTopic = "state.collection.execution"
            msg = {}
            msg['state'] = 'started'
            msg['startTime'] = curTime
            msg['isError'] = False
            msg['pid'] = proc.pid
            msg['procName'] = col2Proc.procName
            pub.sendMessage(msgTopic, msg=msg)

            thread.start_new_thread(processChecker, (proc, col2Proc.procName))

        else:
            raise PsysmonError('No active collection found!')