Exemple #1
0
    def run(self, data, store, signal, context, **kwargs):
        """ The main run method of the walk task.

        Args:
            data (MultiTaskData): The data object that has been passed from the
                                  predecessor task.
            store (DataStoreDocument): The persistent data store object that allows the
                                       task to store data for access across the current
                                       workflow run.
            signal (TaskSignal): The signal object for tasks. It wraps the construction
                                 and sending of signals into easy to use methods.
            context (TaskContext): The context in which the tasks runs.

        Raises:
            LightflowFilesystemPathError: If the specified path is not absolute.

        Returns:
            Action: An Action object containing the data that should be passed on
                    to the next task and optionally a list of successor tasks that
                    should be executed.
        """
        params = self.params.eval(data, store)

        if not isabs(params.path):
            raise LightflowFilesystemPathError(
                'The specified path is not an absolute path')

        for entry in self._scantree(params.path, params.recursive):
            if self._callback is not None:
                self._callback(entry, data, store, signal, context)

        return Action(data)
Exemple #2
0
    def run(self, data, store, signal, context, **kwargs):
        """ The main run method of the MoveTask task.

        Args:
            data (MultiTaskData): The data object that has been passed from the
                                  predecessor task.
            store (DataStoreDocument): The persistent data store object that allows the
                                       task to store data for access across the current
                                       workflow run.
            signal (TaskSignal): The signal object for tasks. It wraps the construction
                                 and sending of signals into easy to use methods.
            context (TaskContext): The context in which the tasks runs.

        Raises:
            LightflowFilesystemPathError: If the source is a directory
                                          but the target is not.
            LightflowFilesystemMoveError: If the move process failed.

        Returns:
            Action: An Action object containing the data that should be passed on
                    to the next task and optionally a list of successor tasks that
                    should be executed.
        """
        params = self.params.eval(data, store)
        sources = [params.sources] if isinstance(params.sources,
                                                 str) else params.sources

        for source in sources:
            logger.info('Move {} to {}'.format(source, params.destination))

            if not os.path.isabs(source):
                raise LightflowFilesystemPathError(
                    'The source path is not an absolute path')

            if not os.path.isabs(params.destination):
                raise LightflowFilesystemPathError(
                    'The destination path is not an absolute path')

            if os.path.isdir(source) and not os.path.isdir(params.destination):
                raise LightflowFilesystemPathError(
                    'The destination is not a valid directory')

            try:
                shutil.move(source, params.destination)
            except OSError as e:
                raise LightflowFilesystemMoveError(e)

        return Action(data)
    def run(self, data, store, signal, context, **kwargs):
        """ The main run method of the PvTriggerTask task.

        Args:
            data (MultiTaskData): The data object that has been passed from the
                                  predecessor task.
            store (DataStoreDocument): The persistent data store object that allows the
                                       task to store data for access across the current
                                       workflow run.
            signal (TaskSignal): The signal object for tasks. It wraps the construction
                                 and sending of signals into easy to use methods.
            context (TaskContext): The context in which the tasks runs.
        """
        params = self.params.eval(data, store)

        skipped_initial = False if params.skip_initial_callback else True
        polling_event_number = 0
        queue = deque()

        # set up the internal callback
        pv = PV(params.pv_name,
                callback=partial(self._pv_callback, queue=queue))

        while True:
            if params.event_trigger_time is not None:
                time.sleep(params.event_trigger_time)

            # check every stop_polling_rate events the stop signal
            polling_event_number += 1
            if polling_event_number > params.stop_polling_rate:
                polling_event_number = 0
                if signal.is_stopped:
                    break

            # get all the events from the queue and call the callback function
            while len(queue) > 0:
                event = queue.pop()
                if skipped_initial:
                    if self._callback is not None:
                        self._callback(data, store, signal, context, **event)
                else:
                    skipped_initial = True

        pv.clear_callbacks()
        return Action(data)
Exemple #4
0
    def run(self, data, store, signal, context, **kwargs):
        """ The main run method of the Python task.

        Args:
            data (:class:`.MultiTaskData`): The data object that has been passed from the
                predecessor task.
            store (:class:`.DataStoreDocument`): The persistent data store object that allows the
                task to store data for access across the current workflow run.
            signal (TaskSignal): The signal object for tasks. It wraps the construction
                and sending of signals into easy to use methods.
            context (TaskContext): The context in which the tasks runs.

        Returns:
            Action: An Action object containing the data that should be passed on
                to the next task and optionally a list of successor tasks that
                should be executed.
        """
        if self._callback is not None:
            result = self._callback(data, store, signal, context, **kwargs)
            return result if result is not None else Action(data)
