Beispiel #1
0
 def setUp(self):
     env.reset()
     subprocess.call('sos remove -s', shell=True)
     #self.resetDir('~/.sos')
     self.temp_files = []
     self.resetDir('temp')
     Host.reset()
Beispiel #2
0
 def setUp(self):
     env.reset()
     #self.resetDir('~/.sos')
     self.temp_files = []
     Host.reset()
     # remove .status file left by failed workflows.
     subprocess.call('sos purge', shell=True)
Beispiel #3
0
 def submit_tasks(self, tasks):
     if not tasks:
         return
     if self.host is None:
         if 'queue' in env.sos_dict['_runtime']:
             queue = env.sos_dict['_runtime']['queue']
         elif env.config['default_queue']:
             queue = env.config['default_queue']
         else:
             queue = 'localhost'
         self.host = Host(queue)
     for task in tasks:
         self.host.submit_task(task)
Beispiel #4
0
    def testRemoteExecution(self):
        subprocess.check_output('sos purge', shell=True).decode()
        script = SoS_Script('''
[10]
input: for_each={'i': range(5)}
task:

run: expand=True
    echo I am {i}
    sleep {5+i}
''')
        wf = script.workflow()
        res = Base_Executor(wf, config={
                'config_file': '~/docker.yml',
                # do not wait for jobs
                'wait_for_task': False,
                'default_queue': 'docker',
                'max_running_jobs': 5,
                'sig_mode': 'force',
                }).run()
        import time
        # we should be able to get status
        tasks = ' '.join(res['pending_tasks'])
        # wait another 15 seconds?
        time.sleep(15)
        out = subprocess.check_output('sos status {} -c ~/docker.yml -q docker'.format(tasks), shell=True).decode()
        self.assertEqual(out.count('completed'), len(res['pending_tasks']), 'Expect all completed jobs: ' + out)

        Host.reset()
        # until we run the workflow again
        #st = time.time()
        Base_Executor(wf, config={
                'config_file': '~/docker.yml',
                # do not wait for jobs
                'wait_for_task': True,
                'default_queue': 'docker',
                'resume_mode': True,
                }).run()
        # should finish relatively fast?
        #self.assertLess(time.time() - st, 5)
        out = subprocess.check_output('sos status {} -c ~/docker.yml'.format(tasks), shell=True).decode()
        self.assertEqual(out.count('completed'), len(res['pending_tasks']), 'Expect all completed jobs: ' + out)
