Skip to content

Commit 2ed7e98

Browse files
committed
Set volume and volume mount as dict
1 parent c84e0c2 commit 2ed7e98

File tree

6 files changed

+82
-37
lines changed

6 files changed

+82
-37
lines changed

docs/source/jupyterhub/customizing/user-resources.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,13 @@ The following configuration will increase the SHM allocation by mounting a
118118
singleuser:
119119
storage:
120120
extraVolumes:
121-
- name: shm-volume
121+
shm-volume:
122+
name: shm-volume
122123
emptyDir:
123124
medium: Memory
124125
extraVolumeMounts:
125-
- name: shm-volume
126+
shm-volume:
127+
name: shm-volume
126128
mountPath: /dev/shm
127129
```
128130

docs/source/jupyterhub/customizing/user-storage.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,11 +235,13 @@ pods:
235235
singleuser:
236236
storage:
237237
extraVolumes:
238-
- name: jupyterhub-shared
238+
jupyterhub-shared:
239+
name: jupyterhub-shared
239240
persistentVolumeClaim:
240241
claimName: jupyterhub-shared-volume
241242
extraVolumeMounts:
242-
- name: jupyterhub-shared
243+
jupyterhub-shared:
244+
name: jupyterhub-shared
243245
mountPath: /home/shared
244246
```
245247

jupyterhub/files/hub/jupyterhub_config.py

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,9 @@ def camelCaseify(s):
252252
if tolerations:
253253
c.KubeSpawner.tolerations = tolerations
254254

255+
volumes = {}
256+
volume_mounts = {}
257+
255258
# Configure dynamically provisioning pvc
256259
storage_type = get_config("singleuser.storage.type")
257260
if storage_type == "dynamic":
@@ -273,32 +276,35 @@ def camelCaseify(s):
273276
)
274277

