DIRAC 9.0.0a54__py3-none-any.whl → 9.0.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. DIRAC/AccountingSystem/Client/AccountingCLI.py +0 -140
  2. DIRAC/AccountingSystem/Client/DataStoreClient.py +0 -13
  3. DIRAC/AccountingSystem/Client/Types/BaseAccountingType.py +0 -7
  4. DIRAC/AccountingSystem/ConfigTemplate.cfg +0 -5
  5. DIRAC/AccountingSystem/Service/DataStoreHandler.py +0 -72
  6. DIRAC/ConfigurationSystem/Client/Helpers/CSGlobals.py +0 -9
  7. DIRAC/ConfigurationSystem/Client/Helpers/Registry.py +34 -32
  8. DIRAC/ConfigurationSystem/Client/Helpers/Resources.py +11 -43
  9. DIRAC/ConfigurationSystem/Client/Helpers/test/Test_Helpers.py +0 -16
  10. DIRAC/ConfigurationSystem/Client/LocalConfiguration.py +14 -8
  11. DIRAC/ConfigurationSystem/Client/PathFinder.py +47 -8
  12. DIRAC/ConfigurationSystem/Client/SyncPlugins/CERNLDAPSyncPlugin.py +4 -1
  13. DIRAC/ConfigurationSystem/Client/VOMS2CSSynchronizer.py +9 -2
  14. DIRAC/ConfigurationSystem/Client/test/Test_PathFinder.py +41 -1
  15. DIRAC/ConfigurationSystem/private/RefresherBase.py +4 -2
  16. DIRAC/Core/DISET/ServiceReactor.py +11 -3
  17. DIRAC/Core/DISET/private/BaseClient.py +1 -2
  18. DIRAC/Core/DISET/private/Transports/M2SSLTransport.py +9 -7
  19. DIRAC/Core/Security/DiracX.py +12 -7
  20. DIRAC/Core/Security/IAMService.py +4 -3
  21. DIRAC/Core/Security/ProxyInfo.py +9 -5
  22. DIRAC/Core/Security/test/test_diracx_token_from_pem.py +161 -0
  23. DIRAC/Core/Tornado/Client/ClientSelector.py +4 -1
  24. DIRAC/Core/Tornado/Server/TornadoService.py +1 -1
  25. DIRAC/Core/Utilities/ClassAd/ClassAdLight.py +4 -290
  26. DIRAC/Core/Utilities/DErrno.py +5 -309
  27. DIRAC/Core/Utilities/Extensions.py +10 -1
  28. DIRAC/Core/Utilities/Graphs/GraphData.py +1 -1
  29. DIRAC/Core/Utilities/JDL.py +1 -195
  30. DIRAC/Core/Utilities/List.py +1 -124
  31. DIRAC/Core/Utilities/MySQL.py +101 -97
  32. DIRAC/Core/Utilities/Os.py +32 -1
  33. DIRAC/Core/Utilities/Platform.py +2 -107
  34. DIRAC/Core/Utilities/ReturnValues.py +7 -252
  35. DIRAC/Core/Utilities/StateMachine.py +12 -178
  36. DIRAC/Core/Utilities/TimeUtilities.py +10 -253
  37. DIRAC/Core/Utilities/test/Test_JDL.py +0 -3
  38. DIRAC/Core/Utilities/test/Test_Profiler.py +20 -20
  39. DIRAC/Core/scripts/dirac_agent.py +1 -1
  40. DIRAC/Core/scripts/dirac_apptainer_exec.py +16 -7
  41. DIRAC/Core/scripts/dirac_platform.py +1 -92
  42. DIRAC/DataManagementSystem/Agent/FTS3Agent.py +8 -7
  43. DIRAC/DataManagementSystem/Agent/RequestOperations/RemoveFile.py +7 -6
  44. DIRAC/DataManagementSystem/Client/FTS3Job.py +71 -34
  45. DIRAC/DataManagementSystem/DB/FTS3DB.py +3 -0
  46. DIRAC/DataManagementSystem/DB/FileCatalogComponents/DatasetManager/DatasetManager.py +1 -1
  47. DIRAC/DataManagementSystem/Utilities/DMSHelpers.py +6 -2
  48. DIRAC/DataManagementSystem/scripts/dirac_dms_create_moving_request.py +2 -0
  49. DIRAC/DataManagementSystem/scripts/dirac_dms_protocol_matrix.py +0 -1
  50. DIRAC/FrameworkSystem/Client/ComponentInstaller.py +4 -2
  51. DIRAC/FrameworkSystem/DB/ProxyDB.py +9 -5
  52. DIRAC/FrameworkSystem/Utilities/TokenManagementUtilities.py +3 -2
  53. DIRAC/FrameworkSystem/Utilities/diracx.py +2 -74
  54. DIRAC/FrameworkSystem/private/authorization/AuthServer.py +2 -2
  55. DIRAC/FrameworkSystem/scripts/dirac_login.py +2 -2
  56. DIRAC/FrameworkSystem/scripts/dirac_proxy_init.py +1 -1
  57. DIRAC/Interfaces/API/Dirac.py +27 -13
  58. DIRAC/Interfaces/API/DiracAdmin.py +42 -7
  59. DIRAC/Interfaces/API/Job.py +1 -0
  60. DIRAC/Interfaces/scripts/dirac_admin_allow_site.py +7 -1
  61. DIRAC/Interfaces/scripts/dirac_admin_ban_site.py +7 -1
  62. DIRAC/Interfaces/scripts/dirac_wms_job_parameters.py +0 -1
  63. DIRAC/MonitoringSystem/Client/Types/WMSHistory.py +4 -0
  64. DIRAC/MonitoringSystem/Client/WebAppClient.py +26 -0
  65. DIRAC/MonitoringSystem/ConfigTemplate.cfg +9 -0
  66. DIRAC/MonitoringSystem/DB/MonitoringDB.py +6 -25
  67. DIRAC/MonitoringSystem/Service/MonitoringHandler.py +0 -33
  68. DIRAC/MonitoringSystem/Service/WebAppHandler.py +599 -0
  69. DIRAC/MonitoringSystem/private/MainReporter.py +0 -3
  70. DIRAC/ProductionSystem/scripts/dirac_prod_get_trans.py +2 -3
  71. DIRAC/RequestManagementSystem/Agent/RequestExecutingAgent.py +8 -6
  72. DIRAC/RequestManagementSystem/ConfigTemplate.cfg +6 -6
  73. DIRAC/RequestManagementSystem/DB/test/RMSTestScenari.py +2 -0
  74. DIRAC/ResourceStatusSystem/Client/SiteStatus.py +4 -2
  75. DIRAC/ResourceStatusSystem/Command/FreeDiskSpaceCommand.py +3 -1
  76. DIRAC/ResourceStatusSystem/Utilities/CSHelpers.py +2 -31
  77. DIRAC/ResourceStatusSystem/scripts/dirac_rss_set_status.py +18 -4
  78. DIRAC/Resources/Catalog/RucioFileCatalogClient.py +1 -1
  79. DIRAC/Resources/Computing/AREXComputingElement.py +19 -3
  80. DIRAC/Resources/Computing/BatchSystems/Condor.py +126 -108
  81. DIRAC/Resources/Computing/BatchSystems/SLURM.py +5 -1
  82. DIRAC/Resources/Computing/BatchSystems/test/Test_SLURM.py +46 -0
  83. DIRAC/Resources/Computing/HTCondorCEComputingElement.py +37 -43
  84. DIRAC/Resources/Computing/SingularityComputingElement.py +6 -1
  85. DIRAC/Resources/Computing/test/Test_HTCondorCEComputingElement.py +67 -49
  86. DIRAC/Resources/Computing/test/Test_PoolComputingElement.py +2 -1
  87. DIRAC/Resources/IdProvider/CheckInIdProvider.py +13 -0
  88. DIRAC/Resources/IdProvider/IdProviderFactory.py +11 -3
  89. DIRAC/Resources/Storage/StorageBase.py +4 -2
  90. DIRAC/Resources/Storage/StorageElement.py +4 -4
  91. DIRAC/TransformationSystem/Agent/TaskManagerAgentBase.py +10 -16
  92. DIRAC/TransformationSystem/Agent/TransformationAgent.py +22 -1
  93. DIRAC/TransformationSystem/Agent/TransformationCleaningAgent.py +15 -15
  94. DIRAC/TransformationSystem/Client/Transformation.py +2 -1
  95. DIRAC/TransformationSystem/Client/TransformationClient.py +0 -7
  96. DIRAC/TransformationSystem/Client/Utilities.py +9 -0
  97. DIRAC/TransformationSystem/Service/TransformationManagerHandler.py +0 -336
  98. DIRAC/TransformationSystem/Utilities/ReplicationCLIParameters.py +3 -3
  99. DIRAC/TransformationSystem/scripts/dirac_production_runjoblocal.py +2 -4
  100. DIRAC/TransformationSystem/test/Test_replicationTransformation.py +5 -6
  101. DIRAC/Workflow/Modules/test/Test_Modules.py +5 -0
  102. DIRAC/WorkloadManagementSystem/Agent/JobAgent.py +1 -5
  103. DIRAC/WorkloadManagementSystem/Agent/JobCleaningAgent.py +11 -7
  104. DIRAC/WorkloadManagementSystem/Agent/PilotSyncAgent.py +4 -3
  105. DIRAC/WorkloadManagementSystem/Agent/PushJobAgent.py +13 -13
  106. DIRAC/WorkloadManagementSystem/Agent/SiteDirector.py +10 -13
  107. DIRAC/WorkloadManagementSystem/Agent/StalledJobAgent.py +18 -51
  108. DIRAC/WorkloadManagementSystem/Agent/StatesAccountingAgent.py +41 -1
  109. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_JobAgent.py +2 -0
  110. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_JobCleaningAgent.py +7 -9
  111. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_PushJobAgent.py +1 -0
  112. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_SiteDirector.py +8 -2
  113. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_StalledJobAgent.py +4 -5
  114. DIRAC/WorkloadManagementSystem/Client/DownloadInputData.py +7 -5
  115. DIRAC/WorkloadManagementSystem/Client/JobMonitoringClient.py +10 -11
  116. DIRAC/WorkloadManagementSystem/Client/JobState/JobManifest.py +32 -261
  117. DIRAC/WorkloadManagementSystem/Client/JobStateUpdateClient.py +3 -0
  118. DIRAC/WorkloadManagementSystem/Client/JobStatus.py +8 -152
  119. DIRAC/WorkloadManagementSystem/Client/SandboxStoreClient.py +25 -38
  120. DIRAC/WorkloadManagementSystem/Client/WMSClient.py +2 -3
  121. DIRAC/WorkloadManagementSystem/Client/test/Test_Client_DownloadInputData.py +29 -0
  122. DIRAC/WorkloadManagementSystem/ConfigTemplate.cfg +4 -8
  123. DIRAC/WorkloadManagementSystem/DB/JobDB.py +40 -69
  124. DIRAC/WorkloadManagementSystem/DB/JobDBUtils.py +18 -147
  125. DIRAC/WorkloadManagementSystem/DB/JobParametersDB.py +9 -9
  126. DIRAC/WorkloadManagementSystem/DB/PilotAgentsDB.py +3 -2
  127. DIRAC/WorkloadManagementSystem/DB/SandboxMetadataDB.py +28 -39
  128. DIRAC/WorkloadManagementSystem/DB/StatusUtils.py +125 -0
  129. DIRAC/WorkloadManagementSystem/DB/tests/Test_JobDB.py +1 -1
  130. DIRAC/WorkloadManagementSystem/DB/tests/Test_StatusUtils.py +28 -0
  131. DIRAC/WorkloadManagementSystem/Executor/JobSanity.py +3 -3
  132. DIRAC/WorkloadManagementSystem/FutureClient/JobStateUpdateClient.py +2 -14
  133. DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapper.py +14 -9
  134. DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapper.py +36 -10
  135. DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapperTemplate.py +4 -0
  136. DIRAC/WorkloadManagementSystem/Service/JobManagerHandler.py +33 -154
  137. DIRAC/WorkloadManagementSystem/Service/JobMonitoringHandler.py +5 -323
  138. DIRAC/WorkloadManagementSystem/Service/JobStateUpdateHandler.py +0 -16
  139. DIRAC/WorkloadManagementSystem/Service/PilotManagerHandler.py +6 -102
  140. DIRAC/WorkloadManagementSystem/Service/SandboxStoreHandler.py +5 -51
  141. DIRAC/WorkloadManagementSystem/Service/WMSAdministratorHandler.py +16 -79
  142. DIRAC/WorkloadManagementSystem/Utilities/JobModel.py +28 -199
  143. DIRAC/WorkloadManagementSystem/Utilities/JobParameters.py +65 -3
  144. DIRAC/WorkloadManagementSystem/Utilities/JobStatusUtility.py +2 -64
  145. DIRAC/WorkloadManagementSystem/Utilities/ParametricJob.py +7 -171
  146. DIRAC/WorkloadManagementSystem/Utilities/PilotCStoJSONSynchronizer.py +73 -7
  147. DIRAC/WorkloadManagementSystem/Utilities/PilotWrapper.py +2 -0
  148. DIRAC/WorkloadManagementSystem/Utilities/RemoteRunner.py +16 -0
  149. DIRAC/WorkloadManagementSystem/Utilities/Utils.py +36 -1
  150. DIRAC/WorkloadManagementSystem/Utilities/jobAdministration.py +15 -0
  151. DIRAC/WorkloadManagementSystem/Utilities/test/Test_JobModel.py +1 -5
  152. DIRAC/WorkloadManagementSystem/Utilities/test/Test_ParametricJob.py +45 -128
  153. DIRAC/WorkloadManagementSystem/Utilities/test/Test_PilotWrapper.py +16 -0
  154. DIRAC/__init__.py +55 -54
  155. {dirac-9.0.0a54.dist-info → dirac-9.0.7.dist-info}/METADATA +6 -4
  156. {dirac-9.0.0a54.dist-info → dirac-9.0.7.dist-info}/RECORD +160 -160
  157. {dirac-9.0.0a54.dist-info → dirac-9.0.7.dist-info}/WHEEL +1 -1
  158. {dirac-9.0.0a54.dist-info → dirac-9.0.7.dist-info}/entry_points.txt +0 -3
  159. DIRAC/Core/Utilities/test/Test_List.py +0 -150
  160. DIRAC/Core/Utilities/test/Test_Time.py +0 -88
  161. DIRAC/TransformationSystem/scripts/dirac_transformation_archive.py +0 -30
  162. DIRAC/TransformationSystem/scripts/dirac_transformation_clean.py +0 -30
  163. DIRAC/TransformationSystem/scripts/dirac_transformation_remove_output.py +0 -30
  164. DIRAC/WorkloadManagementSystem/Utilities/test/Test_JobManager.py +0 -58
  165. {dirac-9.0.0a54.dist-info → dirac-9.0.7.dist-info}/licenses/LICENSE +0 -0
  166. {dirac-9.0.0a54.dist-info → dirac-9.0.7.dist-info}/top_level.txt +0 -0