Beispiel #5
0
class Interactive_Step_Executor(Base_Step_Executor):
    def __init__(self, step, mode='interactive'):
        super(Interactive_Step_Executor, self).__init__(step)
        self.run_mode = mode
        self.host = None

    def init_input_output_vars(self):
        # we keep these variables (which can be result of stepping through previous statements)
        # if no input and/or output statement is defined
        for key in ('step_input', '_depends', 'step_output', 'step_depends',
                    '_depends'):
            if key not in env.sos_dict:
                env.sos_dict.set(key, sos_targets([]))
        if '_output' not in env.sos_dict:
            env.sos_dict.set('_output', sos_targets(_undetermined=True))
        if any(x[0] == ':' and x[1] == 'input' for x in self.step.statements):
            env.sos_dict.set('step_input', sos_targets([]))
            env.sos_dict.set('_input', sos_targets([]))
        if any(x[0] == ':' and x[1] == 'output' for x in self.step.statements):
            env.sos_dict.set('step_output', sos_targets([]))
            env.sos_dict.set('_output', sos_targets([]))
        env.sos_dict.pop('__default_output__', None)

    def submit_tasks(self, tasks):
        if not tasks:
            return
        if self.host is None:
            if 'queue' in env.sos_dict['_runtime']:
                queue = env.sos_dict['_runtime']['queue']
            elif env.config['default_queue']:
                queue = env.config['default_queue']
            else:
                queue = 'localhost'
            self.host = Host(queue)
        for task in tasks:
            self.host.submit_task(task)

    def wait_for_tasks(self, tasks, all_submitted):
        if not tasks:
            return {}
        # when we wait, the "outsiders" also need to see the tags etc
        # of the tasks so we have to write to the database. #156
        env.master_push_socket.send_pyobj(['commit_sig'])
        # turn this function to a generator to satisfy the interface, but do not
        # actually wait for any socket.
        yield None
        # wait till the executor responde
        if all(x == 'completed' for x in self.host.check_status(tasks)):
            if len(tasks) > 4:
                print('HINT: {} task{} completed: {}, {}, ..., {}'.format(
                    len(tasks), 's' if len(tasks) > 1 else '',
                    f"""<a onclick="task_info('{tasks[0]}', '{self.host.alias}')">{tasks[0][:4]}</a>""",
                    f"""<a onclick="task_info('{tasks[1]}', '{self.host.alias}')">{tasks[1][:4]}</a>""",
                    f"""<a onclick="task_info('{tasks[-1]}', '{self.host.alias}')">{tasks[-1][:4]}</a>"""
                ))
            else:
                print('HINT: {} task{} completed: {}'.format(
                    len(tasks), 's' if len(tasks) > 1 else '', ','.join([
                        f"""<a onclick="task_info('{x}', '{self.host.alias}')">{x[:4]}</a>"""
                        for x in tasks
                    ])))
            return self.host.retrieve_results(tasks)
        res = self.host.check_status(tasks)
        if all(x not in ('submitted', 'pending', 'running') for x in res):
            # completed = [task for task, status in zip(tasks, res) if status == 'completed']
            return self.host.retrieve_results(tasks)
        raise TerminateExecution('Terminate with Running Tasks')

    def run(self):
        try:
            runner = Base_Step_Executor.run(self)
            yreq = next(runner)
            while True:
                yreq = runner.send(yreq)
        except StopIteration as e:
            return e.value

    def log(self, stage=None, msg=None):
        if stage == 'start':
            env.logger.debug('{} ``{}``: {}'.format(
                'Checking' if self.run_mode == 'dryrun' else 'Executing',
                self.step.step_name(), self.step.comment.strip()))
        elif stage == 'input':
            if env.sos_dict['step_input'] is not None:
                env.logger.debug('input:    ``{}``'.format(
                    short_repr(env.sos_dict['step_input'])))
        elif stage == 'output':
            if env.sos_dict['step_output'] is not None:
                env.logger.debug('output:   ``{}``'.format(
                    short_repr(env.sos_dict['step_output'])))

    def wait_for_subworkflows(self, workflow_results):
        '''Wait for results from subworkflows'''
        raise RuntimeError(
            'Nested workflow is not supported in interactive mode')

    def handle_unknown_target(self, e):
        # wait for the clearnce of unknown target
        yield None
        raise e

    def verify_dynamic_targets(self, targets):
        raise RuntimeError(
            'Dynamic targets are not supported in interative mode')
Beispiel #6
0
    def testActiveActionOption(self):
        '''Test the active option of actions'''
        # disallow
        self.assertRaises(
            ParsingError, SoS_Script, '''
[1]
rep = range(5)
input: for_each = 'rep'
# ff should change and be usable inside run
ff = f"{_rep}.txt"
run:  expand=True, active=1,2
echo {ff}
touch temp/{ff}
''')
        #
        for active, result in [
            ('0', ['temp/0.txt']),
            ('-1', ['temp/4.txt']),
            ('(1,2)', ['temp/1.txt', 'temp/2.txt']),
            ('[2,3]', ['temp/2.txt', 'temp/3.txt']),
            ('(0,2,4)', ['temp/0.txt', 'temp/2.txt', 'temp/4.txt']),
            ('slice(1,None)',
             ['temp/1.txt', 'temp/2.txt', 'temp/3.txt', 'temp/4.txt']),
            ('slice(1,-2)', ['temp/1.txt', 'temp/2.txt']),
            ('slice(None,None,2)', ['temp/0.txt', 'temp/2.txt', 'temp/4.txt']),
        ]:
            if os.path.isdir('temp'):
                shutil.rmtree('temp')
            os.mkdir('temp')
            # test first iteration
            script = SoS_Script(('''
[1]
rep = range(5)
input: for_each = 'rep'
# ff should change and be usable inside run
ff = f"{_rep}.txt"
run:  expand=True, active=%s
echo {ff}
touch temp/{ff}
''' % active).replace('/', os.sep))
            wf = script.workflow()
            env.config['sig_mode'] = 'force'
            env.config['wait_for_task'] = True
            Host.reset()
            Base_Executor(wf).run()
            files = list(glob.glob(os.path.join('temp', '*.txt')))
            self.assertEqual(sorted(files),
                             sorted([x.replace('/', os.sep) for x in result]))
            #
            # test last iteration
            shutil.rmtree('temp')
            #
            # test active option for task
            os.mkdir('temp')
            script = SoS_Script(('''
[1]
rep = range(5)
input: for_each = 'rep'
# ff should change and be usable inside run
ff = f"{_rep}.txt"
task:  active=%s
run: expand=True
echo {ff}
touch temp/{ff}
''' % active).replace('/', os.sep))
            wf = script.workflow()
            env.config['sig_mode'] = 'force'
            env.config['wait_for_task'] = True
            Host.reset()
            Base_Executor(wf).run()
            files = list(glob.glob(os.path.join('temp', '*.txt')))
            self.assertEqual(sorted(files),
                             sorted([x.replace('/', os.sep) for x in result]),
                             'With option {}'.format(active))
            #
            # test last iteration
            shutil.rmtree('temp')
