11
11
import time
12
12
import threading
13
13
import tempfile
14
+ import hashlib
14
15
15
16
from DIRAC import gLogger , S_OK , S_ERROR
16
17
from DIRAC .Core .DISET .RequestHandler import RequestHandler
24
25
from DIRAC .RequestManagementSystem .Client .Operation import Operation
25
26
from DIRAC .RequestManagementSystem .Client .File import File
26
27
from DIRAC .Resources .Storage .StorageElement import StorageElement
28
+ from DIRAC .Core .Utilities .File import getGlobbedTotalSize
27
29
28
30
29
- class SandboxStoreHandler ( RequestHandler ) :
31
+ class SandboxStoreHandlerMixin :
30
32
__purgeCount = - 1
31
33
__purgeLock = threading .Lock ()
32
34
__purgeWorking = False
@@ -44,10 +46,10 @@ def initializeHandler(cls, serviceInfoDict):
44
46
return S_ERROR (f"Can't connect to DB: { repr (excp )} " )
45
47
return S_OK ()
46
48
47
- def initialize (self ):
49
+ def initializeRequest (self ):
48
50
self .__backend = self .getCSOption ("Backend" , "local" )
49
51
self .__localSEName = self .getCSOption ("LocalSE" , "SandboxSE" )
50
- self .__maxUploadBytes = self .getCSOption ("MaxSandboxSizeMiB" , 10 ) * 1048576
52
+ self ._maxUploadBytes = self .getCSOption ("MaxSandboxSizeMiB" , 10 ) * 1048576
51
53
if self .__backend .lower () == "local" or self .__backend == self .__localSEName :
52
54
self .__useLocalStorage = True
53
55
self .__seNameToUse = self .__localSEName
@@ -75,13 +77,14 @@ def __getSandboxPath(self, md5):
75
77
pathItems .extend ([md5 [0 :3 ], md5 [3 :6 ], md5 ])
76
78
return os .path .join (* pathItems )
77
79
78
- def transfer_fromClient (self , fileId , token , fileSize , fileHelper ):
80
+ def _getFromClient (self , fileId , token , fileSize , fileHelper = None , data = "" ):
79
81
"""
80
82
Receive a file as a sandbox
81
83
"""
82
84
83
- if self .__maxUploadBytes and fileSize > self .__maxUploadBytes :
84
- fileHelper .markAsTransferred ()
85
+ if self ._maxUploadBytes and fileSize > self ._maxUploadBytes :
86
+ if fileHelper :
87
+ fileHelper .markAsTransferred ()
85
88
return S_ERROR ("Sandbox is too big. Please upload it to a grid storage element" )
86
89
87
90
if isinstance (fileId , (list , tuple )):
@@ -113,7 +116,8 @@ def transfer_fromClient(self, fileId, token, fileSize, fileHelper):
113
116
result = self .sandboxDB .getSandboxId (seName , sePFN , credDict ["username" ], credDict ["group" ])
114
117
if result ["OK" ]:
115
118
gLogger .info ("Sandbox already exists. Skipping upload" )
116
- fileHelper .markAsTransferred ()
119
+ if fileHelper :
120
+ fileHelper .markAsTransferred ()
117
121
sbURL = f"SB:{ seName } |{ sePFN } "
118
122
assignTo = {key : [(sbURL , assignTo [key ])] for key in assignTo }
119
123
result = self .export_assignSandboxesToEntities (assignTo )
@@ -126,14 +130,35 @@ def transfer_fromClient(self, fileId, token, fileSize, fileHelper):
126
130
else :
127
131
hdPath = False
128
132
# Write to local file
129
- result = self .__networkToFile (fileHelper , hdPath )
133
+
134
+ if fileHelper :
135
+ result = self .__networkToFile (fileHelper , hdPath )
136
+ elif data :
137
+ hdPath = os .path .realpath (hdPath )
138
+ mkDir (os .path .dirname (hdPath ))
139
+ with open (hdPath , "bw" ) as output :
140
+ output .write (data )
141
+ result = S_OK (hdPath )
142
+ else :
143
+ result = S_ERROR ("No data provided" )
144
+
130
145
if not result ["OK" ]:
131
146
gLogger .error ("Error while receiving sandbox file" , result ["Message" ])
132
147
return result
133
148
hdPath = result ["Value" ]
134
149
gLogger .info ("Wrote sandbox to file" , hdPath )
135
150
# Check hash!
136
- if fileHelper .getHash () != aHash :
151
+ if fileHelper :
152
+ hdHash = fileHelper .getHash ()
153
+ else :
154
+ oMD5 = hashlib .md5 ()
155
+ with open (hdPath , "rb" ) as fd :
156
+ bData = fd .read (10240 )
157
+ while bData :
158
+ oMD5 .update (bData )
159
+ bData = fd .read (10240 )
160
+ hdHash = oMD5 .hexdigest ()
161
+ if hdHash != aHash :
137
162
self .__secureUnlinkFile (hdPath )
138
163
gLogger .error ("Hashes don't match! Client defined hash is different with received data hash!" )
139
164
return S_ERROR ("Hashes don't match!" )
@@ -147,13 +172,14 @@ def transfer_fromClient(self, fileId, token, fileSize, fileHelper):
147
172
sbPath = result ["Value" ][1 ]
148
173
# Register!
149
174
gLogger .info ("Registering sandbox in the DB with" , f"SB:{ self .__seNameToUse } |{ sbPath } " )
175
+ fSize = getGlobbedTotalSize (hdPath )
150
176
result = self .sandboxDB .registerAndGetSandbox (
151
177
credDict ["username" ],
152
178
credDict ["DN" ],
153
179
credDict ["group" ],
154
180
self .__seNameToUse ,
155
181
sbPath ,
156
- fileHelper . getTransferedBytes () ,
182
+ fSize ,
157
183
)
158
184
if not result ["OK" ]:
159
185
self .__secureUnlinkFile (hdPath )
@@ -166,6 +192,13 @@ def transfer_fromClient(self, fileId, token, fileSize, fileHelper):
166
192
return result
167
193
return S_OK (sbURL )
168
194
195
+ def transfer_fromClient (self , fileId , token , fileSize , fileHelper ):
196
+ """
197
+ Receive a file as a sandbox
198
+ """
199
+
200
+ return self ._getFromFile (fileId , token , fileSize , fileHelper = fileHelper )
201
+
169
202
def transfer_bulkFromClient (self , fileId , token , _fileSize , fileHelper ):
170
203
"""Receive files packed into a tar archive by the fileHelper logic.
171
204
token is used for access rights confirmation.
@@ -322,47 +355,39 @@ def __copyToExternalSE(self, localFilePath, sbPath):
322
355
323
356
types_assignSandboxesToEntities = [dict ]
324
357
325
- def export_assignSandboxesToEntities (self , enDict , ownerName = "" , ownerGroup = "" , entitySetup = False ):
358
+ def export_assignSandboxesToEntities (self , enDict , ownerName = "" , ownerGroup = "" ):
326
359
"""
327
360
Assign sandboxes to jobs.
328
361
Expects a dict of { entityId : [ ( SB, SBType ), ... ] }
329
362
"""
330
- if not entitySetup :
331
- entitySetup = self .serviceInfoDict ["clientSetup" ]
332
363
credDict = self .getRemoteCredentials ()
333
364
return self .sandboxDB .assignSandboxesToEntities (
334
- enDict , credDict ["username" ], credDict ["group" ], entitySetup , ownerName , ownerGroup
365
+ enDict , credDict ["username" ], credDict ["group" ], ownerName , ownerGroup
335
366
)
336
367
337
368
##################
338
369
# Unassign sbs to jobs
339
370
340
371
types_unassignEntities = [(list , tuple )]
341
372
342
- def export_unassignEntities (self , entitiesList , entitiesSetup = False ):
373
+ def export_unassignEntities (self , entitiesList ):
343
374
"""
344
375
Unassign a list of jobs
345
376
"""
346
- if not entitiesSetup :
347
- entitiesSetup = self .serviceInfoDict ["clientSetup" ]
348
377
credDict = self .getRemoteCredentials ()
349
- return self .sandboxDB .unassignEntities ({ entitiesSetup : entitiesList } , credDict ["username" ], credDict ["group" ])
378
+ return self .sandboxDB .unassignEntities (entitiesList , credDict ["username" ], credDict ["group" ])
350
379
351
380
##################
352
381
# Getting assigned sandboxes
353
382
354
383
types_getSandboxesAssignedToEntity = [str ]
355
384
356
- def export_getSandboxesAssignedToEntity (self , entityId , entitySetup = False ):
385
+ def export_getSandboxesAssignedToEntity (self , entityId ):
357
386
"""
358
387
Get the sandboxes associated to a job and the association type
359
388
"""
360
- if not entitySetup :
361
- entitySetup = self .serviceInfoDict ["clientSetup" ]
362
389
credDict = self .getRemoteCredentials ()
363
- result = self .sandboxDB .getSandboxesAssignedToEntity (
364
- entityId , entitySetup , credDict ["username" ], credDict ["group" ]
365
- )
390
+ result = self .sandboxDB .getSandboxesAssignedToEntity (entityId , credDict ["username" ], credDict ["group" ])
366
391
if not result ["OK" ]:
367
392
return result
368
393
sbDict = {}
@@ -400,6 +425,10 @@ def transfer_toClient(self, fileID, token, fileHelper):
400
425
fileID is the local file name in the SE.
401
426
token is used for access rights confirmation.
402
427
"""
428
+
429
+ return self ._sendToClient (fileID , token , fileHelper = fileHelper )
430
+
431
+ def _sendToClient (self , fileID , token , fileHelper = None , raw = False ):
403
432
credDict = self .getRemoteCredentials ()
404
433
serviceURL = self .serviceInfoDict ["URL" ]
405
434
filePath = fileID .replace (serviceURL , "" )
@@ -412,13 +441,21 @@ def transfer_toClient(self, fileID, token, fileHelper):
412
441
hdPath = self .__sbToHDPath (filePath )
413
442
if not os .path .isfile (hdPath ):
414
443
return S_ERROR ("Sandbox does not exist" )
415
- result = fileHelper .getFileDescriptor (hdPath , "rb" )
416
- if not result ["OK" ]:
417
- return S_ERROR (f"Failed to get file descriptor: { result ['Message' ]} " )
418
- fd = result ["Value" ]
419
- result = fileHelper .FDToNetwork (fd )
420
- fileHelper .oFile .close ()
421
- return result
444
+
445
+ if fileHelper :
446
+ result = fileHelper .getFileDescriptor (hdPath , "rb" )
447
+ if not result ["OK" ]:
448
+ return S_ERROR (f"Failed to get file descriptor: { result ['Message' ]} " )
449
+ fd = result ["Value" ]
450
+ result = fileHelper .FDToNetwork (fd )
451
+ fileHelper .oFile .close ()
452
+ return result
453
+
454
+ with open (hdPath , "rb" ) as fd :
455
+ if raw :
456
+ return fd .read ()
457
+ else :
458
+ return S_OK (fd .read ())
422
459
423
460
##################
424
461
# Purge sandboxes
@@ -531,3 +568,12 @@ def __deleteSandboxFromExternalBackend(self, SEName, SEPFN):
531
568
except Exception :
532
569
gLogger .exception ("RM raised an exception while trying to delete a remote sandbox" )
533
570
return S_ERROR ("RM raised an exception while trying to delete a remote sandbox" )
571
+
572
+ def export_sendFile (self , filename , fileID , data = "" ):
573
+ print (filename , fileID , data )
574
+
575
+ return S_OK (filename )
576
+
577
+
578
+ class SandboxStoreHandler (SandboxStoreHandlerMixin , RequestHandler ):
579
+ pass
0 commit comments