def getVOUserData(self, vo, refreshFlag=False): """ Get a report for users of a given VO :param str vo: VO name :return: S_OK/S_ERROR, Value = user description dictionary """ if refreshFlag: gConfig.forceRefresh() # Get DIRAC users diracUsers = getUsersInVO(vo) if not diracUsers: return S_ERROR("No VO users found for %s" % vo) if refreshFlag: result = self.csapi.downloadCSData() if not result['OK']: return result result = self.csapi.describeUsers(diracUsers) if not result['OK']: self.log.error('Could not retrieve CS User description') return result
def getVOUserData( self, vo, refreshFlag = False ): """ Get a report for users of a given VO :param str vo: VO name :return: S_OK/S_ERROR, Value = user description dictionary """ if refreshFlag: gConfig.forceRefresh() # Get DIRAC users diracUsers = getUsersInVO( vo ) if not diracUsers: return S_ERROR( "No VO users found for %s" % vo ) if refreshFlag: result = self.csapi.downloadCSData() if not result['OK']: return result result = self.csapi.describeUsers( diracUsers ) if not result['OK']: self.log.error( 'Could not retrieve CS User description' ) return result
def getVOUserData(self, refreshFlag=False): """Get a report for users of a given VO :param bool refreshFlag: flag to indicate that the configuration must be refreshed before looking up user data :return: S_OK/S_ERROR, Value = user description dictionary """ if refreshFlag: gConfig.forceRefresh() # Get DIRAC users diracUsers = getUsersInVO(self.vo) if not diracUsers: return S_ERROR("No VO users found for %s" % self.vo) if refreshFlag: result = self.csapi.downloadCSData() if not result["OK"]: return result result = self.csapi.describeUsers(diracUsers) if not result["OK"]: self.log.error("Could not retrieve CS User description") return result
def getVOUserData(self, refreshFlag=False): """ Get a report for users of a given VO :param bool refreshFlag: flag to indicate that the configuration must be refreshed before looking up user data :return: S_OK/S_ERROR, Value = user description dictionary """ if refreshFlag: gConfig.forceRefresh() # Get DIRAC users diracUsers = getUsersInVO(self.vo) if not diracUsers: return S_ERROR("No VO users found for %s" % self.vo) if refreshFlag: result = self.csapi.downloadCSData() if not result['OK']: return result result = self.csapi.describeUsers(diracUsers) if not result['OK']: self.log.error('Could not retrieve CS User description') return result
def __syncCSWithVOMS(self, vo): self.__adminMsgs = {'Errors': [], 'Info': []} # Get DIRAC group vs VOMS Role Mappings result = getVOMSRoleGroupMapping(vo) if not result['OK']: return result vomsDIRACMapping = result['Value']['VOMSDIRAC'] diracVOMSMapping = result['Value']['DIRACVOMS'] noVOMSGroups = result['Value']['NoVOMS'] vomsSrv = VOMSService(vo) # Get VOMS VO name result = vomsSrv.admGetVOName() if not result['OK']: self.log.error('Could not retrieve VOMS VO name', "for %s" % vo) return result vomsVOName = result['Value'].lstrip('/') self.log.verbose("VOMS VO Name for %s is %s" % (vo, vomsVOName)) # Get VOMS users result = vomsSrv.getUsers() if not result['OK']: self.log.error('Could not retrieve user information from VOMS', result['Message']) return result vomsUserDict = result['Value'] message = "There are %s registered users in VOMS VO %s" % ( len(vomsUserDict), vomsVOName) self.__adminMsgs['Info'].append(message) self.log.info(message) # Get DIRAC users diracUsers = getUsersInVO(vo) if not diracUsers: return S_ERROR("No VO users found for %s" % vo) result = self.csapi.describeUsers(diracUsers) if not result['OK']: self.log.error('Could not retrieve CS User description') return result diracUserDict = result['Value'] self.__adminMsgs['Info'].append( "There are %s registered users in DIRAC for VO %s" % (len(diracUserDict), vo)) self.log.info("There are %s registered users in DIRAC VO %s" % (len(diracUserDict), vo)) # Find new and obsoleted user DNs existingDNs = [] obsoletedDNs = [] newDNs = [] for user in diracUserDict: dn = diracUserDict[user]['DN'] existingDNs.append(dn) if dn not in vomsUserDict: obsoletedDNs.append(dn) for dn in vomsUserDict: if dn not in existingDNs: newDNs.append(dn) allDiracUsers = getAllUsers() nonVOusers = list(set(allDiracUsers) - set(diracUsers)) result = self.csapi.describeUsers(nonVOusers) if not result['OK']: self.log.error('Could not retrieve CS User description') return result nonVOUserDict = result['Value'] # Process users defaultVOGroup = getVOOption(vo, "DefaultGroup", "%s_user" % vo) for dn in vomsUserDict: if dn in newDNs: # Find if the DN is already registered in the DIRAC CS diracName = '' for user in nonVOUserDict: if dn == nonVOUserDict[user]['DN']: diracName = user # We have a real new user if not diracName: nickName = '' result = vomsSrv.attGetUserNickname( dn, vomsUserDict[dn]['CA']) if result['OK']: nickName = result['Value'] if nickName: newDiracName = nickName else: newDiracName = getUserName(dn, vomsUserDict[dn]['mail']) ind = 1 trialName = newDiracName while newDiracName in allDiracUsers: # We have a user with the same name but with a different DN newDiracName = "%s_%d" % (trialName, ind) ind += 1 # We now have everything to add the new user userDict = { "DN": dn, "CA": vomsUserDict[dn]['CA'], "Email": vomsUserDict[dn]['mail'] } groupsWithRole = [] for role in vomsUserDict[dn]['Roles']: fullRole = "/%s/%s" % (vomsVOName, role) group = vomsDIRACMapping.get(fullRole) if group: groupsWithRole.extend(group) userDict['Groups'] = list( set(groupsWithRole + [defaultVOGroup])) self.__adminMsgs['Info'].append( "Adding new user %s: %s" % (newDiracName, str(userDict))) self.voChanged = True if self.autoAddUsers: self.log.info("Adding new user %s: %s" % (newDiracName, str(userDict))) result = self.csapi.modifyUser( newDiracName, userDict, createIfNonExistant=True) if not result['OK']: self.log.warn('Failed adding new user %s' % newDiracName) continue # We have an already existing user userDict = { "DN": dn, "CA": vomsUserDict[dn]['CA'], "Email": vomsUserDict[dn]['mail'] } nonVOGroups = nonVOUserDict.get(diracName, {}).get('Groups', []) existingGroups = diracUserDict.get(diracName, {}).get('Groups', []) groupsWithRole = [] for role in vomsUserDict[dn]['Roles']: fullRole = "/%s/%s" % (vomsVOName, role) group = vomsDIRACMapping.get(fullRole) if group: groupsWithRole.extend(group) keepGroups = nonVOGroups + groupsWithRole + [defaultVOGroup] for group in existingGroups: role = diracVOMSMapping[group] # Among already existing groups for the user keep those without a special VOMS Role # because this membership is done by hand in the CS if not "Role" in role: keepGroups.append(group) # Keep existing groups with no VOMS attribute if any if group in noVOMSGroups: keepGroups.append(group) userDict['Groups'] = keepGroups if self.autoModifyUsers: result = self.csapi.modifyUser(diracName, userDict) if result['OK'] and result['Value']: self.voChanged = True # Check if there are potentially obsoleted users oldUsers = set() for user in diracUserDict: dn = diracUserDict[user]['DN'] if not dn in vomsUserDict and not user in nonVOUserDict: for group in diracUserDict[user]['Groups']: if not group in noVOMSGroups: oldUsers.add(user) if oldUsers: self.voChanged = True self.__adminMsgs['Info'].append( 'The following users to be checked for deletion: %s' % str(oldUsers)) self.log.info( 'The following users to be checked for deletion: %s' % str(oldUsers)) return S_OK()
def __syncCSWithVOMS( self, vo ): self.__adminMsgs = { 'Errors' : [], 'Info' : [] } # Get DIRAC group vs VOMS Role Mappings result = getVOMSRoleGroupMapping( vo ) if not result['OK']: return result vomsDIRACMapping = result['Value']['VOMSDIRAC'] diracVOMSMapping = result['Value']['DIRACVOMS'] noVOMSGroups = result['Value']['NoVOMS'] vomsSrv = VOMSService( vo ) # Get VOMS VO name result = vomsSrv.admGetVOName() if not result['OK']: self.log.error( 'Could not retrieve VOMS VO name', "for %s" % vo ) return result vomsVOName = result[ 'Value' ].lstrip( '/' ) self.log.verbose( "VOMS VO Name for %s is %s" % ( vo, vomsVOName ) ) # Get VOMS users result = vomsSrv.getUsers() if not result['OK']: self.log.error( 'Could not retrieve user information from VOMS', result['Message'] ) return result vomsUserDict = result[ 'Value' ] message = "There are %s registered users in VOMS VO %s" % ( len( vomsUserDict ), vomsVOName ) self.__adminMsgs[ 'Info' ].append( message ) self.log.info( message ) # Get DIRAC users diracUsers = getUsersInVO( vo ) if not diracUsers: return S_ERROR( "No VO users found for %s" % vo ) result = self.csapi.describeUsers( diracUsers ) if not result['OK']: self.log.error( 'Could not retrieve CS User description' ) return result diracUserDict = result['Value'] self.__adminMsgs[ 'Info' ].append( "There are %s registered users in DIRAC for VO %s" % ( len( diracUserDict ), vo ) ) self.log.info( "There are %s registered users in DIRAC VO %s" % ( len( diracUserDict ), vo ) ) # Find new and obsoleted user DNs existingDNs = [] obsoletedDNs = [] newDNs = [] for user in diracUserDict: dn = diracUserDict[user]['DN'] existingDNs.append( dn ) if dn not in vomsUserDict: obsoletedDNs.append( dn ) for dn in vomsUserDict: if dn not in existingDNs: newDNs.append( dn ) allDiracUsers = getAllUsers() nonVOusers = list( set( allDiracUsers ) - set(diracUsers) ) result = self.csapi.describeUsers( nonVOusers ) if not result['OK']: self.log.error( 'Could not retrieve CS User description' ) return result nonVOUserDict = result['Value'] # Process users defaultVOGroup = getVOOption( vo, "DefaultGroup", "%s_user" % vo ) for dn in vomsUserDict: if dn in newDNs: # Find if the DN is already registered in the DIRAC CS diracName = '' for user in nonVOUserDict: if dn == nonVOUserDict[user]['DN']: diracName = user # We have a real new user if not diracName: nickName = '' result = vomsSrv.attGetUserNickname( dn, vomsUserDict[dn]['CA'] ) if result['OK']: nickName = result['Value'] if nickName: newDiracName = nickName else: newDiracName = getUserName( dn, vomsUserDict[dn]['mail'] ) ind = 1 trialName = newDiracName while newDiracName in allDiracUsers: # We have a user with the same name but with a different DN newDiracName = "%s_%d" % ( trialName, ind ) ind += 1 # We now have everything to add the new user userDict = { "DN": dn, "CA": vomsUserDict[dn]['CA'], "Email": vomsUserDict[dn]['mail'] } groupsWithRole = [] for role in vomsUserDict[dn]['Roles']: fullRole = "/%s/%s" % ( vomsVOName, role ) group = vomsDIRACMapping.get( fullRole ) if group: groupsWithRole.append( group ) userDict['Groups'] = list( set( groupsWithRole + [defaultVOGroup] ) ) self.__adminMsgs[ 'Info' ].append( "Adding new user %s: %s" % ( newDiracName, str( userDict ) ) ) self.voChanged = True if self.autoAddUsers: self.log.info( "Adding new user %s: %s" % ( newDiracName, str( userDict ) ) ) result = self.csapi.modifyUser( newDiracName, userDict, createIfNonExistant = True ) if not result['OK']: self.log.warn( 'Failed adding new user %s' % newDiracName ) continue # We have an already existing user userDict = { "DN": dn, "CA": vomsUserDict[dn]['CA'], "Email": vomsUserDict[dn]['mail'] } nonVOGroups = nonVOUserDict.get( diracName, {} ).get( 'Groups', [] ) existingGroups = diracUserDict.get( diracName, {} ).get( 'Groups', [] ) groupsWithRole = [] for role in vomsUserDict[dn]['Roles']: fullRole = "/%s/%s" % ( vomsVOName, role ) group = vomsDIRACMapping.get( fullRole ) if group: groupsWithRole.append( group ) keepGroups = nonVOGroups + groupsWithRole + [defaultVOGroup] for group in existingGroups: role = diracVOMSMapping[group] # Among already existing groups for the user keep those without a special VOMS Role # because this membership is done by hand in the CS if not "Role" in role: keepGroups.append( group ) # Keep existing groups with no VOMS attribute if any if group in noVOMSGroups: keepGroups.append( group ) userDict['Groups'] = keepGroups if self.autoModifyUsers: result = self.csapi.modifyUser( diracName, userDict ) if result['OK'] and result['Value']: self.voChanged = True # Check if there are potentially obsoleted users oldUsers = set() for user in diracUserDict: dn = diracUserDict[user]['DN'] if not dn in vomsUserDict and not user in nonVOUserDict: for group in diracUserDict[user]['Groups']: if not group in noVOMSGroups: oldUsers.add( user ) if oldUsers: self.voChanged = True self.__adminMsgs[ 'Info' ].append( 'The following users to be checked for deletion: %s' % str( oldUsers ) ) self.log.info( 'The following users to be checked for deletion: %s' % str( oldUsers ) ) return S_OK()
def executeForVO(self, vo): """ Execute one SE and user synchronisation cycle for a VO. :param str vo: Virtual organisation name. :return: S_OK or S_ERROR :rtype: dict """ valid_protocols = ["srm", "gsiftp", "davs", "https", "root"] default_email = None try: try: client = Client(account="root", auth_type="userpass") except Exception as err: self.log.info( "Login to Rucio as root with password failed. Will try host cert/key", str(err)) certKeyTuple = Locations.getHostCertificateAndKeyLocation() if not certKeyTuple: self.log.error("Hostcert/key location not set") return S_ERROR("Hostcert/key location not set") hostcert, hostkey = certKeyTuple self.log.info("Logging in with a host cert/key pair:") self.log.debug("account: ", self.clientConfig[vo]["privilegedAccount"]) self.log.debug("rucio host: ", self.clientConfig[vo]["rucioHost"]) self.log.debug("auth host: ", self.clientConfig[vo]["authHost"]) self.log.debug("CA cert path: ", self.caCertPath) self.log.debug("Cert location: ", hostcert) self.log.debug("Key location: ", hostkey) self.log.debug("VO: ", vo) client = Client( account=self.clientConfig[vo]["privilegedAccount"], rucio_host=self.clientConfig[vo]["rucioHost"], auth_host=self.clientConfig[vo]["authHost"], ca_cert=self.caCertPath, auth_type="x509", creds={ "client_cert": hostcert, "client_key": hostkey }, timeout=600, user_agent="rucio-clients", vo=vo, ) self.log.info("Rucio client instantiated for VO:", vo) # Get the storage elements from Dirac Configuration and create them in Rucio newRSE = False self.log.info("Synchronizing SEs for VO ", vo) result = getStorageElements(vo) if result["OK"]: rses = [rse["rse"] for rse in client.list_rses()] for se in result["Value"]: if se not in rses: # The SE doesn't exist. Will create it newRSE = True self.log.info( "Rucio Storage Element does not exist and will be created:", se) try: client.add_rse(rse=se, deterministic=True, volatile=False) except Exception as err: self.log.error( "Cannot create RSE", "[RSE: %s, Error: %s]" % (se, str(err))) continue # Add RSE attributes for the new RSE ret = gConfig.getOptionsDict( "Resources/FTSEndpoints/FTS3") ftsList = "" if ret["OK"]: ftsList = ",".join(ret["Value"].values()) dictRSEAttributes = { "naming_convention": "BelleII", "ANY": True, "fts": ftsList } for key in dictRSEAttributes: self.log.info( "Setting RSE attributes", "[RSE: %s, Attr. name: %s, Value: %s]" % (se, key, dictRSEAttributes[key]), ) client.add_rse_attribute( se, key, value=dictRSEAttributes[key]) client.set_local_account_limit("root", se, 100000000000000000) # Create the protocols try: protocols = client.get_protocols(se) except RSEProtocolNotSupported as err: self.log.info("Cannot get protocols for", "[RSE %s, Error: %s]" % (se, str(err))) protocols = [] existing_protocols = [] for prot in protocols: existing_protocols.append( (str(prot["scheme"]), str(prot["hostname"]), str(prot["port"]), str(prot["prefix"]))) protocols_to_create = [] for params in result["Value"][se]: prot = ( str(params["scheme"]), str(params["hostname"]), str(params["port"]), str(params["prefix"]), ) protocols_to_create.append(prot) if prot not in existing_protocols and prot[ 0] in valid_protocols: # The protocol defined in Dirac does not exist in Rucio. Will be created self.log.info( "Will create new protocol:", "%s://%s:%s%s on %s" % (params["scheme"], params["hostname"], params["port"], params["prefix"], se), ) try: client.add_protocol(rse=se, params=params) except Duplicate as err: self.log.info( "Protocol already exists on", "[RSE: %s, schema:%s]" % (se, params["scheme"])) except Exception as err: self.log.error( "Cannot create protocol on RSE", "[RSE: %s, Error: %s]" % (se, str(err))) else: update = False for protocol in protocols: if prot == ( str(protocol["scheme"]), str(protocol["hostname"]), str(protocol["port"]), str(protocol["prefix"]), ): # Check if the protocol defined in Dirac has the same priority as the one defined in Rucio for domain in ["lan", "wan"]: for activity in [ "read", "write", "delete" ]: if (params["domains"][domain] [activity] != protocol["domains"][domain] [activity]): update = True break if (params["domains"]["wan"] ["third_party_copy"] != protocol["domains"]["wan"] ["third_party_copy"]): update = True if update: data = { "prefix": params["prefix"], "read_lan": params["domains"]["lan"]["read"], "read_wan": params["domains"]["wan"]["read"], "write_lan": params["domains"]["lan"]["write"], "write_wan": params["domains"]["wan"]["write"], "delete_lan": params["domains"]["lan"]["delete"], "delete_wan": params["domains"]["wan"]["delete"], "third_party_copy": params["domains"]["wan"]["write"], } self.log.info( "Will update protocol:", "%s://%s:%s%s on %s" % ( params["scheme"], params["hostname"], params["port"], params["prefix"], se, ), ) client.update_protocols( rse=se, scheme=params["scheme"], data=data, hostname=params["hostname"], port=params["port"], ) for prot in existing_protocols: if prot not in protocols_to_create: self.log.info( "Will delete protocol:", "%s://%s:%s%s on %s" % (prot[0], prot[1], prot[2], prot[3], se)) client.delete_protocols(se, scheme=prot[0], hostname=prot[1], port=prot[2]) else: self.log.error("Cannot get SEs:", result["Message"]) # If new RSE added, add distances rses = [rse["rse"] for rse in client.list_rses()] if newRSE: self.log.info("Adding distances") for src_rse, dest_rse in permutations(rses, r=2): try: client.add_distance(src_rse, dest_rse, { "ranking": 1, "distance": 10 }) except Exception as err: self.log.error( "Cannot add distance for", "Source RSE: %s, Dest RSE: %s, Error:%s" % (src_rse, dest_rse, str(err)), ) # Collect the shares from Dirac Configuration and create them in Rucio self.log.info("Synchronizing shares") result = Operations().getOptionsDict("Production/SEshares") if result["OK"]: rseDict = result["Value"] for rse in rses: try: self.log.info("Setting productionSEshare for", "[RSE: %s : Share: %s", rse, rseDict.get(rse, 0)) client.add_rse_attribute(rse, "productionSEshare", rseDict.get(rse, 0)) except Exception as err: self.log.error( "Cannot create productionSEshare for RSE:", rse) else: self.log.error("Cannot get SEs", result["Message"]) result = Operations().getSections("Shares") if result["OK"]: for dataLevel in result["Value"]: result = Operations().getOptionsDict("Shares/%s" % dataLevel) if not result["OK"]: self.log.error("Cannot get SEs:" % result["Message"]) continue rseDict = result["Value"] for rse in rses: try: self.log.info( "Setting", "%sShare for %s : %s" % (dataLevel, rse, rseDict.get(rse, 0))) client.add_rse_attribute(rse, "%sShare" % dataLevel, rseDict.get(rse, 0)) except Exception as err: self.log.error("Cannot create share:", "%sShare for %s", dataLevel, rse) else: self.log.error("Cannot get shares:", result["Message"]) # Create the RSE attribute PrimaryDataSE and OccupancyLFN result = gConfig.getValue( "Resources/StorageElementGroups/PrimarySEs") result = getStorageElements(vo) if result["OK"]: allSEs = result["Value"] primarySEs = resolveSEGroup("PrimarySEs", allSEs) self.log.info("Will set primarySEs flag to:", str(primarySEs)) for rse in rses: if rse in allSEs: storage = StorageElement(rse) if not storage.valid: self.log.warn( "Storage element is not valid. Skipped RSE:", rse) continue occupancyLFN = storage.options.get("OccupancyLFN") try: client.add_rse_attribute(rse, "OccupancyLFN", occupancyLFN) except Exception as err: self.log.error( "Cannot create RSE attribute OccupancyLFN for", "[RSE: %s, Error: %s]" % (rse, str(err))) if rse in primarySEs: try: client.add_rse_attribute(rse, "PrimaryDataSE", True) except Exception as err: self.log.error( "Cannot create RSE attribute PrimaryDataSE for", "[RSE: %s, Error: %s]" % (rse, str(err)), ) else: try: client.delete_rse_attribute(rse, "PrimaryDataSE") except RSEAttributeNotFound: pass except Exception as err: self.log.error( "Cannot remove RSE attribute PrimaryDataSE for", "[RSE: %s, Error: %s]" % (rse, str(err)), ) self.log.info("RSEs synchronized for VO: ", vo) # Collect the user accounts from Dirac Configuration and create user accounts in Rucio self.log.info("Synchronizing accounts for VO", vo) listAccounts = [ str(acc["account"]) for acc in client.list_accounts() ] listScopes = [str(scope) for scope in client.list_scopes()] dnMapping = {} diracUsers = getUsersInVO(vo) self.log.debug(" Will consider following Dirac users for", "[VO: %s, Dirac users: %s]" % (vo, diracUsers)) for account in diracUsers: dn = getUserOption(account, "DN") email = getUserOption(account, "Email") dnMapping[dn] = email if account not in listAccounts: self.log.info("Will create account with associated DN ", "[account: %s, DN: %s]" % (account, dn)) try: client.add_account(account, "USER", email) listAccounts.append(account) except Exception as err: self.log.error( "Cannot create account", "[account: %s, Error: %s]" % (account, str(err))) try: client.add_identity(account=account, identity=dn, authtype="X509", email=email, default=True) except Exception as err: self.log.error( "Cannot add identity for account", "[Identity: dn=%s, account:%s, Error: %s]" % (dn, account, str(err)), ) self.log.error( " Account/identity skipped (it will not be created in Rucio)", "[%s/%s]" % (account, dn)) continue for rse in rses: client.set_local_account_limit(account, rse, 1000000000000000) else: try: client.add_identity(account=account, identity=dn, authtype="X509", email=email, default=True) except Duplicate: pass except Exception as err: self.log.error( "Cannot create identity for account", "[DN: %s, account: %s, Error: %s]" % (dn, account, str(err)), ) scope = "user." + account if scope not in listScopes: try: self.log.info("Will create a scope", "[Scope: %s]" % scope) client.add_scope(account, scope) self.log.info("Scope successfully added", "[Scope: %s]" % scope) except Exception as err: self.log.error( "Cannot create a scope", "[Scope: %s, Error: %s]" % (scope, str(err))) # Collect the group accounts from Dirac Configuration and create service accounts in Rucio result = getGroupsForVO(vo) if result["OK"]: groups = result["Value"] self.log.debug(" Will consider following Dirac groups for", "[%s VO: %s]" % (vo, groups)) else: groups = [] self.log.debug("No Dirac groups for", "%s VO " % vo) self.log.debug("No Rucio service accounts will be created") for group in groups: if group not in listAccounts: self.log.info( "Will create SERVICE account for Dirac group:", str(group)) try: client.add_account(group, "SERVICE", None) listAccounts.append(group) except Exception as err: self.log.error( "Cannot create SERVICE account for", "[group: %s, Error: %s]" % (group, str(err))) for rse in rses: client.set_local_account_limit(account, rse, 1000000000000000) for dn in getDNsInGroup(group): try: client.add_identity(account=group, identity=dn, authtype="X509", email=dnMapping.get( dn, default_email)) except Duplicate: pass except Exception as err: self.log.error( "Cannot create identity for account", "[identity %s, account %s, Error: %s]" % (dn, group, str(err)), ) self.log.error(format_exc()) # Collect the group accounts from Dirac Configuration and create service accounts in Rucio result = getHosts() if not result["OK"]: self.log.error("Cannot get host accounts:", "%s" % result["Message"]) else: hosts = result["Value"] for host in hosts: dn = getHostOption(host, "DN") email = dnMapping.get(dn, default_email) try: client.add_identity(account="dirac_srv", identity=dn, authtype="X509", email=email) except Duplicate: pass except Exception as err: self.log.error( "Cannot create identity for account dirac_srv:", "[DN: %s, Error: %s]" % (dn, str(err))) self.log.error(format_exc()) return S_OK() except Exception as exc: self.log.exception("Synchronisation for VO failed. VO skipped ", "VO=%s" % vo, lException=exc) return S_ERROR(str(format_exc()))