Skip to content
This repository has been archived by the owner on Nov 7, 2024. It is now read-only.

Add singularity and slurm support #403

Open
wants to merge 30 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
dba5d7d
Added code to support Singularity on HiperGator
suhasthegame Jan 3, 2024
75b8156
Testing for docker_entrypoint
suhasthegame Jan 9, 2024
2a9b195
Intermediate Commit --ignore
suhasthegame Feb 14, 2024
0705809
Added Dependencies --ignore
suhasthegame Feb 19, 2024
9957574
Ignore --all
suhasthegame Feb 21, 2024
5f2aac3
Added version number to girder worker
suhasthegame Feb 27, 2024
03b3717
Changed version
suhasthegame Feb 27, 2024
ba0c9c3
Reverted version back to original
suhasthegame Feb 28, 2024
10a4740
Intermediate Changes Please ignore
Apr 16, 2024
b1889c1
Temporary commit
Apr 30, 2024
b3429fe
Almost working
May 7, 2024
0ff3fec
Bug Fixes
May 14, 2024
27f790b
Addressed GPU config issue for plugins
May 16, 2024
a0f1b72
UF Progress
willdunklin May 21, 2024
9524112
Intermediate commit
Jun 24, 2024
31367c6
Fixed GPU and CPU allocation
Jul 1, 2024
3b08406
Added code to clean up tmp folders after job
Jul 10, 2024
8dadcc3
Merge branch 'migration' of https://github.com/suhasthegame/girder_wo…
willdunklin Jul 17, 2024
c7a9d3b
Split girder-worker-singularity into a seperate package
willdunklin Jul 22, 2024
8baadbc
Update singularity package dependencies
willdunklin Aug 1, 2024
66e99b3
Update singularity threads to track jobId
willdunklin Aug 21, 2024
6c326ee
Refactor singularity-slurm into separate package
willdunklin Aug 27, 2024
32c8e77
Format code
willdunklin Sep 16, 2024
2399313
Add slurm configuration settings
willdunklin Sep 16, 2024
d36a992
Merge branch 'master' of https://github.com/girder/girder_worker into…
willdunklin Sep 25, 2024
5daf316
Format code
willdunklin Sep 26, 2024
7d3783f
Undo test case removal
willdunklin Sep 26, 2024
971a918
Clean up dependencies
willdunklin Oct 2, 2024
bc129a9
Split slurm configuration setting out from worker
willdunklin Oct 2, 2024
2058ecc
Update slurm/singularity extensions to use scm versioning
willdunklin Oct 2, 2024
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
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
/docs/_build/
/tmp/
__pycache__/
/girder_worker.egg-info/
*.egg-info/
/girder-worker-*.tar.gz
*.retry
.vagrant
.tox/
.cache/
htmlcov/
build/
.eggs

1 change: 0 additions & 1 deletion examples/plugin_example/gwexample/analyses/tasks.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from girder_worker.app import app
from girder_worker_utils import types
from girder_worker_utils.decorators import argument