Beispiel #7
0
def runfile(script=None,
            raw_args='',
            wdir='.',
            code=None,
            kernel=None,
            **kwargs):
    # this has something to do with Prefix matching rule of parse_known_args
    #
    # That is to say
    #
    #   --rep 3
    #
    # would be parsed as
    #
    #   args.workflow=3, unknown --rep
    #
    # instead of
    #
    #   args.workflow=None, unknown --rep 3
    #
    # we then have to change the parse to disable args.workflow when
    # there is no workflow option.
    raw_args = shlex.split(raw_args) if isinstance(raw_args, str) else raw_args
    if (script is None and code is None) or '-h' in raw_args:
        parser = get_run_parser(interactive=True, with_workflow=True)
        parser.print_help()
        return
    if raw_args and raw_args[0].lstrip().startswith('-'):
        parser = get_run_parser(interactive=True, with_workflow=False)
        parser.error = _parse_error
        args, workflow_args = parser.parse_known_args(raw_args)
        args.workflow = None
    else:
        parser = get_run_parser(interactive=True, with_workflow=True)
        parser.error = _parse_error
        args, workflow_args = parser.parse_known_args(raw_args)

    # for reporting purpose
    sys.argv = ['%run'] + raw_args

    env.verbosity = args.verbosity
    if kernel and not isinstance(env.logger.handlers[0],
                                 NotebookLoggingHandler):
        env.logger.handlers = []
        levels = {
            0: logging.ERROR,
            1: logging.WARNING,
            2: logging.INFO,
            3: logging.DEBUG,
            4: logging.TRACE,
            None: logging.INFO
        }
        env.logger.addHandler(
            NotebookLoggingHandler(levels[env.verbosity],
                                   kernel,
                                   title=' '.join(sys.argv)))
    else:
        env.logger.handers[0].setTitle(' '.join(sys.argv))

    dt = datetime.datetime.now().strftime('%m%d%y_%H%M')
    if args.__dag__ is None:
        args.__dag__ = f'workflow_{dt}.dot'
    elif args.__dag__ == '':
        args.__dag__ = None

    if args.__report__ is None:
        args.__report__ = f'workflow_{dt}.html'
    elif args.__report__ == '':
        args.__report__ = None

    if args.__remote__:
        from sos.utils import load_config_files
        cfg = load_config_files(args.__config__)
        env.sos_dict.set('CONFIG', cfg)

        # if executing on a remote host...
        from sos.hosts import Host
        host = Host(args.__remote__)
        #
        if script is None:
            if not code.strip():
                return
            script = os.path.join('.sos', '__interactive__.sos')
            with open(script, 'w') as s:
                s.write(code)

        # copy script to remote host...
        host.send_to_host(script)
        from sos.utils import remove_arg
        argv = shlex.split(raw_args) if isinstance(raw_args, str) else raw_args
        argv = remove_arg(argv, '-r')
        argv = remove_arg(argv, '-c')
        # execute the command on remote host
        try:
            with kernel.redirect_sos_io():
                ret = host._host_agent.run_command(['sos', 'run', script] +
                                                   argv,
                                                   wait_for_task=True,
                                                   realtime=True)
            if ret:
                kernel.send_response(
                    kernel.iopub_socket, 'stream',
                    dict(name='stderr',
                         text=
                         f'remote execution of workflow exited with code {ret}'
                         ))
        except Exception as e:
            if kernel:
                kernel.send_response(kernel.iopub_socket, 'stream', {
                    'name': 'stdout',
                    'text': str(e)
                })
        return

    if args.__bin_dirs__:
        for d in args.__bin_dirs__:
            if d == '~/.sos/bin' and not os.path.isdir(os.path.expanduser(d)):
                os.makedirs(os.path.expanduser(d), exist_ok=True)
        os.environ['PATH'] = os.pathsep.join(
            [os.path.expanduser(x)
             for x in args.__bin_dirs__]) + os.pathsep + os.environ['PATH']

    # clear __step_input__, __step_output__ etc because there is
    # no concept of passing input/outputs across cells.
    env.sos_dict.set('__step_output__', sos_targets([]))
    for k in [
            '__step_input__', '__default_output__', 'step_input',
            'step_output', 'step_depends', '_input', '_output', '_depends'
    ]:
        env.sos_dict.pop(k, None)

    try:
        if script is None:
            if not code.strip():
                return
            if kernel is None:
                script = SoS_Script(content=code)
            else:
                if kernel._workflow_mode:
                    # in workflow mode, the content is sent by magics %run and %sosrun
                    script = SoS_Script(content=code)
                else:
                    # this is a scratch step...
                    # if there is no section header, add a header so that the block
                    # appears to be a SoS script with one section
                    if not any([
                            SOS_SECTION_HEADER.match(line)
                            or line.startswith('%from')
                            or line.startswith('%include')
                            for line in code.splitlines()
                    ]):
                        code = '[scratch_0]\n' + code
                        script = SoS_Script(content=code)
                    else:
                        #kernel.send_frontend_msg('stream',
                        #                         {'name': 'stdout', 'text': 'Workflow cell can only be executed with magic %run or %sosrun.'},
                        #                         title='# SoS warning')
                        return
        else:
            script = SoS_Script(filename=script)
        workflow = script.workflow(args.workflow,
                                   use_default=not args.__targets__)
        env.config: DefaultDict[str, Union[None, bool, str]] = defaultdict(str)
        executor = Interactive_Executor(
            workflow,
            args=workflow_args,
            config={
                'config_file':
                args.__config__,
                'output_dag':
                args.__dag__,
                'output_report':
                args.__report__,
                'sig_mode':
                'ignore' if args.dryrun else args.__sig_mode__,
                'default_queue':
                '' if args.__queue__ is None else args.__queue__,
                'wait_for_task':
                True if args.__wait__ is True or args.dryrun else
                (False if args.__no_wait__ else None),
                'resume_mode':
                kernel is not None and kernel._resume_execution,
                'run_mode':
                'dryrun' if args.dryrun else 'interactive',
                'verbosity':
                args.verbosity,

                # wait if -w or in dryrun mode, not wait if -W, otherwise use queue default
                'max_procs':
                args.__max_procs__,
                'max_running_jobs':
                args.__max_running_jobs__,
                # for infomration and resume only
                'workdir':
                os.getcwd(),
                'script':
                "interactive",
                'workflow':
                args.workflow,
                'targets':
                args.__targets__,
                'bin_dirs':
                args.__bin_dirs__,
                'workflow_args':
                workflow_args
            })
        return executor.run(args.__targets__)['__last_res__']
    except PendingTasks:
        raise
    except SystemExit:
        # this happens because the executor is in resume mode but nothing
        # needs to be resumed, we simply pass
        return
    except Exception:
        if args.verbosity and args.verbosity > 2:
            sys.stderr.write(get_traceback())
        raise
    finally:
        env.config['sig_mode'] = 'ignore'
        env.verbosity = 2