275278
# Add volumes to singleuser pods
276-
c.KubeSpawner.volumes = [
277-
{
279+
volumes = {
280+
volume_name_template: {
278281
"name": volume_name_template,
279282
"persistentVolumeClaim": {"claimName": "{pvc_name}"},
280283
}
281-
]
282-
c.KubeSpawner.volume_mounts = [
283-
{
284+
}
285+
volume_mounts = {
286+
volume_name_template: {
284287
"mountPath": get_config("singleuser.storage.homeMountPath"),
285288
"name": volume_name_template,
286289
"subPath": get_config("singleuser.storage.dynamic.subPath"),
287290
}
288-
]
291+
}
289292
elif storage_type == "static":
290293
pvc_claim_name = get_config("singleuser.storage.static.pvcName")
291-
c.KubeSpawner.volumes = [
292-
{"name": "home", "persistentVolumeClaim": {"claimName": pvc_claim_name}}
293-
]
294+
volumes = {
295+
"home": {
296+
"name": "home",
297+
"persistentVolumeClaim": {"claimName": pvc_claim_name},
298+
}
299+
}
294300

295-
c.KubeSpawner.volume_mounts = [
296-
{
301+
volume_mounts = {
302+
"home": {
297303
"mountPath": get_config("singleuser.storage.homeMountPath"),
298304
"name": "home",
299305
"subPath": get_config("singleuser.storage.static.subPath"),
300306
}
301-
]
307+
}
302308

303309
# Inject singleuser.extraFiles as volumes and volumeMounts with data loaded from
304310
# the dedicated k8s Secret prepared to hold the extraFiles actual content.
@@ -323,24 +329,39 @@ def camelCaseify(s):
323329
"secretName": get_name("singleuser"),
324330
"items": items,
325331
}
326-
c.KubeSpawner.volumes.append(volume)
332+
volumes.update({volume["name"]: volume})
327333

328-
volume_mounts = []
329-
for file_key, file_details in extra_files.items():
330-
volume_mounts.append(
331-
{
332-
"mountPath": file_details["mountPath"],
333-
"subPath": file_key,
334-
"name": "files",
335-
}
336-
)
337-
c.KubeSpawner.volume_mounts.extend(volume_mounts)
334+
for idx, (file_key, file_details) in enumerate(extra_files.items()):
335+
volume_mount = {
336+
"mountPath": file_details["mountPath"],
337+
"subPath": file_key,
338+
"name": "files",
339+
}
340+
volume_mounts.update({f"{idx}-files": volume_mount})
338341

339342
# Inject extraVolumes / extraVolumeMounts
340-
c.KubeSpawner.volumes.extend(get_config("singleuser.storage.extraVolumes", []))
341-
c.KubeSpawner.volume_mounts.extend(
342-
get_config("singleuser.storage.extraVolumeMounts", [])
343-
)
343+
extra_volumes = get_config("singleuser.storage.extraVolumes", default={})
344+
if isinstance(extra_volumes, dict):
345+
for key, volume in extra_volumes.items():
346+
volumes.update({key: volume})
347+
elif isinstance(extra_volumes, list):
348+
for volume in extra_volumes:
349+
volumes.update({volume["name"]: volume})
350+
351+
extra_volume_mounts = get_config("singleuser.storage.extraVolumeMounts", default={})
352+
if isinstance(extra_volume_mounts, dict):
353+
for key, volume_mount in extra_volume_mounts.items():
354+
volume_mounts.update({key: volume_mount})
355+
elif isinstance(extra_volume_mounts, list):
356+
# If extraVolumeMounts is a list, we need to add them to the volume_mounts
357+
# dictionary with a unique key.
358+
# Since volume mount's name is not guaranteed to be unique, we use the index
359+
# as part of the key.
360+
for idx, volume_mount in enumerate(extra_volume_mounts):
361+
volume_mounts.update({f"{idx}-{volume_mount['name']}": volume_mount})
362+
363+
c.KubeSpawner.volumes = volumes
364+
c.KubeSpawner.volume_mounts = volume_mounts
344365

345366
c.JupyterHub.services = []
346367
c.JupyterHub.load_roles = []

jupyterhub/values.schema.yaml

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2418,8 +2418,28 @@ properties:
24182418
Configures `KubeSpawner.storage_extra_labels`. Note that these
24192419
labels are set on the PVC during creation only and won't be
24202420
updated after creation.
2421-
extraVolumeMounts: *extraVolumeMounts-spec
2422-
extraVolumes: *extraVolumes-spec
2421+
extraVolumeMounts:
2422+
type: [object, array]
2423+
description: |
2424+
Configures `KubeSpawner.volume_mounts` dictionary. Can be a dictionary
2425+
or an array.
2426+
If it's an array, a combination of the volume name and its index is
2427+
used as the key while setting up the volume mount entry in
2428+
KubeSpawner.volume_mounts and the value is the volume mount
2429+
configuration.
2430+
If it's a dictionary, the keys of the dictionary can be any descriptive
2431+
name for the volume mount and the value is the volume mount
2432+
configuration.
2433+
extraVolumes:
2434+
type: [object, array]
2435+
description: |
2436+
Configures `KubeSpawner.volumes` dictionary. Can be a dictionary or an
2437+
array.
2438+
If it's an array, the name of the volume is used as the key while
2439+
setting up the volume entry in KubeSpawner.volumes and the value is the
2440+
volume configuration.
2441+
If it's a dictionary, the keys of the dictionary can be any descriptive
2442+
name for the volume and the value is the volume configuration.
24232443
homeMountPath:
24242444
type: string
24252445
description: |

jupyterhub/values.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -404,8 +404,8 @@ singleuser:
404404
storage:
405405
type: dynamic
406406
extraLabels: {}
407-
extraVolumes: []
408-
extraVolumeMounts: []
407+
extraVolumes: {}
408+
extraVolumeMounts: {}
409409
static:
410410
pvcName:
411411
subPath: "{username}"

tools/templates/lint-and-validate-values.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -455,8 +455,8 @@ singleuser:
455455
storage:
456456
type: dynamic
457457
extraLabels: *labels
458-
extraVolumes: []
459-
extraVolumeMounts: []
458+
extraVolumes: {}
459+
extraVolumeMounts: {}
460460
static:
461461
pvcName:
462462
subPath: "{username}"

0 commit comments

Comments
 (0)