def _refreshAndPublish(self): """ Refresh configuration and publish local updates """ self._lastUpdateTime = time.time() gLogger.info("Refreshing from master server") sMasterServer = gConfigurationData.getMasterServer() if sMasterServer: from DIRAC.ConfigurationSystem.Client.ConfigurationClient import ConfigurationClient oClient = ConfigurationClient( url=sMasterServer, timeout=self._timeout, useCertificates=gConfigurationData.useServerCertificate(), skipCACheck=gConfigurationData.skipCACheck()) dRetVal = _updateFromRemoteLocation(oClient) if not dRetVal['OK']: gLogger.error("Can't update from master server", dRetVal['Message']) return False if gConfigurationData.getAutoPublish(): gLogger.info("Publishing to master server...") dRetVal = oClient.publishSlaveServer(self._url) if not dRetVal['OK']: gLogger.error("Can't publish to master server", dRetVal['Message']) return True else: gLogger.warn( "No master server is specified in the configuration, trying to get data from other slaves" ) return self._refresh()['OK']
def initialize(self): if self.__initialized['OK']: return self.__initialized if not gConfig.useServerCertificate(): res = self.__getProxyID() else: res = self.__getCertificateID() if not res: self.__initialized = S_ERROR("Cannot locate client credentials") return self.__initialized retVal = gConfig.getOption("/DIRAC/Configuration/MasterServer") if not retVal['OK']: self.__initialized = S_ERROR( "Master server is not known. Is everything initialized?") return self.__initialized self.__rpcClient = ConfigurationClient( url=gConfig.getValue("/DIRAC/Configuration/MasterServer", "")) self.__csMod = Modificator( self.__rpcClient, "%s - %s - %s" % (self.__userGroup, self.__userDN, Time.dateTime().strftime("%Y-%m-%d %H:%M:%S"))) retVal = self.downloadCSData() if not retVal['OK']: self.__initialized = S_ERROR( "Can not download the remote cfg. Is everything initialized?") return self.__initialized self.__initialized = S_OK() return self.__initialized
def publishSlaveServer(self, sSlaveURL): """ Called by the slave server via service, it register a new slave server :param sSlaveURL: url of slave server """ if not gConfigurationData.isMaster(): return S_ERROR("Configuration modification is not allowed in this server") gLogger.info("Pinging slave %s" % sSlaveURL) rpcClient = ConfigurationClient(url=sSlaveURL, timeout=10, useCertificates=True) retVal = rpcClient.ping() if not retVal["OK"]: gLogger.info("Slave %s didn't reply" % sSlaveURL) return if retVal["Value"]["name"] != "Configuration/Server": gLogger.info("Slave %s is not a CS serveR" % sSlaveURL) return bNewSlave = False if sSlaveURL not in self.dAliveSlaveServers: bNewSlave = True gLogger.info("New slave registered", sSlaveURL) self.dAliveSlaveServers[sSlaveURL] = time.time() if bNewSlave: gConfigurationData.setServers(", ".join(self.dAliveSlaveServers)) self.__generateNewVersion()
def initialize(self): """API initialization :return: S_OK()/S_ERROR() """ if self.__initialized["OK"]: return self.__initialized res = self.__getCertificateID() if gConfig.useServerCertificate( ) else self.__getProxyID() if not res["OK"]: gLogger.error(res["Message"]) self.__initialized = S_ERROR("Cannot locate client credentials") return self.__initialized retVal = gConfig.getOption("/DIRAC/Configuration/MasterServer") if not retVal["OK"]: self.__initialized = S_ERROR( "Master server is not known. Is everything initialized?") return self.__initialized self.__rpcClient = ConfigurationClient( url=gConfig.getValue("/DIRAC/Configuration/MasterServer", "")) self.__csMod = Modificator( self.__rpcClient, "%s - %s - %s" % (self.__userGroup, self.__userDN, datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S")), ) retVal = self.downloadCSData() if not retVal["OK"]: self.__initialized = S_ERROR( "Can not download the remote cfg. Is everything initialized?") return self.__initialized self.__initialized = S_OK() return self.__initialized
def do_connect(self, line): """connect Connect to the CS Usage: connect <URL> (Connect to the CS at the specified URL) connect (Connect to the default CS URL of your config) """ if line == "": self.serverURL = gConfigurationData.getMasterServer() self.serverName = gConfigurationData.getName() else: self.serverURL = self.serverName = line if self.serverURL is None: print("Unable to connect to the default server. Maybe you don't have a proxy ?") return self.do_disconnect("") print("Trying to connect to " + self.serverURL + "...", end=" ") self.modificator = Modificator(ConfigurationClient(url=self.serverURL)) rv = self.modificator.loadFromRemote() rv2 = self.modificator.loadCredentials() if rv["OK"] == False or rv2["OK"] == False: print("failed: ", end=" ") if rv["OK"] is False: print(rv["Message"]) else: print(rv2["Message"]) self.connected = False self.update_prompt() else: self.connected = True self.update_prompt() print("done.")
def _tryConnection(self): print("Trying connection to %s" % self.masterURL) try: self.rpcClient = ConfigurationClient(url=self.masterURL) self._setStatus() except Exception as x: gLogger.error("Couldn't connect to master CS server", "%s (%s)" % (self.masterURL, str(x))) self._setStatus(False)
def _refresh(self, fromMaster=False): """ Refresh configuration """ self._lastUpdateTime = time.time() gLogger.debug("Refreshing configuration...") gatewayList = getGatewayURLs("Configuration/Server") updatingErrorsList = [] if gatewayList: initialServerList = gatewayList gLogger.debug("Using configuration gateway", str(initialServerList[0])) elif fromMaster: masterServer = gConfigurationData.getMasterServer() initialServerList = [masterServer] gLogger.debug("Refreshing from master %s" % masterServer) else: initialServerList = gConfigurationData.getServers() gLogger.debug("Refreshing from list %s" % str(initialServerList)) # If no servers in the initial list, we are supposed to use the local configuration only if not initialServerList: return S_OK() randomServerList = List.randomize(initialServerList) gLogger.debug("Randomized server list is %s" % ", ".join(randomServerList)) for sServer in randomServerList: from DIRAC.ConfigurationSystem.Client.ConfigurationClient import ConfigurationClient oClient = ConfigurationClient( url=sServer, useCertificates=gConfigurationData.useServerCertificate(), skipCACheck=gConfigurationData.skipCACheck(), ) dRetVal = _updateFromRemoteLocation(oClient) if dRetVal["OK"]: self._refreshTime = gConfigurationData.getRefreshTime() return dRetVal else: updatingErrorsList.append(dRetVal["Message"]) gLogger.warn( "Can't update from server", "Error while updating from %s: %s" % (sServer, dRetVal["Message"])) if dRetVal["Message"].find("Insane environment") > -1: break return S_ERROR("Reason(s):\n\t%s" % "\n\t".join(List.uniqueElements(updatingErrorsList)))
class CSAPI(object): """ CSAPI objects need an initialization phase """ def __init__(self): """ Initialization function """ self.csModified = False self.__baseSecurity = "/Registry" self.__baseResources = "/Resources" self.__userDN = '' self.__userGroup = '' self.__rpcClient = None self.__csMod = None self.__initialized = S_ERROR("Not initialized") self.initialize() if not self.__initialized['OK']: gLogger.error(self.__initialized) def __getProxyID(self): proxyLocation = Locations.getProxyLocation() if not proxyLocation: gLogger.error("No proxy found!") return False chain = X509Chain() if not chain.loadProxyFromFile(proxyLocation): gLogger.error("Can't read proxy!", proxyLocation) return False retVal = chain.getIssuerCert() if not retVal['OK']: gLogger.error("Can't parse proxy!", retVal['Message']) return False idCert = retVal['Value'] self.__userDN = idCert.getSubjectDN()['Value'] self.__userGroup = chain.getDIRACGroup()['Value'] return True def __getCertificateID(self): certLocation = Locations.getHostCertificateAndKeyLocation() if not certLocation: gLogger.error("No certificate found!") return False chain = X509Chain() retVal = chain.loadChainFromFile(certLocation[0]) if not retVal['OK']: gLogger.error("Can't parse certificate!", retVal['Message']) return False idCert = chain.getIssuerCert()['Value'] self.__userDN = idCert.getSubjectDN()['Value'] self.__userGroup = 'host' return True def initialize(self): if self.__initialized['OK']: return self.__initialized if not gConfig.useServerCertificate(): res = self.__getProxyID() else: res = self.__getCertificateID() if not res: self.__initialized = S_ERROR("Cannot locate client credentials") return self.__initialized retVal = gConfig.getOption("/DIRAC/Configuration/MasterServer") if not retVal['OK']: self.__initialized = S_ERROR( "Master server is not known. Is everything initialized?") return self.__initialized self.__rpcClient = ConfigurationClient( url=gConfig.getValue("/DIRAC/Configuration/MasterServer", "")) self.__csMod = Modificator( self.__rpcClient, "%s - %s - %s" % (self.__userGroup, self.__userDN, Time.dateTime().strftime("%Y-%m-%d %H:%M:%S"))) retVal = self.downloadCSData() if not retVal['OK']: self.__initialized = S_ERROR( "Can not download the remote cfg. Is everything initialized?") return self.__initialized self.__initialized = S_OK() return self.__initialized def downloadCSData(self): if not self.__csMod: return S_ERROR("CSAPI not yet initialized") result = self.__csMod.loadFromRemote() if not result['OK']: return result self.csModified = False self.__csMod.updateGConfigurationData() return S_OK() # Resources-related methods ######################################### def addSite(self, siteName, optionsDict=None): """ Adds a new site to the CS. A site is a container for services, so after calling this function, at least addCEtoSite() should be called. :param str siteName: FQN of the site (e.g. LCG.CERN.ch) :param dict optionsDict: optional dictionary of options :returns: S_OK/S_ERROR structure """ if not self.__initialized['OK']: return self.__initialized self.__csMod.createSection(cfgPath(self.__baseResources, 'Sites')) self.__csMod.createSection( cfgPath(self.__baseResources, 'Sites', siteName.split('.')[0])) self.__csMod.createSection( cfgPath(self.__baseResources, 'Sites', siteName.split('.')[0], siteName)) # add options if requested if optionsDict: for option, optionValue in optionsDict.items( ): # can be an iterator self.__csMod.setOptionValue( cfgPath(self.__baseResources, 'Sites', siteName.split('.')[0], siteName, option), optionValue) self.csModified = True return S_OK(True) def addCEtoSite(self, siteName, ceName, optionsDict=None): """ Adds a new CE to a site definition in the CS. A CE normally has queues, so addQueueToCE should be called after this one. :param str siteName: FQN of the site (e.g. LCG.CERN.ch) :param str ceName: FQN of the CE (e.g. ce503.cern.ch) :param dict optionsDict: optional dictionary of options :returns: S_OK/S_ERROR structure """ res = getSites() if not res['OK']: return res if siteName not in res['Value']: res = self.addSite(siteName) if not res['OK']: return res # CSAPI.createSection() always returns S_OK even if the section already exists self.__csMod.createSection( cfgPath(self.__baseResources, 'Sites', siteName.split('.')[0], siteName, 'CEs')) self.__csMod.createSection( cfgPath(self.__baseResources, 'Sites', siteName.split('.')[0], siteName, 'CEs', ceName)) # add options if requested if optionsDict is not None: for option, optionValue in optionsDict.items( ): # can be an iterator self.__csMod.setOptionValue( cfgPath(self.__baseResources, 'Sites', siteName.split('.')[0], siteName, 'CEs', ceName, option), optionValue) self.csModified = True return S_OK(True) def addQueueToCE(self, ceName, queueName, optionsDict=None): """ Adds a new queue to a CE definition in the CS. :param str ceName: FQN of the CE (e.g. ce503.cern.ch) :param str queueName: name of the queue (e.g. ce503.cern.ch-condor) :param dict optionsDict: optional dictionary of options :returns: S_OK/S_ERROR structure """ res = getCESiteMapping(ceName) if not res['OK']: return res if ceName not in res['Value']: return S_ERROR("CE does not exist") siteName = res['Value'][ceName] # CSAPI.createSection() always returns S_OK even if the section already exists self.__csMod.createSection( cfgPath(self.__baseResources, 'Sites', siteName.split('.')[0], siteName, 'CEs', ceName, 'Queues', queueName)) # add options if requested if optionsDict is not None: for option, optionValue in optionsDict.items( ): # can be an iterator self.__csMod.setOptionValue( cfgPath(self.__baseResources, 'Sites', siteName.split('.')[0], siteName, 'CEs', ceName, 'Queues', queueName, option), optionValue) self.csModified = True return S_OK(True) # Registry-related methods ######################################### def listUsers(self, group=False): if not self.__initialized['OK']: return self.__initialized if not group: return S_OK( self.__csMod.getSections("%s/Users" % self.__baseSecurity)) users = self.__csMod.getValue("%s/Groups/%s/Users" % (self.__baseSecurity, group)) if not users: return S_OK([]) return S_OK(List.fromChar(users)) def listHosts(self): if not self.__initialized['OK']: return self.__initialized return S_OK(self.__csMod.getSections("%s/Hosts" % self.__baseSecurity)) def describeUsers(self, users=None): """ describe users by nickname :param list users: list of users' nicknames :return: a S_OK(description) of the users in input """ if users is None: users = [] if not self.__initialized['OK']: return self.__initialized return S_OK(self.__describeEntity(users)) def describeHosts(self, hosts=None): if hosts is None: hosts = [] if not self.__initialized['OK']: return self.__initialized return S_OK(self.__describeEntity(hosts, True)) def __describeEntity(self, mask, hosts=False): if hosts: csSection = "%s/Hosts" % self.__baseSecurity else: csSection = "%s/Users" % self.__baseSecurity if mask: entities = [ entity for entity in self.__csMod.getSections(csSection) if entity in mask ] else: entities = self.__csMod.getSections(csSection) entitiesDict = {} for entity in entities: entitiesDict[entity] = {} for option in self.__csMod.getOptions("%s/%s" % (csSection, entity)): entitiesDict[entity][option] = self.__csMod.getValue( "%s/%s/%s" % (csSection, entity, option)) if not hosts: groupsDict = self.describeGroups()['Value'] entitiesDict[entity]['Groups'] = [] for group in groupsDict: if 'Users' in groupsDict[group] and entity in groupsDict[ group]['Users']: entitiesDict[entity]['Groups'].append(group) entitiesDict[entity]['Groups'].sort() return entitiesDict def listGroups(self): """ List all groups """ if not self.__initialized['OK']: return self.__initialized return S_OK(self.__csMod.getSections("%s/Groups" % self.__baseSecurity)) def describeGroups(self, mask=None): """ List all groups that are in the mask (or all if no mask) with their properties """ if mask is None: mask = [] if not self.__initialized['OK']: return self.__initialized groups = [ group for group in self.__csMod.getSections("%s/Groups" % self.__baseSecurity) if not mask or (mask and group in mask) ] groupsDict = {} for group in groups: groupsDict[group] = {} for option in self.__csMod.getOptions( "%s/Groups/%s" % (self.__baseSecurity, group)): groupsDict[group][option] = self.__csMod.getValue( "%s/Groups/%s/%s" % (self.__baseSecurity, group, option)) if option in ("Users", "Properties"): groupsDict[group][option] = List.fromChar( groupsDict[group][option]) return S_OK(groupsDict) def deleteUsers(self, users): """ Delete a user/s can receive as a param either a string or a list """ if not self.__initialized['OK']: return self.__initialized if isinstance(users, six.string_types): users = [users] usersData = self.describeUsers(users)['Value'] for username in users: if username not in usersData: gLogger.warn("User %s does not exist" % username) continue userGroups = usersData[username]['Groups'] for group in userGroups: self.__removeUserFromGroup(group, username) gLogger.info("Deleted user %s from group %s" % (username, group)) self.__csMod.removeSection("%s/Users/%s" % (self.__baseSecurity, username)) gLogger.info("Deleted user %s" % username) self.csModified = True return S_OK(True) def __removeUserFromGroup(self, group, username): """ Remove user from a group """ usersInGroup = self.__csMod.getValue("%s/Groups/%s/Users" % (self.__baseSecurity, group)) if usersInGroup is not None: userList = List.fromChar(usersInGroup, ",") userPos = userList.index(username) userList.pop(userPos) self.__csMod.setOptionValue( "%s/Groups/%s/Users" % (self.__baseSecurity, group), ",".join(userList)) def __addUserToGroup(self, group, username): """ Add user to a group """ usersInGroup = self.__csMod.getValue("%s/Groups/%s/Users" % (self.__baseSecurity, group)) if usersInGroup is not None: userList = List.fromChar(usersInGroup) if username not in userList: userList.append(username) self.__csMod.setOptionValue( "%s/Groups/%s/Users" % (self.__baseSecurity, group), ",".join(userList)) else: gLogger.warn("User %s is already in group %s" % (username, group)) def addUser(self, username, properties): """ Add a user to the cs :param str username: username :param dict properties: dictionary describing user properties: - DN - groups - <extra params> :return: True/False """ if not self.__initialized['OK']: return self.__initialized for prop in ("DN", "Groups"): if prop not in properties: gLogger.error("Missing property for user", "%s: %s" % (prop, username)) return S_OK(False) if username in self.listUsers()['Value']: gLogger.error("User is already registered", username) return S_OK(False) groups = self.listGroups()['Value'] for userGroup in properties['Groups']: if userGroup not in groups: gLogger.error("User group is not a valid group", "%s %s" % (username, userGroup)) return S_OK(False) self.__csMod.createSection("%s/Users/%s" % (self.__baseSecurity, username)) for prop in properties: if prop == "Groups": continue self.__csMod.setOptionValue( "%s/Users/%s/%s" % (self.__baseSecurity, username, prop), properties[prop]) for userGroup in properties['Groups']: gLogger.info("Added user %s to group %s" % (username, userGroup)) self.__addUserToGroup(userGroup, username) gLogger.info("Registered user %s" % username) self.csModified = True return S_OK(True) def modifyUser(self, username, properties, createIfNonExistant=False): """ Modify a user :param str username: group name :param dict properties: dictionary describing user properties: - DN - Groups - <extra params> :param bool createIfNonExistant: if true, registers the users if it did not exist :return: S_OK, Value = True/False """ if not self.__initialized['OK']: return self.__initialized modifiedUser = False userData = self.describeUsers([username])['Value'] if username not in userData: if createIfNonExistant: gLogger.info("Registering user %s" % username) return self.addUser(username, properties) gLogger.error("User is not registered", username) return S_OK(False) for prop in properties: if prop == "Groups": continue prevVal = self.__csMod.getValue( "%s/Users/%s/%s" % (self.__baseSecurity, username, prop)) if not prevVal or prevVal != properties[prop]: gLogger.info("Setting %s property for user %s to %s" % (prop, username, properties[prop])) self.__csMod.setOptionValue( "%s/Users/%s/%s" % (self.__baseSecurity, username, prop), properties[prop]) modifiedUser = True if 'Groups' in properties: groups = self.listGroups()['Value'] for userGroup in properties['Groups']: if userGroup not in groups: gLogger.error("User group is not a valid group", "%s %s" % (username, userGroup)) return S_OK(False) groupsToBeDeletedFrom = [] groupsToBeAddedTo = [] for prevGroup in userData[username]['Groups']: if prevGroup not in properties['Groups']: groupsToBeDeletedFrom.append(prevGroup) modifiedUser = True for newGroup in properties['Groups']: if newGroup not in userData[username]['Groups']: groupsToBeAddedTo.append(newGroup) modifiedUser = True for group in groupsToBeDeletedFrom: self.__removeUserFromGroup(group, username) gLogger.info("Removed user %s from group %s" % (username, group)) for group in groupsToBeAddedTo: self.__addUserToGroup(group, username) gLogger.info("Added user %s to group %s" % (username, group)) modified = False if modifiedUser: modified = True gLogger.info("Modified user %s" % username) self.csModified = True else: gLogger.info("Nothing to modify for user %s" % username) return S_OK(modified) def addGroup(self, groupname, properties): """ Add a group to the cs :param str groupname: group name :param dict properties: dictionary describing group properties: - Users - Properties - <extra params> :return: S_OK, Value = True/False """ if not self.__initialized['OK']: return self.__initialized if groupname in self.listGroups()['Value']: gLogger.error("Group is already registered", groupname) return S_OK(False) self.__csMod.createSection("%s/Groups/%s" % (self.__baseSecurity, groupname)) for prop in properties: self.__csMod.setOptionValue( "%s/Groups/%s/%s" % (self.__baseSecurity, groupname, prop), properties[prop]) gLogger.info("Registered group %s" % groupname) self.csModified = True return S_OK(True) def modifyGroup(self, groupname, properties, createIfNonExistant=False): """ Modify a group :param str groupname: group name :param dict properties: dictionary describing group properties: - Users - Properties - <extra params> :param bool createIfNonExistant: if true, creates the group if it did not exist :return: S_OK, Value = True/False """ if not self.__initialized['OK']: return self.__initialized modifiedGroup = False groupData = self.describeGroups([groupname])['Value'] if groupname not in groupData: if createIfNonExistant: gLogger.info("Registering group %s" % groupname) return self.addGroup(groupname, properties) gLogger.error("Group is not registered", groupname) return S_OK(False) for prop in properties: prevVal = self.__csMod.getValue( "%s/Groups/%s/%s" % (self.__baseSecurity, groupname, prop)) if not prevVal or prevVal != properties[prop]: gLogger.info("Setting %s property for group %s to %s" % (prop, groupname, properties[prop])) self.__csMod.setOptionValue( "%s/Groups/%s/%s" % (self.__baseSecurity, groupname, prop), properties[prop]) modifiedGroup = True if modifiedGroup: gLogger.info("Modified group %s" % groupname) self.csModified = True else: gLogger.info("Nothing to modify for group %s" % groupname) return S_OK(True) def addHost(self, hostname, properties): """ Add a host to the cs :param str hostname: host name :param dict properties: dictionary describing host properties: - DN - Properties - <extra params> :return: S_OK, Value = True/False """ if not self.__initialized['OK']: return self.__initialized for prop in ("DN", ): if prop not in properties: gLogger.error("Missing property for host", "%s %s" % (prop, hostname)) return S_OK(False) if hostname in self.listHosts()['Value']: gLogger.error("Host is already registered", hostname) return S_OK(False) self.__csMod.createSection("%s/Hosts/%s" % (self.__baseSecurity, hostname)) for prop in properties: self.__csMod.setOptionValue( "%s/Hosts/%s/%s" % (self.__baseSecurity, hostname, prop), properties[prop]) gLogger.info("Registered host %s" % hostname) self.csModified = True return S_OK(True) def addShifter(self, shifters=None): """ Adds or modify one or more shifters. Also, adds the shifter section in case this is not present. Shifter identities are used in several places, mostly for running agents :param dict shifters: has to be in the form {'ShifterRole':{'User':'******', 'Group':'aDIRACGroup'}} :return: S_OK/S_ERROR """ def getOpsSection(): """ Where is the shifters section? """ vo = CSGlobals.getVO() setup = CSGlobals.getSetup() if vo: res = gConfig.getSections('/Operations/%s/%s/Shifter' % (vo, setup)) if res['OK']: return S_OK('/Operations/%s/%s/Shifter' % (vo, setup)) res = gConfig.getSections('/Operations/%s/Defaults/Shifter' % vo) if res['OK']: return S_OK('/Operations/%s/Defaults/Shifter' % vo) else: res = gConfig.getSections('/Operations/%s/Shifter' % setup) if res['OK']: return S_OK('/Operations/%s/Shifter' % setup) res = gConfig.getSections('/Operations/Defaults/Shifter') if res['OK']: return S_OK('/Operations/Defaults/Shifter') return S_ERROR("No shifter section") if shifters is None: shifters = {} if not self.__initialized['OK']: return self.__initialized # get current shifters opsH = Operations() currentShifterRoles = opsH.getSections('Shifter') if not currentShifterRoles['OK']: # we assume the shifter section is not present currentShifterRoles = [] else: currentShifterRoles = currentShifterRoles['Value'] currentShiftersDict = {} for currentShifterRole in currentShifterRoles: currentShifter = opsH.getOptionsDict('Shifter/%s' % currentShifterRole) if not currentShifter['OK']: return currentShifter currentShifter = currentShifter['Value'] currentShiftersDict[currentShifterRole] = currentShifter # Removing from shifters what does not need to be changed for sRole in list(shifters): # note the pop below if sRole in currentShiftersDict: if currentShiftersDict[sRole] == shifters[sRole]: shifters.pop(sRole) # get shifters section to modify section = getOpsSection() # Is this section present? if not section['OK']: if section['Message'] == "No shifter section": gLogger.warn(section['Message']) gLogger.info("Adding shifter section") vo = CSGlobals.getVO() if vo: section = '/Operations/%s/Defaults/Shifter' % vo else: section = '/Operations/Defaults/Shifter' res = self.__csMod.createSection(section) if not res: gLogger.error("Section %s not created" % section) return S_ERROR("Section %s not created" % section) else: gLogger.error(section['Message']) return section else: section = section['Value'] # add or modify shifters for shifter in shifters: self.__csMod.removeSection(section + '/' + shifter) self.__csMod.createSection(section + '/' + shifter) self.__csMod.createSection(section + '/' + shifter + '/' + 'User') self.__csMod.createSection(section + '/' + shifter + '/' + 'Group') self.__csMod.setOptionValue(section + '/' + shifter + '/' + 'User', shifters[shifter]['User']) self.__csMod.setOptionValue( section + '/' + shifter + '/' + 'Group', shifters[shifter]['Group']) self.csModified = True return S_OK(True) def modifyHost(self, hostname, properties, createIfNonExistant=False): """ Modify a host :param str hostname: hostname name :param dict properties: dictionary describing host properties: - DN - Properties - <extra params> :param bool createIfNonExistant: if true, creates the host if it did not exist :return: S_OK, Value = True/False """ if not self.__initialized['OK']: return self.__initialized modifiedHost = False hostData = self.describeHosts([hostname])['Value'] if hostname not in hostData: if createIfNonExistant: gLogger.info("Registering host %s" % hostname) return self.addHost(hostname, properties) gLogger.error("Host is not registered", hostname) return S_OK(False) for prop in properties: prevVal = self.__csMod.getValue( "%s/Hosts/%s/%s" % (self.__baseSecurity, hostname, prop)) if not prevVal or prevVal != properties[prop]: gLogger.info("Setting %s property for host %s to %s" % (prop, hostname, properties[prop])) self.__csMod.setOptionValue( "%s/Hosts/%s/%s" % (self.__baseSecurity, hostname, prop), properties[prop]) modifiedHost = True if modifiedHost: gLogger.info("Modified host %s" % hostname) self.csModified = True else: gLogger.info("Nothing to modify for host %s" % hostname) return S_OK(True) def syncUsersWithCFG(self, usersCFG): """ Sync users with the cfg contents. Usernames have to be sections containing DN, Groups, and extra properties as parameters """ if not self.__initialized['OK']: return self.__initialized done = True for user in usersCFG.listSections(): properties = {} propList = usersCFG[user].listOptions() for prop in propList: if prop == "Groups": properties[prop] = List.fromChar(usersCFG[user][prop]) else: properties[prop] = usersCFG[user][prop] if not self.modifyUser(user, properties, createIfNonExistant=True): done = False return S_OK(done) def sortUsersAndGroups(self): self.__csMod.sortAlphabetically("%s/Users" % self.__baseSecurity) self.__csMod.sortAlphabetically("%s/Hosts" % self.__baseSecurity) for group in self.__csMod.getSections("%s/Groups" % self.__baseSecurity): usersOptionPath = "%s/Groups/%s/Users" % (self.__baseSecurity, group) users = self.__csMod.getValue(usersOptionPath) if users: usersList = sorted(List.fromChar(users)) sortedUsers = ", ".join(usersList) if users != sortedUsers: self.__csMod.setOptionValue(usersOptionPath, sortedUsers) def checkForUnexistantUsersInGroups(self): allUsers = self.__csMod.getSections("%s/Users" % self.__baseSecurity) allGroups = self.__csMod.getSections("%s/Groups" % self.__baseSecurity) for group in allGroups: usersInGroup = self.__csMod.getValue("%s/Groups/%s/Users" % (self.__baseSecurity, group)) if usersInGroup: filteredUsers = [] usersInGroup = List.fromChar(usersInGroup) for user in usersInGroup: if user in allUsers: filteredUsers.append(user) self.__csMod.setOptionValue( "%s/Groups/%s/Users" % (self.__baseSecurity, group), ",".join(filteredUsers)) def commitChanges(self, sortUsers=True): if not self.__initialized['OK']: return self.__initialized if self.csModified: self.checkForUnexistantUsersInGroups() if sortUsers: self.sortUsersAndGroups() retVal = self.__csMod.commit() if not retVal['OK']: gLogger.error("Can't commit new configuration data", "%s" % retVal['Message']) return retVal return self.downloadCSData() return S_OK() def commit(self): """ Commit the accumulated changes to the CS server """ if not self.__initialized['OK']: return self.__initialized if self.csModified: retVal = self.__csMod.commit() if not retVal['OK']: gLogger.error("Can't commit new configuration data", "%s" % retVal['Message']) return retVal return self.downloadCSData() return S_OK() def mergeFromCFG(self, cfg): """ Merge the internal CFG data with the input """ if not self.__initialized['OK']: return self.__initialized self.__csMod.mergeFromCFG(cfg) self.csModified = True return S_OK() def modifyValue(self, optionPath, newValue): """Modify an existing value at the specified options path. """ if not self.__initialized['OK']: return self.__initialized prevVal = self.__csMod.getValue(optionPath) if prevVal is None: return S_ERROR('Trying to set %s to %s but option does not exist' % (optionPath, newValue)) gLogger.verbose("Changing %s from \n%s \nto \n%s" % (optionPath, prevVal, newValue)) self.__csMod.setOptionValue(optionPath, newValue) self.csModified = True return S_OK('Modified %s' % optionPath) def setOption(self, optionPath, optionValue): """Create an option at the specified path. """ if not self.__initialized['OK']: return self.__initialized self.__csMod.setOptionValue(optionPath, optionValue) self.csModified = True return S_OK('Created new option %s = %s' % (optionPath, optionValue)) def setOptionComment(self, optionPath, comment): """Create an option at the specified path. """ if not self.__initialized['OK']: return self.__initialized self.__csMod.setComment(optionPath, comment) self.csModified = True return S_OK('Set option comment %s : %s' % (optionPath, comment)) def delOption(self, optionPath): """ Delete an option """ if not self.__initialized['OK']: return self.__initialized if not self.__csMod.removeOption(optionPath): return S_ERROR("Couldn't delete option %s" % optionPath) self.csModified = True return S_OK('Deleted option %s' % optionPath) def createSection(self, sectionPath, comment=""): """ Create a new section """ if not self.__initialized['OK']: return self.__initialized self.__csMod.createSection(sectionPath) self.csModified = True if comment: self.__csMod.setComment(sectionPath, comment) return S_OK() def delSection(self, sectionPath): """ Delete a section """ if not self.__initialized['OK']: return self.__initialized if not self.__csMod.removeSection(sectionPath): return S_ERROR("Could not delete section %s " % sectionPath) self.csModified = True return S_OK() def copySection(self, originalPath, targetPath): """ Copy a whole section to a new location """ if not self.__initialized['OK']: return self.__initialized cfg = self.__csMod.getCFG() sectionCfg = cfg[originalPath] result = self.createSection(targetPath) if not result['OK']: return result if not self.__csMod.mergeSectionFromCFG(targetPath, sectionCfg): return S_ERROR("Could not merge cfg into section %s" % targetPath) self.csModified = True return S_OK() def moveSection(self, originalPath, targetPath): """ Move a whole section to a new location """ result = self.copySection(originalPath, targetPath) if not result['OK']: return result result = self.delSection(originalPath) if not result['OK']: return result self.csModified = True return S_OK() def mergeCFGUnderSection(self, sectionPath, cfg): """ Merge the given cfg under a certain section """ if not self.__initialized['OK']: return self.__initialized result = self.createSection(sectionPath) if not result['OK']: return result if not self.__csMod.mergeSectionFromCFG(sectionPath, cfg): return S_ERROR("Could not merge cfg into section %s" % sectionPath) self.csModified = True return S_OK() def mergeWithCFG(self, cfg): """ Merge the given cfg with the current config """ if not self.__initialized['OK']: return self.__initialized self.__csMod.mergeFromCFG(cfg) self.csModified = True return S_OK() def getCurrentCFG(self): """ Get the current CFG as it is """ if not self.__initialized['OK']: return self.__initialized return S_OK(self.__csMod.getCFG()) def showDiff(self): """ Just shows the differences accumulated within the Modificator object """ diffData = self.__csMod.showCurrentDiff() gLogger.notice("Accumulated diff with master CS") for line in diffData: if line[0] in ('+', '-'): gLogger.notice(line) def forceGlobalConfigurationUpdate(self): """ Force global update of configuration on all the registered services :return: S_OK/S_ERROR """ return self.__rpcClient.forceGlobalConfigurationUpdate()