Beispiel #8
0
class Interactive_Step_Executor(Step_Executor):
    def __init__(self, step):
        # This is the only interesting part of this executor. Basically
        # it derives everything from SP_Step_Executor but does not
        # use the Queue mechanism, so the __init__ and the run
        # functions are copied from Base_Step_Executor
        Base_Step_Executor.__init__(self, step)
        self.run_mode='interactive'
        self.host = None

    def submit_tasks(self, tasks):
        if not tasks:
            return
        if self.host is None:
            if 'queue' in env.sos_dict['_runtime']:
                self.queue = env.sos_dict['_runtime']['queue']
            elif env.config['default_queue']:
                self.queue = env.config['default_queue']
            else:
                self.queue = 'localhost'

            self.host = Host(self.queue)
        for task in tasks:
            self.host.submit_task(task)

    def wait_for_tasks(self, tasks):
        if not tasks:
            return {}
        # wait till the executor responde
        if all(x == 'completed' for x in self.host.check_status(tasks)):
            if len(tasks) > 4:
                print('!sos_hint: {} task{} completed: {}, {}, ..., {}'.format(
                    len(tasks), 's' if len(tasks) > 1 else '',
                    f"""<a onclick="task_info('{tasks[0]}', '{self.queue}')">{tasks[0][:4]}</a>""",
                    f"""<a onclick="task_info('{tasks[1]}', '{self.queue}')">{tasks[1][:4]}</a>""",
                    f"""<a onclick="task_info('{tasks[-1]}', '{self.queue}')">{tasks[-1][:4]}</a>"""))
            else:
                print('!sos_hint: {} task{} completed: {}'.format(len(tasks), 's' if len(tasks) > 1 else '',
                    ','.join([f"""<a onclick="task_info('{x}', '{self.queue}')">{x[:4]}</a>""" for x in tasks])))
            self.host._task_engine.remove_tasks(tasks)
            return self.host.retrieve_results(tasks)
        while True:
            res = self.host.check_status(tasks)
            if all(x not in ('submitted', 'pending', 'running') for x in res):
                #completed = [task for task, status in zip(tasks, res) if status == 'completed']
                self.host._task_engine.remove_tasks(tasks)
                return self.host.retrieve_results(tasks)
            # no pending
            elif not env.config['wait_for_task']:
                raise PendingTasks([(self.queue, x) for x,y in zip(tasks, res) if y in ('pending', 'submitted', 'running')])
            time.sleep(1)


    def run(self):
        return Base_Step_Executor.run(self)

    def log(self, stage=None, msg=None):
        if stage == 'start':
            env.logger.debug('{} ``{}``: {}'.format('Checking' if self.run_mode == 'dryrun' else 'Executing',
                self.step.step_name(), self.step.comment.strip()))
        elif stage == 'input':
            if env.sos_dict['input'] is not None:
                env.logger.debug('input:    ``{}``'.format(short_repr(env.sos_dict['input'])))
        elif stage == 'output':
            if env.sos_dict['output'] is not None:
                env.logger.debug('output:   ``{}``'.format(short_repr(env.sos_dict['output'])))
