22
33import os
44from datetime import datetime
5+ from functools import cached_property
56from typing import Annotated , Any , MutableMapping , TypeVar
67
78from pydantic import BaseModel as _BaseModel
2728
2829
2930class BaseModel (_BaseModel ):
30- model_config = ConfigDict (extra = "forbid" , frozen = True )
31+ model_config = ConfigDict (
32+ extra = "forbid" , frozen = True , use_attribute_docstrings = True
33+ )
3134
3235 @model_validator (mode = "before" )
3336 @classmethod
@@ -68,28 +71,51 @@ def legacy_adaptor(cls, v):
6871
6972class UserConfig (BaseModel ):
7073 PreferedUsername : str
74+ """Preferred username for the user account."""
7175 DNs : list [str ] = []
76+ """Distinguished Names of the user's certificates (Mandatory for certificate-based authentication)."""
7277 Email : EmailStr | None = None
78+ """User e-mail address (Mandatory for user registration)."""
7379 Suspended : list [str ] = []
80+ """List of VOs where the user is suspended."""
7481 Quota : int | None = None
82+ """Quota assigned to the user, expressed in MBs."""
7583
7684
7785class GroupConfig (BaseModel ):
7886 AutoAddVOMS : bool = False
87+ """Controls automatic addition of VOMS extension when creating proxies."""
7988 AutoUploadPilotProxy : bool = False
89+ """Controls automatic Proxy upload for Pilot groups."""
8090 AutoUploadProxy : bool = False
91+ """Controls automatic Proxy upload for users in this group."""
8192 JobShare : int = 1000
93+ """Share of computing resources allocated to this group for fair share scheduling."""
8294 Properties : SerializableSet [SecurityProperty ]
95+ """Group properties (set permissions of the group users).
96+
97+ Examples: NormalUser, GenericPilot, ServiceAdministrator.
98+ """
8399 Quota : int | None = None
100+ """Group-specific quota override."""
84101 Users : SerializableSet [str ]
102+ """DIRAC user logins that belong to this group."""
85103 AllowBackgroundTQs : bool = False
104+ """Allow background Task Queues for this group."""
86105 VOMSRole : str | None = None
106+ """Role of the users in the VO (e.g., '/lhcb' for LHCb VO)."""
87107 AutoSyncVOMS : bool = False
108+ """Automatically synchronize group membership with VOMS server."""
88109
89110
90111class IdpConfig (BaseModel ):
91112 URL : str
113+ """The authorization server's issuer identifier.
114+
115+ This is a URL that uses the 'https' scheme and has no query or fragment components.
116+ """
92117 ClientID : str
118+ """OAuth 2.0 client identifier received after client registration with the identity provider."""
93119
94120 @property
95121 def server_metadata_url (self ):
@@ -98,108 +124,187 @@ def server_metadata_url(self):
98124
99125class SupportInfo (BaseModel ):
100126 Email : str | None = None
127+ """Support contact email address."""
101128 Webpage : str | None = None
129+ """Support webpage URL."""
102130 Message : str = "Please contact system administrator"
131+ """Default support message displayed to users."""
103132
104133
105134class RegistryConfig (BaseModel ):
106135 IdP : IdpConfig
136+ """Registered identity provider associated with this VO."""
107137 Support : SupportInfo = Field (default_factory = SupportInfo )
138+ """Support contact information for this VO."""
108139 DefaultGroup : str
140+ """Default user group to be used for new users in this VO."""
109141 DefaultStorageQuota : float = 0
142+ """Default storage quota in GB for users in this VO."""
110143 DefaultProxyLifeTime : int = 12 * 60 * 60
144+ """Default proxy time expressed in seconds (default: 43200 = 12 hours)."""
111145 VOMSName : str | None = None
146+ """Real VOMS VO name, if this VO is associated with VOMS VO."""
112147
113148 Users : MutableMapping [str , UserConfig ]
149+ """DIRAC users section, subsections represent the name of the user."""
114150 Groups : MutableMapping [str , GroupConfig ]
151+ """DIRAC groups section, subsections represent the name of the group."""
152+
153+ @cached_property
154+ def _preferred_username_to_sub (self ) -> dict [str , str ]:
155+ """Compute reverse lookup map from preferred username to user sub."""
156+ return {user .PreferedUsername : sub for sub , user in self .Users .items ()}
115157
116158 def sub_from_preferred_username (self , preferred_username : str ) -> str :
117159 """Get the user sub from the preferred username.
118160
119- TODO: This could easily be cached or optimised
161+ Args:
162+ preferred_username: The preferred username to look up.
163+
164+ Returns:
165+ The user sub (subject identifier) for the given username.
166+
167+ Raises:
168+ KeyError: If no user with the given preferred username is found.
169+
120170 """
121- for sub , user in self . Users . items () :
122- if user . PreferedUsername == preferred_username :
123- return sub
124- raise KeyError (f"User { preferred_username } not found in registry" )
171+ try :
172+ return self . _preferred_username_to_sub [ preferred_username ]
173+ except KeyError :
174+ raise KeyError (f"User { preferred_username } not found in registry" ) from None
125175
126176
127177class DIRACConfig (BaseModel ):
128178 NoSetup : bool = False
179+ """Flag to skip setup procedures during DIRAC initialization. Takes a boolean value. By default false."""
129180
130181
131182class JobMonitoringConfig (BaseModel ):
132183 GlobalJobsInfo : bool = True
184+ """Enable global job information monitoring across all VOs."""
133185
134186
135187class JobSchedulingConfig (BaseModel ):
136188 EnableSharesCorrection : bool = False
189+ """Enable correction of job shares based on historical usage."""
137190 MaxRescheduling : int = 3
191+ """Maximum number of times a job can be rescheduled."""
138192
139193
140194class ServicesConfig (BaseModel ):
141195 Catalogs : MutableMapping [str , Any ] | None = None
196+ """Configuration for data catalog services."""
142197 JobMonitoring : JobMonitoringConfig = JobMonitoringConfig ()
198+ """Job monitoring service configuration."""
143199 JobScheduling : JobSchedulingConfig = JobSchedulingConfig ()
200+ """Job scheduling service configuration."""
144201
145202
146203class JobDescriptionConfig (BaseModel ):
147204 DefaultCPUTime : int = 86400
205+ """Default CPU time limit for jobs in seconds (default: 24 hours)."""
148206 DefaultPriority : int = 1
207+ """Default job priority."""
149208 MinCPUTime : int = 100
209+ """Minimum allowed CPU time for jobs in seconds."""
150210 MinPriority : int = 0
211+ """Minimum allowed job priority."""
151212 MaxCPUTime : int = 500000
213+ """Maximum allowed CPU time for jobs in seconds."""
152214 MaxPriority : int = 10
215+ """Maximum allowed job priority."""
153216 MaxInputData : int = 100
217+ """Maximum number of input data files per job."""
154218 AllowedJobTypes : list [str ] = ["User" , "Test" , "Hospital" ]
219+ """List of allowed job types."""
155220
156221
157222class InputDataPolicyProtocolsConfig (BaseModel ):
158223 Remote : list [str ] = []
224+ """List of protocols that should be considered as remote access methods (e.g., 'https', 'gsiftp', 'srm')."""
159225 Local : list [str ] = []
226+ """List of protocols that should be considered as local access methods (e.g., 'file', 'root')."""
160227
161228
162229class InputDataPolicyConfig (BaseModel ):
163230 # TODO: Remove this once the model is extended to support everything
164- model_config = ConfigDict (extra = "ignore" , frozen = True )
231+ model_config = ConfigDict (
232+ extra = "ignore" , frozen = True , use_attribute_docstrings = True
233+ )
165234
166235 Default : str = "Default = DIRAC.WorkloadManagementSystem.Client.InputDataByProtocol"
236+ """Default input data access policy. This is the fallback policy when no specific protocol is matched."""
167237 Download : str = "DIRAC.WorkloadManagementSystem.Client.DownloadInputData"
238+ """Policy for downloading input data files to the local worker node before job execution."""
168239 Protocol : str = "DIRAC.WorkloadManagementSystem.Client.InputDataByProtocol"
240+ """Policy for accessing input data directly via supported protocols without downloading."""
169241 AllReplicas : bool = True
242+ """Whether to consider all available replicas when resolving input data locations."""
170243 Protocols : InputDataPolicyProtocolsConfig = InputDataPolicyProtocolsConfig ()
244+ """Protocol-specific configuration defining which protocols are available for remote and local access."""
171245 InputDataModule : str = "DIRAC.Core.Utilities.InputDataResolution"
246+ """Module responsible for resolving input data locations and determining access methods."""
172247
173248
174249class OperationsConfig (BaseModel ):
175250 EnableSecurityLogging : bool = False
251+ """Flag for globally disabling the use of the SecurityLogging service.
252+
253+ This is False by default, as should be migrated to use centralized logging.
254+ """
176255 InputDataPolicy : InputDataPolicyConfig = InputDataPolicyConfig ()
256+ """Specify how jobs access their data. See InputDataResolution documentation for details."""
177257 JobDescription : JobDescriptionConfig = JobDescriptionConfig ()
258+ """Configuration for job description defaults and limits."""
178259 Services : ServicesConfig = ServicesConfig ()
260+ """Configuration for various DIRAC services."""
179261 SoftwareDistModule : str = "LocalSoftwareDist"
262+ """Module used for software distribution."""
180263
181264 Cloud : MutableMapping [str , Any ] | None = None
265+ """Cloud computing configuration."""
182266 DataConsistency : MutableMapping [str , Any ] | None = None
267+ """Data consistency checking configuration."""
183268 DataManagement : MutableMapping [str , Any ] | None = None
269+ """Data management operations configuration."""
184270 EMail : MutableMapping [str , Any ] | None = None
271+ """Email notification configuration."""
185272 GaudiExecution : MutableMapping [str , Any ] | None = None
273+ """Gaudi framework execution configuration."""
186274 Hospital : MutableMapping [str , Any ] | None = None
275+ """Job recovery and hospital configuration."""
187276 JobScheduling : MutableMapping [str , Any ] | None = None
277+ """Advanced job scheduling configuration."""
188278 JobTypeMapping : MutableMapping [str , Any ] | None = None
279+ """Mapping of job types to execution environments."""
189280 LogFiles : MutableMapping [str , Any ] | None = None
281+ """Log file management configuration."""
190282 LogStorage : MutableMapping [str , Any ] | None = None
283+ """Log storage backend configuration."""
191284 Logging : MutableMapping [str , Any ] | None = None
285+ """General logging configuration."""
192286 Matching : MutableMapping [str , Any ] | None = None
287+ """Job matching configuration."""
193288 MonitoringBackends : MutableMapping [str , Any ] | None = None
289+ """Monitoring backend configuration."""
194290 NagiosConnector : MutableMapping [str , Any ] | None = None
291+ """Nagios monitoring integration configuration."""
195292 Pilot : MutableMapping [str , Any ] | None = None
293+ """Pilot job configuration."""
196294 Productions : MutableMapping [str , Any ] | None = None
295+ """Production management configuration."""
197296 Shares : MutableMapping [str , Any ] | None = None
297+ """Resource sharing configuration."""
198298 Shifter : MutableMapping [str , Any ] | None = None
299+ """Shifter proxy configuration."""
199300 SiteSEMappingByProtocol : MutableMapping [str , Any ] | None = None
301+ """Site storage element mapping by protocol."""
200302 TransformationPlugins : MutableMapping [str , Any ] | None = None
303+ """Data transformation plugin configuration."""
201304 Transformations : MutableMapping [str , Any ] | None = None
305+ """Data transformation system configuration."""
202306 ResourceStatus : MutableMapping [str , Any ] | None = None
307+ """Resource status monitoring configuration."""
203308
204309
205310class ResourcesComputingConfig (BaseModel ):
@@ -209,6 +314,10 @@ class ResourcesComputingConfig(BaseModel):
209314 # TODO: Figure out how to remove this in LHCbDIRAC and then consider
210315 # constraining there to be at least one entry
211316 OSCompatibility : MutableMapping [str , set [str ]] = {}
317+ """Compatibility matrix between DIRAC platforms and OS versions.
318+
319+ Used by SiteDirector to match TaskQueues to Computing Element capabilities.
320+ """
212321
213322 @field_validator ("OSCompatibility" , mode = "before" )
214323 @classmethod
@@ -232,22 +341,34 @@ def ensure_self_compatibility(cls, v: dict[str, set[str]]) -> dict[str, set[str]
232341
233342class ResourcesConfig (BaseModel ):
234343 # TODO: Remove this once the model is extended to support everything
235- model_config = ConfigDict (extra = "ignore" , frozen = True )
344+ model_config = ConfigDict (
345+ extra = "ignore" , frozen = True , use_attribute_docstrings = True
346+ )
236347
237348 Computing : ResourcesComputingConfig = ResourcesComputingConfig ()
349+ """Computing resource configuration."""
238350
239351
240352class Config (BaseModel ):
241353 DIRAC : DIRACConfig
354+ """The DIRAC section contains general parameters needed in most installation types."""
242355 Operations : MutableMapping [str , OperationsConfig ]
356+ """Operations configuration per VO. The Defaults entry is automatically merged into each VO-specific config."""
243357 Registry : MutableMapping [str , RegistryConfig ]
358+ """Registry sections to register VOs, groups, users and hosts. See UserManagement documentation for details."""
244359 Resources : ResourcesConfig = ResourcesConfig ()
360+ """Resources configuration including computing elements, storage elements, and sites."""
245361
246362 LocalSite : Any = None
363+ """Local site-specific configuration parameters."""
247364 LogLevel : Any = None
365+ """Global logging level configuration."""
248366 MCTestingDestination : Any = None
367+ """Monte Carlo testing destination configuration."""
249368 Systems : Any | None = None
369+ """Systems configuration."""
250370 WebApp : Any = None
371+ """Web application configuration parameters."""
251372
252373 @model_validator (mode = "before" )
253374 @classmethod
0 commit comments