Skip to content

Commit

Permalink
Merge branch 'main' into vub-hpc
Browse files Browse the repository at this point in the history
  • Loading branch information
lexming committed May 14, 2024
2 parents 7be1768 + d7fac91 commit e00822f
Show file tree
Hide file tree
Showing 15 changed files with 365 additions and 168 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 6.0.0
current_version = 7.0.1
tag = True
commit = True
message = Bump to v{new_version}
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/lint-test.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Lint
name: Lint&Test

on:
push:
Expand All @@ -9,16 +9,16 @@ on:
- main

jobs:
lint:
lint-test:
runs-on: ubuntu-latest
steps:
- name: Checkout 🏷️
uses: actions/checkout@v3

- name: Set up Python 🐍
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: 3.8
python-version: '3.8'

- name: Install dependencies ⚙️
run: |
Expand Down
48 changes: 24 additions & 24 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,27 @@ jobs:
runs-on: ubuntu-latest

steps:
- name: Checkout 🏷️
uses: actions/checkout@v2

- name: Set up Python 🐍
uses: actions/setup-python@v2
with:
python-version: '3.10'

- name: Install dependencies ⚙️
run: |
python -m pip install --upgrade pip
pip install build twine
- name: Build the package 📦
run: python -m build

- name: Check the package 🧐
run: python -m twine check dist/*
- name: Release on PyPI 🎉
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
run: python -m twine upload dist/*
- name: Checkout 🏷️
uses: actions/checkout@v3

- name: Set up Python 🐍
uses: actions/setup-python@v4
with:
python-version: '3.10'

- name: Install dependencies ⚙️
run: |
python -m pip install --upgrade pip
pip install build twine
- name: Build the package 📦
run: python -m build

- name: Check the package 🧐
run: python -m twine check dist/*

- name: Release on PyPI 🎉
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
run: python -m twine upload dist/*
34 changes: 24 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ Fork of the original [silx-kit/jupyterhub_moss](https://github.com/silx-kit/jupy
maintained by VUB-HPC.

Notable changes in this fork:
* support for loading modules in the singleuser server job
* support different groups of default environment
* display available resources as job slots per amount of cores

Expand Down Expand Up @@ -142,9 +141,8 @@ For a minimalistic working demo, check the
where almost all Slurm job settings can be set. Some partitions can be hidden
from the _Simple_ tab with setting `simple` to `False`.
- `jupyter_environments`: Mapping of identifer name to information about Python
environment used to run Jupyter on the Slurm nodes. Either `path` or
`modules` (or both) should be defined. This information is a mapping
containing:
environment used to run Jupyter on the Slurm nodes. Either `path` or `modules`
(or both) should be defined. This information is a mapping containing:
- `description`: Text used for display in the selection options.
- `path`: The path to a Python environment bin/ used to start jupyter on the
Slurm nodes. **jupyterhub_moss** needs that a virtual (or conda) environment
Expand All @@ -156,8 +154,7 @@ For a minimalistic working demo, check the
- `add_to_path`: Whether or not to prepend the environment `path` to shell
`PATH`.
- `prologue`: Shell commands to execute on the Slurm node before starting the
Jupyter single-user server. This can be used to run, e.g.,
`module load <module>`. By default no command is run.
Jupyter single-user server. By default no command is run.

### Spawn page

Expand Down Expand Up @@ -185,7 +182,7 @@ requests.

The _Advanced_ tab allows finer control on the requested resources.

<img style="margin:1rem auto" src=https://user-images.githubusercontent.com/9449698/215526665-a650a54d-e7ec-4d50-b5ab-a02d93b23d19.png width="50%">
<img style="margin:1rem auto" src=https://user-images.githubusercontent.com/9449698/262627623-91bd63de-6374-47d4-9064-d1a6e3d56411.png width="50%">

The user can select any partition (`partition_3` is added in this case) and the
table of available resources reflects this. The user can also choose any number
Expand All @@ -207,7 +204,7 @@ The following optional query arguments are available:

- SLURM configuration:

- `mem`: Total amount of memory per node
- `memory`: Total amount of memory per node
([`--mem`](https://slurm.schedmd.com/sbatch.html#OPT_mem))
- `ngpus`: Number of GPUs
([`--gres:<gpu>:`](https://slurm.schedmd.com/sbatch.html#OPT_gres))
Expand All @@ -221,14 +218,31 @@ The following optional query arguments are available:
([`--time`](https://slurm.schedmd.com/sbatch.html#OPT_time))

- Jupyter(Lab) configuration:

- `default_url`: The URL to open the Jupyter environment with: use `/lab` to
start [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) or use
[JupyterLab URLs](https://jupyterlab.readthedocs.io/en/stable/user/urls.html)
- `environment_path`: Path to Python environment bin/ used to start Jupyter
- `environment_modules`: Space separated list of modules to be loaded in single-user server job
- `environment_id`: Name of the Python environment defined in the
configuration used to start Jupyter
- `environment_path`: Path to the Python environment bin/ used to start
Jupyter
- `environment_modules`: Space-separated list of
[environment module](https://modules.sourceforge.net/) names to load before
starting Jupyter
- `root_dir`: The path of the "root" folder browsable from Jupyter(Lab)
(user's home directory if not provided)

To use a Jupyter environment defined in the configuration, only provide its
`environment_id`, for example:
`https://<server:port>/hub/spawn?partition=partition_1&environment_id=default`.

To use a custom Jupyter environment, instead provide the corresponding
`environment_path` and/or `environment_modules`, for example:

- `https://<server:port>/hub/spawn?partition=partition_1&environment_path=/path/to/jupyter/bin`,
or
- `https://<server:port>/hub/spawn?partition=partition_1&environment_modules=myjupytermodule`.

## Development

See [CONTRIBUTING.md](CONTRIBUTING.md).
Expand Down
10 changes: 10 additions & 0 deletions demo/templates/option_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ <h4 style="text-align: left">Currently available resources</h4>
</table>
{% endmacro %}

{% block stylesheet %}
{{ super() }}
<style>
#environment_simple {
color: #f37524;
font-weight: 900;
}
</style>
{% endblock %}

{% block simple_tab_footer %}
{{ resource_table(partitions, simple_only=true) }}
{% endblock simple_tab_footer %}
Expand Down
2 changes: 1 addition & 1 deletion jupyterhub_moss/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from .spawner import MOSlurmSpawner
from .utils import local_path as _local_path

version = "6.2.2"
version = "7.0.1.5"

STATIC_FORM_REGEX = r"/form/(.*)"
STATIC_FORM_PATH = _local_path("form")
Expand Down
68 changes: 38 additions & 30 deletions jupyterhub_moss/form/option_form.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@ function removeAllChildren(node) {
}
}

function createEnvironmentDiv(key, description, path, modules, checked = false) {
function createEnvironmentDiv(key, description, path, modules, iscustom = false) {
const div = document.createElement('div');
div.classList.add('environment-div');

const radio_id = `environment_radio_${key}`;
const title = `Environment Name: ${description}`;
const title = [path ? `Path: ${path}` : "", modules ? `Modules: ${modules}` : ""].filter(v => v).join("\n");

// Store definitions in hidden inputs
const path_input = document.createElement('input');
path_input.setAttribute('type', 'hidden');
path_input.setAttribute('class', 'environment_path');
path_input.setAttribute('value', path);
path_input.setAttribute('value', iscustom ? path : '');
div.appendChild(path_input);
const mods_input = document.createElement('input');
mods_input.setAttribute('type', 'hidden');
mods_input.setAttribute('class', 'environment_modules');
mods_input.setAttribute('value', modules);
mods_input.setAttribute('value', iscustom ? modules : '');
div.appendChild(mods_input);

const input = document.createElement('input');
Expand All @@ -33,16 +33,13 @@ function createEnvironmentDiv(key, description, path, modules, checked = false)
input.setAttribute('name', 'environment_id');
input.setAttribute('value', key);

input.addEventListener('change', updateEnvironmentAddNameRequired);
if (checked) {
input.setAttribute('checked', '');
}
input.addEventListener('change', updateAddCustomEnvironment);
div.appendChild(input);

const label = document.createElement('label');
label.setAttribute('for', radio_id);
label.setAttribute('title', title);
label.textContent = description;
label.textContent = description ? description : [path, modules].filter(v => v).join(" - ");
div.appendChild(label);

return div;
Expand Down Expand Up @@ -111,7 +108,7 @@ function addCustomEnvironment(key, description, path, modules, persist = true) {
'environment_simple_custom'
);

const div = createEnvironmentDiv(key, description, path, modules);
const div = createEnvironmentDiv(key, description, path, modules, true);

button = document.createElement('button');
button.setAttribute('type', 'button');
Expand Down Expand Up @@ -226,7 +223,7 @@ function restoreCustomEnvironmentsFromLocalStorage() {
}

for (const key in config) {
addCustomEnvironment(key, config[key].description, config[key].path, config[key].modules, false);
addCustomEnvironment(key, config[key].description, config[key].path || "", config[key].modules || "", false);
}
}

Expand Down Expand Up @@ -313,13 +310,21 @@ function setVisible(element, visible) {
}
}

function updateEnvironmentAddNameRequired() {
function updateAddCustomEnvironment() {
const environmentAddButton = document.getElementById('environment_add_button');
const environmentAddRadio = document.getElementById('environment_add_radio');
const environmentAddName = document.getElementById('environment_add_name');
if (environmentAddRadio.checked) {
environmentAddName.setAttribute('required', '');
const environmentAddPath = document.getElementById('environment_add_path');
const environmentAddMods = document.getElementById('environment_add_modules');

const isPathOrModules = environmentAddPath.value !== "" || environmentAddMods.value !== "";
environmentAddButton.disabled = !isPathOrModules;

if (environmentAddRadio.checked && !isPathOrModules) {
environmentAddPath.setAttribute('required', '');
environmentAddMods.setAttribute('required', '');
} else {
environmentAddName.removeAttribute('required');
environmentAddPath.removeAttribute('required');
environmentAddMods.removeAttribute('required');
}
}

Expand Down Expand Up @@ -611,21 +616,25 @@ document.addEventListener('DOMContentLoaded', () => {
.addEventListener('change', (e) => updateMemValue());

// Handle add custom environment
document
.getElementById('environment_add_name')
.addEventListener('input', (e) => {
const isInputEmpty = e.target.value === '';
if (environmentAddRadio.value === '' && !isInputEmpty) {var myEle = document.getElementById("myElement");
// First input in the name: select its radio button
environmentAddRadio.checked = true;
}
environmentAddRadio.value = e.target.value;
environmentAddButton.disabled = isInputEmpty;
});
environmentAddPath.addEventListener('input', updateAddCustomEnvironment);
environmentAddMods.addEventListener('input', updateAddCustomEnvironment);

environmentAddName.addEventListener('focus', () => {
environmentAddRadio.checked = true;
updateAddCustomEnvironment();
});
environmentAddPath.addEventListener('focus', () => {
environmentAddRadio.checked = true;
updateAddCustomEnvironment();
});
environmentAddMods.addEventListener('focus', () => {
environmentAddRadio.checked = true;
updateAddCustomEnvironment();
});

environmentAddRadio.addEventListener(
'change',
updateEnvironmentAddNameRequired
updateAddCustomEnvironment
);

environmentAddButton.addEventListener('click', (e) => {
Expand All @@ -638,12 +647,11 @@ document.addEventListener('DOMContentLoaded', () => {
);
if (environmentAddRadio.checked) {
selectEnvironment(key);
updateEnvironmentAddNameRequired();
}
environmentAddName.value = '';
environmentAddPath.value = '';
environmentAddMods.value = '';
environmentAddName.dispatchEvent(new Event('input'));
updateAddCustomEnvironment();
});

// Catch form submit
Expand Down
Loading

0 comments on commit e00822f

Please sign in to comment.