Beispiel #9
0
def runfile(script=None,
            raw_args='',
            wdir='.',
            code=None,
            kernel=None,
            **kwargs):
    # this has something to do with Prefix matching rule of parse_known_args
    #
    # That is to say
    #
    #   --rep 3
    #
    # would be parsed as
    #
    #   args.workflow=3, unknown --rep
    #
    # instead of
    #
    #   args.workflow=None, unknown --rep 3
    #
    # we then have to change the parse to disable args.workflow when
    # there is no workflow option.
    args = shlex.split(raw_args) if isinstance(raw_args, str) else raw_args
    if (script is None and code is None) or '-h' in args:
        parser = get_run_parser(interactive=True, with_workflow=True)
        parser.print_help()
        return
    if args and args[0].lstrip().startswith('-'):
        parser = get_run_parser(interactive=True, with_workflow=False)
        parser.error = _parse_error
        args, workflow_args = parser.parse_known_args(args)
        args.workflow = None
    else:
        parser = get_run_parser(interactive=True, with_workflow=True)
        parser.error = _parse_error
        args, workflow_args = parser.parse_known_args(args)

    # no multi-processing in interactive mode
    env.max_jobs = 1
    env.verbosity = args.verbosity

    if args.__queue__ == '':
        from sos.hosts import list_queues
        list_queues(args.__config__, args.verbosity)
        return

    if args.__remote__:
        from sos.utils import load_config_files
        cfg = load_config_files(args.__config__)
        env.sos_dict.set('CONFIG', cfg)
        if args.__remote__ == '':
            from .hosts import list_queues
            list_queues(cfg, args.verbosity)
            return

        # if executing on a remote host...
        from sos.hosts import Host
        host = Host(args.__remote__)
        #
        if script is None:
            if not code.strip():
                return
            script = os.path.join('.sos', '__interactive__.sos')
            with open(script, 'w') as s:
                s.write(code)

        # copy script to remote host...
        host.send_to_host(script)
        from sos.utils import remove_arg
        argv = shlex.split(raw_args) if isinstance(raw_args, str) else raw_args
        argv = remove_arg(argv, '-r')
        argv = remove_arg(argv, '-c')
        # execute the command on remote host
        try:
            with kernel.redirect_sos_io():
                ret = host._host_agent.run_command(['sos', 'run', script] +
                                                   argv,
                                                   wait_for_task=True,
                                                   realtime=True)
            if ret:
                kernel.send_response(
                    kernel.iopub_socket, 'stream',
                    dict(name='stderr',
                         text=
                         f'remote execution of workflow exited with code {ret}'
                         ))
        except Exception as e:
            if kernel:
                kernel.send_response(kernel.iopub_socket, 'stream', {
                    'name': 'stdout',
                    'text': str(e)
                })
        return

    if args.__bin_dirs__:
        import fasteners
        for d in args.__bin_dirs__:
            if d == '~/.sos/bin' and not os.path.isdir(os.path.expanduser(d)):
                with fasteners.InterProcessLock(
                        os.path.join(tempfile.gettempdir(), 'sos_lock_bin')):
                    os.makedirs(os.path.expanduser(d))
            elif not os.path.isdir(os.path.expanduser(d)):
                raise ValueError(f'directory does not exist: {d}')
        os.environ['PATH'] = os.pathsep.join(
            [os.path.expanduser(x)
             for x in args.__bin_dirs__]) + os.pathsep + os.environ['PATH']

    # clear __step_input__, __step_output__ etc because there is
    # no concept of passing input/outputs across cells.
    env.sos_dict.set('__step_output__', [])
    for k in ['__step_input__', '__default_output__', 'input', 'output', \
        'depends', '_input', '_output', '_depends']:
        env.sos_dict.pop(k, None)

    try:
        if script is None:
            if not code.strip():
                return
            if kernel is None:
                script = SoS_Script(content=code)
            else:
                if kernel._workflow_mode:
                    # in workflow mode, the content is sent by magics %run and %sosrun
                    script = SoS_Script(content=code)
                else:
                    # this is a scratch step...
                    # if there is no section header, add a header so that the block
                    # appears to be a SoS script with one section
                    if not any([
                            SOS_SECTION_HEADER.match(line)
                            or line.startswith('%from')
                            or line.startswith('%include')
                            for line in code.splitlines()
                    ]):
                        code = '[scratch_0]\n' + code
                        script = SoS_Script(content=code)
                    else:
                        if kernel.cell_idx == -1:
                            kernel.send_frontend_msg(
                                'stream', {
                                    'name':
                                    'stdout',
                                    'text':
                                    'Workflow can only be executed with magic %run or %sosrun.'
                                })
                        return
        else:
            script = SoS_Script(filename=script)
        workflow = script.workflow(args.workflow)
        executor = Interactive_Executor(
            workflow,
            args=workflow_args,
            config={
                'config_file':
                args.__config__,
                'output_dag':
                args.__dag__,
                'sig_mode':
                args.__sig_mode__,
                'default_queue':
                '' if args.__queue__ is None else args.__queue__,
                'wait_for_task':
                True if args.__wait__ is True or args.dryrun else
                (False if args.__no_wait__ else None),
                'resume_mode':
                kernel is not None and kernel._resume_execution,
                'run_mode':
                'dryrun' if args.dryrun else 'interactive',
                'verbosity':
                args.verbosity,

                # wait if -w or in dryrun mode, not wait if -W, otherwise use queue default
                'max_procs':
                1,
                'max_running_jobs':
                args.__max_running_jobs__,
                # for infomration and resume only
                'workdir':
                os.getcwd(),
                'script':
                "interactive",
                'workflow':
                args.workflow,
                'targets':
                args.__targets__,
                'bin_dirs':
                args.__bin_dirs__,
                'workflow_args':
                workflow_args
            })
        return executor.run(args.__targets__)
    except PendingTasks:
        raise
    except SystemExit:
        # this happens because the executor is in resume mode but nothing
        # needs to be resumed, we simply pass
        return
    except Exception:
        if args.verbosity and args.verbosity > 2:
            sys.stderr.write(get_traceback())
        raise
    finally:
        env.config['sig_mode'] = 'ignore'
        env.verbosity = 2