@@ -48,13 +48,6 @@ class TransformationClient(Client):
48
48
 
49
49
  getFileSummary(lfns)
50
50
  exists(lfns)
51
-
52
- Web monitoring tools
53
-
54
- getDistinctAttributeValues(attribute, selectDict)
55
- getTransformationStatusCounters()
56
- getTransformationSummary()
57
- getTransformationSummaryWeb(selectDict, sortList, startItem, maxItems)
58
51
  """
59
52
 
60
53
  def __init__(self, **kwargs):
@@ -9,6 +9,8 @@ Utilities for Transformation system
9
9
  import ast
10
10
  import random
11
11
 
12
+ from cachetools import LRUCache, cachedmethod
13
+ from cachetools.keys import hashkey
12
14
  from DIRAC import S_OK, S_ERROR, gLogger
13
15
 
14
16
  from DIRAC.Core.Utilities.List import breakListIntoChunks
@@ -22,6 +24,9 @@ from DIRAC.Resources.Catalog.FileCatalog import FileCatalog
22
24
  from DIRAC.Resources.Storage.StorageElement import StorageElement
23
25
  from DIRAC.TransformationSystem.Client.TransformationClient import TransformationClient
24
26
 
27
+ # Module-level cache for isSameSEInList method (shared across PluginUtilities instances)
28
+ _is_same_se_in_list_cache = LRUCache(maxsize=1024)
29
+
25
30
 
26
31
  class PluginUtilities:
27
32
  """
