diff --git a/nightly_8.3/doctrees/7-to-8/caveats.doctree b/nightly_8.3/doctrees/7-to-8/caveats.doctree new file mode 100644 index 0000000000..9886704ccb Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/caveats.doctree differ diff --git a/nightly_8.3/doctrees/7-to-8/cheat-sheet.doctree b/nightly_8.3/doctrees/7-to-8/cheat-sheet.doctree new file mode 100644 index 0000000000..2383d05c75 Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/cheat-sheet.doctree differ diff --git a/nightly_8.3/doctrees/7-to-8/index.doctree b/nightly_8.3/doctrees/7-to-8/index.doctree new file mode 100644 index 0000000000..6272e63121 Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/index.doctree differ diff --git a/nightly_8.3/doctrees/7-to-8/major-changes/cli.doctree b/nightly_8.3/doctrees/7-to-8/major-changes/cli.doctree new file mode 100644 index 0000000000..ac4c148153 Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/major-changes/cli.doctree differ diff --git a/nightly_8.3/doctrees/7-to-8/major-changes/compatibility-mode.doctree b/nightly_8.3/doctrees/7-to-8/major-changes/compatibility-mode.doctree new file mode 100644 index 0000000000..b1310a0295 Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/major-changes/compatibility-mode.doctree differ diff --git a/nightly_8.3/doctrees/7-to-8/major-changes/config-changes.doctree b/nightly_8.3/doctrees/7-to-8/major-changes/config-changes.doctree new file mode 100644 index 0000000000..a1997cc64e Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/major-changes/config-changes.doctree differ diff --git a/nightly_8.3/doctrees/7-to-8/major-changes/continuing-c7-c8.doctree b/nightly_8.3/doctrees/7-to-8/major-changes/continuing-c7-c8.doctree new file mode 100644 index 0000000000..73be472c8a Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/major-changes/continuing-c7-c8.doctree differ diff --git a/nightly_8.3/doctrees/7-to-8/major-changes/cylc-install.doctree b/nightly_8.3/doctrees/7-to-8/major-changes/cylc-install.doctree new file mode 100644 index 0000000000..e59e1f15f6 Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/major-changes/cylc-install.doctree differ diff --git a/nightly_8.3/doctrees/7-to-8/major-changes/excluding-tasks.doctree b/nightly_8.3/doctrees/7-to-8/major-changes/excluding-tasks.doctree new file mode 100644 index 0000000000..96165ad7cd Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/major-changes/excluding-tasks.doctree differ diff --git a/nightly_8.3/doctrees/7-to-8/major-changes/index.doctree b/nightly_8.3/doctrees/7-to-8/major-changes/index.doctree new file mode 100644 index 0000000000..f714335d52 Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/major-changes/index.doctree differ diff --git a/nightly_8.3/doctrees/7-to-8/major-changes/parameters.doctree b/nightly_8.3/doctrees/7-to-8/major-changes/parameters.doctree new file mode 100644 index 0000000000..f7ab00a945 Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/major-changes/parameters.doctree differ diff --git a/nightly_8.3/doctrees/7-to-8/major-changes/platforms.doctree b/nightly_8.3/doctrees/7-to-8/major-changes/platforms.doctree new file mode 100644 index 0000000000..56e4188181 Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/major-changes/platforms.doctree differ diff --git a/nightly_8.3/doctrees/7-to-8/major-changes/play-pause-stop.doctree b/nightly_8.3/doctrees/7-to-8/major-changes/play-pause-stop.doctree new file mode 100644 index 0000000000..67ae8e9007 Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/major-changes/play-pause-stop.doctree differ diff --git a/nightly_8.3/doctrees/7-to-8/major-changes/python-2-3.doctree b/nightly_8.3/doctrees/7-to-8/major-changes/python-2-3.doctree new file mode 100644 index 0000000000..0f048750df Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/major-changes/python-2-3.doctree differ diff --git a/nightly_8.3/doctrees/7-to-8/major-changes/remote-owner.doctree b/nightly_8.3/doctrees/7-to-8/major-changes/remote-owner.doctree new file mode 100644 index 0000000000..9a0db6eca3 Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/major-changes/remote-owner.doctree differ diff --git a/nightly_8.3/doctrees/7-to-8/major-changes/scheduling.doctree b/nightly_8.3/doctrees/7-to-8/major-changes/scheduling.doctree new file mode 100644 index 0000000000..d81caf116d Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/major-changes/scheduling.doctree differ diff --git a/nightly_8.3/doctrees/7-to-8/major-changes/suicide-triggers.doctree b/nightly_8.3/doctrees/7-to-8/major-changes/suicide-triggers.doctree new file mode 100644 index 0000000000..f868bd6c42 Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/major-changes/suicide-triggers.doctree differ diff --git a/nightly_8.3/doctrees/7-to-8/major-changes/task-job-states.doctree b/nightly_8.3/doctrees/7-to-8/major-changes/task-job-states.doctree new file mode 100644 index 0000000000..3cfbc78fbb Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/major-changes/task-job-states.doctree differ diff --git a/nightly_8.3/doctrees/7-to-8/major-changes/template-vars.doctree b/nightly_8.3/doctrees/7-to-8/major-changes/template-vars.doctree new file mode 100644 index 0000000000..a80ced2053 Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/major-changes/template-vars.doctree differ diff --git a/nightly_8.3/doctrees/7-to-8/major-changes/ui.doctree b/nightly_8.3/doctrees/7-to-8/major-changes/ui.doctree new file mode 100644 index 0000000000..3d73ae8f75 Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/major-changes/ui.doctree differ diff --git a/nightly_8.3/doctrees/7-to-8/summary.doctree b/nightly_8.3/doctrees/7-to-8/summary.doctree new file mode 100644 index 0000000000..cd0a6ba65f Binary files /dev/null and b/nightly_8.3/doctrees/7-to-8/summary.doctree differ diff --git a/nightly_8.3/doctrees/environment.pickle b/nightly_8.3/doctrees/environment.pickle new file mode 100644 index 0000000000..72e95beeff Binary files /dev/null and b/nightly_8.3/doctrees/environment.pickle differ diff --git a/nightly_8.3/doctrees/glossary.doctree b/nightly_8.3/doctrees/glossary.doctree new file mode 100644 index 0000000000..bc2d99e29d Binary files /dev/null and b/nightly_8.3/doctrees/glossary.doctree differ diff --git a/nightly_8.3/doctrees/index.doctree b/nightly_8.3/doctrees/index.doctree new file mode 100644 index 0000000000..d9dadb365a Binary files /dev/null and b/nightly_8.3/doctrees/index.doctree differ diff --git a/nightly_8.3/doctrees/installation.doctree b/nightly_8.3/doctrees/installation.doctree new file mode 100644 index 0000000000..7797a0a05b Binary files /dev/null and b/nightly_8.3/doctrees/installation.doctree differ diff --git a/nightly_8.3/doctrees/plugins/cylc-rose.doctree b/nightly_8.3/doctrees/plugins/cylc-rose.doctree new file mode 100644 index 0000000000..789088ff4c Binary files /dev/null and b/nightly_8.3/doctrees/plugins/cylc-rose.doctree differ diff --git a/nightly_8.3/doctrees/plugins/index.doctree b/nightly_8.3/doctrees/plugins/index.doctree new file mode 100644 index 0000000000..914f368e5b Binary files /dev/null and b/nightly_8.3/doctrees/plugins/index.doctree differ diff --git a/nightly_8.3/doctrees/plugins/install/built-in/cylc.flow.install_plugins.log_vc_info.doctree b/nightly_8.3/doctrees/plugins/install/built-in/cylc.flow.install_plugins.log_vc_info.doctree new file mode 100644 index 0000000000..8f0815ffb8 Binary files /dev/null and b/nightly_8.3/doctrees/plugins/install/built-in/cylc.flow.install_plugins.log_vc_info.doctree differ diff --git a/nightly_8.3/doctrees/plugins/install/index.doctree b/nightly_8.3/doctrees/plugins/install/index.doctree new file mode 100644 index 0000000000..9f7ff6267d Binary files /dev/null and b/nightly_8.3/doctrees/plugins/install/index.doctree differ diff --git a/nightly_8.3/doctrees/plugins/job-runners/index.doctree b/nightly_8.3/doctrees/plugins/job-runners/index.doctree new file mode 100644 index 0000000000..32ef7555c6 Binary files /dev/null and b/nightly_8.3/doctrees/plugins/job-runners/index.doctree differ diff --git a/nightly_8.3/doctrees/plugins/main-loop/built-in/cylc.flow.main_loop.auto_restart.doctree b/nightly_8.3/doctrees/plugins/main-loop/built-in/cylc.flow.main_loop.auto_restart.doctree new file mode 100644 index 0000000000..f24b574c9c Binary files /dev/null and b/nightly_8.3/doctrees/plugins/main-loop/built-in/cylc.flow.main_loop.auto_restart.doctree differ diff --git a/nightly_8.3/doctrees/plugins/main-loop/built-in/cylc.flow.main_loop.health_check.doctree b/nightly_8.3/doctrees/plugins/main-loop/built-in/cylc.flow.main_loop.health_check.doctree new file mode 100644 index 0000000000..a64ddec6cf Binary files /dev/null and b/nightly_8.3/doctrees/plugins/main-loop/built-in/cylc.flow.main_loop.health_check.doctree differ diff --git a/nightly_8.3/doctrees/plugins/main-loop/built-in/cylc.flow.main_loop.log_data_store.doctree b/nightly_8.3/doctrees/plugins/main-loop/built-in/cylc.flow.main_loop.log_data_store.doctree new file mode 100644 index 0000000000..bf57570021 Binary files /dev/null and b/nightly_8.3/doctrees/plugins/main-loop/built-in/cylc.flow.main_loop.log_data_store.doctree differ diff --git a/nightly_8.3/doctrees/plugins/main-loop/built-in/cylc.flow.main_loop.log_main_loop.doctree b/nightly_8.3/doctrees/plugins/main-loop/built-in/cylc.flow.main_loop.log_main_loop.doctree new file mode 100644 index 0000000000..92d03823ce Binary files /dev/null and b/nightly_8.3/doctrees/plugins/main-loop/built-in/cylc.flow.main_loop.log_main_loop.doctree differ diff --git a/nightly_8.3/doctrees/plugins/main-loop/built-in/cylc.flow.main_loop.log_memory.doctree b/nightly_8.3/doctrees/plugins/main-loop/built-in/cylc.flow.main_loop.log_memory.doctree new file mode 100644 index 0000000000..7426e17a6f Binary files /dev/null and b/nightly_8.3/doctrees/plugins/main-loop/built-in/cylc.flow.main_loop.log_memory.doctree differ diff --git a/nightly_8.3/doctrees/plugins/main-loop/built-in/cylc.flow.main_loop.reset_bad_hosts.doctree b/nightly_8.3/doctrees/plugins/main-loop/built-in/cylc.flow.main_loop.reset_bad_hosts.doctree new file mode 100644 index 0000000000..494991564a Binary files /dev/null and b/nightly_8.3/doctrees/plugins/main-loop/built-in/cylc.flow.main_loop.reset_bad_hosts.doctree differ diff --git a/nightly_8.3/doctrees/plugins/main-loop/index.doctree b/nightly_8.3/doctrees/plugins/main-loop/index.doctree new file mode 100644 index 0000000000..b75082f4b1 Binary files /dev/null and b/nightly_8.3/doctrees/plugins/main-loop/index.doctree differ diff --git a/nightly_8.3/doctrees/plugins/xtriggers/index.doctree b/nightly_8.3/doctrees/plugins/xtriggers/index.doctree new file mode 100644 index 0000000000..88ef67980b Binary files /dev/null and b/nightly_8.3/doctrees/plugins/xtriggers/index.doctree differ diff --git a/nightly_8.3/doctrees/reference/api/exceptions.doctree b/nightly_8.3/doctrees/reference/api/exceptions.doctree new file mode 100644 index 0000000000..d69976442d Binary files /dev/null and b/nightly_8.3/doctrees/reference/api/exceptions.doctree differ diff --git a/nightly_8.3/doctrees/reference/api/index.doctree b/nightly_8.3/doctrees/reference/api/index.doctree new file mode 100644 index 0000000000..202db1fa94 Binary files /dev/null and b/nightly_8.3/doctrees/reference/api/index.doctree differ diff --git a/nightly_8.3/doctrees/reference/api/scan.doctree b/nightly_8.3/doctrees/reference/api/scan.doctree new file mode 100644 index 0000000000..883255caee Binary files /dev/null and b/nightly_8.3/doctrees/reference/api/scan.doctree differ diff --git a/nightly_8.3/doctrees/reference/api/zmq.doctree b/nightly_8.3/doctrees/reference/api/zmq.doctree new file mode 100644 index 0000000000..e07ba96f33 Binary files /dev/null and b/nightly_8.3/doctrees/reference/api/zmq.doctree differ diff --git a/nightly_8.3/doctrees/reference/architecture/data-flow.doctree b/nightly_8.3/doctrees/reference/architecture/data-flow.doctree new file mode 100644 index 0000000000..e3a4e02af9 Binary files /dev/null and b/nightly_8.3/doctrees/reference/architecture/data-flow.doctree differ diff --git a/nightly_8.3/doctrees/reference/architecture/index.doctree b/nightly_8.3/doctrees/reference/architecture/index.doctree new file mode 100644 index 0000000000..ce201ab61a Binary files /dev/null and b/nightly_8.3/doctrees/reference/architecture/index.doctree differ diff --git a/nightly_8.3/doctrees/reference/architecture/ui-server.doctree b/nightly_8.3/doctrees/reference/architecture/ui-server.doctree new file mode 100644 index 0000000000..2219970647 Binary files /dev/null and b/nightly_8.3/doctrees/reference/architecture/ui-server.doctree differ diff --git a/nightly_8.3/doctrees/reference/changes.doctree b/nightly_8.3/doctrees/reference/changes.doctree new file mode 100644 index 0000000000..e9d2e6755b Binary files /dev/null and b/nightly_8.3/doctrees/reference/changes.doctree differ diff --git a/nightly_8.3/doctrees/reference/config/file-format.doctree b/nightly_8.3/doctrees/reference/config/file-format.doctree new file mode 100644 index 0000000000..b297e256da Binary files /dev/null and b/nightly_8.3/doctrees/reference/config/file-format.doctree differ diff --git a/nightly_8.3/doctrees/reference/config/global.doctree b/nightly_8.3/doctrees/reference/config/global.doctree new file mode 100644 index 0000000000..d5797401aa Binary files /dev/null and b/nightly_8.3/doctrees/reference/config/global.doctree differ diff --git a/nightly_8.3/doctrees/reference/config/index.doctree b/nightly_8.3/doctrees/reference/config/index.doctree new file mode 100644 index 0000000000..bcb52663ef Binary files /dev/null and b/nightly_8.3/doctrees/reference/config/index.doctree differ diff --git a/nightly_8.3/doctrees/reference/config/sharing-access-to-workflows.doctree b/nightly_8.3/doctrees/reference/config/sharing-access-to-workflows.doctree new file mode 100644 index 0000000000..b44bfa64a2 Binary files /dev/null and b/nightly_8.3/doctrees/reference/config/sharing-access-to-workflows.doctree differ diff --git a/nightly_8.3/doctrees/reference/config/shorthand.doctree b/nightly_8.3/doctrees/reference/config/shorthand.doctree new file mode 100644 index 0000000000..de8700caca Binary files /dev/null and b/nightly_8.3/doctrees/reference/config/shorthand.doctree differ diff --git a/nightly_8.3/doctrees/reference/config/types.doctree b/nightly_8.3/doctrees/reference/config/types.doctree new file mode 100644 index 0000000000..0ee2c94965 Binary files /dev/null and b/nightly_8.3/doctrees/reference/config/types.doctree differ diff --git a/nightly_8.3/doctrees/reference/config/ui-server.doctree b/nightly_8.3/doctrees/reference/config/ui-server.doctree new file mode 100644 index 0000000000..5dd4b2fe00 Binary files /dev/null and b/nightly_8.3/doctrees/reference/config/ui-server.doctree differ diff --git a/nightly_8.3/doctrees/reference/config/workflow.doctree b/nightly_8.3/doctrees/reference/config/workflow.doctree new file mode 100644 index 0000000000..8413115bac Binary files /dev/null and b/nightly_8.3/doctrees/reference/config/workflow.doctree differ diff --git a/nightly_8.3/doctrees/reference/config/writing-platform-configs.doctree b/nightly_8.3/doctrees/reference/config/writing-platform-configs.doctree new file mode 100644 index 0000000000..e976b66c3d Binary files /dev/null and b/nightly_8.3/doctrees/reference/config/writing-platform-configs.doctree differ diff --git a/nightly_8.3/doctrees/reference/dev-history-major-changes.doctree b/nightly_8.3/doctrees/reference/dev-history-major-changes.doctree new file mode 100644 index 0000000000..b1e9fd6e5a Binary files /dev/null and b/nightly_8.3/doctrees/reference/dev-history-major-changes.doctree differ diff --git a/nightly_8.3/doctrees/reference/environments/conda.doctree b/nightly_8.3/doctrees/reference/environments/conda.doctree new file mode 100644 index 0000000000..9648271200 Binary files /dev/null and b/nightly_8.3/doctrees/reference/environments/conda.doctree differ diff --git a/nightly_8.3/doctrees/reference/index.doctree b/nightly_8.3/doctrees/reference/index.doctree new file mode 100644 index 0000000000..1901b03578 Binary files /dev/null and b/nightly_8.3/doctrees/reference/index.doctree differ diff --git a/nightly_8.3/doctrees/reference/job-script-vars/index.doctree b/nightly_8.3/doctrees/reference/job-script-vars/index.doctree new file mode 100644 index 0000000000..ae6a93888e Binary files /dev/null and b/nightly_8.3/doctrees/reference/job-script-vars/index.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/furthertopics/broadcast.doctree b/nightly_8.3/doctrees/tutorial/furthertopics/broadcast.doctree new file mode 100644 index 0000000000..20bff7b57c Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/furthertopics/broadcast.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/furthertopics/clock-triggered-tasks.doctree b/nightly_8.3/doctrees/tutorial/furthertopics/clock-triggered-tasks.doctree new file mode 100644 index 0000000000..a487787ae4 Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/furthertopics/clock-triggered-tasks.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/furthertopics/family-triggers.doctree b/nightly_8.3/doctrees/tutorial/furthertopics/family-triggers.doctree new file mode 100644 index 0000000000..f1c8c07d45 Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/furthertopics/family-triggers.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/furthertopics/index.doctree b/nightly_8.3/doctrees/tutorial/furthertopics/index.doctree new file mode 100644 index 0000000000..1431cf733c Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/furthertopics/index.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/furthertopics/inheritance.doctree b/nightly_8.3/doctrees/tutorial/furthertopics/inheritance.doctree new file mode 100644 index 0000000000..32c1ccbef2 Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/furthertopics/inheritance.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/furthertopics/message-triggers.doctree b/nightly_8.3/doctrees/tutorial/furthertopics/message-triggers.doctree new file mode 100644 index 0000000000..66a673fd71 Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/furthertopics/message-triggers.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/furthertopics/queues.doctree b/nightly_8.3/doctrees/tutorial/furthertopics/queues.doctree new file mode 100644 index 0000000000..688337457c Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/furthertopics/queues.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/furthertopics/retries.doctree b/nightly_8.3/doctrees/tutorial/furthertopics/retries.doctree new file mode 100644 index 0000000000..35ae962e6e Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/furthertopics/retries.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/index.doctree b/nightly_8.3/doctrees/tutorial/index.doctree new file mode 100644 index 0000000000..3df6552b05 Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/index.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/introduction.doctree b/nightly_8.3/doctrees/tutorial/introduction.doctree new file mode 100644 index 0000000000..a2cdf2655e Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/introduction.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/runtime/configuration-consolidation/families.doctree b/nightly_8.3/doctrees/tutorial/runtime/configuration-consolidation/families.doctree new file mode 100644 index 0000000000..8a4bdf800a Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/runtime/configuration-consolidation/families.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/runtime/configuration-consolidation/index.doctree b/nightly_8.3/doctrees/tutorial/runtime/configuration-consolidation/index.doctree new file mode 100644 index 0000000000..58afbbf9ba Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/runtime/configuration-consolidation/index.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/runtime/configuration-consolidation/jinja2.doctree b/nightly_8.3/doctrees/tutorial/runtime/configuration-consolidation/jinja2.doctree new file mode 100644 index 0000000000..53132b6fa0 Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/runtime/configuration-consolidation/jinja2.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/runtime/configuration-consolidation/parameters.doctree b/nightly_8.3/doctrees/tutorial/runtime/configuration-consolidation/parameters.doctree new file mode 100644 index 0000000000..6b755a42bb Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/runtime/configuration-consolidation/parameters.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/runtime/index.doctree b/nightly_8.3/doctrees/tutorial/runtime/index.doctree new file mode 100644 index 0000000000..3c8a21e8a4 Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/runtime/index.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/runtime/introduction.doctree b/nightly_8.3/doctrees/tutorial/runtime/introduction.doctree new file mode 100644 index 0000000000..6f5cde4ee5 Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/runtime/introduction.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/runtime/runtime-configuration.doctree b/nightly_8.3/doctrees/tutorial/runtime/runtime-configuration.doctree new file mode 100644 index 0000000000..b8ff6baa5b Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/runtime/runtime-configuration.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/runtime/summary.doctree b/nightly_8.3/doctrees/tutorial/runtime/summary.doctree new file mode 100644 index 0000000000..4ba6a6f7b0 Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/runtime/summary.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/scheduling/datetime-cycling.doctree b/nightly_8.3/doctrees/tutorial/scheduling/datetime-cycling.doctree new file mode 100644 index 0000000000..638bfffe82 Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/scheduling/datetime-cycling.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/scheduling/further-scheduling.doctree b/nightly_8.3/doctrees/tutorial/scheduling/further-scheduling.doctree new file mode 100644 index 0000000000..bb772d006e Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/scheduling/further-scheduling.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/scheduling/graphing.doctree b/nightly_8.3/doctrees/tutorial/scheduling/graphing.doctree new file mode 100644 index 0000000000..26d2dd50b5 Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/scheduling/graphing.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/scheduling/index.doctree b/nightly_8.3/doctrees/tutorial/scheduling/index.doctree new file mode 100644 index 0000000000..4d9d12d445 Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/scheduling/index.doctree differ diff --git a/nightly_8.3/doctrees/tutorial/scheduling/integer-cycling.doctree b/nightly_8.3/doctrees/tutorial/scheduling/integer-cycling.doctree new file mode 100644 index 0000000000..8b73a40e0d Binary files /dev/null and b/nightly_8.3/doctrees/tutorial/scheduling/integer-cycling.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/cheat-sheet.doctree b/nightly_8.3/doctrees/user-guide/cheat-sheet.doctree new file mode 100644 index 0000000000..f37e7d7ed6 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/cheat-sheet.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/examples/1-hello-world/index.doctree b/nightly_8.3/doctrees/user-guide/examples/1-hello-world/index.doctree new file mode 100644 index 0000000000..2f536f682e Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/examples/1-hello-world/index.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/examples/2-integer-cycling/index.doctree b/nightly_8.3/doctrees/user-guide/examples/2-integer-cycling/index.doctree new file mode 100644 index 0000000000..2243e53d05 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/examples/2-integer-cycling/index.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/examples/3-datetime-cycling/index.doctree b/nightly_8.3/doctrees/user-guide/examples/3-datetime-cycling/index.doctree new file mode 100644 index 0000000000..0329d0ed6e Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/examples/3-datetime-cycling/index.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/examples/converging-workflow/index.doctree b/nightly_8.3/doctrees/user-guide/examples/converging-workflow/index.doctree new file mode 100644 index 0000000000..7997ed8a01 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/examples/converging-workflow/index.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/examples/event-driven-cycling/index.doctree b/nightly_8.3/doctrees/user-guide/examples/event-driven-cycling/index.doctree new file mode 100644 index 0000000000..ff3c39ad33 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/examples/event-driven-cycling/index.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/examples/index.doctree b/nightly_8.3/doctrees/user-guide/examples/index.doctree new file mode 100644 index 0000000000..a1bf5a9a5a Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/examples/index.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/examples/inter-workflow-triggers/index.doctree b/nightly_8.3/doctrees/user-guide/examples/inter-workflow-triggers/index.doctree new file mode 100644 index 0000000000..3fcbfd1ecd Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/examples/inter-workflow-triggers/index.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/index.doctree b/nightly_8.3/doctrees/user-guide/index.doctree new file mode 100644 index 0000000000..c2e392ca5f Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/index.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/installing-workflows.doctree b/nightly_8.3/doctrees/user-guide/installing-workflows.doctree new file mode 100644 index 0000000000..6e7a99a4fb Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/installing-workflows.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/interventions/index.doctree b/nightly_8.3/doctrees/user-guide/interventions/index.doctree new file mode 100644 index 0000000000..b81c3a2687 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/interventions/index.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/introduction.doctree b/nightly_8.3/doctrees/user-guide/introduction.doctree new file mode 100644 index 0000000000..0c8d409be9 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/introduction.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/removing-workflows.doctree b/nightly_8.3/doctrees/user-guide/removing-workflows.doctree new file mode 100644 index 0000000000..2208d1f7e8 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/removing-workflows.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/running-workflows/authentication-files.doctree b/nightly_8.3/doctrees/user-guide/running-workflows/authentication-files.doctree new file mode 100644 index 0000000000..1cbc80e9c0 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/running-workflows/authentication-files.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/running-workflows/dynamic-behaviour.doctree b/nightly_8.3/doctrees/user-guide/running-workflows/dynamic-behaviour.doctree new file mode 100644 index 0000000000..edce5632c5 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/running-workflows/dynamic-behaviour.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/running-workflows/handling-job-preemption.doctree b/nightly_8.3/doctrees/user-guide/running-workflows/handling-job-preemption.doctree new file mode 100644 index 0000000000..29fb19e4a0 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/running-workflows/handling-job-preemption.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/running-workflows/index.doctree b/nightly_8.3/doctrees/user-guide/running-workflows/index.doctree new file mode 100644 index 0000000000..8c118511c8 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/running-workflows/index.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/running-workflows/reflow.doctree b/nightly_8.3/doctrees/user-guide/running-workflows/reflow.doctree new file mode 100644 index 0000000000..8d179476a9 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/running-workflows/reflow.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/running-workflows/retrying-tasks.doctree b/nightly_8.3/doctrees/user-guide/running-workflows/retrying-tasks.doctree new file mode 100644 index 0000000000..ba04914d4b Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/running-workflows/retrying-tasks.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/running-workflows/scheduler-log-files.doctree b/nightly_8.3/doctrees/user-guide/running-workflows/scheduler-log-files.doctree new file mode 100644 index 0000000000..0018811566 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/running-workflows/scheduler-log-files.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/running-workflows/scheduler-start-up.doctree b/nightly_8.3/doctrees/user-guide/running-workflows/scheduler-start-up.doctree new file mode 100644 index 0000000000..ef41e39ed2 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/running-workflows/scheduler-start-up.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/running-workflows/simulation-modes.doctree b/nightly_8.3/doctrees/user-guide/running-workflows/simulation-modes.doctree new file mode 100644 index 0000000000..db8d67b0eb Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/running-workflows/simulation-modes.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/running-workflows/tasks-jobs-ui.doctree b/nightly_8.3/doctrees/user-guide/running-workflows/tasks-jobs-ui.doctree new file mode 100644 index 0000000000..3d3d42915b Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/running-workflows/tasks-jobs-ui.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/running-workflows/tracking-task-state.doctree b/nightly_8.3/doctrees/user-guide/running-workflows/tracking-task-state.doctree new file mode 100644 index 0000000000..42d321bf4c Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/running-workflows/tracking-task-state.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/running-workflows/workflow-completion.doctree b/nightly_8.3/doctrees/user-guide/running-workflows/workflow-completion.doctree new file mode 100644 index 0000000000..d1dcdde598 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/running-workflows/workflow-completion.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/running-workflows/workflow-databases.doctree b/nightly_8.3/doctrees/user-guide/running-workflows/workflow-databases.doctree new file mode 100644 index 0000000000..93c6dabe3f Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/running-workflows/workflow-databases.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/task-implementation/index.doctree b/nightly_8.3/doctrees/user-guide/task-implementation/index.doctree new file mode 100644 index 0000000000..8ac433d045 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/task-implementation/index.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.at.doctree b/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.at.doctree new file mode 100644 index 0000000000..074b4842e3 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.at.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.background.doctree b/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.background.doctree new file mode 100644 index 0000000000..0dd41eed59 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.background.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.loadleveler.doctree b/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.loadleveler.doctree new file mode 100644 index 0000000000..948711039b Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.loadleveler.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.lsf.doctree b/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.lsf.doctree new file mode 100644 index 0000000000..ee0943bf2c Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.lsf.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.moab.doctree b/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.moab.doctree new file mode 100644 index 0000000000..fab546cbd1 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.moab.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.pbs.doctree b/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.pbs.doctree new file mode 100644 index 0000000000..56a3c7ee75 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.pbs.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.sge.doctree b/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.sge.doctree new file mode 100644 index 0000000000..13eedae968 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.sge.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.slurm.doctree b/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.slurm.doctree new file mode 100644 index 0000000000..060d690c29 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.slurm.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.slurm_packjob.doctree b/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.slurm_packjob.doctree new file mode 100644 index 0000000000..accbcdfda9 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/task-implementation/job-runner-handlers/cylc.flow.job_runner_handlers.slurm_packjob.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/task-implementation/job-scripts.doctree b/nightly_8.3/doctrees/user-guide/task-implementation/job-scripts.doctree new file mode 100644 index 0000000000..33b83f08db Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/task-implementation/job-scripts.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/task-implementation/job-submission.doctree b/nightly_8.3/doctrees/user-guide/task-implementation/job-submission.doctree new file mode 100644 index 0000000000..2535d15897 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/task-implementation/job-submission.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/task-implementation/ssh-job-management.doctree b/nightly_8.3/doctrees/user-guide/task-implementation/ssh-job-management.doctree new file mode 100644 index 0000000000..7036b3b04c Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/task-implementation/ssh-job-management.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/troubleshooting.doctree b/nightly_8.3/doctrees/user-guide/troubleshooting.doctree new file mode 100644 index 0000000000..0aeaa8362c Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/troubleshooting.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/writing-workflows/configuration.doctree b/nightly_8.3/doctrees/user-guide/writing-workflows/configuration.doctree new file mode 100644 index 0000000000..47cc0b0ab5 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/writing-workflows/configuration.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/writing-workflows/empy.doctree b/nightly_8.3/doctrees/user-guide/writing-workflows/empy.doctree new file mode 100644 index 0000000000..85047ea1af Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/writing-workflows/empy.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/writing-workflows/external-triggers.doctree b/nightly_8.3/doctrees/user-guide/writing-workflows/external-triggers.doctree new file mode 100644 index 0000000000..5a3b3bafc1 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/writing-workflows/external-triggers.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/writing-workflows/index.doctree b/nightly_8.3/doctrees/user-guide/writing-workflows/index.doctree new file mode 100644 index 0000000000..63984cf874 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/writing-workflows/index.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/writing-workflows/jinja2.doctree b/nightly_8.3/doctrees/user-guide/writing-workflows/jinja2.doctree new file mode 100644 index 0000000000..605610eb4f Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/writing-workflows/jinja2.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/writing-workflows/parameterized-tasks.doctree b/nightly_8.3/doctrees/user-guide/writing-workflows/parameterized-tasks.doctree new file mode 100644 index 0000000000..01d8d8fa53 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/writing-workflows/parameterized-tasks.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/writing-workflows/runtime.doctree b/nightly_8.3/doctrees/user-guide/writing-workflows/runtime.doctree new file mode 100644 index 0000000000..50394b2a71 Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/writing-workflows/runtime.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/writing-workflows/scheduler.doctree b/nightly_8.3/doctrees/user-guide/writing-workflows/scheduler.doctree new file mode 100644 index 0000000000..caac214a8c Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/writing-workflows/scheduler.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/writing-workflows/scheduling.doctree b/nightly_8.3/doctrees/user-guide/writing-workflows/scheduling.doctree new file mode 100644 index 0000000000..23b5d2159d Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/writing-workflows/scheduling.doctree differ diff --git a/nightly_8.3/doctrees/user-guide/writing-workflows/suicide-triggers.doctree b/nightly_8.3/doctrees/user-guide/writing-workflows/suicide-triggers.doctree new file mode 100644 index 0000000000..679e8583ca Binary files /dev/null and b/nightly_8.3/doctrees/user-guide/writing-workflows/suicide-triggers.doctree differ diff --git a/nightly_8.3/doctrees/workflow-design-guide/efficiency.doctree b/nightly_8.3/doctrees/workflow-design-guide/efficiency.doctree new file mode 100644 index 0000000000..4ef5400ce8 Binary files /dev/null and b/nightly_8.3/doctrees/workflow-design-guide/efficiency.doctree differ diff --git a/nightly_8.3/doctrees/workflow-design-guide/general-principles.doctree b/nightly_8.3/doctrees/workflow-design-guide/general-principles.doctree new file mode 100644 index 0000000000..d755e4770e Binary files /dev/null and b/nightly_8.3/doctrees/workflow-design-guide/general-principles.doctree differ diff --git a/nightly_8.3/doctrees/workflow-design-guide/index.doctree b/nightly_8.3/doctrees/workflow-design-guide/index.doctree new file mode 100644 index 0000000000..d02956296c Binary files /dev/null and b/nightly_8.3/doctrees/workflow-design-guide/index.doctree differ diff --git a/nightly_8.3/doctrees/workflow-design-guide/portable-workflows.doctree b/nightly_8.3/doctrees/workflow-design-guide/portable-workflows.doctree new file mode 100644 index 0000000000..d0125ee853 Binary files /dev/null and b/nightly_8.3/doctrees/workflow-design-guide/portable-workflows.doctree differ diff --git a/nightly_8.3/doctrees/workflow-design-guide/style-guide.doctree b/nightly_8.3/doctrees/workflow-design-guide/style-guide.doctree new file mode 100644 index 0000000000..f5b0578e90 Binary files /dev/null and b/nightly_8.3/doctrees/workflow-design-guide/style-guide.doctree differ diff --git a/nightly_8.3/html/.buildinfo b/nightly_8.3/html/.buildinfo new file mode 100644 index 0000000000..91a0ccb5cf --- /dev/null +++ b/nightly_8.3/html/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 0b54d6e99a2f1ac36403ec78e68ff0b3 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/nightly_8.3/html/7-to-8/caveats.html b/nightly_8.3/html/7-to-8/caveats.html new file mode 100644 index 0000000000..e1d0104b0b --- /dev/null +++ b/nightly_8.3/html/7-to-8/caveats.html @@ -0,0 +1,222 @@ + + + + + + + + + Cylc 8.3 Caveats — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Cylc 8.3 Caveats

+

There are a few Cylc 7 features which do not yet have direct replacements in +Cylc 8. These features will be re-implemented in future releases.

+
+

Cylc Flow

+
+
Multiple Flows

The new scheduler can manage multiple flows in the workflow graph. +Commands and options for interacting with flows are still being refined.

+
+
+
+
+

Browser Based UI

+

The old “GUI” has been replaced by the new browser-based “UI”.

+
+
Static Graph Visualization

Not yet reimplemented for Cylc 8. As an interim measure the +cylc graph command can generate a basic PNG image of a workflow +graph if Graphviz is installed in the Cylc environment.

+
+
Multiple Selection

Multiple selection is yet to be implemented, however, it is possible +to issue action for multiple tasks (e.g. kill) without using +multiple selection:

+
    +
  • From the UI click on a workflow/cycle/task/job.

  • +
  • Find the action you want to call (e.g. kill).

  • +
  • Click the pencil symbol next to this action.

  • +
  • Edit the workflows/cycles/tasks/jobs in the form and press submit.

  • +
  • https://github.com/cylc/cylc-ui/issues/434

  • +
+
+
Installing Workflows

At present there is no way to view or install +source workflows in the UI.

+
+
Rose Edit

Rose Edit is awaiting reimplementation.

+
+
Xtrigger Visibility

Xtriggers are not yet visible in the UI.

+ +
+
Documentation / Orientation Guide

Some form of documentation will be provided within the UI itself.

+ +
+
+
+
+

UI Server

+
+
CLI via UIS

The ability to route Cylc commands via the UIS is planned for a future release

+ +
+
+
+
+ + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/7-to-8/cheat-sheet.html b/nightly_8.3/html/7-to-8/cheat-sheet.html new file mode 100644 index 0000000000..b24d5f1c8e --- /dev/null +++ b/nightly_8.3/html/7-to-8/cheat-sheet.html @@ -0,0 +1,559 @@ + + + + + + + + + Cheat Sheet — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Cheat Sheet

+

Quick summary of the command line changes between Cylc 7 / Rose 2019 and Cylc 8.

+
+

Validating

+

Check the workflow configuration for errors:

+ + + + + + + + + + + +

Cylc 7

Rose 2019

Cylc 8 (Rose 2)

cylc validate <name/path>
+
+
+
# validate from $PWD
+rose suite-run --validate
+
+
+
cylc validate <name/path>
+
+
+
+
+
+

Installing & Running

+

Install a workflow from source and run it:

+ + + + + + + + + + + +

Cylc 7

Rose 2019

Cylc 8 (Rose 2)

# no installation capability
+# run from source
+cylc run <name>
+
+
+
# install from $PWD
+# then run
+rose suite-run
+
+
+
# validate, install & play
+cylc vip <name>
+cylc vip # use $PWD
+
+
+
+
+
+

Reloading

+

To update a running workflow with changes from the source directory:

+ + + + + + + + + + + +

Cylc 7

Rose 2019

Cylc 8 (Rose 2)

# update the live source
+# directly, then
+cylc reload <name>
+
+
+
# re-install from source
+# and do ``cylc reload``
+rose suite-run --reload
+
+
+
# Validate against source;
+# Reinstall;
+# Reload or Play
+cylc vr <name>
+
+
+
+
+
+

Pausing & Unpausing

+

Tell a workflow not to submit any new jobs:

+ + + + + + + + + +

Cylc 7 & Rose 2019

Cylc 8 (Rose 2)

cylc hold <name>
+
+cylc unhold <name>
+
+
+
cylc pause <name>
+
+cylc play <name>
+
+
+
+
+
+

Stopping

+

Stop a running workflow:

+
cylc stop <name>
+
+
+
+
+

Restarting

+

Restart a stopped workflow and pick up where it left off:

+ + + + + + + + + + + +

Cylc 7

Rose 2019

Cylc 8 (Rose 2)

# no installation capability
+# restart from source
+cylc restart <name>
+
+
+
# regular restart
+rose suite-restart
+
+
+

Or alternatively:

+
# reinstall and restart
+rose suite-run --restart
+
+
+
# optionally reinstall
+cylc reinstall <name>
+
+# restart
+cylc play <name>
+
+
+
+
+
+

Deleting

+

Delete the workflow run directory (leave source files untouched):

+ + + + + + + + + + + +

Cylc 7

Rose 2019

Cylc 8 (Rose 2)

rm -rf ~/cylc-run/<name>
+
+
+
rose suite-clean <name>
+
+
+
cylc clean <name>
+
+
+
+
+
+

Scanning

+

List all running workflows:

+
cylc scan
+
+
+
+
+

View A Workflow’s Configuration

+

View the parsed workflow configuration:

+ + + + + + + + + + + +

Cylc 7

Rose 2019

Cylc 8 (Rose 2)

cylc get-config --sparse \
+    <name/path>
+
+
+
# install workflow
+rose suite-run -l
+
+# view installed config
+cylc get-config --sparse \
+    <name/path>
+
+
+
cylc config <name/path>
+
+
+
+
+
+

Opening User Interfaces

+

Opening the graphical user interface (GUI) or terminal user interface (TUI) +for monitoring / controlling running workflows:

+ + + + + + + + + + + + + + + + + + + +

Cylc 7 & Rose 2019

Cylc 8 (Rose 2)

Terminal

cylc monitor <name>
+
+
+
cylc tui <name>
+
+
+

Graphical

cylc gui <name>
+
+
+
cylc gui
+
+
+

Web Server

cylc review start
+
+
+
cylc hub
+
+
+
+
+
+

Static Graph Visualisation

+

Generate a visualisation for a workflow without running it:

+ + + + + + + + + +

Cylc 7 & Rose 2019

Cylc 8 (Rose 2)

cylc graph <name>
+
+
+
cylc graph <name>
+
+
+

This generates a basic image file if Graphviz is installed.

+

The web UI will have full graph vis. in a future release.

+
+
+
+

Datetime Operations

+

Datetime operations in task scripts:

+ + + + + + + + + + + + +

Cylc 7 & Rose 2019

Cylc 8 (Rose 2)

rose date <point> --offset <offset>
+
+
+
isodatetime <point> --offset <offset>
+
+
+
rose date -c
+# equivalent to:
+rose date "$CYLC_TASK_CYCLE_POINT"
+
+
+
isodatetime ref
+# equivalent to:
+isodatetime "$CYLC_TASK_CYCLE_POINT"
+
+
+
+
+
+

Rose Stem

+

Run a Rose Stem test suite.

+ + + + + + + + + +

Rose 2019

Rose 2 (Cylc 8)

# install and start
+rose stem
+
+
+
# install
+rose stem
+
+# start
+cylc play <name>
+
+
+
+
+
+

Interventions

+
+

Note

+

See the Interventions section for more details.

+
+

Set task outputs:

+ + + + + + + + + +

Cylc 7

Cylc 8

cylc reset -s=succeeded
+
+
+
cylc set --out=succeeded
+
+
+
+

Insert a task:

+ + + + + + + + + +

Cylc 7

Cylc 8

cylc insert
+
+
+

Tasks are inserted automatically when you “trigger” or “set” them.

+
+
+ + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/7-to-8/index.html b/nightly_8.3/html/7-to-8/index.html new file mode 100644 index 0000000000..2cb53ec23f --- /dev/null +++ b/nightly_8.3/html/7-to-8/index.html @@ -0,0 +1,177 @@ + + + + + + + + + Cylc 8 Migration Guide — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Cylc 8 Migration Guide

+

A quick guide for Cylc 7 (and Rose 2019) users upgrading to Cylc 8.

+
+

Tip

+

If you need help using or understanding Cylc 8 please post questions to the +Cylc 8 Migration category +on the Cylc Forum

+
+

Cylc 8 differs from Cylc 7 in many ways: architecture, scheduling +algorithm, security, UIs, working practices, and more.

+ +
+ + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/7-to-8/major-changes/cli.html b/nightly_8.3/html/7-to-8/major-changes/cli.html new file mode 100644 index 0000000000..2ec91a8c4a --- /dev/null +++ b/nightly_8.3/html/7-to-8/major-changes/cli.html @@ -0,0 +1,399 @@ + + + + + + + + + Command Line Interface — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Command Line Interface

+
+

Does This Change Affect Me?

+

This will affect you if you use the Cylc command line interface.

+
+
+

Overview

+
    +
  • Some commands have been renamed e.g. cylc run -> cylc play.

  • +
  • Some tools have been added or removed.

  • +
  • A new task ID format has been introduced.

  • +
+

For a quick side by side comparison see the Cheat Sheet.

+
+
+

Full List Of Command Changes

+

The command line has been simplified from Cylc 7 with some commands being +renamed or removed.

+

Commands that have been removed entirely:

+
+
cylc checkpoint
    +
  • Database checkpoints are no longer needed.

  • +
  • All task state changes are written to the database when they occur.

  • +
  • Remaining use cases can be handled by starting a new flow +which allow a new execution of the graph to be started from an +arbitrary point in the graph.

  • +
+
+
cylc documentation
    +
  • We no longer include a command for locating this documentation.

  • +
+
+
cylc edit
    +
  • Use a text editor to edit the workflow configuration file.

  • +
+
+
cylc jobscript
    +
  • It is no longer possible generate a jobscript from outside of a workflow.

  • +
+
+
cylc nudge
    +
  • No longer required.

  • +
+
+
cylc register
    +
  • Registration is no longer required, all workflows in the ~/cylc-run +directory are “registered” automatically.

  • +
  • To install a workflow from a working copy use cylc install.

  • +
+
+
cylc review
    +
  • The read-only cylc review web GUI has been removed.

  • +
  • The latest Cylc 7 version of cylc review is Cylc 8 compatible +so can still be used to monitor both Cylc 7 and Cylc 8 workflows +side by side.

  • +
+
+
cylc search
    +
  • Use grep or a text editor to search the workflow configuration or +source directory.

  • +
+
+
cylc submit
    +
  • It is no longer possible to submit a job from outside of a workflow.

  • +
+
+
cylc warranty
    +
  • The Cylc license remains unchanged from Cylc 7.

  • +
+
+
+

Commands that have been replaced:

+
+
cylc conditions
    +
  • See the license file for conditions of usage, or cylc help license

  • +
  • The Cylc license remains unchanged from Cylc 7.

  • +
+
+
cylc get-config,
    +
  • Replaced by cylc config.

  • +
+
+
cylc get-*-config
    +
  • (Where * is site, suite or global)

  • +
  • Replaced by cylc config.

  • +
+
+
cylc graph-diff
    +
  • Replaced by cylc graph <flow1> --diff <flow2>

  • +
+
+
cylc insert
    +
  • Task insertion is now automatic, use cylc trigger.

  • +
+
+
cylc monitor
    +
  • There is now a new more powerful terminal user interface (TUI).

  • +
  • Try cylc tui.

  • +
+
+
cylc print
    +
  • Equivalent to cylc scan --states=all.

  • +
+
+
cylc reset
    +
  • cylc reset has been replaced by cylc set

  • +
  • At Cylc 8 we override task’s prerequisites & outputs rather than modifying +the task state directly.

  • +
+
+
cylc restart
    +
  • Replaced by cylc play.

  • +
+
+
cylc run
    +
  • Replaced by cylc play.

  • +
+
+
cylc spawn
    +
  • Spawning is now performed automatically, on demand. Use cylc trigger to run +a task, or cylc set to spawn tasks that depend on specified outputs.

  • +
+
+
cylc suite-state
    +
  • Renamed as cylc workflow-state.

  • +
+
+
+

Commands that have changed:

+
+
cylc hold
    +
  • Now used on tasks only; use cylc pause to pause an entire workflow +(i.e. to halt all job submissions).

  • +
+
+
cylc release
    +
  • Now used only to release held tasks; use cylc play to resume a paused workflow.

  • +
+
+
+

Graphical User Interfaces (GUIs):

+

The GTK based GUI based GUIs have been removed, please use the new web based +GUI. Consequently the following commands have also been removed:

+
    +
  • cylc gpanel

  • +
  • cylc gscan

  • +
  • cylc gcylc

  • +
+

The cylc gui command remains, it launches a standalone version of the +web GUI (providing the Cylc UI Server is installed).

+

Additionally, there are two +“compound commands” +which automate common working practices, namely:

+
+
cylc vip

Validate, install and play a workflow. This is similar to what +rose suite-run did.

+
+
cylc vr

Validate, reinstall, then either reload (if the workflow is running) or restart +(if it is stopped) the workflow. This is similar to what +rose suite-run --reload and rose suite-run --restart did.

+
+
+
+
+

Cylc 8 Standardised IDs

+

In Cylc 7 there were two ways to specify a task:

+
task.cycle
+cycle/task
+
+
+

In Cylc 8 the former is now deprecated, and the latter has been extended to +provide a unique identifier for all workflows, cycles, tasks and jobs using a +standard format:

+
~user/workflow//cycle/task/job
+
+
+

Consequently task IDs have changed:

+
# old
+cycle.task
+
+# new
+cycle/task
+
+
+

An example using cylc trigger:

+
# old
+cylc trigger workflow task.cycle
+
+# new
+cylc trigger workflow//cycle/task
+
+
+

Cylc 8 still supports the old format, however, the new format unlocks extra +functionality e.g:

+
# stop all running workflows
+cylc stop '*'
+
+# pause all running workflows
+cylc pause '*'
+
+# (re-)trigger all failed tasks in all running workflows
+cylc trigger '*//*:failed'
+
+# hold all tasks in the cycle "2000" in workflows with IDs
+ # beginning with "model"
+cylc hold 'model*//2000'
+
+# delete the run directories for all workflows with IDs
+# beginning with "model_a/"
+cylc clean 'model_a/*'
+
+
+

For more information run cylc help id.

+

For a quick overview of the motivation see the ID post on Discourse.

+
+
+ + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/7-to-8/major-changes/compatibility-mode.html b/nightly_8.3/html/7-to-8/major-changes/compatibility-mode.html new file mode 100644 index 0000000000..d8531d7e62 --- /dev/null +++ b/nightly_8.3/html/7-to-8/major-changes/compatibility-mode.html @@ -0,0 +1,390 @@ + + + + + + + + + Cylc 7 Compatibility Mode — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Cylc 7 Compatibility Mode

+
+

Does This Change Affect Me?

+

This will affect you if you want to run Cylc 7 (suite.rc) workflows +using Cylc 8.

+
+
+

Overview

+

Cylc 8 can run most Cylc 7 workflows “as is”. +The suite.rc filename triggers a backward compatibility mode in which:

+
    +
  • implicit tasks are allowed by default

    +
      +
    • (unless a rose-suite.conf file is found in the run directory +for consistency with rose suite-run behaviour)

    • +
    • (Cylc 8 does not allow implicit tasks by default)

    • +
    +
  • +
  • cycle point time zone defaults to the local time zone

    +
      +
    • (Cylc 8 defaults to UTC)

    • +
    +
  • +
  • waiting tasks are pre-spawned to mimic the Cylc 7 scheduling algorithm and +stall behaviour, and these require +suicide triggers +for alternate graph branching

    +
      +
    • (Cylc 8 spawns tasks on demand, and suicide triggers are not needed for +branching)

    • +
    +
  • +
  • succeeded task outputs are required, +so in the absence of suicide triggers the scheduler will retain other +final status tasks in the n=0 window to stall the +workflow.

    +
      +
    • (in Cylc 8, all outputs are required unless marked as +*optional* by the new ? syntax)

    • +
    +
  • +
+
+
+

Required Changes

+

Providing your Cylc 7 workflow does not use syntax that was deprecated at Cylc 7, +you may be able to run it using Cylc 8 without any modifications while in +compatibility mode.

+

First, run cylc validate with Cylc 7 on your suite.rc workflow +to check for deprecation warnings and fix those before validating with Cylc 8. +See below for an example.

+
+

Warning

+

cylc validate operates on the processed suite.rc, which +means it will not detect any deprecated syntax that is inside a +currently-unused Jinja2/EmPy if...else branch.

+
+

Some workflows may require modifications to either upgrade to Cylc 8 or make +interoperable with Cylc 8 backward compatibility mode. Read on for more details.

+
+

Cylc commands in task scripts

+

Check for any use of Cylc commands in task scripting. Some Cylc 7 commands +have been removed and some others now behave differently. +However, cylc message and cylc broadcast have not changed. +See the full list of command line interface changes +and see below for an example.

+
+
+

Python 2 to 3

+

Whereas Cylc 7 runs using Python 2, Cylc 8 runs using Python 3. This affects: +- modules imported in Jinja2 +- Jinja2 filters, tests and globals +- custom xtrigger functions

+

Note that task scripts are not affected - they run in an independent +environment.

+

See Python 2 => 3 for more information and examples of how to implement +interoperability if your workflows extend Cylc or Jinja2 with custom Python scripts.

+
+
+

Other caveats

+ +
+
+
+

Examples

+
+

Validating with Cylc 7

+

Consider this configuration:

+
+
suite.rc
+
[scheduling]
+    initial cycle point = 11000101T00
+    [[dependencies]]
+        [[[R1]]]
+            graph = task
+
+[runtime]
+    [[task]]
+        pre-command scripting = echo "Hello World"
+
+
+
+

Running cylc validate at Cylc 7 we see that the +workflow is valid, but we are warned that pre-command scripting +was replaced by pre-script at 6.4.0:

+
+
Cylc 7 validation
+
$ cylc validate .
+WARNING - deprecated items were automatically upgraded in 'suite definition':
+WARNING -  * (6.4.0) [runtime][task][pre-command scripting] -> [runtime][task][pre-script] - value unchanged
+Valid for cylc-7.8.7
+
+
+
+
+

Note

+

Cylc 7 has handled this deprecation for us, but at Cylc 8 this +workflow will fail validation.

+
+
Cylc 8 validation
+
$ cylc validate .
+IllegalItemError: [runtime][task]pre-command scripting
+
+
+
+
+

You must change the configuration yourself. In this case:

+
-     pre-command scripting = echo "Hello World"
++     pre-script = echo "Hello World"
+
+
+

Validation will now succeed.

+
+
+

Cylc commands in task scripts

+

You might have a task script that calls a Cylc command like so:

+
[runtime]
+    [[foo]]
+        script = cylc hold "$CYLC_SUITE_NAME"
+
+
+

The cylc hold command has changed in Cylc 8. It is now used for holding +tasks only; use cylc pause for entire workflows. +(Additionally, $CYLC_SUITE_NAME is deprecated in favour of +$CYLC_WORKFLOW_ID, though still supported.)

+

In order to make this interoperable, so that you can run it with both Cylc 7 +and Cylc 8 backward compatibility mode, you could do something like this +in the bash script:

+
[runtime]
+    [[foo]]
+        script = """
+            if [[ "${CYLC_VERSION:0:1}" == 7 ]]; then
+                cylc hold "$CYLC_SUITE_NAME"
+            else
+                cylc pause "$CYLC_WORKFLOW_ID"
+            fi
+        """
+
+
+

Note this logic (and the $CYLC_VERSION environment variable) is executed +at runtime on the job host.

+

Alternatively, you could use Jinja2 like so:

+
[runtime]
+    [[foo]]
+        {% if CYLC_VERSION is defined and CYLC_VERSION[0] == '8' %}
+            script = cylc pause "$CYLC_WORKFLOW_ID"
+        {% else %}
+            script = cylc hold "$CYLC_SUITE_NAME"
+        {% endif %}
+
+
+

Note this logic (and the CYLC_VERSION Jinja2 variable) is executed locally +prior to Cylc parsing the workflow configuration.

+
+
+
+

Renaming to flow.cylc

+

When your workflow runs successfully in backward compatibility mode, it is +ready for renaming suite.rc to flow.cylc. Doing this will turn off +backward compatibility mode, and validation in Cylc 8 will show +deprecation warnings.

+ +
+

Important

+

More complex workflows (e.g. those with suicide triggers) may +fail validation once backward compatibility is off - see +Graph branching, optional outputs and suicide triggers

+
+
+
+ + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/7-to-8/major-changes/config-changes.html b/nightly_8.3/html/7-to-8/major-changes/config-changes.html new file mode 100644 index 0000000000..123d2ededf --- /dev/null +++ b/nightly_8.3/html/7-to-8/major-changes/config-changes.html @@ -0,0 +1,285 @@ + + + + + + + + + Configuration Changes at Cylc 8 — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Configuration Changes at Cylc 8

+

Some configurations have moved or been renamed at Cylc 8.

+

The old configurations are now deprecated, but still supported. +These will be highlighted upon cylc validate after renaming suite.rc +to flow.cylc.

+

Because some workflows use Jinja2 or EmPy branches which may not be switched on at +the time of the initial cylc validate we have also provided +a script, cylc lint -r 728 to check for Cylc 7 +syntax which may be deprecated.

+

There are some examples below of how to upgrade:

+
+

Graph

+

Cylc 7 had unnecessarily deep nesting of graph config sections:

+
[scheduling]
+    initial cycle point = now
+    [[dependencies]]
+        [[[R1]]]
+            graph = "prep => foo"
+        [[[R/^/P1D]]]
+            graph = "foo => bar => baz"
+
+
+

Cylc 8 cleans this up:

+
[scheduling]
+    initial cycle point = now
+    [[graph]]
+        R1 = "prep => foo"
+        R/^/P1D = "foo => bar => baz"
+
+
+
+
+

Fixing deprecation warnings

+

Take the following example flow.cylc file:

+
[cylc]
+   UTC mode = True
+[scheduling]
+    initial cycle point = 2000-01-01
+    [[dependencies]]
+        [[[R1]]]
+            graph = foo => bar
+[runtime]
+    [[foo, bar]]
+
+
+

This workflow will pass validation at Cylc 8, but will give warnings:

+
$ cylc validate .
+WARNING - deprecated items were automatically upgraded in "workflow definition"
+WARNING -  * (8.0.0) [cylc] -> [scheduler] - value unchanged
+WARNING - deprecated graph items were automatically upgraded in "workflow definition":
+   * (8.0.0) [scheduling][dependencies][X]graph -> [scheduling][graph]X - for X in:
+         R1
+Valid for cylc-8.0.0
+
+
+

The warnings explain what needs to be fixed. After making the following changes, +the workflow will validate without any warnings:

+
-[cylc]
++[scheduler]
+     UTC mode = True
+ [scheduling]
+     initial cycle point = 2000-01-01
+-    [[dependencies]]
+-        [[[R1]]]
+-            graph = foo => bar
++    [[graph]]
++        R1 = foo => bar
+ [runtime]
+     [[foo, bar]]
+
+
+
+

Tip

+

Later Cylc releases will not be able to upgrade obsolete Cylc 7 +configurations. It’s a good idea to address warnings as part of routine +workflow review and maintenance to avoid problems later on.

+
+
+
+

Platforms

+ +

At Cylc 7, job hosts were defined to indicate where a job should run. +At Cylc 8, this has been replaced by Platforms.

+
 [runtime]
+     [[foo]]
+-        [[[job]]]
+-            batch system = slurm
+-        [[[remote]]]
+-            host = hpc1.login.1
++        platform = hpc1
+
+
+

For a comprehensive list of valid configuration, see: Workflow Configuration +and Global Configuration.

+
+
+ + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/7-to-8/major-changes/continuing-c7-c8.html b/nightly_8.3/html/7-to-8/major-changes/continuing-c7-c8.html new file mode 100644 index 0000000000..92f27dde70 --- /dev/null +++ b/nightly_8.3/html/7-to-8/major-changes/continuing-c7-c8.html @@ -0,0 +1,228 @@ + + + + + + + + + Continuing a Cylc 7 Workflow with Cylc 8 — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Continuing a Cylc 7 Workflow with Cylc 8

+
+

Does This Change Affect Me?

+

Read this if you have a partially complete Cylc 7 workflow that you want to +continue, rather than start from scratch, with Cylc 8. Some cycling +workflows, for example, may need to run expensive “cold start” tasks and +incur a multi-cycle spin-up if started from scratch.

+
+
+

Warning

+

Cylc 8 cannot restart a Cylc 7 workflow in-place, and continuing in a new +run directory involves some careful set up (below). So, if possible you +should complete the run with Cylc 7.

+
+

To continue a Cylc 7 workflow with Cylc 8:

+
    +
  1. Stop the Cylc 7 workflow at an convenient place

    +
      +
    • Typically the end of a cycle point, to simplify the continuation

    • +
    +
  2. +
  3. Install a new instance of the workflow from +source, with Cylc 8

    +
      +
    • Adapt file paths to the new run directory structure, in workflow and task +configurations

    • +
    • Note Cylc 8 does remote file installation +when a job is first submitted to a platform

    • +
    +
  4. +
  5. Copy runtime files needed by upcoming tasks from the old to the new run +directory

    +
      +
    • This could include external files installed by initial tasks at runtime

    • +
    • Note different files could be present on different job platforms

    • +
    +
  6. +
  7. Start the new Cylc 8 run at the appropriate cycle point or task(s) in the +graph

    +
      +
    • Don’t reset the initial cycle point (in the flow.cylc or on +the command line) to the start point of the +Cylc 8 run. That would result in the “cold start” that this continuation +procedure is designed to avoid. Instead use the --start-cycle-point +option (or --start-task) with cylc play, to start at the right +place within the graph.

    • +
    +
  8. +
+
+ + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/7-to-8/major-changes/cylc-install.html b/nightly_8.3/html/7-to-8/major-changes/cylc-install.html new file mode 100644 index 0000000000..026db1a16a --- /dev/null +++ b/nightly_8.3/html/7-to-8/major-changes/cylc-install.html @@ -0,0 +1,358 @@ + + + + + + + + + Cylc Install — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Cylc Install

+ +
+

Does This Change Affect Me?

+

Almost certainly.

+

This change will affect you:

+
    +
  • If you use rose suite-run to install and run Cylc workflows.

  • +
  • If you usually develop Cylc workflows in the ~/cylc-run directory.

  • +
  • If you develop Cylc workflows outside of the ~/cylc-run directory and +manually copy the files to ~/cylc-run.

  • +
+
+
+

Overview

+

Cylc 7 ran workflows in ~/cylc-run/. You could develop your +workflow in ~/cylc-run or copy it after developing it elsewhere. +If you developed in the ~/cylc-run directory there was a risk that +Cylc might alter your files. If you developed elsewhere you needed to +install your workflows manually with another tool.

+

We designed Cylc 8 to help you keep your development and +running copies separate. By default you can now develop workflows in the +~/cylc-src directory. As a result, you will not change your development +copy by running a workflow. You will, however, need to install your workflow +from ~/cylc-src to ~/cylc-run using the cylc install command.

+
+

Note

+

If you have previously used Rose, cylc install functions in a +similar way to rose suite-run --install-only.

+
+

Examples:

+
    +
  • You can install a workflow from inside the source directory:

    +
    $ cd ~/cylc-src/my-workflow
    +$ cylc install
    +INSTALLED my-workflow/run1 from /home/me/cylc-src/my-workflow
    +
    +
    +
  • +
  • You can install a workflow by providing the workflow source name +(if the source directory is located in any of the +Configurable Source Directories, e.g. ~/cylc-src):

    +
    $ cylc install my-workflow
    +INSTALLED my-workflow/run2 from /home/me/cylc-src/my-workflow
    +
    +
    +
  • +
  • You can install a workflow by providing the path to the source directory:

    +
    $ cylc install ~/cylc-src/my-workflow
    +INSTALLED my-workflow/run3 from /home/me/cylc-src/my-workflow
    +
    +
    +
  • +
+
+

Note

+

Each time you run cylc install for a particular workflow, a new copy of +the workflow is installed to a new run directory. In the example above, we +created three run directories inside ~/cylc-run/my-workflow.

+
+

Once you have installed a workflow you can use cylc play to run it - see +Running Workflows.

+

You can delete installed workflows using cylc clean - see +Removing Workflows.

+

A .cylcignore file can be used to control which files cylc install +transfers to the installed workflow, see 1. File Installation for details.

+
+
+

Remote Installation

+

Remote file installation does not occur until running the workflow. +When the first task runs on a remote platform, Cylc will transfer files from +the run directory to the install target.

+

If you have used Rose 2019, you may be used to all files and directories in +the run directory being included. +However, Cylc 8 will only copy the ana, app, bin, etc and +lib directories by default (in addition to authentication files in +.service). +If you want to include custom files and directories in remote installation, +use flow.cylc[scheduler]install.

+
+

Tip

+

If you need to ensure your workflow is still +interoperable with Cylc 7, wrap it in a +Jinja2 check like so:

+
{% if CYLC_VERSION is defined and CYLC_VERSION[0] == '8' %}
+[scheduler]
+    install = my-dir/, my-file
+{% endif %}
+
+
+
+

See the user guide for more details.

+
+

Warning

+

If you have tasks that mirror/copy the run directory to a remote platform +(such as FCM make tasks), this can cause conflicts with +symlink directory setup.

+

You can find out if symlink directories are configured for the platform by +running:

+
cylc config -i '[install][symlink dirs][<platform-name>]'
+
+
+

The recommended workaround is to use a “dummy” task that runs on the +particular platform before any such mirror tasks in order to setup symlink +directories, but without running anything.

+

For example:

+
[scheduling]
+    [[graph]]
+        R1 = hpc_init => fcm_make
+
+[runtime]
+    [[hpc_init]]
+        platform = <platform-name>
+        script = true
+
+
+
+
+
+

Migrating From rose suite-run

+

The rose suite-run command has been replaced by cylc install.

+
# rose 2019 / Cylc 7
+$ rose suite-run
+
+# rose 2 / Cylc 8
+$ cylc install
+$ cylc play <id>
+
+
+

Support for the rose-suite.conf file is provided by the Cylc Rose +plugin which must be installed for Rose integration.

+
+

Installation

+

See the Installation section for instructions.

+

If Cylc Rose is installed it should appear in the list of installed +Cylc plugins:

+
$ cylc version --long
+8.0 (/path/to/cylc-8)
+
+Plugins:
+    cylc-rose       0.1.1   /path/to/cylc-rose
+
+
+
+
+

Notable differences to rose suite-run

+
+
Command line options:

The cylc install command remembers any options specified on the command +line including Rose optional configurations and template variables and +automatically applies them with future re-installations.

+
+
Rose Stem:

The rose stem command is provided by Cylc Rose. Like rose suite-run, +rose stem used to install and run workflows. It now only +installs the workflow which can then be run with cylc play.

+

See the Rose Stem documentation for more information.

+
+
Roses directory:

By default cylc install looks for workflows in ~/cylc-src, you +you may want to add ~/roses to the list of +global.cylc[install]source dirs.

+
+
Remote Installation:

With Rose 2019 / rose suite-run, files were installed on remote platforms +before the workflow started running.

+

With Rose 2 / cylc install, files are installed on remote platforms just +before the first task runs on that platform.

+

Rose used to install the entire workflow run directory to remote +platforms. It now only installs configured directories for efficiency. +See Remote Installation above for details.

+
+
+
+
+
+ + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/7-to-8/major-changes/excluding-tasks.html b/nightly_8.3/html/7-to-8/major-changes/excluding-tasks.html new file mode 100644 index 0000000000..ce96282b5d --- /dev/null +++ b/nightly_8.3/html/7-to-8/major-changes/excluding-tasks.html @@ -0,0 +1,215 @@ + + + + + + + + + Excluding Tasks at Start-up is Not Supported — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Excluding Tasks at Start-up is Not Supported

+
+

Does This Change Affect Me?

+

This will affect you if your workflows use the following configurations:

+
    +
  • [scheduling][special tasks]include at start-up

  • +
  • [scheduling][special tasks]exclude at start-up

  • +
+
+
+

Overview

+

The Cylc 7 scheduler allowed you to exclude tasks from the scheduler at start-up:

+
# Cylc 7 only
+[scheduling]
+   [[special tasks]]
+        include at start-up = foo, bar, baz  # Cylc 8 ERROR!
+        exclude at start-up = bar  # Cylc 8 ERROR!
+
+
+

The first config item above excludes all task names not in the include-list; +the second excludes specific tasks that would otherwise be included.

+

The Cylc 7 scheduler started up with an instance of every task in its “task +pool”, and the workflow evolved by each task spawning its own next-cycle +instance at the right time. So, if you excluded a task a start-up it would not +run in the workflow at all unless manually inserted later at runtime.

+

The Cylc 8 scheduler starts up with only the initial tasks in the graph and the +workflow evolves by spawning new tasks on demand as dictated by the graph. +Consequently excluding a task at start up as described above would have no +effect at all on most tasks.

+

This feature also predated the current Cylc dependency graph configuration. To +exclude tasks now without entirely removing them from the workflow definition, +just comment them out of the graph.

+
+
+ + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/7-to-8/major-changes/index.html b/nightly_8.3/html/7-to-8/major-changes/index.html new file mode 100644 index 0000000000..cce3529693 --- /dev/null +++ b/nightly_8.3/html/7-to-8/major-changes/index.html @@ -0,0 +1,201 @@ + + + + + + + + + Detailed Description of Major Changes — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+ + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/7-to-8/major-changes/parameters.html b/nightly_8.3/html/7-to-8/major-changes/parameters.html new file mode 100644 index 0000000000..56eb0b7733 --- /dev/null +++ b/nightly_8.3/html/7-to-8/major-changes/parameters.html @@ -0,0 +1,266 @@ + + + + + + + + + Parameters — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Parameters

+
+

does this change affect me?

+

If you use Cylc parameters with negative offsets (e.g. foo<x-1>).

+
+
+

Overview

+

There has been a subtle change in the way negative offsets are handled in parameters.

+
+
+

Example

+

If you have a parameter x with the values 1, 2 & 3:

+
[task parameters]
+   x = 1..3
+
+
+

And use it like so:

+
a<x-1> => b<x> => c<x>
+
+
+

There is some ambiguity about how this should be interpreted when x=1 +because <x-1> would be 0 which is not a valid value for the parameter +x.

+

Cylc 7 removed the part of the expression which was out of range resulting in a +partial evaluation of that line:

+
        b_x1 => c_x1  # x=1
+a_x1 => b_x2 => c_x2  # x=2
+a_x2 => b_x3 => c_x3  # x=3
+
+
+

Whereas Cylc 8 will remove everything after the first out-of-range parameter - <x-1> (so the entire line for this example):

+
a_x1 => b_x2 => c_x2  # x=2
+a_x2 => b_x2 => c_x2  # x=3
+
+
+
+
+

Migration

+

If your workflow depends on the Cylc 7 behaviour, then the solution is +to break the expression into two parts which Cylc will then evaluate separately.

+
- a<x-1> => b<x> => c<x>
++ a<x-1> => b<x>
++ b<x> => c<x>
+
+
+

Resulting in:

+
# a<x-1> => b<x>
+a_x1 => a_x2  # x=2
+a_x2 => a_x3  # x=3
+
+# b<x> => c<x>
+b_x1 => c_x1  # x=1
+b_x2 => c_x2  # x=2
+b_x3 => c_x3  # x=3
+
+
+
+
+

Line Breaks

+

Note that these expressions are all equivalent:

+ + + + + + + +
a<x-1> => b<x> => c<x>
+
+
+
a<x-1> =>
+b<x> =>
+c<x>
+
+
+
a<x-1> => b<x> => \
+c<x>
+
+
+
+
+
+ + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/7-to-8/major-changes/platforms.html b/nightly_8.3/html/7-to-8/major-changes/platforms.html new file mode 100644 index 0000000000..af5a64eb4d --- /dev/null +++ b/nightly_8.3/html/7-to-8/major-changes/platforms.html @@ -0,0 +1,412 @@ + + + + + + + + + Platforms — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Platforms

+
+

Does This Change Affect Me?

+

Cylc platforms are a new feature which replace the task job and +remote configuration sections:

+ +
+
+

Overview

+
+

Note

+
    +
  • The terms platform and job platform are equivalent.

  • +
  • The terms job runner (in Cylc 8 configurations) and batch system +(in Cylc 7 configurations) are equivalent.

  • +
+
+

Submitting a job to a job runner may require configuration.

+

In Cylc 7 this configuration must be provided for each task in the workflow +configuration (suite.rc).

+

In Cylc 8 “platforms” can be defined in the global configuration +(global.cylc) so that this configuration doesn’t have to be +repeated for each task in each workflow.

+

There may be cases where sets of platforms (for example a group of +standalone compute servers, or a pair of mirrored HPC’s) might be equally +suitable for a task. Such platforms can be set up to be platform groups

+
+

See also

+

Listing available platforms for details of how to list platforms +already defined.

+

Platform Configuration for detailed examples of platform +configurations.

+
+
+

Tip

+

Cylc 8 contains upgrade logic (see below) +which handles the deprecated Cylc 7 settings in most cases. +Unless you are in backward compatibility mode, +you should upgrade to using platforms instead. +Deprecated settings will be removed in a later release of Cylc.

+
+
+
+

What is a Platform?

+

A “platform” represents one or more hosts from which jobs can be submitted to or +polled from a common job submission system.

+

If a platform has multiple hosts Cylc will automatically select a host when +needed and will fallback to other hosts if it is not contactable.

+

A “platform group” represents a collection of independent platforms. Cylc will +automatically select a platform and will fallback to other platforms in the +group (for appropriate operations) if the platform is not contactable.

+
+
+

Examples

+
+

See also

+

global.cylc[platforms] has a detailed explanation of how +platforms and platform groups are defined.

+
+
+

Simple example

+

Consider this Cylc 7 syntax in a flow.cylc file:

+
[runtime]
+    [[mytask]]
+        [[[job]]]
+            batch system = slurm
+        [[[remote]]]
+            host = login_node01
+
+
+

The Cylc 8 global config (global.cylc) might contain:

+
[platforms]
+    [[our_cluster]]
+        hosts = login_node01, login_node02
+        job runner = slurm
+
+
+
+

Tip

+

You can view the platforms available at your site by running:

+
cylc config --platforms
+
+
+
+

The platform our_cluster matches the current configuration due to having +the same job runner (batch system) and correct hosts. Thus we can replace the +deprecated syntax:

+
 [runtime]
+     [[mytask]]
+-        [[[job]]]
+-            batch system = slurm
+-        [[[remote]]]
+-            host = login_node01
++        platform = our_cluster
+
+
+
+
+

A variety of other examples

+

Here are some example Cylc 7 task definitions:

+
[runtime]
+   [[mytask_cylc_server]]
+
+   [[mytask_big_server]]
+      [[[remote]]]
+         host = linuxbox42
+
+   [[mytask_submit_local_to_remote_computer]]
+      [[[job]]]
+         batch system = pbs
+
+   [[mytask_login_to_hpc_and_submit]]
+      [[[remote]]]
+         # e.g. rose host-select
+         host = $(supercomputer_login_node_selector_script)
+      [[[job]]]
+         batch system = slurm
+
+
+

This will result in Cylc running:

+
    +
  • mytask_cylc_server on the machine the workflow is running on.

  • +
  • mytask_big_server on linuxbox42, using background.

  • +
  • mytask_submit_local_to_remote_computer on a system where you can +use PBS to submit from the workflow server.

  • +
  • mytask_login_to_hpc_and_submit on a host set by the subshelled +script using Slurm.

  • +
+

At Cylc 8 the equivalent might be:

+
[runtime]
+    [[mytask_cylc_server]]
+
+    [[mytask_big_server]]
+        platform = linuxbox42
+
+    [[mytask_submit_local_to_remote_computer]]
+        platform = pbs_local
+
+    [[mytask_login_to_hpc_and_submit]]
+        # Recommended:
+        platform = slurm_supercomputer
+        # ...but This is still legal:
+        #platform = $(selector-script)
+
+
+

And the platform settings for these examples might be:

+
[platforms]
+    [[linuxbox\d\d]]  # Regex to allow any linuxboxNN to use this definition
+        # Without a hosts, platform name is used as a single host.
+
+    [[pbs_local]]
+        # A computer with PBS, that takes local job submissions
+        job runner = pbs
+        hosts = localhost
+        install target = localhost
+
+    [[slurm_supercomputer]]
+        # This computer with Slurm requires you to use a login node.
+        hosts = login_node01, login_node02  # Cylc will pick a host.
+        job runner = slurm
+
+
+

Note that in these examples, it is assumed that linuxboxNN, pbs_local and +slurm_supercomputer have distinct file systems. +Sets of platforms which share a file system must specify +a single install target.

+
+

Note

+

If an install target is not set, a platform will use its own platform name +as the install target name. If multiple platforms share a file system +but have separate install targets task initialization +will fail.

+
+
+
+
+

How Cylc 8 handles host-to-platform upgrades

+

If you are using the deprecated [remote] and [job] runtime sections, +Cylc 8 will attempt to find a platform which matches the task specification.

+
+

Important

+

Cylc 8 needs platforms matching the Cylc 7 job configuration to be +available in global.cylc[platforms].

+
+
+

Example

+

If, for example you have a Cylc 8 global.cylc with the following +platforms section:

+
[platforms]
+    [[supercomputer_A]]
+        hosts = localhost
+        job runner = slurm
+        install target = localhost
+    [[supercomputer_B]]
+        hosts = tigger, wol, eeyore
+        job runner = pbs
+
+
+

And you have a workflow runtime configuration:

+
[runtime]
+    [[task1]]
+        [[[job]]]
+            batch system = slurm
+    [[task2]]
+        [[[remote]]]
+            host = eeyore
+        [[[job]]]
+            batch system = pbs
+
+
+

Then, task1 will be assigned platform +supercomputer_A because the specified host (implicitly localhost) +is in the list of hosts for supercomputer_A and the batch system is the same. +Likewise, task2 will run on supercomputer_B.

+
+

Important

+

For simplicity, and because the host key is a special case (it can +match and host in [platform]hosts) we only show these two config keys +here. In reality, Cylc 8 compares the whole of +[<task>][job] and [<task>][remote] +sections and all items must match to select a platform.

+
+
+
+
+ + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/7-to-8/major-changes/play-pause-stop.html b/nightly_8.3/html/7-to-8/major-changes/play-pause-stop.html new file mode 100644 index 0000000000..8bb629a69b --- /dev/null +++ b/nightly_8.3/html/7-to-8/major-changes/play-pause-stop.html @@ -0,0 +1,306 @@ + + + + + + + + + Play Pause Stop — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Play Pause Stop

+
+

Does This Change Affect Me?

+

Yes if you run Cylc workflows.

+
+
+

Overview

+

Cylc 8 uses a simplified model for controlling workflows based on the controls +of a tape player.

+

There are now three controls, play, pause and stop:

+
    +
  • When a workflow is playing, the scheduler is running.

  • +
  • When a workflow is paused, no new jobs will be submitted.

  • +
  • When a workflow is stopped the scheduler is no longer running.

  • +
+

These controls are available in the web GUI or on the command line with the +commands:

+
    +
  • cylc play

  • +
  • cylc pause

  • +
  • cylc stop

  • +
+

A workflow can be safely played, paused and stopped any number of times without +interrupting the workflow.

+
+
+

Re-Running Workflows

+

The cylc play command will always pick up where it left off (a +restart).

+

If you want to re-run the entire workflow again from the start either:

+
    +
  • Install a new run.

  • +
  • Or if you want to keep the data from the old run start a new flow at +the beginning of the graph, and stop the original flow.

  • +
+

It is still possible to re-run workflows in-place in the Cylc 7 manner, however, +this is discouraged. +To do this remove the workflow database as well as any other evidence of the +previous run that is no longer desired:

+
# remove the workflow database, the work, share and log directories
+cylc clean <id> --rm .service/db:work:share:log
+
+# only remove the worflow database
+$ cylc clean <id> --rm .service/db
+
+
+

Then restart with cylc play.

+
+
+

Hold & Release

+

The cylc hold and cylc release commands are still present. These +work on individual tasks rather than the workflow as a whole.

+
+
+

Mapping To Old Commands

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Cylc 7

Rose 2019

Cylc 8 (Rose 2)

Play

cylc run <id>
+
+
+
rose suite-run
+
+
+
cylc play <id>
+
+
+

Pause

cylc hold <id>
+
+
+
cylc hold <id>
+
+
+
cylc pause <id>
+
+
+

Resume

cylc release <id>
+
+
+
cylc release <id>
+
+
+
cylc play <id>
+
+
+

Stop

cylc stop <id>
+
+
+
rose suite-shutdown
+
+
+
cylc stop <id>
+
+
+
+
+
+ + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/7-to-8/major-changes/python-2-3.html b/nightly_8.3/html/7-to-8/major-changes/python-2-3.html new file mode 100644 index 0000000000..8428a0b7e7 --- /dev/null +++ b/nightly_8.3/html/7-to-8/major-changes/python-2-3.html @@ -0,0 +1,297 @@ + + + + + + + + + Python 2 => 3 — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Python 2 => 3

+
+

Does This Change Affect Me?

+

This change will affect you if your workflows extend Cylc or Jinja2 with +custom Python scripts.

+

This does not impact task scripts; Cylc can still run Python 2 +tasks if desired.

+
+
+

Overview

+

Cylc 7 ran under Python 2; Cylc 8 runs under Python 3.

+

Cylc can be extended with custom Python scripts. These scripts are run under +the same version of Python used by Cylc.

+

As a result, if you are moving from Cylc 7 to Cylc 8, you must upgrade any +scripts from Python 2 to Python 3 in the process.

+

If you want to support both Cylc 7 and 8, you must support both Python 2 and 3. +There are tools to help you do this, e.g. six.

+
+
+

Impacted Scripts

+

The following scripts must be upgraded if used:

+
+
Custom Jinja2 Filters, Tests and Globals

These allow you to extend Jinja2 with Python code.

+

These scripts are located in the following directories within a workflow:

+
    +
  • Jinja2Filters

  • +
  • Jinja2Tests

  • +
  • Jinja2Globals

  • +
+
+
Modules imported by Jinja2

Python modules can be imported from Jinja2 e.g:

+
{% from "os" import path %}
+
+
+
+
Custom Trigger Functions

Any custom xtrigger functions.

+
+
+
+
+

Package Name Changes

+

Three Python packages have been renamed between Cylc 7 and Cylc 8:

+
    +
  • cylc => cylc.flow

  • +
  • isodatetime => metomi.isodatetime

  • +
  • rose => metomi.rose

  • +
+

If you are importing from these packages you will need to update the package names.

+

Here are some examples:

+

Convert Python code from Cylc 7 to Cylc 8:

+
- from cylc import LOG
++ from cylc.flow import LOG
+- from isodatetime.data import Duration
++ from metomi.isodatetime.data import Duration
+
+
+

Python code which supports both Cylc 7 & Cylc 8:

+
import sys
+if sys.version[0] == '3':
+    from cylc.flow import LOG
+    from metomi.isodatetime.data import Duration
+else:
+    from cylc import LOG
+    from isodatetime.data import Duration
+
+
+

Convert Jinja2 code from Cylc 7 to Cylc 8:

+
#!Jinja2
+- {% from "cylc" import LOG %}
++ {% from "cylc.flow" import LOG %}
+  {% do LOG.debug("Hello World!") %}
+
+
+

Jinja2 code which supports both Cylc 7 & Cylc 8:

+
#!Jinja2
+{% from "sys" import version -%}
+{% if version[0] == '3' -%}
+    {% from "cylc.flow" import LOG -%}
+{% else -%}
+    {% from "cylc" import LOG -%}
+{% endif -%}
+
+{% do LOG.debug("Hello World!") %}
+
+
+
+
+

Jinja2 - integers with leading zeros

+

Integers with leading zeros in Jinja2 expressions are now illegal and will +cause an error like Jinja2Error: expected token 'x', got 'integer'. +For example:

+
$ cylc validate my-workflow
+Jinja2Error: expected token 'end of statement block', got 'integer'
+File ~/cylc-run/my-workflow/flow.cylc
+  {% if START_HOUR == 06 or START_HOUR == 12 %}       <-- TemplateSyntaxError
+
+
+

The solution in this case is:

+
-{% if START_HOUR == 06 or START_HOUR == 12 %}
++{% if START_HOUR == 6 or START_HOUR == 12 %}
+
+
+
+
+

Rose

+

The same changes also impact Rose extensions:

+ +
+
+ + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/7-to-8/major-changes/remote-owner.html b/nightly_8.3/html/7-to-8/major-changes/remote-owner.html new file mode 100644 index 0000000000..6f9c16dc94 --- /dev/null +++ b/nightly_8.3/html/7-to-8/major-changes/remote-owner.html @@ -0,0 +1,212 @@ + + + + + + + + + Remote Usernames — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Remote Usernames

+
+

does this change affect me?

+ +
+
+

Overview

+

If your username differs between the scheduler host and job hosts, then +you may have configured Cylc to run jobs under the correct account using +flow.cylc[runtime][<namespace>][remote]owner +or used the --owner Cylc command line option +with commands which access remote hosts.

+

Cylc no longer supports specifying the username in this way, we suggest +configuring your remote username using the SSH configuration file e.g:

+
Host MyHost
+  User root
+
+
+

SSH will then automatically use the configured username when connecting to the +remote machine.

+

Since Cylc uses SSH and Rsync to manage job hosts, the SSH config also configures +Cylc.

+
+

Note

+

This approach using the SSH configuration file also works with Cylc 7.

+
+
+
+ + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/7-to-8/major-changes/scheduling.html b/nightly_8.3/html/7-to-8/major-changes/scheduling.html new file mode 100644 index 0000000000..4ef78409b2 --- /dev/null +++ b/nightly_8.3/html/7-to-8/major-changes/scheduling.html @@ -0,0 +1,229 @@ + + + + + + + + + Scheduling Algorithm — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Scheduling Algorithm

+ +

Cylc can manage infinite workflows of repeating tasks:

+../../_images/cycling.png +

Cylc 8 has a new scheduling algorithm that:

+
    +
  • Is much more efficient because it only has to manage active tasks

    +
      +
    • waiting tasks are not pre-spawned before they are needed

    • +
    • succeeded tasks are not kept across the active task window

    • +
    • no costly indiscriminate dependency matching is done

    • +
    +
  • +
  • Distinguishes between optional and +required task outputs, to support:

    + +
  • +
  • Causes no implicit dependence on previous-instance job submit

    +
      +
    • instances of same task can run out of cycle point order

    • +
    • the workflow will not unnecessarily stall downstream of failed tasks

    • +
    +
  • +
  • Provides a sensible active-task based window on the evolving workflow

    +
      +
    • (to fully understand which tasks appeared in the Cylc 7 GUI you had to +understand the scheduling algorithm)

    • +
    +
  • +
  • Supports multiple concurrent flows within the same workflow.

  • +
  • Can start a workflow from any task or tasks in the graph (no need for +checkpoint restart)

  • +
  • Can limit activity within as well as across cycles, without risking a stall

  • +
+
+ + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/7-to-8/major-changes/suicide-triggers.html b/nightly_8.3/html/7-to-8/major-changes/suicide-triggers.html new file mode 100644 index 0000000000..0eeb3d1e69 --- /dev/null +++ b/nightly_8.3/html/7-to-8/major-changes/suicide-triggers.html @@ -0,0 +1,277 @@ + + + + + + + + + Graph branching, optional outputs and suicide triggers — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Graph branching, optional outputs and suicide triggers

+

Cylc 8 has a new scheduling algorithm and +a new syntax for dealing with tasks that may not necessarily complete. +It handles graphs in an event-driven manner which means +that a workflow can follow different paths in different eventualities (without +the need for suicide triggers). This is called graph branching.

+
+

Does This Change Affect Me?

+

This change affects you if you are upgrading a Cylc 7 workflow that +contains graph branches that are not necessarily expected to complete +at runtime. You might get a GraphParseError during validation with +Cylc 8.

+

Typically this will be the case if you are using +suicide triggers (marked by ! before the +task name in the graph, e.g. foo:fail => !foo).

+

You should not perform this upgrade if still in Cylc 7 Compatibility Mode +(suite.rc filename).

+
+
+

Required Changes

+

Any task outputs that are not necessarily expected to +complete must be marked as optional using ?. +Suicide triggers can then be removed.

+
+
+

Example

+

Here is an example Cylc 7 graph:

+
foo:fail => recover
+
+foo | recover => bar
+
+# Remove the "recover" task in the success case.
+foo => ! recover
+# Remove the "foo" task in the fail case.
+recover => ! foo
+
+
+
+

digraph Example { +subgraph cluster_1 { + label = ":fail" + color = "red" + fontcolor = "red" + style = "dashed" + recover +} + +foo -> recover +recover -> bar [arrowhead="onormal"] +foo -> bar [arrowhead="onormal" weight=2] +}

+
+

Validating this with Cylc 8 will give an error:

+
$ cylc validate .
+GraphParseError: Opposite outputs foo:succeeded and foo:failed must both be optional if both are used
+
+
+

In Cylc 8, all task outputs are required to complete +unless otherwise indicated. However, it is impossible for both :succeed +and :fail to occur when a task runs.

+

The solution is to mark the outputs which are optional +(in this case foo:succeed and foo:fail) with a ? in the graph. +Also, the suicide triggers can be removed.

+
- foo:fail => recover
++ foo:fail? => recover
+
+- foo | recover => bar
++ foo? | recover => bar
+
+- # Remove the "recover" task in the success case.
+- foo => ! recover
+- # Remove the "foo" task in the fail case.
+- recover => ! foo
+
+
+

In Cylc 7, suicide triggers were used to remove tasks that did not complete +during runtime. Cylc 8’s event-driven graph handling allows such graph +branching using optional output syntax, without the need for suicide triggers. +(Suicide triggers are still supported in Cylc 8; however, they are most +likely unnecessary.)

+
+

Tip

+

Remember: foo? is short for foo:succeed?. It is the output +that is optional, not the task itself.

+
+
+

See also

+ +
+
+
+ + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/7-to-8/major-changes/task-job-states.html b/nightly_8.3/html/7-to-8/major-changes/task-job-states.html new file mode 100644 index 0000000000..aaa75de94e --- /dev/null +++ b/nightly_8.3/html/7-to-8/major-changes/task-job-states.html @@ -0,0 +1,196 @@ + + + + + + + + + Task/Job States — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Task/Job States

+
+

See also

+ +
+

Tasks are nodes in the abstract workflow graph representing +processes that should run once their prerequisites are satisfied. Jobs are the real processes submitted to execute these tasks (or at least, at +the submission stage, real job scripts). A task can have multiple jobs, by +automatic retries and manual re-triggering.

+

Cylc 7 had 13 task/job states. The GUI only showed tasks, with job data +from the latest job.

+

Cylc 8 has only 8 task/job states. The Cylc 8 UI shows both task and jobs. +Task icons are monochrome circles; job icons are coloured squares. The running +task icon incorporates a radial progress indicator.

+../../_images/task-job.png +
+ + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/7-to-8/major-changes/template-vars.html b/nightly_8.3/html/7-to-8/major-changes/template-vars.html new file mode 100644 index 0000000000..ff244ff820 --- /dev/null +++ b/nightly_8.3/html/7-to-8/major-changes/template-vars.html @@ -0,0 +1,261 @@ + + + + + + + + + Template Variables — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Template Variables

+
+

Does This Change Affect Me?

+

Read this section if you set Cylc template variables on the command line +using the -s, --set or -set-file options.

+

This does not affect the Rose jinja2:suite.rc and +empy:suite.rc variables set using the -S option to the +rose suite-run command.

+
+
+

Overview

+

Template variables are passed to Jinja2 or +EmPy for parsing the workflow definition in the +flow.cylc file.

+

In Cylc 7 template variables could only be strings, in Cylc 8 they can be any +valid Python literal including numbers, booleans, and lists.

+
+
+

Changes

+

Strings must be explicitly quoted i.e. key="value" rather than key=value.

+
+
+

Example

+

Setting template variables on the command line:

+
# Cylc 7
+cylc run <suite> -s 'FOO=abc'
+# Cylc 8
+cylc play <flow> -s 'FOO="abc"'
+
+
+

Setting template variables in a “set file” (using --set-file):

+
# Cylc 7
+FOO = abc
+BAR = bcd
+
+# Cylc 8
+FOO = "abc"
+BAR = "bcd"
+
+
+
+
+

New Features

+
+

Any valid Python literals

+

Template variables can now be any valid Python literals e.g:

+
"string"   # string
+123        # integer
+12.34      # float
+True       # boolean
+None       # None type
+[1, 2, 3]  # list
+(1, 2, 3)  # tuple
+{1, 2, 3}  # set
+{"a": 1, "b": 2, "c": 3}  # dictionary
+
+
+

See Default Values and Template Variables for more information.

+
+
+

Shorthand for list of strings

+
+

Added in version 8.2.

+
+

A new shorthand argument (-z/--set-list/--set-template) +has been introduced allowing easier definition of template +variables containing lists of strings on the command line:

+
# Before (still works)
+cylc <command> --set "X=['a', 'b', 'c']"
+
+# After
+cylc <command> --set-list X=a,b,c
+
+
+
+
+
+ + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/7-to-8/major-changes/ui.html b/nightly_8.3/html/7-to-8/major-changes/ui.html new file mode 100644 index 0000000000..be72f9d181 --- /dev/null +++ b/nightly_8.3/html/7-to-8/major-changes/ui.html @@ -0,0 +1,253 @@ + + + + + + + + + Cylc 8 UIs — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Cylc 8 UIs

+

There are two UI options available to monitor and control workflows at Cylc 8.

+
+

Cylc Tui

+

Cylc Tui (TUI = Terminal User Interface) is a command line version of the GUI +which comes packaged with the Cylc scheduler.

+

It can be used to monitor and control any workflows running under your user +account, trigger tasks, access log files and perform other common activities.

+

Start Tui by running the cylc tui command.

+
+../../_images/tui-1.png +
+

Tui showing the details of a failed job.

+
+
+
+../../_images/tui-2.png +
+

A list of actions that can be performed on the selected task.

+
+
+
+../../_images/tui-3.png +
+

Tui displaying the workflow configuration. It can also show scheduler and +job log files.

+
+
+

Tui replaces the Cylc 7 cylc monitor command.

+
+
+

Cylc Web GUI

+

The Cylc GUI application is a monitoring and control application which runs in +a web browser, it is distributed in the Cylc UI Server package which comes +separately from the core scheduler.

+

Start the GUI server and open the web app in your browser by running +cylc gui.

+
+../../_images/cylc-ui-dash.png +
+

The GUI homepage.

+
+
+
+../../_images/cylc-ui-tree.png +
+

The GUI displaying a workflow using the “tree” view.

+
+
+

See UI Server Configuration for how to configure the GUI.

+

As some workflows can be very large, or even infinite, the GUI uses a “window” +system to determine what to display. For more information, see The “n” Window.

+
+
+

Cylc Hub

+

The Cylc 8 GUI can be deployed with Jupyter Hub to support multi-user access +where it is possible to grant users the permission to view and interact with +workflows running under other user accounts. In these deployments, users will +have to authenticate when they open the GUI in the browser.

+

The central server is started by the cylc hub command.

+
+../../_images/hub.png +
+

The Jupyter Hub authentication page in a multi-user setup.

+
+
+

Multi-user setups need to be configured by site administrators, for more +information see Authorizing Others to Access Your Workflows.

+
+
+ + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/7-to-8/summary.html b/nightly_8.3/html/7-to-8/summary.html new file mode 100644 index 0000000000..06e50e692a --- /dev/null +++ b/nightly_8.3/html/7-to-8/summary.html @@ -0,0 +1,466 @@ + + + + + + + + + Summary Of Major Changes — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +
+

Summary Of Major Changes

+
+

Terminology

+

Cylc now uses more widely understood terms for several core concepts.

+ + + + + + + + + + + + + + + + + + + + +

Cylc 7 Term

Cylc 8 Term

suite

workflow

batch system

job runner

suite daemon

scheduler

suite.rc

flow.cylc

+

Note the configuration filename is now flow.cylc, not suite.rc.

+
+
+

Cylc 7 Compatibility Mode

+

Continuing to use the old suite.rc filename triggers a backward +compatibility mode in Cylc 8 which supports Cylc 7 +workflow configurations out of the box, with +some caveats. However, to future-proof +your workflow and take full advantage of Cylc 8 you should upgrade to Cylc 8 syntax.

+
+
+

Upgrading To Cylc 8

+
+

See also

+ +
+

There have been some configuration changes at Cylc 8. +To upgrade your Cylc 7 suite to a Cylc 8 workflow, first make sure it validates +in Cylc 7 without any warnings, then rename the workflow configuration file +from suite.rc to flow.cylc, then run cylc validate in Cylc 8 and +take action on any warnings.

+
+

Note

+

Validation warnings use a shorthand notation +to refer to nested configuration settings on a single line, like this: +[section][sub-section]item.

+
+
+
+

New Web and Terminal UIs

+
+

See also

+ +
+

At Cylc 8, there are two UIs available to monitor and control your workflows:

+
    +
  • a terminal UI application

    +
    +
    cylc tui
    +
    +
    +
    +
  • +
  • a web based UI application (requires Cylc UI Server)

    +
    +
    cylc gui
    +
    +
    +
    +
  • +
+
+
+

Command Changes

+

cylc run <suite_name> at Cylc 7 has become cylc play <workflow_id>.

+
+

See also

+ +
+

At Cylc 8, use cylc pause <workflow_id> to pause a workflow, halting all job +submission. To restart the workflow, use cylc play <workflow_id>.

+

To start a fresh run, use cylc install and play it safely in the new run +directory.

+

(Note that cylc hold and cylc release pause and release individual tasks.)

+
+
+

Task/Job States

+

Tasks are nodes in the abstract workflow graph, representing +applications to run at the appropriate point in the workflow. A job +is the script (and subsequent process) submitted by Cylc to +actually run the application. A task can have multiple jobs as the result of +automatic retries or manual re-triggering.

+

The 13 task/job states in Cylc 7 have been simplified to 8. Tasks and jobs have been +separated and states of both can be viewed in the GUI.

+../_images/task-job.png +

For more information, see Task/Job States.

+
+
+

Optional and Required Task Outputs

+
+

See also

+ +
+

By default, all Cylc 8 tasks are required to succeed - i.e., success is +a required output. Tasks with final status and incomplete +outputs get retained in the n=0 window pending user +intervention, which will stall the workflow.

+

Alternatively, outputs can be marked as optional, +which allows optional graph branching.

+

This allows the scheduler to correctly diagnose workflow completion.

+
+
+

Platform Awareness

+
+

See also

+

Platforms at Cylc 8.

+
+

Cylc 7 was aware of individual job hosts - one selected a host using: +[runtime][<namespace>][remote]host.

+

Cylc 8 is aware of sets of host settings called +[job] platforms. To choose a platform for a task use +[runtime][<namespace>]platform

+

Hosts of a platform must share a file system and job runner: +If one host is unavailable Cylc 8 can use other hosts +on the same platform to interact with jobs.

+

The same hosts can belong to multiple platforms, for example +you might be able to use the same host to launch both background and Slurm +jobs.

+
+

Note

+

Cylc 8 will pick a sensible platform for your Cylc 7 settings, +These deprecated settings will be removed in a future release.

+
+
+
+

Workflow Installation

+

Cylc 8 supports workflow installation.

+

For users of Rose, this replaces the functionality of rose suite-run.

+
+

Cylc Install

+
+

See also

+ +
+

Cylc install cleanly separates workflow source directory from +run directory. It installs workflow files ready for cylc play.

+
$ pwd
+~/cylc-src/demo
+
+$ ls
+flow.cylc
+
+$ cylc install
+INSTALLED demo/run1 from /home/oliverh/cylc-src/demo
+
+$ cylc play demo
+...
+demo/run1: oliver.niwa.local PID=6702
+
+
+

By default, run numbers increment with each install.

+
+
+

File Installation

+

When the first job runs on a remote platform (after start-up, or after a cylc reload), a +remote initialization process is triggered to install workflow files there.

+
+ +
+
+

Removing Workflows

+

Workflows can be deleted with cylc clean - see Removing Workflows. This +replaces the rose suite-clean functionality.

+
+
+

Architecture

+

There have been fundamental changes to the architecture of Cylc. You can read +about the new system design here Architecture.

+
+
+

Scheduling Algorithm

+

The scheduling algorithm has been changed, more information is available: +Scheduling Algorithm.

+
+
+

Log Files

+

The workflow log files have moved to new locations and some new files have been +added. For information on the Cylc 8 log files, see +Workflow Logs.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +

Cylc 7 (and Rose 2019)

Cylc 8

log/suite/log

log/scheduler/log

log/suite/log.<time>

log/scheduler/<start_number>-<type>-<file_number>.log

suite.rc.processed

log/config/flow-processed.cylc

log/rose-suite-run.log

log/install/<start_number>-install.log

+

log/remote-install/<start_number>-<type>-<platform>.log

+

log/rose-conf/<time>-run.conf

log/config/<time>-rose-suite.conf

log/<time>-run.version

log/version/uncommitted.diff

+

log/version/vcs.json

+

log/suiterc/<time>-run.rc

log/config/<start_number>-<type>-<file_number>.cylc

+
+
+

Other Changes

+

There are an assortment of other features implemented at Cylc 8. Some noteworthy +minor changes include:

+
+
Runahead Limit

The default runahead limit has been increased from three cycles to five.

+
+
Queues

Internal Queues are now more efficient (for the scheduler), +we now recommend using queues to restrict the number of running tasks in +situations where graphing may have been used previously.

+
+
Time Zones

[scheduler]cycle point time zone now defaults to UTC, unless you +are working in Cylc 7 Compatibility Mode.

+
+
Job Scripts

All user-defined task scripting now runs in a subshell, so you can safely +switch Python environments inside tasks without affecting Cylc. +Further information is available in the User Guide: Job Scripts.

+
+
Packaging

Cylc 8 (and its package dependencies) is now available from Conda Forge and PyPI +for installations into a Python 3 virtual environment.

+
+
Remote usernames

If usernames differ on remote job hosts they must now be configured using +an SSH config file rather than the via Cylc 7 [remote]owner configuration. +See Remote Usernames.

+
+
+
+
+ + +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_images/analysis_view.gif b/nightly_8.3/html/_images/analysis_view.gif new file mode 100644 index 0000000000..c54b5c6d43 Binary files /dev/null and b/nightly_8.3/html/_images/analysis_view.gif differ diff --git a/nightly_8.3/html/_images/conditional-triggers.png b/nightly_8.3/html/_images/conditional-triggers.png new file mode 100644 index 0000000000..96b2af67c6 Binary files /dev/null and b/nightly_8.3/html/_images/conditional-triggers.png differ diff --git a/nightly_8.3/html/_images/cycling.png b/nightly_8.3/html/_images/cycling.png new file mode 100644 index 0000000000..b7be9a34c5 Binary files /dev/null and b/nightly_8.3/html/_images/cycling.png differ diff --git a/nightly_8.3/html/_images/cylc-completion.bash.gif b/nightly_8.3/html/_images/cylc-completion.bash.gif new file mode 100644 index 0000000000..5477aa9f42 Binary files /dev/null and b/nightly_8.3/html/_images/cylc-completion.bash.gif differ diff --git a/nightly_8.3/html/_images/cylc-graph-group-by-cycle-point.png b/nightly_8.3/html/_images/cylc-graph-group-by-cycle-point.png new file mode 100644 index 0000000000..518537b349 Binary files /dev/null and b/nightly_8.3/html/_images/cylc-graph-group-by-cycle-point.png differ diff --git a/nightly_8.3/html/_images/cylc-graph-reversible.svg b/nightly_8.3/html/_images/cylc-graph-reversible.svg new file mode 100644 index 0000000000..72327dafef --- /dev/null +++ b/nightly_8.3/html/_images/cylc-graph-reversible.svg @@ -0,0 +1,77 @@ + + + + + + +_anonymous_0 +cluster_1 + + +cluster_2 + + + +1/foo + +foo + + +1/baz + +baz + + +1/foo->1/baz + + + + +1/bar + +bar + + +1/bar->1/baz + + + + +2/bar + +bar + + +2/baz + +baz + + +2/foo->2/baz + + + + +2/foo + +foo + + +2/bar->2/baz + + + + + diff --git a/nightly_8.3/html/_images/cylc-graph.gif b/nightly_8.3/html/_images/cylc-graph.gif new file mode 100644 index 0000000000..733b6e9208 Binary files /dev/null and b/nightly_8.3/html/_images/cylc-graph.gif differ diff --git a/nightly_8.3/html/_images/cylc-graph.png b/nightly_8.3/html/_images/cylc-graph.png new file mode 100644 index 0000000000..4e10870075 Binary files /dev/null and b/nightly_8.3/html/_images/cylc-graph.png differ diff --git a/nightly_8.3/html/_images/cylc-gui-scan-view.png b/nightly_8.3/html/_images/cylc-gui-scan-view.png new file mode 100644 index 0000000000..8b33785cdb Binary files /dev/null and b/nightly_8.3/html/_images/cylc-gui-scan-view.png differ diff --git a/nightly_8.3/html/_images/cylc-gui-table-view.png b/nightly_8.3/html/_images/cylc-gui-table-view.png new file mode 100644 index 0000000000..6c237d76a3 Binary files /dev/null and b/nightly_8.3/html/_images/cylc-gui-table-view.png differ diff --git a/nightly_8.3/html/_images/cylc-gui-tree-view.png b/nightly_8.3/html/_images/cylc-gui-tree-view.png new file mode 100644 index 0000000000..7df1c4d49b Binary files /dev/null and b/nightly_8.3/html/_images/cylc-gui-tree-view.png differ diff --git a/nightly_8.3/html/_images/cylc-gui-views-button.png b/nightly_8.3/html/_images/cylc-gui-views-button.png new file mode 100644 index 0000000000..1cd741543c Binary files /dev/null and b/nightly_8.3/html/_images/cylc-gui-views-button.png differ diff --git a/nightly_8.3/html/_images/cylc-set-outputs.gif b/nightly_8.3/html/_images/cylc-set-outputs.gif new file mode 100644 index 0000000000..a731371ae9 Binary files /dev/null and b/nightly_8.3/html/_images/cylc-set-outputs.gif differ diff --git a/nightly_8.3/html/_images/cylc-set.gif b/nightly_8.3/html/_images/cylc-set.gif new file mode 100644 index 0000000000..9ab94c7473 Binary files /dev/null and b/nightly_8.3/html/_images/cylc-set.gif differ diff --git a/nightly_8.3/html/_images/cylc-tools.png b/nightly_8.3/html/_images/cylc-tools.png new file mode 100644 index 0000000000..298445dff3 Binary files /dev/null and b/nightly_8.3/html/_images/cylc-tools.png differ diff --git a/nightly_8.3/html/_images/cylc-ui-dash.png b/nightly_8.3/html/_images/cylc-ui-dash.png new file mode 100644 index 0000000000..81bd5c6c90 Binary files /dev/null and b/nightly_8.3/html/_images/cylc-ui-dash.png differ diff --git a/nightly_8.3/html/_images/cylc-ui-tree.png b/nightly_8.3/html/_images/cylc-ui-tree.png new file mode 100644 index 0000000000..11c5d9f58a Binary files /dev/null and b/nightly_8.3/html/_images/cylc-ui-tree.png differ diff --git a/nightly_8.3/html/_images/edit-a-tasks-configuration.gui.gif b/nightly_8.3/html/_images/edit-a-tasks-configuration.gui.gif new file mode 100644 index 0000000000..e9df3a18b2 Binary files /dev/null and b/nightly_8.3/html/_images/edit-a-tasks-configuration.gui.gif differ diff --git a/nightly_8.3/html/_images/edit-runtime-screenshot.png b/nightly_8.3/html/_images/edit-runtime-screenshot.png new file mode 100644 index 0000000000..264b0f5f9e Binary files /dev/null and b/nightly_8.3/html/_images/edit-runtime-screenshot.png differ diff --git a/nightly_8.3/html/_images/edit-the-workflow-configuration.tui.gif b/nightly_8.3/html/_images/edit-the-workflow-configuration.tui.gif new file mode 100644 index 0000000000..77b27980d3 Binary files /dev/null and b/nightly_8.3/html/_images/edit-the-workflow-configuration.tui.gif differ diff --git a/nightly_8.3/html/_images/eg2-dynamic.png b/nightly_8.3/html/_images/eg2-dynamic.png new file mode 100644 index 0000000000..34a8eb0580 Binary files /dev/null and b/nightly_8.3/html/_images/eg2-dynamic.png differ diff --git a/nightly_8.3/html/_images/eg2-static.png b/nightly_8.3/html/_images/eg2-static.png new file mode 100644 index 0000000000..4bd6087ada Binary files /dev/null and b/nightly_8.3/html/_images/eg2-static.png differ diff --git a/nightly_8.3/html/_images/failure-recovery.png b/nightly_8.3/html/_images/failure-recovery.png new file mode 100644 index 0000000000..625a11bd3c Binary files /dev/null and b/nightly_8.3/html/_images/failure-recovery.png differ diff --git a/nightly_8.3/html/_images/fam-to-fam-1.png b/nightly_8.3/html/_images/fam-to-fam-1.png new file mode 100644 index 0000000000..e263198d12 Binary files /dev/null and b/nightly_8.3/html/_images/fam-to-fam-1.png differ diff --git a/nightly_8.3/html/_images/fam-to-fam-2.png b/nightly_8.3/html/_images/fam-to-fam-2.png new file mode 100644 index 0000000000..a0c2b97b3b Binary files /dev/null and b/nightly_8.3/html/_images/fam-to-fam-2.png differ diff --git a/nightly_8.3/html/_images/gantt_view.png b/nightly_8.3/html/_images/gantt_view.png new file mode 100644 index 0000000000..454167a24f Binary files /dev/null and b/nightly_8.3/html/_images/gantt_view.png differ diff --git a/nightly_8.3/html/_images/graphviz-01cdfbbf3d7a8a7da6b86824adc2682acb58bc7c.svg b/nightly_8.3/html/_images/graphviz-01cdfbbf3d7a8a7da6b86824adc2682acb58bc7c.svg new file mode 100644 index 0000000000..6a50170903 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-01cdfbbf3d7a8a7da6b86824adc2682acb58bc7c.svg @@ -0,0 +1,244 @@ + + + + + + +example + + +cluster_1 + +1 + + +cluster_2 + +2 + + +cluster_3 + +3 + + + +1/pur + +buy_ingredients +1 + + + +1/mak + +make_dough +1 + + + +1/pur->1/mak + + + + + +1/bak + +bake_bread +1 + + + +1/mak->1/bak + + + + + +1/sel + +sell_bread +1 + + + +1/bak->1/sel + + + + + +1/cle + +clean_oven +1 + + + +1/bak->1/cle + + + + + +1/pre + +pre_heat_oven +1 + + + +1/pre->1/bak + + + + + +2/pur + +buy_ingredients +2 + + + +2/mak + +make_dough +2 + + + +2/pur->2/mak + + + + + +2/bak + +bake_bread +2 + + + +2/mak->2/bak + + + + + +2/sel + +sell_bread +2 + + + +2/bak->2/sel + + + + + +2/cle + +clean_oven +2 + + + +2/bak->2/cle + + + + + +2/pre + +pre_heat_oven +2 + + + +2/pre->2/bak + + + + + +3/pur + +buy_ingredients +3 + + + +3/mak + +make_dough +3 + + + +3/pur->3/mak + + + + + +3/bak + +bake_bread +3 + + + +3/mak->3/bak + + + + + +3/sel + +sell_bread +3 + + + +3/bak->3/sel + + + + + +3/cle + +clean_oven +3 + + + +3/bak->3/cle + + + + + +3/pre + +pre_heat_oven +3 + + + +3/pre->3/bak + + + + + diff --git a/nightly_8.3/html/_images/graphviz-0b0909ede98c7ce9e0a52dfc78d5a8fb69f0abb9.svg b/nightly_8.3/html/_images/graphviz-0b0909ede98c7ce9e0a52dfc78d5a8fb69f0abb9.svg new file mode 100644 index 0000000000..8dd48cfe61 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-0b0909ede98c7ce9e0a52dfc78d5a8fb69f0abb9.svg @@ -0,0 +1,55 @@ + + + + + + +Example + + + +ENGINE + +ENGINE + + + +TURBINE_ENGINE + +TURBINE_ENGINE + + + +ENGINE->TURBINE_ENGINE + + + + + +INTERNAL_COMBUSTION_ENGINE + +INTERNAL_COMBUSTION_ENGINE + + + +ENGINE->INTERNAL_COMBUSTION_ENGINE + + + + + +HUMAN_ENGINE + +HUMAN_ENGINE + + + +ENGINE->HUMAN_ENGINE + + + + + diff --git a/nightly_8.3/html/_images/graphviz-0bee4c9c9c742616fb232cb9cddb1033b1add029.svg b/nightly_8.3/html/_images/graphviz-0bee4c9c9c742616fb232cb9cddb1033b1add029.svg new file mode 100644 index 0000000000..941d6982b9 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-0bee4c9c9c742616fb232cb9cddb1033b1add029.svg @@ -0,0 +1,115 @@ + + + + + + +Example + + + +VEHICLE + +VEHICLE + + + +AIR_VEHICLE + +AIR_VEHICLE + + + +VEHICLE->AIR_VEHICLE + + + + + +LAND_VEHICLE + +LAND_VEHICLE + + + +VEHICLE->LAND_VEHICLE + + + + + +WATER_VEHICLE + +WATER_VEHICLE + + + +VEHICLE->WATER_VEHICLE + + + + + +HOVERCRAFT + +HOVERCRAFT + + + +AIR_VEHICLE->HOVERCRAFT + + + + + +LAND_VEHICLE->HOVERCRAFT + + + + + +WATER_VEHICLE->HOVERCRAFT + + + + + +bht130 + +bht130 + + + +HOVERCRAFT->bht130 + + + + + +ENGINE + +ENGINE + + + +INTERNAL_COMBUSTION_ENGINE + +INTERNAL_COMBUSTION_ENGINE + + + +ENGINE->INTERNAL_COMBUSTION_ENGINE + + + + + +INTERNAL_COMBUSTION_ENGINE->bht130 + + + + + diff --git a/nightly_8.3/html/_images/graphviz-194935d8af5bcb677dda98ebd876694ee5c3f272.svg b/nightly_8.3/html/_images/graphviz-194935d8af5bcb677dda98ebd876694ee5c3f272.svg new file mode 100644 index 0000000000..dbb4d4e2c2 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-194935d8af5bcb677dda98ebd876694ee5c3f272.svg @@ -0,0 +1,31 @@ + + + + + + +Mini_Cylc + + + +make_dough + +make_dough + + + +buy_ingredients + +buy_ingredients + + + +buy_ingredients->make_dough + + + + + diff --git a/nightly_8.3/html/_images/graphviz-2177d3d933cdc16287d883a6c7ec5a4c5e8ed10b.svg b/nightly_8.3/html/_images/graphviz-2177d3d933cdc16287d883a6c7ec5a4c5e8ed10b.svg new file mode 100644 index 0000000000..964ce86ce2 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-2177d3d933cdc16287d883a6c7ec5a4c5e8ed10b.svg @@ -0,0 +1,54 @@ + + + + + + +Example + + +cluster_1 + +:fail + + + +recover + +recover + + + +bar + +bar + + + +recover->bar + + + + + +foo + +foo + + + +foo->recover + + + + + +foo->bar + + + + + diff --git a/nightly_8.3/html/_images/graphviz-309a6f1074f1f753764c56c9f6c29577d957299a.svg b/nightly_8.3/html/_images/graphviz-309a6f1074f1f753764c56c9f6c29577d957299a.svg new file mode 100644 index 0000000000..38a03c742d --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-309a6f1074f1f753764c56c9f6c29577d957299a.svg @@ -0,0 +1,141 @@ + + + + + + +example + + +cluster_legend + +Legend + + +cluster_diagram + + +cluster_subshell + +Subshell process + + + +user defined script + +user defined script + + + +cylc defined script + +cylc defined script + + + + +cylc-env + +cylc-env + + + +env-script + +env-script + + + +cylc-env->env-script + + + + + +user-env + +user-env + + + +pre-script + +pre-script + + + +user-env->pre-script + + + + + +init-script + +init-script + + + +init-script->cylc-env + + + + + +env-script->user-env + + + + + +script + +script + + + +pre-script->script + + + + + +post-script + +post-script + + + +script->post-script + + + + + +err-script + +err-script + + + +post-script->err-script + + + + + +exit-script + +exit-script + + + +post-script->exit-script + + + + + diff --git a/nightly_8.3/html/_images/graphviz-3cc27ffde90900b8d8bd3e50af7f154fa0d61474.svg b/nightly_8.3/html/_images/graphviz-3cc27ffde90900b8d8bd3e50af7f154fa0d61474.svg new file mode 100644 index 0000000000..6c4f9ca942 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-3cc27ffde90900b8d8bd3e50af7f154fa0d61474.svg @@ -0,0 +1,79 @@ + + + + + + +Mini_Cylc + + + +f + +f + + + +b + +b + + + +d + +d + + + +b->d + + + + + +c + +c + + + +b->c + + + + + +d->f + + + + + +e + +e + + + +e->f + + + + + +a + +a + + + +a->b + + + + + diff --git a/nightly_8.3/html/_images/graphviz-49ba9b997629895dcb4de0b35f149b3287affd13.svg b/nightly_8.3/html/_images/graphviz-49ba9b997629895dcb4de0b35f149b3287affd13.svg new file mode 100644 index 0000000000..d525e5d624 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-49ba9b997629895dcb4de0b35f149b3287affd13.svg @@ -0,0 +1,83 @@ + + + + + + +example + + +cluster_success + +:succeed + + +cluster_failure + +:fail + + + +c + +c + + + +d + +d + + + +c->d + + + + + +r + +r + + + +r->d + + + + + +a + +a + + + +b + +b + + + +a->b + + + + + +b->c + + + + + +b->r + + + + + diff --git a/nightly_8.3/html/_images/graphviz-59cbd426cb6d31a781562ad157e7ba086e2941ed.svg b/nightly_8.3/html/_images/graphviz-59cbd426cb6d31a781562ad157e7ba086e2941ed.svg new file mode 100644 index 0000000000..565a925736 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-59cbd426cb6d31a781562ad157e7ba086e2941ed.svg @@ -0,0 +1,67 @@ + + + + + + +Mini_Cylc + + + +bar_m1 + +bar_m1 + + + +baz_m1 + +baz_m1 + + + +bar_m1->baz_m1 + + + + + +bar_m3 + +bar_m3 + + + +baz_m3 + +baz_m3 + + + +bar_m3->baz_m3 + + + + + +bar_m2 + +bar_m2 + + + +baz_m2 + +baz_m2 + + + +bar_m2->baz_m2 + + + + + diff --git a/nightly_8.3/html/_images/graphviz-5bcc0ec6c89032b0219d6542b92a01a9ebb98158.svg b/nightly_8.3/html/_images/graphviz-5bcc0ec6c89032b0219d6542b92a01a9ebb98158.svg new file mode 100644 index 0000000000..d72568a3c7 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-5bcc0ec6c89032b0219d6542b92a01a9ebb98158.svg @@ -0,0 +1,71 @@ + + + + + + +example + + + +get_observations_aldergrove + +get_observations_aldergrove + + + +consolidate_observations + +consolidate_observations + + + +get_observations_aldergrove->consolidate_observations + + + + + + + +get_observations_camborne + +get_observations_camborne + + + +get_observations_camborne->consolidate_observations + + + + + + +get_observations_heathrow + +get_observations_heathrow + + + +get_observations_heathrow->consolidate_observations + + + + + +get_observations_shetland + +get_observations_shetland + + + +get_observations_shetland->consolidate_observations + + + + + + diff --git a/nightly_8.3/html/_images/graphviz-6437cd2c62395d4695c4220027574b1021f6efbb.svg b/nightly_8.3/html/_images/graphviz-6437cd2c62395d4695c4220027574b1021f6efbb.svg new file mode 100644 index 0000000000..0c044b18fc --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-6437cd2c62395d4695c4220027574b1021f6efbb.svg @@ -0,0 +1,46 @@ + + + + + + +Example + + + +1/foo + +foo +2000-01-01T12 + + + +2/foo + +foo +2000-01-02T12 + + + +1/foo->2/foo + + + + + +3/foo + +foo +2000-01-03T12 + + + +2/foo->3/foo + + + + + diff --git a/nightly_8.3/html/_images/graphviz-65d4dbac5a6d4914d2c419d6ab0e28a1fdf0a091.svg b/nightly_8.3/html/_images/graphviz-65d4dbac5a6d4914d2c419d6ab0e28a1fdf0a091.svg new file mode 100644 index 0000000000..5a1c564c23 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-65d4dbac5a6d4914d2c419d6ab0e28a1fdf0a091.svg @@ -0,0 +1,271 @@ + + + + + + +Example + + + +root + +root + + + +ENGINE + +ENGINE + + + +root->ENGINE + + + + + +VEHICLE + +VEHICLE + + + +root->VEHICLE + + + + + +INTERNAL_COMBUSTION_ENGINE + +INTERNAL_COMBUSTION_ENGINE + + + +ENGINE->INTERNAL_COMBUSTION_ENGINE + + + + + +TURBINE_ENGINE + +TURBINE_ENGINE + + + +ENGINE->TURBINE_ENGINE + + + + + +HUMAN_ENGINE + +HUMAN_ENGINE + + + +ENGINE->HUMAN_ENGINE + + + + + +LAND_VEHICLE + +LAND_VEHICLE + + + +VEHICLE->LAND_VEHICLE + + + + + +WATER_VEHICLE + +WATER_VEHICLE + + + +VEHICLE->WATER_VEHICLE + + + + + +AIR_VEHICLE + +AIR_VEHICLE + + + +VEHICLE->AIR_VEHICLE + + + + + +r44 + +r44 + + + +INTERNAL_COMBUSTION_ENGINE->r44 + + + + + +bht130 + +bht130 + + + +INTERNAL_COMBUSTION_ENGINE->bht130 + + + + + +v22 + +v22 + + + +TURBINE_ENGINE->v22 + + + + + +a380 + +a380 + + + +TURBINE_ENGINE->a380 + + + + + +penny_farthing + +penny_farthing + + + +HUMAN_ENGINE->penny_farthing + + + + + +HOVERCRAFT + +HOVERCRAFT + + + +LAND_VEHICLE->HOVERCRAFT + + + + + +BICYCLE + +BICYCLE + + + +LAND_VEHICLE->BICYCLE + + + + + +WATER_VEHICLE->HOVERCRAFT + + + + + +AIRPLANE + +AIRPLANE + + + +AIR_VEHICLE->AIRPLANE + + + + + +HELICOPTER + +HELICOPTER + + + +AIR_VEHICLE->HELICOPTER + + + + + +AIR_VEHICLE->HOVERCRAFT + + + + + +AIRPLANE->v22 + + + + + +AIRPLANE->a380 + + + + + +HELICOPTER->r44 + + + + + +HELICOPTER->v22 + + + + + +HOVERCRAFT->bht130 + + + + + +BICYCLE->penny_farthing + + + + + diff --git a/nightly_8.3/html/_images/graphviz-67061a0cb1a093d3d29cd2a417dc12c16a2e0b16.svg b/nightly_8.3/html/_images/graphviz-67061a0cb1a093d3d29cd2a417dc12c16a2e0b16.svg new file mode 100644 index 0000000000..6e4acb75d2 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-67061a0cb1a093d3d29cd2a417dc12c16a2e0b16.svg @@ -0,0 +1,256 @@ + + + + + + +example + + +cluster_1 + +1 + + +cluster_2 + +2 + + +cluster_3 + +3 + + + +1/pur + +buy_ingredients +1 + + + +1/mak + +make_dough +1 + + + +1/pur->1/mak + + + + + +1/bak + +bake_bread +1 + + + +1/mak->1/bak + + + + + +1/sel + +sell_bread +1 + + + +1/bak->1/sel + + + + + +1/cle + +clean_oven +1 + + + +1/bak->1/cle + + + + + +2/pre + +pre_heat_oven +2 + + + +1/cle->2/pre + + + + + +1/pre + +pre_heat_oven +1 + + + +1/pre->1/bak + + + + + +2/pur + +buy_ingredients +2 + + + +2/mak + +make_dough +2 + + + +2/pur->2/mak + + + + + +2/bak + +bake_bread +2 + + + +2/mak->2/bak + + + + + +2/sel + +sell_bread +2 + + + +2/bak->2/sel + + + + + +2/cle + +clean_oven +2 + + + +2/bak->2/cle + + + + + +3/pre + +pre_heat_oven +3 + + + +2/cle->3/pre + + + + + +2/pre->2/bak + + + + + +3/pur + +buy_ingredients +3 + + + +3/mak + +make_dough +3 + + + +3/pur->3/mak + + + + + +3/bak + +bake_bread +3 + + + +3/mak->3/bak + + + + + +3/sel + +sell_bread +3 + + + +3/bak->3/sel + + + + + +3/cle + +clean_oven +3 + + + +3/bak->3/cle + + + + + +3/pre->3/bak + + + + + diff --git a/nightly_8.3/html/_images/graphviz-82162b15e08c43cf33d6d779e1f24205d0f65641.svg b/nightly_8.3/html/_images/graphviz-82162b15e08c43cf33d6d779e1f24205d0f65641.svg new file mode 100644 index 0000000000..bbeeedda5c --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-82162b15e08c43cf33d6d779e1f24205d0f65641.svg @@ -0,0 +1,79 @@ + + + + + + +Mini_Cylc + + + +make_dough + +make_dough + + + +bake_bread + +bake_bread + + + +make_dough->bake_bread + + + + + +sell_bread + +sell_bread + + + +bake_bread->sell_bread + + + + + +clean_oven + +clean_oven + + + +bake_bread->clean_oven + + + + + +buy_ingredients + +buy_ingredients + + + +buy_ingredients->make_dough + + + + + +pre_heat_oven + +pre_heat_oven + + + +pre_heat_oven->bake_bread + + + + + diff --git a/nightly_8.3/html/_images/graphviz-89d82f78578995e979e462991b8773bd86eac8a6.svg b/nightly_8.3/html/_images/graphviz-89d82f78578995e979e462991b8773bd86eac8a6.svg new file mode 100644 index 0000000000..5731a5311a --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-89d82f78578995e979e462991b8773bd86eac8a6.svg @@ -0,0 +1,75 @@ + + + + + + +Example + + +cluster_1 + +one:failed AND two:failed + + +cluster_2 + +both tasks finished + + + +one + +one + + + +run_if_both_fail + +run_if_both_fail + + + +one->run_if_both_fail + + +:fail? + + + +always_run + +always_run + + + +one->always_run + + +:finish + + + +two + +two + + + +two->run_if_both_fail + + +:fail? + + + +two->always_run + + +:finish + + + diff --git a/nightly_8.3/html/_images/graphviz-8e0c9728aa86a233cf46544e68a49dea2fe207ab.svg b/nightly_8.3/html/_images/graphviz-8e0c9728aa86a233cf46544e68a49dea2fe207ab.svg new file mode 100644 index 0000000000..ecf8ae22d6 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-8e0c9728aa86a233cf46544e68a49dea2fe207ab.svg @@ -0,0 +1,43 @@ + + + + + + +Example + + + +foo + +foo + + + +bar + +bar + + + +foo->bar + + + + + +baz + +baz + + + +bar->baz + + + + + diff --git a/nightly_8.3/html/_images/graphviz-8e506f6bf51898e3f9d2d2af1fa383f3d3b2bcbc.svg b/nightly_8.3/html/_images/graphviz-8e506f6bf51898e3f9d2d2af1fa383f3d3b2bcbc.svg new file mode 100644 index 0000000000..40517f9826 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-8e506f6bf51898e3f9d2d2af1fa383f3d3b2bcbc.svg @@ -0,0 +1,361 @@ + + + + + + + + + +absolute_outputs + +absolute_outputs + +cycle + +name + +output + + + +broadcast_events + +broadcast_events + +time + +change + +point + +namespace + +key + +value + + + +broadcast_states + +broadcast_states + +point + +namespace + +key + +value + + + +inheritance + +inheritance + +namespace + +inheritance + + + +task_action_timers + +task_action_timers + +cycle + +name + +ctx_key + +ctx + +delays + +num + +delay + +timeout + + + +task_events + +task_events + +name + +cycle + +time + +submit_num + +event + +message + + + +task_jobs + +task_jobs + +cycle + +name + +submit_num + +flow_nums + +is_manual_submit + +try_num + +time_submit + +time_submit_exit + +submit_status + +time_run + +time_run_exit + +run_signal + +run_status + +platform_name + +job_runner_name + +job_id + + + +task_late_flags + +task_late_flags + +cycle + +name + +value + + + +task_outputs + +task_outputs + +cycle + +name + +flow_nums + +outputs + + + +task_pool + +task_pool + +cycle + +name + +flow_nums + +status + +is_held + + + +task_pool--task_action_timers + +{0,1} +0..N + + + +task_pool--task_late_flags + +{0,1} +{0,1} + + + +task_pool--task_outputs + +{0,1} +0..N + + + +task_prerequisites + +task_prerequisites + +cycle + +name + +flow_nums + +prereq_name + +prereq_cycle + +prereq_output + +satisfied + + + +task_pool--task_prerequisites + +{0,1} +0..N + + + +task_timeout_timers + +task_timeout_timers + +cycle + +name + +timeout + + + +task_pool--task_timeout_timers + +{0,1} +{0,1} + + + +task_states + +task_states + +name + +cycle + +flow_nums + +time_created + +time_updated + +submit_num + +status + +flow_wait + +is_manual_submit + + + +task_states--task_events + +{0,1} +0..N + + + +task_states--task_jobs + +{0,1} +0..N + + + +tasks_to_hold + +tasks_to_hold + +name + +cycle + + + +workflow_flows + +workflow_flows + +flow_num + +start_time + +description + + + +workflow_params + +workflow_params + +key + +value + + + +workflow_template_vars + +workflow_template_vars + +key + +value + + + +xtriggers + +xtriggers + +signature + +results + +absolute_outputs + +broadcast_events + +broadcast_states + +inheritance + +tasks_to_hold + +workflow_flows + +workflow_params + +workflow_template_vars + +xtriggers + + + diff --git a/nightly_8.3/html/_images/graphviz-8e815b3f336404aebf4c3ca5d0d776c2c9baf002.svg b/nightly_8.3/html/_images/graphviz-8e815b3f336404aebf4c3ca5d0d776c2c9baf002.svg new file mode 100644 index 0000000000..1d15b2a633 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-8e815b3f336404aebf4c3ca5d0d776c2c9baf002.svg @@ -0,0 +1,94 @@ + + + + + + +Example + + +cluster_1 + +:good + + +cluster_2 + +:bad + + +cluster_3 + +:ugly + + + +good + +good + + + +fin + +fin + + + +good->fin + + + + + +bad + +bad + + + +bad->fin + + + + + +ugly + +ugly + + + +ugly->fin + + + + + +showdown + +showdown + + + +showdown->good + + + + + +showdown->bad + + + + + +showdown->ugly + + + + + diff --git a/nightly_8.3/html/_images/graphviz-96a7dfe8255fbca2ef4621d8e1a50a80c86195c2.svg b/nightly_8.3/html/_images/graphviz-96a7dfe8255fbca2ef4621d8e1a50a80c86195c2.svg new file mode 100644 index 0000000000..e13181b05d --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-96a7dfe8255fbca2ef4621d8e1a50a80c86195c2.svg @@ -0,0 +1,66 @@ + + + + + + +Example + + +cluster_1 + +:fail + + + +recover + +recover + + + +baz + +baz + + + +recover->baz + + + + + +foo + +foo + + + +bar + +bar + + + +foo->bar + + + + + +bar->recover + + + + + +bar->baz + + + + + diff --git a/nightly_8.3/html/_images/graphviz-9726db191ee25dce5b92484f57f89135b5e17b75.svg b/nightly_8.3/html/_images/graphviz-9726db191ee25dce5b92484f57f89135b5e17b75.svg new file mode 100644 index 0000000000..3383b01ad2 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-9726db191ee25dce5b92484f57f89135b5e17b75.svg @@ -0,0 +1,61 @@ + + + + + + +example + + +cluster_T06 + +T06 + + +cluster_T12 + +T12 + + +cluster_T18 + +T18 + + + +forecast.t06 + +forecast +T06 + + + +forecast.t12 + +forecast +T12 + + + +forecast.t06->forecast.t12 + + + + + +forecast.t18 + +forecast +T18 + + + +forecast.t12->forecast.t18 + + + + + diff --git a/nightly_8.3/html/_images/graphviz-973f7a17b789c0420fc4acc3fa1d4b8e9c03b664.svg b/nightly_8.3/html/_images/graphviz-973f7a17b789c0420fc4acc3fa1d4b8e9c03b664.svg new file mode 100644 index 0000000000..992903ee09 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-973f7a17b789c0420fc4acc3fa1d4b8e9c03b664.svg @@ -0,0 +1,67 @@ + + + + + + +Example + + + +VEHICLE + +VEHICLE + + + +LAND_VEHICLE + +LAND_VEHICLE + + + +VEHICLE->LAND_VEHICLE + + + + + +BICYCLE + +BICYCLE + + + +LAND_VEHICLE->BICYCLE + + + + + +penny_farthing + +penny_farthing + + + +BICYCLE->penny_farthing + + + + + +HUMAN_ENGINE + +HUMAN_ENGINE + + + +HUMAN_ENGINE->penny_farthing + + + + + diff --git a/nightly_8.3/html/_images/graphviz-97706327755f266e946da142ff5b9c269a7417e0.svg b/nightly_8.3/html/_images/graphviz-97706327755f266e946da142ff5b9c269a7417e0.svg new file mode 100644 index 0000000000..413bfd096a --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-97706327755f266e946da142ff5b9c269a7417e0.svg @@ -0,0 +1,61 @@ + + + + + + +Example + + + +random_seed + +random_seed + + + +breed + +breed + + + +random_seed->breed + + + + + +test_fitness + +test_fitness + + + +breed->test_fitness + + + + + +test_fitness->breed + + + + + +stop + +stop + + + +test_fitness->stop + + + + + diff --git a/nightly_8.3/html/_images/graphviz-9c6c3320344b9bad792fb330e3b5a3287587062f.svg b/nightly_8.3/html/_images/graphviz-9c6c3320344b9bad792fb330e3b5a3287587062f.svg new file mode 100644 index 0000000000..db3cfdef0b --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-9c6c3320344b9bad792fb330e3b5a3287587062f.svg @@ -0,0 +1,89 @@ + + + + + + +Example + + +cluster_1 + +2000-01-01T00:00Z + + +cluster_2 + +2000-01-01T12:00Z + + +cluster_3 + +2000-01-02T00:00Z + + + +01T00/foo + +foo +2000-01-01T00:00Z + + + +01T00/bar + +bar +2000-01-01T00:00Z + + + +01T00/foo->01T00/bar + + + + + +01T00/baz + +baz +2000-01-01T00:00Z + + + +b01T12/az + +baz +2000-01-01T12:00Z + + + +02T00/foo + +foo +2000-01-02T00:00Z + + + +02T00/bar + +bar +2000-01-02T00:00Z + + + +02T00/foo->02T00/bar + + + + + +02T00/baz + +baz +2000-01-02T00:00Z + + + diff --git a/nightly_8.3/html/_images/graphviz-a02e167fd91d9a135d2030f0136dc13a230eb00f.svg b/nightly_8.3/html/_images/graphviz-a02e167fd91d9a135d2030f0136dc13a230eb00f.svg new file mode 100644 index 0000000000..784b8e9c67 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-a02e167fd91d9a135d2030f0136dc13a230eb00f.svg @@ -0,0 +1,46 @@ + + + + + + +Example + + + +1/foo + +foo +2000-01-01T00 + + + +2/foo + +foo +2000-01-02T00 + + + +1/foo->2/foo + + + + + +3/foo + +foo +2000-01-03T00 + + + +2/foo->3/foo + + + + + diff --git a/nightly_8.3/html/_images/graphviz-a0b983d4be5182e8e12f4aacfcc75c2683db3c40.svg b/nightly_8.3/html/_images/graphviz-a0b983d4be5182e8e12f4aacfcc75c2683db3c40.svg new file mode 100644 index 0000000000..8144bc373c --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-a0b983d4be5182e8e12f4aacfcc75c2683db3c40.svg @@ -0,0 +1,139 @@ + + + + + + +Example + + +cluster_1 + +1 + + +cluster_2 + +2 + + +cluster_3 + +3 + + + +1/foo + +foo +1 + + + +1/bar + +bar +1 + + + +1/foo->1/bar + + + + + +1/baz + +baz +1 + + + +1/bar->1/baz + + + + + +2/bar + +bar +2 + + + +1/bar->2/bar + + + + + +2/foo + +foo +2 + + + +2/foo->2/bar + + + + + +2/baz + +baz +2 + + + +2/bar->2/baz + + + + + +3/bar + +bar +3 + + + +2/bar->3/bar + + + + + +3/foo + +foo +3 + + + +3/foo->3/bar + + + + + +3/baz + +baz +3 + + + +3/bar->3/baz + + + + + diff --git a/nightly_8.3/html/_images/graphviz-a8b1e9e93fab74bdbf93d1612a22c4eef701651d.svg b/nightly_8.3/html/_images/graphviz-a8b1e9e93fab74bdbf93d1612a22c4eef701651d.svg new file mode 100644 index 0000000000..d525e5d624 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-a8b1e9e93fab74bdbf93d1612a22c4eef701651d.svg @@ -0,0 +1,83 @@ + + + + + + +example + + +cluster_success + +:succeed + + +cluster_failure + +:fail + + + +c + +c + + + +d + +d + + + +c->d + + + + + +r + +r + + + +r->d + + + + + +a + +a + + + +b + +b + + + +a->b + + + + + +b->c + + + + + +b->r + + + + + diff --git a/nightly_8.3/html/_images/graphviz-aca8d285197e57a400e199c11a8dce9f5229b6a0.svg b/nightly_8.3/html/_images/graphviz-aca8d285197e57a400e199c11a8dce9f5229b6a0.svg new file mode 100644 index 0000000000..3732efbe63 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-aca8d285197e57a400e199c11a8dce9f5229b6a0.svg @@ -0,0 +1,255 @@ + + + + + + +example + + +cluster_1 + +1 + + +cluster_2 + +2 + + +cluster_3 + +3 + + + +1/a + +a +1 + + + +1/b + +b +1 + + + +1/a->1/b + + + + + +1/d + +d +1 + + + +1/b->1/d + + + + + +1/f + +f +1 + + + +1/b->1/f + + + + + +1/e + +e +1 + + + +1/d->1/e + + + + + +2/c + +c +2 + + + +1/f->2/c + + + + + +1/c + +c +1 + + + +1/c->1/b + + + + + +2/a + +a +2 + + + +1/e->2/a + + + + + +2/b + +b +2 + + + +2/a->2/b + + + + + +2/d + +d +2 + + + +2/b->2/d + + + + + +2/f + +f +2 + + + +2/b->2/f + + + + + +3/a + +a +3 + + + +2/d->3/a + + + + + +3/c + +c +3 + + + +2/f->3/c + + + + + +2/c->2/b + + + + + +3/b + +b +3 + + + +3/a->3/b + + + + + +3/d + +d +3 + + + +3/b->3/d + + + + + +3/f + +f +3 + + + +3/b->3/f + + + + + +3/e + +e +3 + + + +3/d->3/e + + + + + +3/c->3/b + + + + + diff --git a/nightly_8.3/html/_images/graphviz-b280465dc5ff0105af7f02b917256ecf1a7e9c85.svg b/nightly_8.3/html/_images/graphviz-b280465dc5ff0105af7f02b917256ecf1a7e9c85.svg new file mode 100644 index 0000000000..157281b96b --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-b280465dc5ff0105af7f02b917256ecf1a7e9c85.svg @@ -0,0 +1,79 @@ + + + + + + +bakery + + + +purchase ingredients + +purchase ingredients + + + +make dough + +make dough + + + +purchase ingredients->make dough + + + + + +bake bread + +bake bread + + + +make dough->bake bread + + + + + +sell bread + +sell bread + + + +bake bread->sell bread + + + + + +clean oven + +clean oven + + + +bake bread->clean oven + + + + + +pre-heat oven + +pre-heat oven + + + +pre-heat oven->bake bread + + + + + diff --git a/nightly_8.3/html/_images/graphviz-b850ea169f58a15feb1d5b7b3a2b593602948b1e.svg b/nightly_8.3/html/_images/graphviz-b850ea169f58a15feb1d5b7b3a2b593602948b1e.svg new file mode 100644 index 0000000000..84edd71d7d --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-b850ea169f58a15feb1d5b7b3a2b593602948b1e.svg @@ -0,0 +1,91 @@ + + + + + + +Example + + + +AIRPLANE + +AIRPLANE + + + +a380 + +a380 + + + +AIRPLANE->a380 + + + + + +HELICOPTER + +HELICOPTER + + + +r44 + +r44 + + + +HELICOPTER->r44 + + + + + +root + +root + + + +VEHICLE + +VEHICLE + + + +root->VEHICLE + + + + + +AIR_VEHICLE + +AIR_VEHICLE + + + +VEHICLE->AIR_VEHICLE + + + + + +AIR_VEHICLE->AIRPLANE + + + + + +AIR_VEHICLE->HELICOPTER + + + + + diff --git a/nightly_8.3/html/_images/graphviz-bbc033dc2abc4e5b314270dae1e5c178111a46e8.svg b/nightly_8.3/html/_images/graphviz-bbc033dc2abc4e5b314270dae1e5c178111a46e8.svg new file mode 100644 index 0000000000..e3ec57224b --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-bbc033dc2abc4e5b314270dae1e5c178111a46e8.svg @@ -0,0 +1,63 @@ + + + + + + +_ + + + +Jobs + +Jobs + + + +Scheduler + +Scheduler + + + +Jobs->Scheduler + + + ZMQ + GraphQL + (default) + + + +UIS + +UIS + + + +Scheduler->UIS + + + ZMQ + GraphQL (control) + Protobuf (data) + + + +UI + +UI + + + +UIS->UI + + + Websocket + GraphQL + + + diff --git a/nightly_8.3/html/_images/graphviz-d5181c18b29b889a1db79d16a30c45bed288b3d9.svg b/nightly_8.3/html/_images/graphviz-d5181c18b29b889a1db79d16a30c45bed288b3d9.svg new file mode 100644 index 0000000000..90fbd5e95c --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-d5181c18b29b889a1db79d16a30c45bed288b3d9.svg @@ -0,0 +1,79 @@ + + + + + + +graph_tutorial + + + +a + +a + + + +b + +b + + + +a->b + + + + + +d + +d + + + +b->d + + + + + +f + +f + + + +b->f + + + + + +e + +e + + + +d->e + + + + + +c + +c + + + +c->b + + + + + diff --git a/nightly_8.3/html/_images/graphviz-e0054d6b31d1071b99e7fe278d0ac5efbadd46a8.svg b/nightly_8.3/html/_images/graphviz-e0054d6b31d1071b99e7fe278d0ac5efbadd46a8.svg new file mode 100644 index 0000000000..b6ff0945f1 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-e0054d6b31d1071b99e7fe278d0ac5efbadd46a8.svg @@ -0,0 +1,351 @@ + + + + + + +example + + +cluster_1 + +1 + + +cluster_2 + +2 + + +cluster_3 + +3 + + +cluster_4 + +4 + + + +1/pur + +buy_ingredients +1 + + + +1/mak + +make_dough +1 + + + +1/pur->1/mak + + + + + +1/bak + +bake_bread +1 + + + +1/mak->1/bak + + + + + +1/sel + +sell_bread +1 + + + +1/bak->1/sel + + + + + +1/cle + +clean_oven +1 + + + +1/bak->1/cle + + + + + +3/pur + +buy_ingredients +3 + + + +1/sel->3/pur + + + + + +2/pre + +pre_heat_oven +2 + + + +1/cle->2/pre + + + + + +1/pre + +pre_heat_oven +1 + + + +1/pre->1/bak + + + + + +2/pur + +buy_ingredients +2 + + + +2/mak + +make_dough +2 + + + +2/pur->2/mak + + + + + +2/bak + +bake_bread +2 + + + +2/mak->2/bak + + + + + +2/sel + +sell_bread +2 + + + +2/bak->2/sel + + + + + +2/cle + +clean_oven +2 + + + +2/bak->2/cle + + + + + +4/pur + +buy_ingredients +4 + + + +2/sel->4/pur + + + + + +3/pre + +pre_heat_oven +3 + + + +2/cle->3/pre + + + + + +2/pre->2/bak + + + + + +3/mak + +make_dough +3 + + + +3/pur->3/mak + + + + + +3/bak + +bake_bread +3 + + + +3/mak->3/bak + + + + + +3/sel + +sell_bread +3 + + + +3/bak->3/sel + + + + + +3/cle + +clean_oven +3 + + + +3/bak->3/cle + + + + + +4/pre + +pre_heat_oven +4 + + + +3/cle->4/pre + + + + + +3/pre->3/bak + + + + + +4/mak + +make_dough +4 + + + +4/pur->4/mak + + + + + +4/bak + +bake_bread +4 + + + +4/mak->4/bak + + + + + +4/sel + +sell_bread +4 + + + +4/bak->4/sel + + + + + +4/cle + +clean_oven +4 + + + +4/bak->4/cle + + + + + +4/pre->4/bak + + + + + diff --git a/nightly_8.3/html/_images/graphviz-e01d8ef2fe4bb77eae144c568ae38f16a0cdd8dc.svg b/nightly_8.3/html/_images/graphviz-e01d8ef2fe4bb77eae144c568ae38f16a0cdd8dc.svg new file mode 100644 index 0000000000..e62d1ff032 --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-e01d8ef2fe4bb77eae144c568ae38f16a0cdd8dc.svg @@ -0,0 +1,55 @@ + + + + + + +Mini_Cylc + + + +bake_bread + +bake_bread + + + +sell_bread + +sell_bread + + + +bake_bread->sell_bread + + + + + +make_dough + +make_dough + + + +make_dough->bake_bread + + + + + +buy_ingredients + +buy_ingredients + + + +buy_ingredients->make_dough + + + + + diff --git a/nightly_8.3/html/_images/graphviz-f6aacb832331612a9543a5f40d8dc8da04c9400d.svg b/nightly_8.3/html/_images/graphviz-f6aacb832331612a9543a5f40d8dc8da04c9400d.svg new file mode 100644 index 0000000000..2d0513cedd --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-f6aacb832331612a9543a5f40d8dc8da04c9400d.svg @@ -0,0 +1,31 @@ + + + + + + +example + + + +forecast + +forecast + + + +post_process_exeter + +post_process_exeter + + + +forecast->post_process_exeter + + + + + diff --git a/nightly_8.3/html/_images/graphviz-fd21ff6d92366e729e6e7bc9abd416eee88993a1.svg b/nightly_8.3/html/_images/graphviz-fd21ff6d92366e729e6e7bc9abd416eee88993a1.svg new file mode 100644 index 0000000000..0fcf26389e --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-fd21ff6d92366e729e6e7bc9abd416eee88993a1.svg @@ -0,0 +1,87 @@ + + + + + + +example + + +cluster_T00 + ++PT0H + + +cluster_T03 + ++PT3H + + +cluster_T06 + ++PT6H + + + +observations.t00 + +consolidate observations ++PT0H + + + +forecast.t06 + +forecast ++PT6H + + + +observations.t00->forecast.t06 + + + + + +observations.t03 + +consolidate observations ++PT3H + + + +observations.t03->forecast.t06 + + + + + +get_rainfall.t06 + +get_rainfall ++PT6H + + + +get_rainfall.t06->forecast.t06 + + + + + +observations.t06 + +consolidate observations ++PT6H + + + +observations.t06->forecast.t06 + + + + + diff --git a/nightly_8.3/html/_images/graphviz-fe358295b739cfd9b1c6fb67e74ce961621f9cd7.svg b/nightly_8.3/html/_images/graphviz-fe358295b739cfd9b1c6fb67e74ce961621f9cd7.svg new file mode 100644 index 0000000000..2bedb3d96d --- /dev/null +++ b/nightly_8.3/html/_images/graphviz-fe358295b739cfd9b1c6fb67e74ce961621f9cd7.svg @@ -0,0 +1,109 @@ + + + + + + +Example + + + +AIRPLANE + +AIRPLANE + + + +v22 + +v22 + + + +AIRPLANE->v22 + + + + + +a380 + +a380 + + + +AIRPLANE->a380 + + + + + +HELICOPTER + +HELICOPTER + + + +HELICOPTER->v22 + + + + + +r44 + +r44 + + + +HELICOPTER->r44 + + + + + +root + +root + + + +VEHICLE + +VEHICLE + + + +root->VEHICLE + + + + + +AIR_VEHICLE + +AIR_VEHICLE + + + +VEHICLE->AIR_VEHICLE + + + + + +AIR_VEHICLE->AIRPLANE + + + + + +AIR_VEHICLE->HELICOPTER + + + + + diff --git a/nightly_8.3/html/_images/gui-arch-multi-user.svg b/nightly_8.3/html/_images/gui-arch-multi-user.svg new file mode 100644 index 0000000000..71dea933f0 --- /dev/null +++ b/nightly_8.3/html/_images/gui-arch-multi-user.svg @@ -0,0 +1,2568 @@ + + + + + + + + + + image/svg+xml + + + + + + + + z + + + + + + + + + + + https://<host>:port?token + + + + + + Browser + + + + + + + + + + + + + + + + Cylc Workflow + + + + + + + + + + + + + + + + + + + + + + + + + + Cylc Jobs + + + + + + + + + #1234 + #2345 + + + + + + + + + + Cylc Workflow + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cylc Jobs + + + + + #3456 + + + User 1 + + + + + + + + + Connects + (Certificate from filesystem) + + + User Machine 1 + + + + + + + + + + Cylc Servers + + + + + + + + + + Job Platform 1 + + + + + + + + + + + + Job Platform 2 + + + + + + + + + + Submits + Updates + + + + + + + + + + + + + + + + + + + + + + + https://<host>:port?token + + + + + + Browser + + + + + + + + Jupyter Server + + + + Cylc UI Server + Jupyter Lab + Workflow data services + Workflow control services + User interface + Optionally any number ofJupyter Server extensions(e.g. Jupyter Lab) can be runwithin the same Jupyter Serverinstance as the Cylc UI Server. + + + + + + + + Token / cookie management + + + + + + + + + + Cylc Workflow + + + + + + + + + + + + + + + + + + + + + + + + + + Cylc Jobs + + + + + #4567 + + User 2 + + + Connects + (Certificate from filesystem) + + + User Machine 2 + + + + + + + + + + + Job Platform 1 + + + + + + + + + + Submits + Updates + + + + + + + + Jupyter Server + + + + Cylc UI Server + Jupyter Lab + Workflow data services + Workflow control services + User interface + Optionally any number ofJupyter Server extensions(e.g. Jupyter Lab) can be runwithin the same Jupyter Serverinstance as the Cylc UI Server. + + + + + + + + Token / cookie management + + + Jupyter Hub + + + Authenticator + Database + Spawner + Spawns + + + + + (privileged) + Spawns + + + Authenticates + + + + + Proxy + + + Configures + + + + + + Connects + + + + + Configurable-HTTP-proxy + Hub User + + + Connects + Authenticates + + + + diff --git a/nightly_8.3/html/_images/gui-arch-single-user.svg b/nightly_8.3/html/_images/gui-arch-single-user.svg new file mode 100644 index 0000000000..0bc174c8fc --- /dev/null +++ b/nightly_8.3/html/_images/gui-arch-single-user.svg @@ -0,0 +1,1469 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + Jupyter Server + + + + Cylc UI Server + Jupyter Lab + Workflow data services + Workflow control services + User interface + Optionally any number ofJupyter Server extensions(e.g. Jupyter Lab) can be runwithin the same Jupyter Serverinstance as the Cylc UI Server. + + + + > + + CLI + + + + https://<host>:port?token + + + + + + Browser + + + + + + + + + + + + + + + Authentication services + Token / cookie management + + + + + + + + + + Cylc Workflow + + + + + + + + + + + + + + + + + + + + + + + + + + Cylc Jobs + + + + + + + + + #1234 + #2345 + + + + + + + + + + Cylc Workflow + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cylc Jobs + + + + + #3456 + + + User + Spawns + + + + + Connects + (URL token) + + + + + + + + + Connects + (Certificate from filesystem) + + + + User Machine + + + + + + + + + + Cylc Servers + + + + + + + + + + Job Platform 1 + + + + + + + + + + + + Job Platform 2 + + + + + + + + + + + + + + Submits + Updates + + + + + + + + + + + + + + + + z + + diff --git a/nightly_8.3/html/_images/gui-n-window-selector.gif b/nightly_8.3/html/_images/gui-n-window-selector.gif new file mode 100644 index 0000000000..d7c54e1841 Binary files /dev/null and b/nightly_8.3/html/_images/gui-n-window-selector.gif differ diff --git a/nightly_8.3/html/_images/hub.png b/nightly_8.3/html/_images/hub.png new file mode 100644 index 0000000000..49f9511d47 Binary files /dev/null and b/nightly_8.3/html/_images/hub.png differ diff --git a/nightly_8.3/html/_images/initial-start-stop-final-cp.svg b/nightly_8.3/html/_images/initial-start-stop-final-cp.svg new file mode 100644 index 0000000000..b89348a522 --- /dev/null +++ b/nightly_8.3/html/_images/initial-start-stop-final-cp.svg @@ -0,0 +1,421 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + initial + final + start + stop + + + 1 + 2 + 3 + 4 + 5 + 6 + + 0 + P1=foo + + + tasks are scheduled in this range + the scheduler is run in this range + P2=bar + + + + + + + diff --git a/nightly_8.3/html/_images/iso8601-dates.svg b/nightly_8.3/html/_images/iso8601-dates.svg new file mode 100644 index 0000000000..83b561be6a --- /dev/null +++ b/nightly_8.3/html/_images/iso8601-dates.svg @@ -0,0 +1,265 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + 1985-04-12 + 23:20:30Z + T + Date Components + Time Components + + + + + + + + + + + Separator + Year + Month + Day + Hour + Minute + Second + Time Zone + + + diff --git a/nightly_8.3/html/_images/jinja2-ensemble-graph.png b/nightly_8.3/html/_images/jinja2-ensemble-graph.png new file mode 100644 index 0000000000..55f8fe9a1e Binary files /dev/null and b/nightly_8.3/html/_images/jinja2-ensemble-graph.png differ diff --git a/nightly_8.3/html/_images/jinja2-workflow-graph.png b/nightly_8.3/html/_images/jinja2-workflow-graph.png new file mode 100644 index 0000000000..8772afbf27 Binary files /dev/null and b/nightly_8.3/html/_images/jinja2-workflow-graph.png differ diff --git a/nightly_8.3/html/_images/job-failed.png b/nightly_8.3/html/_images/job-failed.png new file mode 100644 index 0000000000..57b42de1a4 Binary files /dev/null and b/nightly_8.3/html/_images/job-failed.png differ diff --git a/nightly_8.3/html/_images/job-running.png b/nightly_8.3/html/_images/job-running.png new file mode 100644 index 0000000000..32d08b54ac Binary files /dev/null and b/nightly_8.3/html/_images/job-running.png differ diff --git a/nightly_8.3/html/_images/job-submit-failed.png b/nightly_8.3/html/_images/job-submit-failed.png new file mode 100644 index 0000000000..1be29f8775 Binary files /dev/null and b/nightly_8.3/html/_images/job-submit-failed.png differ diff --git a/nightly_8.3/html/_images/job-submitted.png b/nightly_8.3/html/_images/job-submitted.png new file mode 100644 index 0000000000..e16aef0b6b Binary files /dev/null and b/nightly_8.3/html/_images/job-submitted.png differ diff --git a/nightly_8.3/html/_images/job-succeeded.png b/nightly_8.3/html/_images/job-succeeded.png new file mode 100644 index 0000000000..657e5c4840 Binary files /dev/null and b/nightly_8.3/html/_images/job-succeeded.png differ diff --git a/nightly_8.3/html/_images/log-view-screenshot.png b/nightly_8.3/html/_images/log-view-screenshot.png new file mode 100644 index 0000000000..1e5dac9ed6 Binary files /dev/null and b/nightly_8.3/html/_images/log-view-screenshot.png differ diff --git a/nightly_8.3/html/_images/n-window.gif b/nightly_8.3/html/_images/n-window.gif new file mode 100644 index 0000000000..351a27b47b Binary files /dev/null and b/nightly_8.3/html/_images/n-window.gif differ diff --git a/nightly_8.3/html/_images/n-window.png b/nightly_8.3/html/_images/n-window.png new file mode 100644 index 0000000000..0a98ab44ba Binary files /dev/null and b/nightly_8.3/html/_images/n-window.png differ diff --git a/nightly_8.3/html/_images/new-flow-n.png b/nightly_8.3/html/_images/new-flow-n.png new file mode 100644 index 0000000000..0f74647a32 Binary files /dev/null and b/nightly_8.3/html/_images/new-flow-n.png differ diff --git a/nightly_8.3/html/_images/no-flow-n.png b/nightly_8.3/html/_images/no-flow-n.png new file mode 100644 index 0000000000..efe0cb53ee Binary files /dev/null and b/nightly_8.3/html/_images/no-flow-n.png differ diff --git a/nightly_8.3/html/_images/param-1.png b/nightly_8.3/html/_images/param-1.png new file mode 100644 index 0000000000..6f839b0bd2 Binary files /dev/null and b/nightly_8.3/html/_images/param-1.png differ diff --git a/nightly_8.3/html/_images/param-2.png b/nightly_8.3/html/_images/param-2.png new file mode 100644 index 0000000000..5c5245176f Binary files /dev/null and b/nightly_8.3/html/_images/param-2.png differ diff --git a/nightly_8.3/html/_images/params1.png b/nightly_8.3/html/_images/params1.png new file mode 100644 index 0000000000..8ec5cd7358 Binary files /dev/null and b/nightly_8.3/html/_images/params1.png differ diff --git a/nightly_8.3/html/_images/re-run-a-task.gui.gif b/nightly_8.3/html/_images/re-run-a-task.gui.gif new file mode 100644 index 0000000000..bbc293b5e3 Binary files /dev/null and b/nightly_8.3/html/_images/re-run-a-task.gui.gif differ diff --git a/nightly_8.3/html/_images/re-run-a-task.tui.gif b/nightly_8.3/html/_images/re-run-a-task.tui.gif new file mode 100644 index 0000000000..131193792b Binary files /dev/null and b/nightly_8.3/html/_images/re-run-a-task.tui.gif differ diff --git a/nightly_8.3/html/_images/re-run-all-failed-tasks.gui.gif b/nightly_8.3/html/_images/re-run-all-failed-tasks.gui.gif new file mode 100644 index 0000000000..686cf46df3 Binary files /dev/null and b/nightly_8.3/html/_images/re-run-all-failed-tasks.gui.gif differ diff --git a/nightly_8.3/html/_images/re-run-multiple-tasks.gui.gif b/nightly_8.3/html/_images/re-run-multiple-tasks.gui.gif new file mode 100644 index 0000000000..bf6f635b61 Binary files /dev/null and b/nightly_8.3/html/_images/re-run-multiple-tasks.gui.gif differ diff --git a/nightly_8.3/html/_images/recurrence-sections.svg b/nightly_8.3/html/_images/recurrence-sections.svg new file mode 100644 index 0000000000..05d0223f23 --- /dev/null +++ b/nightly_8.3/html/_images/recurrence-sections.svg @@ -0,0 +1,416 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + 1 + + 2 + + 3 + + 4 + + 5 + + 6 + + 7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Foo + Bar + Baz + + + + + + + + diff --git a/nightly_8.3/html/_images/same-flow-behind.png b/nightly_8.3/html/_images/same-flow-behind.png new file mode 100644 index 0000000000..94de228370 Binary files /dev/null and b/nightly_8.3/html/_images/same-flow-behind.png differ diff --git a/nightly_8.3/html/_images/same-flow-n.png b/nightly_8.3/html/_images/same-flow-n.png new file mode 100644 index 0000000000..9aa0be6d2f Binary files /dev/null and b/nightly_8.3/html/_images/same-flow-n.png differ diff --git a/nightly_8.3/html/_images/same-flow-wait-n.png b/nightly_8.3/html/_images/same-flow-wait-n.png new file mode 100644 index 0000000000..b54aaa9641 Binary files /dev/null and b/nightly_8.3/html/_images/same-flow-wait-n.png differ diff --git a/nightly_8.3/html/_images/set-a-switch-task.gui.gif b/nightly_8.3/html/_images/set-a-switch-task.gui.gif new file mode 100644 index 0000000000..877d0c6065 Binary files /dev/null and b/nightly_8.3/html/_images/set-a-switch-task.gui.gif differ diff --git a/nightly_8.3/html/_images/set-and-release-hold-point.gif b/nightly_8.3/html/_images/set-and-release-hold-point.gif new file mode 100644 index 0000000000..055c679062 Binary files /dev/null and b/nightly_8.3/html/_images/set-and-release-hold-point.gif differ diff --git a/nightly_8.3/html/_images/set-task-outputs.gui.gif b/nightly_8.3/html/_images/set-task-outputs.gui.gif new file mode 100644 index 0000000000..c28ffc391c Binary files /dev/null and b/nightly_8.3/html/_images/set-task-outputs.gui.gif differ diff --git a/nightly_8.3/html/_images/set-task-outputs.tui.gif b/nightly_8.3/html/_images/set-task-outputs.tui.gif new file mode 100644 index 0000000000..2abcbb35cf Binary files /dev/null and b/nightly_8.3/html/_images/set-task-outputs.tui.gif differ diff --git a/nightly_8.3/html/_images/set-task-prerequisites.gui.gif b/nightly_8.3/html/_images/set-task-prerequisites.gui.gif new file mode 100644 index 0000000000..abe55b3c94 Binary files /dev/null and b/nightly_8.3/html/_images/set-task-prerequisites.gui.gif differ diff --git a/nightly_8.3/html/_images/task-expired.png b/nightly_8.3/html/_images/task-expired.png new file mode 100644 index 0000000000..b4344ac41b Binary files /dev/null and b/nightly_8.3/html/_images/task-expired.png differ diff --git a/nightly_8.3/html/_images/task-failed.png b/nightly_8.3/html/_images/task-failed.png new file mode 100644 index 0000000000..fb628682fb Binary files /dev/null and b/nightly_8.3/html/_images/task-failed.png differ diff --git a/nightly_8.3/html/_images/task-isHeld.png b/nightly_8.3/html/_images/task-isHeld.png new file mode 100644 index 0000000000..cd37e27c93 Binary files /dev/null and b/nightly_8.3/html/_images/task-isHeld.png differ diff --git a/nightly_8.3/html/_images/task-isQueued.png b/nightly_8.3/html/_images/task-isQueued.png new file mode 100644 index 0000000000..77f2a7fd19 Binary files /dev/null and b/nightly_8.3/html/_images/task-isQueued.png differ diff --git a/nightly_8.3/html/_images/task-isRunahead.png b/nightly_8.3/html/_images/task-isRunahead.png new file mode 100644 index 0000000000..59bdbc5f80 Binary files /dev/null and b/nightly_8.3/html/_images/task-isRunahead.png differ diff --git a/nightly_8.3/html/_images/task-job.png b/nightly_8.3/html/_images/task-job.png new file mode 100644 index 0000000000..7f79ea734e Binary files /dev/null and b/nightly_8.3/html/_images/task-job.png differ diff --git a/nightly_8.3/html/_images/task-preparing.png b/nightly_8.3/html/_images/task-preparing.png new file mode 100644 index 0000000000..e4ea5699c9 Binary files /dev/null and b/nightly_8.3/html/_images/task-preparing.png differ diff --git a/nightly_8.3/html/_images/task-running-0.png b/nightly_8.3/html/_images/task-running-0.png new file mode 100644 index 0000000000..ca51f50524 Binary files /dev/null and b/nightly_8.3/html/_images/task-running-0.png differ diff --git a/nightly_8.3/html/_images/task-running-100.png b/nightly_8.3/html/_images/task-running-100.png new file mode 100644 index 0000000000..1a2f80f1f3 Binary files /dev/null and b/nightly_8.3/html/_images/task-running-100.png differ diff --git a/nightly_8.3/html/_images/task-running-25.png b/nightly_8.3/html/_images/task-running-25.png new file mode 100644 index 0000000000..da231a1ea0 Binary files /dev/null and b/nightly_8.3/html/_images/task-running-25.png differ diff --git a/nightly_8.3/html/_images/task-running-50.png b/nightly_8.3/html/_images/task-running-50.png new file mode 100644 index 0000000000..2354d2b0d0 Binary files /dev/null and b/nightly_8.3/html/_images/task-running-50.png differ diff --git a/nightly_8.3/html/_images/task-running-75.png b/nightly_8.3/html/_images/task-running-75.png new file mode 100644 index 0000000000..0f4e332e7f Binary files /dev/null and b/nightly_8.3/html/_images/task-running-75.png differ diff --git a/nightly_8.3/html/_images/task-submit-failed.png b/nightly_8.3/html/_images/task-submit-failed.png new file mode 100644 index 0000000000..09e3e999da Binary files /dev/null and b/nightly_8.3/html/_images/task-submit-failed.png differ diff --git a/nightly_8.3/html/_images/task-submitted.png b/nightly_8.3/html/_images/task-submitted.png new file mode 100644 index 0000000000..e4ea5699c9 Binary files /dev/null and b/nightly_8.3/html/_images/task-submitted.png differ diff --git a/nightly_8.3/html/_images/task-succeeded.png b/nightly_8.3/html/_images/task-succeeded.png new file mode 100644 index 0000000000..0475116128 Binary files /dev/null and b/nightly_8.3/html/_images/task-succeeded.png differ diff --git a/nightly_8.3/html/_images/task-waiting.png b/nightly_8.3/html/_images/task-waiting.png new file mode 100644 index 0000000000..2091463332 Binary files /dev/null and b/nightly_8.3/html/_images/task-waiting.png differ diff --git a/nightly_8.3/html/_images/test1.png b/nightly_8.3/html/_images/test1.png new file mode 100644 index 0000000000..06a4bdf07f Binary files /dev/null and b/nightly_8.3/html/_images/test1.png differ diff --git a/nightly_8.3/html/_images/test2.png b/nightly_8.3/html/_images/test2.png new file mode 100644 index 0000000000..4ea60b9dd0 Binary files /dev/null and b/nightly_8.3/html/_images/test2.png differ diff --git a/nightly_8.3/html/_images/test4.png b/nightly_8.3/html/_images/test4.png new file mode 100644 index 0000000000..8cd8a9c0a2 Binary files /dev/null and b/nightly_8.3/html/_images/test4.png differ diff --git a/nightly_8.3/html/_images/test5.png b/nightly_8.3/html/_images/test5.png new file mode 100644 index 0000000000..f0940ea682 Binary files /dev/null and b/nightly_8.3/html/_images/test5.png differ diff --git a/nightly_8.3/html/_images/time_series.png b/nightly_8.3/html/_images/time_series.png new file mode 100644 index 0000000000..7c4ecbc8b6 Binary files /dev/null and b/nightly_8.3/html/_images/time_series.png differ diff --git a/nightly_8.3/html/_images/tui-1.gif b/nightly_8.3/html/_images/tui-1.gif new file mode 100644 index 0000000000..33837a001b Binary files /dev/null and b/nightly_8.3/html/_images/tui-1.gif differ diff --git a/nightly_8.3/html/_images/tui-1.png b/nightly_8.3/html/_images/tui-1.png new file mode 100644 index 0000000000..77d39023cf Binary files /dev/null and b/nightly_8.3/html/_images/tui-1.png differ diff --git a/nightly_8.3/html/_images/tui-2.png b/nightly_8.3/html/_images/tui-2.png new file mode 100644 index 0000000000..b8c31db7c1 Binary files /dev/null and b/nightly_8.3/html/_images/tui-2.png differ diff --git a/nightly_8.3/html/_images/tui-3.png b/nightly_8.3/html/_images/tui-3.png new file mode 100644 index 0000000000..b819f2a289 Binary files /dev/null and b/nightly_8.3/html/_images/tui-3.png differ diff --git a/nightly_8.3/html/_images/ui-view-selector.jpg b/nightly_8.3/html/_images/ui-view-selector.jpg new file mode 100644 index 0000000000..f39bb446f7 Binary files /dev/null and b/nightly_8.3/html/_images/ui-view-selector.jpg differ diff --git a/nightly_8.3/html/_images/ui-workspace-tabs.gif b/nightly_8.3/html/_images/ui-workspace-tabs.gif new file mode 100644 index 0000000000..519cc9a596 Binary files /dev/null and b/nightly_8.3/html/_images/ui-workspace-tabs.gif differ diff --git a/nightly_8.3/html/_images/vip-vr.gif b/nightly_8.3/html/_images/vip-vr.gif new file mode 100644 index 0000000000..3785db19cf Binary files /dev/null and b/nightly_8.3/html/_images/vip-vr.gif differ diff --git a/nightly_8.3/html/_images/websocket-communication.png b/nightly_8.3/html/_images/websocket-communication.png new file mode 100644 index 0000000000..7c5586e682 Binary files /dev/null and b/nightly_8.3/html/_images/websocket-communication.png differ diff --git a/nightly_8.3/html/_images/websocket-graphql-ws-protocol.png b/nightly_8.3/html/_images/websocket-graphql-ws-protocol.png new file mode 100644 index 0000000000..70f3617538 Binary files /dev/null and b/nightly_8.3/html/_images/websocket-graphql-ws-protocol.png differ diff --git a/nightly_8.3/html/_modules/cylc/flow/exceptions.html b/nightly_8.3/html/_modules/cylc/flow/exceptions.html new file mode 100644 index 0000000000..3fa254d4c0 --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/flow/exceptions.html @@ -0,0 +1,768 @@ + + + + + + + + cylc.flow.exceptions — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for cylc.flow.exceptions

+# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+"""Exceptions for "expected" errors."""
+
+
+from textwrap import wrap
+from typing import (
+    Dict,
+    Optional,
+    Sequence,
+    Set,
+    Union,
+    TYPE_CHECKING,
+)
+
+from cylc.flow.util import format_cmd
+
+if TYPE_CHECKING:
+    from cylc.flow.subprocctx import SubFuncContext
+
+
+
+[docs] +class CylcError(Exception): + """Generic exception for Cylc errors. + + This exception is raised in-place of "expected" errors where a short + message to the user is more appropriate than traceback. + + CLI commands will catch this exception and exit with str(exception). + """
+ + + +
+[docs] +class PluginError(CylcError): + """Represents an error arising from a Cylc plugin. + + Args: + entry_point: + The plugin entry point as defined in setup.cfg + (e.g. 'cylc.main_loop') + plugin_name: + Name of the plugin + exc: + Original exception caught when trying to run the plugin + + """ + + def __init__(self, entry_point: str, plugin_name: str, exc: Exception): + self.entry_point = entry_point + self.plugin_name = plugin_name + self.exc = exc + + def __str__(self) -> str: + return ( + f"Error in plugin {self.entry_point}.{self.plugin_name}\n" + f"{type(self.exc).__name__}: {self.exc}" + )
+ + + +
+[docs] +class InputError(CylcError): + """Exception covering erroneous user input to a Cylc interface. + + Ideally this would be handled in the interface (e.g. argument parser). + If this isn't possible raise InputError. + + """
+ + + +
+[docs] +class CylcConfigError(CylcError): + """Generic exception to handle an error in a Cylc configuration file."""
+ + # TODO: reference the configuration element causing the problem + + +
+[docs] +class WorkflowConfigError(CylcConfigError): + """Exception for configuration errors in a Cylc workflow configuration."""
+ + + +
+[docs] +class GlobalConfigError(CylcConfigError): + """Exception for configuration errors in a Cylc global configuration."""
+ + + +
+[docs] +class GraphParseError(WorkflowConfigError): + """Exception for errors in Cylc workflow graphing."""
+ + + +
+[docs] +class TriggerExpressionError(GraphParseError): + """Trigger expression syntax issue."""
+ + + +
+[docs] +class TaskProxySequenceBoundsError(CylcError): + """Error on TaskProxy.__init__ with out of sequence bounds start point.""" + + def __init__(self, msg): + CylcError.__init__( + self, 'Not loading %s (out of sequence bounds)' % msg)
+ + + +
+[docs] +class ParamExpandError(WorkflowConfigError): + """Exception for errors in Cylc parameter expansion."""
+ + + +
+[docs] +class WorkflowEventError(CylcError): + """Exception for errors in Cylc event handlers."""
+ + + +
+[docs] +class CommandFailedError(CylcError): + """Exception for when scheduler commands fail.""" + def __init__(self, value: Union[str, Exception]): + self.value = value + + def __str__(self) -> str: + if isinstance(self.value, Exception): + return f"{type(self.value).__name__}: {self.value}" + return self.value
+ + + +
+[docs] +class ServiceFileError(CylcError): + """Exception for errors related to workflow service files."""
+ + + +
+[docs] +class WorkflowFilesError(CylcError): + """Exception for errors related to workflow files/directories.""" + bullet = "\n -"
+ + + +
+[docs] +class ContactFileExists(CylcError): + """Workflow contact file exists."""
+ + + +
+[docs] +class FileRemovalError(CylcError): + """Exception for errors during deletion of files/directories, which are + probably the filesystem's fault, not Cylc's.""" + + def __init__(self, exc: Exception) -> None: + CylcError.__init__( + self, + f"{exc}. This is probably a temporary issue with the filesystem, " + "not a problem with Cylc." + )
+ + + +
+[docs] +class PlatformError(CylcError): + """Error in the management of a remote platform. + + If the exception represents a command failure, provide either the ctx OR + manually populate the remaining kwargs. Otherwise leave the kwargs blank. + + Args: + message: + Short description. + platform_name: + Name of the platform. + ctx: + SubFuncContext object if available. + The other kwargs are derived from this. + cmd: + The remote command. + ret_code: + The command's return code. + out: + The command's stdout. + err: + The command's stderr. + + """ + + MSG_INIT = "initialisation did not complete" + MSG_SELECT = "host selection failed" + MSG_TIDY = "clean up did not complete" + + def __init__( + self, + message: str, + platform_name: str, + *, + ctx: 'Optional[SubFuncContext]' = None, + cmd: Union[str, Sequence[str], None] = None, + ret_code: Optional[int] = None, + out: Optional[str] = None, + err: Optional[str] = None + ) -> None: + self.msg = message + self.platform_name = platform_name + if ctx: + self.cmd = ctx.cmd + self.ret_code = ctx.ret_code + self.out = ctx.out + self.err = ctx.err + else: + self.cmd = cmd + self.ret_code = ret_code + self.out = out + self.err = err + # convert the cmd object to a str if needed + if self.cmd and not isinstance(self.cmd, str): + self.cmd = format_cmd(self.cmd) + + def __str__(self): + # matches cylc.flow.platforms.log_platform_event format + if self.platform_name: + ret = f'platform: {self.platform_name} - {self.msg}' + else: + ret = f'{self.msg}' + for label, item in [ + ('COMMAND', self.cmd), + ('RETURN CODE', self.ret_code), + ('STDOUT', self.out), + ('STDERR', self.err) + ]: + if item is not None: + ret += f'\n{label}:' + for line in str(item).splitlines(True): # keep newline chars + ret += f"\n {line}" + return ret
+ + + +
+[docs] +class TaskDefError(WorkflowConfigError): + """Exception raise for errors in TaskDef initialization."""
+ + + +
+[docs] +class XtriggerConfigError(WorkflowConfigError): + """An error in an xtrigger. + + For example: + + * If the function module was not found. + * If the function was not found in the xtrigger module. + * If the function is not callable. + * If any string template in the function context + arguments are not present in the expected template values. + + """ + + def __init__(self, label: str, func: str, message: Union[str, Exception]): + self.label = label + self.func = func + self.message = message + + def __str__(self) -> str: + return f'[@{self.label}] {self.func}\n{self.message}'
+ + + +
+[docs] +class ClientError(CylcError): + """Base class for errors raised by Cylc client instances. + + For example, the workflow you are trying to connect to is stopped. + + Attributes: + message: + The exception message. + traceback: + The underlying exception instance if available. + workflow: + The workflow ID if available. + """ + + def __init__( + self, + message: str, + traceback: Optional[str] = None, + workflow: Optional[str] = None + ): + self.message = message + self.traceback = traceback + # Workflow not included in string representation but useful bit of + # info to attach to the exception object + self.workflow = workflow + + def __str__(self) -> str: + ret = self.message + if self.traceback: + # append server-side traceback + ret += '\n' + self.traceback + return ret
+ + + +
+[docs] +class WorkflowStopped(ClientError): + """The Cylc scheduler you attempted to connect to is stopped.""" + + def __init__(self, workflow): + self.workflow = workflow + + def __str__(self): + return f'{self.workflow} is not running'
+ + + +
+[docs] +class ClientTimeout(CylcError): + """The scheduler did not respond within the timeout. + + This could be due to: + * Network issues. + * Scheduler issues. + * Insufficient timeout. + + To increase the timeout, use the ``--comms-timeout`` option. + + """ + + def __init__(self, message: str, workflow: Optional[str] = None): + self.message = message + self.workflow = workflow + + def __str__(self) -> str: + return self.message
+ + + +
+[docs] +class CyclingError(CylcError): + """Base class for errors in cycling configuration."""
+ + + +
+[docs] +class CyclerTypeError(CyclingError): + """An error raised when incompatible cycling types are wrongly mixed.""" + + def __init__(self, *args): + CyclingError.__init__( + self, + 'Incompatible cycling types: {0} ({1}), {2} ({3})'.format(*args))
+ + + +
+[docs] +class PointParsingError(CyclingError): + """An error raised when a point has an incorrect value.""" + + def __init__(self, *args): + CyclingError.__init__( + self, 'Incompatible value for {0}: {1}: {2}'.format(*args))
+ + + +
+[docs] +class IntervalParsingError(CyclingError): + """An error raised when an interval has an incorrect value.""" + + def __init__(self, *args): + CyclingError.__init__( + self, 'Incompatible value for {0}: {1}'.format(*args))
+ + + +
+[docs] +class SequenceParsingError(CyclingError): + """Error on parsing an invalid sequence."""
+ + + +
+[docs] +class SequenceDegenerateError(CyclingError): + """An error raised when adjacent points on a sequence are equal.""" + + def __init__(self, *args): + CyclingError.__init__( + self, ( + '{0}, point format {1}: equal adjacent points:' + ' {2} => {3}.' + ).format(*args))
+ + + +
+[docs] +class CylcTimeSyntaxError(CyclingError): + """An error denoting invalid ISO/Cylc input syntax."""
+ + + +
+[docs] +class CylcMissingContextPointError(CyclingError): + """An error denoting a missing (but required) context cycle point."""
+ + + +
+[docs] +class CylcMissingFinalCyclePointError(CyclingError): + """An error denoting a missing (but required) final cycle point."""
+ + + +
+[docs] +class PlatformLookupError(CylcConfigError): + """Unable to determine the correct job platform from the information + given"""
+ + + +
+[docs] +class HostSelectException(CylcError): + """No hosts could be selected from the provided configuration.""" + + def __init__(self, data: Dict[str, dict]): + self.data = data + + def __str__(self) -> str: + ret = 'Could not select host from:' + for host, data in sorted(self.data.items()): + if host != 'ranking': + ret += f'\n {host}:' + for key, value in data.items(): + ret += f'\n {key}: {value}' + hint = self.get_hint() + if hint: + ret += f'\n\n{hint}' + return ret + +
+[docs] + def get_hint(self): + """Return a hint to explain this error for certain cases.""" + if all( + # all procs came back with special SSH error code 255 + datum.get('returncode') == 255 + for key, datum in self.data.items() + if key != 'ranking' + ): + # likely SSH issues + return ( + 'Cylc could not establish SSH connection to the run hosts.' + '\nEnsure you can SSH to these hosts without having to' + ' answer any prompts.' + ) + + if ( + # a ranking expression was used + self.data.get('ranking') + # and all procs came back with special 'cylc psutil' error code 2 + # (which is used for errors relating to the extraction of metrics) + and all( + datum.get('returncode') == 2 + for key, datum in self.data.items() + if key != 'ranking' + ) + ): + # likely an issue with the ranking expression + lines = wrap( + self.data.get("ranking"), + initial_indent=' ', + subsequent_indent=' ', + ) + ranking = "\n".join(lines) + return ( + 'This is likely an error in the ranking expression:' + f'\n{ranking}' + '\n\nConfigured by:' + '\n global.cylc[scheduler][run hosts]ranking' + ) + + return None
+
+ + + +
+[docs] +class NoHostsError(CylcError): + """None of the hosts of a given platform were reachable.""" + def __init__(self, platform): + self.platform_name = platform['name'] + + def __str__(self): + return f'Unable to find valid host for {self.platform_name}'
+ + + +
+[docs] +class NoPlatformsError(PlatformLookupError): + """None of the platforms of a given set were reachable. + + Args: + identity: + The name of the platform group or install target. + set_type: + Whether the set of platforms is a platform group or an install + target. + place: + Where the attempt to get the platform failed. + """ + def __init__( + self, + identity: str, + hosts_consumed: Set[str], + set_type: str = 'group', + place: str = '', + ): + self.identity = identity + self.type = set_type + self.hosts_consumed = hosts_consumed + if place: + self.place = f' during {place}.' + else: + self.place = '.' + + def __str__(self): + return ( + f'Unable to find a platform from {self.type} {self.identity}' + f'{self.place}' + )
+ + + +
+[docs] +class CylcVersionError(CylcError): + """Contact file is for a Cylc Version not supported by this script.""" + def __init__(self, version=None): + self.version = version + + def __str__(self): + if self.version is not None: + return ( + f'Installed Cylc {self.version} workflow is not ' + 'compatible with Cylc 8.' + ) + else: + return "Installed workflow is not compatible with Cylc 8."
+ + + +
+[docs] +class InvalidCompletionExpression(CylcError): + """For the [runtime][<namespace>]completion configuration. + + Raised when non-whitelisted syntax is present. + """ + def __init__(self, message, expr=None): + self.message = message + self.expr = expr + + def __str__(self): + return self.message
+ +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/flow/jinja/filters/duration_as.html b/nightly_8.3/html/_modules/cylc/flow/jinja/filters/duration_as.html new file mode 100644 index 0000000000..f99f4fa1c1 --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/flow/jinja/filters/duration_as.html @@ -0,0 +1,256 @@ + + + + + + + + cylc.flow.jinja.filters.duration_as — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for cylc.flow.jinja.filters.duration_as

+# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
+# Copyright (C) 2008-2019 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/>.
+"""Filter for formatting ISO8601 duration strings."""
+
+from typing import Callable, Dict, Tuple
+
+from metomi.isodatetime.parsers import DurationParser
+
+SECONDS_PER_MINUTE = 60.0
+MINUTES_PER_HOUR = 60.0
+HOURS_PER_DAY = 24.0
+DAYS_PER_WEEK = 7.0
+
+SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR
+SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY
+SECONDS_PER_WEEK = SECONDS_PER_DAY * DAYS_PER_WEEK
+
+CONVERSIONS: Dict[Tuple[str, str], Callable] = {
+    ('s', 'seconds'): float,
+    ('m', 'minutes'): lambda s: float(s) / SECONDS_PER_MINUTE,
+    ('h', 'hours'): lambda s: float(s) / SECONDS_PER_HOUR,
+    ('d', 'days'): lambda s: float(s) / SECONDS_PER_DAY,
+    ('w', 'weeks'): lambda s: float(s) / SECONDS_PER_WEEK,
+}
+
+
+
+[docs] +def duration_as(iso8601_duration: str, units: str) -> float: + """Format an :term:`ISO8601 duration` string as the specified units. + + Units for the conversion can be specified in a case-insensitive short or + long form: + + - Seconds - "s" or "seconds" + - Minutes - "m" or "minutes" + - Hours - "h" or "hours" + - Days - "d" or "days" + - Weeks - "w" or "weeks" + + While the filtered value is a floating-point number, it is often required + to supply an integer to workflow entities (e.g. environment variables) that + require it. This is accomplished by chaining filters: + + - ``{{CYCLE_INTERVAL | duration_as('h') | int}}`` - 24 + - ``{{CYCLE_SUBINTERVAL | duration_as('h') | int}}`` - 0 + - ``{{CYCLE_INTERVAL | duration_as('s') | int}}`` - 86400 + - ``{{CYCLE_SUBINTERVAL | duration_as('s') | int}}`` - 1800 + + Args: + iso8601_duration: Any valid ISO8601 duration as a string. + units: Destination unit for the duration conversion + + Return: + The total number of the specified unit contained in the specified + duration as a floating-point number. + + Raises: + ISO8601SyntaxError: In the event of an invalid datetime string. + + Python Examples: + >>> # Basic usage. + >>> duration_as('PT1M', 's') + 60.0 + >>> duration_as('PT1H', 'seconds') + 3600.0 + + >>> # Exceptions. + >>> duration_as('invalid value', 's') # doctest: +NORMALIZE_WHITESPACE + Traceback (most recent call last): + metomi.isodatetime.exceptions.ISO8601SyntaxError: Invalid ISO 8601\ + duration representation: invalid value + >>> duration_as('invalid unit', '#') # doctest: +NORMALIZE_WHITESPACE + Traceback (most recent call last): + ValueError: No matching units found for # + + Jinja2 Examples: + .. code-block:: cylc + + {% set CYCLE_INTERVAL = 'PT1D' %} + {{ CYCLE_INTERVAL | duration_as('h') }} # 24.0 + {% set CYCLE_SUBINTERVAL = 'PT30M' %} + {{ CYCLE_SUBINTERVAL | duration_as('hours') }} # 0.5 + {% set CYCLE_INTERVAL = 'PT1D' %} + {{ CYCLE_INTERVAL | duration_as('s') }} # 86400.0 + {% set CYCLE_SUBINTERVAL = 'PT30M' %} + {{ CYCLE_SUBINTERVAL | duration_as('seconds') }} # 1800.0 + + """ + for converter_names in CONVERSIONS: + if units.lower() in converter_names: + converter = CONVERSIONS[converter_names] + break + else: + raise ValueError('No matching units found for %s' % units) + return converter(DurationParser().parse(iso8601_duration).get_seconds())
+ +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/flow/jinja/filters/pad.html b/nightly_8.3/html/_modules/cylc/flow/jinja/filters/pad.html new file mode 100644 index 0000000000..72890f4215 --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/flow/jinja/filters/pad.html @@ -0,0 +1,203 @@ + + + + + + + + cylc.flow.jinja.filters.pad — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for cylc.flow.jinja.filters.pad

+# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+"""Filter for padding strings to a set number of chars."""
+
+from typing import Union
+
+
+
+[docs] +def pad(value: str, length: Union[int, str], fillchar: str = ' '): + """Pads a string to some length with a fill character + + Useful for generating task names and related values in ensemble workflows. + + Args: + value: + The string to pad. + length: + The length for the returned string. + fillchar: + The character to fill in surplus space (space by default). + + Returns: + str: value padded to the left with fillchar to length length. + + Python Examples: + >>> pad('13', 3, '0') + '013' + >>> pad('foo', 6) + ' foo' + >>> pad('foo', 2) + 'foo' + + Jinja2 Examples: + .. code-block:: cylc + + {% for i in range(0,100) %} # 0, 1, ..., 99 + {% set j = i | pad(2,'0') %} + [[A_{{j}}]] # [[A_00]], [[A_01]], ..., [[A_99]] + {% endfor %} + + """ + return str(value).rjust(int(length), str(fillchar))
+ +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/flow/jinja/filters/strftime.html b/nightly_8.3/html/_modules/cylc/flow/jinja/filters/strftime.html new file mode 100644 index 0000000000..2828fb7527 --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/flow/jinja/filters/strftime.html @@ -0,0 +1,253 @@ + + + + + + + + cylc.flow.jinja.filters.strftime — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for cylc.flow.jinja.filters.strftime

+# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+"""Filter for formatting ISO8601 datetime strings."""
+
+from typing import Optional
+
+from metomi.isodatetime.parsers import TimePointParser
+
+
+
+[docs] +def strftime( + iso8601_datetime: str, + strftime_str: str, + strptime_str: Optional[str] = None, +): + """Format an :term:`ISO8601 datetime` string using an strftime string. + + .. code-block:: cylc + + {{ '10661004T08+01' | strftime('%H') }} # 00 + + It is also possible to parse non-standard date-time strings by passing a + strptime string as the second argument. + + Args: + iso8601_datetime: + Any valid ISO8601 datetime as a string. + strftime_str: + A valid strftime string to format the output datetime. + strptime_str: + A valid strptime string defining the format of the provided + iso8601_datetime. + + Return: + The result of applying the strftime to the iso8601_datetime as parsed + by the strptime string if provided. + + Raises: + ISO8601SyntaxError: In the event of an invalid datetime string. + StrftimeSyntaxError: In the event of an invalid strftime string. + + Python Examples: + >>> # Basic usage. + >>> strftime('2000-01-01T00Z', '%H') + '00' + >>> strftime('2000', '%H') + '00' + >>> strftime('2000', '%Y/%m/%d %H:%M:%S') + '2000/01/01 00:00:00' + >>> strftime('10661014T08+01', '%z') # Timezone offset. + '+0100' + >>> strftime('10661014T08+01', '%j') # Day of the year + '287' + + >>> # Strptime. + >>> strftime('12,30,2000', '%m', '%m,%d,%Y') + '12' + >>> strftime('1066/10/14 08:00:00', '%Y%m%dT%H', '%Y/%m/%d %H:%M:%S') + '10661014T08' + + >>> # Exceptions. + >>> strftime('invalid', '%H') # doctest: +NORMALIZE_WHITESPACE + Traceback (most recent call last): + <class 'metomi.isodatetime.exceptions.ISO8601SyntaxError'> + metomi.isodatetime.exceptions.ISO8601SyntaxError: Invalid ISO 8601 \ + date representation: invalid + >>> strftime('2000', '%invalid') # doctest: +NORMALIZE_WHITESPACE + Traceback (most recent call last): + metomi.isodatetime.exceptions.StrftimeSyntaxError: Invalid \ + strftime/strptime representation: %i + >>> strftime('2000', '%Y', '%invalid') + ... # doctest: +NORMALIZE_WHITESPACE + Traceback (most recent call last): + metomi.isodatetime.exceptions.StrftimeSyntaxError: Invalid \ + strftime/strptime representation: %i + + Jinja2 Examples: + .. code-block:: cylc + + {% set START_CYCLE = '10661004T08+01' %} + + {{START_CYCLE | strftime('%Y')}} # 1066 + {{START_CYCLE | strftime('%m')}} # 10 + {{START_CYCLE | strftime('%d')}} # 14 + {{START_CYCLE | strftime('%H:%M:%S %z')}} # 08:00:00 +01 + {{'12,30,2000' | strftime('%m', '%m,%d,%Y')}} # 12 + + """ + if not strptime_str: + return TimePointParser().parse(iso8601_datetime).strftime(strftime_str) + return TimePointParser().strptime(iso8601_datetime, strptime_str).strftime( + strftime_str)
+ +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/flow/job_runner_handlers/documentation.html b/nightly_8.3/html/_modules/cylc/flow/job_runner_handlers/documentation.html new file mode 100644 index 0000000000..b0ae26b39e --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/flow/job_runner_handlers/documentation.html @@ -0,0 +1,617 @@ + + + + + + + + cylc.flow.job_runner_handlers.documentation — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for cylc.flow.job_runner_handlers.documentation

+# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+
+"""
+This file is used to auto-generate some reference documentation for the
+job runner plugin interface.
+
+Note the class contained here is just for documentation purposes and is
+not intended to be subclassed.
+"""
+
+from typing import (
+    Iterable,
+    List,
+    Tuple,
+    TYPE_CHECKING,
+)
+
+if TYPE_CHECKING:
+    import re
+
+
+
+[docs] +class ExampleHandler(): + """Documentation for writing job runner handlers. + + Cylc can submit jobs to a number of different job runners + (aka batch systems) e.g. Slurm and PBS. For a list of built-in integrations + see :ref:`AvailableMethods`. + + If the job runner you require is not on this list, Cylc provides a generic + interface for writing your own integration. + + Defining a new job runner handler requires a little Python programming. Use + the built-in handlers + (e.g. :py:mod:`cylc.flow.job_runner_handlers.background`) as examples. + + .. _where to put job runner handler modules: + + .. rubric:: Installation + + Custom job runner handlers must be installed on workflow and job + hosts in one of these locations: + + - under ``WORKFLOW-RUN-DIR/lib/python/`` + - under ``CYLC-PATH/cylc/flow/job_runner_handlers/`` + - or anywhere in ``$PYTHONPATH`` + + Each module should export the symbol ``JOB_RUNNER_HANDLER`` for the + singleton instance that implements the job system handler logic e.g: + + .. code-block:: python + :caption: my_handler.py + + class MyHandler(): + pass + + JOB_RUNNER_HANDLER = MyHandler() + + Each job runner handler class should instantiate with no argument. + + + .. rubric:: Usage + + You can then define a Cylc platform using the handler: + + .. code-block:: cylc + :caption: global.cylc + + [platforms] + [[my_platform]] + job runner = my_handler # note matches Python module name + hosts = localhost + + And configure tasks to submit to it: + + .. code-block:: cylc + :caption: flow.cylc + + [runtime] + [[my_task]] + script = echo "Hello World!" + platform = my_platform + + + .. rubric:: Common Arguments + + ``job_conf: dict`` + The Cylc job configuration as a dictionary with the following fields: + + * ``dependencies`` + * ``directives`` + * ``env-script`` + * ``environment`` + * ``err-script`` + * ``execution_time_limit`` + * ``exit-script`` + * ``flow_nums`` + * ``init-script`` + * ``job_d`` + * ``job_file_path`` + * ``job_runner_command_template`` + * ``job_runner_name`` + * ``namespace_hierarchy`` + * ``param_var`` + * ``platform`` + * ``post-script`` + * ``pre-script`` + * ``script`` + * ``submit_num`` + * ``task_id`` + * ``try_num`` + * ``uuid_str`` + * ``work_d`` + * ``workflow_name`` + + ``submit_opts: dict`` + The Cylc job submission options as a dictionary which may contain + the following fields: + + * ``env`` + * ``execution_time_limit`` + * ``execution_time_limit`` + * ``job_runner_cmd_tmpl`` + * ``job_runner_cmd_tmpl`` + + + .. rubric:: An Example + + The following ``qsub.py`` module overrides the built-in *pbs* + job runner handler to change the directive prefix from ``#PBS`` to + ``#QSUB``: + + .. TODO - double check that this still works, it's been a while + + .. code-block:: python + + #!/usr/bin/env python3 + + from cylc.flow.job_runner_handlers.pbs import PBSHandler + + class QSUBHandler(PBSHandler): + DIRECTIVE_PREFIX = "#QSUB " + + JOB_RUNNER_HANDLER = QSUBHandler() + + If this is in the Python search path (see + :ref:`Where To Put Job Runner Handler Modules` above) you can use it by + name in your global configuration: + + .. code-block:: cylc + + [platforms] + [[my_platform]] + hosts = myhostA, myhostB + job runner = qsub # <---! + + Then in your ``flow.cylc`` file you can use this platform: + + .. code-block:: cylc + + # Note, this workflow will fail at run time because we only changed the + # directive format, and PBS does not accept ``#QSUB`` directives in + # reality. + + [scheduling] + [[graph]] + R1 = "a" + [runtime] + [[root]] + execution time limit = PT1M + platform = my_platform + [[[directives]]] + -l nodes = 1 + -q = long + -V = + + .. note:: + + Don't subclass this class as it provides optional interfaces which + you may not want to inherit. + + """ + + FAIL_SIGNALS: Tuple[str] + """A tuple containing the names of signals to trap for reporting errors. + + The default is ``("EXIT", "ERR", "TERM", "XCPU")``. + + ``ERR`` and ``EXIT`` are always recommended. + ``EXIT`` is used to report premature stopping of the job + script, and its trap is unset at the end of the script. + """ + + KILL_CMD_TMPL: str + """Command template for killing a job submission. + + A Python string template for getting the job runner command to remove + and terminate a job ID. The command is formed using the logic: + ``job_runner.KILL_CMD_TMPL % {"job_id": job_id}``. + + For info on Python string template format see: + https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting + + """ + + POLL_CMD: str + """Command for checking job submissions. + + A list of job IDs to poll will be provided as arguments. + + The command should write valid submitted/running job IDs to stdout. + + * To filter out invalid/failed jobs use + :py:meth:`ExampleHandler.filter_poll_many_output`. + * To build a more advanced command than is possible with this configuration + use :py:meth:`ExampleHandler.get_poll_many_cmd`. + + """ + + POLL_CANT_CONNECT_ERR: str + """String for detecting communication errors in poll command output. + + A string containing an error message. If this is defined, when a poll + command returns a non-zero return code and its STDERR contains this + string, then the poll result will not be trusted, because it is assumed + that the job runner is currently unavailable. Jobs submitted to the + job runner will be assumed OK until we are able to connect to the + job runner again. + + """ + + SHOULD_KILL_PROC_GROUP: bool + """Kill jobs by killing the process group. + + A boolean to indicate whether it is necessary to kill a job by sending + a signal to its Unix process group. This boolean also indicates that + a job submitted via this job runner will physically run on the same + host it is submitted to. + + """ + + SHOULD_POLL_PROC_GROUP: bool + """Poll jobs by PID. + + A boolean to indicate whether it is necessary to poll a job by its PID + as well as the job ID. + + """ + + REC_ID_FROM_SUBMIT_OUT: 're.Pattern' + """Regular expression to extract job IDs from submission stderr. + + A regular expression (compiled) to extract the job "id" from the standard + output or standard error of the job submission command. + + """ + + REC_ID_FROM_SUBMIT_ERR: 're.Pattern' + """Regular expression to extract job IDs from submission stderr. + + See :py:attr:`ExampleHandler.REC_ID_FROM_SUBMIT_OUT`. + + """ + + SUBMIT_CMD_ENV: Iterable[str] + """Extra environment variables for the job runner command. + + A Python dict (or an iterable that can be used to update a dict) + containing extra environment variables for getting the job runner + command to submit a job file. + + """ + + SUBMIT_CMD_TMPL: str + """Command template for job submission. + + A Python string template for getting the job runner command to submit a + job file. The command is formed using the logic: + ``job_runner.SUBMIT_CMD_TMPL % {"job": job_file_path}`` + + For info on Python string template format see: + https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting + + """ + +
+[docs] + def filter_poll_many_output(self, out: str) -> List[str]: + """Filter job ides out of poll output. + + Called after the job runner's poll command. The method should read + the output and return a list of job IDs that are still in the + job runner. + + Args: + out: Job poll stdout. + + Returns: + List of job IDs + + """ + raise NotImplementedError()
+ + +
+[docs] + def filter_submit_output(self, out: str, err: str) -> Tuple[str, str]: + """Filter job submission stdout/err. + + Filter the standard output and standard error of the job submission + command. This is useful if the job submission command returns + information that should just be ignored. + + See also :py:meth:`ExampleHandler.SUBMIT_CMD_TMPL`. + + Args: + out: Job submit stdout. + err: Job submit stderr. + + Returns: + (new_out, new_err) + """ + raise NotImplementedError()
+ + +
+[docs] + def format_directives(self, job_conf: dict) -> List[str]: + """Returns lines to be appended to the job script. + + This method formats the job directives for a job file, if + job file directives are relevant for the job runner. The argument + "job_conf" is a dict containing the job configuration. + + Args: + job_conf: The Cylc configuration. + + Returns: + lines + + """ + raise NotImplementedError()
+ + +
+[docs] + def get_poll_many_cmd(self, job_id_list: List[str]) -> List[str]: + """Return a command to poll the specified jobs. + + If specified, this will be called instead of + :py:attr:`ExampleHandler.POLL_CMD`. + + Args: + job_id_list: The list of job IDs to poll. + + Returns: + command e.g. ['foo', '--bar', 'baz'] + + """ + raise NotImplementedError()
+ + +
+[docs] + def get_submit_stdin(self, job_file_path: str, submit_opts: dict) -> Tuple: + """ + + Return a 2-element tuple ``(proc_stdin_arg, proc_stdin_value)``. + + * Element 1 is suitable for the ``stdin=...`` argument of + ``subprocess.Popen`` so it can be a file handle, ``subprocess.PIPE`` + or ``None``. + * Element 2 is the string content to pipe to stdin of the submit + command (relevant only if ``proc_stdin_arg`` is ``subprocess.PIPE``. + + Args: + job_file_path: The path to the job file for this submission. + submit_opts: Job submission options. + + Returns: + (proc_stdin_arg, proc_stdin_value) + + """ + raise NotImplementedError()
+ + +
+[docs] + def get_vacation_signal(self, job_conf: dict) -> str: + """Return the vacation signal. + + If relevant, return a string containing the name of the signal that + indicates the job has been vacated by the job runner. + + Args: + job_conf: The Cylc configuration. + + Returns: + signal + + """ + raise NotImplementedError()
+ + +
+[docs] + def submit( + self, + job_file_path: str, + submit_opts: dict, + ) -> Tuple[int, str, str]: + """Submit a job. + + Submit a job and return an instance of the Popen object for the + submission. This method is useful if the job submission requires logic + beyond just running a system or shell command. + + See also :py:attr:`ExampleHandler.SUBMIT_CMD_TMPL`. + + You must pass "env=submit_opts.get('env')" to Popen - see + :py:mod:`cylc.flow.job_runner_handlers.background` + for an example. + + Args: + job_file_path: The job file for this submission. + submit_opts: Job submission options. + + Returns: + (ret_code, out, err) + + ret_code: + Subprocess return code. + out: + Subprocess standard output. + err: + Subprocess standard error. + + """ + raise NotImplementedError()
+ + +
+[docs] + def manip_job_id(self, job_id: str) -> str: + """Modify the job ID that is returned by the job submit command. + + Args: + job_id: The job ID returned by the submit command. + + Returns: + job_id + + """ + raise NotImplementedError()
+
+ +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/flow/main_loop.html b/nightly_8.3/html/_modules/cylc/flow/main_loop.html new file mode 100644 index 0000000000..bb82ffdb83 --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/flow/main_loop.html @@ -0,0 +1,531 @@ + + + + + + + + cylc.flow.main_loop — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for cylc.flow.main_loop

+# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+"""Plugins for running Python code inside of the Cylc scheduler.
+
+.. _BuiltInPlugins:
+
+Built In Plugins
+----------------
+
+Cylc Flow provides the following plugins:
+
+.. autosummary::
+   :toctree: built-in
+   :template: main_loop_plugin.rst
+
+   cylc.flow.main_loop.auto_restart
+   cylc.flow.main_loop.health_check
+   cylc.flow.main_loop.log_data_store
+   cylc.flow.main_loop.log_main_loop
+   cylc.flow.main_loop.log_memory
+   cylc.flow.main_loop.reset_bad_hosts
+
+.. Note: Autosummary generates files in this directory, these are cleaned
+         up by `make clean`.
+
+
+Configuring
+-----------
+
+Main loop plugins can be activated either by:
+
+* Using the ``--main-loop`` option with ``cylc play`` e.g:
+
+  .. code-block:: console
+
+     $ # run a workflow using the "health check" and "auto restart" plugins:
+     $ cylc play my-workflow --main-loop 'health check' \
+--main-loop 'auto restart'
+
+* Adding them to the default list of plugins in
+  :cylc:conf:`global.cylc[scheduler][main loop]plugins` e.g:
+
+  .. code-block:: cylc
+
+     [scheduler]
+         [[main loop]]
+             plugins = health check, auto restart
+
+Main loop plugins can be individually configured in their
+:cylc:conf:`global.cylc[scheduler][main loop][<plugin name>]` section e.g:
+
+.. code-block:: cylc
+
+   [scheduler]
+       [[main loop]]
+           [[[health check]]]
+               interval = PT5M  # perform check every 5 minutes
+
+
+Developing Main Loop Plugins
+----------------------------
+
+Main loop plugins are Python modules containing asynchronous function(s)
+(sometimes referred to as coroutines) which Cylc Flow executes within the
+scheduler.
+
+Hello World
+^^^^^^^^^^^
+
+Here is the "hello world" of main loop plugins:
+
+.. code-block:: python
+   :caption: my_plugin.py
+
+   from cylc.flow import LOG
+   from cylc.flow.main_loop import startup
+
+   @startup
+   async def my_startup_coroutine(schd, state):
+      # write Hello <workflow name> to the Cylc log.
+      LOG.info(f'Hello {schd.workflow}')
+
+Plugins are registered by registering them with the ``cylc.main_loop``
+entry point:
+
+.. code-block:: python
+   :caption: setup.py
+
+   # plugins must be properly installed, in-place PYTHONPATH meddling will
+   # not work.
+
+   from setuptools import setup
+
+   setup(
+       name='my-plugin',
+       version='1.0',
+       py_modules=['my_plugin'],
+       entry_points={
+          # register this plugin with Cylc
+          'cylc.main_loop': [
+            # name = python.namespace.of.module
+            'my_plugin=my_plugin.my_plugin'
+          ]
+       }
+   )
+
+Examples
+^^^^^^^^
+
+For examples see the built-in plugins in the :py:mod:`cylc.flow.main_loop`
+module which are registered in the Cylc Flow ``setup.cfg`` file.
+
+Coroutines
+^^^^^^^^^^
+
+.. _coroutines: https://docs.python.org/3/library/asyncio-task.html#coroutines
+
+Plugins provide asynchronous functions (`coroutines`_) which Cylc will
+then run inside the scheduler.
+
+Coroutines should be fast running (read as gentle on the scheduler)
+and perform IO asynchronously.
+
+Coroutines shouldn't meddle with the state of the scheduler and should be
+parallel-safe with other plugins.
+
+Event Types
+^^^^^^^^^^^
+
+Coroutines must be decorated using one of the main loop decorators. The
+choice of decorator effects when the coroutine is called and what
+arguments are provided to it.
+
+The available event types are:
+
+.. autofunction:: cylc.flow.main_loop.startup
+
+.. autofunction:: cylc.flow.main_loop.shutdown
+
+.. autofunction:: cylc.flow.main_loop.periodic
+
+"""
+from collections import deque
+from inspect import (
+    getmembers,
+    isfunction
+)
+from textwrap import indent
+from time import time
+
+from cylc.flow import LOG, iter_entry_points
+from cylc.flow.exceptions import CylcError, InputError, PluginError
+
+
+class MainLoopPluginException(Exception):
+    """Raised in-place of CylcError exceptions.
+
+    Note:
+        * Not an instace of CylcError as that is used for controlled
+          shutdown e.g. SchedulerStop.
+
+    """
+
+
+async def _wrapper(fcn, scheduler, state, timings=None):
+    """Wrapper for all plugin functions.
+
+    * Logs the function's execution.
+    * Times the function.
+    * Catches any exceptions which aren't subclasses of CylcError.
+
+    """
+    sig = f'{fcn.__module__}:{fcn.__name__}'
+    LOG.debug(f'main_loop [run] {sig}')
+    start_time = time()
+    try:
+        await fcn(scheduler, state)
+    except CylcError as exc:
+        # allow CylcErrors through (e.g. SchedulerStop)
+        # NOTE: the `from None` bit gets rid of this gunk:
+        # > During handling of the above exception another exception
+        raise MainLoopPluginException(exc) from None
+    except Exception as exc:
+        LOG.error(f'Error in main loop plugin {sig}')
+        LOG.exception(exc)
+    duration = time() - start_time
+    LOG.debug(f'main_loop [end] {sig} ({duration:.3f}s)')
+    if timings is not None:
+        timings.append((start_time, duration))
+
+
+def _debounce(interval, timings):
+    """Rate limiter, returns True if the interval has elapsed.
+
+    Arguments:
+        interval (float):
+            Time interval in seconds as a float-type object.
+        timings (list):
+            List-list object of the timings of previous runs in the form
+            ``(completion_wallclock_time, run_duration)``.
+            Wallclock times are unix epoch times in seconds.
+
+    Examples:
+        >>> from time import time
+
+        No previous run (should always return True):
+        >>> _debounce(1., [(0, 0)])
+        True
+
+        Interval not yet elapsed since previous run:
+        >>> _debounce(1., [(time(), 0)])
+        False
+
+        Interval has elapsed since previous run:
+        >>> _debounce(1., [(time() - 2, 0)])
+        True
+
+    """
+    if not interval:
+        return True
+    try:
+        last_run_at = timings[-1][0]
+    except IndexError:
+        last_run_at = 0
+    if (time() - last_run_at) > interval:
+        return True
+    return False
+
+
+
+[docs] +def startup(fcn): + """Decorates a coroutine which is run at workflow startup. + + The decorated coroutine should have the signature: + + ``async coroutine(scheduler, plugin_state) -> None`` + + Exceptions: + + * Regular Exceptions are caught and logged. + * Exceptions which subclass CylcError are re-raised as + MainLoopPluginException + + """ + fcn.main_loop = CoroTypes.StartUp + return fcn
+ + + +
+[docs] +def shutdown(fcn): + """Decorates a coroutine which is run at workflow shutdown. + + Note shutdown refers to "clean" shutdown as opposed to workflow abort. + + The decorated coroutine should have the signature: + + ``async coroutine(scheduler, plugin_state) -> None`` + + Exceptions: + + * Regular Exceptions are caught and logged. + * Exceptions which subclass CylcError are re-raised as + MainLoopPluginException + + """ + fcn.main_loop = CoroTypes.ShutDown + return fcn
+ + + +
+[docs] +def periodic(fcn): + """Decorates a coroutine which is run at a set interval. + + The decorated coroutine should have the signature: + + ``async coroutine(scheduler, plugin_state) -> None`` + + Exceptions: + + * Regular Exceptions are caught and logged. + * Exceptions which subclass CylcError are re-raised as + MainLoopPluginException + + Configuration: + + * The interval of execution can be altered using + :cylc:conf:`global.cylc[scheduler][main loop][<plugin name>]interval` + + """ + fcn.main_loop = CoroTypes.Periodic + return fcn
+ + + +class CoroTypes: + """Different types of coroutine which can be used with the main loop.""" + + StartUp = startup + ShutDown = shutdown + Periodic = periodic + + +def load(config, additional_plugins=None): + additional_plugins = additional_plugins or [] + entry_points = { + entry_point.name: entry_point + for entry_point in + iter_entry_points('cylc.main_loop') + } + plugins = { + 'state': {}, + 'timings': {} + } + for plugin_name in set(config['plugins'] + additional_plugins): + # get plugin + try: + entry_point = entry_points[plugin_name.replace(' ', '_')] + except KeyError: + raise InputError( + f'No main-loop plugin: "{plugin_name}"\n' + + ' Available plugins:\n' + + indent('\n'.join(sorted(entry_points)), ' ') + ) + # load plugin + try: + module = entry_point.load() + except Exception as exc: + raise PluginError( + 'cylc.main_loop', entry_point.name, exc + ) + # load coroutines + log = [] + for coro_name, coro in getmembers(module): + if isfunction(coro) and hasattr(coro, 'main_loop'): + log.append(coro_name) + plugins.setdefault( + coro.main_loop, {} + )[(plugin_name, coro_name)] = coro + plugins['timings'][(plugin_name, coro_name)] = deque(maxlen=1) + LOG.debug( + 'Loaded main loop plugin "%s":\n%s', + plugin_name, + '\n'.join(f'* {x}' for x in log) + ) + # set the initial state of the plugin + plugins['state'][plugin_name] = {} + # make a note of the config here for ease of reference + plugins['config'] = config + return plugins + + +def get_runners(plugins, coro_type, scheduler): + return [ + _wrapper( + coro, + scheduler, + plugins['state'][plugin_name], + timings=plugins['timings'][(plugin_name, coro_name)] + ) + for (plugin_name, coro_name), coro + in plugins.get(coro_type, {}).items() + if coro_type != CoroTypes.Periodic + or _debounce( + plugins['config'].get(plugin_name, {}).get('interval', None), + plugins['timings'][(plugin_name, coro_name)] + ) + ] +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/flow/main_loop/auto_restart.html b/nightly_8.3/html/_modules/cylc/flow/main_loop/auto_restart.html new file mode 100644 index 0000000000..bb4992e62c --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/flow/main_loop/auto_restart.html @@ -0,0 +1,403 @@ + + + + + + + + cylc.flow.main_loop.auto_restart — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for cylc.flow.main_loop.auto_restart

+# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+"""Automatically restart workflows if they are running on bad servers.
+
+Loads in the global configuration to check if the server a workflow is running
+on is listed in :cylc:conf:`global.cylc[scheduler][run hosts]condemned`.
+
+This is useful if a host needs to be taken off-line e.g. for scheduled
+maintenance.
+
+This functionality is configured via the following site configuration
+settings:
+
+.. cylc-scope:: global.cylc
+
+- :cylc:conf:`[scheduler]auto restart delay`
+- :cylc:conf:`[scheduler][run hosts]condemned`
+- :cylc:conf:`[scheduler][run hosts]available`
+
+
+
+The auto stop-restart feature has two modes:
+
+Normal Mode
+   When a host is added to the
+   :cylc:conf:`[scheduler][run hosts]condemned` list, any workflows
+   running on that host will automatically shutdown then restart selecting a
+   new host from :cylc:conf:`[scheduler][run hosts]available`.
+
+   For safety, before attempting to stop the workflow Cylc will first wait
+   for any jobs running locally (under background or at) to complete.
+
+   In order for Cylc to be able to restart workflows the
+   :cylc:conf:`[scheduler][run hosts]available` hosts must all be on a
+   shared filesystem.
+Force Mode
+   If a host is suffixed with an exclamation mark then Cylc will not attempt
+   to automatically restart the workflow and any local jobs (running under
+   background or at) will be left running.
+
+For example in the following configuration any workflows running on
+``foo`` will attempt to restart on ``pub`` whereas any workflows
+running on ``bar`` will stop immediately, making no attempt to restart.
+
+.. code-block:: cylc
+
+   [scheduler]
+        [[run hosts]]
+            available = pub
+            condemned = foo, bar!
+
+.. warning::
+
+   Cylc will reject hosts with ambiguous names such as ``localhost`` or
+   ``127.0.0.1`` for this configuration as
+   :cylc:conf:`[scheduler][run hosts]condemned`
+   are evaluated on the workflow host server.
+
+To prevent large numbers of workflows attempting to restart simultaneously the
+:cylc:conf:`[scheduler]auto restart delay` setting defines a period
+of time in seconds.
+Workflows will wait for a random period of time between zero and
+:cylc:conf:`[scheduler]auto restart delay` seconds before
+attempting to stop and restart.
+
+Workflows that are started up in no-detach mode cannot auto stop-restart on a
+different host - as it will still end up attached to the condemned host.
+Therefore, a workflow in no-detach mode running on a condemned host will abort
+with a non-zero return code. The parent process should manually handle the
+restart of the workflow if desired.
+
+.. cylc-scope::
+
+"""
+from random import random
+from time import time
+import traceback
+
+from cylc.flow import LOG
+from cylc.flow.cfgspec.glbl_cfg import glbl_cfg
+from cylc.flow.exceptions import CylcConfigError, HostSelectException
+from cylc.flow.host_select import select_workflow_host
+from cylc.flow.hostuserutil import get_fqdn_by_host
+from cylc.flow.main_loop import periodic
+from cylc.flow.parsec.exceptions import ParsecError
+from cylc.flow.scheduler import SchedulerError
+from cylc.flow.workflow_status import AutoRestartMode
+from cylc.flow.wallclock import (
+    get_time_string_from_unix_time as time2str
+)
+
+
+
+[docs] +@periodic +async def auto_restart(scheduler, _): + """Automatically restart the workflow if configured to do so.""" + try: + current_glbl_cfg = glbl_cfg(cached=False) + except (CylcConfigError, ParsecError) as exc: + LOG.error( + 'auto restart: an error in the global config is preventing it from' + f' being reloaded:\n{exc}' + ) + # skip check - we can't do anything until the global config has been + # fixed + return False # return False to make testing easier + mode = _should_auto_restart(scheduler, current_glbl_cfg) + + if mode: + LOG.info('The Cylc workflow host will soon become un-available.') + _set_auto_restart( + scheduler, + restart_delay=current_glbl_cfg.get( + ['scheduler', 'auto restart delay'] + ), + mode=mode + )
+ + + +def _should_auto_restart(scheduler, current_glbl_cfg): + # check if workflow host is condemned - if so auto restart + if scheduler.stop_mode is None: + for host in current_glbl_cfg.get( + ['scheduler', 'run hosts', 'condemned'] + ): + if host.endswith('!'): + # host ends in an `!` -> force shutdown mode + mode = AutoRestartMode.FORCE_STOP + host = host[:-1] + else: + # normal mode (stop and restart the workflow) + mode = AutoRestartMode.RESTART_NORMAL + if scheduler.auto_restart_time is not None: + # workflow is already scheduled to stop-restart only + # AutoRestartMode.FORCE_STOP can override this. + continue + + if get_fqdn_by_host(host) == scheduler.host: + # this host is condemned, take the appropriate action + + return mode + return False + + +def _can_auto_restart(): + """Determine whether this workflow can safely auto stop-restart.""" + # Check whether there is currently an available host to restart on. + try: + select_workflow_host(cached=False) + except HostSelectException: + LOG.critical( + 'Workflow cannot automatically restart because:\n' + + 'No alternative host to restart workflow on.') + return False + except Exception: + # Any unexpected error in host selection shouldn't be able to take + # down the workflow. + LOG.critical( + 'Workflow cannot automatically restart because:\n' + + 'Error in host selection:\n' + + traceback.format_exc()) + return False + else: + return True + + +def _set_auto_restart( + scheduler, + restart_delay=None, + mode=AutoRestartMode.RESTART_NORMAL +): + """Configure the workflow to automatically stop and restart. + + Restart handled by `workflow_auto_restart`. + + Args: + scheduler (cylc.flow.scheduler.Scheduler): + Scheduler instance of the running workflow. + restart_delay (cylc.flow.parsec.DurationFloat): + Workflow will wait a random period between 0 and + `restart_delay` seconds before attempting to stop/restart in + order to avoid multiple workflows restarting simultaneously. + mode (str): Auto stop-restart mode. + + Return: + bool: False if it is not possible to automatically stop/restart + the workflow due to its configuration/runtime state. + """ + # Check that the workflow isn't already shutting down. + if scheduler.stop_mode: + return True + + # Force mode, stop the workflow now, don't restart it. + if mode == AutoRestartMode.FORCE_STOP: + LOG.critical( + 'This workflow will be shutdown as the workflow ' + 'host is unable to continue running it.\n' + 'When another workflow host becomes available ' + 'the workflow can be restarted by:\n' + f' $ cylc play {scheduler.workflow}') + if scheduler.auto_restart_time: + LOG.info('Scheduled automatic restart canceled') + scheduler.auto_restart_time = time() + scheduler.auto_restart_mode = mode + return True + + # Check workflow isn't already scheduled to auto-stop. + if scheduler.auto_restart_time is not None: + return True + + # Workflow host is condemned and workflow running in no detach mode. + # Raise an error to cause the workflow to abort. + # This should raise an "abort" event and return a non-zero code to the + # caller still attached to the workflow process. + if scheduler.options.no_detach: + raise SchedulerError('Workflow host condemned in no detach mode') + + # Check workflow is able to be safely restarted. + if not _can_auto_restart(): + return False + + LOG.info('Workflow will automatically restart on a new host.') + if restart_delay is not None and restart_delay != 0: + if restart_delay > 0: + # Delay shutdown by a random interval to avoid many + # workflows restarting simultaneously. + shutdown_delay = int(random() * restart_delay) # nosec + else: + # Un-documented feature, schedule exact restart interval for + # testing purposes. + shutdown_delay = abs(int(restart_delay)) + shutdown_time = time() + shutdown_delay + LOG.info('Workflow will restart in %ss (at %s)', shutdown_delay, + time2str(shutdown_time)) + scheduler.auto_restart_time = shutdown_time + else: + scheduler.auto_restart_time = time() + + scheduler.auto_restart_mode = AutoRestartMode.RESTART_NORMAL + + return True +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/flow/main_loop/health_check.html b/nightly_8.3/html/_modules/cylc/flow/main_loop/health_check.html new file mode 100644 index 0000000000..9b527d06f1 --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/flow/main_loop/health_check.html @@ -0,0 +1,209 @@ + + + + + + + + cylc.flow.main_loop.health_check — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for cylc.flow.main_loop.health_check

+# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+"""Checks the integrity of the workflow run directory.
+
+* Ensures workflow run directory is still present.
+* Ensures contact file is present and consistent with the running workflow.
+
+Shuts down the workflow in the event of inconsistency or error.
+
+"""
+import os
+
+from cylc.flow import workflow_files
+from cylc.flow.exceptions import CylcError, ServiceFileError
+from cylc.flow.main_loop import periodic
+
+
+
+[docs] +@periodic +async def health_check(scheduler, _): + """Perform workflow health checks.""" + # 1. check if workflow run dir still present - if not shutdown. + _check_workflow_run_dir(scheduler) + # 2. check if contact file consistent with current start - if not + # shutdown. + _check_contact_file(scheduler)
+ + + +def _check_workflow_run_dir(scheduler): + if not os.path.exists(scheduler.workflow_run_dir): + raise CylcError( + 'Workflow run directory does not exist:' + f' {scheduler.workflow_run_dir}' + ) + + +def _check_contact_file(scheduler): + try: + contact_data = workflow_files.load_contact_file( + scheduler.workflow) + if contact_data != scheduler.contact_data: + raise CylcError('contact file modified') + except (AssertionError, IOError, ValueError, ServiceFileError): + raise CylcError( + '%s: contact file corrupted/modified and may be left' + % workflow_files.get_contact_file_path(scheduler.workflow) + ) +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/flow/main_loop/log_data_store.html b/nightly_8.3/html/_modules/cylc/flow/main_loop/log_data_store.html new file mode 100644 index 0000000000..67b68b70e2 --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/flow/main_loop/log_data_store.html @@ -0,0 +1,287 @@ + + + + + + + + cylc.flow.main_loop.log_data_store — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for cylc.flow.main_loop.log_data_store

+# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+"""Log the number and size of each type of object in the data store.
+
+.. note::
+
+   This plugin is for Cylc developers debugging the data store.
+
+If ``matplotlib`` is installed this plugin will plot results as a PDF in
+the run directory when the workflow is shut down (cleanly).
+
+"""
+import json
+from pathlib import Path
+from time import time
+
+from cylc.flow.main_loop import (startup, shutdown, periodic)
+
+
+try:
+    import matplotlib
+    matplotlib.use('Agg')
+    from matplotlib import pyplot as plt
+    PLT = True
+except ModuleNotFoundError:
+    PLT = False
+
+from pympler.asizeof import asized
+
+
+
+[docs] +@startup +async def init(scheduler, state): + """Construct the initial state.""" + state['objects'] = {} + state['size'] = {} + state['times'] = [] + for key, _ in _iter_data_store(scheduler.data_store_mgr.data): + state['objects'][key] = [] + state['size'][key] = []
+ + + +
+[docs] +@periodic +async def log_data_store(scheduler, state): + """Count the number of objects and the data store size.""" + state['times'].append(time()) + for key, value in _iter_data_store(scheduler.data_store_mgr.data): + state['objects'][key].append( + len(value) + ) + state['size'][key].append( + asized(value).size + )
+ + + +
+[docs] +@shutdown +async def report(scheduler, state): + """Dump data to JSON, attempt to plot results.""" + _dump(state, scheduler.workflow_run_dir) + _plot(state, scheduler.workflow_run_dir)
+ + + +def _iter_data_store(data_store): + for item in data_store.values(): + for key, value in item.items(): + if key != 'workflow': + yield (key, value) + # there should only be one workflow in the data store + break + + +def _dump(state, path): + data = { + 'times': state['times'], + 'objects': state['objects'], + 'size': state['size'] + } + json.dump( + data, + Path(path, f'{__name__}.json').open('w+') + ) + return True + + +def _plot(state, path): + if ( + not PLT + or len(state['times']) < 2 + ): + return False + + times = [tick - state['times'][0] for tick in state['times']] + _, ax1 = plt.subplots(figsize=(10, 7.5)) + + ax1.set_xlabel('Time (s)') + + ax1.set_ylabel('Objects') + for key, objects in state['objects'].items(): + ax1.plot(times, objects, label=key) + + ax2 = ax1.twinx() + ax2.set_ylabel('Size (kb)') + for sizes in state['size'].values(): + ax2.plot(times, [x / 1000 for x in sizes], linestyle=':') + + ax1.legend(loc=0) + ax2.legend( + (ax1.get_children()[0], ax2.get_children()[0]), + ('objects', 'size'), + loc=1 + ) + + # start the x-axis at zero + ax1.set_xlim(0, ax1.get_xlim()[1]) + + plt.savefig( + Path(path, f'{__name__}.pdf') + ) + return True +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/flow/main_loop/log_main_loop.html b/nightly_8.3/html/_modules/cylc/flow/main_loop/log_main_loop.html new file mode 100644 index 0000000000..9f0297ad2a --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/flow/main_loop/log_main_loop.html @@ -0,0 +1,262 @@ + + + + + + + + cylc.flow.main_loop.log_main_loop — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for cylc.flow.main_loop.log_main_loop

+# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+"""Main loop plugin for monitoring main loop plugins.
+
+.. note::
+
+   This plugin is for Cylc developers debugging main loop operations.
+
+If ``matplotlib`` is installed this plugin will plot results as a PDF in
+the run directory when the workflow is shut down (cleanly).
+
+"""
+from collections import deque
+import json
+from pathlib import Path
+
+from cylc.flow.main_loop import startup, shutdown
+
+try:
+    import matplotlib
+    matplotlib.use('Agg')
+    from matplotlib import pyplot as plt
+    PLT = True
+except ModuleNotFoundError:
+    PLT = False
+
+
+
+[docs] +@startup +async def init(scheduler, _): + """Override default queue length of 1. + + This allows timings to accumulate, normally only the most recent is kept. + """ + plugins = scheduler.main_loop_plugins + for plugin in plugins['timings']: + plugins['timings'][plugin] = deque()
+ + + +
+[docs] +@shutdown +async def report(scheduler, _): + """Extract plugin function timings.""" + data = scheduler.main_loop_plugins['timings'] + if data: + data = _normalise(data) + _dump(data, scheduler.workflow_run_dir) + _plot(data, scheduler.workflow_run_dir)
+ + + +def _normalise(data): + earliest_time = min(( + start_time + for _, timings in data.items() + for start_time, duration in timings + )) + return { + plugin_name: [ + (start_time - earliest_time, duration) + for start_time, duration in timings + ] + for (plugin_name, _), timings in data.items() + } + + +def _dump(data, path): + json.dump( + data, + Path(path, f'{__name__}.json').open('w+'), + indent=4 + ) + return True + + +def _plot(data, path): + if not PLT: + return False + + _, ax1 = plt.subplots(figsize=(10, 7.5)) + ax1.set_xlabel('Workflow Run Time (s)') + ax1.set_ylabel('XTrigger Run Time (s)') + + for plugin_name, (timings) in data.items(): + x_data = [] + y_data = [] + for start_time, duration in timings: + x_data.append(start_time) + y_data.append(duration) + ax1.scatter(x_data, y_data, label=plugin_name) + + ax1.set_xlim(0, ax1.get_xlim()[1]) + ax1.set_ylim(0, ax1.get_ylim()[1]) + + ax1.legend() + plt.savefig( + Path(path, f'{__name__}.pdf') + ) + return True +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/flow/main_loop/log_memory.html b/nightly_8.3/html/_modules/cylc/flow/main_loop/log_memory.html new file mode 100644 index 0000000000..da56208f57 --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/flow/main_loop/log_memory.html @@ -0,0 +1,337 @@ + + + + + + + + cylc.flow.main_loop.log_memory — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for cylc.flow.main_loop.log_memory

+# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+"""Log the memory usage of a running scheduler over time.
+
+.. note::
+
+   This plugin is for Cylc developers debugging cylc memory usage.
+
+   For general interest memory measurement try
+   ``/usr/bin/time -v cylc play`` or ``cylc play --profile``.
+
+.. note::
+
+   Pympler associates memory with the first object which references it.
+
+   In Cylc we have some objects (e.g. the configuration) which are references
+   from multiple places.
+
+   This can result in a certain amount of "jitter" in the results where
+   pympler has swapper from associating memory with one object to another.
+
+   Watch out for matching increase/decrease in reported memory in
+   different objects.
+
+.. warning::
+
+   This plugin can slow down a workflow significantly due to the
+   complexity of memory calculations.
+
+   Set a sensible interval before running workflows.
+
+If ``matplotlib`` is installed this plugin will plot results as a PDF in
+the run directory when the workflow is shut down (cleanly).
+
+"""
+
+import json
+from pathlib import Path
+from time import time
+
+from cylc.flow.main_loop import (startup, shutdown, periodic)
+
+try:
+    import matplotlib
+    matplotlib.use('Agg')
+    from matplotlib import pyplot as plt
+    PLT = True
+except ModuleNotFoundError:
+    PLT = False
+
+from pympler.asizeof import asized
+
+
+# TODO: make this configurable in the global config
+MIN_SIZE = 10000
+
+
+
+[docs] +@startup +async def init(scheduler, state): + """Take an initial memory snapshot.""" + state['data'] = [] + await take_snapshot(scheduler, state)
+ + + +
+[docs] +@periodic +async def take_snapshot(scheduler, state): + """Take a memory snapshot""" + state['data'].append(( + time(), + _compute_sizes(scheduler, min_size=MIN_SIZE) + ))
+ + + +
+[docs] +@shutdown +async def report(scheduler, state): + """Take a final memory snapshot and dump the results.""" + await take_snapshot(scheduler, state) + _dump(state['data'], scheduler.workflow_run_dir) + fields, times = _transpose(state['data']) + _plot( + fields, + times, + scheduler.workflow_run_dir, + f'cylc.flow.scheduler.Scheduler attrs > {MIN_SIZE / 1000}kb' + )
+ + + +def _compute_sizes(obj, min_size=10000): + """Return the sizes of the attributes of an object.""" + size = asized(obj, detail=2) + for ref in size.refs: + if ref.name == '__dict__': + break + else: + raise Exception('Cannot find __dict__ reference') + + return { + **{ + item.name.split(':')[0][4:]: item.size + for item in ref.refs + if item.size > min_size + }, + **{'total': size.size}, + } + + +def _transpose(data): + """Pivot data from snapshot to series oriented.""" + all_keys = set() + for _, datum in data: + all_keys.update(datum.keys()) + + # sort keys by the size of the last checkpoint so that the fields + # get plotted from largest to smallest + all_keys = list(all_keys) + all_keys.sort(key=lambda x: data[-1][1].get(x, 0), reverse=True) + + # extract data for each field, if not present + fields = {} + for key in all_keys: + fields[key] = [ + datum.get(key, -1) + for _, datum in data + ] + + start_time = data[0][0] + times = [ + timestamp - start_time + for timestamp, _ in data + ] + + return fields, times + + +def _dump(data, path): + json.dump( + data, + Path(path, f'{__name__}.json').open('w+') + ) + return True + + +def _plot(fields, times, path, title='Objects'): + if ( + not PLT + or len(times) < 2 + ): + return False + + fig, ax1 = plt.subplots(figsize=(10, 7.5)) + + fig.suptitle(title) + ax1.set_xlabel('Time (s)') + ax1.set_ylabel('Memory (kb)') + + for key, sizes in fields.items(): + ax1.plot(times, [x / 1000 for x in sizes], label=key) + + ax1.legend(loc=0) + + # start both axis at 0 + ax1.set_xlim(0, ax1.get_xlim()[1]) + ax1.set_ylim(0, ax1.get_ylim()[1]) + + plt.savefig( + Path(path, f'{__name__}.pdf') + ) + return True +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/flow/main_loop/reset_bad_hosts.html b/nightly_8.3/html/_modules/cylc/flow/main_loop/reset_bad_hosts.html new file mode 100644 index 0000000000..bf3681222c --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/flow/main_loop/reset_bad_hosts.html @@ -0,0 +1,188 @@ + + + + + + + + cylc.flow.main_loop.reset_bad_hosts — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for cylc.flow.main_loop.reset_bad_hosts

+# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+"""Resets the list of bad hosts.
+
+The scheduler stores a set of hosts which it has been unable to contact to
+save contacting these hosts again.
+
+This list is cleared if a task cannot be submitted because all of the hosts it
+might use cannot be reached.
+
+If a task succeeds in submitting a job on the second host it tries, then the
+first host remains in the set of unreachable (bad) hosts, even though the
+failure might have been transitory. For this reason, this plugin periodically
+clears the set.
+
+Suggested interval - an hour.
+"""
+
+from cylc.flow.main_loop import periodic
+
+
+
+[docs] +@periodic +async def reset_bad_hosts(scheduler, _): + """Empty bad_hosts.""" + scheduler.task_events_mgr.reset_bad_hosts()
+ +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/flow/network/client.html b/nightly_8.3/html/_modules/cylc/flow/network/client.html new file mode 100644 index 0000000000..4ff7489caf --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/flow/network/client.html @@ -0,0 +1,516 @@ + + + + + + + + cylc.flow.network.client — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for cylc.flow.network.client

+# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+"""Client for workflow runtime API."""
+
+from abc import ABCMeta, abstractmethod
+import asyncio
+import os
+from shutil import which
+import socket
+import sys
+from typing import Any, Optional, Union, Dict
+
+import zmq
+import zmq.asyncio
+
+from cylc.flow import LOG
+from cylc.flow.exceptions import (
+    ClientError,
+    ClientTimeout,
+    ContactFileExists,
+    CylcError,
+    WorkflowStopped,
+)
+from cylc.flow.hostuserutil import get_fqdn_by_host
+from cylc.flow.network import (
+    encode_,
+    decode_,
+    get_location,
+    ZMQSocketBase
+)
+from cylc.flow.network.client_factory import CommsMeth
+from cylc.flow.network.server import PB_METHOD_MAP
+from cylc.flow.workflow_files import (
+    detect_old_contact_file,
+)
+
+
+class WorkflowRuntimeClientBase(metaclass=ABCMeta):
+    """Base class for WorkflowRuntimeClients.
+
+    WorkflowRuntimeClients that inherit from this must implement an async
+    method ``async_request()``. This base class provides a ``serial_request()``
+    method based on the ``async_request()`` method, callable by ``__call__``.
+    It also provides a comms timeout handler method.
+    """
+
+    DEFAULT_TIMEOUT = 5  # seconds
+
+    def __init__(
+        self,
+        workflow: str,
+        host: Optional[str] = None,
+        port: Union[int, str, None] = None,
+        timeout: Union[float, str, None] = None
+    ):
+        self.workflow = workflow
+        if not host or not port:
+            host, port, _ = get_location(workflow)
+        else:
+            port = int(port)
+        self.host = self._orig_host = host
+        self.port = self._orig_port = port
+        self.timeout = (
+            float(timeout) if timeout is not None else self.DEFAULT_TIMEOUT
+        )
+
+    @abstractmethod
+    async def async_request(
+        self,
+        command: str,
+        args: Optional[Dict[str, Any]] = None,
+        timeout: Optional[float] = None,
+        req_meta: Optional[Dict[str, Any]] = None
+    ) -> object:
+        """Send an asynchronous request."""
+        ...
+
+    def serial_request(
+        self,
+        command: str,
+        args: Optional[Dict[str, Any]] = None,
+        timeout: Optional[float] = None,
+        req_meta: Optional[Dict[str, Any]] = None
+    ) -> object:
+        """Send a request.
+
+        For convenience use ``__call__`` to call this method.
+
+        Args:
+            command: The name of the endpoint to call.
+            args: Arguments to pass to the endpoint function.
+            timeout: Override the default timeout (seconds).
+
+        Raises:
+            ClientTimeout: If a response takes longer than timeout to arrive.
+            ClientError: Coverall for all other issues including failed auth.
+
+        Returns:
+            object: The data exactly as returned from the endpoint function,
+                nothing more, nothing less.
+
+        """
+        loop = getattr(self, 'loop', asyncio.new_event_loop())
+        task = loop.create_task(
+            self.async_request(command, args, timeout, req_meta)
+        )
+        loop.run_until_complete(task)
+        if not hasattr(self, 'loop'):
+            # (If inheriting class does have an event loop, don't mess with it)
+            loop.close()
+        return task.result()
+
+    __call__ = serial_request
+
+    def timeout_handler(self) -> None:
+        """Handle the eventuality of a communication timeout with the workflow.
+
+        Raises:
+            WorkflowStopped: if the workflow has already stopped.
+            CyclError: if the workflow has moved to different host/port.
+        """
+        contact_host, contact_port, _ = get_location(self.workflow)
+        if (
+            contact_host != get_fqdn_by_host(self._orig_host)
+            or contact_port != self._orig_port
+        ):
+            raise CylcError(
+                'The workflow is no longer running at '
+                f'{self._orig_host}:{self._orig_port}\n'
+                f'It has moved to {contact_host}:{contact_port}'
+            )
+
+        if os.getenv('CYLC_TASK_COMMS_METHOD'):
+            # don't attempt to clean up old contact files in task messages
+            return
+
+        # Cannot connect, perhaps workflow is no longer running and is leaving
+        # behind a contact file?
+        try:
+            detect_old_contact_file(self.workflow)
+        except ContactFileExists:
+            # old contact file exists and the workflow process still alive
+            return
+        else:
+            # the workflow has stopped
+            raise WorkflowStopped(self.workflow)
+
+
+
+[docs] +class WorkflowRuntimeClient( # type: ignore[misc] + ZMQSocketBase, WorkflowRuntimeClientBase +): + # (Ignoring mypy 'definition of "host" in base class "ZMQSocketBase" is + # incompatible with definition in base class "WorkflowRuntimeClientBase"') + """Initiate a client to the scheduler API. + + Initiates the REQ part of a ZMQ REQ-REP pair. + + This class contains the logic for the ZMQ message interface and client - + server communication. + + Determine host and port from the contact file unless provided. + + If there is no socket bound to the specified host/port the client will + bail after ``timeout`` seconds. + + Args: + workflow: + Name of the workflow to connect to. + timeout: + Set the default timeout in seconds. The default is + ``ZMQClient.DEFAULT_TIMEOUT``. + Note the default timeout can be overridden for individual requests. + host: + The host where the flow is running if known. + + If both host and port are provided it is not necessary to load + the contact file. + port: + The port on which the REQ-REP TCP server is listening. + + If both host and port are provided it is not necessary to load + the contact file. + + Attributes: + host: + Workflow host name. + port: + Workflow host port. + timeout_handler: + Optional function which runs before ClientTimeout is raised. + This provides an interface for raising more specific exceptions in + the event of a communication timeout. + header: + Request "header" data to attach to each request. + + Usage: + Call endpoints using ``ZMQClient.__call__``. + + Message interface: + * Accepts responses of the format: {"data": {...}} + * Accepts error in the format: {"error": {"message": MSG}} + * Returns requests of the format: {"command": CMD, + "args": {...}} + + Raises: + WorkflowStopped: if the workflow is not running. + + Call server "endpoints" using: + ``__call__``, ``serial_request`` + .. automethod:: + cylc.flow.network.client.WorkflowRuntimeClient.serial_request + + ``async_request`` + .. automethod:: + cylc.flow.network.client.WorkflowRuntimeClient.async_request + + """ + # socket & event loop not None - get assigned on init by self.start(): + socket: zmq.asyncio.Socket + loop: asyncio.AbstractEventLoop + + def __init__( + self, + workflow: str, + host: Optional[str] = None, + port: Union[int, str, None] = None, + timeout: Union[float, str, None] = None, + context: Optional[zmq.asyncio.Context] = None, + srv_public_key_loc: Optional[str] = None + ): + ZMQSocketBase.__init__(self, zmq.REQ, workflow, context=context) + WorkflowRuntimeClientBase.__init__(self, workflow, host, port, timeout) + # convert to milliseconds: + self.timeout *= 1000 + self.poller: Any = None + # Connect the ZMQ socket on instantiation + self.start(self.host, self.port, srv_public_key_loc) + # gather header info post start + self.header = self.get_header() + + def _socket_options(self): + """Set socket options after socket instantiation before connect. + + Overwrites Base method. + + """ + # if there is no server don't keep the client hanging around + self.socket.setsockopt(zmq.LINGER, int(self.DEFAULT_TIMEOUT)) + + # create a poller to handle timeouts + self.poller = zmq.Poller() + self.poller.register(self.socket, zmq.POLLIN) + +
+[docs] + async def async_request( + self, + command: str, + args: Optional[Dict[str, Any]] = None, + timeout: Optional[float] = None, + req_meta: Optional[Dict[str, Any]] = None + ) -> object: + """Send an asynchronous request using asyncio. + + Has the same arguments and return values as ``serial_request``. + + """ + timeout = (float(timeout) * 1000 if timeout else None) or self.timeout + if not args: + args = {} + + # Note: we are using CurveZMQ to secure the messages (see + # self.curve_auth, self.socket.curve_...key etc.). We have set up + # public-key cryptography on the ZMQ messaging and sockets, so + # there is no need to encrypt messages ourselves before sending. + + # send message + msg: Dict[str, Any] = {'command': command, 'args': args} + msg.update(self.header) + # add the request metadata + if req_meta: + msg['meta'].update(req_meta) + LOG.debug('zmq:send %s', msg) + message = encode_(msg) + self.socket.send_string(message) + + # receive response + if self.poller.poll(timeout): + res = await self.socket.recv() + else: + self.timeout_handler() + raise ClientTimeout( + 'Timeout waiting for server response.' + ' This could be due to network or server issues.' + '\n* You might want to increase the timeout using the' + ' --comms-timeout option;' + '\n* or check the workflow log.' + ) + + if msg['command'] in PB_METHOD_MAP: + response = {'data': res} + else: + response = decode_( + res.decode() if isinstance(res, bytes) else res + ) + LOG.debug('zmq:recv %s', response) + + try: + return response['data'] + except KeyError: + error = response.get( + 'error', + {'message': f'Received invalid response: {response}'}, + ) + raise ClientError( + error.get('message'), # type: ignore + error.get('traceback'), # type: ignore + )
+ + + def get_header(self) -> dict: + """Return "header" data to attach to each request for traceability. + + Returns: + dict: dictionary with the header information, such as + program and hostname. + """ + host = socket.gethostname() + if len(sys.argv) > 1: + cmd = sys.argv[1] + else: + cmd = sys.argv[0] + + cylc_executable_location = which("cylc") + if cylc_executable_location: + cylc_bin_dir = os.path.abspath( + os.path.join(cylc_executable_location, os.pardir) + ) + if not cylc_bin_dir.endswith("/"): + cylc_bin_dir = f"{cylc_bin_dir}/" + + if cmd.startswith(cylc_bin_dir): + cmd = cmd.replace(cylc_bin_dir, '') + return { + 'meta': { + 'prog': cmd, + 'host': host, + 'comms_method': + os.getenv( + "CLIENT_COMMS_METH", + default=CommsMeth.ZMQ.value + ) + } + }
+ +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/flow/network/server.html b/nightly_8.3/html/_modules/cylc/flow/network/server.html new file mode 100644 index 0000000000..1faaf0aa0b --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/flow/network/server.html @@ -0,0 +1,610 @@ + + + + + + + + cylc.flow.network.server — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for cylc.flow.network.server

+# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+"""Server for workflow runtime API."""
+
+import asyncio
+from queue import Queue
+from textwrap import dedent
+from time import sleep
+from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Union
+
+from graphql.execution.executors.asyncio import AsyncioExecutor
+import zmq
+from zmq.auth.thread import ThreadAuthenticator
+
+from cylc.flow import LOG, workflow_files
+from cylc.flow.cfgspec.glbl_cfg import glbl_cfg
+from cylc.flow.network.authorisation import authorise
+from cylc.flow.network.graphql import (
+    CylcGraphQLBackend, IgnoreFieldMiddleware, instantiate_middleware
+)
+from cylc.flow.network.publisher import WorkflowPublisher
+from cylc.flow.network.replier import WorkflowReplier
+from cylc.flow.network.resolvers import Resolvers
+from cylc.flow.network.schema import schema
+from cylc.flow.data_store_mgr import DELTAS_MAP
+from cylc.flow.data_messages_pb2 import PbEntireWorkflow
+
+if TYPE_CHECKING:
+    from cylc.flow.scheduler import Scheduler
+    from graphql.execution import ExecutionResult
+
+
+# maps server methods to the protobuf message (for client/UIS import)
+PB_METHOD_MAP: Dict[str, Any] = {
+    'pb_entire_workflow': PbEntireWorkflow,
+    'pb_data_elements': DELTAS_MAP
+}
+
+
+def expose(func=None):
+    """Expose a method on the sever."""
+    func.exposed = True
+    return func
+
+
+def filter_none(dictionary):
+    """Filter out `None` items from a dictionary:
+
+    Examples:
+        >>> filter_none({
+        ...     'a': 0,
+        ...     'b': '',
+        ...     'c': None
+        ... })
+        {'a': 0, 'b': ''}
+
+    """
+    return {
+        key: value
+        for key, value in dictionary.items()
+        if value is not None
+    }
+
+
+
+[docs] +class WorkflowRuntimeServer: + """Workflow runtime service API facade exposed via zmq. + + This class starts and coordinates the publisher and replier, and + contains the Cylc endpoints invoked by the receiver to provide a response + to incoming messages. + + Args: + schd (object): The parent object instantiating the server. In + this case, the workflow scheduler. + + Usage: + * Define endpoints using the ``expose`` decorator. + * Endpoints are called via the receiver using the function name. + + Message interface: + * Accepts messages of the format: {"command": CMD, "args": {...}} + * Returns responses of the format: {"data": {...}} + * Returns error in the format: {"error": {"message": MSG}} + + Common Arguments: + Arguments which are shared between multiple commands. + + task identifier (str): + A task identifier in the format ``cycle-point/task-name`` + e.g. ``1/foo`` or ``20000101T0000Z/bar``. + + .. _task globs: + + task globs (list): + A list of Cylc IDs relative to the workflow. + + * ``1`` - The cycle point "1". + * ``1/foo`` - The task "foo" in the cycle "1". + * ``1/foo/01`` - The first job of the task "foo" from the cycle + "1". + + Glob-like patterns may be used to match multiple items e.g. + + ``*`` + Matches everything. + ``1/*`` + Matches everything in cycle ``1``. + ``*/*:failed`` + Matches all failed tasks. + + """ + endpoints: Dict[str, object] + + OPERATE_SLEEP_INTERVAL = 0.2 + STOP_SLEEP_INTERVAL = 0.2 + + def __init__(self, schd): + + self.zmq_context = None + self.port = None + self.pub_port = None + self.replier = None + self.publisher = None + self.loop = None + self.thread = None + self.curve_auth = None + self.client_pub_key_dir = None + + self.schd: 'Scheduler' = schd + self.resolvers = Resolvers( + self.schd.data_store_mgr, + schd=self.schd + ) + self.middleware = [ + IgnoreFieldMiddleware, + ] + + self.publish_queue: 'Queue[Iterable[tuple]]' = Queue() + self.waiting_to_stop = False + self.stopped = True + + self.register_endpoints() + +
+[docs] + def start(self, barrier): + """Start the TCP servers.""" + # set asyncio loop on thread + try: + self.loop = asyncio.get_running_loop() + except RuntimeError: + self.loop = asyncio.new_event_loop() + asyncio.set_event_loop(self.loop) + + # TODO: this in zmq asyncio context? + # Requires the scheduler main loop in asyncio first + # And use of concurrent.futures.ThreadPoolExecutor? + self.zmq_context = zmq.Context() + # create an authenticator for the ZMQ context + self.curve_auth = ThreadAuthenticator(self.zmq_context, log=LOG) + self.curve_auth.start() # start the authentication thread + + # Setting the location means that the CurveZMQ auth will only + # accept public client certificates from the given directory, as + # generated by a user when they initiate a ZMQ socket ready to + # connect to a server. + workflow_srv_dir = workflow_files.get_workflow_srv_dir( + self.schd.workflow) + client_pub_keyinfo = workflow_files.KeyInfo( + workflow_files.KeyType.PUBLIC, + workflow_files.KeyOwner.CLIENT, + workflow_srv_dir=workflow_srv_dir) + self.client_pub_key_dir = client_pub_keyinfo.key_path + + # Initial load for the localhost key. + self.curve_auth.configure_curve( + domain='*', + location=(self.client_pub_key_dir) + ) + + min_, max_ = glbl_cfg().get(['scheduler', 'run hosts', 'ports']) + self.replier = WorkflowReplier(self, context=self.zmq_context) + self.replier.start(min_, max_) + self.publisher = WorkflowPublisher( + self.schd.workflow, context=self.zmq_context + ) + self.publisher.start(min_, max_) + self.port = self.replier.port + self.pub_port = self.publisher.port + self.schd.data_store_mgr.delta_workflow_ports() + + # wait for threads to setup socket ports before continuing + barrier.wait() + + self.stopped = False + + self.operate()
+ + +
+[docs] + async def stop(self, reason: Union[BaseException, str]) -> None: + """Stop the TCP servers, and clean up authentication. + + This method must be called/awaited from a different thread to the + server's self.thread in order to interrupt the self.operate() loop + and wait for self.thread to terminate. + """ + self.waiting_to_stop = True + if self.thread and self.thread.is_alive(): + # Wait for self.operate() loop to finish: + while self.waiting_to_stop: + # Non-async sleep - yield to other threads rather than + # event loop (allows self.operate() running in different + # thread to return) + sleep(self.STOP_SLEEP_INTERVAL) + + if self.replier: + self.replier.stop(stop_loop=False) + if self.publisher: + await self.publish_queued_items() + await self.publisher.publish( + (b'shutdown', str(reason).encode('utf-8')) + ) + self.publisher.stop(stop_loop=False) + self.publisher = None + if self.curve_auth: + self.curve_auth.stop() # stop the authentication thread + if self.loop and self.loop.is_running(): + self.loop.stop() + if self.thread and self.thread.is_alive(): + self.thread.join() # Wait for processes to return + + self.stopped = True
+ + +
+[docs] + def operate(self) -> None: + """Orchestrate the receive, send, publish of messages.""" + # Note: this cannot be an async method because the response part + # of the listener runs the event loop synchronously + # (in graphql AsyncioExecutor) + while True: + if self.waiting_to_stop: + # The self.stop() method is waiting for us to signal that we + # have finished here + self.waiting_to_stop = False + return + + # Gather and respond to any requests. + self.replier.listener() + # Publish all requested/queued. + self.loop.run_until_complete(self.publish_queued_items()) + + # Yield control to other threads + sleep(self.OPERATE_SLEEP_INTERVAL)
+ + +
+[docs] + async def publish_queued_items(self) -> None: + """Publish all queued items.""" + while self.publish_queue.qsize(): + articles = self.publish_queue.get() + await self.publisher.publish(*articles)
+ + +
+[docs] + def receiver(self, message): + """Process incoming messages and coordinate response. + + Wrap incoming messages, dispatch them to exposed methods and/or + coordinate a publishing stream. + + Args: + message (dict): message contents + """ + # TODO: If requested, coordinate publishing response/stream. + + # determine the server method to call + try: + method = getattr(self, message['command']) + args = message['args'] + args.update({'user': message['user']}) + if 'meta' in message: + args['meta'] = message['meta'] + except KeyError: + # malformed message + return {'error': { + 'message': 'Request missing required field(s).'}} + except AttributeError: + # no exposed method by that name + return {'error': { + 'message': 'No method by the name "%s"' % message['command']}} + + # generate response + try: + response = method(**args) + except Exception as exc: + # includes incorrect arguments (TypeError) + LOG.exception(exc) # note the error server side + import traceback + return {'error': { + 'message': str(exc), 'traceback': traceback.format_exc()}} + + return {'data': response}
+ + +
+[docs] + def register_endpoints(self): + """Register all exposed methods.""" + self.endpoints = {name: obj + for name, obj in self.__class__.__dict__.items() + if hasattr(obj, 'exposed')}
+ + +
+[docs] + @authorise() + @expose + def api( + self, + endpoint: Optional[str] = None, + **_kwargs + ) -> Union[str, List[str]]: + """Return information about this API. + + Returns a list of callable endpoints. + + Args: + endpoint: + If specified the documentation for the endpoint + will be returned instead. + + Returns: + List of endpoints or string documentation of the + requested endpoint. + + """ + if not endpoint: + return [ + method for method in dir(self) + if getattr(getattr(self, method), 'exposed', False) + ] + + try: + method = getattr(self, endpoint) + except AttributeError: + return 'No method by name "%s"' % endpoint + if method.exposed: + head, tail = method.__doc__.split('\n', 1) + tail = dedent(tail) + return '%s\n%s' % (head, tail) + return 'No method by name "%s"' % endpoint
+ + +
+[docs] + @authorise() + @expose + def graphql( + self, + request_string: Optional[str] = None, + variables: Optional[Dict[str, Any]] = None, + meta: Optional[Dict[str, Any]] = None + ): + """Return the GraphQL schema execution result. + + Args: + request_string: GraphQL request passed to Graphene. + variables: Dict of variables passed to Graphene. + meta: Dict containing auth user etc. + + Returns: + object: Execution result, or a list with errors. + """ + try: + executed: 'ExecutionResult' = schema.execute( + request_string, + variable_values=variables, + context_value={ + 'resolvers': self.resolvers, + 'meta': meta or {}, + }, + backend=CylcGraphQLBackend(), + middleware=list(instantiate_middleware(self.middleware)), + executor=AsyncioExecutor(), + validate=True, # validate schema (dev only? default is True) + return_promise=False, + ) + except Exception as exc: + return 'ERROR: GraphQL execution error \n%s' % exc + if executed.errors: + errors: List[Any] = [] + for error in executed.errors: + LOG.error(error) + if hasattr(error, '__traceback__'): + import traceback + formatted_tb = traceback.format_exception( + type(error), error, error.__traceback__ + ) + LOG.error("".join(formatted_tb)) + errors.append({ + 'error': { + 'message': str(error), + 'traceback': formatted_tb + } + }) + continue + errors.append(getattr(error, 'message', None)) + return errors + return executed.data
+ + + # UIServer Data Commands +
+[docs] + @authorise() + @expose + def pb_entire_workflow(self, **_kwargs) -> bytes: + """Send the entire data-store in a single Protobuf message. + + Returns serialised Protobuf message + + """ + pb_msg = self.schd.data_store_mgr.get_entire_workflow() + return pb_msg.SerializeToString()
+ + +
+[docs] + @authorise() + @expose + def pb_data_elements(self, element_type: str, **_kwargs) -> bytes: + """Send the specified data elements in delta form. + + Args: + element_type: Key from DELTAS_MAP dictionary. + + Returns serialised Protobuf message + + """ + pb_msg = self.schd.data_store_mgr.get_data_elements(element_type) + return pb_msg.SerializeToString()
+
+ +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/flow/parsec/exceptions.html b/nightly_8.3/html/_modules/cylc/flow/parsec/exceptions.html new file mode 100644 index 0000000000..847a6dfc9d --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/flow/parsec/exceptions.html @@ -0,0 +1,456 @@ + + + + + + + + cylc.flow.parsec.exceptions — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for cylc.flow.parsec.exceptions

+# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+
+from copy import copy
+import os
+import textwrap
+import typing as t
+
+from cylc.flow.parsec.util import itemstr
+
+
+TRACEBACK_WRAPPER = textwrap.TextWrapper()
+
+
+
+[docs] +class ParsecError(Exception): + """Generic exception for Parsec errors.""" + + schd_expected: bool = False + """Set this flag to True on the exception if it is anticipated during + Cylc Scheduler run (apart from loading of config we do not expect + ParsecErrors during runtime)."""
+ + + +
+[docs] +class ItemNotFoundError(ParsecError, KeyError): + """Error raised for missing configuration items.""" + + def __init__(self, item): + self.item = item + + def __str__(self): + return f'You have not set \"{self.item}\" in this config.'
+ + + +
+[docs] +class InvalidConfigError(ParsecError, KeyError): + """Error raised for missing configuration items.""" + + def __init__(self, item, specname): + self.item = item + self.specname = specname + + def __str__(self): + return ( + f'"{self.item}" is not a valid ' + f'configuration for {self.specname}.' + )
+ + + +
+[docs] +class NotSingleItemError(ParsecError, TypeError): + """Error raised if an iterable is given where an item is expected.""" + + def __init__(self, item): + self.item = item + + def __str__(self): + return f'not a singular item: {self.item}'
+ + + +
+[docs] +class FileParseError(ParsecError): + """Error raised when attempting to read in the config file(s). + + Args: + reason: + Description of error. + err_type: + Classification of error (e.g. Jinja2Error). + help_lines: + Additional info to include in the exception. + lines: + (preferred) Dictionary in the format + {filename: [context_line, ..., error_line]} + index: + The line number of the error in the config (counting from the + shebang line *not* the first line). + line: + The line of the error in the config. + fpath: + The path to the file containing the error. + + """ + + def __init__( + self, + reason: str, + index: t.Optional[int] = None, + line: t.Optional[str] = None, + lines: t.Optional[t.Dict[str, t.List[str]]] = None, + err_type: t.Optional[str] = None, + fpath: t.Optional[str] = None, + help_lines: t.Optional[t.Iterable[str]] = None, + ): + self.reason = reason + self.line_num = index + 1 if index is not None else None + self.line = line + self.lines = lines + self.err_type = err_type + self.fpath = fpath + self.help_lines = help_lines or [] + + def __str__(self) -> str: + msg = '' + msg += self.reason + + if self.line_num is not None or self.fpath: + temp = [] + if self.fpath: + temp.append(f'in {self.fpath}') + if self.line_num is not None: + temp.append(f'line {self.line_num}') + msg += f' ({" ".join(temp)})' + if self.line: + msg += ":\n " + self.line.strip() + if self.lines: + for filename, lines in self.lines.items(): + msg += f'\nFile {filename}\n ' + '\n '.join(lines) + msg += "\t<--" + if self.err_type: + msg += ' %s' % self.err_type + help_lines = list(self.help_lines) + if self.line_num: + # TODO - make 'view' function independent of cylc: + help_lines.append("line numbers match 'cylc view -p'") + for help_line in help_lines: + msg += f'\n({help_line})' + return msg
+ + + +
+[docs] +class TemplateVarLanguageClash(FileParseError): + """Multiple workflow configuration templating engines configured."""
+ + + +
+[docs] +class EmPyError(FileParseError): + """Wrapper class for EmPy exceptions."""
+ + + +
+[docs] +class Jinja2Error(FileParseError): + """Wrapper class for Jinja2 exceptions. + + Args: + exception: + The exception being re-raised + lines: + Dictionary in the format + {filename: [context_line, ..., error_line]} + filename: + Alternative to "lines" where less detail is available. + + """ + + def __init__( + self, + exception: Exception, + lines: t.Optional[t.Dict[str, t.List[str]]] = None, + filename: t.Optional[str] = None, + ): + # extract the first sentence of exception + msg: str = str(exception) + try: + msg, tail = msg.split('. ', 1) + except ValueError: + tail = '' + else: + msg += '.' + tail = tail.strip() + + # append the filename e.g. for a Jinja2 template + if filename: + msg += f'\nError in file "{filename}"' + + # append the rest of the exception + if tail: + msg += '\n' + '\n'.join(TRACEBACK_WRAPPER.wrap(tail)) + + FileParseError.__init__( + self, + msg, + lines=lines, + err_type=exception.__class__.__name__ + )
+ + + +
+[docs] +class IncludeFileNotFoundError(ParsecError): + """Error raised for missing include files.""" + + def __init__(self, flist): + """Missing include file error. + + E.g. for [DIR/top.cylc, DIR/inc/sub.cylc, DIR/inc/gone.cylc] + "Include-file not found: inc/gone.cylc via inc/sub.cylc from + DIR/top.cylc" + """ + rflist = copy(flist) + top_file = rflist[0] + top_dir = os.path.dirname(top_file) + '/' + rflist.reverse() + msg = rflist[0].replace(top_dir, '') + for f in rflist[1:-1]: + msg += ' via %s' % f.replace(top_dir, '') + msg += ' from %s' % top_file + ParsecError.__init__(self, msg)
+ + + +
+[docs] +class UpgradeError(ParsecError): + """Error raised upon fault in an upgrade operation."""
+ + + +
+[docs] +class ValidationError(ParsecError): + """Generic exception for invalid configurations.""" + + def __init__(self, keys, value=None, msg=None, exc=None, vtype=None, + key=None): + self.keys = keys + self.value = value + self.msg = msg + self.exc = exc + self.vtype = vtype + self.key = key + + def __str__(self): + msg = '' + if self.vtype: + msg += f'(type={self.vtype}) ' + if self.key: + msg += itemstr(self.keys, self.key) + elif self.value: + msg += itemstr(self.keys[:-1], self.keys[-1], value=self.value) + if self.msg or self.exc: + msg += ( + f' - ({self.exc or ""}' + f'{": " if (self.exc and self.msg) else ""}' + f'{self.msg or ""})' + ) + return msg
+ + + +
+[docs] +class IllegalValueError(ValidationError): + """Bad setting value.""" + + def __init__(self, vtype, keys, value, exc=None, msg=None): + ValidationError.__init__( + self, keys, vtype=vtype, value=value, exc=exc, msg=msg)
+ + + +
+[docs] +class ListValueError(IllegalValueError): + """Bad setting value, for a comma separated list.""" + + def __init__(self, keys, value, msg=None, exc=None): + IllegalValueError.__init__( + self, 'list', keys, value, exc=exc, msg=msg)
+ + + +
+[docs] +class IllegalItemError(ValidationError): + """Bad setting section or option name.""" + + def __init__(self, keys, key, msg=None, exc=None): + ValidationError.__init__(self, keys, key=key, exc=exc, msg=msg)
+ +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/flow/unicode_rules.html b/nightly_8.3/html/_modules/cylc/flow/unicode_rules.html new file mode 100644 index 0000000000..0289bc27ed --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/flow/unicode_rules.html @@ -0,0 +1,528 @@ + + + + + + + + cylc.flow.unicode_rules — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for cylc.flow.unicode_rules

+# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+
+"""Module for unicode restrictions"""
+
+import re
+
+from cylc.flow.task_id import (
+    _TASK_NAME_CHARACTERS,
+    _TASK_NAME_PREFIX,
+)
+from cylc.flow.task_qualifiers import TASK_QUALIFIERS
+from cylc.flow.task_state import TASK_STATUSES_ORDERED
+
+ENGLISH_REGEX_MAP = {
+    r'\w': 'alphanumeric',
+    r'a-zA-Z0-9': 'latin letters and numbers',
+    r'\d': 'numbers',
+    r'\-': '``-``',
+    r'\.': '``.``',
+    r'\/': '``/``'
+}
+
+
+def regex_chars_to_text(chars):
+    r"""Return a string representing a regex component.
+
+    Examples:
+        >>> regex_chars_to_text(['a', 'b', 'c'])
+        ['``a``', '``b``', '``c``']
+        >>> regex_chars_to_text([r'\-', r'\.', r'\/'])
+        ['``-``', '``.``', '``/``']
+        >>> regex_chars_to_text([r'\w'])
+        ['alphanumeric']
+        >>> regex_chars_to_text(['not_in_map'])
+        ['``not_in_map``']
+
+    """
+    return [
+        ENGLISH_REGEX_MAP.get(char, f'``{char}``')
+        for char in chars
+    ]
+
+
+def length(minimum, maximum):
+    """Restrict character length.
+
+    Example:
+        >>> regex, message = length(0, 5)
+        >>> message
+        'must be between 0 and 5 characters long'
+        >>> bool(regex.match('abcde'))
+        True
+        >>> bool(regex.match('abcdef'))
+        False
+
+    """
+    return (
+        re.compile(r'^.{%d,%d}$' % (minimum, maximum)),
+        f'must be between {minimum} and {maximum} characters long'
+    )
+
+
+def allowed_characters(*chars):
+    """Restrict permitted characters.
+
+    Example:
+        >>> regex, message = allowed_characters('a', 'b', 'c')
+        >>> message
+        'can only contain: ``a``, ``b``, ``c``'
+        >>> bool(regex.match('abc'))
+        True
+        >>> bool(regex.match('def'))
+        False
+
+    """
+    return (
+        re.compile(r'^[%s]+$' % ''.join(chars)),
+        f'can only contain: {", ".join(regex_chars_to_text(chars))}'
+    )
+
+
+def disallowed_characters(*chars):
+    """Restrict permitted characters.
+
+    Example:
+        >>> regex, message = disallowed_characters('&', '~')
+        >>> message
+        'cannot contain: ``&``, ``~``'
+        >>> bool(regex.match('abc01'))
+        True
+        >>> bool(regex.match('abc&01'))
+        False
+
+    """
+    return (
+        re.compile(r'^[^%s]*$' % ''.join(chars)),
+        f'cannot contain: {", ".join(regex_chars_to_text(chars))}'
+    )
+
+
+def starts_with(*chars):
+    """Restrict first character.
+
+    Example:
+        >>> regex, message = starts_with('a', 'b', 'c')
+        >>> message
+        'must start with: ``a``, ``b``, ``c``'
+        >>> bool(regex.match('def'))
+        False
+        >>> bool(regex.match('adef'))
+        True
+
+    """
+    return (
+        re.compile(r'^[%s]' % ''.join(chars)),
+        f'must start with: {", ".join(regex_chars_to_text(chars))}'
+    )
+
+
+def not_starts_with_char(*chars):
+    """Restrict first character.
+
+    Example:
+        >>> regex, message = not_starts_with_char('a', 'b', 'c')
+        >>> message
+        'cannot start with: ``a``, ``b``, ``c``'
+        >>> bool(regex.match('def'))
+        True
+        >>> bool(regex.match('adef'))
+        False
+
+    """
+    return (
+        re.compile(r'^[^%s]' % ''.join(chars)),
+        f'cannot start with: {", ".join(regex_chars_to_text(chars))}'
+    )
+
+
+def not_starts_with(string):
+    """Restrict strings starting with ___.
+
+    Example:
+        Regular usage:
+        >>> regex, message = not_starts_with('foo')
+        >>> message
+        'cannot start with: ``foo``'
+        >>> bool(regex.match('tfoo'))
+        True
+        >>> bool(regex.match('foot'))
+        False
+
+        Note regex chars are escaped automatically:
+        >>> regex, message = not_starts_with('...')
+        >>> bool(regex.match('aaa b'))
+        True
+        >>> bool(regex.match('... b'))
+        False
+
+    """
+    return (
+        re.compile(rf'^(?!{re.escape(string)})'),
+        f'cannot start with: ``{string}``'
+    )
+
+
+def _human_format_list(lst):
+    """Write a list in plain text.
+
+    Examples:
+        >>> _human_format_list(['a'])
+        'a'
+        >>> _human_format_list(['a', 'b'])
+        'a or b'
+        >>> _human_format_list(['a', 'b', 'c'])
+        'a, b or c'
+
+    """
+    if len(lst) > 1:
+        return ', '.join(lst[:-1]) + f' or {lst[-1]}'
+    return lst[0]
+
+
+def _re_format_list(lst):
+    """Write a list in regex format.
+
+    Examples:
+        >>> _re_format_list('a')
+        '(a)'
+        >>> _re_format_list(['a', 'b'])
+        '(a|b)'
+        >>> _re_format_list(['a', 'b', 'c'])
+        '(a|b|c)'
+
+    """
+    return f"({'|'.join(map(re.escape, lst))})"
+
+
+def not_equals(*strings):
+    r"""Restrict entire string.
+
+    Example:
+        Regular usage:
+        >>> regex, message = not_equals('foo')
+        >>> message
+        'cannot be: ``foo``'
+        >>> bool(regex.match('foot'))  # "foot" shouldn't match
+        True
+        >>> bool(regex.match('a\nb'))  # newlines should be tolerated
+        True
+        >>> bool(regex.match('foo'))   # "foo" should match
+        False
+
+        Regular use (multi):
+        >>> regex, message = not_equals('foo', 'bar', 'baz')
+        >>> regex.pattern
+        '^(?!^(foo|bar|baz)$).*$'
+        >>> message
+        'cannot be: ``foo``, ``bar`` or ``baz``'
+
+        Note regex chars are escaped automatically:
+        >>> regex, message = not_equals('...')
+        >>> bool(regex.match('...'))
+        False
+        >>> bool(regex.match('aaa'))
+        True
+
+    """
+    return (
+        re.compile(rf'^(?!^{_re_format_list(strings)}$).*$', re.M),
+        'cannot be: ' + _human_format_list([f'``{s}``' for s in strings])
+    )
+
+
+def disallow_char_if_not_at_end_of_first_word(char):
+    """Prevent use of a (non-alphanumeric) character unless it occurs directly
+    after first word (in which case there is no limit on subsequent
+    occurances).
+
+    Example:
+        >>> regex, message = disallow_char_if_not_at_end_of_first_word(':')
+        >>> message
+        'cannot contain ``:`` unless it occurs at the end of the first word'
+        >>> bool(regex.match('Foo: bar'))
+        True
+        >>> bool(regex.match('INFO: Foo: bar'))
+        True
+        >>> bool(regex.match('Foo bar: baz'))
+        False
+        >>> bool(regex.match('Foo bar'))
+        True
+
+    """
+    return (
+        re.compile(fr'^(\w+{char}.*|[^{char}]+)$', flags=re.S),
+        f'cannot contain ``{char}`` unless it occurs at the end of the '
+        'first word'
+    )
+
+
+class UnicodeRuleChecker():
+
+    RULES: list = []
+
+    @classmethod
+    def __init_subclass__(cls):
+        cls.__doc__ = cls.__doc__ + '\n' if cls.__doc__ else ''
+        cls.__doc__ += '\n' + '\n'.join([
+            f'* {message}'
+            for regex, message in cls.RULES
+        ])
+
+    @classmethod
+    def validate(cls, string):
+        """Run this collection of rules against the given string.
+
+        Args:
+            string (str):
+                String to validate.
+
+        Returns:
+            tuple - (outcome, message)
+            outcome (bool) - True if all patterns match.
+            message (str) - User-friendly error message.
+
+        """
+        for rule, message in cls.RULES:
+            if not rule.match(string):
+                return (
+                    False,
+                    # convert RST style literals to Markdown for error messages
+                    # (RST used in docs)
+                    message.replace('``', '`'),
+                )
+        return (True, None)
+
+
+
+[docs] +class WorkflowNameValidator(UnicodeRuleChecker): + """The rules for valid workflow names:""" + + RULES = [ + length(1, 254), + not_starts_with_char(r'\.', r'\-', r'\d'), + allowed_characters(r'\w', r'\/', '_', '+', r'\-', r'\.', '@'), + ]
+ + + +
+[docs] +class XtriggerNameValidator(UnicodeRuleChecker): + """The rules for valid xtrigger labels:""" + + RULES = [ + allowed_characters(r'a-zA-Z0-9', '_'), + not_starts_with('_cylc'), + ]
+ + + +
+[docs] +class TaskMessageValidator(UnicodeRuleChecker): + """The rules for valid task messages:""" + + RULES = [ + # <severity>:<message> e.g. "WARN: something went wrong + disallow_char_if_not_at_end_of_first_word(':'), + # blacklist built-in qualifiers + # (technically we need only blacklist task messages, however, to avoid + # confusion it's best to blacklist qualifiers too) + not_equals(*TASK_QUALIFIERS), + not_starts_with('_cylc'), + ]
+ + + +
+[docs] +class TaskOutputValidator(UnicodeRuleChecker): + """The rules for valid task outputs/message triggers:""" + + RULES = [ + # restrict outputs to sensible characters + allowed_characters(r'\w', r'\d', r'\-'), + # blacklist the _cylc prefix + not_starts_with('_cylc'), + # blacklist keywords + not_equals('required', 'optional', 'all', 'and', 'or'), + # blacklist built-in task qualifiers and statuses (e.g. "waiting") + not_equals(*sorted({*TASK_QUALIFIERS, *TASK_STATUSES_ORDERED})), + ]
+ + + +
+[docs] +class TaskNameValidator(UnicodeRuleChecker): + """The rules for valid task and family names:""" + + RULES = [ + starts_with(_TASK_NAME_PREFIX), + allowed_characters(*_TASK_NAME_CHARACTERS), + not_starts_with('_cylc'), + not_equals('root'), + ]
+ +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/flow/xtriggers/echo.html b/nightly_8.3/html/_modules/cylc/flow/xtriggers/echo.html new file mode 100644 index 0000000000..cd3d457c05 --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/flow/xtriggers/echo.html @@ -0,0 +1,213 @@ + + + + + + + + cylc.flow.xtriggers.echo — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for cylc.flow.xtriggers.echo

+# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+
+"""A Cylc xtrigger function."""
+
+from typing import Any, Dict, Tuple
+from cylc.flow.exceptions import WorkflowConfigError
+
+
+
+[docs] +def echo(*args, **kwargs) -> Tuple: + """Print arguments to stdout, return kwargs['succeed'] and kwargs. + + This may be a useful aid to understanding how xtriggers work. + + Args: + succeed: Set the success of failure of this xtrigger. + *args: Print to stdout. + **kwargs: Print to stdout, and return as output. + + Returns: + (True/False, kwargs) + + Examples: + + >>> echo('Breakfast Time', succeed=True, egg='poached') + echo: ARGS: ('Breakfast Time',) + echo: KWARGS: {'succeed': True, 'egg': 'poached'} + (True, {'succeed': True, 'egg': 'poached'}) + + """ + print("echo: ARGS:", args) + print("echo: KWARGS:", kwargs) + + return kwargs["succeed"], kwargs
+ + + +def validate(all_args: Dict[str, Any]): + """ + Validate the xtrigger function arguments parsed from the workflow config. + + This is separate from the xtrigger to allow parse-time validation. + + """ + # NOTE: with (*args, **kwargs) pattern, all_args looks like: + # { + # 'args': (arg1, arg2, ...), + # 'kwargs': {kwarg1: val, kwarg2: val, ...} + # } + succeed = all_args['kwargs'].get("succeed") + if not isinstance(succeed, bool): + raise WorkflowConfigError("Requires 'succeed=True/False' arg") +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/flow/xtriggers/wall_clock.html b/nightly_8.3/html/_modules/cylc/flow/xtriggers/wall_clock.html new file mode 100644 index 0000000000..ec845ae530 --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/flow/xtriggers/wall_clock.html @@ -0,0 +1,227 @@ + + + + + + + + cylc.flow.xtriggers.wall_clock — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for cylc.flow.xtriggers.wall_clock

+# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+
+"""xtrigger function to trigger off of a wall clock time."""
+
+from time import time
+from typing import Any, Dict
+from cylc.flow.cycling.iso8601 import interval_parse
+from cylc.flow.exceptions import WorkflowConfigError
+
+
+
+[docs] +def wall_clock(offset: str = 'PT0S', sequential: bool = True): + """Trigger at a specific real "wall clock" time relative to the cycle point + in the graph. + + Clock triggers, unlike other trigger functions, are executed synchronously + in the main process. + + Args: + offset: + ISO 8601 interval to wait after the cycle point is reached in real + time before triggering. May be negative, in which case it will + trigger before the real time reaches the cycle point. + sequential: + Wall-clock xtriggers are run sequentially by default. + See :ref:`Sequential Xtriggers` for more details. + + .. versionchanged:: 8.3.0 + + The ``sequential`` argument was added. + """ + # NOTE: This is just a placeholder for the actual implementation. + # This is only used for validating the signature and for autodocs. + ...
+ + + +def _wall_clock(trigger_time: int) -> bool: + """Actual implementation of wall_clock. + + Return True after the desired wall clock time, or False before. + + Args: + trigger_time: + Trigger time as seconds since Unix epoch. + sequential (bool): + Used by the workflow to flag corresponding xtriggers as sequential. + """ + return time() > trigger_time + + +def validate(args: Dict[str, Any]): + """Validate and manipulate args parsed from the workflow config. + + NOTE: the xtrigger signature is different to the function signature above + + wall_clock() # infer zero interval + wall_clock(PT1H) + wall_clock(offset=PT1H) + + The offset must be a valid ISO 8601 interval. + """ + try: + interval_parse(args["offset"]) + except (ValueError, AttributeError): + raise WorkflowConfigError(f"Invalid offset: {args['offset']}") +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/flow/xtriggers/workflow_state.html b/nightly_8.3/html/_modules/cylc/flow/xtriggers/workflow_state.html new file mode 100644 index 0000000000..da14bf93e2 --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/flow/xtriggers/workflow_state.html @@ -0,0 +1,416 @@ + + + + + + + + cylc.flow.xtriggers.workflow_state — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+
    +
  • + + +
  • +
  • +
+
+
+
+
+ +

Source code for cylc.flow.xtriggers.workflow_state

+# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+
+from typing import Dict, Optional, Tuple, Any
+import asyncio
+from inspect import signature
+
+from cylc.flow.scripts.workflow_state import WorkflowPoller
+from cylc.flow.id import tokenise
+from cylc.flow.exceptions import WorkflowConfigError, InputError
+from cylc.flow.task_state import TASK_STATUS_SUCCEEDED
+from cylc.flow.dbstatecheck import check_polling_config
+
+
+DEFAULT_STATUS = TASK_STATUS_SUCCEEDED
+
+
+
+[docs] +def workflow_state( + workflow_task_id: str, + offset: Optional[str] = None, + flow_num: Optional[int] = None, + is_trigger: bool = False, + is_message: bool = False, + alt_cylc_run_dir: Optional[str] = None, +) -> Tuple[bool, Dict[str, Any]]: + """Connect to a workflow DB and check a task status or output. + + If the status or output has been achieved, return {True, result}. + + Args: + workflow_task_id: + ID (workflow//point/task:selector) of the target task. + offset: + Offset from cycle point as an ISO8601 or integer duration, + e.g. PT1H (1 hour) or P1 (1 integer cycle) + flow_num: + Flow number of the target task. + is_trigger: + Interpret the task:selector as a task trigger name rather than a + task status. + is_message: + Interpret the task:selector as a task output message rather than a + task status. + alt_cylc_run_dir: + Alternate cylc-run directory, e.g. for another user. + + Returns: + tuple: (satisfied, result) + + satisfied: + True if ``satisfied`` else ``False``. + result: + Dict containing the keys: + + * ``workflow`` + * ``task`` + * ``point`` + * ``offset`` + * ``status`` + * ``message`` + * ``trigger`` + * ``flow_num`` + * ``run_dir`` + + .. versionchanged:: 8.3.0 + + The ``workflow_task_id`` argument was introduced to replace the + separate ``workflow``, ``point``, ``task``, ``status``, and ``message`` + arguments (which are still supported for backwards compatibility). + The ``flow_num`` argument was added. The ``cylc_run_dir`` argument + was renamed to ``alt_cylc_run_dir``. + """ + poller = WorkflowPoller( + workflow_task_id, + offset, + flow_num, + alt_cylc_run_dir, + DEFAULT_STATUS, + is_trigger, is_message, + old_format=False, + condition=workflow_task_id, + max_polls=1, # (for xtriggers the scheduler does the polling) + interval=0, # irrelevant for 1 poll + args=[] + ) + + # NOTE the results dict item names remain compatible with older usage. + + if asyncio.run(poller.poll()): + results = { + 'workflow': poller.workflow_id, + 'task': poller.task, + 'point': poller.cycle, + } + if poller.alt_cylc_run_dir is not None: + results['cylc_run_dir'] = poller.alt_cylc_run_dir + + if offset is not None: + results['offset'] = poller.offset + + if flow_num is not None: + results["flow_num"] = poller.flow_num + + if poller.is_message: + results['message'] = poller.selector + elif poller.is_trigger: + results['trigger'] = poller.selector + else: + results['status'] = poller.selector + + return (True, results) + else: + return (False, {})
+ + + +def validate(args: Dict[str, Any]): + """Validate workflow_state xtrigger function args. + + Arguments: + workflow_task_id: + full workflow//cycle/task[:selector] + offset: + must be a valid status + flow_num: + must be an integer + alt_cylc_run_dir: + must be a valid path + + """ + tokens = tokenise(args["workflow_task_id"]) + + if any( + tokens[token] is None + for token in ("workflow", "cycle", "task") + ): + raise WorkflowConfigError( + "Full ID needed: workflow//cycle/task[:selector].") + + if ( + args["flow_num"] is not None and + not isinstance(args["flow_num"], int) + ): + raise WorkflowConfigError("flow_num must be an integer if given.") + + try: + check_polling_config( + tokens['cycle_sel'] or tokens['task_sel'] or DEFAULT_STATUS, + args['is_trigger'], + args['is_message'], + ) + except InputError as exc: + raise WorkflowConfigError(str(exc)) from None + + +# BACK COMPAT: workflow_state_backcompat +# from: 8.0.0 +# to: 8.3.0 +# remove at: 8.x +def _workflow_state_backcompat( + workflow: str, + task: str, + point: str, + offset: Optional[str] = None, + status: str = 'succeeded', + message: Optional[str] = None, + cylc_run_dir: Optional[str] = None +) -> Tuple[bool, Optional[Dict[str, Optional[str]]]]: + """Back-compat wrapper for the workflow_state xtrigger. + + Note Cylc 7 DBs only stored custom task outputs, not standard ones. + + Arguments: + workflow: + The workflow to interrogate. + task: + The name of the task to query. + point: + The cycle point. + offset: + The offset between the cycle this xtrigger is used in and the one + it is querying for as an ISO8601 time duration. + e.g. PT1H (one hour). + status: + The task status required for this xtrigger to be satisfied. + message: + The custom task output required for this xtrigger to be satisfied. + + .. note:: + + This cannot be specified in conjunction with ``status``. + + cylc_run_dir: + Alternate cylc-run directory, e.g. for another user. + + Returns: + tuple: (satisfied, results) + + satisfied: + True if ``satisfied`` else ``False``. + results: + Dictionary containing the args / kwargs which were provided + to this xtrigger. + + """ + args = { + 'workflow': workflow, + 'task': task, + 'point': point, + 'offset': offset, + 'status': status, + 'message': message, + 'cylc_run_dir': cylc_run_dir + } + upg_args = _upgrade_workflow_state_sig(args) + satisfied, _results = workflow_state(**upg_args) + + return (satisfied, args) + + +# BACK COMPAT: workflow_state_backcompat +# from: 8.0.0 +# to: 8.3.0 +# remove at: 8.x +def _upgrade_workflow_state_sig(args: Dict[str, Any]) -> Dict[str, Any]: + """Return upgraded args for workflow_state, given the deprecated args.""" + is_message = False + workflow_task_id = f"{args['workflow']}//{args['point']}/{args['task']}" + status = args.get('status') + message = args.get('message') + if status is not None: + workflow_task_id += f":{status}" + elif message is not None: + is_message = True + workflow_task_id += f":{message}" + return { + 'workflow_task_id': workflow_task_id, + 'offset': args.get('offset'), + 'alt_cylc_run_dir': args.get('cylc_run_dir'), + 'is_message': is_message, + } + + +# BACK COMPAT: workflow_state_backcompat +# from: 8.0.0 +# to: 8.3.0 +# remove at: 8.x +def _validate_backcompat(args: Dict[str, Any]): + """Validate old workflow_state xtrigger function args. + """ + bound_args = signature(workflow_state).bind( + **_upgrade_workflow_state_sig(args) + ) + bound_args.apply_defaults() + validate(bound_args.arguments) +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/flow/xtriggers/xrandom.html b/nightly_8.3/html/_modules/cylc/flow/xtriggers/xrandom.html new file mode 100644 index 0000000000..607afb5cf3 --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/flow/xtriggers/xrandom.html @@ -0,0 +1,275 @@ + + + + + + + + cylc.flow.xtriggers.xrandom — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for cylc.flow.xtriggers.xrandom

+# THIS FILE IS PART OF THE CYLC WORKFLOW ENGINE.
+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+
+from random import random, randint
+from time import sleep
+from typing import Any, Dict, Tuple
+
+from cylc.flow.exceptions import WorkflowConfigError
+
+
+COLORS = ["red", "orange", "yellow", "green", "blue", "indigo", "violet"]
+SIZES = ["tiny", "small", "medium", "large", "huge", "humongous"]
+
+
+
+[docs] +def xrandom( + percent: float, secs: int = 0, _: Any = None +) -> Tuple[bool, Dict[str, str]]: + """Random xtrigger, with configurable sleep and percent success. + + Sleep for ``sec`` seconds, and report satisfied with ``percent`` + likelihood. + + The ``_`` argument is not used in the function code, but can be used to + specialize the function signature to cycle point or task. + + Args: + percent: + Percent likelihood of passing. + secs: + Seconds to sleep before starting the trigger. + _: + Used to allow users to specialize the trigger with extra + parameters. + + Returns: + tuple: (satisfied, results) + + satisfied: + True if ``satisfied`` else ``False``. + results: + A dictionary containing the following keys: + + ``COLOR`` + A random colour (e.g. red, orange, ...). + ``SIZE`` + A random size (e.g. small, medium, ...). + + Examples: + If the percent is zero, it returns that the trigger condition was + not satisfied, and an empty dictionary. + + >>> xrandom(0, 0) + (False, {}) + + If the percent is not zero, but the random percent success is not met, + then it also returns that the trigger condition was not satisfied, + and an empty dictionary. + + >>> import sys + >>> mocked_random = lambda: 0.3 + >>> sys.modules[__name__].random = mocked_random + >>> xrandom(15.5, 0) + (False, {}) + + Finally, if the percent is not zero, and the random percent success is + met, then it returns that the trigger condition was satisfied, and a + dictionary containing random colour and size as result. + + >>> import sys + >>> mocked_random = lambda: 0.9 + >>> sys.modules[__name__].random = mocked_random + >>> mocked_randint = lambda x, y: 1 + >>> sys.modules[__name__].randint = mocked_randint + >>> xrandom(99.99, 0) + (True, {'COLOR': 'orange', 'SIZE': 'small'}) + + """ + sleep(float(secs)) + results = {} + satisfied = random() < float(percent) / 100 # nosec: B311 + if satisfied: + results = { + 'COLOR': COLORS[randint(0, len(COLORS) - 1)], # nosec: B311 + 'SIZE': SIZES[randint(0, len(SIZES) - 1)] # nosec: B311 + } + return satisfied, results
+ + + +
+[docs] +def validate(args: Dict[str, Any]): + """Validate the args that xrandom is called with. + + Cylc calls this function automatically when parsing the workflow. + + Here we specify the rules for args are: + + * percent: Must be 0 ≤ x ≤ 100 + * secs: Must be an integer. + """ + percent = args['percent'] + if ( + not isinstance(percent, (float, int)) + or not (0 <= percent <= 100) + ): + raise WorkflowConfigError( + "'percent' should be a float between 0 and 100" + ) + + secs = args['secs'] + if not isinstance(secs, int): + raise WorkflowConfigError("'secs' should be an integer")
+ +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/uiserver/app.html b/nightly_8.3/html/_modules/cylc/uiserver/app.html new file mode 100644 index 0000000000..616dafc828 --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/uiserver/app.html @@ -0,0 +1,745 @@ + + + + + + + + cylc.uiserver.app — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for cylc.uiserver.app

+#!/usr/bin/env python3
+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+
+"""
+Cylc UI Server can be configured using a ``jupyter_config.py`` file, loaded
+from a hierarchy of locations. This hierarchy includes the prepackaged
+configuration, the site directory (which defaults to ``/etc/cylc/uiserver`` but
+can be set with the environment variable ``$CYLC_SITE_CONF_PATH``) and
+the user directory (``~/.cylc/uiserver``).
+For example, at Cylc UI Server version 0.6.0, the hierarchy (highest priority
+at the bottom) would be:
+
+* ``cylc/uiserver/jupyter_config.py`` (pre-packaged default)
+* ``/etc/cylc/uiserver/jupyter_config.py``
+* ``/etc/cylc/uiserver/0/jupyter_config.py``
+* ``/etc/cylc/uiserver/0.6/jupyter_config.py``
+* ``/etc/cylc/uiserver/0.6.0/jupyter_config.py``
+* ``~/.cylc/uiserver/jupyter_config.py``
+* ``~/.cylc/uiserver/0/jupyter_config.py``
+* ``~/.cylc/uiserver/0.6/jupyter_config.py``
+* ``~/.cylc/uiserver/0.6.0/jupyter_config.py``
+
+
+An example configuration might look like this:
+
+.. code-block:: python
+
+   # scan for workflows every 10 seconds
+   c.CylcUIServer.scan_interval = 10
+
+The Cylc UI Server is a `Jupyter Server`_ extension. For generic configuration
+options see the Jupyter Servers documentation:
+:external+jupyter_server:ref:`other-full-config`.
+Cylc specific configurations are documented here.
+
+.. note::
+
+   ``c.CylcUIServer.site_authorization`` should be defined in
+   ``/etc/cylc/uiserver/jupyter_config.py``, or, alternatively, via
+   the environment variable ``CYLC_SITE_CONF_PATH``.
+"""
+
+from concurrent.futures import ProcessPoolExecutor
+import getpass
+import os
+from pathlib import Path, PurePath
+import sys
+from textwrap import dedent
+from typing import List, Optional
+
+from pkg_resources import parse_version
+from tornado import ioloop
+from tornado.web import RedirectHandler
+from traitlets import (
+    Bool,
+    Dict,
+    Float,
+    Int,
+    TraitError,
+    TraitType,
+    Undefined,
+    Unicode,
+    default,
+    validate,
+)
+from types import SimpleNamespace
+
+from jupyter_server.extension.application import ExtensionApp
+
+from cylc.flow.network.graphql import (
+    CylcGraphQLBackend, IgnoreFieldMiddleware
+)
+from cylc.flow.profiler import Profiler
+from cylc.uiserver import (
+    __file__ as uis_pkg,
+)
+from cylc.uiserver.authorise import (
+    Authorization,
+    AuthorizationMiddleware
+)
+from cylc.uiserver.data_store_mgr import DataStoreMgr
+from cylc.uiserver.handlers import (
+    CylcStaticHandler,
+    CylcVersionHandler,
+    SubscriptionHandler,
+    UIServerGraphQLHandler,
+    UserProfileHandler,
+)
+from cylc.uiserver.config_util import (
+    get_conf_dir_hierarchy,
+    SITE_CONF_ROOT,
+    USER_CONF_ROOT
+)
+from cylc.uiserver.resolvers import Resolvers
+from cylc.uiserver.schema import schema
+from cylc.uiserver.websockets.tornado import TornadoSubscriptionServer
+from cylc.uiserver.workflows_mgr import WorkflowsManager
+
+INFO_FILES_DIR = Path(USER_CONF_ROOT / "info_files")
+
+
+class PathType(TraitType):
+    """A pathlib traitlet type which allows string and undefined values."""
+
+    @property
+    def info_text(self):
+        return 'a pathlib.PurePath object'
+
+    def validate(self, obj, value):
+        if isinstance(value, str):
+            return Path(value).expanduser()
+        if isinstance(value, PurePath):
+            return value
+        if value == Undefined:
+            return value
+        self.error(obj, value)
+
+
+
+[docs] +class CylcUIServer(ExtensionApp): + + name = 'cylc' + app_name = 'cylc-gui' + load_other_extensions = True + description = ''' + Cylc gui - A user interface for monitoring and controlling Cylc workflows. + ''' # type: ignore[assignment] + examples = dedent(''' + cylc gui # Start the Cylc GUI (at the dashboard page) + cylc gui [workflow] # Start the Cylc GUI (at the workflow page) + cylc gui --new [workflow] # Start a new Cylc server instance if an old one + # has become unresponsive. + cylc gui --no-browser # Start the server but don't open the browser + + ''') # type: ignore[assignment] + # TODO: Add a link to the access group table mappings in cylc documentation + # https://github.com/cylc/cylc-uiserver/issues/466 + AUTH_DESCRIPTION = ''' + Authorization can be granted at operation (mutation) level, i.e. + specifically grant user access to execute Cylc commands, e.g. + ``play``, ``pause``, ``edit``, ``trigger`` etc. For your + convenience, these operations have been mapped to access groups + ``READ``, ``CONTROL`` and ``ALL``. + + To remove permissions, prepend the access group or operation with + ``!``. + + Permissions are additive but negated permissions take precedence + above additions e.g. ``CONTROL, !stop`` will permit all operations + in the ``CONTROL`` group except for ``stop``. + + .. note:: + + Any authorization permissions granted to a user will be + applied to all workflows. + + For more information, including the access group mappings, see + :ref:`cylc.uiserver.multi-user`. + ''' + + site_authorization = Dict( + config=True, + help=''' + Dictionary containing site limits and defaults for authorization. + + This configuration should be placed only in the site set + configuration file and not the user configuration file (use + ``c.CylcUIServer.user_authorization`` for user defined + authorization). + + If this configuration is empty, site authorization defaults to no + configurable authorization and users will be unable to set any + authorization. + + ''' + AUTH_DESCRIPTION + ''' + + .. rubric:: Example Configuration: + + .. code-block:: python + + c.CylcUIServer.site_authorization = { + "*": { # For all ui-server owners, + "*": { # Any authenticated user + "default": "READ", # Has default read access + }, + "user1": { # user1 + "default": ["!ALL"], # No privileges for all + # ui-server owners. + }, # No limit set, so all ui-server owners + }, # limit is also "!ALL" for user1 + "server_owner_1": { # For specific UI Server owner, + "group:group_a": { # Any member of group_a + "default": "READ", # Will have default read access + "limit": ["ALL", "!play"], # server_owner_1 can + }, # grant All privileges, except play. + }, + "group:grp_of_svr_owners": { # Group of UI Server owners + "group:group_b": { + "limit": [ # can grant groupB users up to READ and + "READ", # CONTROL privileges, without stop and + "CONTROL", # kill + "!stop", + "!kill", # No default, so default is no access + ], + }, + }, + } + + ''') + + user_authorization = Dict( + config=True, + help=''' + Dictionary containing authorized users and permission levels for + authorization. + + Use this setting to share control of your workflows + with other users. + + Note that you are only permitted to give away permissions up to + your limit for each user, as defined in the site_authorization + configuration. + + ''' + AUTH_DESCRIPTION + ''' + + Example configuration, residing in + ``~/.cylc/uiserver/jupyter_config.py``: + + .. code-block:: python + + c.CylcUIServer.user_authorization = { + "*": ["READ"], # any authenticated user has READ access + "group:group2": ["ALL"], # Any user in system group2 has + # access to all operations + "userA": ["ALL", "!stop"], # userA has ALL operations, not + # stop + } + + ''' + ) + + ui_path = PathType( + config=False, + help=''' + Path to the UI build to serve. + + Internal config derived from ui_build_dir and ui_version. + ''' + ) + ui_build_dir = PathType( + config=True, + help=''' + The directory containing the UI build. + + This can be a directory containing a single UI build e.g:: + + dir/ + index.html + + Or a tree of builds where each build has a version number e.g:: + + dir/ + 1.0/ + index.html + 2.0/ + index.html + + By default this points at the UI build tree which was bundled with + the UI Server. Change this if you want to pick up a different + build e.g. for development or evaluation purposes. + + Takes effect on (re)start. + ''' + ) + ui_version = Unicode( + config=True, + help=''' + Hardcodes the UI version to serve. + + If the ``ui_build_dir`` is a tree of builds, this config can be + used to determine which UI build is used. + + By default the highest version is chosen according to PEP440 + version sorting rules. + + Takes effect on (re)start. + ''' + ) + scan_interval = Float( + config=True, + help=''' + Set the interval between workflow scans in seconds. + + Workflow scans allow a UI server to detect workflows which have + been started from the CLI since the last update. + + This involves a number of filesystem operations, to reduce + system load set a higher value. + ''', + default_value=5.0 # default values as kwargs correctly display in docs + ) + max_workers = Int( + config=True, + help=''' + Set the maximum number of workers for process pools. + ''', + default_value=1 + ) + max_threads = Int( + config=True, + help=''' + Set the maximum number of threads the Cylc UI Server can use. + + This determines the maximum number of active workflows that the + server can track. + ''', + default_value=100, + ) + profile = Bool( + config=True, + help=''' + Turn on Python profiling. + + The profile results will be saved to ~/.cylc/uiserver/profile.prof + in cprofile format. + ''', + default_value=False, + ) + + @validate('ui_build_dir') + def _check_ui_build_dir_exists(self, proposed): + if proposed['value'].exists(): + return proposed['value'] + raise TraitError(f'ui_build_dir does not exist: {proposed["value"]}') + + @validate('site_authorization') + def _check_site_auth_dict_correct_format(self, proposed): + # TODO: More advanced auth dict validating + if isinstance(proposed['value'], dict): + return proposed['value'] + raise TraitError( + f'Error in site authorization config: {proposed["value"]}') + + @staticmethod + def _list_ui_versions(path: Path) -> List[str]: + """Return a list of UI build versions detected in self.ui_path.""" + return sorted( + ( + version.name + for version in path.glob('[0-9][0-9.]*') + if version + ), + key=parse_version + ) + + @default('ui_path') + def _get_ui_path(self): + build_dir = self.ui_build_dir + version = self.ui_version + + if build_dir and build_dir != Undefined: + # ui path has been configured, check if the path is a build + # (rather than a dir of builds e.g. development build) + if (build_dir / 'index.html').exists(): + return build_dir + else: + # default UI build base directory + build_dir = Path(uis_pkg).parent / 'ui' + + if not version: + # pick the highest installed version by default + try: + version = self._list_ui_versions(build_dir)[-1] + except IndexError: + raise Exception( + f'Could not find any UI builds in {build_dir}.' + ) + + ui_path = build_dir / version + if (ui_path / 'index.html').exists(): + return ui_path + + raise Exception(f'Could not find UI build in {ui_path}') + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._config_file_paths: Optional[List[str]] = None + self.executor = ProcessPoolExecutor(max_workers=self.max_workers) + self.workflows_mgr = WorkflowsManager(self, log=self.log) + self.data_store_mgr = DataStoreMgr( + self.workflows_mgr, + self.log, + self.max_threads, + ) + # sub_status dictionary storing status of subscriptions + self.sub_statuses = {} + self.resolvers = Resolvers( + self.data_store_mgr, + log=self.log, + executor=self.executor, + workflows_mgr=self.workflows_mgr, + ) + + @property + def config_file_paths(self) -> List[str]: + if self._config_file_paths is None: + ret = get_conf_dir_hierarchy( + [ + SITE_CONF_ROOT, # site configuration + USER_CONF_ROOT, # user configuration + ], filename=False + ) + # Next include currently needed for directory making + ret.insert(0, str(Path(uis_pkg).parent)) # packaged config + ret.reverse() + self._config_file_paths = ret + return self._config_file_paths + + def initialize_settings(self): + """Update extension settings. + + Update the self.settings trait to pass extra settings to the underlying + Tornado Web Application. + + self.settings.update({'<trait>':...}) + """ + super().initialize_settings() + + # startup messages + self.log.info("Starting Cylc UI Server") + self.log.info(f'Serving UI from: {self.ui_path}') + self.log.debug( + 'CylcUIServer config:\n' + '\n'.join( + f' * {key} = {repr(value)}' + for key, value in self.config['CylcUIServer'].items() + ) + ) + + # start profiling + self.profiler = Profiler( + # the profiler is designed to attach to a Cylc scheduler + schd=SimpleNamespace(workflow_log_dir=USER_CONF_ROOT), + # profiling is turned on via the "profile" traitlet + enabled=self.profile, + ) + self.profiler.start() + + # start the async scan task running (do this on server start not init) + ioloop.IOLoop.current().add_callback( + self.workflows_mgr.run + ) + # configure the scan interval + ioloop.PeriodicCallback( + self.workflows_mgr.scan, + self.scan_interval * 1000 + ).start() + + def initialize_handlers(self): + self.authobj = self.set_auth() + self.set_sub_server() + + self.handlers.extend([ + ( + 'cylc/version', + CylcVersionHandler, + {'auth': self.authobj} + ), + ( + 'cylc/graphql', + UIServerGraphQLHandler, + { + 'schema': schema, + 'resolvers': self.resolvers, + 'backend': CylcGraphQLBackend(), + 'middleware': [ + AuthorizationMiddleware, + IgnoreFieldMiddleware + ], + 'auth': self.authobj, + } + ), + ( + 'cylc/graphql/batch', + UIServerGraphQLHandler, + { + 'schema': schema, + 'resolvers': self.resolvers, + 'backend': CylcGraphQLBackend(), + 'middleware': [ + AuthorizationMiddleware, + IgnoreFieldMiddleware + ], + 'batch': True, + 'auth': self.authobj, + } + ), + ( + 'cylc/subscriptions', + SubscriptionHandler, + { + 'sub_server': self.subscription_server, + 'resolvers': self.resolvers, + 'sub_statuses': self.sub_statuses + } + ), + ( + 'cylc/userprofile', + UserProfileHandler, + {'auth': self.authobj} + ), + ( + 'cylc/(.*)?', + CylcStaticHandler, + { + 'path': str(self.ui_path), + 'default_filename': 'index.html' + } + ), + ( + # redirect '/cylc' to '/cylc/' + 'cylc', + RedirectHandler, + { + 'url': 'cylc/' + } + ) + ]) + + def set_sub_server(self): + self.subscription_server = TornadoSubscriptionServer( + schema, + backend=CylcGraphQLBackend(), + middleware=[ + IgnoreFieldMiddleware, + AuthorizationMiddleware, + ], + auth=self.authobj, + ) + + def set_auth(self): + """Create authorization object. + One for the lifetime of the UIServer. + """ + return Authorization( + getpass.getuser(), + self.config.CylcUIServer.user_authorization, + self.config.CylcUIServer.site_authorization, + self.log + ) + + def initialize_templates(self): + """Change the jinja templating environment.""" + + @classmethod + def launch_instance(cls, argv=None, workflow_id=None, **kwargs): + if workflow_id: + cls.default_url = f"/cylc/#/workspace/{workflow_id}" + else: + cls.default_url = "/cylc" + if argv is None: + # jupyter server isn't expecting to be launched by a Cylc command + # this patches some internal logic + argv = sys.argv[2:] + os.environ["JUPYTER_RUNTIME_DIR"] = str(INFO_FILES_DIR) + super().launch_instance(argv=argv, **kwargs) + del os.environ["JUPYTER_RUNTIME_DIR"] + + async def stop_extension(self): + # stop the async scan task + await self.workflows_mgr.stop() + + # stop active subscriptions + for sub in self.data_store_mgr.w_subs.values(): + sub.stop() + + # Shutdown the thread pool executor (used for subscription processing) + self.data_store_mgr.executor.shutdown(wait=False) + + # stop the process pool (used for background commands) + self.executor.shutdown() + + # Destroy ZeroMQ context of all sockets + self.workflows_mgr.context.destroy() + self.profiler.stop()
+ +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/cylc/uiserver/authorise.html b/nightly_8.3/html/_modules/cylc/uiserver/authorise.html new file mode 100644 index 0000000000..f0b5d18e2f --- /dev/null +++ b/nightly_8.3/html/_modules/cylc/uiserver/authorise.html @@ -0,0 +1,787 @@ + + + + + + + + cylc.uiserver.authorise — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
+
+
+ +
+
+
+
+ +

Source code for cylc.uiserver.authorise

+# Copyright (C) NIWA & British Crown (Met Office) & Contributors.
+#
+# 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/>.
+
+from contextlib import suppress
+from functools import lru_cache
+from getpass import getuser
+import grp
+from typing import List, Dict, Optional, Union, Any, Sequence, Set, Tuple
+from inspect import iscoroutinefunction
+import os
+import re
+
+import graphene
+from jupyter_server.auth import Authorizer
+from tornado import web
+from traitlets.config.loader import LazyConfigValue
+
+from cylc.uiserver.schema import UISMutations
+from cylc.uiserver.utils import is_bearer_token_authenticated
+
+
+
+[docs] +class CylcAuthorizer(Authorizer): + """Defines a safe default authorization policy for Jupyter Server. + + `Jupyter Server`_ provides an authorisation layer which gives full + permissions to any user who has been granted permission to the Jupyter Hub + ``access:servers`` scope + (see :ref:`JupyterHub scopes reference <jupyterhub-scopes>`). This allows + the execution of arbitrary code under another user account. + + To prevent this you must define an authorisation policy using + :py:attr:`c.ServerApp.authorizer_class + <jupyter_server.serverapp.ServerApp.authorizer_class>`. + + This class defines a policy which blocks all API calls to another user's + server, apart from calls to Cylc interfaces explicitly defined in the + :ref:`Cylc authorisation configuration <cylc.uiserver.user_authorization>`. + + This class is configured as the default authoriser for all Jupyter Server + instances spawned via the ``cylc hubapp`` command. This is the default if + you started `Jupyter Hub`_ using the ``cylc hub`` command. To see where + this default is set, see this file for the appropriate release of + cylc-uiserver: + https://github.com/cylc/cylc-uiserver/blob/master/cylc/uiserver/jupyter_config.py + + If you are launching Jupyter Hub via another command (e.g. ``jupyterhub``) + or are overriding :py:attr:`jupyterhub.app.JupyterHub.spawner_class`, then + you will need to configure a safe authorisation policy e.g: + + .. code-block:: python + + from cylc.uiserver.authorise import CylcAuthorizer + c.ServerApp.authorizer_class = CylcAuthorizer + + .. note:: + + It is possible to provide read-only access to Jupyter Server extensions + such as Jupyter Lab, however, this isn't advisable as Jupyter Lab does + not apply file-system permissions to what another user is allowed to + see. + + If you wish to grant users access to other user's Jupyter Lab servers, + override this configuration with due care over what you choose to + expose. + + """ + + # This is here just to fix sphinx autodoc warning from traitlets' __init__ + # see https://github.com/cylc/cylc-uiserver/pull/560 + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + def is_authorized(self, handler, user, action, resource) -> bool: + """Allow a user to access their own server. + + Note that Cylc uses its own authorization system (which is locked-down + by default) and is not affected by this policy. + """ + if is_bearer_token_authenticated(handler): + # this session is authenticated by a token or password NOT by + # Jupyter Hub -> the bearer of the token has full permissions + return True + + # the username of the user running this server + # (used for authorzation purposes) + me = getuser() + + if user.username == me: + # give the user full permissions to their own server + return True + + # block access to everyone else + return False
+ + + +def constant(func): + """Decorator preventing reassignment""" + + def fset(self, value): + raise TypeError + + def fget(): + return func() + + return property(fget, fset) + + +class Authorization: + """Authorization Information Class + One instance for the life of the UI Server. If authorization settings + change they will need to re-start the UI Server. + Authorization has access groups: `READ`, `CONTROL`, `ALL` - along with + their negations, `!READ`, `!CONTROL` and `!ALL` which indicate removal of + the permission groups. + + """ + + # config literals + DEFAULT = "default" + LIMIT = "limit" + GRP_IDENTIFIER = "group:" + + # Operations + + ########################################################################## + # !WARNING! # + # # + # Beware of changing these permission groups. Users may be relying on # + # these settings. Changes should be widely publicised to users. # + # # + # If adding/removing operations, ensure documentation is updated. # + # # + ########################################################################## + + READ_OPERATION = "read" + + # Access group identifiers (used in config) + + READ = "READ" + CONTROL = "CONTROL" + ALL = "ALL" + NOT_READ = "!READ" + NOT_CONTROL = "!CONTROL" + NOT_ALL = "!ALL" + + # Access Groups + + READ_OPS = {READ_OPERATION} + ASYNC_OPS = {"query", "mutation"} + READ_AUTH_OPS = {"query", "subscription"} + + @staticmethod + @constant + def ALL_OPS() -> List[str]: + """ALL OPS constant, returns list of all mutations.""" + return get_list_of_mutations() + + @staticmethod + @constant + def CONTROL_OPS() -> List[str]: + """CONTROL OPS constant, returns list of all control mutations.""" + return get_list_of_mutations(control=True) + + def __init__(self, owner, owner_auth_conf, site_auth_conf, log) -> None: + self.owner = owner + self.log = log + self.owner_auth_conf = self.set_auth_conf(owner_auth_conf) + self.site_auth_config = self.set_auth_conf(site_auth_conf) + self.owner_user_info = { + "user": self.owner, + "user_groups": self._get_groups(self.owner), + } + self.owner_dict = self.build_owner_site_auth_conf() + + # lru_cache this method - see flake8-bugbear B019 + self.get_permitted_operations = lru_cache(maxsize=128)( + self._get_permitted_operations + ) + + @staticmethod + def expand_and_process_access_groups(permission_set: set) -> set: + """Process a permission set. + + Takes a permission set, e.g. limits, defaults. + Expands the access groups and removes negated operations. + + Args: + permission_set: set of permissions + + Returns: + permission_set: processed permission set. + """ + for action_group, expansion in { + Authorization.CONTROL: Authorization.CONTROL_OPS.fget(), + Authorization.ALL: Authorization.ALL_OPS.fget(), + Authorization.READ: Authorization.READ_OPS, + }.items(): + if action_group in permission_set: + permission_set.remove(action_group) + permission_set.update(expansion) + # Expand negated permissions + for action_group, expansion in { + Authorization.NOT_CONTROL: [ + f"!{x}" for x in Authorization.CONTROL_OPS.fget()], + Authorization.NOT_ALL: [ + f"!{x}" for x in Authorization.ALL_OPS.fget()], + Authorization.NOT_READ: [ + f"!{x}" for x in Authorization.READ_OPS]}.items(): + if action_group in permission_set: + permission_set.remove(action_group) + permission_set.update(expansion) + # Remove negated permissions + remove = set() + + for perm in permission_set: + if perm.startswith("!"): + remove.add(perm.lstrip("!")) + remove.add(perm) + permission_set.difference_update(remove) + permission_set.discard("") + return permission_set + + @staticmethod + def set_auth_conf(auth_conf: Union[LazyConfigValue, dict]) -> dict: + """Resolve lazy config where empty + + Args: + auth_conf: Authorization configuration from a jupyter_config.py + + Returns: + Valid configuration dictionary + """ + if isinstance(auth_conf, LazyConfigValue): + return auth_conf.to_dict() + return auth_conf + + def get_owner_site_limits_for_access_user( + self, access_user: Dict[str, Union[str, Sequence[Any]]] + ) -> Set: + """Returns limits owner can give to given access_user + + Args: + access_user: Dictionary containing info about access user and their + membership of system groups. + + Returns: + Set of limits that the uiserver owner is allowed to give away + for given access user. + """ + limits: Set[str] = set() + if not self.owner_dict: + return limits + items_to_check = ["*", access_user["access_username"]] + items_to_check.extend(access_user["access_user_groups"]) + for item in items_to_check: + permission: Union[str, List] = "" + default = "" + with suppress(KeyError): + default = self.owner_dict[item].get(Authorization.DEFAULT, "") + with suppress(KeyError): + permission = self.owner_dict[item].get( + Authorization.LIMIT, default) + if permission == []: + raise_auth_config_exception("site") + if isinstance(permission, str): + limits.add(permission) + else: + limits.update(permission) + limits.discard("") + return limits + + def get_access_user_permissions_from_owner_conf( + self, access_user: Dict[str, Union[str, Sequence[Any]]] + ) -> set: + """ + Returns set of operations specific to access user from owner user conf. + + Args: + access_user: Dictionary containing info about access user and their + membership of system groups. Defaults to None. + """ + items_to_check = ["*", access_user["access_username"]] + items_to_check.extend(access_user["access_user_groups"]) + allowed_operations = set() + for item in items_to_check: + permission = self.owner_auth_conf.get(item, "") + # Specifiying empty list equates to removing of all permissions. + if permission == []: + raise_auth_config_exception("user") + if isinstance(permission, str): + allowed_operations.add(permission) + else: + allowed_operations.update(permission) + allowed_operations.discard("") + return allowed_operations + + # lru_cached - see __init__() + def _get_permitted_operations(self, access_user: str): + """Return permitted operations for given access_user. + + Cached for efficiency. + Checks: + - site config to ensure owner is permitted to give away permissions + - user config for authorised operations related to access_user and + their groups + - if user not in user config, then returns defaults from site config. + + Args: + access_user: username to check for permitted operations + + Returns: + Set of operations permitted by given access user for this UI Server + """ + # For use in the ui, owner permissions (ALL operations) are set + if access_user == self.owner: + return set(Authorization.ALL_OPS.fget()) + # Otherwise process permissions for (non-uiserver owner) access_user + + access_user_dict = { + "access_username": access_user, + "access_user_groups": self._get_groups(access_user), + } + limits_owner_can_give = self.get_owner_site_limits_for_access_user( + access_user=access_user_dict) + user_conf_permitted_ops = ( + self.get_access_user_permissions_from_owner_conf( + access_user=access_user_dict) + ) + # If not explicit permissions for access user in owner conf then revert + # to site defaults + if len(user_conf_permitted_ops) == 0: + user_conf_permitted_ops = ( + self.return_site_auth_defaults_for_access_user( + access_user=access_user_dict + ) + ) + user_conf_permitted_ops = self.expand_and_process_access_groups( + user_conf_permitted_ops + ) + limits_owner_can_give = self.expand_and_process_access_groups( + limits_owner_can_give + ) + allowed_operations = limits_owner_can_give.intersection( + user_conf_permitted_ops + ) + self.log.info( + f"User {access_user} authorized permissions: " + f"{sorted(allowed_operations)}" + ) + return allowed_operations + + def is_permitted(self, access_user: str, operation: str) -> bool: + """Checks if user is permitted to action operation. + + Args: + access_user: User attempting to action given operation. + operation: operation name + + Returns: + True if access_user permitted to action operation, otherwise, + False. + """ + if access_user == self.owner_user_info["user"]: + return True + # re.sub needed for snake/camel case + if re.sub( + r'(?<!^)(?=[A-Z])', '_', operation + ).lower() in self.get_permitted_operations(access_user): + self.log.info(f"{access_user}: authorized to {operation}") + return True + self.log.info(f"{access_user}: not authorized to {operation}") + + return False + + def build_owner_site_auth_conf(self): + """Build UI Server owner permissions dictionary. + Creates a reduced site auth dictionary for the ui-server owner. + + """ + owner_dict = {} + items_to_check = ["*", self.owner_user_info["user"]] + items_to_check.extend(self.owner_user_info["user_groups"]) + + # dict containing user info applying to the current ui_server owner + for uis_owner_conf, access_user_dict in self.site_auth_config.items(): + if uis_owner_conf in items_to_check: + # acc_user = access_user + for acc_user_conf, acc_user_perms in access_user_dict.items(): + existing_user_conf = owner_dict.get(acc_user_conf) + if existing_user_conf: + # process limits and defaults and update dictionary + existing_default = existing_user_conf.get( + Authorization.DEFAULT, '') + existing_limit = existing_user_conf.get( + Authorization.LIMIT, existing_default) + new_default = acc_user_perms.get( + Authorization.DEFAULT, '') + new_limit = acc_user_perms.get( + Authorization.LIMIT, new_default) + set_defs = set() + for conf in [existing_default, new_default]: + if isinstance(conf, list): + set_defs.update(conf) + else: + set_defs.add(conf) + set_lims = set() + for conf in [existing_limit, new_limit]: + if isinstance(conf, list): + set_lims.update(conf) + else: + set_lims.add(conf) + # update and continue + owner_dict[ + acc_user_conf][Authorization.LIMIT] = list( + set_lims) + owner_dict[ + acc_user_conf][Authorization.DEFAULT] = list( + set_defs) + continue + owner_dict.update(access_user_dict) + # Now we have a reduced site auth dictionary for the current owner + return owner_dict + + def return_site_auth_defaults_for_access_user( + self, access_user: Dict[str, Union[str, Sequence[Any]]] + ) -> Set: + """Return site authorization defaults for given access user. + Args: + access_user: access_user dictionary, in the form + {'access_username': username + 'access_user_group: [group1, group2,...]' + } + Returns: + Set of default operations permitted + + """ + defaults: Set[str] = set() + if not self.owner_dict: + return defaults + items_to_check = ["*", access_user["access_username"]] + items_to_check.extend(access_user["access_user_groups"]) + for item in items_to_check: + permission: Union[str, List] = "" + with suppress(KeyError): + permission = self.owner_dict[item].get( + Authorization.DEFAULT, "" + ) + if permission == []: + raise_auth_config_exception("site") + if isinstance(permission, str): + defaults.add(permission) + else: + defaults.update(permission) + defaults.discard("") + return defaults + + def _get_groups(self, user: str) -> List: + """Allows get groups to use self.logger if something goes wrong. + + Added to provide a single interface for get_groups to this class, to + avoid having to pass the logger to get_groups (and methods it calls). + """ + good_groups, bad_groups = get_groups(user) + if bad_groups: + self.log.warning( + f'{user} has the following invalid groups in their profile ' + f'{bad_groups} - these groups will be ignored.' + ) + return good_groups + + +# GraphQL middleware +class AuthorizationMiddleware: + """Authorization Middleware for authorization checking GraphQL. + + Mutations are checked against permissions from config files. + + Raises: + web.HTTPError: Unauthorized requests. + """ + + auth = None + + def resolve(self, next_, root, info, **args): + current_user = info.context["current_user"] + # We won't be re-checking auth for return variables + if len(info.path) > 1: + return next_(root, info, **args) + op_name = self.get_op_name(info.field_name, info.operation.operation) + # It shouldn't get here but worth checking for zero trust + if not op_name: + self.auth_failed( + current_user, op_name, http_code=400, + msg="Operation not in schema." + ) + try: + authorised = self.auth.is_permitted(current_user, op_name) + except Exception: + # Fail secure + authorised = False + if not authorised: + self.auth_failed(current_user, op_name, http_code=403) + if (info.operation.operation in Authorization.ASYNC_OPS + or iscoroutinefunction(next_)): + return self.async_resolve(next_, root, info, **args) + return next_(root, info, **args) + + def auth_failed(self, current_user: str, op_name: str, + http_code: int, message: Optional[str] = None): + """ + Raise authorization error + Args: + current_user: username accessing operation + op_name: operation name + http_code: http error code to raise + message: Message to log Defaults to None. + + Raises: + web.HTTPError + """ + log_message = (f"Authorization failed for {current_user}" + f":requested to {op_name}.") + if message: + log_message = log_message + " " + message + raise web.HTTPError(http_code, reason=message) + + def get_op_name(self, field_name: str, operation: str) -> Optional[str]: + """ + Returns operation name required for authorization. + Converts queries and subscriptions to read operations. + Args: + field_name: Field name e.g. play + operation: operation type + + Returns: + operation name + """ + if operation in Authorization.READ_AUTH_OPS: + return Authorization.READ_OPERATION + else: + # Check it is a mutation in our schema + if self.auth and re.sub( + r'(?<!^)(?=[A-Z])', '_', field_name + ).lower() in Authorization.ALL_OPS.fget(): + return field_name + return None + + async def async_resolve(self, next_, root, info, **args): + """Return awaited coroutine""" + return await next_(root, info, **args) + + +
+[docs] +def get_groups(username: str) -> Tuple[List[str], List[str]]: + """Return list of system groups for given user. + + Uses ``os.getgrouplist`` and ``os.NGROUPS_MAX`` to get system groups for a + given user. ``grp.getgrgid`` then parses these to return a list of group + names. + + Args: + username: username used to check system groups. + + Returns: + list: system groups for username given + """ + groupmax = os.NGROUPS_MAX # type: ignore + group_ids = os.getgrouplist(username, groupmax) + group_ids.remove(groupmax) + # turn list of group_ids into group names with group identifier prepended + return parse_group_ids(group_ids)
+ + + +def parse_group_ids(group_ids: List) -> Tuple[List[str], List[str]]: + """Returns list of groups in the correct format for authorisation. + + Args: + group_ids: List of users groups, in number format + + Returns: + List: List of users groups, in id format with group identifier + prepended. + """ + group_list = [] + bad_group_list = [] + for x in group_ids: + try: + group_list.append( + f"{Authorization.GRP_IDENTIFIER}{grp.getgrgid(x).gr_name}" + ) + except OverflowError: + continue + except KeyError: + bad_group_list.append(x) + return group_list, bad_group_list + + +def get_list_of_mutations(control: bool = False) -> List[str]: + """Gets list of mutations""" + list_of_mutations = [ + attr for attr in dir(UISMutations) + if isinstance(getattr(UISMutations, attr), graphene.Field) + ] + if control: + # Broadcast is an ALL mutation + list_of_mutations.remove("broadcast") + else: + # 'read' is used soley for authorization and is not a UISMutation + list_of_mutations.append(Authorization.READ_OPERATION) + return list_of_mutations + + +def raise_auth_config_exception(config_type: str): + """Error raise for empty list in auth config. + + Args: + config_type: Either site or user. + """ + raise Exception( + f'Error in {config_type} config: ' + f'`c.CylcUIServer.{config_type}_authorization`. ' + f'"[]" is not supported. Use "{Authorization.NOT_ALL}" to remove all' + ' permissions.' + ) +
+ +
+
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_modules/index.html b/nightly_8.3/html/_modules/index.html new file mode 100644 index 0000000000..9ebf659d12 --- /dev/null +++ b/nightly_8.3/html/_modules/index.html @@ -0,0 +1,167 @@ + + + + + + + + Overview: module code — Cylc 8.3.7.dev documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/nightly_8.3/html/_sources/7-to-8/caveats.rst.txt b/nightly_8.3/html/_sources/7-to-8/caveats.rst.txt new file mode 100644 index 0000000000..0b9cf1630d --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/caveats.rst.txt @@ -0,0 +1,58 @@ +Cylc |version| Caveats +====================== + +There are a few Cylc 7 features which do not yet have direct replacements in +Cylc 8. These features will be re-implemented in future releases. + + +Cylc Flow +--------- + +Multiple Flows + The new :term:`scheduler` can manage multiple flows in the workflow graph. + Commands and options for interacting with flows are still being refined. + + +Browser Based UI +---------------- + +The old "GUI" has been replaced by the new browser-based "UI". + +Static Graph Visualization + Not yet reimplemented for Cylc 8. As an interim measure the + ``cylc graph`` command can generate a basic PNG image of a workflow + graph if Graphviz is installed in the Cylc environment. + +Multiple Selection + Multiple selection is yet to be implemented, however, it is possible + to issue action for multiple tasks (e.g. ``kill``) without using + multiple selection: + + * From the UI click on a workflow/cycle/task/job. + * Find the action you want to call (e.g. kill). + * Click the pencil symbol next to this action. + * Edit the workflows/cycles/tasks/jobs in the form and press submit. + + * https://github.com/cylc/cylc-ui/issues/434 +Installing Workflows + At present there is no way to view or install + :term:`source workflows ` in the UI. +Rose Edit + Rose Edit is awaiting reimplementation. +Xtrigger Visibility + Xtriggers are not yet visible in the UI. + + * https://github.com/cylc/cylc-ui/issues/331 +Documentation / Orientation Guide + Some form of documentation will be provided within the UI itself. + + * https://github.com/cylc/cylc-ui/issues/155 + + +UI Server +--------- + +CLI via UIS + The ability to route Cylc commands via the UIS is planned for a future release + + * https://github.com/cylc/cylc-flow/issues/3528 diff --git a/nightly_8.3/html/_sources/7-to-8/cheat-sheet.rst.txt b/nightly_8.3/html/_sources/7-to-8/cheat-sheet.rst.txt new file mode 100644 index 0000000000..fa121afeb7 --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/cheat-sheet.rst.txt @@ -0,0 +1,345 @@ +.. _728.cheat_sheet: + +Cheat Sheet +=========== + +Quick summary of the command line changes between Cylc 7 / Rose 2019 and Cylc 8. + +.. highlight:: sub + + +Validating +---------- + +Check the workflow configuration for errors: + +.. list-table:: + :class: grid-table + + * - **Cylc 7** + - **Rose 2019** + - **Cylc 8** (Rose 2) + * - :: + + cylc validate + - :: + + # validate from $PWD + rose suite-run --validate + - :: + + cylc validate + +Installing & Running +-------------------- + +Install a workflow from source and run it: + +.. list-table:: + :class: grid-table + + * - **Cylc 7** + - **Rose 2019** + - **Cylc 8** (Rose 2) + * - :: + + # no installation capability + # run from source + cylc run + - :: + + # install from $PWD + # then run + rose suite-run + - :: + + # validate, install & play + cylc vip + cylc vip # use $PWD + + +Reloading +--------- + +To update a running workflow with changes from the source directory: + +.. list-table:: + :class: grid-table + + * - **Cylc 7** + - **Rose 2019** + - **Cylc 8** (Rose 2) + * - :: + + # update the live source + # directly, then + cylc reload + - :: + + # re-install from source + # and do ``cylc reload`` + rose suite-run --reload + - :: + + # Validate against source; + # Reinstall; + # Reload or Play + cylc vr + + +Pausing & Unpausing +------------------- + +Tell a workflow not to submit any new jobs: + +.. list-table:: + :class: grid-table + + * - **Cylc 7** & Rose 2019 + - **Cylc 8** (Rose 2) + * - :: + + cylc hold + + cylc unhold + - :: + + cylc pause + + cylc play + +Stopping +-------- + +Stop a running workflow:: + + cylc stop + +Restarting +---------- + +Restart a stopped workflow and pick up where it left off: + +.. list-table:: + :class: grid-table + + * - **Cylc 7** + - **Rose 2019** + - **Cylc 8** (Rose 2) + * - :: + + # no installation capability + # restart from source + cylc restart + - :: + + # regular restart + rose suite-restart + + Or alternatively:: + + # reinstall and restart + rose suite-run --restart + - :: + + # optionally reinstall + cylc reinstall + + # restart + cylc play + +Deleting +-------- + +Delete the workflow :term:`run directory` (leave source files untouched): + +.. list-table:: + :class: grid-table + + * - **Cylc 7** + - **Rose 2019** + - **Cylc 8** (Rose 2) + * - :: + + rm -rf ~/cylc-run/ + - :: + + rose suite-clean + - :: + + cylc clean + +Scanning +-------- + +List all running workflows:: + + cylc scan + +View A Workflow's Configuration +------------------------------- + +View the parsed workflow configuration: + +.. list-table:: + :class: grid-table + + * - **Cylc 7** + - **Rose 2019** + - **Cylc 8** (Rose 2) + * - :: + + cylc get-config --sparse \ + + - :: + + # install workflow + rose suite-run -l + + # view installed config + cylc get-config --sparse \ + + - :: + + cylc config + +Opening User Interfaces +----------------------- + +Opening the graphical user interface (GUI) or terminal user interface (TUI) +for monitoring / controlling running workflows: + +.. list-table:: + :class: grid-table + + * - + - **Cylc 7** & Rose 2019 + - **Cylc 8** (Rose 2) + * - Terminal + - :: + + cylc monitor + - :: + + cylc tui + * - Graphical + - :: + + cylc gui + - :: + + cylc gui + + * - Web Server + - :: + + cylc review start + + - :: + + cylc hub + +Static Graph Visualisation +-------------------------- + +Generate a visualisation for a workflow without running it: + +.. list-table:: + :class: grid-table + + * - **Cylc 7** & Rose 2019 + - **Cylc 8** (Rose 2) + * - :: + + cylc graph + - :: + + cylc graph + + This generates a basic image file if Graphviz is installed. + + The web UI will have full graph vis. in a future release. + +Datetime Operations +------------------- + +Datetime operations in task scripts: + +.. list-table:: + :class: grid-table + + * - **Cylc 7** & Rose 2019 + - **Cylc 8** (Rose 2) + * - :: + + rose date --offset + - :: + + isodatetime --offset + * - :: + + rose date -c + # equivalent to: + rose date "$CYLC_TASK_CYCLE_POINT" + - :: + + isodatetime ref + # equivalent to: + isodatetime "$CYLC_TASK_CYCLE_POINT" + +Rose Stem +--------- + +Run a :ref:`rose:Rose Stem` test suite. + +.. list-table:: + :class: grid-table + + * - **Rose 2019** + - **Rose 2** (Cylc 8) + * - :: + + # install and start + rose stem + - :: + + # install + rose stem + + # start + cylc play + + +Interventions +------------- + +.. note:: + + See the :ref:`user-guide.interventions` section for more details. + +Set task outputs: + +.. list-table:: + :class: grid-table + + * - **Cylc 7** + - **Cylc 8** + * - :: + + cylc reset -s=succeeded + - :: + + cylc set --out=succeeded + + +Insert a task: + +.. list-table:: + :class: grid-table + + * - **Cylc 7** + - **Cylc 8** + * - :: + + cylc insert + - Tasks are inserted automatically when you "trigger" or "set" them. diff --git a/nightly_8.3/html/_sources/7-to-8/index.rst.txt b/nightly_8.3/html/_sources/7-to-8/index.rst.txt new file mode 100644 index 0000000000..a589a85f93 --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/index.rst.txt @@ -0,0 +1,22 @@ +Cylc 8 Migration Guide +====================== + +**A quick guide for Cylc 7 (and Rose 2019) users upgrading to Cylc 8.** + +.. tip:: + + If you need help using or understanding Cylc 8 please post questions to the + `Cylc 8 Migration category `_ + on the `Cylc Forum `_ + + +Cylc 8 differs from Cylc 7 in many ways: architecture, scheduling +algorithm, security, UIs, working practices, and more. + +.. toctree:: + :maxdepth: 1 + + summary + cheat-sheet + major-changes/index + caveats diff --git a/nightly_8.3/html/_sources/7-to-8/major-changes/cli.rst.txt b/nightly_8.3/html/_sources/7-to-8/major-changes/cli.rst.txt new file mode 100644 index 0000000000..5cd17cb2ee --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/major-changes/cli.rst.txt @@ -0,0 +1,193 @@ +.. _MajorChangesCLI: + +Command Line Interface +====================== + +.. admonition:: Does This Change Affect Me? + :class: tip + + This will affect you if you use the Cylc command line interface. + + +Overview +-------- + +* Some commands have been renamed e.g. ``cylc run`` -> ``cylc play``. +* Some tools have been added or removed. +* A new task ID format has been introduced. + +For a quick side by side comparison see the :ref:`728.cheat_sheet`. + + +Full List Of Command Changes +---------------------------- + +The command line has been simplified from Cylc 7 with some commands being +renamed or removed. + +.. _license: https://github.com/cylc/cylc-flow/blob/master/COPYING + +.. rubric:: Commands that have been removed entirely: + +``cylc checkpoint`` + - Database checkpoints are no longer needed. + - All task state changes are written to the database when they occur. + - Remaining use cases can be handled by starting a new :term:`flow` + which allow a new execution of the graph to be started from an + arbitrary point in the graph. +``cylc documentation`` + - We no longer include a command for locating this documentation. +``cylc edit`` + - Use a text editor to edit the workflow configuration file. +``cylc jobscript`` + - It is no longer possible generate a jobscript from outside of a workflow. +``cylc nudge`` + - No longer required. +``cylc register`` + - Registration is no longer required, all workflows in the ``~/cylc-run`` + directory are "registered" automatically. + - To install a workflow from a working copy use ``cylc install``. +``cylc review`` + - The read-only ``cylc review`` web GUI has been removed. + - The latest Cylc 7 version of ``cylc review`` is Cylc 8 compatible + so can still be used to monitor both Cylc 7 and Cylc 8 workflows + side by side. +``cylc search`` + - Use ``grep`` or a text editor to search the workflow configuration or + source directory. +``cylc submit`` + - It is no longer possible to submit a job from outside of a workflow. +``cylc warranty`` + - The Cylc license remains unchanged from Cylc 7. + +.. rubric:: Commands that have been replaced: + +``cylc conditions`` + - See the `license`_ file for conditions of usage, or ``cylc help license`` + - The Cylc license remains unchanged from Cylc 7. +``cylc get-config``, + - Replaced by ``cylc config``. +``cylc get-*-config`` + - (Where ``*`` is ``site``, ``suite`` or ``global``) + - Replaced by ``cylc config``. +``cylc graph-diff`` + - Replaced by ``cylc graph --diff `` +``cylc insert`` + - Task insertion is now automatic, use ``cylc trigger``. +``cylc monitor`` + - There is now a new more powerful terminal user interface (TUI). + - Try ``cylc tui``. +``cylc print`` + - Equivalent to ``cylc scan --states=all``. +``cylc reset`` + - ``cylc reset`` has been replaced by ``cylc set`` + - At Cylc 8 we override task's prerequisites & outputs rather than modifying + the task state directly. +``cylc restart`` + - Replaced by ``cylc play``. +``cylc run`` + - Replaced by ``cylc play``. +``cylc spawn`` + - Spawning is now performed automatically, on demand. Use ``cylc trigger`` to run + a task, or ``cylc set`` to spawn tasks that depend on specified outputs. +``cylc suite-state`` + - Renamed as ``cylc workflow-state``. + +.. rubric:: Commands that have changed: + +``cylc hold`` + - Now used on tasks only; use ``cylc pause`` to pause an entire workflow + (i.e. to halt all job submissions). +``cylc release`` + - Now used only to release held tasks; use ``cylc play`` to resume a paused workflow. + +.. rubric:: Graphical User Interfaces (GUIs): + +The GTK based GUI based GUIs have been removed, please use the new web based +GUI. Consequently the following commands have also been removed: + +- ``cylc gpanel`` +- ``cylc gscan`` +- ``cylc gcylc`` + +The ``cylc gui`` command remains, it launches a standalone version of the +web GUI (providing the `Cylc UI Server`_ is installed). + +Additionally, there are two +":ref:`compound commands `" +which automate common working practices, namely: + +``cylc vip`` + Validate, install and play a workflow. This is similar to what + ``rose suite-run`` did. +``cylc vr`` + Validate, reinstall, then either reload (if the workflow is running) or restart + (if it is stopped) the workflow. This is similar to what + ``rose suite-run --reload`` and ``rose suite-run --restart`` did. + + +Cylc 8 Standardised IDs +----------------------- + +In Cylc 7 there were two ways to specify a task: + +.. code-block:: none + + task.cycle + cycle/task + +In Cylc 8 the former is now deprecated, and the latter has been extended to +provide a unique identifier for all workflows, cycles, tasks and jobs using a +standard format: + +.. code-block:: none + + ~user/workflow//cycle/task/job + +Consequently task IDs have changed: + +.. code-block:: none + + # old + cycle.task + + # new + cycle/task + +An example using ``cylc trigger``: + +.. code-block:: bash + + # old + cylc trigger workflow task.cycle + + # new + cylc trigger workflow//cycle/task + +Cylc 8 still supports the old format, however, the new format unlocks extra +functionality e.g: + +.. code-block:: bash + + # stop all running workflows + cylc stop '*' + + # pause all running workflows + cylc pause '*' + + # (re-)trigger all failed tasks in all running workflows + cylc trigger '*//*:failed' + + # hold all tasks in the cycle "2000" in workflows with IDs + # beginning with "model" + cylc hold 'model*//2000' + + # delete the run directories for all workflows with IDs + # beginning with "model_a/" + cylc clean 'model_a/*' + +For more information run ``cylc help id``. + +.. _ID post on Discourse: https://cylc.discourse.group/t/cylc-8-id-changes/425 + +For a quick overview of the motivation see the `ID post on Discourse`_. diff --git a/nightly_8.3/html/_sources/7-to-8/major-changes/compatibility-mode.rst.txt b/nightly_8.3/html/_sources/7-to-8/major-changes/compatibility-mode.rst.txt new file mode 100644 index 0000000000..2d19dea402 --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/major-changes/compatibility-mode.rst.txt @@ -0,0 +1,238 @@ +.. _cylc_7_compat_mode: + +Cylc 7 Compatibility Mode +========================= + +.. admonition:: Does This Change Affect Me? + :class: tip + + This will affect you if you want to run Cylc 7 (``suite.rc``) workflows + using Cylc 8. + +Overview +-------- + +Cylc 8 can run most Cylc 7 workflows "as is". +The ``suite.rc`` filename triggers a backward compatibility mode in which: + +- :term:`implicit tasks ` are allowed by default + + - (unless a ``rose-suite.conf`` file is found in the :term:`run directory` + for consistency with ``rose suite-run`` behaviour) + - (Cylc 8 does not allow implicit tasks by default) + +- :term:`cycle point time zone` defaults to the local time zone + + - (Cylc 8 defaults to UTC) + +- waiting tasks are pre-spawned to mimic the Cylc 7 scheduling algorithm and + stall behaviour, and these require + :term:`suicide triggers ` + for alternate :term:`graph branching` + + - (Cylc 8 spawns tasks on demand, and suicide triggers are not needed for + branching) + +- ``succeeded`` task outputs are :ref:`required `, + so in the absence of suicide triggers the scheduler will retain other + :term:`final status` tasks in the :term:`n=0 window ` to stall the + workflow. + + - (in Cylc 8, **all** outputs are *required* unless marked as + :ref:`*optional* ` by the new ``?`` syntax) + + +.. _compat_required_changes: + +Required Changes +---------------- + +Providing your Cylc 7 workflow does not use syntax that was deprecated at Cylc 7, +you may be able to run it using Cylc 8 without any modifications while in +compatibility mode. + +First, run ``cylc validate`` **with Cylc 7** on your ``suite.rc`` workflow +to check for deprecation warnings and fix those before validating with Cylc 8. +See :ref:`below ` for an example. + +.. warning:: + + ``cylc validate`` operates on the processed ``suite.rc``, which + means it will not detect any deprecated syntax that is inside a + currently-unused Jinja2/EmPy ``if...else`` branch. + +Some workflows may require modifications to either upgrade to Cylc 8 or make +interoperable with Cylc 8 backward compatibility mode. Read on for more details. + + +Cylc commands in task scripts +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Check for any use of Cylc commands in task scripting. Some Cylc 7 commands +have been removed and some others now behave differently. +However, ``cylc message`` and ``cylc broadcast`` have *not* changed. +See the :ref:`full list of command line interface changes` +and see :ref:`below ` for an example. + + +Python 2 to 3 +^^^^^^^^^^^^^ + +Whereas Cylc 7 runs using Python 2, Cylc 8 runs using Python 3. This affects: +- modules imported in Jinja2 +- Jinja2 filters, tests and globals +- custom xtrigger functions + +Note that task scripts are not affected - they run in an independent +environment. + +See :ref:`py23` for more information and examples of how to implement +interoperability if your workflows extend Cylc or Jinja2 with custom Python scripts. + + +Other caveats +^^^^^^^^^^^^^ + +- Cylc 8 cannot *restart* a partially completed Cylc 7 workflow in-place. If + possible, complete the run with Cylc 7. Otherwise, see + :ref:`compat_continuing_c7_with_c8`. + +- Cylc 8 only transfers certain files and directories by default during + remote installation. See :ref:`728.remote-install` for more information. + +- Cylc 8 does not support + :ref:`excluding/including tasks at start-up`. + If your workflow used this old functionality, it may have been used in + combination with the ``cylc insert`` command (which has been removed from + Cylc 8) and ``cylc remove`` (which still exists but is much less needed). + +- Cylc 8 does not support :ref:`specifying remote usernames <728.remote_owner>` + using :cylc:conf:`flow.cylc[runtime][][remote]owner`. + + +Examples +-------- + +.. _compat.eg.c7val: + +Validating with Cylc 7 +^^^^^^^^^^^^^^^^^^^^^^ + +Consider this configuration: + +.. code-block:: cylc + :caption: ``suite.rc`` + + [scheduling] + initial cycle point = 11000101T00 + [[dependencies]] + [[[R1]]] + graph = task + + [runtime] + [[task]] + pre-command scripting = echo "Hello World" + +Running ``cylc validate`` at **Cylc 7** we see that the +workflow is valid, but we are warned that ``pre-command scripting`` +was replaced by ``pre-script`` at 6.4.0: + +.. code-block:: console + :caption: Cylc 7 validation + + $ cylc validate . + WARNING - deprecated items were automatically upgraded in 'suite definition': + WARNING - * (6.4.0) [runtime][task][pre-command scripting] -> [runtime][task][pre-script] - value unchanged + Valid for cylc-7.8.7 + +.. note:: + + **Cylc 7** has handled this deprecation for us, but at **Cylc 8** this + workflow will fail validation. + + .. code-block:: console + :caption: Cylc 8 validation + + $ cylc validate . + IllegalItemError: [runtime][task]pre-command scripting + +You must change the configuration yourself. In this case: + +.. code-block:: diff + + - pre-command scripting = echo "Hello World" + + pre-script = echo "Hello World" + +Validation will now succeed. + + +.. _compat.eg.cylc-commands: + +Cylc commands in task scripts +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You might have a task script that calls a Cylc command like so: + +.. code-block:: cylc + + [runtime] + [[foo]] + script = cylc hold "$CYLC_SUITE_NAME" + +The ``cylc hold`` command has changed in Cylc 8. It is now used for holding +tasks only; use ``cylc pause`` for entire workflows. +(Additionally, ``$CYLC_SUITE_NAME`` is deprecated in favour of +``$CYLC_WORKFLOW_ID``, though still supported.) + +In order to make this interoperable, so that you can run it with both Cylc 7 +and Cylc 8 backward compatibility mode, you could do something like this +in the bash script: + +.. code-block:: cylc + + [runtime] + [[foo]] + script = """ + if [[ "${CYLC_VERSION:0:1}" == 7 ]]; then + cylc hold "$CYLC_SUITE_NAME" + else + cylc pause "$CYLC_WORKFLOW_ID" + fi + """ + +Note this logic (and the ``$CYLC_VERSION`` environment variable) is executed +at runtime on the :term:`job host`. + +Alternatively, you could use :ref:`Jinja` like so: + +.. code-block:: cylc + + [runtime] + [[foo]] + {% if CYLC_VERSION is defined and CYLC_VERSION[0] == '8' %} + script = cylc pause "$CYLC_WORKFLOW_ID" + {% else %} + script = cylc hold "$CYLC_SUITE_NAME" + {% endif %} + +Note this logic (and the ``CYLC_VERSION`` Jinja2 variable) is executed locally +prior to Cylc parsing the workflow configuration. + + +Renaming to ``flow.cylc`` +------------------------- + +When your workflow runs successfully in backward compatibility mode, it is +ready for renaming ``suite.rc`` to ``flow.cylc``. Doing this will turn off +backward compatibility mode, and validation in Cylc 8 will show +deprecation warnings. + +.. seealso:: + + :ref:`configuration-changes` + +.. important:: + + More complex workflows (e.g. those with suicide triggers) may + fail validation once backward compatibility is off - see + :ref:`728.optional_outputs` diff --git a/nightly_8.3/html/_sources/7-to-8/major-changes/config-changes.rst.txt b/nightly_8.3/html/_sources/7-to-8/major-changes/config-changes.rst.txt new file mode 100644 index 0000000000..ea304c2c28 --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/major-changes/config-changes.rst.txt @@ -0,0 +1,124 @@ +.. _configuration-changes: + +Configuration Changes at Cylc 8 +=============================== + +Some configurations have moved or been renamed at Cylc 8. + +The old configurations are now deprecated, but still supported. +These will be highlighted upon ``cylc validate`` after renaming ``suite.rc`` +to ``flow.cylc``. + +Because some workflows use Jinja2 or EmPy branches which may not be switched on at +the time of the initial ``cylc validate`` we have also provided +a script, :ref:`cylc lint -r 728 ` to check for Cylc 7 +syntax which may be deprecated. + +There are some examples below of how to upgrade: + + +.. _7-to-8.graph_syntax: + +Graph +----- + +Cylc 7 had unnecessarily deep nesting of graph config sections: + +.. code-block:: cylc + + [scheduling] + initial cycle point = now + [[dependencies]] + [[[R1]]] + graph = "prep => foo" + [[[R/^/P1D]]] + graph = "foo => bar => baz" + +Cylc 8 cleans this up: + +.. code-block:: cylc + + [scheduling] + initial cycle point = now + [[graph]] + R1 = "prep => foo" + R/^/P1D = "foo => bar => baz" + + +Fixing deprecation warnings +--------------------------- + +Take the following example ``flow.cylc`` file: + +.. code-block:: cylc + + [cylc] + UTC mode = True + [scheduling] + initial cycle point = 2000-01-01 + [[dependencies]] + [[[R1]]] + graph = foo => bar + [runtime] + [[foo, bar]] + +This workflow will pass validation at Cylc 8, but will give warnings: + +.. code-block:: console + + $ cylc validate . + WARNING - deprecated items were automatically upgraded in "workflow definition" + WARNING - * (8.0.0) [cylc] -> [scheduler] - value unchanged + WARNING - deprecated graph items were automatically upgraded in "workflow definition": + * (8.0.0) [scheduling][dependencies][X]graph -> [scheduling][graph]X - for X in: + R1 + Valid for cylc-8.0.0 + +The warnings explain what needs to be fixed. After making the following changes, +the workflow will validate without any warnings: + +.. code-block:: diff + + -[cylc] + +[scheduler] + UTC mode = True + [scheduling] + initial cycle point = 2000-01-01 + - [[dependencies]] + - [[[R1]]] + - graph = foo => bar + + [[graph]] + + R1 = foo => bar + [runtime] + [[foo, bar]] + +.. tip:: + + Later Cylc releases will not be able to upgrade obsolete Cylc 7 + configurations. It's a good idea to address warnings as part of routine + workflow review and maintenance to avoid problems later on. + + +Platforms +--------- + +.. seealso:: + + - :ref:`Platforms at Cylc 8. ` + - :ref:`System admin's guide to writing platforms. ` + +At Cylc 7, job hosts were defined to indicate where a job should run. +At Cylc 8, this has been replaced by Platforms. + +.. code-block:: diff + + [runtime] + [[foo]] + - [[[job]]] + - batch system = slurm + - [[[remote]]] + - host = hpc1.login.1 + + platform = hpc1 + +For a comprehensive list of valid configuration, see: :ref:`workflow-configuration` +and :ref:`global-configuration`. diff --git a/nightly_8.3/html/_sources/7-to-8/major-changes/continuing-c7-c8.rst.txt b/nightly_8.3/html/_sources/7-to-8/major-changes/continuing-c7-c8.rst.txt new file mode 100644 index 0000000000..1e074aad4f --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/major-changes/continuing-c7-c8.rst.txt @@ -0,0 +1,46 @@ +.. _compat_continuing_c7_with_c8: + +Continuing a Cylc 7 Workflow with Cylc 8 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. admonition:: Does This Change Affect Me? + :class: tip + + Read this if you have a partially complete Cylc 7 workflow that you want to + continue, rather than start from scratch, with Cylc 8. Some cycling + workflows, for example, may need to run expensive "cold start" tasks and + incur a multi-cycle spin-up if started from scratch. + +.. warning:: + + Cylc 8 cannot restart a Cylc 7 workflow in-place, and continuing in a new + run directory involves some careful set up (below). So, **if possible you + should complete the run with Cylc 7**. + + +To continue a Cylc 7 workflow with Cylc 8: + +1. Stop the Cylc 7 workflow at an convenient place + + - Typically the end of a cycle point, to simplify the continuation +2. :ref:`Install ` a new instance of the workflow from + source, with Cylc 8 + + - Adapt file paths to the new run directory structure, in workflow and task + configurations + - Note Cylc 8 does :ref:`remote file installation <728.remote-install>` + when a job is first submitted to a platform +3. Copy runtime files needed by upcoming tasks from the old to the new run + directory + + - This could include external files installed by initial tasks at runtime + - Note different files could be present on different job platforms +4. Start the new Cylc 8 run at the appropriate cycle point or task(s) in the + graph + + - Don't reset the :term:`initial cycle point` (in the ``flow.cylc`` or on + the command line) to the :term:`start point ` of the + Cylc 8 run. That would result in the "cold start" that this continuation + procedure is designed to avoid. Instead use the ``--start-cycle-point`` + option (or ``--start-task``) with ``cylc play``, to start at the right + place within the graph. diff --git a/nightly_8.3/html/_sources/7-to-8/major-changes/cylc-install.rst.txt b/nightly_8.3/html/_sources/7-to-8/major-changes/cylc-install.rst.txt new file mode 100644 index 0000000000..361948002d --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/major-changes/cylc-install.rst.txt @@ -0,0 +1,205 @@ +.. _MajorChangesInstall: + +Cylc Install +============ + +.. seealso:: + + :ref:`User Guide: Installing Workflows ` + +.. admonition:: Does This Change Affect Me? + :class: tip + + **Almost certainly.** + + This change will affect you: + + - If you use ``rose suite-run`` to install and run Cylc workflows. + - If you usually develop Cylc workflows in the ``~/cylc-run`` directory. + - If you develop Cylc workflows outside of the ``~/cylc-run`` directory and + manually copy the files to ``~/cylc-run``. + + +Overview +-------- + +Cylc 7 ran workflows in ``~/cylc-run/``. You could develop your +workflow in ``~/cylc-run`` or copy it after developing it elsewhere. +If you developed in the ``~/cylc-run`` directory there was a risk that +Cylc might alter your files. If you developed elsewhere you needed to +install your workflows manually with another tool. + +We designed Cylc 8 to help you keep your development and +running copies separate. By default you can now develop workflows in the +``~/cylc-src`` directory. As a result, you will not change your development +copy by running a workflow. You will, however, need to install your workflow +from ``~/cylc-src`` to ``~/cylc-run`` using the ``cylc install`` command. + +.. note:: + + If you have previously used Rose, ``cylc install`` functions in a + similar way to ``rose suite-run --install-only``. + +Examples: + +- You can install a workflow from inside the source directory: + + .. code-block:: console + + $ cd ~/cylc-src/my-workflow + $ cylc install + INSTALLED my-workflow/run1 from /home/me/cylc-src/my-workflow + +- You can install a workflow by providing the workflow source name + (if the source directory is located in any of the + :ref:`configurable source dirs`, e.g. ``~/cylc-src``): + + .. code-block:: console + + $ cylc install my-workflow + INSTALLED my-workflow/run2 from /home/me/cylc-src/my-workflow + +- You can install a workflow by providing the path to the source directory: + + .. code-block:: console + + $ cylc install ~/cylc-src/my-workflow + INSTALLED my-workflow/run3 from /home/me/cylc-src/my-workflow + +.. note:: + + Each time you run ``cylc install`` for a particular workflow, a new copy of + the workflow is installed to a new run directory. In the example above, we + created three run directories inside ``~/cylc-run/my-workflow``. + +Once you have installed a workflow you can use ``cylc play`` to run it - see +:ref:`RunningWorkflows`. + +You can delete installed workflows using ``cylc clean`` - see +:ref:`Removing-workflows`. + +A ``.cylcignore`` file can be used to control which files ``cylc install`` +transfers to the installed workflow, see :ref:`File Installation` for details. + + +.. _728.remote-install: + +Remote Installation +------------------- + +Remote file installation does not occur until running the workflow. +When the first task runs on a remote platform, Cylc will transfer files from +the :term:`run directory` to the :term:`install target`. + +If you have used Rose 2019, you may be used to all files and directories in +the run directory being included. +However, Cylc 8 will only copy the ``ana``, ``app``, ``bin``, ``etc`` and +``lib`` directories by default (in addition to authentication files in +``.service``). +If you want to include custom files and directories in remote installation, +use :cylc:conf:`flow.cylc[scheduler]install`. + +.. tip:: + + If you need to ensure your workflow is still + :ref:`interoperable ` with Cylc 7, wrap it in a + Jinja2 check like so: + + .. code-block:: cylc + + {% if CYLC_VERSION is defined and CYLC_VERSION[0] == '8' %} + [scheduler] + install = my-dir/, my-file + {% endif %} + +See :ref:`the user guide ` for more details. + +.. warning:: + + If you have tasks that mirror/copy the run directory to a remote platform + (such as `FCM make `__ tasks), this can cause conflicts with + :ref:`symlink directory setup `. + + You can find out if symlink directories are configured for the platform by + running:: + + cylc config -i '[install][symlink dirs][]' + + The recommended workaround is to use a "dummy" task that runs on the + particular platform before any such mirror tasks in order to setup symlink + directories, but without running anything. + + For example: + + .. code-block:: cylc + + [scheduling] + [[graph]] + R1 = hpc_init => fcm_make + + [runtime] + [[hpc_init]] + platform = + script = true + + +Migrating From ``rose suite-run`` +--------------------------------- + +The ``rose suite-run`` command has been replaced by ``cylc install``. + +.. code-block:: bash + + # rose 2019 / Cylc 7 + $ rose suite-run + + # rose 2 / Cylc 8 + $ cylc install + $ cylc play + +Support for the ``rose-suite.conf`` file is provided by the :ref:`Cylc Rose` +plugin which must be installed for Rose integration. + +.. spoiler:: Installation + :class: hint + + See the :ref:`installation` section for instructions. + + If Cylc Rose is installed it should appear in the list of installed + Cylc plugins: + + .. code-block:: console + + $ cylc version --long + 8.0 (/path/to/cylc-8) + + Plugins: + cylc-rose 0.1.1 /path/to/cylc-rose + +Notable differences to ``rose suite-run`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Command line options: + The ``cylc install`` command remembers any options specified on the command + line including Rose optional configurations and template variables and + automatically applies them with future re-installations. +Rose Stem: + The ``rose stem`` command is provided by Cylc Rose. Like ``rose suite-run``, + ``rose stem`` used to install and run workflows. It now only + installs the workflow which can then be run with ``cylc play``. + + See the :ref:`Rose Stem` documentation for more information. +Roses directory: + By default ``cylc install`` looks for workflows in ``~/cylc-src``, you + you may want to add ``~/roses`` to the list of + :cylc:conf:`global.cylc[install]source dirs`. +Remote Installation: + With Rose 2019 / ``rose suite-run``, files were installed on remote platforms + before the *workflow* started running. + + With Rose 2 / ``cylc install``, files are installed on remote platforms just + before the *first task* runs on that platform. + + Rose used to install the entire workflow :term:`run directory` to remote + platforms. It now only installs configured directories for efficiency. + See `Remote Installation`_ above for details. diff --git a/nightly_8.3/html/_sources/7-to-8/major-changes/excluding-tasks.rst.txt b/nightly_8.3/html/_sources/7-to-8/major-changes/excluding-tasks.rst.txt new file mode 100644 index 0000000000..e3cefa66cd --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/major-changes/excluding-tasks.rst.txt @@ -0,0 +1,43 @@ +.. _MajorChangesExcludingTasksAtStartup: + +Excluding Tasks at Start-up is Not Supported +============================================ + +.. admonition:: Does This Change Affect Me? + :class: tip + + This will affect you if your workflows use the following configurations: + + * ``[scheduling][special tasks]include at start-up`` + * ``[scheduling][special tasks]exclude at start-up`` + + +Overview +-------- + +The Cylc 7 scheduler allowed you to exclude tasks from the scheduler at start-up: + +.. code-block:: cylc + + # Cylc 7 only + [scheduling] + [[special tasks]] + include at start-up = foo, bar, baz # Cylc 8 ERROR! + exclude at start-up = bar # Cylc 8 ERROR! + +The first config item above excludes all task names not in the include-list; +the second excludes specific tasks that would otherwise be included. + +The Cylc 7 scheduler started up with an instance of every task in its "task +pool", and the workflow evolved by each task spawning its own next-cycle +instance at the right time. So, if you excluded a task a start-up it would not +run in the workflow at all unless manually inserted later at runtime. + +The Cylc 8 scheduler starts up with only the initial tasks in the graph and the +workflow evolves by spawning new tasks on demand as dictated by the graph. +Consequently excluding a task at start up as described above would have no +effect at all on most tasks. + +This feature also predated the current Cylc dependency graph configuration. To +exclude tasks now without entirely removing them from the workflow definition, +just comment them out of the graph. diff --git a/nightly_8.3/html/_sources/7-to-8/major-changes/index.rst.txt b/nightly_8.3/html/_sources/7-to-8/major-changes/index.rst.txt new file mode 100644 index 0000000000..ef14eb5acf --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/major-changes/index.rst.txt @@ -0,0 +1,15 @@ +Detailed Description of Major Changes +===================================== + +This section goes into detail on some of the major changes that you may need to +understand to migrate from Cylc 7 to Cylc 8. + +.. toctree:: + :maxdepth: 1 + :glob: + + * + +.. TODO - Split into breaking changes and other Major Changes + +.. TODO - Add a page with a Cylc 7 suite needing upgrading. diff --git a/nightly_8.3/html/_sources/7-to-8/major-changes/parameters.rst.txt b/nightly_8.3/html/_sources/7-to-8/major-changes/parameters.rst.txt new file mode 100644 index 0000000000..c1ed14d96a --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/major-changes/parameters.rst.txt @@ -0,0 +1,100 @@ +Parameters +========== + +.. admonition:: does this change affect me? + :class: tip + + If you use Cylc parameters with negative offsets (e.g. ``foo``). + + +Overview +-------- + +There has been a subtle change in the way negative offsets are handled in parameters. + + +Example +------- + +If you have a parameter ``x`` with the values 1, 2 & 3: + +.. code-block:: cylc + + [task parameters] + x = 1..3 + +And use it like so: + +.. code-block:: cylc-graph + + a => b => c + +There is some ambiguity about how this should be interpreted when ``x=1`` +because ```` would be ``0`` which is not a valid value for the parameter +``x``. + +Cylc 7 removed the part of the expression which was out of range resulting in a +partial evaluation of that line: + +.. code-block:: cylc-graph + + b_x1 => c_x1 # x=1 + a_x1 => b_x2 => c_x2 # x=2 + a_x2 => b_x3 => c_x3 # x=3 + +Whereas Cylc 8 will remove everything after the first out-of-range parameter - ```` (so the entire line for this example): + +.. code-block:: cylc-graph + + a_x1 => b_x2 => c_x2 # x=2 + a_x2 => b_x2 => c_x2 # x=3 + + +Migration +--------- + +If your workflow depends on the Cylc 7 behaviour, then the solution is +to break the expression into two parts which Cylc will then evaluate separately. + +.. code-block:: diff + + - a => b => c + + a => b + + b => c + +Resulting in: + +.. code-block:: cylc-graph + + # a => b + a_x1 => a_x2 # x=2 + a_x2 => a_x3 # x=3 + + # b => c + b_x1 => c_x1 # x=1 + b_x2 => c_x2 # x=2 + b_x3 => c_x3 # x=3 + + +Line Breaks +----------- + +Note that these expressions are all equivalent: + +.. list-table:: + :class: grid-table + + * - .. code-block:: + + a => b => c + + - .. code-block:: + + a => + b => + c + + - .. code-block:: + + a => b => \ + c diff --git a/nightly_8.3/html/_sources/7-to-8/major-changes/platforms.rst.txt b/nightly_8.3/html/_sources/7-to-8/major-changes/platforms.rst.txt new file mode 100644 index 0000000000..d97f26dbb4 --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/major-changes/platforms.rst.txt @@ -0,0 +1,262 @@ +.. _MajorChangesPlatforms: + +Platforms +========= + +.. admonition:: Does This Change Affect Me? + :class: tip + + Cylc platforms are a new feature which replace the task ``job`` and + ``remote`` configuration sections: + + * :cylc:conf:`[runtime][][job]` + * :cylc:conf:`[runtime][][remote]` + + +Overview +-------- + +.. note:: + + - The terms :term:`platform` and job platform are equivalent. + - The terms :term:`job runner` (in Cylc 8 configurations) and batch system + (in Cylc 7 configurations) are equivalent. + +Submitting a job to a :term:`job runner` may require configuration. + +In Cylc 7 this configuration must be provided for each task in the workflow +configuration (``suite.rc``). + +In Cylc 8 "platforms" can be defined in the global configuration +(:cylc:conf:`global.cylc`) so that this configuration doesn't have to be +repeated for each task in each workflow. + +There may be cases where sets of platforms (for example a group of +standalone compute servers, or a pair of mirrored HPC's) might be equally +suitable for a task. Such platforms can be set up to be ``platform groups`` + +.. seealso:: + + :ref:`ListingAvailablePlatforms` for details of how to list platforms + already defined. + + :ref:`AdminGuide.PlatformConfigs` for detailed examples of platform + configurations. + +.. tip:: + + Cylc 8 contains upgrade logic (:ref:`see below `) + which handles the deprecated Cylc 7 settings in most cases. + Unless you are in :ref:`backward compatibility mode `, + you should upgrade to using platforms instead. + Deprecated settings will be removed in a later release of Cylc. + + +What is a Platform? +------------------- + +A "platform" represents one or more hosts from which jobs can be submitted to or +polled from a common job submission system. + +If a platform has multiple hosts Cylc will automatically select a host when +needed and will fallback to other hosts if it is not contactable. + +A "platform group" represents a collection of independent platforms. Cylc will +automatically select a platform and will fallback to other platforms in the +group (for appropriate operations) if the platform is not contactable. + + +Examples +-------- + +.. seealso:: + + :cylc:conf:`global.cylc[platforms]` has a detailed explanation of how + platforms and platform groups are defined. + +Simple example +^^^^^^^^^^^^^^ + +Consider this Cylc 7 syntax in a ``flow.cylc`` file: + +.. code-block:: cylc + + [runtime] + [[mytask]] + [[[job]]] + batch system = slurm + [[[remote]]] + host = login_node01 + +The Cylc 8 global config (``global.cylc``) might contain: + +.. code-block:: cylc + + [platforms] + [[our_cluster]] + hosts = login_node01, login_node02 + job runner = slurm + +.. tip:: + + You can view the platforms available at your site by running:: + + cylc config --platforms + +The platform ``our_cluster`` matches the current configuration due to having +the same job runner (batch system) and correct hosts. Thus we can replace the +deprecated syntax: + +.. code-block:: diff + + [runtime] + [[mytask]] + - [[[job]]] + - batch system = slurm + - [[[remote]]] + - host = login_node01 + + platform = our_cluster + + +A variety of other examples +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Here are some example Cylc 7 task definitions: + +.. code-block:: cylc + + [runtime] + [[mytask_cylc_server]] + + [[mytask_big_server]] + [[[remote]]] + host = linuxbox42 + + [[mytask_submit_local_to_remote_computer]] + [[[job]]] + batch system = pbs + + [[mytask_login_to_hpc_and_submit]] + [[[remote]]] + # e.g. rose host-select + host = $(supercomputer_login_node_selector_script) + [[[job]]] + batch system = slurm + + +This will result in Cylc running: + +- ``mytask_cylc_server`` on the machine the workflow is running on. +- ``mytask_big_server`` on ``linuxbox42``, using background. +- ``mytask_submit_local_to_remote_computer`` on a system where you can + use PBS to submit from the workflow server. +- ``mytask_login_to_hpc_and_submit`` on a host set by the subshelled + script using Slurm. + +At Cylc 8 the equivalent might be: + +.. code-block:: cylc + + [runtime] + [[mytask_cylc_server]] + + [[mytask_big_server]] + platform = linuxbox42 + + [[mytask_submit_local_to_remote_computer]] + platform = pbs_local + + [[mytask_login_to_hpc_and_submit]] + # Recommended: + platform = slurm_supercomputer + # ...but This is still legal: + #platform = $(selector-script) + +And the platform settings for these examples might be: + +.. code-block:: cylc + + [platforms] + [[linuxbox\d\d]] # Regex to allow any linuxboxNN to use this definition + # Without a hosts, platform name is used as a single host. + + [[pbs_local]] + # A computer with PBS, that takes local job submissions + job runner = pbs + hosts = localhost + install target = localhost + + [[slurm_supercomputer]] + # This computer with Slurm requires you to use a login node. + hosts = login_node01, login_node02 # Cylc will pick a host. + job runner = slurm + + +Note that in these examples, it is assumed that ``linuxboxNN``, ``pbs_local`` and +``slurm_supercomputer`` have distinct file systems. +Sets of platforms which share a file system must specify +a single :ref:`install target `. + +.. note:: + If an install target is not set, a platform will use its own platform name + as the install target name. If multiple platforms share a file system + but have separate :ref:`install targets ` task initialization + will fail. + +.. _host-to-platform-logic: + +How Cylc 8 handles host-to-platform upgrades +-------------------------------------------- + +If you are using the deprecated ``[remote]`` and ``[job]`` runtime sections, +Cylc 8 will attempt to find a platform which matches the task specification. + +.. important:: + + Cylc 8 needs platforms matching the Cylc 7 job configuration to be + available in :cylc:conf:`global.cylc[platforms]`. + + +Example +^^^^^^^ + +If, for example you have a **Cylc 8** ``global.cylc`` with the following +platforms section: + +.. code-block:: cylc + + [platforms] + [[supercomputer_A]] + hosts = localhost + job runner = slurm + install target = localhost + [[supercomputer_B]] + hosts = tigger, wol, eeyore + job runner = pbs + +And you have a workflow runtime configuration: + +.. code-block:: cylc + + [runtime] + [[task1]] + [[[job]]] + batch system = slurm + [[task2]] + [[[remote]]] + host = eeyore + [[[job]]] + batch system = pbs + +Then, ``task1`` will be assigned platform +``supercomputer_A`` because the specified host (implicitly ``localhost``) +is in the list of hosts for ``supercomputer_A`` **and** the batch system is the same. +Likewise, ``task2`` will run on ``supercomputer_B``. + +.. important:: + + For simplicity, and because the ``host`` key is a special case (it can + match and host in ``[platform]hosts``) we only show these two config keys + here. In reality, **Cylc 8 compares the whole of** + ``[][job]`` **and** ``[][remote]`` + **sections and all items must match to select a platform.** diff --git a/nightly_8.3/html/_sources/7-to-8/major-changes/play-pause-stop.rst.txt b/nightly_8.3/html/_sources/7-to-8/major-changes/play-pause-stop.rst.txt new file mode 100644 index 0000000000..b7e9d75076 --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/major-changes/play-pause-stop.rst.txt @@ -0,0 +1,123 @@ +.. _728.play_pause_stop: + +Play Pause Stop +=============== + +.. admonition:: Does This Change Affect Me? + :class: tip + + Yes if you run Cylc workflows. + + +Overview +-------- + +Cylc 8 uses a simplified model for controlling workflows based on the controls +of a tape player. + +There are now three controls, play, pause and stop: + +* When a workflow is playing, the :term:`scheduler` is running. +* When a workflow is paused, no new jobs will be submitted. +* When a workflow is stopped the :term:`scheduler` is no longer running. + +These controls are available in the web GUI or on the command line with the +commands: + +* ``cylc play`` +* ``cylc pause`` +* ``cylc stop`` + +A workflow can be safely played, paused and stopped any number of times without +interrupting the workflow. + + +Re-Running Workflows +-------------------- + +The ``cylc play`` command will always pick up where it left off (a +:term:`restart`). + +If you want to re-run the entire workflow again from the start either: + +* :ref:`Install a new run`. +* Or if you want to keep the data from the old run start a new :term:`flow` at + the beginning of the graph, and stop the original flow. + +It is still possible to re-run workflows in-place in the Cylc 7 manner, however, +this is discouraged. +To do this remove the workflow database as well as any other evidence of the +previous run that is no longer desired: + +.. code-block:: bash + + # remove the workflow database, the work, share and log directories + cylc clean --rm .service/db:work:share:log + + # only remove the worflow database + $ cylc clean --rm .service/db + +Then restart with ``cylc play``. + + +Hold & Release +-------------- + +The ``cylc hold`` and ``cylc release`` commands are still present. These +work on individual tasks rather than the workflow as a whole. + + +Mapping To Old Commands +----------------------- + +.. list-table:: + :class: grid-table + + * - + - **Cylc 7** + - **Rose 2019** + - **Cylc 8** (Rose 2) + + * - Play + - :: + + cylc run + - :: + + rose suite-run + - :: + + cylc play + + * - Pause + - :: + + cylc hold + - :: + + cylc hold + - :: + + cylc pause + + * - Resume + - :: + + cylc release + - :: + + cylc release + - :: + + cylc play + + * - Stop + - :: + + cylc stop + - :: + + rose suite-shutdown + - :: + + cylc stop diff --git a/nightly_8.3/html/_sources/7-to-8/major-changes/python-2-3.rst.txt b/nightly_8.3/html/_sources/7-to-8/major-changes/python-2-3.rst.txt new file mode 100644 index 0000000000..aa79f79a59 --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/major-changes/python-2-3.rst.txt @@ -0,0 +1,144 @@ +.. _py23: + +Python 2 => 3 +============= + +.. admonition:: Does This Change Affect Me? + :class: tip + + This change will affect you if your workflows extend Cylc or Jinja2 with + custom Python scripts. + + This does not impact :term:`task` scripts; Cylc can still run Python 2 + tasks if desired. + + +Overview +-------- + +.. _six: https://pypi.org/project/six/ + +Cylc 7 ran under Python 2; Cylc 8 runs under Python 3. + +Cylc can be extended with custom Python scripts. These scripts are run under +the same version of Python used by Cylc. + +As a result, if you are moving from Cylc 7 to Cylc 8, you must upgrade any +scripts from Python 2 to Python 3 in the process. + +If you want to support both Cylc 7 and 8, you must support both Python 2 and 3. +There are tools to help you do this, e.g. `six`_. + + +Impacted Scripts +---------------- + +The following scripts must be upgraded if used: + +:ref:`CustomJinja2Filters` + These allow you to extend Jinja2 with Python code. + + These scripts are located in the following directories within a workflow: + + * ``Jinja2Filters`` + * ``Jinja2Tests`` + * ``Jinja2Globals`` + +:ref:`Modules imported by Jinja2 ` + Python modules can be imported from Jinja2 e.g: + + .. code-block:: jinja + + {% from "os" import path %} + +:ref:`Custom Trigger Functions` + Any custom xtrigger functions. + + +Package Name Changes +-------------------- + +Three Python packages have been renamed between Cylc 7 and Cylc 8: + +* ``cylc`` => ``cylc.flow`` +* ``isodatetime`` => ``metomi.isodatetime`` +* ``rose`` => ``metomi.rose`` + +If you are importing from these packages you will need to update the package names. + +Here are some examples: + +.. rubric:: Convert Python code from Cylc 7 to Cylc 8: + +.. code-block:: diff + + - from cylc import LOG + + from cylc.flow import LOG + - from isodatetime.data import Duration + + from metomi.isodatetime.data import Duration + +.. rubric:: Python code which supports both Cylc 7 & Cylc 8: + +.. code-block:: python + + import sys + if sys.version[0] == '3': + from cylc.flow import LOG + from metomi.isodatetime.data import Duration + else: + from cylc import LOG + from isodatetime.data import Duration + +.. rubric:: Convert Jinja2 code from Cylc 7 to Cylc 8: + +.. code-block:: diff + + #!Jinja2 + - {% from "cylc" import LOG %} + + {% from "cylc.flow" import LOG %} + {% do LOG.debug("Hello World!") %} + +.. rubric:: Jinja2 code which supports both Cylc 7 & Cylc 8: + +.. code-block:: jinja + + #!Jinja2 + {% from "sys" import version -%} + {% if version[0] == '3' -%} + {% from "cylc.flow" import LOG -%} + {% else -%} + {% from "cylc" import LOG -%} + {% endif -%} + + {% do LOG.debug("Hello World!") %} + + +Jinja2 - integers with leading zeros +------------------------------------ + +Integers with leading zeros in Jinja2 expressions are now illegal and will +cause an error like ``Jinja2Error: expected token 'x', got 'integer'``. +For example: + +.. code-block:: console + + $ cylc validate my-workflow + Jinja2Error: expected token 'end of statement block', got 'integer' + File ~/cylc-run/my-workflow/flow.cylc + {% if START_HOUR == 06 or START_HOUR == 12 %} <-- TemplateSyntaxError + +The solution in this case is: + +.. code-block:: diff + + -{% if START_HOUR == 06 or START_HOUR == 12 %} + +{% if START_HOUR == 6 or START_HOUR == 12 %} + + +Rose +---- + +The same changes also impact Rose extensions: + +* :ref:`Rose Macros ` +* :ref:`Rose Ana Tasks ` diff --git a/nightly_8.3/html/_sources/7-to-8/major-changes/remote-owner.rst.txt b/nightly_8.3/html/_sources/7-to-8/major-changes/remote-owner.rst.txt new file mode 100644 index 0000000000..433be640e3 --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/major-changes/remote-owner.rst.txt @@ -0,0 +1,40 @@ +.. _728.remote_owner: + +Remote Usernames +================ + +.. admonition:: does this change affect me? + :class: tip + + * If you set :cylc:conf:`flow.cylc[runtime][][remote]owner` + * If you use ``--owner`` on the command line + + +Overview +-------- + +If your username differs between the :term:`scheduler` host and job hosts, then +you may have configured Cylc to run jobs under the correct account using +:cylc:conf:`flow.cylc[runtime][][remote]owner` +or used the ``--owner`` Cylc command line option +with commands which access remote hosts. + +.. _SSH configuration file: https://man.openbsd.org/ssh_config + +Cylc no longer supports specifying the username in this way, we suggest +configuring your remote username using the `SSH configuration file`_ e.g: + +.. code-block:: none + + Host MyHost + User root + +SSH will then automatically use the configured username when connecting to the +remote machine. + +Since Cylc uses SSH and Rsync to manage job hosts, the SSH config also configures +Cylc. + +.. note:: + + This approach using the SSH configuration file also works with Cylc 7. diff --git a/nightly_8.3/html/_sources/7-to-8/major-changes/scheduling.rst.txt b/nightly_8.3/html/_sources/7-to-8/major-changes/scheduling.rst.txt new file mode 100644 index 0000000000..1da463951d --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/major-changes/scheduling.rst.txt @@ -0,0 +1,47 @@ +.. _728.scheduling_algorithm: + +Scheduling Algorithm +==================== + +.. seealso:: + + Migration Guide: + + * :ref:`728.optional_outputs` + + User Guide: + + * :ref:`User Guide Required Outputs` + * :ref:`User Guide Optional Outputs` + * :ref:`user-guide-reflow` + * :ref:`n-window` + +Cylc can manage infinite workflows of repeating tasks: + +.. image:: ../../img/cycling.png + :align: center + +Cylc 8 has a new scheduling algorithm that: + +- Is much more efficient because it only has to manage active tasks + + - waiting tasks are not pre-spawned before they are needed + - succeeded tasks are not kept across the active task window + - no costly indiscriminate dependency matching is done +- Distinguishes between :term:`optional ` and + :term:`required ` task outputs, to support: + + - :term:`graph branching` without :term:`suicide triggers ` + - correct diagnosis of :term:`workflow completion` +- Causes no implicit dependence on previous-instance job submit + + - instances of same task can run out of cycle point order + - the workflow will not unnecessarily stall downstream of failed tasks +- Provides a sensible active-task based window on the evolving workflow + + - (to fully understand which tasks appeared in the Cylc 7 GUI you had to + understand the scheduling algorithm) +- Supports multiple concurrent :term:`flows` within the same workflow. +- Can start a workflow from any task or tasks in the graph (no need for + checkpoint restart) +- Can limit activity within as well as across cycles, without risking a stall diff --git a/nightly_8.3/html/_sources/7-to-8/major-changes/suicide-triggers.rst.txt b/nightly_8.3/html/_sources/7-to-8/major-changes/suicide-triggers.rst.txt new file mode 100644 index 0000000000..c24e925b4c --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/major-changes/suicide-triggers.rst.txt @@ -0,0 +1,110 @@ +.. _728.optional_outputs: + +Graph branching, optional outputs and suicide triggers +====================================================== + +Cylc 8 has a :ref:`new scheduling algorithm <728.scheduling_algorithm>` and +a new syntax for dealing with tasks that may not necessarily complete. +It handles :term:`graphs ` in an event-driven manner which means +that a workflow can follow different paths in different eventualities (without +the need for suicide triggers). This is called :term:`graph branching`. + +.. admonition:: Does This Change Affect Me? + :class: tip + + This change affects you if you are upgrading a Cylc 7 workflow that + contains graph branches that are not necessarily expected to complete + at runtime. You might get a ``GraphParseError`` during validation with + Cylc 8. + + Typically this will be the case if you are using + :term:`suicide triggers ` (marked by ``!`` before the + task name in the graph, e.g. ``foo:fail => !foo``). + + You should *not* perform this upgrade if still in :ref:`cylc_7_compat_mode` + (``suite.rc`` filename). + + +Required Changes +^^^^^^^^^^^^^^^^ + +Any :term:`task outputs ` that are not necessarily expected to +complete must be marked as :term:`optional ` using ``?``. +Suicide triggers can then be removed. + +Example +^^^^^^^ + +Here is an example Cylc 7 :term:`graph`: + +.. code-block:: cylc-graph + + foo:fail => recover + + foo | recover => bar + + # Remove the "recover" task in the success case. + foo => ! recover + # Remove the "foo" task in the fail case. + recover => ! foo + +.. digraph:: Example + :align: center + + subgraph cluster_1 { + label = ":fail" + color = "red" + fontcolor = "red" + style = "dashed" + recover + } + + foo -> recover + recover -> bar [arrowhead="onormal"] + foo -> bar [arrowhead="onormal" weight=2] + +Validating this with Cylc 8 will give an error: + +.. code-block:: console + + $ cylc validate . + GraphParseError: Opposite outputs foo:succeeded and foo:failed must both be optional if both are used + +In Cylc 8, all task outputs are :term:`required ` to complete +unless otherwise indicated. However, it is impossible for both ``:succeed`` +and ``:fail`` to occur when a task runs. + +The solution is to mark the outputs which are :term:`optional ` +(in this case ``foo:succeed`` and ``foo:fail``) with a ``?`` in the graph. +Also, the suicide triggers can be removed. + +.. code-block:: diff + + - foo:fail => recover + + foo:fail? => recover + + - foo | recover => bar + + foo? | recover => bar + + - # Remove the "recover" task in the success case. + - foo => ! recover + - # Remove the "foo" task in the fail case. + - recover => ! foo + +In Cylc 7, suicide triggers were used to remove tasks that did not complete +during runtime. Cylc 8's event-driven graph handling allows such graph +branching using optional output syntax, without the need for suicide triggers. +(Suicide triggers are still supported in Cylc 8; however, they are most +likely unnecessary.) + +.. tip:: + + Remember: ``foo?`` is short for ``foo:succeed?``. It is the *output* + that is optional, not the task itself. + +.. seealso:: + + - :ref:`Required ` and + :ref:`optional ` outputs in the User Guide. + + - :ref:`Graph Branching` in the user guide. diff --git a/nightly_8.3/html/_sources/7-to-8/major-changes/task-job-states.rst.txt b/nightly_8.3/html/_sources/7-to-8/major-changes/task-job-states.rst.txt new file mode 100644 index 0000000000..3265b1c271 --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/major-changes/task-job-states.rst.txt @@ -0,0 +1,24 @@ +.. _728.task_job_states: + +Task/Job States +=============== + +.. seealso:: + + - User Guide :ref:`task-job-states` + +:term:`Tasks ` are nodes in the abstract workflow graph representing +processes that should run once their prerequisites are satisfied. :term:`Jobs +` are the real processes submitted to execute these tasks (or at least, at +the submission stage, real job scripts). A task can have multiple jobs, by +automatic retries and manual re-triggering. + +Cylc 7 had 13 task/job states. The GUI only showed tasks, with job data +from the latest job. + +Cylc 8 has only 8 task/job states. The Cylc 8 UI shows both task and jobs. +Task icons are monochrome circles; job icons are coloured squares. The running +task icon incorporates a radial progress indicator. + +.. image:: ../../img/task-job.png + :align: center diff --git a/nightly_8.3/html/_sources/7-to-8/major-changes/template-vars.rst.txt b/nightly_8.3/html/_sources/7-to-8/major-changes/template-vars.rst.txt new file mode 100644 index 0000000000..a97836bada --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/major-changes/template-vars.rst.txt @@ -0,0 +1,95 @@ +Template Variables +================== + +.. admonition:: Does This Change Affect Me? + :class: tip + + Read this section if you set Cylc template variables on the command line + using the ``-s``, ``--set`` or ``-set-file`` options. + + This does *not* affect the Rose ``jinja2:suite.rc`` and + ``empy:suite.rc`` variables set using the ``-S`` option to the + ``rose suite-run`` command. + + +Overview +-------- + +Template variables are passed to :ref:`Jinja2 ` or +:ref:`EmPy ` for parsing the workflow definition in the +:cylc:conf:`flow.cylc` file. + +In Cylc 7 template variables could only be strings, in Cylc 8 they can be any +valid Python literal including numbers, booleans, and lists. + + +Changes +------- + +Strings must be explicitly quoted i.e. ``key="value"`` rather than ``key=value``. + + +Example +------- + +.. rubric:: Setting template variables on the command line: + +.. code-block:: bash + + # Cylc 7 + cylc run -s 'FOO=abc' + # Cylc 8 + cylc play -s 'FOO="abc"' + + +.. rubric:: Setting template variables in a "set file" (using ``--set-file``): + +.. code-block:: python + + # Cylc 7 + FOO = abc + BAR = bcd + + # Cylc 8 + FOO = "abc" + BAR = "bcd" + + +New Features +------------ + +Any valid Python literals +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Template variables can now be any valid Python literals e.g: + +.. code-block:: python + + "string" # string + 123 # integer + 12.34 # float + True # boolean + None # None type + [1, 2, 3] # list + (1, 2, 3) # tuple + {1, 2, 3} # set + {"a": 1, "b": 2, "c": 3} # dictionary + +See :ref:`jinja2-template-variables` for more information. + +Shorthand for list of strings +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. versionadded:: 8.2 + +A new shorthand argument (``-z``/``--set-list``/``--set-template``) +has been introduced allowing easier definition of template +variables containing lists of strings on the command line: + +.. code-block:: shell + + # Before (still works) + cylc --set "X=['a', 'b', 'c']" + + # After + cylc --set-list X=a,b,c diff --git a/nightly_8.3/html/_sources/7-to-8/major-changes/ui.rst.txt b/nightly_8.3/html/_sources/7-to-8/major-changes/ui.rst.txt new file mode 100644 index 0000000000..f867e529c7 --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/major-changes/ui.rst.txt @@ -0,0 +1,87 @@ +.. _728.ui: + +Cylc 8 UIs +========== + +There are two UI options available to monitor and control workflows at Cylc 8. + + +Cylc Tui +-------- + +Cylc Tui (TUI = Terminal User Interface) is a command line version of the GUI +which comes packaged with the Cylc scheduler. + +It can be used to monitor and control any workflows running under your user +account, trigger tasks, access log files and perform other common activities. + +Start Tui by running the ``cylc tui`` command. + +.. figure:: ../../img/tui-1.png + :figwidth: 80% + :align: center + + Tui showing the details of a failed job. + +.. figure:: ../../img/tui-2.png + :figwidth: 80% + :align: center + + A list of actions that can be performed on the selected task. + +.. figure:: ../../img/tui-3.png + :figwidth: 80% + :align: center + + Tui displaying the workflow configuration. It can also show scheduler and + job log files. + +Tui replaces the Cylc 7 ``cylc monitor`` command. + + +Cylc Web GUI +------------ + +The Cylc GUI application is a monitoring and control application which runs in +a web browser, it is distributed in the `Cylc UI Server`_ package which comes +separately from the core scheduler. + +Start the GUI server and open the web app in your browser by running +``cylc gui``. + +.. figure:: ../../img/cylc-ui-dash.png + :figwidth: 80% + :align: center + + The GUI homepage. + +.. figure:: ../../img/cylc-ui-tree.png + :figwidth: 80% + :align: center + + The GUI displaying a workflow using the "tree" view. + +See :ref:`UI_Server_config` for how to configure the GUI. + +As some workflows can be very large, or even infinite, the GUI uses a "window" +system to determine what to display. For more information, see :ref:`n-window`. + + +Cylc Hub +-------- + +The Cylc 8 GUI can be deployed with Jupyter Hub to support multi-user access +where it is possible to grant users the permission to view and interact with +workflows running under other user accounts. In these deployments, users will +have to authenticate when they open the GUI in the browser. + +The central server is started by the ``cylc hub`` command. + +.. figure:: ../../img/hub.png + :figwidth: 80% + :align: center + + The Jupyter Hub authentication page in a multi-user setup. + +Multi-user setups need to be configured by site administrators, for more +information see :ref:`cylc.uiserver.multi-user`. diff --git a/nightly_8.3/html/_sources/7-to-8/summary.rst.txt b/nightly_8.3/html/_sources/7-to-8/summary.rst.txt new file mode 100644 index 0000000000..5a92a86067 --- /dev/null +++ b/nightly_8.3/html/_sources/7-to-8/summary.rst.txt @@ -0,0 +1,294 @@ +.. _728.overview: + +Summary Of Major Changes +======================== + +Terminology +----------- + +Cylc now uses more widely understood terms for several core concepts. + +.. table:: + + ============= ============== + Cylc 7 Term Cylc 8 Term + ============= ============== + suite *workflow* + batch system *job runner* + suite daemon *scheduler* + ``suite.rc`` ``flow.cylc`` + ============= ============== + +Note the configuration filename is now ``flow.cylc``, not ``suite.rc``. + +Cylc 7 Compatibility Mode +------------------------- + +Continuing to use the old ``suite.rc`` filename triggers a :ref:`backward +compatibility mode` in Cylc 8 which supports Cylc 7 +workflow configurations out of the box, with +:ref:`some caveats `. However, to future-proof +your workflow and take full advantage of Cylc 8 you should upgrade to Cylc 8 syntax. + +Upgrading To Cylc 8 +------------------- +.. seealso:: + + * Major Changes: :ref:`configuration-changes` + * Major Changes: :ref:`cylc_7_compat_mode` + +There have been some configuration changes at Cylc 8. +To upgrade your Cylc 7 suite to a Cylc 8 workflow, first make sure it validates +in Cylc 7 without any warnings, then rename the workflow configuration file +from ``suite.rc`` to ``flow.cylc``, then run ``cylc validate`` in Cylc 8 and +take action on any warnings. + +.. TODO Add ref to breaking changes section within Major changes, once created, + including optional ouputs. + +.. note:: + + Validation warnings use a :ref:`shorthand notation` + to refer to nested configuration settings on a single line, like this: + ``[section][sub-section]item``. + + +New Web and Terminal UIs +------------------------ +.. seealso:: + + * Major Changes: :ref:`728.ui` + +At Cylc 8, there are two UIs available to monitor and control your workflows: + +- a terminal UI application + + .. code-block:: bash + + cylc tui + +- a web based UI application (requires `Cylc UI Server`_) + + .. code-block:: bash + + cylc gui + +Command Changes +--------------- + +``cylc run `` at Cylc 7 has become ``cylc play ``. + +.. seealso:: + + * User Guide: :ref:`WorkflowStartUp` + * Major Changes: :ref:`728.play_pause_stop` + * Major Changes: :ref:`MajorChangesCLI` + +At Cylc 8, use ``cylc pause `` to pause a workflow, halting all job +submission. To restart the workflow, use ``cylc play ``. + +To start a fresh run, use ``cylc install`` and play it safely in the new run +directory. + +(Note that ``cylc hold`` and ``cylc release`` pause and release individual tasks.) + +Task/Job States +--------------- + +:term:`Tasks ` are nodes in the abstract workflow graph, representing +applications to run at the appropriate point in the workflow. A :term:`job ` +is the script (and subsequent process) submitted by Cylc to +actually run the application. A task can have multiple jobs as the result of +automatic retries or manual re-triggering. + + +The 13 task/job states in Cylc 7 have been simplified to 8. Tasks and jobs have been +separated and states of both can be viewed in the GUI. + +.. image:: ../img/task-job.png + :align: center + +For more information, see :ref:`728.task_job_states`. + + +Optional and Required Task Outputs +---------------------------------- + +.. seealso:: + + * Major Changes::ref:`728.optional_outputs` + * User Guide::ref:`User Guide Required Outputs` + * User Guide::ref:`User Guide Optional Outputs` + +By default, all Cylc 8 tasks are required to succeed - i.e., success is +a :term:`required output`. Tasks with :term:`final status` and incomplete +outputs get retained in the :term:`n=0 window ` pending user +intervention, which will :term:`stall` the workflow. + +Alternatively, outputs can be marked as :term:`optional `, +which allows :term:`optional graph branching `. + +This allows the scheduler to correctly diagnose :term:`workflow completion`. + + +Platform Awareness +------------------ + +.. seealso:: + + :ref:`Platforms at Cylc 8.` + +Cylc 7 was aware of individual job hosts - one selected a host using: +``[runtime][][remote]host``. + +Cylc 8 is aware of sets of host settings called +:term:`[job] platforms `. To choose a platform for a task use +``[runtime][]platform`` + +Hosts of a platform must share a file system and :term:`job runner`: +If one host is unavailable Cylc 8 can use other hosts +on the same platform to interact with jobs. + +The same hosts can belong to multiple platforms, for example +you might be able to use the same host to launch both background and Slurm +jobs. + +.. note:: + + Cylc 8 will pick a sensible platform for your Cylc 7 settings, + These deprecated settings will be removed in a future release. + + +Workflow Installation +--------------------- + +Cylc 8 supports workflow installation. + +For users of `Rose`_, this replaces the functionality of ``rose suite-run``. + +Cylc Install +^^^^^^^^^^^^ + +.. seealso:: + + * Major Changes: :ref:`Moving to Cylc Install` + +Cylc install cleanly separates workflow :term:`source directory` from +:term:`run directory`. It installs workflow files ready for ``cylc play``. + +.. code-block:: console + + $ pwd + ~/cylc-src/demo + + $ ls + flow.cylc + + $ cylc install + INSTALLED demo/run1 from /home/oliverh/cylc-src/demo + + $ cylc play demo + ... + demo/run1: oliver.niwa.local PID=6702 + +By default, run numbers increment with each install. + + +File Installation +^^^^^^^^^^^^^^^^^ +When the first job runs on a remote platform (after start-up, or after a ``cylc reload``), a +remote initialization process is triggered to install workflow files there. + +Symlink Dirs +^^^^^^^^^^^^ + +.. seealso:: + + * User Guide: :ref:`SymlinkDirs` + * User Guide: :ref:`RemoteInit` + +Symlinking the workflow directories used by Cylc provides a useful way of +managing disk space. + +These symlinks are created on a per install target basis, as configured in +:cylc:conf:`global.cylc[install][symlink dirs]`. Install targets are managed on +a site level, for more information see :ref:`Install Targets` + +This functionality replaces the Rose ``root dir`` configuration +for Cylc 7 (however, note it does not allow per-workflow configuration). + + +Removing Workflows +------------------ + +Workflows can be deleted with ``cylc clean`` - see :ref:`Removing-workflows`. This +replaces the ``rose suite-clean`` functionality. + +Architecture +------------ + +There have been fundamental changes to the architecture of Cylc. You can read +about the new system design here :ref:`architecture-reference`. + +Scheduling Algorithm +-------------------- + +The scheduling algorithm has been changed, more information is available: +:ref:`728.scheduling_algorithm`. + +Log Files +--------- + +The workflow log files have moved to new locations and some new files have been +added. For information on the Cylc 8 log files, see +:ref:`user-guide.log_files`. + +.. list-table:: + + * - **Cylc 7** (and Rose 2019) + - **Cylc 8** + * - ``log/suite/log`` + - ``log/scheduler/log`` + * - ``log/suite/log.