2
2
3
3
from configparser import ConfigParser
4
4
from io import StringIO
5
- from pathlib import Path
6
- from typing import Any , Optional , Self
5
+ from pathlib import PurePosixPath
6
+ from typing import Any , Final , Optional , Self
7
7
8
+ from kubernetes import client
8
9
from marshmallow import EXCLUDE , Schema , ValidationError , fields , validates_schema
9
10
10
11
from renku_data_services .base_models import APIUser
11
12
from renku_data_services .notebooks .api .classes .cloud_storage import ICloudStorageRequest
12
13
from renku_data_services .notebooks .config import _NotebooksConfig
13
14
15
+ _sanitize_for_serialization = client .ApiClient ().sanitize_for_serialization
16
+
14
17
15
18
class RCloneStorageRequest (Schema ):
16
19
"""Request for RClone based storage."""
@@ -36,6 +39,8 @@ def validate_storage(self, data: dict, **kwargs: dict) -> None:
36
39
class RCloneStorage (ICloudStorageRequest ):
37
40
"""RClone based storage."""
38
41
42
+ pvc_secret_annotation_name : Final [str ] = "csi-rclone.dev/secretName"
43
+
39
44
def __init__ (
40
45
self ,
41
46
source_path : str ,
@@ -60,7 +65,7 @@ async def storage_from_schema(
60
65
user : APIUser ,
61
66
internal_gitlab_user : APIUser ,
62
67
project_id : int ,
63
- work_dir : Path ,
68
+ work_dir : PurePosixPath ,
64
69
config : _NotebooksConfig ,
65
70
) -> Self :
66
71
"""Create storage object from request."""
@@ -92,8 +97,73 @@ async def storage_from_schema(
92
97
await config .storage_validator .validate_storage_configuration (configuration , source_path )
93
98
return cls (source_path , configuration , readonly , mount_folder , name , config )
94
99
100
+ def pvc (
101
+ self ,
102
+ base_name : str ,
103
+ namespace : str ,
104
+ labels : dict [str , str ] | None = None ,
105
+ annotations : dict [str , str ] | None = None ,
106
+ ) -> client .V1PersistentVolumeClaim :
107
+ """The PVC for mounting cloud storage."""
108
+ return client .V1PersistentVolumeClaim (
109
+ metadata = client .V1ObjectMeta (
110
+ name = base_name ,
111
+ namespace = namespace ,
112
+ annotations = {self .pvc_secret_annotation_name : base_name } | (annotations or {}),
113
+ labels = {"name" : base_name } | (labels or {}),
114
+ ),
115
+ spec = client .V1PersistentVolumeClaimSpec (
116
+ access_modes = ["ReadOnlyMany" if self .readonly else "ReadWriteMany" ],
117
+ resources = client .V1VolumeResourceRequirements (requests = {"storage" : "10Gi" }),
118
+ storage_class_name = self .config .cloud_storage .storage_class ,
119
+ ),
120
+ )
121
+
122
+ def volume_mount (self , base_name : str ) -> client .V1VolumeMount :
123
+ """The volume mount for cloud storage."""
124
+ return client .V1VolumeMount (
125
+ mount_path = self .mount_folder ,
126
+ name = base_name ,
127
+ read_only = self .readonly ,
128
+ )
129
+
130
+ def volume (self , base_name : str ) -> client .V1Volume :
131
+ """The volume entry for the statefulset specification."""
132
+ return client .V1Volume (
133
+ name = base_name ,
134
+ persistent_volume_claim = client .V1PersistentVolumeClaimVolumeSource (
135
+ claim_name = base_name , read_only = self .readonly
136
+ ),
137
+ )
138
+
139
+ def secret (
140
+ self ,
141
+ base_name : str ,
142
+ namespace : str ,
143
+ labels : dict [str , str ] | None = None ,
144
+ annotations : dict [str , str ] | None = None ,
145
+ ) -> client .V1Secret :
146
+ """The secret containing the configuration for the rclone csi driver."""
147
+ return client .V1Secret (
148
+ metadata = client .V1ObjectMeta (
149
+ name = base_name ,
150
+ namespace = namespace ,
151
+ annotations = annotations ,
152
+ labels = {"name" : base_name } | (labels or {}),
153
+ ),
154
+ string_data = {
155
+ "remote" : self .name or base_name ,
156
+ "remotePath" : self .source_path ,
157
+ "configData" : self .config_string (self .name or base_name ),
158
+ },
159
+ )
160
+
95
161
def get_manifest_patch (
96
- self , base_name : str , namespace : str , labels : dict = {}, annotations : dict = {}
162
+ self ,
163
+ base_name : str ,
164
+ namespace : str ,
165
+ labels : dict [str , str ] | None = None ,
166
+ annotations : dict [str , str ] | None = None ,
97
167
) -> list [dict [str , Any ]]:
98
168
"""Get server manifest patch."""
99
169
patches = []
@@ -104,57 +174,22 @@ def get_manifest_patch(
104
174
{
105
175
"op" : "add" ,
106
176
"path" : f"/{ base_name } -pv" ,
107
- "value" : {
108
- "apiVersion" : "v1" ,
109
- "kind" : "PersistentVolumeClaim" ,
110
- "metadata" : {
111
- "name" : base_name ,
112
- "labels" : {"name" : base_name },
113
- },
114
- "spec" : {
115
- "accessModes" : ["ReadOnlyMany" if self .readonly else "ReadWriteMany" ],
116
- "resources" : {"requests" : {"storage" : "10Gi" }},
117
- "storageClassName" : self .config .cloud_storage .storage_class ,
118
- },
119
- },
177
+ "value" : _sanitize_for_serialization (self .pvc (base_name , namespace , labels , annotations )),
120
178
},
121
179
{
122
180
"op" : "add" ,
123
181
"path" : f"/{ base_name } -secret" ,
124
- "value" : {
125
- "apiVersion" : "v1" ,
126
- "kind" : "Secret" ,
127
- "metadata" : {
128
- "name" : base_name ,
129
- "labels" : {"name" : base_name },
130
- },
131
- "type" : "Opaque" ,
132
- "stringData" : {
133
- "remote" : self .name or base_name ,
134
- "remotePath" : self .source_path ,
135
- "configData" : self .config_string (self .name or base_name ),
136
- },
137
- },
182
+ "value" : _sanitize_for_serialization (self .secret (base_name , namespace , labels , annotations )),
138
183
},
139
184
{
140
185
"op" : "add" ,
141
186
"path" : "/statefulset/spec/template/spec/containers/0/volumeMounts/-" ,
142
- "value" : {
143
- "mountPath" : self .mount_folder ,
144
- "name" : base_name ,
145
- "readOnly" : self .readonly ,
146
- },
187
+ "value" : _sanitize_for_serialization (self .volume_mount (base_name )),
147
188
},
148
189
{
149
190
"op" : "add" ,
150
191
"path" : "/statefulset/spec/template/spec/volumes/-" ,
151
- "value" : {
152
- "name" : base_name ,
153
- "persistentVolumeClaim" : {
154
- "claimName" : base_name ,
155
- "readOnly" : self .readonly ,
156
- },
157
- },
192
+ "value" : _sanitize_for_serialization (self .volume (base_name )),
158
193
},
159
194
],
160
195
}
0 commit comments