@@ -400,6 +405,10 @@ class PluginUtilities:
400
405
 
401
406
  return StorageElement(se1).isSameSE(StorageElement(se2))
402
407
 
408
+ @cachedmethod(
409
+ lambda self: _is_same_se_in_list_cache,
410
+ key=lambda _, a, b: hashkey(a, *sorted(b)),
411
+ )
403
412
  def isSameSEInList(self, se1, seList):
404
413
  """Check if an SE is the same as any in a list"""
405
414
  if se1 in seList:
@@ -3,22 +3,12 @@
3
3
  import datetime
4
4
 
5
5
  from DIRAC import S_ERROR, S_OK
6
- from DIRAC.ConfigurationSystem.Client.Helpers.Operations import Operations
7
6
  from DIRAC.Core.DISET.RequestHandler import RequestHandler
8
7
  from DIRAC.Core.Security.Properties import SecurityProperty
9
8
  from DIRAC.Core.Utilities.Decorators import deprecated
10
9
  from DIRAC.Core.Utilities.DEncode import ignoreEncodeWarning
11
10
  from DIRAC.Core.Utilities.JEncode import encode as jencode
12
11
  from DIRAC.Core.Utilities.ObjectLoader import ObjectLoader
13
- from DIRAC.RequestManagementSystem.Client.Operation import Operation
14
- from DIRAC.RequestManagementSystem.Client.Request import Request
15
- from DIRAC.TransformationSystem.Client import TransformationFilesStatus
16
- from DIRAC.WorkloadManagementSystem.Client import JobStatus
17
-
18
- TASKS_STATE_NAMES = ["TotalCreated", "Created"] + sorted(
19
- set(JobStatus.JOB_STATES) | set(Request.ALL_STATES) | set(Operation.ALL_STATES)
20
- )
21
- FILES_STATE_NAMES = ["PercentProcessed", "Total"] + TransformationFilesStatus.TRANSFORMATION_FILES_STATES
22
12
 
