mirror of
https://github.com/clearml/clearml
synced 2025-06-26 18:16:07 +00:00
Add custom task binary support to clearml-task and CreateAndPopulate (allows bash script execution, requires agent version >=1.9.0)
This commit is contained in:
parent
bb8975065b
commit
cf1178ff5f
@ -48,6 +48,7 @@ class CreateAndPopulate(object):
|
|||||||
force_single_script_file=False, # type: bool
|
force_single_script_file=False, # type: bool
|
||||||
raise_on_missing_entries=False, # type: bool
|
raise_on_missing_entries=False, # type: bool
|
||||||
verbose=False, # type: bool
|
verbose=False, # type: bool
|
||||||
|
binary=None # type: Optional[str]
|
||||||
):
|
):
|
||||||
# type: (...) -> None
|
# type: (...) -> None
|
||||||
"""
|
"""
|
||||||
@ -90,6 +91,7 @@ class CreateAndPopulate(object):
|
|||||||
:param force_single_script_file: If True, do not auto-detect local repository
|
:param force_single_script_file: If True, do not auto-detect local repository
|
||||||
:param raise_on_missing_entries: If True, raise ValueError on missing entries when populating
|
:param raise_on_missing_entries: If True, raise ValueError on missing entries when populating
|
||||||
:param verbose: If True, print verbose logging
|
:param verbose: If True, print verbose logging
|
||||||
|
:param binary: Binary used to launch the entry point
|
||||||
"""
|
"""
|
||||||
if repo and len(urlparse(repo).scheme) <= 1 and not re.compile(self._VCS_SSH_REGEX).match(repo):
|
if repo and len(urlparse(repo).scheme) <= 1 and not re.compile(self._VCS_SSH_REGEX).match(repo):
|
||||||
folder = repo
|
folder = repo
|
||||||
@ -136,6 +138,7 @@ class CreateAndPopulate(object):
|
|||||||
self.force_single_script_file = bool(force_single_script_file)
|
self.force_single_script_file = bool(force_single_script_file)
|
||||||
self.raise_on_missing_entries = raise_on_missing_entries
|
self.raise_on_missing_entries = raise_on_missing_entries
|
||||||
self.verbose = verbose
|
self.verbose = verbose
|
||||||
|
self.binary = binary
|
||||||
|
|
||||||
def create_task(self, dry_run=False):
|
def create_task(self, dry_run=False):
|
||||||
# type: (bool) -> Union[Task, Dict]
|
# type: (bool) -> Union[Task, Dict]
|
||||||
@ -148,6 +151,7 @@ class CreateAndPopulate(object):
|
|||||||
local_entry_file = None
|
local_entry_file = None
|
||||||
repo_info = None
|
repo_info = None
|
||||||
stand_alone_script_outside_repo = False
|
stand_alone_script_outside_repo = False
|
||||||
|
entry_point = ""
|
||||||
# populate from local repository / script
|
# populate from local repository / script
|
||||||
if self.folder or (self.script and Path(self.script).is_file() and not self.repo):
|
if self.folder or (self.script and Path(self.script).is_file() and not self.repo):
|
||||||
self.folder = os.path.expandvars(os.path.expanduser(self.folder)) if self.folder else None
|
self.folder = os.path.expandvars(os.path.expanduser(self.folder)) if self.folder else None
|
||||||
@ -222,7 +226,8 @@ class CreateAndPopulate(object):
|
|||||||
# check if we have no repository and no requirements raise error
|
# check if we have no repository and no requirements raise error
|
||||||
if self.raise_on_missing_entries and (not self.requirements_file and not self.packages) \
|
if self.raise_on_missing_entries and (not self.requirements_file and not self.packages) \
|
||||||
and not self.repo and (
|
and not self.repo and (
|
||||||
not repo_info or not repo_info.script or not repo_info.script.get('repository')):
|
not repo_info or not repo_info.script or not repo_info.script.get('repository')) \
|
||||||
|
and (not entry_point or not entry_point.endswith(".sh")):
|
||||||
raise ValueError("Standalone script detected \'{}\', but no requirements provided".format(self.script))
|
raise ValueError("Standalone script detected \'{}\', but no requirements provided".format(self.script))
|
||||||
if dry_run:
|
if dry_run:
|
||||||
task = None
|
task = None
|
||||||
@ -266,10 +271,10 @@ class CreateAndPopulate(object):
|
|||||||
task_state['script']['diff'] = repo_info.script['diff'] or ''
|
task_state['script']['diff'] = repo_info.script['diff'] or ''
|
||||||
task_state['script']['working_dir'] = repo_info.script['working_dir']
|
task_state['script']['working_dir'] = repo_info.script['working_dir']
|
||||||
task_state['script']['entry_point'] = repo_info.script['entry_point']
|
task_state['script']['entry_point'] = repo_info.script['entry_point']
|
||||||
task_state['script']['binary'] = '/bin/bash' if (
|
task_state['script']['binary'] = self.binary or ('/bin/bash' if (
|
||||||
(repo_info.script['entry_point'] or '').lower().strip().endswith('.sh') and
|
(repo_info.script['entry_point'] or '').lower().strip().endswith('.sh') and
|
||||||
not (repo_info.script['entry_point'] or '').lower().strip().startswith('-m ')) \
|
not (repo_info.script['entry_point'] or '').lower().strip().startswith('-m ')) \
|
||||||
else repo_info.script['binary']
|
else repo_info.script['binary'])
|
||||||
task_state['script']['requirements'] = repo_info.script.get('requirements') or {}
|
task_state['script']['requirements'] = repo_info.script.get('requirements') or {}
|
||||||
if self.cwd:
|
if self.cwd:
|
||||||
cwd = self.cwd
|
cwd = self.cwd
|
||||||
@ -344,14 +349,20 @@ class CreateAndPopulate(object):
|
|||||||
detailed_req_report=False,
|
detailed_req_report=False,
|
||||||
force_single_script=True,
|
force_single_script=True,
|
||||||
)
|
)
|
||||||
task_state['script']['binary'] = '/bin/bash' if (
|
task_state['script']['binary'] = self.binary or ('/bin/bash' if (
|
||||||
(repo_info.script['entry_point'] or '').lower().strip().endswith('.sh') and
|
(repo_info.script['entry_point'] or '').lower().strip().endswith('.sh') and
|
||||||
not (repo_info.script['entry_point'] or '').lower().strip().startswith('-m ')) \
|
not (repo_info.script['entry_point'] or '').lower().strip().startswith('-m ')) \
|
||||||
else repo_info.script['binary']
|
else repo_info.script['binary'])
|
||||||
task_state['script']['diff'] = repo_info.script['diff'] or ''
|
task_state['script']['diff'] = repo_info.script['diff'] or ''
|
||||||
task_state['script']['entry_point'] = repo_info.script['entry_point']
|
task_state['script']['entry_point'] = repo_info.script['entry_point']
|
||||||
if create_requirements:
|
if create_requirements:
|
||||||
task_state['script']['requirements'] = repo_info.script.get('requirements') or {}
|
task_state['script']['requirements'] = repo_info.script.get('requirements') or {}
|
||||||
|
else:
|
||||||
|
if self.binary:
|
||||||
|
task_state["script"]["binary"] = self.binary
|
||||||
|
elif entry_point and entry_point.lower().strip().endswith(".sh") and not \
|
||||||
|
entry_point.lower().strip().startswith("-m"):
|
||||||
|
task_state["script"]["binary"] = "/bin/bash"
|
||||||
else:
|
else:
|
||||||
# standalone task
|
# standalone task
|
||||||
task_state['script']['entry_point'] = self.script if self.script else \
|
task_state['script']['entry_point'] = self.script if self.script else \
|
||||||
|
@ -59,11 +59,20 @@ def setup_parser(parser):
|
|||||||
type=str,
|
type=str,
|
||||||
default=None,
|
default=None,
|
||||||
help="Specify the entry point script for the remote execution. "
|
help="Specify the entry point script for the remote execution. "
|
||||||
"Currently support .py .ipynb and .sh scripts (python, jupyter notebook, bash) "
|
"Currently supports .py .ipynb and .sh scripts (python, jupyter notebook, bash) "
|
||||||
"When used in tandem with --repo the script should be a relative path inside "
|
"When used in tandem with --repo the script should be a relative path inside "
|
||||||
"the repository, for example: --script source/train.py "
|
"the repository, for example: --script source/train.py."
|
||||||
"When used with --folder it supports a direct path to a file inside the local "
|
"When used with --folder it supports a direct path to a file inside the local "
|
||||||
"repository itself, for example: --script ~/project/source/train.py",
|
"repository itself, for example: --script ~/project/source/train.py. "
|
||||||
|
"To run a bash script, simply specify the path of that script; the script should "
|
||||||
|
"have the .sh extension, for example: --script init.sh"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--binary",
|
||||||
|
type=str,
|
||||||
|
default=None,
|
||||||
|
help="Binary used to launch the entry point. For example: '--binary python3', '--binary /bin/bash'."
|
||||||
|
"By default, the binary will be auto-detected."
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--module",
|
"--module",
|
||||||
@ -186,6 +195,8 @@ def cli():
|
|||||||
print("Importing offline session: {}".format(args.import_offline_session))
|
print("Importing offline session: {}".format(args.import_offline_session))
|
||||||
Task.import_offline_session(args.import_offline_session)
|
Task.import_offline_session(args.import_offline_session)
|
||||||
else:
|
else:
|
||||||
|
if args.script and args.script.endswith(".sh") and not args.binary:
|
||||||
|
print("Detected shell script. Binary will be set to '/bin/bash'")
|
||||||
create_populate = CreateAndPopulate(
|
create_populate = CreateAndPopulate(
|
||||||
project_name=args.project,
|
project_name=args.project,
|
||||||
task_name=args.name,
|
task_name=args.name,
|
||||||
@ -206,6 +217,7 @@ def cli():
|
|||||||
add_task_init_call=not args.skip_task_init,
|
add_task_init_call=not args.skip_task_init,
|
||||||
raise_on_missing_entries=True,
|
raise_on_missing_entries=True,
|
||||||
verbose=True,
|
verbose=True,
|
||||||
|
binary=args.binary
|
||||||
)
|
)
|
||||||
# verify args before creating the Task
|
# verify args before creating the Task
|
||||||
create_populate.update_task_args(args.args)
|
create_populate.update_task_args(args.args)
|
||||||
|
Loading…
Reference in New Issue
Block a user