Skip to content

Commit 81b0759

Browse files
committed
add support for GRES to ondemand desktop,matlab,rstudio apps
1 parent 0ed4fab commit 81b0759

File tree

5 files changed

+140
-3
lines changed

5 files changed

+140
-3
lines changed

ansible/roles/openondemand/README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,11 @@ This role enables SSL on the Open Ondemand server, using the following self-sign
7373
- `openondemand_desktop_screensaver`: Optional. Whether to enable screen locking/screensaver. **NB:** Users must have passwords if this is enabled. Bool, default `false`.
7474
- `openondemand_filesapp_paths`: List of paths (in addition to $HOME, which is always added) to include shortcuts to within the Files dashboard app.
7575
- `openondemand_jupyter_partition`: Required. Name of Slurm partition to use for Jupyter Notebook servers. Requires a corresponding group named "openondemand_jupyter" and entry in openhpc_partitions.
76-
76+
- `openondemand_gres_options`: Optional. A list of `[label, value]` items used
77+
to provide a drop-down for resource/GRES selection in application forms. The
78+
default constructs a list from all GRES definitions in the cluster. See the
79+
`option` attribute of the Select Field [form widget](https://osc.github.io/ood-documentation/latest/how-tos/app-development/interactive/form-widgets.html#form-widgets).
80+
7781
### Monitoring
7882

7983
- `openondemand_exporter`: Optional. Install the Prometheus [ondemand_exporter](https://github.com/OSC/ondemand_exporter) on the `openondemand` node to export metrics about Open Ondemand itself. Default `true`.

ansible/roles/openondemand/defaults/main.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ openondemand_osc_ood_defaults:
102102
ood_auth_openidc: "{{ openondemand_auth_defaults.oidc.ood_auth_openidc if (openondemand_auth | lower) == 'oidc' else none }}"
103103
httpd_auth: "{{ openondemand_auth_defaults[openondemand_auth | lower].httpd_auth }}"
104104

105+
# Apps:
105106
openondemand_code_server_version: 4.102.2
106107
openondemand_rstudio_version: 2025.05.1-513
107108
openondemand_matlab_version: ''
109+
# Below
110+
openondemand_gres_options: "{{ _openondemand_sinfo_gres.stdout | to_gres_options }}"
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/usr/bin/python
2+
# pylint: disable=missing-module-docstring
3+
4+
# Copyright: (c) 2025, StackHPC
5+
# Apache 2 License
6+
7+
def to_gres_options(stdout):
8+
gres_data = {} # k=gres_opt, v=[label, max_count] # where gres_opt is what would be passed to --gres
9+
gres_data['none'] = ['None', 0]
10+
11+
for line in stdout.splitlines():
12+
if '(null)' in line:
13+
continue
14+
partition, gres = line.split(' ')
15+
gres_name, gres_type, gres_number_cores = gres.split(':', maxsplit=2)
16+
gres_count, gres_cores = gres_number_cores.split('(')
17+
18+
for gres_opt in [gres_name, f'{gres_name}:{gres_type}']:
19+
if gres_opt not in gres_data:
20+
label = f'{gres_type} {gres_name}' if ':' in gres_opt else f'Any {gres_opt}'
21+
gres_data[gres_opt] = [label, gres_count]
22+
elif gres_count > gres_data[gres_name][1]:
23+
gres_data[gres_opt][1] = gres_count
24+
gres_options = []
25+
for gres_opt in gres_data:
26+
max_count = gres_data[gres_opt][1]
27+
label = gres_data[gres_opt][0]
28+
if gres_opt != 'none':
29+
label += f' (max count: {max_count})'
30+
gres_options.append((label, gres_opt))
31+
return gres_options
32+
33+
34+
# pylint: disable=useless-object-inheritance
35+
class FilterModule(object):
36+
"""Ansible core jinja2 filters"""
37+
38+
# pylint: disable=missing-function-docstring
39+
def filters(self):
40+
return {
41+
"to_gres_options": to_gres_options,
42+
}

ansible/roles/openondemand/tasks/main.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@
3939
vars_from: main.yml
4040
public: true
4141

42+
- name: Get GRES information
43+
command:
44+
cmd: sinfo --noheader --format "%R %G" # can't use , or : as separator
45+
register: _openondemand_sinfo_gres
46+
# partition_name gres
47+
# e.g.
48+
# gpu gpu:H200:8(S:0-1)
49+
# normal (null)
50+
# no_smi (null)
51+
4252
- ansible.builtin.include_role:
4353
name: osc.ood
4454
tasks_from: install-apps.yml

environments/common/inventory/group_vars/all/openondemand.yml

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,16 +122,30 @@ openondemand_apps_desktop_default:
122122
- bc_queue
123123
- bc_num_hours
124124
- num_cores
125+
- gres
126+
- gres_count
125127
- node
126128
attributes:
127129
desktop: xfce
128-
# bc_account: # i.e. slurm account
129-
# value: root
130130
bc_queue:
131131
value: "{{ openondemand_desktop_partition | default(none) }}"
132132
num_cores:
133133
label: Number of cores
134134
value: 1
135+
gres:
136+
label: Resources
137+
help: Select GPU or other Slurm GRES resources
138+
required: true
139+
widget: select
140+
options: "{{ openondemand_gres_options }}"
141+
gres_count:
142+
label: Resource count
143+
help: Count of GPU or other resources
144+
required: false
145+
widget: number_field
146+
value: 1
147+
min: 1
148+
step: 1
135149
node:
136150
label: Node name
137151
help: Select a particular node or leave empty to let Slurm pick the next available
@@ -144,6 +158,9 @@ openondemand_apps_desktop_default:
144158
- <%= "--nodes=1" %>
145159
- <%= "--ntasks=#{num_cores}" %>
146160
- <%= "--nodelist=#{node}" %>
161+
<% if gres != 'none' %>
162+
- <%= "--gres=#{gres}:#{gres_count}" %>
163+
<% end %>
147164
openondemand_apps_desktop: "{{ {'bc_desktop':openondemand_apps_desktop_default} if openondemand_desktop_partition | default(none) else {} }}"
148165

149166
# yamllint disable-line rule:line-length
@@ -158,12 +175,32 @@ openondemand_apps_jupyter_default:
158175
- bc_queue
159176
- bc_num_hours
160177
- num_cores
178+
- gres
179+
- gres_count
161180
- node
162181
attributes: # TODO
163182
num_cores:
164183
label: Number of cores
165184
value: 1
166185
modules: ""
186+
gres:
187+
label: Resources
188+
help: Select GPU or other Slurm GRES resources
189+
required: true
190+
widget: select
191+
options: "{{ openondemand_gres_options }}"
192+
gres_count:
193+
label: Resource count
194+
help: Count of GPU or other resources
195+
required: false
196+
widget: number_field
197+
value: 1
198+
min: 1
199+
step: 1
200+
node:
201+
label: Node name
202+
help: Select a particular node or leave empty to let Slurm pick the next available
203+
value: ""
167204
extra_jupyter_args: ""
168205
bc_queue:
169206
value: "{{ openondemand_jupyter_partition | default(none) }}"
@@ -182,6 +219,9 @@ openondemand_apps_jupyter_default:
182219
- <%= "--nodes=1" %>
183220
- <%= "--ntasks=#{num_cores}" %>
184221
- <%= "--nodelist=#{node}" %>
222+
<% if gres != 'none' %>
223+
- <%= "--gres=#{gres}:#{gres_count}" %>
224+
<% end %>
185225
openondemand_apps_jupyter: "{{ {'jupyter':openondemand_apps_jupyter_default} if openondemand_jupyter_partition | default(none) else {} }}"
186226

187227
openondemand_apps_rstudio_default:
@@ -233,6 +273,20 @@ openondemand_apps_rstudio_default:
233273
bc_email_on_started: false
234274
auto_modules_RStudio-Server:
235275
default: false
276+
gres:
277+
label: Resources
278+
help: Select GPU or other Slurm GRES resources
279+
required: true
280+
widget: select
281+
options: "{{ openondemand_gres_options }}"
282+
gres_count:
283+
label: Resource count
284+
help: Count of GPU or other resources
285+
required: false
286+
widget: number_field
287+
value: 1
288+
min: 1
289+
step: 1
236290
form:
237291
- bc_queue
238292
- rstudio_module
@@ -242,6 +296,8 @@ openondemand_apps_rstudio_default:
242296
- ram
243297
- bc_num_hours
244298
- bc_email_on_started
299+
- gres
300+
- gres_count
245301
submit: |
246302
---
247303
batch_connect:
@@ -261,6 +317,9 @@ openondemand_apps_rstudio_default:
261317
- "<%= cores.blank? ? 1 : cores.to_i %>"<% if auto_queues.start_with?("gpu") %>
262318
- "--gpus-per-task"
263319
- "1"<% end %>
320+
<% if gres != 'none' %>
321+
- <%= "--gres=#{gres}:#{gres_count}" %>
322+
<% end %>
264323
openondemand_apps_rstudio: "{{ {'rstudio':openondemand_apps_rstudio_default} if openondemand_rstudio_partition | default(none) else {} }}"
265324

266325
openondemand_apps_matlab_default:
@@ -274,6 +333,8 @@ openondemand_apps_matlab_default:
274333
- matlab_module
275334
- cores
276335
- ram
336+
- gres
337+
- gres_count
277338
attributes:
278339
desktop: xfce
279340
# bc_account: # i.e. slurm account
@@ -314,6 +375,20 @@ openondemand_apps_matlab_default:
314375
step: 1
315376
value: 30
316377
cachable: true
378+
gres:
379+
label: Resources
380+
help: Select GPU or other Slurm GRES resources
381+
required: true
382+
widget: select
383+
options: "{{ openondemand_gres_options }}"
384+
gres_count:
385+
label: Resource count
386+
help: Count of GPU or other resources
387+
required: false
388+
widget: number_field
389+
value: 1
390+
min: 1
391+
step: 1
317392
submit: |
318393
---
319394
script:
@@ -327,6 +402,9 @@ openondemand_apps_matlab_default:
327402
- "<%= ram.blank? ? 4 : ram.to_i %>G"
328403
- "--cpus-per-task"
329404
- "<%= cores.blank? ? 1 : cores.to_i %>"
405+
<% if gres != 'none' %>
406+
- <%= "--gres=#{gres}:#{gres_count}" %>
407+
<% end %>
330408
openondemand_apps_matlab: "{{ {'matlab':openondemand_apps_matlab_default} if openondemand_matlab_partition | default(none) else {} }}"
331409

332410
openondemand_apps_codeserver_default:

0 commit comments

Comments
 (0)