Beispiel #10
0
class Interactive_Step_Executor(Step_Executor):

    def __init__(self, step, mode='interactive'):
        # This is the only interesting part of this executor. Basically
        # it derives everything from SP_Step_Executor but does not
        # use the Queue mechanism, so the __init__ and the run
        # functions are copied from Base_Step_Executor
        Base_Step_Executor.__init__(self, step)
        self.run_mode = mode
        self.host = None

    def submit_tasks(self, tasks):
        if not tasks:
            return
        if self.host is None:
            if 'queue' in env.sos_dict['_runtime']:
                queue = env.sos_dict['_runtime']['queue']
            elif env.config['default_queue']:
                queue = env.config['default_queue']
            else:
                queue = 'localhost'
            self.host = Host(queue)
        for task in tasks:
            self.host.submit_task(task)

    def wait_for_tasks(self, tasks, all_submitted):
        if not tasks:
            return {}
        # when we wait, the "outsiders" also need to see the tags etc
        # of the tasks so we have to write to the database. #156
        env.master_push_socket.send_pyobj(['commit_sig'])
        if all_submitted and 'shared' not in env.sos_dict['_runtime']:
            # if no shared and all taks have been submited return
            sys.exit(0)
        # turn this function to a generator to satisfy the interface, but do not
        # actually wait for any socket.
        yield None
        # wait till the executor responde
        if all(x == 'completed' for x in self.host.check_status(tasks)):
            if len(tasks) > 4:
                print('HINT: {} task{} completed: {}, {}, ..., {}'.format(
                    len(tasks), 's' if len(tasks) > 1 else '',
                    f"""<a onclick="task_info('{tasks[0]}', '{self.host.alias}')">{tasks[0][:4]}</a>""",
                    f"""<a onclick="task_info('{tasks[1]}', '{self.host.alias}')">{tasks[1][:4]}</a>""",
                    f"""<a onclick="task_info('{tasks[-1]}', '{self.host.alias}')">{tasks[-1][:4]}</a>"""
                ))
            else:
                print('HINT: {} task{} completed: {}'.format(
                    len(tasks), 's' if len(tasks) > 1 else '', ','.join([
                        f"""<a onclick="task_info('{x}', '{self.host.alias}')">{x[:4]}</a>"""
                        for x in tasks
                    ])))
            return self.host.retrieve_results(tasks)
        while True:
            res = self.host.check_status(tasks)
            if all(x not in ('submitted', 'pending', 'running') for x in res):
                #completed = [task for task, status in zip(tasks, res) if status == 'completed']
                return self.host.retrieve_results(tasks)
            time.sleep(0.1)

    def run(self):
        try:
            runner = Base_Step_Executor.run(self)
            yreq = next(runner)
            while True:
                yreq = runner.send(yreq)
        except StopIteration as e:
            return e.value

    def log(self, stage=None, msg=None):
        if stage == 'start':
            env.logger.debug('{} ``{}``: {}'.format(
                'Checking' if self.run_mode == 'dryrun' else 'Executing',
                self.step.step_name(), self.step.comment.strip()))
        elif stage == 'input':
            if env.sos_dict['step_input'] is not None:
                env.logger.debug('input:    ``{}``'.format(
                    short_repr(env.sos_dict['step_input'])))
        elif stage == 'output':
            if env.sos_dict['step_output'] is not None:
                env.logger.debug('output:   ``{}``'.format(
                    short_repr(env.sos_dict['step_output'])))