23
13
 
24
14
  class TransformationManagerHandlerMixin:
@@ -530,39 +520,12 @@ class TransformationManagerHandlerMixin:
530
520
  """Set metadata to a file or to a directory (path)"""
531
521
  return cls.transformationDB.setMetadata(path, querydict)
532
522
 
533
- ####################################################################
534
- #
535
- # These are the methods used for web monitoring
536
- #
537
-
538
- # TODO Get rid of this (talk to Matvey)
539
- types_getDistinctAttributeValues = [str, dict]
540
-
541
- @classmethod
542
- def export_getDistinctAttributeValues(cls, attribute, selectDict):
543
- res = cls.transformationDB.getTableDistinctAttributeValues("Transformations", [attribute], selectDict)
544
- if not res["OK"]:
545
- return res
546
- return S_OK(res["Value"][attribute])
547
-
548
523
  types_getTableDistinctAttributeValues = [str, list, dict]
549
524
 
550
525
  @classmethod
551
526
  def export_getTableDistinctAttributeValues(cls, table, attributes, selectDict):
552
527
  return cls.transformationDB.getTableDistinctAttributeValues(table, attributes, selectDict)
553
528
 
554
- types_getTransformationStatusCounters = []
555
-
556
- @classmethod
557
- def export_getTransformationStatusCounters(cls):
558
- res = cls.transformationDB.getCounters("Transformations", ["Status"], {})
559
- if not res["OK"]:
560
- return res
561
- statDict = {}
562
- for attrDict, count in res["Value"]:
563
- statDict[attrDict["Status"]] = count
564
- return S_OK(statDict)
565
-
566
529
  types_getTransformationSummary = []
567
530
 
568
531
  def export_getTransformationSummary(self):
@@ -587,305 +550,6 @@ class TransformationManagerHandlerMixin:
587
550
  resultDict[transID] = transDict
588
551
  return S_OK(resultDict)
589
552
 
