1
- import asyncio
1
+ import asyncio
2
2
import kubernetes_asyncio
3
3
from kubernetes_asyncio import config , client
4
4
import datetime
5
5
6
- #nsprefix = 'mtdminer-'
7
- #nssuffix = '-prod-ns'
8
6
ns = 'metadynminer-ns'
9
7
usagelog = '/srv/jupyterhub/usage.log'
10
8
11
- from kubernetes_asyncio .client import (
12
- V1ObjectMeta ,
13
- V1Secret ,
14
- V1PersistentVolume ,
15
- V1PersistentVolumeClaim ,
16
- V1ResourceRequirements ,
17
- V1LabelSelector ,
18
- V1CSIPersistentVolumeSource ,
19
- V1PersistentVolumeSpec ,
20
- V1PersistentVolumeClaimSpec ,
21
- V1Namespace ,
22
- V1ServiceAccount ,
23
- V1RoleBinding ,
24
- V1RoleRef ,
25
- V1Subject ,
26
- V1ClusterRole ,
27
- V1PolicyRule ,
28
- ApiException ,
29
- )
30
-
31
- async def check_pvc (home_pvc_name , namespace ):
32
- async with kubernetes_asyncio .client .ApiClient () as api_client :
33
- v1 = kubernetes_asyncio .client .CoreV1Api (api_client )
34
- pvcs = await v1 .list_namespaced_persistent_volume_claim (namespace )
35
- for claim in pvcs .items :
36
- if claim .metadata .name == home_pvc_name :
37
- return claim
38
- return None
39
-
40
- async def delete_pvc (namespace , pvc ):
41
- async with kubernetes_asyncio .client .ApiClient () as api_client :
42
- v1 = kubernetes_asyncio .client .CoreV1Api (api_client )
43
- await v1 .delete_namespaced_persistent_volume_claim (name = pvc , namespace = namespace )
44
- await asyncio .sleep (1 )
45
-
46
- async def create_pvc (home_pvc_name , home_pv_name , namespace , storage_class , capacity ):
47
- pvc = V1PersistentVolumeClaim ()
48
- pvc .api_version = "v1"
49
- pvc .kind = "PersistentVolumeClaim"
50
- pvc .metadata = V1ObjectMeta ()
51
- pvc .metadata .name = home_pvc_name
52
- pvc .spec = V1PersistentVolumeClaimSpec ()
53
- pvc .spec .access_modes = ['ReadWriteMany' ]
54
- pvc .spec .resources = V1ResourceRequirements ()
55
- pvc .spec .resources .requests = {"storage" : capacity }
56
- pvc .spec .storage_class_name = storage_class
57
- if storage_class != "nfs-csi" :
58
- pvc .spec .selector = V1LabelSelector ()
59
- pvc .spec .selector .match_labels = {"name" : home_pv_name }
60
- try :
61
- async with kubernetes_asyncio .client .ApiClient () as api_client :
62
- v1 = kubernetes_asyncio .client .CoreV1Api (api_client )
63
- x = await v1 .create_namespaced_persistent_volume_claim (namespace , pvc )
64
- await asyncio .sleep (1 )
65
- except ApiException as e :
66
- if re .search ("object is being deleted:" , e .body ):
67
- raise web .HTTPError (401 , "Can't delete PVC {}, please contact administrator!" .format (home_pvc_name ))
68
- return False
69
- return True
70
-
71
- def add_volume (spawner_vol_list , volume , volname ):
72
- volume_exists = False
73
- for vol in spawner_vol_list :
74
- if "name" in vol and vol ["name" ] == volname :
75
- volume_exists = True
76
- if not volume_exists :
77
- spawner_vol_list .append (volume )
78
-
79
- def mount (spawner , pv , pvc , mountpath ):
80
- volume = {"name" : pv , "persistentVolumeClaim" : {"claimName" : pvc }}
81
- volume_mount = {"mountPath" : mountpath , "name" : pv }
82
- if len (spawner .volumes ) == 0 :
83
- spawner .volumes = [volume ]
84
- else :
85
- add_volume (spawner .volumes , volume , pv )
86
- if len (spawner .volume_mounts ) == 0 :
87
- spawner .volume_mounts = [volume_mount ]
88
- else :
89
- add_volume (spawner .volume_mounts , volume_mount , pvc )
90
-
91
- async def mount_persistent_hub_home (spawner , username , namespace ):
92
- hub_home_name = username + "-home-default"
93
-
94
- if spawner .user_options .get ('delhome' ) == "delete" :
95
- pvc = await check_pvc (hub_home_name , namespace )
96
- if pvc :
97
- await delete_pvc (namespace , hub_home_name )
98
- await create_pvc (hub_home_name , hub_home_name + "-pv" , namespace , "nfs-csi" , "10Gi" )
99
- else :
100
- pvc = await check_pvc (hub_home_name , namespace )
101
- if not pvc :
102
- await create_pvc (hub_home_name , hub_home_name + "-pv" , namespace , "nfs-csi" , "10Gi" )
103
-
104
- mount (spawner , hub_home_name + "-pv" , hub_home_name , "/home/jovyan" )
105
-
106
- async def check_ns (user_ns ):
107
- async with kubernetes_asyncio .client .ApiClient () as api_client :
108
- v1 = kubernetes_asyncio .client .CoreV1Api (api_client )
109
- nss = await v1 .list_namespace (watch = False )
110
- for ns in nss .items :
111
- if ns .metadata .name == user_ns :
112
- ann = ns .metadata .annotations .get ("field.cattle.io/projectId" )
113
- if not ann or ann != 'c-m-qvndqhf6:p-wt9xp' :
114
- return True , False
115
- return True , True
116
- return False , False
117
-
118
-
119
- async def create_ns (username , original ):
120
- namespace = nsprefix + username + nssuffix
121
- exists , ann = await check_ns (namespace )
122
- if not exists :
123
- ns = V1Namespace ()
124
- ns .metadata = V1ObjectMeta (name = namespace ,
125
- annotations = {'field.cattle.io/projectId' : 'c-m-qvndqhf6:p-wt9xp' , 'user' : original },
126
- labels = {'hub.jupyter.org/network-access-hub' : 'true' })
127
-
128
- async with kubernetes_asyncio .client .ApiClient () as api_client :
129
- v1 = kubernetes_asyncio .client .CoreV1Api (api_client )
130
- await v1 .create_namespace (body = ns )
131
- await asyncio .sleep (1 )
132
- return namespace
133
- if exists and not ann :
134
- raise web .
HTTPError (
401 ,
"Non-labelled namespace error! Please contact administrator at [email protected] ." )
135
- return namespace
136
-
137
- async def check_sa (user_sa , namespace ):
138
- async with kubernetes_asyncio .client .ApiClient () as api_client :
139
- v1 = kubernetes_asyncio .client .CoreV1Api (api_client )
140
- sas = await v1 .list_namespaced_service_account (namespace = namespace )
141
- for sa in sas .items :
142
- if sa .metadata .name == user_sa :
143
- return True
144
- return False
145
-
146
-
147
- async def create_sa (username , namespace ):
148
- sa_name = "sa-" + username
149
- exists = await check_sa (sa_name , namespace )
150
- if not exists :
151
- sa = V1ServiceAccount ()
152
- sa .metadata = V1ObjectMeta (name = sa_name )
153
- async with kubernetes_asyncio .client .ApiClient () as api_client :
154
- v1 = kubernetes_asyncio .client .CoreV1Api (api_client )
155
- await v1 .create_namespaced_service_account (namespace = namespace , body = sa )
156
- await asyncio .sleep (1 )
157
- return sa_name
158
-
159
-
160
- async def check_rb (namespace ):
161
- async with kubernetes_asyncio .client .ApiClient () as api_client :
162
- v1 = kubernetes_asyncio .client .RbacAuthorizationV1Api (api_client )
163
- rbs = await v1 .list_namespaced_role_binding (namespace = namespace )
164
- for rb in rbs .items :
165
- if rb .metadata .name == "hub-resources-access-binding" :
166
- return True
167
- return False
168
-
169
-
170
- async def create_rb (sa_name , namespace ):
171
- try :
172
- rb = V1RoleBinding (role_ref = V1RoleRef (api_group = "rbac.authorization.k8s.io" , kind = "ClusterRole" ,
173
- name = "hub-resources-access" ))
174
- rb .metadata = V1ObjectMeta (name = "hub-resources-access-binding" , namespace = namespace )
175
- rb .subjects = [V1Subject (kind = "ServiceAccount" , name = sa_name )]
176
- async with kubernetes_asyncio .client .ApiClient () as api_client :
177
- v1 = kubernetes_asyncio .client .RbacAuthorizationV1Api (api_client )
178
- await v1 .create_namespaced_role_binding (namespace = namespace , body = rb )
179
- await asyncio .sleep (1 )
180
- except kubernetes_asyncio .client .exceptions .ApiException as e :
181
- pass # buzz off
182
-
183
-
184
-
185
9
async def bootstrap_pre_spawn (spawner ):
186
10
config .load_incluster_config ()
187
11
namespace = spawner .namespace
@@ -192,28 +16,9 @@ async def bootstrap_pre_spawn(spawner):
192
16
if "_" in username :
193
17
username = username .replace ("_" , "-5f" )
194
18
195
- # spawner.environment = {"JUPYTERHUB_API_URL": "http://hub.gmxhub-ns.svc.cluster.local:8081/hub/api",
196
- # "JUPYTERHUB_ACTIVITY_URL": "http://hub.gmxhub-ns.svc.cluster.local:8081/hub/api/users/"+username+"/activity"}
197
-
198
- # ns = await create_ns(username, original)
199
- # sa = await create_sa(username, ns)
200
- # sa = 'hub'
201
- # await create_rb(sa, ns)
202
-
203
- await mount_persistent_hub_home (spawner , username , ns )
204
-
205
- # spawner.args += [ '--port=8888', '--ip=0.0.0.0', f'--NotebookApp.base_url=/user/{username}/' ]
206
- # spawner.args += [ '--port=8888', '--ip=0.0.0.0' ]
207
-
208
19
with open (usagelog ,"a" ) as l :
209
20
l .write (datetime .datetime .now (datetime .timezone .utc ).strftime ('%c %z:' ) + username + '\n ' )
210
21
211
- # gpu = spawner.user_options.get('gpu')
212
- # cpu = spawner.user_options.get('cpu')
213
- # mem = spawner.user_options.get('mem')
214
- # image = spawner.user_options.get('container_image')
215
-
216
- # spawner.image = 'ljocha/gromacs-hub'
217
22
spawner .image = get_config ('hub.config.notebookImage' )
218
23
spawner .cpu_limit = 1.
219
24
spawner .cpu_guarantee = .2
@@ -222,10 +27,4 @@ async def bootstrap_pre_spawn(spawner):
222
27
spawner .container_security_context = {"capabilities" : {"drop" : ["ALL" ]}}
223
28
224
29
c .KubeSpawner .pre_spawn_hook = bootstrap_pre_spawn
225
- #c.KubeSpawner.enable_user_namespaces = True
226
- #c.KubeSpawner.user_namespace_template = nsprefix + "{username}" + nssuffix
227
- #c.KubeSpawner.enable_user_namespaces = False
228
- #c.KubeSpawner.user_namespace_template = "jupyterhub-{username}-prod-ns"
229
30
c .KubeSpawner .automount_service_account_token = False
230
- #c.KubeSpawner.service_account = "sa-{username}"
231
- # c.KubeSpawner.service_account = "metadynminer-jobs"
0 commit comments