DIRAC 9.0.0a42__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 (236) 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 +38 -26
  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 +32 -19
  14. DIRAC/ConfigurationSystem/Client/test/Test_PathFinder.py +41 -1
  15. DIRAC/ConfigurationSystem/private/RefresherBase.py +4 -2
  16. DIRAC/Core/Base/API.py +4 -7
  17. DIRAC/Core/Base/SQLAlchemyDB.py +1 -0
  18. DIRAC/Core/DISET/ServiceReactor.py +11 -3
  19. DIRAC/Core/DISET/private/BaseClient.py +1 -2
  20. DIRAC/Core/DISET/private/Transports/M2SSLTransport.py +9 -7
  21. DIRAC/Core/DISET/private/Transports/SSL/M2Utils.py +3 -1
  22. DIRAC/Core/LCG/GOCDBClient.py +5 -7
  23. DIRAC/Core/Security/DiracX.py +31 -17
  24. DIRAC/Core/Security/IAMService.py +5 -10
  25. DIRAC/Core/Security/Locations.py +27 -18
  26. DIRAC/Core/Security/ProxyInfo.py +9 -5
  27. DIRAC/Core/Security/VOMSService.py +2 -4
  28. DIRAC/Core/Security/m2crypto/X509Certificate.py +4 -6
  29. DIRAC/Core/Security/m2crypto/asn1_utils.py +17 -5
  30. DIRAC/Core/Security/test/test_diracx_token_from_pem.py +161 -0
  31. DIRAC/Core/Tornado/Client/ClientSelector.py +4 -1
  32. DIRAC/Core/Tornado/Server/TornadoService.py +1 -1
  33. DIRAC/Core/Utilities/CGroups2.py +328 -0
  34. DIRAC/Core/Utilities/ClassAd/ClassAdLight.py +4 -290
  35. DIRAC/Core/Utilities/DErrno.py +5 -309
  36. DIRAC/Core/Utilities/Extensions.py +10 -1
  37. DIRAC/Core/Utilities/File.py +1 -1
  38. DIRAC/Core/Utilities/Graphs/GraphData.py +1 -1
  39. DIRAC/Core/Utilities/Graphs/GraphUtilities.py +6 -1
  40. DIRAC/Core/Utilities/JDL.py +1 -195
  41. DIRAC/Core/Utilities/List.py +1 -124
  42. DIRAC/Core/Utilities/MySQL.py +103 -99
  43. DIRAC/Core/Utilities/Os.py +32 -1
  44. DIRAC/Core/Utilities/Platform.py +2 -107
  45. DIRAC/Core/Utilities/Proxy.py +0 -4
  46. DIRAC/Core/Utilities/ReturnValues.py +7 -252
  47. DIRAC/Core/Utilities/StateMachine.py +12 -178
  48. DIRAC/Core/Utilities/Subprocess.py +35 -14
  49. DIRAC/Core/Utilities/TimeUtilities.py +10 -253
  50. DIRAC/Core/Utilities/test/Test_JDL.py +0 -3
  51. DIRAC/Core/Utilities/test/Test_Profiler.py +20 -20
  52. DIRAC/Core/scripts/dirac_agent.py +1 -1
  53. DIRAC/Core/scripts/dirac_apptainer_exec.py +72 -46
  54. DIRAC/Core/scripts/dirac_configure.py +1 -3
  55. DIRAC/Core/scripts/dirac_install_db.py +24 -6
  56. DIRAC/Core/scripts/dirac_platform.py +1 -92
  57. DIRAC/DataManagementSystem/Agent/FTS3Agent.py +8 -7
  58. DIRAC/DataManagementSystem/Agent/RequestOperations/RemoveFile.py +7 -6
  59. DIRAC/DataManagementSystem/Client/FTS3Job.py +71 -34
  60. DIRAC/DataManagementSystem/DB/FTS3DB.py +7 -3
  61. DIRAC/DataManagementSystem/DB/FileCatalogComponents/DatasetManager/DatasetManager.py +1 -1
  62. DIRAC/DataManagementSystem/DB/FileCatalogDB.sql +9 -9
  63. DIRAC/DataManagementSystem/DB/FileCatalogWithFkAndPsDB.sql +9 -9
  64. DIRAC/DataManagementSystem/Utilities/DMSHelpers.py +6 -2
  65. DIRAC/DataManagementSystem/scripts/dirac_admin_allow_se.py +13 -8
  66. DIRAC/DataManagementSystem/scripts/dirac_admin_ban_se.py +13 -8
  67. DIRAC/DataManagementSystem/scripts/dirac_dms_create_moving_request.py +2 -0
  68. DIRAC/DataManagementSystem/scripts/dirac_dms_protocol_matrix.py +0 -1
  69. DIRAC/FrameworkSystem/Client/BundleDeliveryClient.py +2 -7
  70. DIRAC/FrameworkSystem/Client/ComponentInstaller.py +9 -4
  71. DIRAC/FrameworkSystem/Client/ProxyManagerClient.py +5 -2
  72. DIRAC/FrameworkSystem/Client/SystemAdministratorClientCLI.py +11 -6
  73. DIRAC/FrameworkSystem/ConfigTemplate.cfg +2 -0
  74. DIRAC/FrameworkSystem/DB/AuthDB.py +3 -3
  75. DIRAC/FrameworkSystem/DB/InstalledComponentsDB.py +4 -4
  76. DIRAC/FrameworkSystem/DB/ProxyDB.py +11 -3
  77. DIRAC/FrameworkSystem/DB/TokenDB.py +1 -1
  78. DIRAC/FrameworkSystem/Service/ProxyManagerHandler.py +8 -6
  79. DIRAC/FrameworkSystem/Utilities/MonitoringUtilities.py +2 -19
  80. DIRAC/FrameworkSystem/Utilities/TokenManagementUtilities.py +3 -2
  81. DIRAC/FrameworkSystem/Utilities/diracx.py +36 -14
  82. DIRAC/FrameworkSystem/private/authorization/AuthServer.py +2 -2
  83. DIRAC/FrameworkSystem/scripts/dirac_admin_update_pilot.py +18 -11
  84. DIRAC/FrameworkSystem/scripts/dirac_login.py +2 -2
  85. DIRAC/FrameworkSystem/scripts/dirac_proxy_init.py +7 -8
  86. DIRAC/Interfaces/API/Dirac.py +27 -15
  87. DIRAC/Interfaces/API/DiracAdmin.py +45 -17
  88. DIRAC/Interfaces/API/Job.py +9 -13
  89. DIRAC/Interfaces/scripts/dirac_admin_allow_site.py +12 -18
  90. DIRAC/Interfaces/scripts/dirac_admin_ban_site.py +12 -10
  91. DIRAC/Interfaces/scripts/dirac_admin_get_site_mask.py +4 -13
  92. DIRAC/Interfaces/scripts/dirac_admin_reset_job.py +3 -6
  93. DIRAC/Interfaces/scripts/dirac_wms_job_parameters.py +0 -1
  94. DIRAC/MonitoringSystem/Client/Types/WMSHistory.py +4 -0
  95. DIRAC/MonitoringSystem/Client/WebAppClient.py +26 -0
  96. DIRAC/MonitoringSystem/ConfigTemplate.cfg +9 -0
  97. DIRAC/MonitoringSystem/DB/MonitoringDB.py +6 -25
  98. DIRAC/MonitoringSystem/Service/MonitoringHandler.py +0 -33
  99. DIRAC/MonitoringSystem/Service/WebAppHandler.py +599 -0
  100. DIRAC/MonitoringSystem/private/MainReporter.py +0 -3
  101. DIRAC/ProductionSystem/DB/ProductionDB.sql +4 -4
  102. DIRAC/ProductionSystem/scripts/dirac_prod_get.py +2 -2
  103. DIRAC/ProductionSystem/scripts/dirac_prod_get_all.py +2 -2
  104. DIRAC/ProductionSystem/scripts/dirac_prod_get_trans.py +2 -3
  105. DIRAC/RequestManagementSystem/Agent/RequestExecutingAgent.py +8 -6
  106. DIRAC/RequestManagementSystem/Agent/RequestOperations/ForwardDISET.py +2 -14
  107. DIRAC/RequestManagementSystem/Client/ReqClient.py +66 -13
  108. DIRAC/RequestManagementSystem/ConfigTemplate.cfg +6 -6
  109. DIRAC/RequestManagementSystem/DB/RequestDB.py +10 -5
  110. DIRAC/RequestManagementSystem/DB/test/RMSTestScenari.py +2 -0
  111. DIRAC/RequestManagementSystem/private/RequestValidator.py +40 -46
  112. DIRAC/ResourceStatusSystem/Client/SiteStatus.py +4 -2
  113. DIRAC/ResourceStatusSystem/Command/FreeDiskSpaceCommand.py +3 -1
  114. DIRAC/ResourceStatusSystem/DB/ResourceManagementDB.py +8 -8
  115. DIRAC/ResourceStatusSystem/DB/ResourceStatusDB.py +2 -2
  116. DIRAC/ResourceStatusSystem/Utilities/CSHelpers.py +2 -31
  117. DIRAC/ResourceStatusSystem/scripts/dirac_rss_set_status.py +30 -12
  118. DIRAC/Resources/Catalog/RucioFileCatalogClient.py +195 -1
  119. DIRAC/Resources/Catalog/test/Test_RucioFileCatalogClient.py +181 -0
  120. DIRAC/Resources/Computing/AREXComputingElement.py +25 -8
  121. DIRAC/Resources/Computing/BatchSystems/Condor.py +126 -108
  122. DIRAC/Resources/Computing/BatchSystems/SLURM.py +5 -1
  123. DIRAC/Resources/Computing/BatchSystems/test/Test_SLURM.py +46 -0
  124. DIRAC/Resources/Computing/ComputingElement.py +1 -1
  125. DIRAC/Resources/Computing/HTCondorCEComputingElement.py +44 -44
  126. DIRAC/Resources/Computing/InProcessComputingElement.py +4 -2
  127. DIRAC/Resources/Computing/LocalComputingElement.py +1 -18
  128. DIRAC/Resources/Computing/SSHBatchComputingElement.py +1 -17
  129. DIRAC/Resources/Computing/SSHComputingElement.py +1 -18
  130. DIRAC/Resources/Computing/SingularityComputingElement.py +19 -5
  131. DIRAC/Resources/Computing/test/Test_HTCondorCEComputingElement.py +67 -49
  132. DIRAC/Resources/Computing/test/Test_PoolComputingElement.py +2 -1
  133. DIRAC/Resources/IdProvider/CheckInIdProvider.py +13 -0
  134. DIRAC/Resources/IdProvider/IdProviderFactory.py +11 -3
  135. DIRAC/Resources/MessageQueue/StompMQConnector.py +1 -1
  136. DIRAC/Resources/Storage/GFAL2_StorageBase.py +24 -15
  137. DIRAC/Resources/Storage/OccupancyPlugins/WLCGAccountingHTTPJson.py +1 -3
  138. DIRAC/Resources/Storage/StorageBase.py +4 -2
  139. DIRAC/Resources/Storage/StorageElement.py +6 -7
  140. DIRAC/StorageManagementSystem/DB/StorageManagementDB.sql +2 -2
  141. DIRAC/TransformationSystem/Agent/TaskManagerAgentBase.py +10 -16
  142. DIRAC/TransformationSystem/Agent/TransformationAgent.py +22 -1
  143. DIRAC/TransformationSystem/Agent/TransformationCleaningAgent.py +16 -16
  144. DIRAC/TransformationSystem/Client/TaskManager.py +2 -4
  145. DIRAC/TransformationSystem/Client/Transformation.py +6 -7
  146. DIRAC/TransformationSystem/Client/TransformationClient.py +21 -11
  147. DIRAC/TransformationSystem/Client/Utilities.py +9 -0
  148. DIRAC/TransformationSystem/DB/TransformationDB.py +11 -14
  149. DIRAC/TransformationSystem/DB/TransformationDB.sql +9 -9
  150. DIRAC/TransformationSystem/Service/TransformationManagerHandler.py +0 -333
  151. DIRAC/TransformationSystem/Utilities/ReplicationCLIParameters.py +3 -3
  152. DIRAC/TransformationSystem/Utilities/TransformationInfo.py +7 -5
  153. DIRAC/TransformationSystem/scripts/dirac_production_runjoblocal.py +2 -4
  154. DIRAC/TransformationSystem/test/Test_TransformationInfo.py +22 -15
  155. DIRAC/TransformationSystem/test/Test_replicationTransformation.py +5 -6
  156. DIRAC/Workflow/Modules/test/Test_Modules.py +5 -0
  157. DIRAC/WorkloadManagementSystem/Agent/JobAgent.py +38 -26
  158. DIRAC/WorkloadManagementSystem/Agent/JobCleaningAgent.py +12 -8
  159. DIRAC/WorkloadManagementSystem/Agent/PilotSyncAgent.py +4 -3
  160. DIRAC/WorkloadManagementSystem/Agent/PushJobAgent.py +13 -13
  161. DIRAC/WorkloadManagementSystem/Agent/SiteDirector.py +18 -14
  162. DIRAC/WorkloadManagementSystem/Agent/StalledJobAgent.py +18 -51
  163. DIRAC/WorkloadManagementSystem/Agent/StatesAccountingAgent.py +41 -1
  164. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_JobAgent.py +45 -4
  165. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_JobCleaningAgent.py +7 -9
  166. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_PushJobAgent.py +1 -0
  167. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_SiteDirector.py +9 -2
  168. DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_StalledJobAgent.py +4 -5
  169. DIRAC/WorkloadManagementSystem/Client/DownloadInputData.py +9 -9
  170. DIRAC/WorkloadManagementSystem/Client/InputDataResolution.py +6 -6
  171. DIRAC/WorkloadManagementSystem/Client/JobMonitoringClient.py +10 -11
  172. DIRAC/WorkloadManagementSystem/Client/JobReport.py +1 -1
  173. DIRAC/WorkloadManagementSystem/Client/JobState/CachedJobState.py +3 -0
  174. DIRAC/WorkloadManagementSystem/Client/JobState/JobManifest.py +32 -261
  175. DIRAC/WorkloadManagementSystem/Client/JobState/JobState.py +6 -0
  176. DIRAC/WorkloadManagementSystem/Client/JobStateUpdateClient.py +3 -0
  177. DIRAC/WorkloadManagementSystem/Client/JobStatus.py +8 -152
  178. DIRAC/WorkloadManagementSystem/Client/PoolXMLSlice.py +12 -19
  179. DIRAC/WorkloadManagementSystem/Client/SandboxStoreClient.py +25 -38
  180. DIRAC/WorkloadManagementSystem/Client/WMSClient.py +2 -3
  181. DIRAC/WorkloadManagementSystem/Client/test/Test_Client_DownloadInputData.py +29 -0
  182. DIRAC/WorkloadManagementSystem/ConfigTemplate.cfg +4 -8
  183. DIRAC/WorkloadManagementSystem/DB/JobDB.py +89 -132
  184. DIRAC/WorkloadManagementSystem/DB/JobDB.sql +8 -8
  185. DIRAC/WorkloadManagementSystem/DB/JobDBUtils.py +18 -147
  186. DIRAC/WorkloadManagementSystem/DB/JobLoggingDB.py +19 -6
  187. DIRAC/WorkloadManagementSystem/DB/JobParametersDB.py +9 -9
  188. DIRAC/WorkloadManagementSystem/DB/PilotAgentsDB.py +16 -5
  189. DIRAC/WorkloadManagementSystem/DB/PilotAgentsDB.sql +3 -3
  190. DIRAC/WorkloadManagementSystem/DB/SandboxMetadataDB.py +44 -82
  191. DIRAC/WorkloadManagementSystem/DB/StatusUtils.py +125 -0
  192. DIRAC/WorkloadManagementSystem/DB/tests/Test_JobDB.py +1 -1
  193. DIRAC/WorkloadManagementSystem/DB/tests/Test_StatusUtils.py +28 -0
  194. DIRAC/WorkloadManagementSystem/Executor/JobSanity.py +5 -4
  195. DIRAC/WorkloadManagementSystem/Executor/JobScheduling.py +4 -0
  196. DIRAC/WorkloadManagementSystem/FutureClient/JobStateUpdateClient.py +75 -33
  197. DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapper.py +22 -11
  198. DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapperTemplate.py +9 -10
  199. DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapper.py +60 -10
  200. DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapperTemplate.py +4 -0
  201. DIRAC/WorkloadManagementSystem/Service/JobManagerHandler.py +33 -154
  202. DIRAC/WorkloadManagementSystem/Service/JobMonitoringHandler.py +5 -323
  203. DIRAC/WorkloadManagementSystem/Service/JobStateUpdateHandler.py +0 -16
  204. DIRAC/WorkloadManagementSystem/Service/PilotManagerHandler.py +6 -103
  205. DIRAC/WorkloadManagementSystem/Service/SandboxStoreHandler.py +7 -53
  206. DIRAC/WorkloadManagementSystem/Service/WMSAdministratorHandler.py +16 -79
  207. DIRAC/WorkloadManagementSystem/Service/WMSUtilities.py +4 -18
  208. DIRAC/WorkloadManagementSystem/Utilities/JobModel.py +28 -209
  209. DIRAC/WorkloadManagementSystem/Utilities/JobParameters.py +65 -3
  210. DIRAC/WorkloadManagementSystem/Utilities/JobStatusUtility.py +2 -64
  211. DIRAC/WorkloadManagementSystem/Utilities/ParametricJob.py +7 -171
  212. DIRAC/WorkloadManagementSystem/Utilities/PilotCStoJSONSynchronizer.py +73 -7
  213. DIRAC/WorkloadManagementSystem/Utilities/PilotWrapper.py +41 -11
  214. DIRAC/WorkloadManagementSystem/Utilities/RemoteRunner.py +16 -0
  215. DIRAC/WorkloadManagementSystem/Utilities/Utils.py +36 -1
  216. DIRAC/WorkloadManagementSystem/Utilities/jobAdministration.py +15 -0
  217. DIRAC/WorkloadManagementSystem/Utilities/test/Test_JobModel.py +1 -15
  218. DIRAC/WorkloadManagementSystem/Utilities/test/Test_ParametricJob.py +45 -128
  219. DIRAC/WorkloadManagementSystem/Utilities/test/Test_PilotWrapper.py +16 -0
  220. DIRAC/WorkloadManagementSystem/scripts/dirac_jobexec.py +7 -2
  221. DIRAC/WorkloadManagementSystem/scripts/dirac_wms_pilot_job_info.py +1 -1
  222. DIRAC/__init__.py +62 -60
  223. DIRAC/tests/Utilities/testJobDefinitions.py +22 -28
  224. {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/METADATA +8 -5
  225. {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/RECORD +229 -228
  226. {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/WHEEL +1 -1
  227. {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/entry_points.txt +0 -3
  228. DIRAC/Core/Utilities/test/Test_List.py +0 -150
  229. DIRAC/Core/Utilities/test/Test_Time.py +0 -88
  230. DIRAC/Resources/Computing/PilotBundle.py +0 -70
  231. DIRAC/TransformationSystem/scripts/dirac_transformation_archive.py +0 -30
  232. DIRAC/TransformationSystem/scripts/dirac_transformation_clean.py +0 -30
  233. DIRAC/TransformationSystem/scripts/dirac_transformation_remove_output.py +0 -30
  234. DIRAC/WorkloadManagementSystem/Utilities/test/Test_JobManager.py +0 -58
  235. {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info/licenses}/LICENSE +0 -0
  236. {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,599 @@
1
+ """
2
+ The WebAppHandler module provides a class to handle web requests from the DIRAC WebApp.
3
+ It is not indented to be used in diracx
4
+ """
5
+ from DIRAC import S_ERROR, S_OK
6
+ from DIRAC.ConfigurationSystem.Client.Helpers.Operations import Operations
7
+ from DIRAC.ConfigurationSystem.Client.Helpers.Resources import getSites
8
+ from DIRAC.Core.DISET.RequestHandler import RequestHandler
9
+ from DIRAC.Core.Utilities.ObjectLoader import ObjectLoader
10
+ from DIRAC.RequestManagementSystem.Client.Operation import Operation
11
+ from DIRAC.RequestManagementSystem.Client.Request import Request
12
+ from DIRAC.TransformationSystem.Client import TransformationFilesStatus
13
+ from DIRAC.WorkloadManagementSystem.Client import JobStatus
14
+ from DIRAC.WorkloadManagementSystem.Service.JobPolicy import RIGHT_GET_INFO, JobPolicy
15
+
16
+ TASKS_STATE_NAMES = ["TotalCreated", "Created"] + sorted(
17
+ set(JobStatus.JOB_STATES) | set(Request.ALL_STATES) | set(Operation.ALL_STATES)
18
+ )
19
+ FILES_STATE_NAMES = ["PercentProcessed", "Total"] + TransformationFilesStatus.TRANSFORMATION_FILES_STATES
20
+
21
+
22
+ class WebAppHandler(RequestHandler):
23
+ @classmethod
24
+ def initializeHandler(cls, serviceInfoDict):
25
+ """Initialization of DB objects"""
26
+
27
+ try:
28
+ result = ObjectLoader().loadObject("WorkloadManagementSystem.DB.PilotAgentsDB", "PilotAgentsDB")
29
+ if not result["OK"]:
30
+ return result
31
+ try:
32
+ cls.pilotAgentsDB = result["Value"](parentLogger=cls.log)
33
+ except RuntimeError:
34
+ cls.log.warn("Could not connect to PilotAgentsDB")
35
+
36
+ result = ObjectLoader().loadObject("WorkloadManagementSystem.DB.JobDB", "JobDB")
37
+ if not result["OK"]:
38
+ return result
39
+ try:
40
+ cls.jobDB = result["Value"](parentLogger=cls.log)
41
+ except RuntimeError:
42
+ cls.log.warn("Could not connect to JobDB")
43
+
44
+ result = ObjectLoader().loadObject("TransformationSystem.DB.TransformationDB", "TransformationDB")
45
+ if not result["OK"]:
46
+ return result
47
+ try:
48
+ cls.transformationDB = result["Value"](parentLogger=cls.log)
49
+ except RuntimeError:
50
+ cls.log.warn("Could not connect to TransformationDB")
51
+
52
+ except RuntimeError as excp:
53
+ cls.log.exception()
54
+ return S_ERROR(f"Can't connect to DB: {excp}")
55
+
56
+ return S_OK()
57
+
58
+ ##############################################################################
59
+ # PilotAgents
60
+ ##############################################################################
61
+
62
+ types_getPilotMonitorWeb = [dict, list, int, int]
63
+
64
+ @classmethod
65
+ def export_getPilotMonitorWeb(cls, selectDict, sortList, startItem, maxItems):
66
+ """Get the summary of the pilot information for a given page in the
67
+ pilot monitor in a generic format
68
+ """
69
+
70
+ return cls.pilotAgentsDB.getPilotMonitorWeb(selectDict, sortList, startItem, maxItems)
71
+
72
+ types_getPilotMonitorSelectors = []
73
+
74
+ @classmethod
75
+ def export_getPilotMonitorSelectors(cls):
76
+ """Get all the distinct selector values for the Pilot Monitor web portal page"""
77
+
78
+ return cls.pilotAgentsDB.getPilotMonitorSelectors()
79
+
80
+ types_getPilotSummaryWeb = [dict, list, int, int]
81
+
82
+ @classmethod
83
+ def export_getPilotSummaryWeb(cls, selectDict, sortList, startItem, maxItems):
84
+ """Get the summary of the pilot information for a given page in the
85
+ pilot monitor in a generic format
86
+ """
87
+
88
+ return cls.pilotAgentsDB.getPilotSummaryWeb(selectDict, sortList, startItem, maxItems)
89
+
90
+ types_getPilotStatistics = [str, dict]
91
+
92
+ @classmethod
93
+ def export_getPilotStatistics(cls, attribute, selectDict):
94
+ """Get pilot statistics distribution per attribute value with a given selection"""
95
+
96
+ startDate = selectDict.get("FromDate", None)
97
+ if startDate:
98
+ del selectDict["FromDate"]
99
+
100
+ if startDate is None:
101
+ startDate = selectDict.get("LastUpdate", None)
102
+ if startDate:
103
+ del selectDict["LastUpdate"]
104
+ endDate = selectDict.get("ToDate", None)
105
+ if endDate:
106
+ del selectDict["ToDate"]
107
+
108
+ result = cls.pilotAgentsDB.getCounters(
109
+ "PilotAgents", [attribute], selectDict, newer=startDate, older=endDate, timeStamp="LastUpdateTime"
110
+ )
111
+ statistics = {}
112
+ if result["OK"]:
113
+ for status, count in result["Value"]:
114
+ statistics[status[attribute]] = count
115
+
116
+ return S_OK(statistics)
117
+
118
+ types_getPilotsCounters = [str, list, dict]
119
+
120
+ # This was PilotManagerHandler.getCounters
121
+ @classmethod
122
+ def export_getPilotsCounters(cls, table, keys, condDict, newer=None, timeStamp="SubmissionTime"):
123
+ """Set the pilot agent status"""
124
+
125
+ return cls.pilotAgentsDB.getCounters(table, keys, condDict, newer=newer, timeStamp=timeStamp)
126
+
127
+ ##############################################################################
128
+ # Jobs
129
+ ##############################################################################
130
+
131
+ types_getJobPageSummaryWeb = [dict, list, int, int]
132
+
133
+ def export_getJobPageSummaryWeb(self, selectDict, sortList, startItem, maxItems, selectJobs=True):
134
+ """Get the summary of the job information for a given page in the
135
+ job monitor in a generic format
136
+ """
137
+
138
+ resultDict = {}
139
+
140
+ startDate, endDate, selectDict = self.parseSelectors(selectDict)
141
+
142
+ # initialize jobPolicy
143
+ credDict = self.getRemoteCredentials()
144
+ owner = credDict["username"]
145
+ ownerGroup = credDict["group"]
146
+ operations = Operations(group=ownerGroup)
147
+ globalJobsInfo = operations.getValue("/Services/JobMonitoring/GlobalJobsInfo", True)
148
+ jobPolicy = JobPolicy(owner, ownerGroup, globalJobsInfo)
149
+ jobPolicy.jobDB = self.jobDB
150
+ result = jobPolicy.getControlledUsers(RIGHT_GET_INFO)
151
+ if not result["OK"]:
152
+ return result
153
+ if not result["Value"]:
154
+ return S_ERROR(f"User and group combination has no job rights ({owner!r}, {ownerGroup!r})")
155
+ if result["Value"] != "ALL":
156
+ selectDict[("Owner", "OwnerGroup")] = result["Value"]
157
+
158
+ # Sorting instructions. Only one for the moment.
159
+ if sortList:
160
+ orderAttribute = sortList[0][0] + ":" + sortList[0][1]
161
+ else:
162
+ orderAttribute = None
163
+
164
+ result = self.jobDB.getCounters(
165
+ "Jobs", ["Status"], selectDict, newer=startDate, older=endDate, timeStamp="LastUpdateTime"
166
+ )
167
+ if not result["OK"]:
168
+ return result
169
+
170
+ statusDict = {}
171
+ nJobs = 0
172
+ for stDict, count in result["Value"]:
173
+ nJobs += count
174
+ statusDict[stDict["Status"]] = count
175
+
176
+ resultDict["TotalRecords"] = nJobs
177
+ if nJobs == 0:
178
+ return S_OK(resultDict)
179
+
180
+ resultDict["Extras"] = statusDict
181
+
182
+ if selectJobs:
183
+ iniJob = startItem
184
+ if iniJob >= nJobs:
185
+ return S_ERROR("Item number out of range")
186
+
187
+ result = self.jobDB.selectJobs(
188
+ selectDict, orderAttribute=orderAttribute, newer=startDate, older=endDate, limit=(maxItems, iniJob)
189
+ )
190
+ if not result["OK"]:
191
+ return result
192
+
193
+ summaryJobList = result["Value"]
194
+ if not globalJobsInfo:
195
+ validJobs, _invalidJobs, _nonauthJobs, _ownJobs = jobPolicy.evaluateJobRights(
196
+ summaryJobList, RIGHT_GET_INFO
197
+ )
198
+ summaryJobList = validJobs
199
+
200
+ result = self.jobDB.getJobsAttributes(summaryJobList)
201
+ if not result["OK"]:
202
+ return result
203
+
204
+ summaryDict = result["Value"]
205
+ # If no jobs can be selected after the properties check
206
+ if not summaryDict:
207
+ return S_OK(resultDict)
208
+
209
+ # Evaluate last sign of life time
210
+ for jobDict in summaryDict.values():
211
+ if not jobDict.get("HeartBeatTime") or jobDict["HeartBeatTime"] == "None":
212
+ jobDict["LastSignOfLife"] = jobDict["LastUpdateTime"]
213
+ else:
214
+ jobDict["LastSignOfLife"] = jobDict["HeartBeatTime"]
215
+
216
+ # prepare the standard structure now
217
+ # This should be faster than making a list of values()
218
+ for jobDict in summaryDict.values():
219
+ paramNames = list(jobDict)
220
+ break
221
+ records = [list(jobDict.values()) for jobDict in summaryDict.values()]
222
+
223
+ resultDict["ParameterNames"] = paramNames
224
+ resultDict["Records"] = records
225
+
226
+ return S_OK(resultDict)
227
+
228
+ types_getJobStats = [str, dict]
229
+
230
+ @classmethod
231
+ def export_getJobStats(cls, attribute, selectDict):
232
+ """Get job statistics distribution per attribute value with a given selection"""
233
+ startDate, endDate, selectDict = cls.parseSelectors(selectDict)
234
+ result = cls.jobDB.getCounters(
235
+ "Jobs", [attribute], selectDict, newer=startDate, older=endDate, timeStamp="LastUpdateTime"
236
+ )
237
+ if not result["OK"]:
238
+ return result
239
+ resultDict = {}
240
+ for cDict, count in result["Value"]:
241
+ resultDict[cDict[attribute]] = count
242
+
243
+ return S_OK(resultDict)
244
+
245
+ @classmethod
246
+ def parseSelectors(cls, selectDict=None):
247
+ """Parse selectors before DB query
248
+
249
+ :param dict selectDict: selectors
250
+
251
+ :return: str, str, dict -- start/end date, selectors
252
+ """
253
+ selectDict = selectDict or {}
254
+
255
+ # Get time period
256
+ startDate = selectDict.get("FromDate", None)
257
+ if startDate:
258
+ del selectDict["FromDate"]
259
+ # For backward compatibility
260
+ if startDate is None:
261
+ startDate = selectDict.get("LastUpdate", None)
262
+ if startDate:
263
+ del selectDict["LastUpdate"]
264
+ endDate = selectDict.get("ToDate", None)
265
+ if endDate:
266
+ del selectDict["ToDate"]
267
+
268
+ # Provide JobID bound to a specific PilotJobReference
269
+ # There is no reason to have both PilotJobReference and JobID in selectDict
270
+ # If that occurs, use the JobID instead of the PilotJobReference
271
+ pilotJobRefs = selectDict.get("PilotJobReference")
272
+ if pilotJobRefs:
273
+ del selectDict["PilotJobReference"]
274
+ if not selectDict.get("JobID"):
275
+ for pilotJobRef in [pilotJobRefs] if isinstance(pilotJobRefs, str) else pilotJobRefs:
276
+ res = cls.pilotAgentsDB.getPilotInfo(pilotJobRef)
277
+ if res["OK"] and "Jobs" in res["Value"][pilotJobRef]:
278
+ selectDict["JobID"] = selectDict.get("JobID", [])
279
+ selectDict["JobID"].extend(res["Value"][pilotJobRef]["Jobs"])
280
+
281
+ return startDate, endDate, selectDict
282
+
283
+ types_getJobsCounters = [list]
284
+
285
+ # This was JobManagerHanlder.getCounters
286
+ @classmethod
287
+ def export_getJobsCounters(cls, attrList, attrDict=None, cutDate=""):
288
+ """
289
+ Retrieve list of distinct attributes values from attrList
290
+ with attrDict as condition.
291
+ For each set of distinct values, count number of occurences.
292
+ Return a list. Each item is a list with 2 items, the list of distinct
293
+ attribute values and the counter
294
+ """
295
+
296
+ _, _, attrDict = cls.parseSelectors(attrDict)
297
+ return cls.jobDB.getCounters("Jobs", attrList, attrDict, newer=str(cutDate), timeStamp="LastUpdateTime")
298
+
299
+ types_getSiteSummaryWeb = [dict, list, int, int]
300
+
301
+ @classmethod
302
+ def export_getSiteSummaryWeb(cls, selectDict, sortList, startItem, maxItems):
303
+ """Get the summary of the jobs running on sites in a generic format
304
+
305
+ :param dict selectDict: selectors
306
+ :param list sortList: sorting list
307
+ :param int startItem: start item number
308
+ :param int maxItems: maximum of items
309
+
310
+ :return: S_OK(dict)/S_ERROR()
311
+ """
312
+ return cls.jobDB.getSiteSummaryWeb(selectDict, sortList, startItem, maxItems)
313
+
314
+ types_getSiteSummarySelectors = []
315
+
316
+ @classmethod
317
+ def export_getSiteSummarySelectors(cls):
318
+ """Get all the distinct selector values for the site summary web portal page
319
+
320
+ :return: S_OK(dict)/S_ERROR()
321
+ """
322
+ resultDict = {}
323
+ statusList = ["Good", "Fair", "Poor", "Bad", "Idle"]
324
+ resultDict["Status"] = statusList
325
+ maskStatus = ["Active", "Banned", "NoMask", "Reduced"]
326
+ resultDict["MaskStatus"] = maskStatus
327
+
328
+ res = getSites()
329
+ if not res["OK"]:
330
+ return res
331
+ siteList = res["Value"]
332
+
333
+ countryList = []
334
+ for site in siteList:
335
+ if site.find(".") != -1:
336
+ country = site.split(".")[2].lower()
337
+ if country not in countryList:
338
+ countryList.append(country)
339
+ countryList.sort()
340
+ resultDict["Country"] = countryList
341
+ siteList.sort()
342
+ resultDict["Site"] = siteList
343
+
344
+ return S_OK(resultDict)
345
+
346
+ types_getApplicationStates = []
347
+
348
+ @classmethod
349
+ def export_getApplicationStates(cls, condDict=None, older=None, newer=None):
350
+ """Return Distinct Values of ApplicationStatus job Attribute in WMS"""
351
+ return cls.jobDB.getDistinctJobAttributes("ApplicationStatus", condDict, older, newer)
352
+
353
+ types_getJobTypes = []
354
+
355
+ @classmethod
356
+ def export_getJobTypes(cls, condDict=None, older=None, newer=None):
357
+ """Return Distinct Values of JobType job Attribute in WMS"""
358
+ return cls.jobDB.getDistinctJobAttributes("JobType", condDict, older, newer)
359
+
360
+ types_getOwners = []
361
+
362
+ @classmethod
363
+ def export_getOwners(cls, condDict=None, older=None, newer=None):
364
+ """
365
+ Return Distinct Values of Owner job Attribute in WMS
366
+ """
367
+ return cls.jobDB.getDistinctJobAttributes("Owner", condDict, older, newer)
368
+
369
+ types_getOwnerGroup = []
370
+
371
+ @classmethod
372
+ def export_getOwnerGroup(cls):
373
+ """
374
+ Return Distinct Values of OwnerGroup from the JobDB
375
+ """
376
+ return cls.jobDB.getDistinctJobAttributes("OwnerGroup")
377
+
378
+ types_getJobGroups = []
379
+
380
+ @classmethod
381
+ def export_getJobGroups(cls, condDict=None, older=None, cutDate=None):
382
+ """
383
+ Return Distinct Values of ProductionId job Attribute in WMS
384
+ """
385
+ return cls.jobDB.getDistinctJobAttributes("JobGroup", condDict, older, newer=cutDate)
386
+
387
+ types_getSites = []
388
+
389
+ @classmethod
390
+ def export_getSites(cls, condDict=None, older=None, newer=None):
391
+ """
392
+ Return Distinct Values of Site job Attribute in WMS
393
+ """
394
+ return cls.jobDB.getDistinctJobAttributes("Site", condDict, older, newer)
395
+
396
+ types_getStates = []
397
+
398
+ @classmethod
399
+ def export_getStates(cls, condDict=None, older=None, newer=None):
400
+ """
401
+ Return Distinct Values of Status job Attribute in WMS
402
+ """
403
+ return cls.jobDB.getDistinctJobAttributes("Status", condDict, older, newer)
404
+
405
+ types_getMinorStates = []
406
+
407
+ @classmethod
408
+ def export_getMinorStates(cls, condDict=None, older=None, newer=None):
409
+ """
410
+ Return Distinct Values of Minor Status job Attribute in WMS
411
+ """
412
+ return cls.jobDB.getDistinctJobAttributes("MinorStatus", condDict, older, newer)
413
+
414
+ ##############################################################################
415
+ # Transformations
416
+ ##############################################################################
417
+
418
+ types_getDistinctAttributeValues = [str, dict]
419
+
420
+ @classmethod
421
+ def export_getDistinctAttributeValues(cls, attribute, selectDict):
422
+ res = cls.transformationDB.getTableDistinctAttributeValues("Transformations", [attribute], selectDict)
423
+ if not res["OK"]:
424
+ return res
425
+ return S_OK(res["Value"][attribute])
426
+
427
+ types_getTransformationFilesSummaryWeb = [dict, list, int, int]
428
+
429
+ @classmethod
430
+ def export_getTransformationFilesSummaryWeb(cls, selectDict, sortList, startItem, maxItems):
431
+ fromDate = selectDict.get("FromDate", None)
432
+ if fromDate:
433
+ del selectDict["FromDate"]
434
+ toDate = selectDict.get("ToDate", None)
435
+ if toDate:
436
+ del selectDict["ToDate"]
437
+ # Sorting instructions. Only one for the moment.
438
+ if sortList:
439
+ orderAttribute = sortList[0][0] + ":" + sortList[0][1]
440
+ else:
441
+ orderAttribute = None
442
+ # Get the columns that match the selection
443
+ res = cls.transformationDB.getTransformationFiles(
444
+ condDict=selectDict, older=toDate, newer=fromDate, timeStamp="LastUpdate", orderAttribute=orderAttribute
445
+ )
446
+ if not res["OK"]:
447
+ return res
448
+ allRows = res["Value"]
449
+
450
+ # Prepare the standard structure now within the resultDict dictionary
451
+ resultDict = {}
452
+ resultDict["TotalRecords"] = len(allRows)
453
+
454
+ if not allRows:
455
+ return S_OK(resultDict)
456
+
457
+ # Get the rows which are within the selected window
458
+ ini = startItem
459
+ last = ini + maxItems
460
+ if ini >= resultDict["TotalRecords"]:
461
+ return S_ERROR("Item number out of range")
462
+ if last > resultDict["TotalRecords"]:
463
+ last = resultDict["TotalRecords"]
464
+
465
+ selectedRows = allRows[ini:last]
466
+ resultDict["Records"] = []
467
+ for row in selectedRows:
468
+ resultDict["Records"].append(list(row.values()))
469
+
470
+ # Create the ParameterNames entry
471
+ resultDict["ParameterNames"] = list(selectedRows[0].keys())
472
+
473
+ # Generate the status dictionary
474
+ statusDict = {}
475
+ for row in selectedRows:
476
+ status = row["Status"]
477
+ statusDict[status] = statusDict.setdefault(status, 0) + 1
478
+ resultDict["Extras"] = statusDict
479
+
480
+ # Obtain the distinct values of the selection parameters
481
+ res = cls.transformationDB.getTableDistinctAttributeValues(
482
+ "TransformationFiles",
483
+ ["TransformationID", "Status", "UsedSE", "TargetSE"],
484
+ selectDict,
485
+ older=toDate,
486
+ newer=fromDate,
487
+ )
488
+ if not res["OK"]:
489
+ return res
490
+ resultDict["Selections"] = res["Value"]
491
+
492
+ return S_OK(resultDict)
493
+
494
+ types_getTransformationSummaryWeb = [dict, list, int, int]
495
+
496
+ @classmethod
497
+ def export_getTransformationSummaryWeb(cls, selectDict, sortList, startItem, maxItems):
498
+ """Get the summary of the transformation information for a given page in the generic format"""
499
+
500
+ # Obtain the timing information from the selectDict
501
+ last_update = selectDict.get("CreationDate", None)
502
+ if last_update:
503
+ del selectDict["CreationDate"]
504
+ fromDate = selectDict.get("FromDate", None)
505
+ if fromDate:
506
+ del selectDict["FromDate"]
507
+ if not fromDate:
508
+ fromDate = last_update
509
+ toDate = selectDict.get("ToDate", None)
510
+ if toDate:
511
+ del selectDict["ToDate"]
512
+ # Sorting instructions. Only one for the moment.
513
+ if sortList:
514
+ orderAttribute = []
515
+ for i in sortList:
516
+ orderAttribute += [i[0] + ":" + i[1]]
517
+ else:
518
+ orderAttribute = None
519
+
520
+ # Get the transformations that match the selection
521
+ res = cls.transformationDB.getTransformations(
522
+ condDict=selectDict, older=toDate, newer=fromDate, orderAttribute=orderAttribute
523
+ )
524
+ if not res["OK"]:
525
+ return res
526
+
527
+ ops = Operations()
528
+ # Prepare the standard structure now within the resultDict dictionary
529
+ resultDict = {}
530
+ trList = res["Records"]
531
+ # Create the total records entry
532
+ nTrans = len(trList)
533
+ resultDict["TotalRecords"] = nTrans
534
+ # Create the ParameterNames entry
535
+ # As this list is a reference to the list in the DB, we cannot extend it, therefore copy it
536
+ resultDict["ParameterNames"] = list(res["ParameterNames"])
537
+ # Add the job states to the ParameterNames entry
538
+ taskStateNames = TASKS_STATE_NAMES + ops.getValue("Transformations/AdditionalTaskStates", [])
539
+ resultDict["ParameterNames"] += ["Jobs_" + x for x in taskStateNames]
540
+ # Add the file states to the ParameterNames entry
541
+ fileStateNames = FILES_STATE_NAMES + ops.getValue("Transformations/AdditionalFileStates", [])
542
+ resultDict["ParameterNames"] += ["Files_" + x for x in fileStateNames]
543
+
544
+ # Get the transformations which are within the selected window
545
+ if nTrans == 0:
546
+ return S_OK(resultDict)
547
+ ini = startItem
548
+ last = ini + maxItems
549
+ if ini >= nTrans:
550
+ return S_ERROR("Item number out of range")
551
+ if last > nTrans:
552
+ last = nTrans
553
+ transList = trList[ini:last]
554
+
555
+ statusDict = {}
556
+ extendableTranfs = ops.getValue("Transformations/ExtendableTransfTypes", ["Simulation", "MCsimulation"])
557
+ givenUpFileStatus = ops.getValue("Transformations/GivenUpFileStatus", ["MissingInFC"])
558
+ problematicStatuses = ops.getValue("Transformations/ProblematicStatuses", ["Problematic"])
559
+ # Add specific information for each selected transformation
560
+ for trans in transList:
561
+ transDict = dict(zip(resultDict["ParameterNames"], trans))
562
+
563
+ # Update the status counters
564
+ status = transDict["Status"]
565
+ statusDict[status] = statusDict.setdefault(status, 0) + 1
566
+
567
+ # Get the statistics on the number of jobs for the transformation
568
+ transID = transDict["TransformationID"]
569
+ res = cls.transformationDB.getTransformationTaskStats(transID)
570
+ taskDict = {}
571
+ if res["OK"] and res["Value"]:
572
+ taskDict = res["Value"]
573
+ for state in taskStateNames:
574
+ trans.append(taskDict.get(state, 0))
575
+
576
+ # Get the statistics for the number of files for the transformation
577
+ fileDict = {}
578
+ transType = transDict["Type"]
579
+ if transType.lower() in extendableTranfs:
580
+ fileDict["PercentProcessed"] = "-"
581
+ else:
582
+ res = cls.transformationDB.getTransformationStats(transID)
583
+ if res["OK"]:
584
+ fileDict = res["Value"]
585
+ total = fileDict["Total"]
586
+ for stat in givenUpFileStatus:
587
+ total -= fileDict.get(stat, 0)
588
+ processed = fileDict.get(TransformationFilesStatus.PROCESSED, 0)
589
+ fileDict["PercentProcessed"] = f"{int(processed * 1000.0 / total) / 10.0:.1f}" if total else 0.0
590
+ problematic = 0
591
+ for stat in problematicStatuses:
592
+ problematic += fileDict.get(stat, 0)
593
+ fileDict["Problematic"] = problematic
594
+ for state in fileStateNames:
595
+ trans.append(fileDict.get(state, 0))
596
+
597
+ resultDict["Records"] = transList
598
+ resultDict["Extras"] = statusDict
599
+ return S_OK(resultDict)
@@ -5,7 +5,6 @@ import hashlib
5
5
  import re
6
6
 
7
7
  from DIRAC import S_OK, S_ERROR, gConfig
8
- from DIRAC.ConfigurationSystem.Client.Helpers import CSGlobals
9
8
  from DIRAC.ConfigurationSystem.Client.PathFinder import getServiceSection
10
9
  from DIRAC.MonitoringSystem.private.Plotters.BasePlotter import BasePlotter as myBasePlotter
11
10
  from DIRAC.Core.Utilities.ObjectLoader import loadObjects
@@ -56,7 +55,6 @@ class MainReporter:
56
55
  :param str setup: DIRAC setup
57
56
  """
58
57
  self.__db = db
59
- self.__setup = CSGlobals.getSetup().lower()
60
58
  self.__csSection = getServiceSection("Monitoring/Monitoring")
61
59
  self.__plotterList = PlottersList()
62
60
 
@@ -75,7 +73,6 @@ class MainReporter:
75
73
  requestToHash[key] = epoch - epoch % granularity
76
74
  md5Hash = hashlib.md5()
77
75
  md5Hash.update(repr(requestToHash).encode())
78
- md5Hash.update(self.__setup.encode())
79
76
  return md5Hash.hexdigest()
80
77
 
81
78
  def generate(self, reportRequest):
@@ -31,7 +31,7 @@ CREATE TABLE Productions(
31
31
  Status CHAR(32) DEFAULT 'New',
32
32
  PRIMARY KEY(ProductionID),
33
33
  INDEX(ProductionName)
34
- ) ENGINE = InnoDB DEFAULT CHARSET = utf8;
34
+ ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
35
35
 
36
36
  -- -------------------------------------------------------------------------------
37
37
  DROP TABLE IF EXISTS ProductionSteps;
@@ -51,7 +51,7 @@ CREATE TABLE ProductionSteps(
51
51
  InsertedTime DATETIME,
52
52
  PRIMARY KEY(StepID),
53
53
  UNIQUE INDEX(StepID)
54
- ) ENGINE = InnoDB DEFAULT CHARSET = utf8;
54
+ ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
55
55
 
56
56
  -- -------------------------------------------------------------------------------
57
57
  DROP TABLE IF EXISTS ProductionTransformations;
@@ -63,7 +63,7 @@ CREATE TABLE ProductionTransformations(
63
63
  PRIMARY KEY(ProductionID, TransformationID),
64
64
  UNIQUE INDEX(TransformationID),
65
65
  FOREIGN KEY(ProductionID) REFERENCES Productions(ProductionID)
66
- ) ENGINE = InnoDB DEFAULT CHARSET = utf8;
66
+ ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
67
67
 
68
68
  -- -------------------------------------------------------------------------------
69
69
  DROP TABLE IF EXISTS ProductionTransformationLinks;
@@ -75,6 +75,6 @@ CREATE TABLE ProductionTransformationLinks(
75
75
  INDEX(TransformationID),
76
76
  FOREIGN KEY(ProductionID) REFERENCES Productions(ProductionID),
77
77
  FOREIGN KEY(TransformationID) REFERENCES ProductionTransformations(TransformationID)
78
- ) ENGINE = InnoDB DEFAULT CHARSET = utf8;
78
+ ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;
79
79
 
80
80
  SET FOREIGN_KEY_CHECKS = 1;
@@ -24,7 +24,7 @@ def main():
24
24
  prodID = args[0]
25
25
  res = prodClient.getProduction(prodID)
26
26
 
27
- fields = ["ProductionName", "Status", "ProductionID", "CreationDate", "LastUpdate", "AuthorDN", "AuthorGroup"]
27
+ fields = ["ProductionName", "Status", "ProductionID", "CreationDate", "LastUpdate", "Author", "AuthorGroup"]
28
28
  records = []
29
29
 
30
30
  if res["OK"]:
@@ -39,7 +39,7 @@ def main():
39
39
  str(prod["ProductionID"]),
40
40
  str(prod["CreationDate"]),
41
41
  str(prod["LastUpdate"]),
42
- str(prod["AuthorDN"]),
42
+ str(prod["Author"]),
43
43
  str(prod["AuthorGroup"]),
44
44
  ]
45
45
  )
@@ -16,7 +16,7 @@ def main():
16
16
  prodClient = ProductionClient()
17
17
  res = prodClient.getProductions()
18
18
 
19
- fields = ["ProductionName", "Status", "ProductionID", "CreationDate", "LastUpdate", "AuthorDN", "AuthorGroup"]
19
+ fields = ["ProductionName", "Status", "ProductionID", "CreationDate", "LastUpdate", "Author", "AuthorGroup"]
20
20
  records = []
21
21
 
22
22
  if res["OK"]:
@@ -31,7 +31,7 @@ def main():
31
31
  str(prod["ProductionID"]),
32
32
  str(prod["CreationDate"]),
33
33
  str(prod["LastUpdate"]),
34
- str(prod["AuthorDN"]),
34
+ str(prod["Author"]),
35
35
  str(prod["AuthorGroup"]),
36
36
  ]
37
37
  )