590
- types_getTabbedSummaryWeb = [str, dict, dict, list, int, int]
591
-
592
- def export_getTabbedSummaryWeb(self, table, requestedTables, selectDict, sortList, startItem, maxItems):
593
- tableDestinations = {
594
- "Transformations": {
595
- "TransformationFiles": ["TransformationID"],
596
- "TransformationTasks": ["TransformationID"],
597
- },
598
- "TransformationFiles": {
599
- "Transformations": ["TransformationID"],
600
- "TransformationTasks": ["TransformationID", "TaskID"],
601
- },
602
- "TransformationTasks": {
603
- "Transformations": ["TransformationID"],
604
- "TransformationFiles": ["TransformationID", "TaskID"],
605
- },
606
- }
607
-
608
- tableSelections = {
609
- "Transformations": ["TransformationID", "AgentType", "Type", "TransformationGroup", "Plugin"],
610
- "TransformationFiles": ["TransformationID", "TaskID", "Status", "UsedSE", "TargetSE"],
611
- "TransformationTasks": ["TransformationID", "TaskID", "ExternalStatus", "TargetSE"],
612
- }
613
-
614
- tableTimeStamps = {
615
- "Transformations": "CreationDate",
616
- "TransformationFiles": "LastUpdate",
617
- "TransformationTasks": "CreationTime",
618
- }
619
-
620
- tableStatusColumn = {
621
- "Transformations": "Status",
622
- "TransformationFiles": "Status",
623
- "TransformationTasks": "ExternalStatus",
624
- }
625
-
626
- resDict = {}
627
- res = self.__getTableSummaryWeb(
628
- table,
629
- selectDict,
630
- sortList,
631
- startItem,
632
- maxItems,
633
- selectColumns=tableSelections[table],
634
- timeStamp=tableTimeStamps[table],
635
- statusColumn=tableStatusColumn[table],
636
- )
637
- if not res["OK"]:
638
- self.log.error("Failed to get Summary for table", f"{table} {res['Message']}")
639
- return res
640
- resDict[table] = res["Value"]
641
- selections = res["Value"]["Selections"]
642
- tableSelection = {}
643
- for destination in tableDestinations[table].keys():
644
- tableSelection[destination] = {}
645
- for parameter in tableDestinations[table][destination]:
646
- tableSelection[destination][parameter] = selections.get(parameter, [])
647
-
648
- for table, paramDict in requestedTables.items():
649
- sortList = paramDict.get("SortList", [])
650
- startItem = paramDict.get("StartItem", 0)
651
- maxItems = paramDict.get("MaxItems", 50)
652
- res = self.__getTableSummaryWeb(
653
- table,
654
- tableSelection[table],
655
- sortList,
656
- startItem,
657
- maxItems,
658
- selectColumns=tableSelections[table],
659
- timeStamp=tableTimeStamps[table],
660
- statusColumn=tableStatusColumn[table],
661
- )
662
- if not res["OK"]:
663
- self.log.error("Failed to get Summary for table", f"{table} {res['Message']}")
664
- return res
665
- resDict[table] = res["Value"]
666
- return S_OK(resDict)
667
-
668
- types_getTransformationsSummaryWeb = [dict, list, int, int]
669
-
670
- def export_getTransformationsSummaryWeb(self, selectDict, sortList, startItem, maxItems):
671
- return self.__getTableSummaryWeb(
672
- "Transformations",
673
- selectDict,
674
- sortList,
675
- startItem,
676
- maxItems,
677
- selectColumns=["TransformationID", "AgentType", "Type", "Group", "Plugin"],
678
- timeStamp="CreationDate",
679
- statusColumn="Status",
680
- )
681
-
682
- types_getTransformationTasksSummaryWeb = [dict, list, int, int]
683
-
684
- def export_getTransformationTasksSummaryWeb(self, selectDict, sortList, startItem, maxItems):
685
- return self.__getTableSummaryWeb(
686
- "TransformationTasks",
687
- selectDict,
688
- sortList,
689
- startItem,
690
- maxItems,
691
- selectColumns=["TransformationID", "ExternalStatus", "TargetSE"],
692
- timeStamp="CreationTime",
693
- statusColumn="ExternalStatus",
694
- )
695
-
696
- types_getTransformationFilesSummaryWeb = [dict, list, int, int]
697
-
698
- def export_getTransformationFilesSummaryWeb(self, selectDict, sortList, startItem, maxItems):
699
- return self.__getTableSummaryWeb(
700
- "TransformationFiles",
701
- selectDict,
702
- sortList,
703
- startItem,
704
- maxItems,
705
- selectColumns=["TransformationID", "Status", "UsedSE", "TargetSE"],
706
- timeStamp="LastUpdate",
707
- statusColumn="Status",
708
- )
709
-
710
- def __getTableSummaryWeb(
711
- self, table, selectDict, sortList, startItem, maxItems, selectColumns=[], timeStamp=None, statusColumn="Status"
712
- ):
713
- fromDate = selectDict.get("FromDate", None)
714
- if fromDate:
715
- del selectDict["FromDate"]
716
- # if not fromDate:
717
- # fromDate = last_update
718
- toDate = selectDict.get("ToDate", None)
719
- if toDate:
720
- del selectDict["ToDate"]
721
- # Sorting instructions. Only one for the moment.
722
- if sortList:
723
- orderAttribute = sortList[0][0] + ":" + sortList[0][1]
724
- else:
725
- orderAttribute = None
726
- # Get the columns that match the selection
727
- fcn = None
728
- fcnName = f"get{table}"
729
- if hasattr(self.transformationDB, fcnName) and callable(getattr(self.transformationDB, fcnName)):
730
- fcn = getattr(self.transformationDB, fcnName)
731
- if not fcn:
732
- return S_ERROR(f"Unable to invoke gTransformationDB.{fcnName}, it isn't a member function")
733
- res = fcn(condDict=selectDict, older=toDate, newer=fromDate, timeStamp=timeStamp, orderAttribute=orderAttribute)
734
- if not res["OK"]:
735
- return res
736
-
737
- # The full list of columns in contained here
738
- allRows = res["Value"]
739
- # Prepare the standard structure now within the resultDict dictionary
740
- resultDict = {}
741
- # Create the total records entry
742
- resultDict["TotalRecords"] = len(allRows)
743
-
744
- # Get the rows which are within the selected window
745
- if resultDict["TotalRecords"] == 0:
746
- return S_OK(resultDict)
747
- ini = startItem
748
- last = ini + maxItems
749
- if ini >= resultDict["TotalRecords"]:
750
- return S_ERROR("Item number out of range")
751
- if last > resultDict["TotalRecords"]:
752
- last = resultDict["TotalRecords"]
753
-
754
- selectedRows = allRows[ini:last]
755
- resultDict["Records"] = []
756
- for row in selectedRows:
757
- resultDict["Records"].append(list(row.values()))
758
-
759
- # Create the ParameterNames entry
760
- resultDict["ParameterNames"] = list(selectedRows[0].keys())
761
- # Find which element in the tuple contains the requested status
762
- if statusColumn not in resultDict["ParameterNames"]:
763
- return S_ERROR("Provided status column not present")
764
-
765
- # Generate the status dictionary
766
- statusDict = {}
767
- for row in selectedRows:
768
- status = row[statusColumn]
769
- statusDict[status] = statusDict.setdefault(status, 0) + 1
770
- resultDict["Extras"] = statusDict
771
-
772
- # Obtain the distinct values of the selection parameters
773
- res = self.transformationDB.getTableDistinctAttributeValues(
774
- table, selectColumns, selectDict, older=toDate, newer=fromDate
775
- )
776
- distinctSelections = zip(selectColumns, [])
777
- if res["OK"]:
778
- distinctSelections = res["Value"]
779
- resultDict["Selections"] = distinctSelections
780
-
781
- return S_OK(resultDict)
782
-
783
- types_getTransformationSummaryWeb = [dict, list, int, int]
784
-
785
- def export_getTransformationSummaryWeb(self, selectDict, sortList, startItem, maxItems):
786
- """Get the summary of the transformation information for a given page in the generic format"""
787
-
788
- # Obtain the timing information from the selectDict
789
- last_update = selectDict.get("CreationDate", None)
790
- if last_update:
791
- del selectDict["CreationDate"]
792
- fromDate = selectDict.get("FromDate", None)
793
- if fromDate:
794
- del selectDict["FromDate"]
795
- if not fromDate:
796
- fromDate = last_update
797
- toDate = selectDict.get("ToDate", None)
798
- if toDate:
799
- del selectDict["ToDate"]
800
- # Sorting instructions. Only one for the moment.
801
- if sortList:
802
- orderAttribute = []
803
- for i in sortList:
804
- orderAttribute += [i[0] + ":" + i[1]]
805
- else:
806
- orderAttribute = None
807
-
808
- # Get the transformations that match the selection
809
- res = self.transformationDB.getTransformations(
810
- condDict=selectDict, older=toDate, newer=fromDate, orderAttribute=orderAttribute
811
- )
812
- if not res["OK"]:
813
- return res
814
-
815
- ops = Operations()
816
- # Prepare the standard structure now within the resultDict dictionary
817
- resultDict = {}
818
- trList = res["Records"]
819
- # Create the total records entry
820
- nTrans = len(trList)
821
- resultDict["TotalRecords"] = nTrans
822
- # Create the ParameterNames entry
823
- # As this list is a reference to the list in the DB, we cannot extend it, therefore copy it
824
- resultDict["ParameterNames"] = list(res["ParameterNames"])
825
- # Add the job states to the ParameterNames entry
826
- taskStateNames = TASKS_STATE_NAMES + ops.getValue("Transformations/AdditionalTaskStates", [])
827
- resultDict["ParameterNames"] += ["Jobs_" + x for x in taskStateNames]
828
- # Add the file states to the ParameterNames entry
829
- fileStateNames = FILES_STATE_NAMES + ops.getValue("Transformations/AdditionalFileStates", [])
830
- resultDict["ParameterNames"] += ["Files_" + x for x in fileStateNames]
831
-
832
- # Get the transformations which are within the selected window
833
- if nTrans == 0:
834
- return S_OK(resultDict)
835
- ini = startItem
836
- last = ini + maxItems
837
- if ini >= nTrans:
838
- return S_ERROR("Item number out of range")
839
- if last > nTrans:
840
- last = nTrans
841
- transList = trList[ini:last]
842
-
843
- statusDict = {}
844
- extendableTranfs = ops.getValue("Transformations/ExtendableTransfTypes", ["Simulation", "MCsimulation"])
845
- givenUpFileStatus = ops.getValue("Transformations/GivenUpFileStatus", ["MissingInFC"])
846
- problematicStatuses = ops.getValue("Transformations/ProblematicStatuses", ["Problematic"])
847
- # Add specific information for each selected transformation
848
- for trans in transList:
849
- transDict = dict(zip(resultDict["ParameterNames"], trans))
850
-
851
- # Update the status counters
852
- status = transDict["Status"]
853
- statusDict[status] = statusDict.setdefault(status, 0) + 1
854
-
855
- # Get the statistics on the number of jobs for the transformation
856
- transID = transDict["TransformationID"]
857
- res = self.transformationDB.getTransformationTaskStats(transID)
858
- taskDict = {}
859
- if res["OK"] and res["Value"]:
860
- taskDict = res["Value"]
861
- for state in taskStateNames:
862
- trans.append(taskDict.get(state, 0))
863
-
864
- # Get the statistics for the number of files for the transformation
865
- fileDict = {}
866
- transType = transDict["Type"]
867
- if transType.lower() in extendableTranfs:
868
- fileDict["PercentProcessed"] = "-"
869
- else:
870
- res = self.transformationDB.getTransformationStats(transID)
871
- if res["OK"]:
872
- fileDict = res["Value"]
873
- total = fileDict["Total"]
874
- for stat in givenUpFileStatus:
875
- total -= fileDict.get(stat, 0)
876
- processed = fileDict.get(TransformationFilesStatus.PROCESSED, 0)
877
- fileDict["PercentProcessed"] = f"{int(processed * 1000.0 / total) / 10.0:.1f}" if total else 0.0
878
- problematic = 0
879
- for stat in problematicStatuses:
880
- problematic += fileDict.get(stat, 0)
881
- fileDict["Problematic"] = problematic
882
- for state in fileStateNames:
883
- trans.append(fileDict.get(state, 0))
884
-
885
- resultDict["Records"] = transList
886
- resultDict["Extras"] = statusDict
887
- return S_OK(resultDict)
888
-
889
553
 
