def main(parser, options, suite, *task_globs): if not options.state and not options.outputs: parser.error("Neither --state=STATE nor --output=OUTPUT is set") if options.state == "spawn": # Back compat. sys.stderr.write( "'cylc reset -s spawn' is deprecated; calling 'cylc spawn'\n") cmd = sys.argv[0].replace('reset', 'spawn') try: os.execvp(cmd, [cmd] + task_globs) except OSError as exc: if exc.filename is None: exc.filename = cmd raise SystemExit(exc) if not options.state: options.state = '' prompt('Reset task(s) %s in %s' % (task_globs, suite), options.force) pclient = SuiteRuntimeClient(suite, options.owner, options.host, options.port, options.comms_timeout) pclient( 'reset_task_states', { 'task_globs': task_globs, 'state': options.state, 'outputs': options.outputs })
def main(parser, options, suite, *task_globs): prompt('remove task(s) %s in %s' % (task_globs, suite), options.force) pclient = SuiteRuntimeClient( suite, options.owner, options.host, options.port, options.comms_timeout) pclient( 'remove_tasks', {'tasks': task_globs, 'spawn': (not options.no_spawn)} )
def main(parser, options, suite, *task_globs): """CLI of "cylc kill".""" if task_globs: prompt('Kill task %s in %s' % (task_globs, suite), options.force) else: prompt('Kill ALL tasks in %s' % (suite), options.force) pclient = SuiteRuntimeClient(suite, options.owner, options.host, options.port) pclient('kill_tasks', {'tasks': task_globs}, timeout=options.comms_timeout)
def main(parser, options, suite, *task_globs): if task_globs: prompt('Poll task %s in %s' % (task_globs, suite), options.force) else: prompt('Poll ALL tasks in %s' % (suite), options.force) pclient = SuiteRuntimeClient(suite, options.owner, options.host, options.port, options.comms_timeout) pclient('poll_tasks', { 'tasks': task_globs, 'poll_succeeded': options.poll_succ })
def main(parser, options, suite, severity_str): try: severity = LOGGING_LVL_OF[severity_str] except KeyError: parser.error("Illegal logging level, %s" % severity_str) prompt("Set logging level to %s in %s" % (severity_str, suite), options.force) pclient = SuiteRuntimeClient( suite, options.owner, options.host, options.port, options.comms_timeout) pclient('set_verbosity', {'level': severity})
def main(parser, options, suite, *items): for i, item in enumerate(items): if not TaskID.is_valid_id_2(item): raise UserInputError( '"%s": invalid task ID (argument %d)' % (item, i + 1)) prompt('Insert %s in %s' % (items, suite), options.force) pclient = SuiteRuntimeClient( suite, options.owner, options.host, options.port) pclient( 'insert_tasks', {'items': items, 'no_check': options.no_check, 'stop_point_string': options.stop_point_string}, timeout=options.comms_timeout )
def main(parser, options, suite, *task_globs): if task_globs: prompt('Hold task(s) %s in %s' % (task_globs, suite), options.force) elif options.hold_point_string: prompt('Hold suite after %s' % options.hold_point_string, options.force) else: prompt('Hold suite %s' % suite, options.force) pclient = SuiteRuntimeClient(suite, options.owner, options.host, options.port) if task_globs: pclient('hold_tasks', {'task_globs': task_globs}, timeout=options.comms_timeout) elif options.hold_point_string: pclient('hold_after_point_string', {'point_string': options.hold_point_string}, timeout=options.comms_timeout) else: pclient('hold_suite', timeout=options.comms_timeout)
def main(parser, options, suite, shutdown_arg=None): if shutdown_arg is not None and options.kill: parser.error("ERROR: --kill is not compatible with [STOP]") if options.kill and options.now: parser.error("ERROR: --kill is not compatible with --now") pclient = SuiteRuntimeClient(suite, options.owner, options.host, options.port, options.comms_timeout) if int(options.max_polls) > 0: # (test to avoid the "nothing to do" warning for # --max-polls=0) spoller = StopPoller(pclient, "suite stopped", options.interval, options.max_polls) if options.wall_clock: prompt( 'Set shutdown at wall clock %s for %s' % (options.wall_clock, suite), options.force) pclient('set_stop_after_clock_time', {'datetime_string': options.wall_clock}) elif shutdown_arg is not None and TaskID.is_valid_id(shutdown_arg): # STOP argument detected prompt('Set shutdown after task %s for %s' % (shutdown_arg, suite), options.force) pclient('set_stop_after_task', {'task_id': shutdown_arg}) elif shutdown_arg is not None: # not a task ID, may be a cycle point prompt('Set shutdown at cycle point %s for %s' % (shutdown_arg, suite), options.force) pclient('set_stop_after_point', {'point_string': shutdown_arg}) elif options.now > 1: prompt('Shut down and terminate %s now' % suite, options.force) pclient('stop_now', {'terminate': True}) elif options.now: prompt('Shut down %s now' % suite, options.force) pclient('stop_now') else: prompt('Shut down %s' % suite, options.force) pclient('set_stop_cleanly', {'kill_active_tasks': options.kill}) if int(options.max_polls) > 0: # (test to avoid the "nothing to do" warning for # --max-polls=0) if not spoller.poll(): sys.exit(1)
def main(parser, options, suite, *task_globs): prompt('Spawn task(s) %s in %s' % (task_globs, suite), options.force) pclient = SuiteRuntimeClient(suite, options.owner, options.host, options.port, options.comms_timeout) pclient('spawn_tasks', {'task_globs': task_globs})
def main(parser, options, suite, *task_globs): """CLI for "cylc trigger".""" msg = 'Trigger task(s) %s in %s' % (task_globs, suite) prompt(msg, options.force) pclient = SuiteRuntimeClient( suite, options.owner, options.host, options.port, options.comms_timeout) aborted = False if options.edit_run: task_id = task_globs[0] # Check that TASK is a unique task. success, msg = pclient( 'ping_task', {'task_id': task_id, 'exists_only': True} ) # Get the job filename from the suite server program - the task cycle # point may need standardising to the suite cycle point format. jobfile_path = pclient( 'get_task_jobfile_path', {'task_id': task_id}) if not jobfile_path: raise UserInputError('task not found') # Note: localhost time and file system time may be out of sync, # so the safe way to detect whether a new file is modified # or is to detect whether time stamp has changed or not. # Comparing the localhost time with the file timestamp is unsafe # and may cause the "while True" loop that follows to sys.exit # with an error message after MAX_TRIES. try: old_mtime = os.stat(jobfile_path).st_mtime except OSError: old_mtime = None # Tell the suite server program to generate the job file. pclient( 'dry_run_tasks', {'tasks': [task_id], 'check_syntax': False} ) # Wait for the new job file to be written. Use mtime because the same # file could potentially exist already, left from a previous run. count = 0 MAX_TRIES = 10 while True: count += 1 try: mtime = os.stat(jobfile_path).st_mtime except OSError: pass else: if old_mtime is None or mtime > old_mtime: break if count > MAX_TRIES: raise CylcError( 'no job file after %s seconds' % MAX_TRIES) time.sleep(1) # Make a pre-edit copy to allow a post-edit diff. jobfile_copy_path = "%s.ORIG" % jobfile_path shutil.copy(jobfile_path, jobfile_copy_path) # Edit the new job file. if options.geditor: editor = glbl_cfg().get(['editors', 'gui']) else: editor = glbl_cfg().get(['editors', 'terminal']) # The editor command may have options, e.g. 'emacs -nw'. command_list = re.split(' ', editor) command_list.append(jobfile_path) command = ' '.join(command_list) try: # Block until the editor exits. retcode = call(command_list) if retcode != 0: raise CylcError( 'command failed with %d:\n %s' % (retcode, command)) except OSError: raise CylcError('unable to execute:\n %s' % command) # Get confirmation after editing is done. # Don't allow force-no-prompt in this case. if options.geditor: # Alert stdout of the dialog window, in case it's missed. print("Editing done. I'm popping up a confirmation dialog now.") # Save a diff to record the changes made. difflog = os.path.join(os.path.dirname(jobfile_path), JOB_LOG_DIFF) with open(difflog, 'wb') as diff_file: for line in difflib.unified_diff( open(jobfile_copy_path).readlines(), open(jobfile_path).readlines(), fromfile="original", tofile="edited"): diff_file.write(line.encode()) os.unlink(jobfile_copy_path) msg = "Trigger edited task %s?" % task_id if not prompt(msg, gui=options.geditor, no_force=True, no_abort=True): log_dir_symlink = os.path.dirname(jobfile_path) real_log_dir = os.path.realpath(log_dir_symlink) prev_nn = "%02d" % (int(os.path.basename(real_log_dir)) - 1) os.unlink(log_dir_symlink) if int(prev_nn) == 0: # No previous submit: delete the whole parent directory. shutil.rmtree(os.path.dirname(real_log_dir)) else: # Reset to previous NN symlink and delete the log directory. dirname = os.path.dirname(real_log_dir) os.symlink(prev_nn, os.path.join(dirname, "NN")) shutil.rmtree(real_log_dir) aborted = True # Trigger the task proxy(s). pclient( 'trigger_tasks', {'tasks': task_globs, 'back_out': aborted} )
def main(parser, options, suite): prompt('Reload %s' % suite, options.force) pclient = SuiteRuntimeClient( suite, options.owner, options.host, options.port, options.comms_timeout) pclient('reload_suite')