Skip to content

Commit

Permalink
Merge pull request #2461 from hjoliver/fix-aborted-edit-run
Browse files Browse the repository at this point in the history
Fix re-trigger after aborted edit run.
  • Loading branch information
matthewrmshin authored Nov 1, 2017
2 parents da6151f + ed0732d commit 2e61ad1
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 15 deletions.
26 changes: 16 additions & 10 deletions bin/cylc-trigger
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ def main():
options.comms_timeout, my_uuid=options.set_uuid,
print_uuid=options.print_uuid)

aborted = False
if options.edit_run:
items = parser.parse_multitask_compat(options, args)
task_id = items[0]
Expand Down Expand Up @@ -163,7 +164,6 @@ def main():
print "Editing done. I'm popping up a confirmation dialog now."

# Save a diff to record the changes made.
log_dir = os.path.dirname(jobfile_path)
with open("%s-edit.diff" % jobfile_path, 'wb') as diff_file:
for line in difflib.unified_diff(
open(jobfile_copy_path).readlines(),
Expand All @@ -173,20 +173,26 @@ def main():
diff_file.write(line)
os.unlink(jobfile_copy_path)

log_dir = os.path.dirname(jobfile_path)
msg = "Trigger edited task %s?" % task_id
if not prompt(msg, gui=options.geditor, no_force=True, no_abort=True):
# Generate placeholder log files for the aborted run.
for log in ["job.out", "job.err"]:
lf = os.path.join(log_dir, log)
with open(lf, 'wb') as log_file:
log_file.write("This edit run was aborted\n")
print "Run aborted."
sys.exit(0)
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(os.path.join(dirname, prev_nn),
os.path.join(dirname, "NN"))
shutil.rmtree(real_log_dir)
aborted = True

# Trigger the task proxy(s).
items = parser.parse_multitask_compat(options, args)
pclient.put_command('trigger_tasks', items=items)
pclient.put_command('trigger_tasks', items=items, back_out=aborted)


if __name__ == "__main__":
Expand Down
6 changes: 4 additions & 2 deletions lib/cylc/network/httpserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -669,16 +669,18 @@ def take_checkpoints(self, items):

@cherrypy.expose
@cherrypy.tools.json_out()
def trigger_tasks(self, items):
def trigger_tasks(self, items, back_out=False):
"""Trigger submission of task jobs where possible.
items is a list of identifiers for matching task proxies.
"""
self._check_access_priv_and_report(PRIV_FULL_CONTROL)
back_out = self._literal_eval('back_out', back_out)
if not isinstance(items, list):
items = [items]
items = [str(item) for item in items]
self.schd.command_queue.put(("trigger_tasks", (items,), {}))
self.schd.command_queue.put(
("trigger_tasks", (items,), {"back_out": back_out}))
return (True, 'Command queued')

def _access_priv_ok(self, required_privilege_level):
Expand Down
4 changes: 2 additions & 2 deletions lib/cylc/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -1601,9 +1601,9 @@ def paused(self):
"""Is the suite paused?"""
return self.pool.is_held

def command_trigger_tasks(self, items):
def command_trigger_tasks(self, items, back_out=False):
"""Trigger tasks."""
return self.pool.trigger_tasks(items)
return self.pool.trigger_tasks(items, back_out)

def command_dry_run_tasks(self, items):
"""Dry-run tasks, e.g. edit run."""
Expand Down
7 changes: 6 additions & 1 deletion lib/cylc/task_pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -1118,11 +1118,16 @@ def remove_tasks(self, items, spawn=False):
self.remove(itask, 'by request')
return len(bad_items)

def trigger_tasks(self, items):
def trigger_tasks(self, items, back_out=False):
"""Trigger tasks."""
itasks, bad_items = self.filter_task_proxies(items)
n_warnings = len(bad_items)
for itask in itasks:
if back_out:
# (Aborted edit-run, reset for next trigger attempt).
itask.submit_num -= 1
itask.local_job_file_path = None
continue
if itask.state.status in TASK_STATUSES_ACTIVE:
LOG.warning('%s: already triggered' % itask.identity)
n_warnings += 1
Expand Down
36 changes: 36 additions & 0 deletions tests/cylc-trigger/07-edit-run-abort.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#!/bin/bash
# THIS FILE IS PART OF THE CYLC SUITE ENGINE.
# Copyright (C) 2008-2017 NIWA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#-------------------------------------------------------------------------------

# Test that aborting an edit-run has no effect on the next run (GitHub #2461)

. $(dirname $0)/test_header

set_test_number 2
install_suite "${TEST_NAME_BASE}" "${TEST_NAME_BASE}"

TEST_NAME="${TEST_NAME_BASE}-validate"
run_ok "${TEST_NAME}" cylc validate "${SUITE_NAME}"

# Configure a fake editor and run a suite with a task that does an edit run.
create_test_globalrc '' '
[editors]
terminal = my-edit'
TEST_NAME="${TEST_NAME_BASE}-run"
run_ok "${TEST_NAME}" cylc run --no-detach "${SUITE_NAME}"

purge_suite "${SUITE_NAME}"
3 changes: 3 additions & 0 deletions tests/cylc-trigger/07-edit-run-abort/bin/my-edit
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash

sed -i 's@echo HELLO@echo OOPS; /bin/false@' "$@"
22 changes: 22 additions & 0 deletions tests/cylc-trigger/07-edit-run-abort/suite.rc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[meta]
title = A suite to test an aborted edit run has no subsequent effect.
[cylc]
[[events]]
abort on timeout = True
timeout = PT20S
[scheduling]
[[dependencies]]
graph = victim => perpetrator
[runtime]
[[victim]]
script = echo HELLO
[[perpetrator]]
script = """
# Edit run to break victim, but abort after the edit.
cylc trigger --edit $CYLC_SUITE_NAME victim.1 << __END__
n
__END__
# Then trigger victim - the original unedited task should run.
cylc trigger $CYLC_SUITE_NAME victim.1
"""

0 comments on commit 2e61ad1

Please sign in to comment.