Exemple #5
0
    def run(self, data, store, signal, context, **kwargs):
        """ The main run method of the MakeDir task.

        Args:
            data (MultiTaskData): The data object that has been passed from the
                                  predecessor task.
            store (DataStoreDocument): The persistent data store object that allows the
                                       task to store data for access across the current
                                       workflow run.
            signal (TaskSignal): The signal object for tasks. It wraps the construction
                                 and sending of signals into easy to use methods.
            context (TaskContext): The context in which the tasks runs.

        Raises:
            AbsolutePathError: If the specified directories are not absolute paths.

        Returns:
            Action: An Action object containing the data that should be passed on
                    to the next task and optionally a list of successor tasks that
                    should be executed.
        """
        params = self.params.eval(data, store)
        paths = [params.paths] if isinstance(params.paths, str) else params.paths
#
        for path in paths:
            if not os.path.isabs(path):
                raise LightflowFilesystemPathError(
                    'The specified path is not an absolute path')

            if not os.path.exists(path):
                try:
                    os.makedirs(path)
                except OSError as e:
                    raise LightflowFilesystemMkdirError(e)

            else:
                logger.info('Directory {} already exists. Skip creation.'.format(path))

        return Action(data)
    def run(self, data, store, signal, context, **kwargs):
        """ The main run method of the NotifyTriggerTask task.

        Args:
            data (MultiTaskData): The data object that has been passed from the
                                  predecessor task.
            store (DataStoreDocument): The persistent data store object that allows the
                                       task to store data for access across the current
                                       workflow run.
            signal (TaskSignal): The signal object for tasks. It wraps the construction
                                 and sending of signals into easy to use methods.
            context (TaskContext): The context in which the tasks runs.

        Raises:
            LightflowFilesystemPathError: If the specified path is not absolute.
        """
        params = self.params.eval(data, store)

        if not os.path.isabs(params.path):
            raise LightflowFilesystemPathError(
                'The specified path is not an absolute path')

        # if requested, pre-fill the file list with existing lines
        lines = []
        num_read_lines = 0
        if params.use_existing:
            with open(params.path, 'r') as file:
                lines = file.readlines()

            num_read_lines = len(lines)
            if params.flush_existing and num_read_lines > 0:
                if self._callback is not None:
                    self._callback(lines, data, store, signal, context)

                del lines[:]

        polling_event_number = 0

        def watch_file(file_pointer, task_signal):
            while True:
                if task_signal.is_stopped:
                    break

                new = file_pointer.readline()
                if new:
                    yield new
                else:
                    time.sleep(params.event_trigger_time)

        file = open(params.path, 'r')
        try:
            if params.use_existing:
                for i in range(num_read_lines):
                    file.readline()
            else:
                file.seek(0, 2)

            for line in watch_file(file, signal):
                lines.append(line)

                # check every stop_polling_rate events the stop signal
                polling_event_number += 1
                if polling_event_number > params.stop_polling_rate:
                    polling_event_number = 0
                    if signal.is_stopped:
                        break

                # as soon as enough lines have been aggregated call the callback function
                if len(lines) >= params.aggregate:
                    chunks = len(lines) // params.aggregate
                    for i in range(0, chunks):
                        if self._callback is not None:
                            self._callback(lines[0:params.aggregate], data,
                                           store, signal, context)

                        del lines[0:params.aggregate]
        finally:
            file.close()

        return Action(data)
Exemple #7
0
def decide_on_successor(data, store, signal, context):
    data['number'] = random()
    if data['number'] < 0.5:
        return Action(data, limit=[small_number_task])
    else:
        return Action(data, limit=[large_number_task])
Exemple #8
0
def branch_with_limit(data, store, signal, context):
    return Action(data, limit=[lane1_print_task, 'lane2_print_task'])
