Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

conf: cylc executable => cylc path #4105

Merged
merged 1 commit into from
Mar 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 38 additions & 11 deletions cylc/flow/cfgspec/globalcfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -427,10 +427,21 @@

ssh user@host 'bash --login cylc ...'

which will source ``/etc/profile`` and ``~/.profile`` to set up
the user environment. However, for security reasons some
institutions do not allow unattended commands to start login
shells, so you can turn off this behaviour to get:
which will source the following files (in order):

* ``/etc/profile``
* ``~/.bash_profile``
* ``~/.bash_login``
* ``~/.profile``

.. _Bash man pages: https://linux.die.net/man/1/bash

For more information on login shells see the "Invocation"
section of the `Bash man pages`_.

For security reasons some institutions do not allow unattended
commands to start login shells, so you can turn off this
behaviour to get:

.. code-block:: bash

Expand All @@ -441,17 +452,33 @@
environment.
''')
Conf('hosts', VDR.V_STRING_LIST)
Conf('cylc executable', VDR.V_STRING, 'cylc', desc='''
The ``cylc`` executable on a remote host.
Conf('cylc path', VDR.V_STRING, desc='''
The path containing the ``cylc`` executable on a remote host.

This may be necessary if the ``cylc`` executable is not in the
``$PATH`` for an ``ssh`` call.
Test whether this is the case by using
``ssh <host> command -v cylc``.

This path is used for remote invocations of the ``cylc``
command and is added to the ``$PATH`` in job scripts
for the configured platform.

.. note::

This should normally point to the cylc multi-version wrapper
on the host, not ``bin/cylc`` for a specific installed
version.
If :cylc:conf:`[..]use login shell = True` (the default)
then an alternative approach is to add ``cylc`` to the
``$PATH`` in the system or user Bash profile files
(e.g. ``~/.bash_profile``).

.. tip::

For multi-version installations this should point to the
Cylc wrapper script rather than the ``cylc`` executable
itself.

Specify a full path if ``cylc`` is not in ``$PATH`` when it is
invoked via ``ssh`` on this host.
See :ref:`managing environments` for more information on
the wrapper script.
''')
Conf('global init-script', VDR.V_STRING, desc='''
If specified, the value of this setting will be inserted to
Expand Down
12 changes: 4 additions & 8 deletions cylc/flow/job_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,14 +170,10 @@ def _write_prelude(self, handle, job_conf):
job_conf)
if vacation_signals_str:
handle.write("\nCYLC_VACATION_SIGNALS='%s'" % vacation_signals_str)
# Path to cylc executable, if defined.
cylc_exec = job_conf['platform']['cylc executable']
if not cylc_exec.endswith('cylc'):
raise ValueError(
f'ERROR: bad cylc executable in global config: {cylc_exec}')
cylc_bin = os.path.dirname(cylc_exec)
if cylc_bin:
handle.write(f"\nexport PATH={cylc_bin}:$PATH")
# Path to the `cylc` executable, if defined.
cylc_path = job_conf['platform']['cylc path']
if cylc_path:
handle.write(f"\nexport PATH={cylc_path}:$PATH")
# Environment variables for prelude
if cylc.flow.flags.debug:
handle.write("\nexport CYLC_DEBUG=true")
Expand Down
38 changes: 20 additions & 18 deletions cylc/flow/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import os
from shlex import quote
from pathlib import Path
from posix import WIFSIGNALED
import shlex
import signal
Expand Down Expand Up @@ -212,7 +213,7 @@ def construct_ssh_cmd(raw_cmd, platform, **kwargs):
raw_cmd,
host=get_host_from_platform(platform),
ssh_cmd=platform['ssh command'],
ssh_cylc=platform['cylc executable'],
remote_cylc_path=platform['cylc path'],
ssh_login_shell=platform['use login shell'],
**kwargs
)
Expand All @@ -225,7 +226,7 @@ def _construct_ssh_cmd(
stdin=False,
ssh_cmd=None,
ssh_login_shell=None,
ssh_cylc=None,
remote_cylc_path=None,
set_UTC=False,
allow_flag_opts=False,
timeout=None
Expand All @@ -245,8 +246,9 @@ def _construct_ssh_cmd(
ssh command to use: If unset defaults to localhost ssh cmd.
ssh_login_shell (boolean):
If True, launch remote command with `bash -l -c 'exec "$0" "$@"'`.
ssh_cylc (string):
Location of the remote cylc executable.
remote_cylc_path (string):
Path containing the `cylc` executable.
This is required if the remote executable is not in $PATH.
set_UTC (boolean):
If True, check UTC mode and specify if set to True (non-default).
allow_flag_opts (boolean):
Expand All @@ -256,8 +258,9 @@ def _construct_ssh_cmd(
String for bash timeout command.

Return:
A list containing a chosen command including all arguments and options
necessary to directly execute the bare command on a given host via ssh.
list - A list containing a chosen command including all arguments and
options necessary to directly execute the bare command on a given host
via ssh.
"""
# If ssh cmd isn't given use the default from localhost settings.
if ssh_cmd is None:
Expand Down Expand Up @@ -306,16 +309,15 @@ def _construct_ssh_cmd(
command += ['timeout', timeout]

# 'cylc' on the remote host
if ssh_cylc:
command.append(ssh_cylc)
if not remote_cylc_path:
remote_cylc_path = get_platform()['cylc path']

if remote_cylc_path:
cylc_cmd = str(Path(remote_cylc_path) / 'cylc')
else:
ssh_cylc = get_platform()['cylc executable']
if ssh_cylc.endswith('cylc'):
command.append(ssh_cylc)
else:
# TODO - raise appropriate exception
raise ValueError(
r'ERROR: bad cylc executable in global config: %s' % ssh_cylc)
cylc_cmd = 'cylc'

command.append(cylc_cmd)

# Insert core raw command after ssh, but before its own, command options.
command += raw_cmd
Expand All @@ -342,7 +344,7 @@ def remote_cylc_cmd(cmd, platform, **kwargs):
cmd,
host=get_host_from_platform(platform),
ssh_cmd=platform['ssh command'],
ssh_cylc=platform['cylc executable'],
remote_cylc_path=platform['cylc path'],
ssh_login_shell=platform['use login shell'],
**kwargs
)
Expand All @@ -355,7 +357,7 @@ def _remote_cylc_cmd(
stdin_str=None,
ssh_login_shell=None,
ssh_cmd=None,
ssh_cylc=None,
remote_cylc_path=None,
capture_process=False,
manage=False
):
Expand All @@ -376,7 +378,7 @@ def _remote_cylc_cmd(
stdin=True if stdin_str else stdin,
ssh_login_shell=ssh_login_shell,
ssh_cmd=ssh_cmd,
ssh_cylc=ssh_cylc
remote_cylc_path=remote_cylc_path
),
stdin=stdin,
stdin_str=stdin_str,
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/job-submission/18-clean-env.t
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
create_test_global_config "" "
[platforms]
[[localhost]]
cylc executable = $(command -v cylc)
cylc path = $(dirname "$(command -v cylc)")
clean job submission environment = True
job submission environment pass-through = BEEF
"
Expand Down
2 changes: 1 addition & 1 deletion tests/functional/jobscript/00-torture.t
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export PATH_TO_CYLC_BIN="/path/to/cylc/bin"
create_test_global_config '' "
[platforms]
[[localhost]]
cylc executable = $PATH_TO_CYLC_BIN/cylc"
cylc path = $PATH_TO_CYLC_BIN"
#-------------------------------------------------------------------------------
TEST_NAME="${TEST_NAME_BASE}-run"
suite_run_ok "${TEST_NAME}" cylc play --reference-test --debug --no-detach "${SUITE_NAME}"
Expand Down
16 changes: 1 addition & 15 deletions tests/unit/test_job_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,20 +67,6 @@ def inner_func(custom_settings=None):
yield inner_func


def test_write_prelude_invalid_cylc_command():
job_conf = {
"platform": {
"job runner": "background",
"hosts": ["localhost"],
"cylc executable": "sl -a"
}
}
with pytest.raises(ValueError) as ex:
with TemporaryFile(mode="w+") as handle:
JobFileWriter()._write_prelude(handle, job_conf)
assert("bad cylc executable" in str(ex))


@mock.patch.dict(
"os.environ", {'CYLC_SUITE_DEF_PATH': 'cylc/suite/def/path'})
@mock.patch("cylc.flow.job_file.get_remote_suite_run_dir")
Expand Down Expand Up @@ -286,7 +272,7 @@ def test_write_prelude(monkeypatch, fixture_get_platform):
"copyable environment variables": [
"CYLC_SUITE_INITIAL_CYCLE_POINT"
],
"cylc executable": "moo/baa/cylc"
"cylc path": "moo/baa"
}),
"directives": {"restart": "yes"},
}
Expand Down