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.
- DIRAC/AccountingSystem/Client/AccountingCLI.py +0 -140
- DIRAC/AccountingSystem/Client/DataStoreClient.py +0 -13
- DIRAC/AccountingSystem/Client/Types/BaseAccountingType.py +0 -7
- DIRAC/AccountingSystem/ConfigTemplate.cfg +0 -5
- DIRAC/AccountingSystem/Service/DataStoreHandler.py +0 -72
- DIRAC/ConfigurationSystem/Client/Helpers/CSGlobals.py +0 -9
- DIRAC/ConfigurationSystem/Client/Helpers/Registry.py +38 -26
- DIRAC/ConfigurationSystem/Client/Helpers/Resources.py +11 -43
- DIRAC/ConfigurationSystem/Client/Helpers/test/Test_Helpers.py +0 -16
- DIRAC/ConfigurationSystem/Client/LocalConfiguration.py +14 -8
- DIRAC/ConfigurationSystem/Client/PathFinder.py +47 -8
- DIRAC/ConfigurationSystem/Client/SyncPlugins/CERNLDAPSyncPlugin.py +4 -1
- DIRAC/ConfigurationSystem/Client/VOMS2CSSynchronizer.py +32 -19
- DIRAC/ConfigurationSystem/Client/test/Test_PathFinder.py +41 -1
- DIRAC/ConfigurationSystem/private/RefresherBase.py +4 -2
- DIRAC/Core/Base/API.py +4 -7
- DIRAC/Core/Base/SQLAlchemyDB.py +1 -0
- DIRAC/Core/DISET/ServiceReactor.py +11 -3
- DIRAC/Core/DISET/private/BaseClient.py +1 -2
- DIRAC/Core/DISET/private/Transports/M2SSLTransport.py +9 -7
- DIRAC/Core/DISET/private/Transports/SSL/M2Utils.py +3 -1
- DIRAC/Core/LCG/GOCDBClient.py +5 -7
- DIRAC/Core/Security/DiracX.py +31 -17
- DIRAC/Core/Security/IAMService.py +5 -10
- DIRAC/Core/Security/Locations.py +27 -18
- DIRAC/Core/Security/ProxyInfo.py +9 -5
- DIRAC/Core/Security/VOMSService.py +2 -4
- DIRAC/Core/Security/m2crypto/X509Certificate.py +4 -6
- DIRAC/Core/Security/m2crypto/asn1_utils.py +17 -5
- DIRAC/Core/Security/test/test_diracx_token_from_pem.py +161 -0
- DIRAC/Core/Tornado/Client/ClientSelector.py +4 -1
- DIRAC/Core/Tornado/Server/TornadoService.py +1 -1
- DIRAC/Core/Utilities/CGroups2.py +328 -0
- DIRAC/Core/Utilities/ClassAd/ClassAdLight.py +4 -290
- DIRAC/Core/Utilities/DErrno.py +5 -309
- DIRAC/Core/Utilities/Extensions.py +10 -1
- DIRAC/Core/Utilities/File.py +1 -1
- DIRAC/Core/Utilities/Graphs/GraphData.py +1 -1
- DIRAC/Core/Utilities/Graphs/GraphUtilities.py +6 -1
- DIRAC/Core/Utilities/JDL.py +1 -195
- DIRAC/Core/Utilities/List.py +1 -124
- DIRAC/Core/Utilities/MySQL.py +103 -99
- DIRAC/Core/Utilities/Os.py +32 -1
- DIRAC/Core/Utilities/Platform.py +2 -107
- DIRAC/Core/Utilities/Proxy.py +0 -4
- DIRAC/Core/Utilities/ReturnValues.py +7 -252
- DIRAC/Core/Utilities/StateMachine.py +12 -178
- DIRAC/Core/Utilities/Subprocess.py +35 -14
- DIRAC/Core/Utilities/TimeUtilities.py +10 -253
- DIRAC/Core/Utilities/test/Test_JDL.py +0 -3
- DIRAC/Core/Utilities/test/Test_Profiler.py +20 -20
- DIRAC/Core/scripts/dirac_agent.py +1 -1
- DIRAC/Core/scripts/dirac_apptainer_exec.py +72 -46
- DIRAC/Core/scripts/dirac_configure.py +1 -3
- DIRAC/Core/scripts/dirac_install_db.py +24 -6
- DIRAC/Core/scripts/dirac_platform.py +1 -92
- DIRAC/DataManagementSystem/Agent/FTS3Agent.py +8 -7
- DIRAC/DataManagementSystem/Agent/RequestOperations/RemoveFile.py +7 -6
- DIRAC/DataManagementSystem/Client/FTS3Job.py +71 -34
- DIRAC/DataManagementSystem/DB/FTS3DB.py +7 -3
- DIRAC/DataManagementSystem/DB/FileCatalogComponents/DatasetManager/DatasetManager.py +1 -1
- DIRAC/DataManagementSystem/DB/FileCatalogDB.sql +9 -9
- DIRAC/DataManagementSystem/DB/FileCatalogWithFkAndPsDB.sql +9 -9
- DIRAC/DataManagementSystem/Utilities/DMSHelpers.py +6 -2
- DIRAC/DataManagementSystem/scripts/dirac_admin_allow_se.py +13 -8
- DIRAC/DataManagementSystem/scripts/dirac_admin_ban_se.py +13 -8
- DIRAC/DataManagementSystem/scripts/dirac_dms_create_moving_request.py +2 -0
- DIRAC/DataManagementSystem/scripts/dirac_dms_protocol_matrix.py +0 -1
- DIRAC/FrameworkSystem/Client/BundleDeliveryClient.py +2 -7
- DIRAC/FrameworkSystem/Client/ComponentInstaller.py +9 -4
- DIRAC/FrameworkSystem/Client/ProxyManagerClient.py +5 -2
- DIRAC/FrameworkSystem/Client/SystemAdministratorClientCLI.py +11 -6
- DIRAC/FrameworkSystem/ConfigTemplate.cfg +2 -0
- DIRAC/FrameworkSystem/DB/AuthDB.py +3 -3
- DIRAC/FrameworkSystem/DB/InstalledComponentsDB.py +4 -4
- DIRAC/FrameworkSystem/DB/ProxyDB.py +11 -3
- DIRAC/FrameworkSystem/DB/TokenDB.py +1 -1
- DIRAC/FrameworkSystem/Service/ProxyManagerHandler.py +8 -6
- DIRAC/FrameworkSystem/Utilities/MonitoringUtilities.py +2 -19
- DIRAC/FrameworkSystem/Utilities/TokenManagementUtilities.py +3 -2
- DIRAC/FrameworkSystem/Utilities/diracx.py +36 -14
- DIRAC/FrameworkSystem/private/authorization/AuthServer.py +2 -2
- DIRAC/FrameworkSystem/scripts/dirac_admin_update_pilot.py +18 -11
- DIRAC/FrameworkSystem/scripts/dirac_login.py +2 -2
- DIRAC/FrameworkSystem/scripts/dirac_proxy_init.py +7 -8
- DIRAC/Interfaces/API/Dirac.py +27 -15
- DIRAC/Interfaces/API/DiracAdmin.py +45 -17
- DIRAC/Interfaces/API/Job.py +9 -13
- DIRAC/Interfaces/scripts/dirac_admin_allow_site.py +12 -18
- DIRAC/Interfaces/scripts/dirac_admin_ban_site.py +12 -10
- DIRAC/Interfaces/scripts/dirac_admin_get_site_mask.py +4 -13
- DIRAC/Interfaces/scripts/dirac_admin_reset_job.py +3 -6
- DIRAC/Interfaces/scripts/dirac_wms_job_parameters.py +0 -1
- DIRAC/MonitoringSystem/Client/Types/WMSHistory.py +4 -0
- DIRAC/MonitoringSystem/Client/WebAppClient.py +26 -0
- DIRAC/MonitoringSystem/ConfigTemplate.cfg +9 -0
- DIRAC/MonitoringSystem/DB/MonitoringDB.py +6 -25
- DIRAC/MonitoringSystem/Service/MonitoringHandler.py +0 -33
- DIRAC/MonitoringSystem/Service/WebAppHandler.py +599 -0
- DIRAC/MonitoringSystem/private/MainReporter.py +0 -3
- DIRAC/ProductionSystem/DB/ProductionDB.sql +4 -4
- DIRAC/ProductionSystem/scripts/dirac_prod_get.py +2 -2
- DIRAC/ProductionSystem/scripts/dirac_prod_get_all.py +2 -2
- DIRAC/ProductionSystem/scripts/dirac_prod_get_trans.py +2 -3
- DIRAC/RequestManagementSystem/Agent/RequestExecutingAgent.py +8 -6
- DIRAC/RequestManagementSystem/Agent/RequestOperations/ForwardDISET.py +2 -14
- DIRAC/RequestManagementSystem/Client/ReqClient.py +66 -13
- DIRAC/RequestManagementSystem/ConfigTemplate.cfg +6 -6
- DIRAC/RequestManagementSystem/DB/RequestDB.py +10 -5
- DIRAC/RequestManagementSystem/DB/test/RMSTestScenari.py +2 -0
- DIRAC/RequestManagementSystem/private/RequestValidator.py +40 -46
- DIRAC/ResourceStatusSystem/Client/SiteStatus.py +4 -2
- DIRAC/ResourceStatusSystem/Command/FreeDiskSpaceCommand.py +3 -1
- DIRAC/ResourceStatusSystem/DB/ResourceManagementDB.py +8 -8
- DIRAC/ResourceStatusSystem/DB/ResourceStatusDB.py +2 -2
- DIRAC/ResourceStatusSystem/Utilities/CSHelpers.py +2 -31
- DIRAC/ResourceStatusSystem/scripts/dirac_rss_set_status.py +30 -12
- DIRAC/Resources/Catalog/RucioFileCatalogClient.py +195 -1
- DIRAC/Resources/Catalog/test/Test_RucioFileCatalogClient.py +181 -0
- DIRAC/Resources/Computing/AREXComputingElement.py +25 -8
- DIRAC/Resources/Computing/BatchSystems/Condor.py +126 -108
- DIRAC/Resources/Computing/BatchSystems/SLURM.py +5 -1
- DIRAC/Resources/Computing/BatchSystems/test/Test_SLURM.py +46 -0
- DIRAC/Resources/Computing/ComputingElement.py +1 -1
- DIRAC/Resources/Computing/HTCondorCEComputingElement.py +44 -44
- DIRAC/Resources/Computing/InProcessComputingElement.py +4 -2
- DIRAC/Resources/Computing/LocalComputingElement.py +1 -18
- DIRAC/Resources/Computing/SSHBatchComputingElement.py +1 -17
- DIRAC/Resources/Computing/SSHComputingElement.py +1 -18
- DIRAC/Resources/Computing/SingularityComputingElement.py +19 -5
- DIRAC/Resources/Computing/test/Test_HTCondorCEComputingElement.py +67 -49
- DIRAC/Resources/Computing/test/Test_PoolComputingElement.py +2 -1
- DIRAC/Resources/IdProvider/CheckInIdProvider.py +13 -0
- DIRAC/Resources/IdProvider/IdProviderFactory.py +11 -3
- DIRAC/Resources/MessageQueue/StompMQConnector.py +1 -1
- DIRAC/Resources/Storage/GFAL2_StorageBase.py +24 -15
- DIRAC/Resources/Storage/OccupancyPlugins/WLCGAccountingHTTPJson.py +1 -3
- DIRAC/Resources/Storage/StorageBase.py +4 -2
- DIRAC/Resources/Storage/StorageElement.py +6 -7
- DIRAC/StorageManagementSystem/DB/StorageManagementDB.sql +2 -2
- DIRAC/TransformationSystem/Agent/TaskManagerAgentBase.py +10 -16
- DIRAC/TransformationSystem/Agent/TransformationAgent.py +22 -1
- DIRAC/TransformationSystem/Agent/TransformationCleaningAgent.py +16 -16
- DIRAC/TransformationSystem/Client/TaskManager.py +2 -4
- DIRAC/TransformationSystem/Client/Transformation.py +6 -7
- DIRAC/TransformationSystem/Client/TransformationClient.py +21 -11
- DIRAC/TransformationSystem/Client/Utilities.py +9 -0
- DIRAC/TransformationSystem/DB/TransformationDB.py +11 -14
- DIRAC/TransformationSystem/DB/TransformationDB.sql +9 -9
- DIRAC/TransformationSystem/Service/TransformationManagerHandler.py +0 -333
- DIRAC/TransformationSystem/Utilities/ReplicationCLIParameters.py +3 -3
- DIRAC/TransformationSystem/Utilities/TransformationInfo.py +7 -5
- DIRAC/TransformationSystem/scripts/dirac_production_runjoblocal.py +2 -4
- DIRAC/TransformationSystem/test/Test_TransformationInfo.py +22 -15
- DIRAC/TransformationSystem/test/Test_replicationTransformation.py +5 -6
- DIRAC/Workflow/Modules/test/Test_Modules.py +5 -0
- DIRAC/WorkloadManagementSystem/Agent/JobAgent.py +38 -26
- DIRAC/WorkloadManagementSystem/Agent/JobCleaningAgent.py +12 -8
- DIRAC/WorkloadManagementSystem/Agent/PilotSyncAgent.py +4 -3
- DIRAC/WorkloadManagementSystem/Agent/PushJobAgent.py +13 -13
- DIRAC/WorkloadManagementSystem/Agent/SiteDirector.py +18 -14
- DIRAC/WorkloadManagementSystem/Agent/StalledJobAgent.py +18 -51
- DIRAC/WorkloadManagementSystem/Agent/StatesAccountingAgent.py +41 -1
- DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_JobAgent.py +45 -4
- DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_JobCleaningAgent.py +7 -9
- DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_PushJobAgent.py +1 -0
- DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_SiteDirector.py +9 -2
- DIRAC/WorkloadManagementSystem/Agent/test/Test_Agent_StalledJobAgent.py +4 -5
- DIRAC/WorkloadManagementSystem/Client/DownloadInputData.py +9 -9
- DIRAC/WorkloadManagementSystem/Client/InputDataResolution.py +6 -6
- DIRAC/WorkloadManagementSystem/Client/JobMonitoringClient.py +10 -11
- DIRAC/WorkloadManagementSystem/Client/JobReport.py +1 -1
- DIRAC/WorkloadManagementSystem/Client/JobState/CachedJobState.py +3 -0
- DIRAC/WorkloadManagementSystem/Client/JobState/JobManifest.py +32 -261
- DIRAC/WorkloadManagementSystem/Client/JobState/JobState.py +6 -0
- DIRAC/WorkloadManagementSystem/Client/JobStateUpdateClient.py +3 -0
- DIRAC/WorkloadManagementSystem/Client/JobStatus.py +8 -152
- DIRAC/WorkloadManagementSystem/Client/PoolXMLSlice.py +12 -19
- DIRAC/WorkloadManagementSystem/Client/SandboxStoreClient.py +25 -38
- DIRAC/WorkloadManagementSystem/Client/WMSClient.py +2 -3
- DIRAC/WorkloadManagementSystem/Client/test/Test_Client_DownloadInputData.py +29 -0
- DIRAC/WorkloadManagementSystem/ConfigTemplate.cfg +4 -8
- DIRAC/WorkloadManagementSystem/DB/JobDB.py +89 -132
- DIRAC/WorkloadManagementSystem/DB/JobDB.sql +8 -8
- DIRAC/WorkloadManagementSystem/DB/JobDBUtils.py +18 -147
- DIRAC/WorkloadManagementSystem/DB/JobLoggingDB.py +19 -6
- DIRAC/WorkloadManagementSystem/DB/JobParametersDB.py +9 -9
- DIRAC/WorkloadManagementSystem/DB/PilotAgentsDB.py +16 -5
- DIRAC/WorkloadManagementSystem/DB/PilotAgentsDB.sql +3 -3
- DIRAC/WorkloadManagementSystem/DB/SandboxMetadataDB.py +44 -82
- DIRAC/WorkloadManagementSystem/DB/StatusUtils.py +125 -0
- DIRAC/WorkloadManagementSystem/DB/tests/Test_JobDB.py +1 -1
- DIRAC/WorkloadManagementSystem/DB/tests/Test_StatusUtils.py +28 -0
- DIRAC/WorkloadManagementSystem/Executor/JobSanity.py +5 -4
- DIRAC/WorkloadManagementSystem/Executor/JobScheduling.py +4 -0
- DIRAC/WorkloadManagementSystem/FutureClient/JobStateUpdateClient.py +75 -33
- DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapper.py +22 -11
- DIRAC/WorkloadManagementSystem/JobWrapper/JobWrapperTemplate.py +9 -10
- DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapper.py +60 -10
- DIRAC/WorkloadManagementSystem/JobWrapper/test/Test_JobWrapperTemplate.py +4 -0
- DIRAC/WorkloadManagementSystem/Service/JobManagerHandler.py +33 -154
- DIRAC/WorkloadManagementSystem/Service/JobMonitoringHandler.py +5 -323
- DIRAC/WorkloadManagementSystem/Service/JobStateUpdateHandler.py +0 -16
- DIRAC/WorkloadManagementSystem/Service/PilotManagerHandler.py +6 -103
- DIRAC/WorkloadManagementSystem/Service/SandboxStoreHandler.py +7 -53
- DIRAC/WorkloadManagementSystem/Service/WMSAdministratorHandler.py +16 -79
- DIRAC/WorkloadManagementSystem/Service/WMSUtilities.py +4 -18
- DIRAC/WorkloadManagementSystem/Utilities/JobModel.py +28 -209
- DIRAC/WorkloadManagementSystem/Utilities/JobParameters.py +65 -3
- DIRAC/WorkloadManagementSystem/Utilities/JobStatusUtility.py +2 -64
- DIRAC/WorkloadManagementSystem/Utilities/ParametricJob.py +7 -171
- DIRAC/WorkloadManagementSystem/Utilities/PilotCStoJSONSynchronizer.py +73 -7
- DIRAC/WorkloadManagementSystem/Utilities/PilotWrapper.py +41 -11
- DIRAC/WorkloadManagementSystem/Utilities/RemoteRunner.py +16 -0
- DIRAC/WorkloadManagementSystem/Utilities/Utils.py +36 -1
- DIRAC/WorkloadManagementSystem/Utilities/jobAdministration.py +15 -0
- DIRAC/WorkloadManagementSystem/Utilities/test/Test_JobModel.py +1 -15
- DIRAC/WorkloadManagementSystem/Utilities/test/Test_ParametricJob.py +45 -128
- DIRAC/WorkloadManagementSystem/Utilities/test/Test_PilotWrapper.py +16 -0
- DIRAC/WorkloadManagementSystem/scripts/dirac_jobexec.py +7 -2
- DIRAC/WorkloadManagementSystem/scripts/dirac_wms_pilot_job_info.py +1 -1
- DIRAC/__init__.py +62 -60
- DIRAC/tests/Utilities/testJobDefinitions.py +22 -28
- {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/METADATA +8 -5
- {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/RECORD +229 -228
- {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/WHEEL +1 -1
- {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/entry_points.txt +0 -3
- DIRAC/Core/Utilities/test/Test_List.py +0 -150
- DIRAC/Core/Utilities/test/Test_Time.py +0 -88
- DIRAC/Resources/Computing/PilotBundle.py +0 -70
- DIRAC/TransformationSystem/scripts/dirac_transformation_archive.py +0 -30
- DIRAC/TransformationSystem/scripts/dirac_transformation_clean.py +0 -30
- DIRAC/TransformationSystem/scripts/dirac_transformation_remove_output.py +0 -30
- DIRAC/WorkloadManagementSystem/Utilities/test/Test_JobManager.py +0 -58
- {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info/licenses}/LICENSE +0 -0
- {DIRAC-9.0.0a42.dist-info → dirac-9.0.7.dist-info}/top_level.txt +0 -0
|
@@ -17,6 +17,7 @@ def main():
|
|
|
17
17
|
remove = False
|
|
18
18
|
site = ""
|
|
19
19
|
mute = False
|
|
20
|
+
userName = ""
|
|
20
21
|
|
|
21
22
|
Script.registerSwitch("r", "AllowRead", " Allow only reading from the storage element")
|
|
22
23
|
Script.registerSwitch("w", "AllowWrite", " Allow only writing to the storage element")
|
|
@@ -25,6 +26,7 @@ def main():
|
|
|
25
26
|
Script.registerSwitch("a", "All", " Allow all access to the storage element")
|
|
26
27
|
Script.registerSwitch("m", "Mute", " Do not send email")
|
|
27
28
|
Script.registerSwitch("S:", "Site=", " Allow all SEs associated to site")
|
|
29
|
+
Script.registerSwitch("t:", "tokenOwner=", " Optional Name of the token owner")
|
|
28
30
|
# Registering arguments will automatically add their description to the help menu
|
|
29
31
|
Script.registerArgument(["seGroupList: list of SEs or comma-separated SEs"])
|
|
30
32
|
|
|
@@ -48,6 +50,8 @@ def main():
|
|
|
48
50
|
mute = True
|
|
49
51
|
if switch[0].lower() in ("s", "site"):
|
|
50
52
|
site = switch[1]
|
|
53
|
+
if switch[0] in ("t", "tokenOwner"):
|
|
54
|
+
userName = switch[1]
|
|
51
55
|
|
|
52
56
|
# imports
|
|
53
57
|
from DIRAC import gLogger
|
|
@@ -69,15 +73,16 @@ def main():
|
|
|
69
73
|
ses = resolveSEGroup(ses)
|
|
70
74
|
diracAdmin = DiracAdmin()
|
|
71
75
|
|
|
72
|
-
res = getProxyInfo()
|
|
73
|
-
if not res["OK"]:
|
|
74
|
-
gLogger.error("Failed to get proxy information", res["Message"])
|
|
75
|
-
DIRAC.exit(2)
|
|
76
|
-
|
|
77
|
-
userName = res["Value"].get("username")
|
|
78
76
|
if not userName:
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
res = getProxyInfo()
|
|
78
|
+
if not res["OK"]:
|
|
79
|
+
gLogger.error("Failed to get proxy information", res["Message"])
|
|
80
|
+
DIRAC.exit(2)
|
|
81
|
+
|
|
82
|
+
userName = res["Value"].get("username")
|
|
83
|
+
if not userName:
|
|
84
|
+
gLogger.error("Failed to get username for proxy")
|
|
85
|
+
DIRAC.exit(2)
|
|
81
86
|
|
|
82
87
|
if site:
|
|
83
88
|
res = getSites()
|
|
@@ -18,6 +18,7 @@ def main():
|
|
|
18
18
|
remove = True
|
|
19
19
|
sites = []
|
|
20
20
|
mute = False
|
|
21
|
+
userName = ""
|
|
21
22
|
|
|
22
23
|
Script.registerSwitch("r", "BanRead", " Ban only reading from the storage element")
|
|
23
24
|
Script.registerSwitch("w", "BanWrite", " Ban writing to the storage element")
|
|
@@ -28,6 +29,7 @@ def main():
|
|
|
28
29
|
Script.registerSwitch(
|
|
29
30
|
"S:", "Site=", " Ban all SEs associate to site (note that if writing is allowed, check is always allowed)"
|
|
30
31
|
)
|
|
32
|
+
Script.registerSwitch("t:", "tokenOwner=", " Optional Name of the token owner")
|
|
31
33
|
# Registering arguments will automatically add their description to the help menu
|
|
32
34
|
Script.registerArgument(["seGroupList: list of SEs or comma-separated SEs"])
|
|
33
35
|
|
|
@@ -56,6 +58,8 @@ def main():
|
|
|
56
58
|
mute = True
|
|
57
59
|
if switch[0].lower() in ("s", "site"):
|
|
58
60
|
sites = switch[1].split(",")
|
|
61
|
+
if switch[0] in ("t", "tokenOwner"):
|
|
62
|
+
userName = switch[1]
|
|
59
63
|
|
|
60
64
|
# from DIRAC.ConfigurationSystem.Client.CSAPI import CSAPI
|
|
61
65
|
from DIRAC import gLogger
|
|
@@ -68,15 +72,16 @@ def main():
|
|
|
68
72
|
ses = resolveSEGroup(ses)
|
|
69
73
|
diracAdmin = DiracAdmin()
|
|
70
74
|
|
|
71
|
-
res = getProxyInfo()
|
|
72
|
-
if not res["OK"]:
|
|
73
|
-
gLogger.error("Failed to get proxy information", res["Message"])
|
|
74
|
-
DIRAC.exit(2)
|
|
75
|
-
|
|
76
|
-
userName = res["Value"].get("username")
|
|
77
75
|
if not userName:
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
res = getProxyInfo()
|
|
77
|
+
if not res["OK"]:
|
|
78
|
+
gLogger.error("Failed to get proxy information", res["Message"])
|
|
79
|
+
DIRAC.exit(2)
|
|
80
|
+
|
|
81
|
+
userName = res["Value"].get("username")
|
|
82
|
+
if not userName:
|
|
83
|
+
gLogger.error("Failed to get username for proxy")
|
|
84
|
+
DIRAC.exit(2)
|
|
80
85
|
|
|
81
86
|
for site in sites:
|
|
82
87
|
res = DMSHelpers().getSEsForSite(site)
|
|
@@ -41,6 +41,7 @@ class CreateMovingRequest:
|
|
|
41
41
|
self.flags = [
|
|
42
42
|
("C", "CheckMigration", "Ensure the LFNs are migrated to tape before removing any replicas"),
|
|
43
43
|
("X", "Execute", "Put Requests, else dryrun"),
|
|
44
|
+
("", "SourceOnly", "Only treat files that are already at the Source-SE"),
|
|
44
45
|
]
|
|
45
46
|
self.registerSwitchesAndParseCommandLine()
|
|
46
47
|
self.getLFNList()
|
|
@@ -208,6 +209,7 @@ class CreateMovingRequest:
|
|
|
208
209
|
|
|
209
210
|
replicate = Operation()
|
|
210
211
|
replicate.Type = "ReplicateAndRegister"
|
|
212
|
+
replicate.SourceSE = ",".join(self.switches.get("SourceSE", []))
|
|
211
213
|
replicate.TargetSE = self.switches.get("TargetSE")
|
|
212
214
|
self.addLFNs(replicate, lfnChunk, addPFN=True)
|
|
213
215
|
request.addOperation(replicate)
|
|
@@ -177,7 +177,6 @@ def main():
|
|
|
177
177
|
for src, dst in ((x, y) for x in fromSE for y in targetSE):
|
|
178
178
|
if ftsTab:
|
|
179
179
|
try:
|
|
180
|
-
# breakpoint()
|
|
181
180
|
fts3TpcProto = fts3Plugin.selectTPCProtocols(sourceSEName=ses[src].name, destSEName=ses[dst].name)
|
|
182
181
|
res = ses[dst].generateTransferURLsBetweenSEs(lfn, ses[src], fts3TpcProto)
|
|
183
182
|
except ValueError as e:
|
|
@@ -143,13 +143,9 @@ class BundleDeliveryClient(Client):
|
|
|
143
143
|
if "X509_CERT_DIR" in os.environ:
|
|
144
144
|
X509_CERT_DIR = os.environ["X509_CERT_DIR"]
|
|
145
145
|
del os.environ["X509_CERT_DIR"]
|
|
146
|
-
casLocation = Locations.getCAsLocation()
|
|
147
|
-
if not casLocation:
|
|
148
|
-
casLocation = Locations.getCAsDefaultLocation()
|
|
149
|
-
result = self.syncDir("CAs", casLocation)
|
|
150
146
|
if X509_CERT_DIR:
|
|
151
147
|
os.environ["X509_CERT_DIR"] = X509_CERT_DIR
|
|
152
|
-
return
|
|
148
|
+
return self.syncDir("CAs", Locations.getCAsLocation())
|
|
153
149
|
|
|
154
150
|
def syncCRLs(self):
|
|
155
151
|
"""Synchronize CRLs
|
|
@@ -160,10 +156,9 @@ class BundleDeliveryClient(Client):
|
|
|
160
156
|
if "X509_CERT_DIR" in os.environ:
|
|
161
157
|
X509_CERT_DIR = os.environ["X509_CERT_DIR"]
|
|
162
158
|
del os.environ["X509_CERT_DIR"]
|
|
163
|
-
result = self.syncDir("CRLs", Locations.getCAsLocation())
|
|
164
159
|
if X509_CERT_DIR:
|
|
165
160
|
os.environ["X509_CERT_DIR"] = X509_CERT_DIR
|
|
166
|
-
return
|
|
161
|
+
return self.syncDir("CRLs", Locations.getCAsLocation())
|
|
167
162
|
|
|
168
163
|
def getCAs(self):
|
|
169
164
|
"""This method can be used to create the CAs. If the file can not be created,
|
|
@@ -60,7 +60,6 @@ from collections import defaultdict
|
|
|
60
60
|
|
|
61
61
|
import importlib_metadata as metadata
|
|
62
62
|
import importlib_resources
|
|
63
|
-
import MySQLdb
|
|
64
63
|
from diraccfg import CFG
|
|
65
64
|
from prompt_toolkit import prompt
|
|
66
65
|
|
|
@@ -69,7 +68,6 @@ from DIRAC import gConfig, gLogger, rootPath
|
|
|
69
68
|
from DIRAC.ConfigurationSystem.Client import PathFinder
|
|
70
69
|
from DIRAC.ConfigurationSystem.Client.CSAPI import CSAPI
|
|
71
70
|
from DIRAC.ConfigurationSystem.Client.Helpers import (
|
|
72
|
-
CSGlobals,
|
|
73
71
|
cfgInstallPath,
|
|
74
72
|
cfgInstallSection,
|
|
75
73
|
cfgPath,
|
|
@@ -85,6 +83,7 @@ from DIRAC.Core.Security.Properties import (
|
|
|
85
83
|
PRODUCTION_MANAGEMENT,
|
|
86
84
|
PROXY_MANAGEMENT,
|
|
87
85
|
SERVICE_ADMINISTRATOR,
|
|
86
|
+
SITE_MANAGER,
|
|
88
87
|
TRUSTED_HOST,
|
|
89
88
|
)
|
|
90
89
|
from DIRAC.Core.Utilities.Extensions import (
|
|
@@ -96,7 +95,6 @@ from DIRAC.Core.Utilities.Extensions import (
|
|
|
96
95
|
findServices,
|
|
97
96
|
)
|
|
98
97
|
from DIRAC.Core.Utilities.File import mkDir, mkLink
|
|
99
|
-
from DIRAC.Core.Utilities.MySQL import MySQL
|
|
100
98
|
from DIRAC.Core.Utilities.PrettyPrint import printTable
|
|
101
99
|
from DIRAC.Core.Utilities.ReturnValues import S_ERROR, S_OK
|
|
102
100
|
from DIRAC.Core.Utilities.Subprocess import systemCall
|
|
@@ -432,6 +430,8 @@ class ComponentInstaller:
|
|
|
432
430
|
defaultHostProperties = [
|
|
433
431
|
TRUSTED_HOST,
|
|
434
432
|
CS_ADMINISTRATOR,
|
|
433
|
+
SERVICE_ADMINISTRATOR,
|
|
434
|
+
SITE_MANAGER,
|
|
435
435
|
JOB_ADMINISTRATOR,
|
|
436
436
|
FULL_DELEGATION,
|
|
437
437
|
PROXY_MANAGEMENT,
|
|
@@ -2053,6 +2053,8 @@ class ComponentInstaller:
|
|
|
2053
2053
|
"""
|
|
2054
2054
|
Install requested DB in MySQL server
|
|
2055
2055
|
"""
|
|
2056
|
+
import MySQLdb
|
|
2057
|
+
|
|
2056
2058
|
dbName = MySQLdb.escape_string(dbName.encode()).decode()
|
|
2057
2059
|
if not self.mysqlRootPwd:
|
|
2058
2060
|
rootPwdPath = cfgInstallPath("Database", "RootPwd")
|
|
@@ -2106,7 +2108,8 @@ class ComponentInstaller:
|
|
|
2106
2108
|
|
|
2107
2109
|
perms = (
|
|
2108
2110
|
"SELECT,INSERT,LOCK TABLES,UPDATE,DELETE,CREATE,DROP,ALTER,REFERENCES,"
|
|
2109
|
-
"CREATE VIEW,SHOW VIEW,INDEX,TRIGGER,ALTER ROUTINE,CREATE ROUTINE"
|
|
2111
|
+
"CREATE VIEW,SHOW VIEW,INDEX,TRIGGER,ALTER ROUTINE,CREATE ROUTINE,"
|
|
2112
|
+
"CREATE TEMPORARY TABLES"
|
|
2110
2113
|
)
|
|
2111
2114
|
cmd = f"GRANT {perms} ON `{dbName}`.* TO '{self.mysqlUser}'@'%'"
|
|
2112
2115
|
result = self.execMySQL(cmd)
|
|
@@ -2199,6 +2202,8 @@ class ComponentInstaller:
|
|
|
2199
2202
|
"""
|
|
2200
2203
|
Execute MySQL Command
|
|
2201
2204
|
"""
|
|
2205
|
+
from DIRAC.Core.Utilities.MySQL import MySQL
|
|
2206
|
+
|
|
2202
2207
|
if not self.mysqlRootPwd:
|
|
2203
2208
|
return S_ERROR("MySQL root password is not defined")
|
|
2204
2209
|
if dbName not in self.db:
|
|
@@ -418,7 +418,7 @@ class ProxyManagerClient(metaclass=DIRACSingleton.DIRACSingleton):
|
|
|
418
418
|
proxyToConnect=proxyToConnect,
|
|
419
419
|
)
|
|
420
420
|
|
|
421
|
-
def dumpProxyToFile(self, chain, destinationFile=None, requiredTimeLeft=600):
|
|
421
|
+
def dumpProxyToFile(self, chain, destinationFile=None, requiredTimeLeft=600, includeToken=True):
|
|
422
422
|
"""Dump a proxy to a file. It's cached so multiple calls won't generate extra files
|
|
423
423
|
|
|
424
424
|
:param X509Chain chain: proxy as a chain
|
|
@@ -442,7 +442,10 @@ class ProxyManagerClient(metaclass=DIRACSingleton.DIRACSingleton):
|
|
|
442
442
|
filename = retVal["Value"]
|
|
443
443
|
if not (result := chain.getDIRACGroup())["OK"]:
|
|
444
444
|
return result
|
|
445
|
-
if
|
|
445
|
+
if (
|
|
446
|
+
includeToken
|
|
447
|
+
and not (result := addTokenToPEM(filename, result["Value"]))["OK"] # pylint: disable=unsubscriptable-object
|
|
448
|
+
):
|
|
446
449
|
return result
|
|
447
450
|
self.__filesCache.add(cHash, chain.getRemainingSecs()["Value"], filename)
|
|
448
451
|
return S_OK(filename)
|
|
@@ -11,7 +11,6 @@ import sys
|
|
|
11
11
|
import time
|
|
12
12
|
|
|
13
13
|
from DIRAC import gConfig, gLogger
|
|
14
|
-
from DIRAC.ConfigurationSystem.Client.Helpers import CSGlobals
|
|
15
14
|
from DIRAC.Core.Base.CLI import CLI, colorize
|
|
16
15
|
from DIRAC.Core.Security.ProxyInfo import getProxyInfo
|
|
17
16
|
from DIRAC.Core.Utilities import List
|
|
@@ -623,6 +622,11 @@ class SystemAdministratorClientCLI(CLI):
|
|
|
623
622
|
install agent <system> <agent> [-m <ModuleName>] [-p <Option>=<Value>] [-p <Option>=<Value>] ...
|
|
624
623
|
install executor <system> <executor> [-m <ModuleName>] [-p <Option>=<Value>] [-p <Option>=<Value>] ...
|
|
625
624
|
"""
|
|
625
|
+
result = getProxyInfo()
|
|
626
|
+
if not result["OK"]:
|
|
627
|
+
self._errMsg(result["Message"])
|
|
628
|
+
user = result["Value"]["username"]
|
|
629
|
+
|
|
626
630
|
argss = args.split()
|
|
627
631
|
hostSetup = extension = None
|
|
628
632
|
if not argss:
|
|
@@ -673,7 +677,7 @@ class SystemAdministratorClientCLI(CLI):
|
|
|
673
677
|
|
|
674
678
|
if database != "InstalledComponentsDB":
|
|
675
679
|
result = MonitoringUtilities.monitorInstallation(
|
|
676
|
-
"DB", system.replace("System", ""), database, cpu=cpu, hostname=hostname
|
|
680
|
+
"DB", system.replace("System", ""), database, cpu=cpu, hostname=hostname, user=user
|
|
677
681
|
)
|
|
678
682
|
if not result["OK"]:
|
|
679
683
|
self._errMsg(result["Message"])
|
|
@@ -786,14 +790,14 @@ class SystemAdministratorClientCLI(CLI):
|
|
|
786
790
|
return
|
|
787
791
|
|
|
788
792
|
result = MonitoringUtilities.monitorInstallation(
|
|
789
|
-
"DB", system, "InstalledComponentsDB", cpu=cpu, hostname=hostname
|
|
793
|
+
"DB", system, "InstalledComponentsDB", cpu=cpu, hostname=hostname, user=user
|
|
790
794
|
)
|
|
791
795
|
if not result["OK"]:
|
|
792
796
|
self._errMsg(f"Error registering installation into database: {result['Message']}")
|
|
793
797
|
return
|
|
794
798
|
|
|
795
799
|
result = MonitoringUtilities.monitorInstallation(
|
|
796
|
-
option, system, component, module, cpu=cpu, hostname=hostname
|
|
800
|
+
option, system, component, module, cpu=cpu, hostname=hostname, user=user
|
|
797
801
|
)
|
|
798
802
|
if not result["OK"]:
|
|
799
803
|
self._errMsg(f"Error registering installation into database: {result['Message']}")
|
|
@@ -820,6 +824,7 @@ class SystemAdministratorClientCLI(CLI):
|
|
|
820
824
|
result = getProxyInfo()
|
|
821
825
|
if not result["OK"]:
|
|
822
826
|
self._errMsg(result["Message"])
|
|
827
|
+
user = result["Value"]["username"]
|
|
823
828
|
|
|
824
829
|
option = argss[0]
|
|
825
830
|
if option == "db":
|
|
@@ -842,7 +847,7 @@ class SystemAdministratorClientCLI(CLI):
|
|
|
842
847
|
self._errMsg(result["Message"])
|
|
843
848
|
return
|
|
844
849
|
system = result["Value"][component]["System"]
|
|
845
|
-
result = MonitoringUtilities.monitorUninstallation(system, component, hostname=hostname, cpu=cpu)
|
|
850
|
+
result = MonitoringUtilities.monitorUninstallation(system, component, hostname=hostname, cpu=cpu, user=user)
|
|
846
851
|
if not result["OK"]:
|
|
847
852
|
self._errMsg(result["Message"])
|
|
848
853
|
return
|
|
@@ -937,7 +942,7 @@ class SystemAdministratorClientCLI(CLI):
|
|
|
937
942
|
else:
|
|
938
943
|
cpu = result["Value"]["CPUModel"]
|
|
939
944
|
hostname = self.host
|
|
940
|
-
result = MonitoringUtilities.monitorUninstallation(system, component, hostname=hostname, cpu=cpu)
|
|
945
|
+
result = MonitoringUtilities.monitorUninstallation(system, component, hostname=hostname, cpu=cpu, user=user)
|
|
941
946
|
if not result["OK"]:
|
|
942
947
|
return result
|
|
943
948
|
|
|
@@ -167,6 +167,7 @@ Services
|
|
|
167
167
|
componentExists = authenticated
|
|
168
168
|
getComponents = authenticated
|
|
169
169
|
hostExists = authenticated
|
|
170
|
+
installationExists = authenticated
|
|
170
171
|
getHosts = authenticated
|
|
171
172
|
installationExists = authenticated
|
|
172
173
|
getInstallations = authenticated
|
|
@@ -184,6 +185,7 @@ Services
|
|
|
184
185
|
componentExists = authenticated
|
|
185
186
|
getComponents = authenticated
|
|
186
187
|
hostExists = authenticated
|
|
188
|
+
installationExists = authenticated
|
|
187
189
|
getHosts = authenticated
|
|
188
190
|
installationExists = authenticated
|
|
189
191
|
getInstallations = authenticated
|
|
@@ -22,7 +22,7 @@ Model = declarative_base()
|
|
|
22
22
|
|
|
23
23
|
class RefreshToken(Model):
|
|
24
24
|
__tablename__ = "RefreshToken"
|
|
25
|
-
__table_args__ = {"mysql_engine": "InnoDB", "mysql_charset": "
|
|
25
|
+
__table_args__ = {"mysql_engine": "InnoDB", "mysql_charset": "utf8mb4"}
|
|
26
26
|
jti = Column(String(255), nullable=False, primary_key=True)
|
|
27
27
|
issued_at = Column(Integer, nullable=False, default=0)
|
|
28
28
|
access_token = Column(Text, nullable=False)
|
|
@@ -31,7 +31,7 @@ class RefreshToken(Model):
|
|
|
31
31
|
|
|
32
32
|
class JWK(Model):
|
|
33
33
|
__tablename__ = "JWK"
|
|
34
|
-
__table_args__ = {"mysql_engine": "InnoDB", "mysql_charset": "
|
|
34
|
+
__table_args__ = {"mysql_engine": "InnoDB", "mysql_charset": "utf8mb4"}
|
|
35
35
|
kid = Column(String(255), unique=True, primary_key=True, nullable=False)
|
|
36
36
|
key = Column(Text, nullable=False)
|
|
37
37
|
expires_at = Column(Integer, nullable=False, default=0)
|
|
@@ -39,7 +39,7 @@ class JWK(Model):
|
|
|
39
39
|
|
|
40
40
|
class AuthSession(Model):
|
|
41
41
|
__tablename__ = "AuthSession"
|
|
42
|
-
__table_args__ = {"mysql_engine": "InnoDB", "mysql_charset": "
|
|
42
|
+
__table_args__ = {"mysql_engine": "InnoDB", "mysql_charset": "utf8mb4"}
|
|
43
43
|
id = Column(String(255), unique=True, primary_key=True, nullable=False)
|
|
44
44
|
uri = Column(String(255))
|
|
45
45
|
state = Column(String(255))
|
|
@@ -27,7 +27,7 @@ class Component(componentsBase):
|
|
|
27
27
|
"""
|
|
28
28
|
|
|
29
29
|
__tablename__ = "Components"
|
|
30
|
-
__table_args__ = {"mysql_engine": "InnoDB", "mysql_charset": "
|
|
30
|
+
__table_args__ = {"mysql_engine": "InnoDB", "mysql_charset": "utf8mb4"}
|
|
31
31
|
|
|
32
32
|
componentID = Column("ComponentID", Integer, primary_key=True)
|
|
33
33
|
system = Column("DIRACSystem", String(32), nullable=False)
|
|
@@ -87,7 +87,7 @@ class Host(componentsBase):
|
|
|
87
87
|
"""
|
|
88
88
|
|
|
89
89
|
__tablename__ = "Hosts"
|
|
90
|
-
__table_args__ = {"mysql_engine": "InnoDB", "mysql_charset": "
|
|
90
|
+
__table_args__ = {"mysql_engine": "InnoDB", "mysql_charset": "utf8mb4"}
|
|
91
91
|
|
|
92
92
|
hostID = Column("HostID", Integer, primary_key=True)
|
|
93
93
|
hostName = Column("HostName", String(32), nullable=False)
|
|
@@ -138,7 +138,7 @@ class InstalledComponent(componentsBase):
|
|
|
138
138
|
"""
|
|
139
139
|
|
|
140
140
|
__tablename__ = "InstalledComponents"
|
|
141
|
-
__table_args__ = {"mysql_engine": "InnoDB", "mysql_charset": "
|
|
141
|
+
__table_args__ = {"mysql_engine": "InnoDB", "mysql_charset": "utf8mb4"}
|
|
142
142
|
|
|
143
143
|
componentID = Column("ComponentID", Integer, ForeignKey("Components.ComponentID"), primary_key=True)
|
|
144
144
|
hostID = Column("HostID", Integer, ForeignKey("Hosts.HostID"), primary_key=True)
|
|
@@ -217,7 +217,7 @@ class HostLogging(componentsBase):
|
|
|
217
217
|
"""
|
|
218
218
|
|
|
219
219
|
__tablename__ = "HostLogging"
|
|
220
|
-
__table_args__ = {"mysql_engine": "InnoDB", "mysql_charset": "
|
|
220
|
+
__table_args__ = {"mysql_engine": "InnoDB", "mysql_charset": "utf8mb4"}
|
|
221
221
|
|
|
222
222
|
hostName = Column("HostName", String(32), nullable=False, primary_key=True)
|
|
223
223
|
# status
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
* ProxyDB_Log -- table with logs.
|
|
10
10
|
"""
|
|
11
11
|
import textwrap
|
|
12
|
+
from threading import Lock
|
|
13
|
+
|
|
14
|
+
from cachetools import TTLCache, cachedmethod
|
|
12
15
|
|
|
13
16
|
from DIRAC import S_ERROR, S_OK, gLogger
|
|
14
17
|
from DIRAC.ConfigurationSystem.Client.Helpers import Registry
|
|
@@ -22,6 +25,10 @@ from DIRAC.Resources.ProxyProvider.ProxyProviderFactory import ProxyProviderFact
|
|
|
22
25
|
|
|
23
26
|
DEFAULT_MAIL_FROM = "proxymanager@diracgrid.org"
|
|
24
27
|
|
|
28
|
+
# Module-level cache for getProxyStrength method (shared across ProxyDB instances)
|
|
29
|
+
_get_proxy_strength_cache = TTLCache(maxsize=1000, ttl=600)
|
|
30
|
+
_get_proxy_strength_lock = Lock()
|
|
31
|
+
|
|
25
32
|
|
|
26
33
|
class ProxyDB(DB):
|
|
27
34
|
NOTIFICATION_TIMES = [2592000, 1296000]
|
|
@@ -395,6 +402,7 @@ class ProxyDB(DB):
|
|
|
395
402
|
return S_ERROR(", ".join(errMsgs))
|
|
396
403
|
return result
|
|
397
404
|
|
|
405
|
+
@cachedmethod(lambda self: _get_proxy_strength_cache, lock=lambda self: _get_proxy_strength_lock)
|
|
398
406
|
def getProxyStrength(self, userDN, userGroup=None, vomsAttr=None):
|
|
399
407
|
"""Load the proxy in cache corresponding to the criteria, and check its strength
|
|
400
408
|
|
|
@@ -597,13 +605,13 @@ class ProxyDB(DB):
|
|
|
597
605
|
:return: S_OK(dict)/S_ERROR() -- dict contain attribute and VOMS VO
|
|
598
606
|
"""
|
|
599
607
|
if requiredVOMSAttribute:
|
|
600
|
-
return S_OK({"attribute": requiredVOMSAttribute, "
|
|
608
|
+
return S_OK({"attribute": requiredVOMSAttribute, "VO": Registry.getVOForGroup(userGroup)})
|
|
601
609
|
|
|
602
610
|
csVOMSMapping = Registry.getVOMSAttributeForGroup(userGroup)
|
|
603
611
|
if not csVOMSMapping:
|
|
604
612
|
return S_ERROR(f"No mapping defined for group {userGroup} in the CS")
|
|
605
613
|
|
|
606
|
-
return S_OK({"attribute": csVOMSMapping, "
|
|
614
|
+
return S_OK({"attribute": csVOMSMapping, "VO": Registry.getVOForGroup(userGroup)})
|
|
607
615
|
|
|
608
616
|
def getVOMSProxy(self, userDN, userGroup, requiredLifeTime=None, requestedVOMSAttr=None):
|
|
609
617
|
"""Get proxy string from the Proxy Repository for use with userDN
|
|
@@ -620,7 +628,7 @@ class ProxyDB(DB):
|
|
|
620
628
|
if not retVal["OK"]:
|
|
621
629
|
return retVal
|
|
622
630
|
vomsAttr = retVal["Value"]["attribute"]
|
|
623
|
-
vomsVO = retVal["Value"]["
|
|
631
|
+
vomsVO = retVal["Value"]["VO"]
|
|
624
632
|
|
|
625
633
|
# Look in the cache
|
|
626
634
|
retVal = self.__getPemAndTimeLeft(userDN, userGroup, vomsAttr)
|
|
@@ -24,7 +24,7 @@ class Token(Model, OAuth2TokenMixin):
|
|
|
24
24
|
"""This class describes token fields"""
|
|
25
25
|
|
|
26
26
|
__tablename__ = "Token"
|
|
27
|
-
__table_args__ = {"mysql_engine": "InnoDB", "mysql_charset": "
|
|
27
|
+
__table_args__ = {"mysql_engine": "InnoDB", "mysql_charset": "utf8mb4"}
|
|
28
28
|
# access_token too large for varchar(255)
|
|
29
29
|
# 767 bytes is the stated prefix limitation for InnoDB tables in MySQL version 5.6
|
|
30
30
|
# https://stackoverflow.com/questions/1827063/mysql-error-key-specification-without-a-key-length
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""ProxyManager is the implementation of the ProxyManagement service in the DISET framework
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
.. literalinclude:: ../ConfigTemplate.cfg
|
|
4
|
+
:start-after: ##BEGIN ProxyManager:
|
|
5
|
+
:end-before: ##END
|
|
6
|
+
:dedent: 2
|
|
7
|
+
:caption: ProxyManager options
|
|
8
8
|
"""
|
|
9
|
+
|
|
9
10
|
from DIRAC import S_ERROR, S_OK, gLogger
|
|
10
11
|
from DIRAC.ConfigurationSystem.Client.Helpers import Registry
|
|
11
12
|
from DIRAC.Core.DISET.RequestHandler import RequestHandler, getServiceOption
|
|
@@ -325,6 +326,7 @@ class ProxyManagerHandlerMixin:
|
|
|
325
326
|
credDict["group"],
|
|
326
327
|
set(credDict.get("groupProperties", []) + credDict.get("properties", [])),
|
|
327
328
|
expires_minutes=credDict["secondsLeft"] // 60 + 1,
|
|
329
|
+
source="ProxyManager",
|
|
328
330
|
)
|
|
329
331
|
|
|
330
332
|
|
|
@@ -6,10 +6,9 @@ import socket
|
|
|
6
6
|
|
|
7
7
|
from DIRAC import S_OK
|
|
8
8
|
from DIRAC.FrameworkSystem.Client.ComponentMonitoringClient import ComponentMonitoringClient
|
|
9
|
-
from DIRAC.Core.Security.ProxyInfo import getProxyInfo
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
def monitorInstallation(componentType, system, component, module=None, cpu=None, hostname=None):
|
|
11
|
+
def monitorInstallation(componentType, system, component, module=None, cpu=None, hostname=None, user=None):
|
|
13
12
|
"""
|
|
14
13
|
Register the installation of a component in the InstalledComponentsDB
|
|
15
14
|
"""
|
|
@@ -19,14 +18,6 @@ def monitorInstallation(componentType, system, component, module=None, cpu=None,
|
|
|
19
18
|
module = component
|
|
20
19
|
|
|
21
20
|
# Retrieve user installing the component
|
|
22
|
-
user = None
|
|
23
|
-
result = getProxyInfo()
|
|
24
|
-
if result["OK"]:
|
|
25
|
-
proxyInfo = result["Value"]
|
|
26
|
-
if "username" in proxyInfo:
|
|
27
|
-
user = proxyInfo["username"]
|
|
28
|
-
else:
|
|
29
|
-
return result
|
|
30
21
|
if not user:
|
|
31
22
|
user = "unknown"
|
|
32
23
|
|
|
@@ -61,21 +52,13 @@ def monitorInstallation(componentType, system, component, module=None, cpu=None,
|
|
|
61
52
|
return result
|
|
62
53
|
|
|
63
54
|
|
|
64
|
-
def monitorUninstallation(system, component, cpu=None, hostname=None):
|
|
55
|
+
def monitorUninstallation(system, component, cpu=None, hostname=None, user=None):
|
|
65
56
|
"""
|
|
66
57
|
Register the uninstallation of a component in the InstalledComponentsDB
|
|
67
58
|
"""
|
|
68
59
|
monitoringClient = ComponentMonitoringClient()
|
|
69
60
|
|
|
70
61
|
# Retrieve user uninstalling the component
|
|
71
|
-
user = None
|
|
72
|
-
result = getProxyInfo()
|
|
73
|
-
if result["OK"]:
|
|
74
|
-
proxyInfo = result["Value"]
|
|
75
|
-
if "username" in proxyInfo:
|
|
76
|
-
user = proxyInfo["username"]
|
|
77
|
-
else:
|
|
78
|
-
return result
|
|
79
62
|
if not user:
|
|
80
63
|
user = "unknown"
|
|
81
64
|
|
|
@@ -10,11 +10,12 @@ DEFAULT_RT_EXPIRATION_TIME = 24 * 3600
|
|
|
10
10
|
DEFAULT_AT_EXPIRATION_TIME = 1200
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def getIdProviderClient(userGroup: str, idProviderClientName: str = None):
|
|
13
|
+
def getIdProviderClient(userGroup: str, idProviderClientName: str = None, client_name_prefix: str = ""):
|
|
14
14
|
"""Get an IdProvider client
|
|
15
15
|
|
|
16
16
|
:param userGroup: group name
|
|
17
17
|
:param idProviderClientName: name of an identity provider in the DIRAC CS
|
|
18
|
+
:param client_name_prefix: prefix of the client in the CS options
|
|
18
19
|
"""
|
|
19
20
|
# Get IdProvider credentials from CS
|
|
20
21
|
if not idProviderClientName and userGroup:
|
|
@@ -23,7 +24,7 @@ def getIdProviderClient(userGroup: str, idProviderClientName: str = None):
|
|
|
23
24
|
return S_ERROR(f"The {userGroup} group belongs to the VO that is not tied to any Identity Provider.")
|
|
24
25
|
|
|
25
26
|
# Prepare the client instance of the appropriate IdP
|
|
26
|
-
return IdProviderFactory().getIdProvider(idProviderClientName)
|
|
27
|
+
return IdProviderFactory().getIdProvider(idProviderClientName, client_name_prefix=client_name_prefix)
|
|
27
28
|
|
|
28
29
|
|
|
29
30
|
def getCachedKey(
|
|
@@ -1,28 +1,40 @@
|
|
|
1
1
|
import requests
|
|
2
2
|
|
|
3
|
-
from cachetools import TTLCache, cached
|
|
3
|
+
from cachetools import TTLCache, LRUCache, cached
|
|
4
4
|
from cachetools.keys import hashkey
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from tempfile import NamedTemporaryFile
|
|
7
7
|
from typing import Any
|
|
8
|
+
from collections.abc import Generator
|
|
8
9
|
from DIRAC import gConfig
|
|
9
10
|
from DIRAC.ConfigurationSystem.Client.Helpers import Registry
|
|
10
|
-
|
|
11
|
+
from contextlib import contextmanager
|
|
11
12
|
|
|
12
13
|
from diracx.core.preferences import DiracxPreferences
|
|
13
14
|
|
|
14
15
|
from diracx.core.utils import write_credentials
|
|
15
16
|
|
|
16
17
|
from diracx.core.models import TokenResponse
|
|
17
|
-
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
from diracx.client.sync import SyncDiracClient
|
|
21
|
+
except ImportError:
|
|
22
|
+
# TODO: Remove this once diracx is tagged
|
|
23
|
+
from diracx.client import DiracClient as SyncDiracClient
|
|
18
24
|
|
|
19
25
|
# How long tokens are kept
|
|
20
26
|
DEFAULT_TOKEN_CACHE_TTL = 5 * 60
|
|
21
27
|
DEFAULT_TOKEN_CACHE_SIZE = 1024
|
|
22
28
|
|
|
29
|
+
legacy_exchange_session = requests.Session()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def get_token(
|
|
33
|
+
username: str, group: str, dirac_properties: set[str], *, expires_minutes: int | None = None, source: str = ""
|
|
34
|
+
):
|
|
35
|
+
"""Do a legacy exchange to get a DiracX access_token+refresh_token
|
|
23
36
|
|
|
24
|
-
|
|
25
|
-
"""Do a legacy exchange to get a DiracX access_token+refresh_token"""
|
|
37
|
+
The source parameter only purpose is to appear in the URL on diracx logs"""
|
|
26
38
|
diracxUrl = gConfig.getValue("/DiracX/URL")
|
|
27
39
|
if not diracxUrl:
|
|
28
40
|
raise ValueError("Missing mandatory /DiracX/URL configuration")
|
|
@@ -33,12 +45,13 @@ def get_token(username: str, group: str, dirac_properties: set[str], *, expires_
|
|
|
33
45
|
vo = Registry.getVOForGroup(group)
|
|
34
46
|
scopes = [f"vo:{vo}", f"group:{group}"] + [f"property:{prop}" for prop in dirac_properties]
|
|
35
47
|
|
|
36
|
-
r =
|
|
48
|
+
r = legacy_exchange_session.get(
|
|
37
49
|
f"{diracxUrl}/api/auth/legacy-exchange",
|
|
38
50
|
params={
|
|
39
51
|
"preferred_username": username,
|
|
40
52
|
"scope": " ".join(scopes),
|
|
41
53
|
"expires_minutes": expires_minutes,
|
|
54
|
+
"source": source,
|
|
42
55
|
},
|
|
43
56
|
headers={"Authorization": f"Bearer {apiKey}"},
|
|
44
57
|
timeout=10,
|
|
@@ -51,21 +64,25 @@ def get_token(username: str, group: str, dirac_properties: set[str], *, expires_
|
|
|
51
64
|
|
|
52
65
|
@cached(
|
|
53
66
|
TTLCache(maxsize=DEFAULT_TOKEN_CACHE_SIZE, ttl=DEFAULT_TOKEN_CACHE_TTL),
|
|
54
|
-
key=lambda a, b, c: hashkey(a, b, *sorted(c)),
|
|
67
|
+
key=lambda a, b, c, **_: hashkey(a, b, *sorted(c)),
|
|
55
68
|
)
|
|
56
|
-
def _get_token_file(username: str, group: str, dirac_properties: set[str]) -> Path:
|
|
69
|
+
def _get_token_file(username: str, group: str, dirac_properties: set[str], *, source: str = "") -> Path:
|
|
57
70
|
"""Write token to a temporary file and return the path to that file"""
|
|
58
|
-
data = get_token(username, group, dirac_properties)
|
|
71
|
+
data = get_token(username, group, dirac_properties, source=source)
|
|
59
72
|
token_location = Path(NamedTemporaryFile().name)
|
|
60
73
|
write_credentials(TokenResponse(**data), location=token_location)
|
|
61
74
|
return token_location
|
|
62
75
|
|
|
63
76
|
|
|
64
|
-
|
|
77
|
+
diracx_client_cache = LRUCache(maxsize=64)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
@contextmanager
|
|
81
|
+
def TheImpersonator(credDict: dict[str, Any], *, source: str = "") -> Generator[SyncDiracClient, None, None]:
|
|
65
82
|
"""
|
|
66
83
|
Client to be used by DIRAC server needing to impersonate
|
|
67
84
|
a user for diracx.
|
|
68
|
-
It queries a token, places it in a file, and returns the `
|
|
85
|
+
It queries a token, places it in a file, and returns the `SyncDiracClient`
|
|
69
86
|
class
|
|
70
87
|
|
|
71
88
|
Use as a context manager
|
|
@@ -78,7 +95,12 @@ def TheImpersonator(credDict: dict[str, Any]) -> DiracClient:
|
|
|
78
95
|
credDict["username"],
|
|
79
96
|
credDict["group"],
|
|
80
97
|
set(credDict.get("groupProperties", []) + credDict.get("properties", [])),
|
|
98
|
+
source=source,
|
|
81
99
|
)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
100
|
+
client = diracx_client_cache.get(token_location)
|
|
101
|
+
if client is None:
|
|
102
|
+
pref = DiracxPreferences(url=diracxUrl, credentials_path=token_location)
|
|
103
|
+
client = SyncDiracClient(diracx_preferences=pref)
|
|
104
|
+
client.__enter__()
|
|
105
|
+
diracx_client_cache[token_location] = client
|
|
106
|
+
yield client
|