Add working directory field in options form

This commit is contained in:
Benoît Seignovert 2024-02-26 14:35:30 +01:00
parent 0273f449b8
commit c67e8742c8
Signed by: Benoît Seignovert
GPG key ID: F5D8895227D18A0B
8 changed files with 71 additions and 8 deletions

View file

@ -11,7 +11,7 @@ from traceback import format_exc
from flask import Flask, render_template, request
from glicid_spawner.form import TEMPLATES, options_from_form
from glicid_spawner.micromamba import MicromambaEnv
from glicid_spawner.resources import CPU, MEMORY, gpu_max_duration
from glicid_spawner.resources import CPU, MEMORY, get_folders, gpu_max_duration
from glicid_spawner.slurm import gres, sinfo_from_file
from livereload import Server
@ -22,6 +22,7 @@ ENVS = [
MicromambaEnv('USER', 'bar', f'/{USERNAME}/envs/bar'),
MicromambaEnv('GLOBAL', 'baz', '/global/envs/baz'),
]
FOLDERS = get_folders(USERNAME)
# Dummy SLURM config
DATA = Path(__file__).parent / '..' / 'tests' / 'data'
@ -38,6 +39,7 @@ GPU_MULTI_CLUSTER = gpu_max_duration(gres(SLURM_MULTI_CLUSTER))
# Format dummy options
OPTIONS = {
'username': USERNAME,
'folders': FOLDERS,
'envs': ENVS,
'cpus': CPU,
'mems': MEMORY,

View file

@ -3,7 +3,7 @@
from jinja2 import Environment, PackageLoader, select_autoescape
from .micromamba import get_envs
from .resources import CPU, GPU_DEFAULTS, MEMORY, gpu_max_duration
from .resources import CPU, GPU_DEFAULTS, MEMORY, get_folders, gpu_max_duration
from .slurm import gres, sinfo
TEMPLATES = Environment(
@ -21,6 +21,7 @@ def options_attrs(username: str) -> dict:
return {
'username': username,
'folders': get_folders(username),
'envs': get_envs(username),
'cpus': CPU,
'mems': MEMORY,
@ -38,6 +39,7 @@ def options_form(username: str) -> str:
def options_from_form(formdata) -> dict:
"""Export options from default form."""
# Parse form data response
workdir = formdata['workdir'][0]
env = formdata['python-env'][0]
cpu = int(formdata['cpu'][0])
mem = int(formdata['mem'][0])
@ -52,6 +54,7 @@ def options_from_form(formdata) -> dict:
# Export options
options = {
'workdir': workdir,
'pyenv': env,
'nprocs': cpu,
'memory': f'{mem}GB',

View file

@ -37,3 +37,15 @@ def gpu_max_duration(gpus: list, unknown_default=1) -> dict:
defaults = {gpu: duration for gpu, duration in GPU_DEFAULTS.items() if gpu in gpus}
unknowns = {gpu: unknown_default for gpu in gpus if gpu not in GPU_DEFAULTS}
return defaults | unknowns
def get_folders(username: str) -> list:
"""List of folders accessible to the users as a working directory."""
return [
f'/home/{username}',
f'/scratch/nautilus/users/{username}',
f'/scratch/waves/users/{username}',
'/scratch/nautilus/projects',
'/scratch/waves/projects',
'/LAB-DATA/',
]

View file

@ -5,6 +5,7 @@
<div class="form-horizontal">
{% include "views/username.jinja" %}
{% include "views/chdir.jinja" %}
{% include "views/envs.jinja" %}
{% include "views/resources.jinja" %}
{% include "views/slurm.jinja" %}

View file

@ -0,0 +1,13 @@
<div class="form-group">
<label for="workdir" class="col-sm-3 control-label">Working directory:</label>
<div class="col-sm-9">
<div class="input-group">
<div class="input-group-addon"><span class="fa fa-briefcase"></span></div>
<select class="form-control" name="workdir">
{%- for folder in folders -%}
<option value="{{ folder }}">{{ folder }}</option>
{% endfor -%}
</select>
</div>
</div>
</div>

View file

@ -1,10 +1,13 @@
<div class="form-group">
<label for="python-env" class="col-sm-3 control-label">Python environment:</label>
<div class="col-sm-9">
<select class="form-control" name="python-env">
{%- for pyenv in envs -%}
<option value="{{ pyenv.path }}">{{ pyenv.name }} ({{ pyenv.scope | upper }})</option>
{% endfor -%}
</select>
<div class="input-group">
<div class="input-group-addon"><span class="fa fa-bar-chart"></span></div>
<select class="form-control" name="python-env">
{%- for pyenv in envs -%}
<option value="{{ pyenv.path }}">{{ pyenv.name }} ({{ pyenv.scope | upper }})</option>
{% endfor -%}
</select>
</div>
</div>
</div>

View file

@ -48,6 +48,15 @@ def test_options_attrs(mock_cluster):
assert options['username'] == 'john-doe'
assert options['folders'] == [
'/home/john-doe',
'/scratch/nautilus/users/john-doe',
'/scratch/waves/users/john-doe',
'/scratch/nautilus/projects',
'/scratch/waves/projects',
'/LAB-DATA/',
]
assert [env.path for env in options['envs']] == [
'/john-doe/envs/foo',
'/john-doe/envs/bar',
@ -243,6 +252,7 @@ def test_options_from_form():
"""Test options from form parser."""
# No GPU
formdata = {
'workdir': ['/home/john-doe/'],
'python-env': ['/john-doe/envs/foo'],
'cpu': ['1'],
'mem': ['4'],
@ -250,6 +260,7 @@ def test_options_from_form():
}
assert options_from_form(formdata) == {
'workdir': '/home/john-doe/',
'pyenv': '/john-doe/envs/foo',
'nprocs': 1,
'memory': '4GB',
@ -258,6 +269,7 @@ def test_options_from_form():
# With GPU (in defaults list)
formdata = {
'workdir': ['/scratch/nautilus/users/john-doe/'],
'python-env': ['/john-doe/envs/bar'],
'cpu': ['2'],
'mem': ['16'],
@ -266,6 +278,7 @@ def test_options_from_form():
}
assert options_from_form(formdata) == {
'workdir': '/scratch/nautilus/users/john-doe/',
'pyenv': '/john-doe/envs/bar',
'nprocs': 2,
'memory': '16GB',
@ -276,6 +289,7 @@ def test_options_from_form():
# With unknown GPU (default 1h allocation)
formdata = {
'workdir': ['/scratch/waves/projects/'],
'python-env': ['/global/envs/baz'],
'cpu': ['8'],
'mem': ['16'],
@ -284,6 +298,7 @@ def test_options_from_form():
}
assert options_from_form(formdata) == {
'workdir': '/scratch/waves/projects/',
'pyenv': '/global/envs/baz',
'nprocs': 8,
'memory': '16GB',
@ -294,6 +309,7 @@ def test_options_from_form():
# Invalid CPU request (0h allocated)
formdata = {
'workdir': ['/LAD-DATA/'],
'python-env': ['/global/envs/qux'],
'cpu': ['128'],
'mem': ['4096'],
@ -302,6 +318,7 @@ def test_options_from_form():
}
assert options_from_form(formdata) == {
'workdir': '/LAD-DATA/',
'pyenv': '/global/envs/qux',
'nprocs': 128,
'memory': '4096GB',

View file

@ -1,6 +1,6 @@
"""Test resources module."""
from glicid_spawner.resources import CPU, GPU_DEFAULTS, MEMORY, gpu_max_duration
from glicid_spawner.resources import CPU, GPU_DEFAULTS, MEMORY, get_folders, gpu_max_duration
def test_default_resources():
@ -22,3 +22,15 @@ def test_gpu_max_duration():
# Sorted by defaults order, then unknowns
assert list(gpu) == ['None', 'A100', 'T4', 'K80']
assert list(gpu.values()) == [24, 1, 3, 3]
def test_resources_workdir():
"""Test resources working directories."""
assert get_folders('john-doe') == [
'/home/john-doe',
'/scratch/nautilus/users/john-doe',
'/scratch/waves/users/john-doe',
'/scratch/nautilus/projects',
'/scratch/waves/projects',
'/LAB-DATA/',
]