Exemple #9
0
    def run(self, data, store, signal, context, **kwargs):
        """ The main run method of the Python task.

        Args:
            data (:class:`.MultiTaskData`): The data object that has been passed from the
                predecessor task.
            store (:class:`.DataStoreDocument`): The persistent data store object that allows the
                task to store data for access across the current workflow run.
            signal (TaskSignal): The signal object for tasks. It wraps the construction
                and sending of signals into easy to use methods.
            context (TaskContext): The context in which the tasks runs.

        Returns:
            Action (Action): An Action object containing the data that should be passed on
                to the next task and optionally a list of successor tasks that
                should be executed.
        """
        params = self.params.eval(data, store, exclude=['command'])

        capture_stdout = self._callback_stdout is not None or params.capture_stdout
        capture_stderr = self._callback_stderr is not None or params.capture_stderr

        stdout_file = TemporaryFile() if params.capture_stdout else None
        stderr_file = TemporaryFile() if params.capture_stderr else None

        stdout = PIPE if capture_stdout else None
        stderr = PIPE if capture_stderr else None

        # change the user or group under which the process should run
        if params.user is not None or params.group is not None:
            pre_exec = self._run_as(params.user, params.group)
        else:
            pre_exec = None

        # call the command
        proc = Popen(self.params.eval_single('command', data, store),
                     cwd=params.cwd,
                     shell=True,
                     env=params.env,
                     preexec_fn=pre_exec,
                     stdout=stdout,
                     stderr=stderr,
                     stdin=PIPE if params.stdin is not None else None)

        # if input is available, send it to the process
        if params.stdin is not None:
            proc.stdin.write(params.stdin.encode(sys.getfilesystemencoding()))

        # send a notification that the process has been started
        try:
            if self._callback_process is not None:
                self._callback_process(proc.pid, data, store, signal, context)
        except (StopTask, AbortWorkflow):
            proc.terminate()
            raise

        # send the output handling to a thread
        if capture_stdout or capture_stderr:
            output_reader = BashTaskOutputReader(proc, stdout_file,
                                                 stderr_file,
                                                 self._callback_stdout,
                                                 self._callback_stderr,
                                                 params.refresh_time, data,
                                                 store, signal, context)
            output_reader.start()
        else:
            output_reader = None

        # wait for the process to complete and watch for a stop signal
        while proc.poll() is None or\
                (output_reader is not None and output_reader.is_alive()):
            sleep(params.refresh_time)
            if signal.is_stopped:
                proc.terminate()

        if output_reader is not None:
            output_reader.join()
            data = output_reader.data

            # if a stop or abort exception was raised, stop the bash process and re-raise
            if output_reader.exc_obj is not None:
                if proc.poll() is None:
                    proc.terminate()
                raise output_reader.exc_obj

        # send a notification that the process has completed
        if self._callback_end is not None:
            if stdout_file is not None:
                stdout_file.seek(0)
            if stderr_file is not None:
                stderr_file.seek(0)

            self._callback_end(proc.returncode, stdout_file, stderr_file, data,
                               store, signal, context)

        if stdout_file is not None:
            stdout_file.close()

        if stderr_file is not None:
            stderr_file.close()

        return Action(data)
    def run(self, data, store, signal, context, **kwargs):
        """ The main run method of the NotifyTriggerTask task.

        Args:
            data (MultiTaskData): The data object that has been passed from the
                                  predecessor task.
            store (DataStoreDocument): The persistent data store object that allows the
                                       task to store data for access across the current
                                       workflow run.
            signal (TaskSignal): The signal object for tasks. It wraps the construction
                                 and sending of signals into easy to use methods.
            context (TaskContext): The context in which the tasks runs.

        Raises:
            LightflowFilesystemPathError: If the specified path is not absolute.
        """
        params = self.params.eval(data, store)

        # build notification mask
        on_file_create = constants.IN_CREATE if params.on_file_create else 0x00000000
        on_file_close = constants.IN_CLOSE_WRITE if params.on_file_close else 0x00000000
        on_file_delete = constants.IN_DELETE if params.on_file_delete else 0x00000000
        on_file_move = constants.IN_MOVE if params.on_file_move else 0x00000000
        mask = (on_file_create | on_file_close | on_file_delete | on_file_move)

        if not os.path.isabs(params.path):
            raise LightflowFilesystemPathError(
                'The specified path is not an absolute path')

        if params.recursive:
            notify = adapters.InotifyTree(params.path.encode('utf-8'))
        else:
            notify = adapters.Inotify()
            notify.add_watch(params.path.encode('utf-8'))

        # setup regex
        if isinstance(params.exclude_mask, str):
            regex = re.compile(params.exclude_mask)
        else:
            regex = None

        # if requested, pre-fill the file list with existing files
        files = []
        if params.use_existing:
            for (dir_path, dir_names, filenames) in os.walk(params.path):
                files.extend([os.path.join(dir_path, filename) for filename in filenames])
                if not params.recursive:
                    break

            if regex is not None:
                files = [file for file in files if regex.search(file) is None]

            if params.flush_existing and len(files) > 0:
                if self._callback is not None:
                    self._callback(files, data, store, signal, context)
                del files[:]

        polling_event_number = 0
        try:
            for event in notify.event_gen():
                if params.event_trigger_time is not None:
                    time.sleep(params.event_trigger_time)

                # check every stop_polling_rate events the stop signal
                polling_event_number += 1
                if polling_event_number > params.stop_polling_rate:
                    polling_event_number = 0
                    if signal.is_stopped:
                        break

                # in case of an event check whether it matches the mask and call a dag
                if event is not None:
                    (header, type_names, watch_path, filename) = event

                    if (not header.mask & constants.IN_ISDIR) and\
                            (header.mask & mask):
                        new_file = os.path.join(watch_path.decode('utf-8'),
                                                filename.decode('utf-8'))

                        add_file = not params.skip_duplicate or \
                            (params.skip_duplicate and new_file not in files)

                        if add_file and regex is not None:
                            add_file = regex.search(new_file) is None

                        if add_file:
                            files.append(new_file)

                # as soon as enough files have been aggregated call the sub dag
                if len(files) >= params.aggregate:
                    chunks = len(files) // params.aggregate
                    for i in range(0, chunks):
                        if self._callback is not None:
                            self._callback(files[0:params.aggregate], data,
                                           store, signal, context)
                        del files[0:params.aggregate]

        finally:
            if not params.recursive:
                notify.remove_watch(params.path.encode('utf-8'))

        return Action(data)