Skip to content

Commit fee8fed

Browse files
committed
feat(transformation): unassign input sandboxes on clean/archive
1 parent 3c881d1 commit fee8fed

2 files changed

Lines changed: 68 additions & 0 deletions

File tree

src/DIRAC/TransformationSystem/Agent/TransformationCleaningAgent.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ def __init__(self, *args, **kwargs):
7171
self.pilotAgentsDB = None
7272
self.taskQueueDB = None
7373
self.storageManagementDB = None
74+
self.sandboxDB = None
7475

7576
# # transformations types
7677
self.transformationTypes = None
@@ -153,6 +154,18 @@ def initialize(self):
153154
except RuntimeError:
154155
pass
155156

157+
# SandboxMetadataDB is optional: used only to unassign a transformation's
158+
# input sandboxes at clean/archive time. A failure here must not stop the
159+
# agent — sandbox unassignment simply becomes a no-op.
160+
try:
161+
result = ObjectLoader().loadObject("WorkloadManagementSystem.DB.SandboxMetadataDB", "SandboxMetadataDB")
162+
if result["OK"]:
163+
self.sandboxDB = result["Value"](parentLogger=self.log)
164+
else:
165+
self.log.warn("Could not load SandboxMetadataDB; sandbox unassignment disabled", result["Message"])
166+
except RuntimeError as excp:
167+
self.log.warn("Could not connect to SandboxMetadataDB; sandbox unassignment disabled", str(excp))
168+
156169
return S_OK()
157170

158171
#############################################################################
@@ -514,6 +527,7 @@ def archiveTransformation(self, transID):
514527
:param int transID: transformation ID
515528
"""
516529
self.log.info(f"Archiving transformation {transID}")
530+
self._unassignTransformationSandboxes(transID)
517531
# Clean the jobs in the WMS and any failover requests found
518532
res = self.cleanTransformationTasks(transID)
519533
if not res["OK"]:
@@ -531,11 +545,28 @@ def archiveTransformation(self, transID):
531545
self.log.info(f"Updated status of transformation {transID} to Archived")
532546
return S_OK()
533547

548+
def _unassignTransformationSandboxes(self, transID):
549+
"""Best-effort removal of a transformation's input-sandbox assignment.
550+
551+
Drops the ``Transformation:<transID>`` mapping in the SandboxMetadataDB so
552+
the sandbox store cleaner can reclaim the (now unused) sandboxes. Never
553+
raises and never returns an error: a sandbox-DB problem must not block
554+
transformation cleaning.
555+
556+
:param int transID: transformation ID
557+
"""
558+
if not self.sandboxDB:
559+
return
560+
result = self.sandboxDB.unassignEntities([f"Transformation:{transID}"])
561+
if not result["OK"]:
562+
self.log.warn("Could not unassign sandboxes for transformation", f"{transID}: {result['Message']}")
563+
534564
def cleanTransformation(self, transID):
535565
"""This removes what was produced by the supplied transformation,
536566
leaving only some info and log in the transformation DB.
537567
"""
538568
self.log.info("Cleaning transformation", transID)
569+
self._unassignTransformationSandboxes(transID)
539570
res = self.getTransformationDirectories(transID)
540571
if not res["OK"]:
541572
self.log.error(
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# pylint: disable=missing-docstring
2+
from unittest.mock import MagicMock
3+
4+
from DIRAC import gLogger
5+
from DIRAC.TransformationSystem.Agent.TransformationCleaningAgent import TransformationCleaningAgent
6+
7+
8+
def _bare_agent():
9+
# Bypass AgentModule.__init__ (needs a running config); we only test the helper.
10+
agent = TransformationCleaningAgent.__new__(TransformationCleaningAgent)
11+
agent.log = gLogger.getSubLogger("test")
12+
agent.sandboxDB = None
13+
return agent
14+
15+
16+
def test_unassign_callsDBWithTransformationEntity():
17+
agent = _bare_agent()
18+
agent.sandboxDB = MagicMock()
19+
agent.sandboxDB.unassignEntities.return_value = {"OK": True, "Value": 1}
20+
21+
agent._unassignTransformationSandboxes(12345)
22+
23+
agent.sandboxDB.unassignEntities.assert_called_once_with(["Transformation:12345"])
24+
25+
26+
def test_unassign_noDBisNoop():
27+
agent = _bare_agent() # sandboxDB is None
28+
agent._unassignTransformationSandboxes(12345) # must not raise
29+
30+
31+
def test_unassign_dbErrorDoesNotRaise():
32+
agent = _bare_agent()
33+
agent.sandboxDB = MagicMock()
34+
agent.sandboxDB.unassignEntities.return_value = {"OK": False, "Message": "boom"}
35+
36+
agent._unassignTransformationSandboxes(12345)
37+
agent.sandboxDB.unassignEntities.assert_called_once_with(["Transformation:12345"])

0 commit comments

Comments
 (0)