890
554
  class TransformationManagerHandler(TransformationManagerHandlerMixin, RequestHandler):
891
555
  pass
@@ -1,10 +1,10 @@
1
1
  """
2
2
  Command Line Parameters for creating the Replication transformations Script
3
3
  """
4
- from DIRAC import S_OK, S_ERROR, gLogger
4
+ from DIRAC import S_ERROR, S_OK, gLogger
5
+ from DIRAC.ConfigurationSystem.Client.Helpers.Registry import getVOForGroup
5
6
  from DIRAC.Core.Security.Properties import SecurityProperty
6
7
  from DIRAC.Core.Security.ProxyInfo import getProxyInfo
7
- from DIRAC.ConfigurationSystem.Client.Helpers.Registry import getVOMSVOForGroup
8
8
 
9
9
 
10
10
  class Params:
@@ -144,7 +144,7 @@ class Params:
144
144
  return False
145
145
  proxyValues = proxyInfo.get("Value", {})
146
146
  group = proxyValues.get("group", "")
147
- vomsvo = getVOMSVOForGroup(group)
147
+ vomsvo = getVOForGroup(group)
148
148
  if not vomsvo:
149
149
  self.errorMessages.append("ERROR: ProxyGroup not associated to VOMS VO, get a different proxy")
150
150
  return False
