#-*- coding: utf-8 -*- # Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import os, sys, re #from cl_print import color_print from cl_datavars import DataVars from server.utils import execProg from cl_template import template from cl_api import packagesAPI, APIError from server.ldap import iniLdapParser, ldapFunction, shareldap from server.utils import genSleep from cl_utils import removeDir, _error from cl_lang import lang tr = lang() tr.setLocalDomain('cl_ldap') tr.setLanguage(sys.modules[__name__]) __version__ = "2.2.0.0" __app__ = "calculate-ldap" from cl_abstract import abs_api_service class DataVarsLdap(DataVars): """Хранение переменных""" # Имя секции в calculate2.env envSection = "ldap" def importLdap(self, **args): '''Импорт переменных для calculate-ldap''' # Импорт переменных self.importData(self.envSection, ('cl_vars_ldap','cl_fill_ldap')) class Template: """Templates methods""" def applyTemplates(self): """Apply templates""" clTempl = template(self.clVars) dirsFiles = clTempl.applyTemplates() if clTempl.getError(): self.printERROR(clTempl.getError().strip()) return False else: return dirsFiles class shareVars: """share methods template vars""" # template variables clVars = False def createClVars(self, clVars=False): """Создает объект Vars""" if not clVars: clVars = DataVarsLdap() # Импортируем переменные clVars.importLdap() # Заменяем значения переменных переменными из env файлов clVars.flIniFile() # Устанавливаем у объекта атрибут объект переменных self.clVars = clVars return self.clVars class internalMethods(abs_api_service, shareVars, Template): '''Methods ldap service''' prioritet = 25 nameService = "ldap" nameDaemon = 'slapd' _templDict = {'name':nameDaemon} # files pidFile = '/var/run/openldap/%(name)s.pid' %_templDict # command cmdPath = '/etc/init.d/%(name)s' %_templDict _templDict.update({'cmd':cmdPath}) cmdStart = '%(cmd)s start' %_templDict cmdReStart = '%(cmd)s restart' %_templDict cmdStop = '%(cmd)s stop' %_templDict cmdShowDaemons = 'rc-update show default' reShowDaemons = re.compile("(.+)\s+\|\s+.+") cmdAddRunlevel = 'rc-update add %(name)s default' %_templDict cmdDelRunlevel = 'rc-update del %(name)s default' %_templDict def get_service_name(self): '''Get name service''' return self.nameService def get_pkg_name(self): '''Get name service''' return __app__ def get_vars(self): '''Get Service vars''' return self.createClVars(self.clVars) def is_setup(self): '''Is setup service (True/False)''' self.createClVars(self.clVars) return self.clVars.Get('sr_ldap_set') == "on" def _getRunlevelDaemons(self): """Получаем всех демонов в default уровне""" textLines = execProg(self.cmdShowDaemons) if textLines is False: self.printERROR(_("ERROR") + ": " + self.cmdShowDaemons) return False else: daemons = [] for line in textLines: res = self.reShowDaemons.search(line) if res: daemon = res.groups(0)[0] daemons.append(daemon) return daemons def is_start(self): '''Run ldap server (True/False)''' if os.access(self.pidFile, os.R_OK): pid = open(self.pidFile).read().strip() if pid: procDir = "/proc"+"/"+pid if os.access(procDir, os.F_OK): return True return False def start(self): '''Start LDAP server''' if not self.is_start(): if execProg(self.cmdStart) is False: self.printERROR(_("Can't execute '%s'") %self.cmdStart) self.printNotOK(_("Starting LDAP") + " ...") return False return True def restart(self): '''Restart LDAP server''' if self.is_start(): if execProg(self.cmdReStart) is False: self.printERROR(_("Can't execute '%s'") %self.cmdReStart) self.printNotOK(_("Restarting LDAP")+ " ...") return False else: return self.start() return True def stop(self): '''Stop LDAP server''' if self.is_start(): if execProg(self.cmdStop) is False: self.printERROR(_("Can't execute '%s'") %self.cmdStop) self.printNotOK(_("Stopping LDAP")+ " ...") return False return True def is_runlevel(self): '''Находится ли LDAP в автозагрузке''' daemons = self._getRunlevelDaemons() if daemons is False: return False if self.nameDaemon in daemons: return True else: return False def add_runlevel(self): '''Add daemon to runlevel''' if not self.is_runlevel(): if execProg(self.cmdAddRunlevel) is False: self.printERROR(_("Can't execute '%s'") %self.cmdAddRunlevel) self.printNotOK(_("service %(name)s added to runlevel")\ %self._templDict + " ...") return False return True def del_runlevel(self): '''Delete daemon from runlevel''' if self.is_runlevel(): if execProg(self.cmdDelRunlevel) is False: self.printERROR(_("Can't execute '%s'") %self.cmdDelRunlevel) self.printNotOK(_("service %(name)s removed from runlevel")\ %self._templDict + " ...") return False return True def get_prioritet(self): '''Get run daemon prioritet''' return self.prioritet def del_vars_from_env(self): '''Delete template vars in env files''' self.createClVars(self.clVars) deleteVariables = ("sr_ldap_set",) locations = map(lambda x: x[0], self.clVars.Get("cl_env_data")) for varName in deleteVariables: for locate in locations: if not self.clVars.Delete(varName, location=locate, header=self.clVars.envSection): fileName = filter(lambda x: x[0] == locate, self.clVars.Get("cl_env_data"))[0][1] self.printERROR(_("Can't delete variable '%(name)s' " "in file %(file)s") %{'name':varName, 'file':fileName}) return False return True def updateVars(self): self.createClVars() return True def get_service_info(self, request): '''Get service information''' res = "" if request == "scheme": self.createClVars(self.clVars) res = self.clVars.Get('ld_ldap_scheme_conf') elif request == "access_pw": self.createClVars(self.clVars) res = self.clVars.Get('ld_ldap_access_pw_conf') elif request == "access_dn": self.createClVars(self.clVars) res = self.clVars.Get('ld_ldap_access_dn_conf') return res def scheme(self): '''include lines in slapd.conf''' return self.get_service_info('scheme') def access_pw(self): '''Access userPasswod lines in slapd.conf''' return self.get_service_info('access_pw') def access_dn(self): '''Access DN lines in slapd.conf''' return self.get_service_info('access_dn') def apply_templates(self): '''Apply package templates''' if self.is_setup(): self.clVars.Set("cl_ldap_update_action","up", force=True) return Template.applyTemplates(self) return True class Singleton(object): _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super(Singleton, cls).__new__( cls, *args, **kwargs) return cls._instance class allMethods(Singleton, internalMethods, shareldap): """Методы севисa Ldap""" # Базовый ldif файл ldifFileBase = '/usr/lib/calculate-2.2/calculate-ldap/ldif/base.ldif' apiFile = '/usr/lib/calculate-2.2/calculate-ldap/pym/cl_ldap_api.py' libAPIObj = packagesAPI() def removeLdapDatabase(self): """Удаляем предыдущую базу данных""" pathDatabase = "/var/lib/openldap-data" #if os.path.exists(pathDatabase) and os.listdir(pathDatabase): #if os.system("rm /var/lib/openldap-data/* &>/dev/null") !=0: #self.printERROR("Can't remove /var/lib/openldap-data/*") #return False #return True if os.path.exists(pathDatabase): fileOrDirNames = os.listdir(pathDatabase) if fileOrDirNames: for fileOrDirName in fileOrDirNames: fullFileOrDirName = os.path.join(pathDatabase, fileOrDirName) if os.path.isdir(fullFileOrDirName): try: removeDir(pathDatabase) except: self.printERROR(_("Can't remove directory %s")\ %fullFileOrDirName) return False else: try: os.remove(fullFileOrDirName) except: self.printERROR(_("Can't remove file %s")\ %fullFileOrDirName) return False self.printOK(_("Erased LDAP Database") + " ...") return True def connectLdapServer(self): """Соединяемся с LDAP сервером используем DN и пароль временного админстратора """ # Если раннее была ошибка то выходим if self.getError(): self.printERROR (_("ERROR") + ": " +\ self.getError().strip()) return False tmpDn = self.clVars.Get("ld_temp_dn") tmpPw = self.clVars.Get("ld_temp_pw") ldapObj = ldapFunction(tmpDn, tmpPw) # Генератор задержек wait = genSleep() while ldapObj.getError(): try: # Задержка wait.next() except StopIteration: break # Очистка ошибки _error.error = [] ldapObj = ldapFunction(tmpDn, tmpPw) self.ldapObj = ldapObj self.conLdap = ldapObj.conLdap if ldapObj.getError(): # Удаляем одинаковые ошибки listError = [] for e in ldapObj.error: if not e in listError: listError.append(e) _error.error = listError self.printERROR(_("Can not connected to LDAP server")) return False return True def setup(self, force=False): """Настройка LDAP сервиса (создание дерева)""" # Принудительная установка if self.clVars.Get("sr_ldap_set") == "on" and not force: self.printWARNING (_("WARNING") + ": " +\ _("LDAP server is configured")+ ".") return True if not force: # предупреждение при выполнении этой программы будут изменены # конфигурационные файлы и база данных сервиса LDAP а также # конфигурационные файлы установленных сервисов self.printWARNING (_("WARNING") + ": " +\ _("Executing of the program will change") + " " +\ _("the configuration files and database of LDAP service")+\ ".") # если вы готовы продолжить работу программы нажмите Y если нет n messDialog = \ _("If you are ready to continue executing the program")+", "+\ _("input 'yes'") +", "+ _("if not 'no'") if not dialogYesNo(messDialog): return True else: # делаем backup # Проверим запущен ли ldap if not self.is_start(): # Запускаем LDAP сервер if not self.start(): return False #if not self.backupServer(): #return False if self.is_runlevel(): # Удаляем из автозапуска демона if not self.del_runlevel(): return False listAPIObj = self.libAPIObj.all.APIList() listAPIObjReverse = self.libAPIObj.all.APIListReverse() if filter(lambda x:\ x.api.get_pkg_name()=="calculate_ldap",listAPIObj): self.printERROR(_("Can not found API module in package " "calculate-ldap")) self.printWARNING(_("Run: cl-ldap-setup --install")) return False # Останавливаем все установленные сервисы for obj in listAPIObjReverse: apiObj = obj.api if hasattr(apiObj, 'stop') and not apiObj.stop(): return False # Удаляем из автозагрузки все установленные сервисы for obj in listAPIObjReverse: apiObj = obj.api if hasattr(apiObj, 'del_runlevel') and not apiObj.del_runlevel(): return False # Удаляем из крона скрипт для чистки удаленых пользователей # создаем объект репликации #objRepl = servRepl() #if not objRepl.cronReplicationOFF(): #return False # Удаляем из share файл .replrun #if not self.servSambaObj.delReplFile(self.clVars): #return False # Удаляем переменные for obj in listAPIObjReverse: apiObj = obj.api if hasattr(apiObj,'del_vars_from_env') and \ not apiObj.del_vars_from_env(): return False # Получим путь к ldap файлу ldapParser = iniLdapParser() ldapFile = ldapParser.nameIniFile # Удаляем ldap файл if os.path.exists(ldapFile): os.remove(ldapFile) self.clVars.Write("sr_ldap_set", "off",force=True) self.clVars.Set("sr_ldap_set", "on", force=True) self.clVars.Set("cl_ldap_setup_action","up", force=True) # Первый проход self.clVars.Set("cl_pass_step", "1", True) if self.applyTemplates() is False: self.printERROR(_("Can not apply templates") + ":" + " " +\ _("first pass")) return False # Удаляем старую базу данных if not self.removeLdapDatabase(): return False # Запускаем LDAP сервер if not self.start(): return False # Соединяемся с LDAP временным пользователем if not self.connectLdapServer(): return False # Получаем текст нужного ldif-a baseLdif = self.createLdif(self.ldifFileBase) # Если нет ошибок при соединении применяем ldif if not self.ldapObj.getError(): self.ldapObj.ldapAdd(baseLdif) if self.ldapObj.getError(): print _("LDAP Error") + ": " + self.ldapObj.getError().strip() return False self.printOK(_("Added ldif file") + " ...") # Второй проход, # удаляем временного пользователя root из конфигурационного файла self.clVars.Set("cl_pass_step","2",True) if self.applyTemplates() is False: self.printERROR(_("Can not apply profiles") +":"+ _("second pass")) return False # Перезапускаем LDAP сервер if not self.restart(): return False # Записываем данные администратора сервера ldapParser.setVar("admin", {"DN":self.clVars.Get("ld_admin_dn"), "PASS":self.clVars.Get("ld_admin_pw")}) # Устанавливаем автозапуск демона if not self.add_runlevel(): return False # Записываем переменные для пользователя #clientVars = ["ur_organization", "ur_signature"] #if not self.saveVarsClient(clientVars): #return False self.clVars.Write("sr_ldap_set","on",force=True) self.printOK(_("LDAP service configured") + " ...") return True REGISTERED_METHODS = ['add_runlevel', 'apply_templates', 'get_pkg_name', 'get_prioritet', 'get_service_info', 'get_service_name', 'get_vars','is_runlevel', 'is_setup', 'is_start', 'restart', 'scheme', 'setup', 'start', 'stop'] class serviceAPI(object): """Proxy object""" def __init__(self): self.__subject = allMethods() for attr in dir(self.__subject): if attr in REGISTERED_METHODS: object.__setattr__(self, attr, getattr(self.__subject, attr))