Expand Down
3 changes: 2 additions & 1 deletion girder_worker/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ def gw_task_prerun(task=None, sender=None, task_id=None,
raise

try:
task.girder_client = GirderClient(apiUrl=task.request.girder_api_url)
# task.girder_client = GirderClient(apiUrl=task.request.girder_api_url)
task.girder_client = GirderClient(apiUrl='http://0.0.0.0:8101/api/v1')
task.girder_client.token = task.request.girder_client_token
except AttributeError:
task.girder_client = None
Expand Down
6 changes: 6 additions & 0 deletions girder_worker/docker/io/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ class FileDescriptorReader(StreamReader):
"""
Reader to read from a file descriptor.
"""

def __init__(self, fd):
self._fd = fd

Expand All @@ -208,6 +209,7 @@ class FileDescriptorWriter(StreamWriter):
"""
Writer to write to a file descriptor.
"""

def __init__(self, fd):
self._fd = fd

Expand All @@ -225,6 +227,7 @@ class StdStreamWriter(StreamWriter):
"""
Writer for write to stdout and stderr.
"""

def __init__(self, stream):
self._stream = stream

Expand All @@ -240,6 +243,7 @@ class NamedPipe:
"""
A named pipe.
"""

def __init__(self, path):
self.path = path
self._fd = None
Expand Down Expand Up @@ -267,6 +271,7 @@ class NamedPipeReader(FileDescriptorReader):
"""
Reader to read from a named pipe.
"""

def __init__(self, pipe, container_path=None):
super().__init__(None)
self._pipe = pipe
Expand All @@ -290,6 +295,7 @@ class NamedPipeWriter(FileDescriptorWriter):
"""
Write to write to a named pipe.
"""

def __init__(self, pipe, container_path=None):
super().__init__(None)
self._pipe = pipe
Expand Down
1 change: 1 addition & 0 deletions girder_worker/docker/io/girder.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class GirderFileStreamReader(StreamReader):
"""
Stream a file from Girder.
"""

def __init__(self, client, file_id):
"""
:param client: The GirderClient instance to use.
Expand Down
12 changes: 8 additions & 4 deletions girder_worker/docker/tasks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,19 @@
import sys
import threading
import time

try:
import docker
from docker.errors import DockerException, APIError, InvalidVersion
from girder_worker.docker import nvidia
from docker.errors import APIError, DockerException, InvalidVersion
from requests.exceptions import ReadTimeout

from girder_worker.docker import nvidia
except ImportError:
# These imports will not be available on the girder side.
pass
from girder_worker.app import app, Task

from girder_worker import logger
from girder_worker.app import Task, app
from girder_worker.docker import utils
from girder_worker.docker.stream_adapter import DockerStreamPushAdapter
from girder_worker.docker.io import (
Expand All @@ -24,6 +27,7 @@
FDStreamConnector,
StdStreamWriter
)

from girder_worker.docker.transforms import (
ContainerStdErr,
ContainerStdOut,
Expand Down Expand Up @@ -145,6 +149,7 @@ class _SocketReader(FileDescriptorReader):
with python 2 attach_socket(...) returns a socket like object, with python 3
it returns an instance of SocketIO.
"""

def __init__(self, socket):
self._socket = socket

Expand Down Expand Up @@ -424,7 +429,6 @@ def _docker_run(task, image, pull_image=True, entrypoint=None, container_args=No
results = []
if hasattr(task.request, 'girder_result_hooks'):
results = (None,) * len(task.request.girder_result_hooks)

return results


Expand Down
17 changes: 15 additions & 2 deletions girder_worker/docker/transforms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class HostStdOut(Transform):
Represents the standard output stream on the host machine. Can be used with
:py:class:`girder_worker.docker.transforms.Connect` to write text to stdout.
"""

def transform(self, **kwargs):
from girder_worker.docker.io import (
StdStreamWriter
Expand All @@ -34,6 +35,7 @@ class HostStdErr(Transform):
Represents the standard error stream on the host machine. Can be used with
:py:class:`girder_worker.docker.transforms.Connect` to write text to stderr.
"""

def transform(self, **kwargs):
from girder_worker.docker.io import (
StdStreamWriter
Expand All @@ -47,6 +49,7 @@ class ContainerStdOut(Transform):
:py:class:`girder_worker.docker.transforms.Connect` to redirect the containers
standard output to another stream.
"""

def transform(self, **kwargs):
return self

Expand All @@ -61,6 +64,7 @@ class ContainerStdErr(Transform):
:py:class:`girder_worker.docker.transforms.Connect` to redirect the containers
standard error to another stream.
"""

def transform(self, **kwargs):
return self

Expand All @@ -81,6 +85,7 @@ class BindMountVolume(Transform):
:param mode: The mounting mode
:type mode: str
"""

def __init__(self, host_path, container_path, mode='rw'):
self._host_path = host_path
self._container_path = container_path
Expand Down Expand Up @@ -156,6 +161,7 @@ class TemporaryVolume(_TemporaryVolumeBase, metaclass=_TemporaryVolumeMetaClass)
"""
# Note that this mode is explicitly set with os.chmod. What you
# set, is what you get - no os.makedirs umask shenanigans.

def __init__(self, host_dir=None, mode=0o777):
super().__init__(None, None)
self.host_dir = host_dir
Expand All @@ -179,6 +185,7 @@ class _DefaultTemporaryVolume(TemporaryVolume):
containing information about the actual default temporary volume associated with the
task. The place holder then delegates all functionality to this instance.
"""

def transform(self, _default_temp_volume=None, **kwargs):
self._instance = _default_temp_volume
self._transformed = True
Expand Down Expand Up @@ -253,6 +260,7 @@ class NamedInputPipe(NamedPipeBase):
the volume will be used when creating the pipe. The default location is
:py:obj:`girder_worker.docker.transforms.TemporaryVolume.default`
"""

def __init__(self, name, container_path=None, host_path=None, volume=TemporaryVolume.default):
super().__init__(name, container_path, host_path, volume)

Expand Down Expand Up @@ -283,6 +291,7 @@ class NamedOutputPipe(NamedPipeBase):
the volume will be use when creating the pipe. The default location is
:py:attr:`girder_worker.docker.transforms.TemporaryVolume.default`
"""

def __init__(self, name, container_path=None, host_path=None, volume=TemporaryVolume.default):
super().__init__(name, container_path, host_path, volume)

Expand All @@ -308,11 +317,13 @@ class VolumePath(Transform):
:py:attr:`girder_worker.docker.transforms.TemporaryVolume.default`
:type volume: :py:class:`girder_worker.docker.transforms.BindMountVolume`
"""

def __init__(self, filename, volume=TemporaryVolume.default):
if os.path.isabs(filename):
raise Exception('VolumePath paths must be relative to a volume (%s).' % filename)

self.filename = filename
# Modify filename for cli_run
# self.filename = filename
self.filename = filename.replace(' ', '_')
self._volume = volume

def transform(self, *pargs, **kwargs):
Expand Down Expand Up @@ -344,6 +355,7 @@ class Connect(Transform):
:py:class:`girder_worker.docker.transforms.HostStdOut` or
:py:class:`girder_worker.docker.transforms.HostStdErr`
"""

def __init__(self, input, output):
super().__init__()
self._input = input
Expand Down Expand Up @@ -380,6 +392,7 @@ class ChunkedTransferEncodingStream(Transform):
:param headers: HTTP headers to send.
:type header: dict
"""

def __init__(self, url, headers={}, **kwargs):
self.url = url
self.headers = headers
Expand Down
8 changes: 8 additions & 0 deletions girder_worker/docker/transforms/girder.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class ProgressPipe(Transform):
:param volume: The bind mount volume where the underlying named pipe will reside.
:type volume: :py:class:`girder_worker.docker.transforms.BindMountVolume`
"""

def __init__(self, name='.girder_progress', volume=TemporaryVolume.default):
self.name = name
self._volume = volume
Expand All @@ -70,6 +71,7 @@ class GirderFileIdToStream(GirderClientTransform):
:param _id: The Girder file ID.
:type _id: str or ObjectId
"""

def __init__(self, _id, **kwargs):
super().__init__(**kwargs)
self.file_id = _id
Expand All @@ -93,6 +95,7 @@ class GirderFileIdToVolume(GirderClientTransform):
:param filename: Alternate name for the file. Default is to use the name from Girder.
:type filename: str
"""

def __init__(self, _id, volume=TemporaryVolume.default, filename=None, **kwargs):
super().__init__(**kwargs)
self._file_id = str(_id)
Expand Down Expand Up @@ -153,6 +156,7 @@ class GirderFolderIdToVolume(GirderClientTransform):
:param folder_name: Alternate name for the directory. Default is to use the name from Girder.
:type folder_name: str
"""

def __init__(self, _id, volume=TemporaryVolume.default, folder_name=None, **kwargs):
super().__init__(**kwargs)
self._folder_id = str(_id)
Expand Down Expand Up @@ -206,6 +210,7 @@ class GirderItemIdToVolume(GirderClientTransform):
:param item_name: Alternate name for the file. Default is to use the name from Girder.
:type item_name: str
"""

def __init__(self, _id, volume=TemporaryVolume.default, **kwargs):
super().__init__(**kwargs)
self._item_id = str(_id)
Expand Down Expand Up @@ -257,6 +262,7 @@ class GirderUploadVolumePathToItem(GirderUploadToItem):
:param delete_file: Whether to delete the file afterward.
:type delete_file: bool
"""

def __init__(self, volumepath, item_id, delete_file=False, **kwargs):
item_id = str(item_id)
super().__init__(item_id, delete_file, **kwargs)
Expand All @@ -281,6 +287,7 @@ class GirderUploadVolumePathToFolder(GirderUploadToFolder):
:param delete_file: Whether to delete the data afterward.
:type delete_file: bool
"""

def __init__(self, volumepath, folder_id, delete_file=False, **kwargs):
super().__init__(str(folder_id), delete_file, **kwargs)
self._volumepath = volumepath
Expand Down Expand Up @@ -311,6 +318,7 @@ class GirderUploadVolumePathJobArtifact(GirderUploadJobArtifact):
fails. This can be used to debug failed ``docker_run`` tasks.
:type upload_on_exception: bool
"""

def __init__(self, volumepath, job_id=None, name=None, upload_on_exception=False, **kwargs):
if job_id is not None:
job_id = str(job_id)
Expand Down
2 changes: 1 addition & 1 deletion girder_worker/entrypoint.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from importlib import import_module

import celery
from girder_worker_utils import decorators

from stevedore import extension


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ form#g-worker-settings-form(role="form")
.checkbox
label.control-label(for="g-worker-direct-path")
input#g-worker-direct-path(type="checkbox")
span When possible, send local file paths to the worker to avoid downloading files
span When possible, send local file paths to the worker to avoid downloading file

p#g-worker-settings-error-message.g-validation-failed-message
input.btn.btn-sm.btn-primary(type="submit", value="Save")
Expand Down
2 changes: 1 addition & 1 deletion girder_worker/girder_plugin/web_client/views/ConfigView.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ var ConfigView = View.extend({
'worker.api_url',
'worker.broker',
'worker.backend',
'worker.direct_path'
'worker.direct_path',
])
}
}).done((resp) => {
Expand Down
10 changes: 10 additions & 0 deletions girder_worker/singularity/girder_worker_singularity/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from girder_worker import GirderWorkerPluginABC


class SingularityPlugin(GirderWorkerPluginABC):

def __init__(self, app, *args, **kwargs):
self.app = app

def task_imports(self):
return ['girder_worker_singularity.tasks']
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from girder.plugin import GirderPlugin


class WorkerSingularityPlugin(GirderPlugin):
DISPLAY_NAME = 'Worker Singularity'

def load(self, info):
pass
Loading