@@ -16,7 +16,7 @@ from urllib.request import urlopen
16
16
  from DIRAC.Interfaces.API.Dirac import Dirac
17
17
  from DIRAC.Core.Utilities.File import mkDir
18
18
  from DIRAC.Core.Base.Script import Script
19
- from DIRAC.ConfigurationSystem.Client.Helpers.CSGlobals import getVO, getSetup
19
+ from DIRAC.ConfigurationSystem.Client.Helpers.CSGlobals import getVO
20
20
  from DIRAC.ConfigurationSystem.Client.ConfigurationData import gConfigurationData
21
21
 
22
22
 
@@ -79,14 +79,12 @@ def __configurePilot(basepath, vo):
79
79
  This method was created specifically for LHCb pilots, more info
80
80
  about othe VOs is needed to make it more general.
81
81
  """
82
- currentSetup = getSetup()
83
82
  masterCS = gConfigurationData.getMasterServer()
84
83
 
85
84
  os.system(
86
85
  "python "
87
86
  + basepath
88
- + "dirac-pilot.py -S %s -l %s -C %s -N ce.debug.ch -Q default -n DIRAC.JobDebugger.ch -dd"
89
- % (currentSetup, vo, masterCS)
87
+ + f"dirac-pilot.py -l {vo} -C {masterCS} -N ce.debug.ch -Q default -n DIRAC.JobDebugger.ch -dd"
90
88
  )
91
89
 
92
90
  diracdir = os.path.expanduser("~") + os.path.sep
@@ -1,14 +1,13 @@
1
1
  """Test the dirac-transformation-replication script and helper"""
2
2
  import unittest
3
+ from unittest.mock import MagicMock as Mock
4
+ from unittest.mock import patch
3
5
 
4
- from unittest.mock import MagicMock as Mock, patch
5
-
6
- from DIRAC import S_OK, S_ERROR
7
-
8
- from DIRAC.TransformationSystem.Utilities.ReplicationTransformation import createDataTransformation
6
+ from DIRAC import S_ERROR, S_OK
9
7
  from DIRAC.TransformationSystem.Utilities.ReplicationCLIParameters import Params
8
+ from DIRAC.TransformationSystem.Utilities.ReplicationTransformation import createDataTransformation
10
9
 
11
- GET_VOMS = "DIRAC.TransformationSystem.Utilities.ReplicationCLIParameters.getVOMSVOForGroup"
10
+ GET_VOMS = "DIRAC.TransformationSystem.Utilities.ReplicationCLIParameters.getVOForGroup"
12
11
  GET_PROXY = "DIRAC.TransformationSystem.Utilities.ReplicationCLIParameters.getProxyInfo"
13
12
 
14
13
 
@@ -5,6 +5,8 @@ import os
5
5
  import copy
6
6
  import shutil
7
7
 
8
+ import pytest
9
+
8
10
  from unittest.mock import MagicMock as Mock
9
11
 
10
12
  from DIRAC import gLogger
@@ -742,6 +744,7 @@ class FailoverRequestSuccess(ModulesTestCase):
742
744
  class ScriptSuccess(ModulesTestCase):
743
745
  #################################################
744
746
 
747
+ @pytest.mark.slow
745
748
  def test_execute(self):
746
749
  self.script.jobType = "merge"
747
750
  self.script.stepInputData = ["foo", "bar"]
@@ -770,6 +773,7 @@ class ScriptSuccess(ModulesTestCase):
770
773
  class ScriptUnicode(ModulesTestCase):
771
774
  #################################################
772
775
 
776
+ @pytest.mark.slow
773
777
  def test_execute(self):
774
778
  self.script.jobType = "merge"
775
779
  self.script.stepInputData = ["foo", "bar"]
@@ -799,6 +803,7 @@ class ScriptUnicode(ModulesTestCase):
799
803
  class ScriptFailure(ModulesTestCase):
800
804
  #################################################
801
805
 
806
+ @pytest.mark.slow
802
807
  def test_execute(self):
803
808
  self.script.jobType = "merge"
804
809
  self.script.stepInputData = ["foo", "bar"]
@@ -236,7 +236,6 @@ class JobAgent(AgentModule):
236
236
  jobGroup = matcherInfo["Group"]
237
237
  owner = matcherInfo["Owner"]
238
238
  ceDict = matcherInfo["CEDict"]
239
- matchTime = matcherInfo["matchTime"]
240
239
 
241
240
  optimizerParams = {}
242
241
  for key in matcherInfo:
@@ -263,9 +262,6 @@ class JobAgent(AgentModule):
263
262
  self.log.verbose("Job request successful: \n", jobRequest["Value"])
264
263
  self.log.info("Received", f"JobID={jobID}, JobType={jobType}, Owner={owner}, JobGroup={jobGroup}")
265
264
  self.jobCount += 1
266
- self.jobs[jobID]["JobReport"].setJobParameter(
267
- par_name="MatcherServiceTime", par_value=str(matchTime), sendFlag=False
268
- )
269
265
 
270
266
  self.jobs[jobID]["JobReport"].setJobStatus(minorStatus="Job Received by Agent", sendFlag=False)
271
267
  result_setupProxy = self._setupProxy(owner, jobGroup)
@@ -547,7 +543,7 @@ class JobAgent(AgentModule):
547
543
  jobRequest = MatcherClient().requestJob(ceDict)
548
544
  matchTime = time.time() - start
549
545
 
550
- self.log.info("MatcherTime", f"= {matchTime:.2f} (s)")
546
+ self.log.verbose("MatcherTime", f"= {matchTime:.2f} (s)")
551
547
  if jobRequest["OK"]:
552
548
  jobRequest["Value"]["matchTime"] = matchTime
553
549
  jobRequest["Value"]["CEDict"] = ceDict
@@ -35,10 +35,12 @@ from DIRAC.RequestManagementSystem.Client.Operation import Operation
35
35
  from DIRAC.RequestManagementSystem.Client.ReqClient import ReqClient
36
36
  from DIRAC.RequestManagementSystem.Client.Request import Request
37
37
  from DIRAC.WorkloadManagementSystem.Client import JobStatus
38
- from DIRAC.WorkloadManagementSystem.Client.JobMonitoringClient import JobMonitoringClient
39
- from DIRAC.WorkloadManagementSystem.Client.SandboxStoreClient import SandboxStoreClient
40
38
  from DIRAC.WorkloadManagementSystem.Client.WMSClient import WMSClient
41
39
  from DIRAC.WorkloadManagementSystem.DB.JobDB import JobDB
40
+ from DIRAC.WorkloadManagementSystem.DB.SandboxMetadataDB import SandboxMetadataDB
41
+ from DIRAC.WorkloadManagementSystem.Service.JobPolicy import RIGHT_DELETE
42
+ from DIRAC.WorkloadManagementSystem.DB.StatusUtils import kill_delete_jobs
43
+ from DIRAC.WorkloadManagementSystem.Utilities.JobParameters import getJobParameters
42
44
 
43
45
 
44
46
  class JobCleaningAgent(AgentModule):
@@ -152,8 +154,9 @@ class JobCleaningAgent(AgentModule):
152
154
  return S_OK()
153
155
 
154
156
  self.log.info("Unassigning sandboxes from soon to be deleted jobs", f"({len(jobList)})")
155
- result = SandboxStoreClient(useCertificates=True).unassignJobs(jobList)
156
- if not result["OK"]:
157
+
158
+ entitiesList = [f"Job:{jobId}" for jobId in jobList]
159
+ if not (result := SandboxMetadataDB().unassignEntities(entitiesList))["OK"]:
157
160
  self.log.error("Cannot unassign jobs to sandboxes", result["Message"])
158
161
  return result
159
162
 
@@ -229,11 +232,11 @@ class JobCleaningAgent(AgentModule):
229
232
  if not res["OK"]:
230
233
  self.log.error("No DN found", f"for {user}")
231
234
  return res
232
- wmsClient = WMSClient(useCertificates=True, delegatedDN=res["Value"][0], delegatedGroup=ownerGroup)
233
235
  if remove:
236
+ wmsClient = WMSClient(useCertificates=True, delegatedDN=res["Value"][0], delegatedGroup=ownerGroup)
234
237
  result = wmsClient.removeJob(jobsList)
235
238
  else:
236
- result = wmsClient.deleteJob(jobsList)
239
+ result = kill_delete_jobs(RIGHT_DELETE, jobsList)
237
240
  if not result["OK"]:
238
241
  self.log.error(
239
242
  f"Could not {'remove' if remove else 'delete'} jobs",
@@ -293,7 +296,8 @@ class JobCleaningAgent(AgentModule):
293
296
  failed = {}
294
297
  successful = {}
295
298
 
296
- result = JobMonitoringClient().getJobParameters(jobIDList, ["OutputSandboxLFN"])
299
+ jobIDs = [int(jobID) for jobID in jobIDList]
300
+ result = getJobParameters(jobIDs, "OutputSandboxLFN")
297
301
  if not result["OK"]:
298
302
  return result
299
303
  osLFNDict = result["Value"]
@@ -1,4 +1,4 @@
1
- """ This agent syncs CS and pilot files to a web server of your choice
1
+ """This agent syncs CS and pilot files to a web server of your choice
2
2
 
3
3
  .. literalinclude:: ../ConfigTemplate.cfg
4
4
  :start-after: ##BEGIN PilotSyncAgent
@@ -7,6 +7,7 @@
7
7
  :caption: PilotsSyncAgent options
8
8
 
9
9
  """
10
+
10
11
  import os
11
12
  import json
12
13
  import shutil
@@ -38,8 +39,8 @@ class PilotSyncAgent(AgentModule):
38
39
  self.workingDirectory = self.am_getOption("WorkDirectory")
39
40
  self.saveDir = self.am_getOption("SaveDirectory", self.saveDir)
40
41
  self.uploadLocations = self.am_getOption("UploadLocations", self.uploadLocations)
41
- includeMasterCS = self.am_getOption("IncludeMasterCS", self.includeMasterCS)
42
- if isinstance(includeMasterCS, str) and includeMasterCS.lower() in ["n", "no", "false"]:
42
+ self.includeMasterCS = self.am_getOption("IncludeMasterCS", self.includeMasterCS)
43
+ if isinstance(self.includeMasterCS, str) and self.includeMasterCS.lower() in ["n", "no", "false"]:
43
44
  self.includeMasterCS = False
44
45
 
45
46
  self.certAndKeyLocation = getHostCertificateAndKeyLocation()