From 169141c918c7e902dfd0ac542748082791bd10b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A5=D0=B8=D1=80=D0=B5=D1=86=D0=BA=D0=B8=D0=B9=20=D0=9C?= =?UTF-8?q?=D0=B8=D1=85=D0=B0=D0=B8=D0=BB?= Date: Mon, 23 May 2016 14:46:49 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=D0=B0=20?= =?UTF-8?q?=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82=D1=83=D1=80=D0=B0=20=D0=BC?= =?UTF-8?q?=D0=BE=D0=B4=D1=83=D0=BB=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README | 15 - i18n/cl_ldap_ru.mo | Bin 128686 -> 0 bytes ldif/base.ldif | 30 -- pym/cl_fill_ldap.py | 62 ----- pym/cl_ldap_api.py | 474 -------------------------------- pym/cl_ldap_service.py | 53 ---- pym/cl_ldap_setup_cmd.py | 109 -------- pym/cl_share_cmd.py | 83 ------ pym/cl_vars_ldap.py | 108 -------- pym/{ => ldap}/__init__.py | 0 pym/ldap/datavars.py | 33 +++ pym/ldap/ldap.py | 40 +++ pym/ldap/utils/__init__.py | 0 pym/ldap/utils/cl_ldap_setup.py | 47 ++++ pym/ldap/variables/__init__.py | 20 ++ pym/ldap/variables/action.py | 37 +++ pym/ldap/variables/ldap.py | 20 ++ pym/ldap/wsdl_ldap.py | 74 +++++ scripts/cl-ldap-setup | 65 ----- setup.cfg | 5 - setup.py | 84 ++---- 21 files changed, 294 insertions(+), 1065 deletions(-) delete mode 100644 README delete mode 100644 i18n/cl_ldap_ru.mo delete mode 100644 ldif/base.ldif delete mode 100644 pym/cl_fill_ldap.py delete mode 100644 pym/cl_ldap_api.py delete mode 100644 pym/cl_ldap_service.py delete mode 100644 pym/cl_ldap_setup_cmd.py delete mode 100644 pym/cl_share_cmd.py delete mode 100644 pym/cl_vars_ldap.py rename pym/{ => ldap}/__init__.py (100%) create mode 100644 pym/ldap/datavars.py create mode 100644 pym/ldap/ldap.py create mode 100644 pym/ldap/utils/__init__.py create mode 100644 pym/ldap/utils/cl_ldap_setup.py create mode 100644 pym/ldap/variables/__init__.py create mode 100644 pym/ldap/variables/action.py create mode 100644 pym/ldap/variables/ldap.py create mode 100644 pym/ldap/wsdl_ldap.py delete mode 100644 scripts/cl-ldap-setup delete mode 100644 setup.cfg diff --git a/README b/README deleted file mode 100644 index 22bb42d..0000000 --- a/README +++ /dev/null @@ -1,15 +0,0 @@ -AUTHOR: Calculate Ltd. - -INSTALL -------- - -calculate-ldap needs the following library version installed, in order to run: - python >= 2.5 - python-ldap >= 2.0.0 - pyxml >= 0.8 - calculate-lib >= 2.2.0.0 - -To install calculate-ldap, just execute the install script 'setup.py'. -Example: - - ./setup.py install diff --git a/i18n/cl_ldap_ru.mo b/i18n/cl_ldap_ru.mo deleted file mode 100644 index 8d12e9e7fe1689513835068be93239448822e67c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 128686 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 VD|bebVQa~wrX1C3AiF(^^&F$S z@L!GbHr~OTPk!87Et+yvuIsh6B4BW(jphbntk~O6>BdoQlpcnJn)tsxo#Pe(Xp*n_ zXXl?ee{tirEm>tqStepX(*ad$1`vQUoE}}I)XnQ*e1s6f1$(hea)o#8OW9$;Mz$RS z0*&Zna@T9q*R<^rNYh>9@m9_d;4)df5*_z9f0;k}>_Spokn)aydF{sC*Vr{=QTEc6 z5;@(H$<@RNbnAy|W3B`+h64?N9f?m$)@N2Rp635Rciihj^%(aaPBohP6m_YIzfOpW zHktKB(fnU=fE2vsul9)SiU7WERe@#hXqXBVYX(B9kRI7zLKKl8co;t z)VoRc9D&Qw=YhS#P_TRCe1ATfh{?YgWWp<5m~XTx*?~zyT~Y9NvWdJyL*=FlqWsa? zTFf1?<$B;kJTi#jU@M^sl2{+`v_(fVVmdmcZm#$o_{9tpbcvj$--7&De#9S5vAgum zKS~hr@5dmF9B}#wz-k|rob;gabrmys>f$q-qvbJtCd#ZH`GP;wG;WvKWK<=>VX3w* zmmDxt+5_=oGghHNz(-w)QTBihsv|2hzKcP{DL*R&o{{iWblkRYkCHEH)1CTVC|pql zFl4261DeG#E}-_p08c-u8tcbK2C!)+imEO~%EDNXA3kTW%9c)>=?_J@I=ARnvq~aP zI>-A!AA0mbZeiQHv=P*y&gUmJj0Ect<<85wj~9xX%~3Av$mGR1A)W^0;r#nmotII7WWrR#K{DkDX<$s#@^ znF}n;ngil}W;baiixkdKSV0jYFc3pW^?-d~W;mgjmTkaXl5?y&X@}p+g4hFTAqPL+CYnatSk}xnp(e`rL>$Lx~sbJs)@+E2~RTC z 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 WG)A1N8P#gL(x_JUReTD?U;iKVg=5eF diff --git a/ldif/base.ldif b/ldif/base.ldif deleted file mode 100644 index d578635..0000000 --- a/ldif/base.ldif +++ /dev/null @@ -1,30 +0,0 @@ -# Directory Server -dn: #-ld_base_dn-# -objectClass: dcObject -objectClass: organization -dc: #-ld_base_root-# -o: Calculate Directory Server - -# Services -dn: #-ld_services_dn-# -objectClass: top -objectClass: organizationalUnit -ou: Services - -# Admin -dn: #-ld_admin_dn-# -cn: #-ld_admin_login-# -sn: #-ld_admin_login-# -objectClass: person -objectClass: top -description: LDAP Administrator stuff -userPassword: #-ld_admin_hash-# - -# Bind -dn: #-ld_bind_dn-# -cn: #-ld_bind_login-# -sn: #-ld_bind_login-# -objectClass: person -objectClass: top -description: LDAP Proxy User -userPassword: #-ld_bind_hash-# diff --git a/pym/cl_fill_ldap.py b/pym/cl_fill_ldap.py deleted file mode 100644 index 5925091..0000000 --- a/pym/cl_fill_ldap.py +++ /dev/null @@ -1,62 +0,0 @@ -#-*- 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 -from cl_datavars import glob_attr -from cl_utils import genpassword -from encrypt import getHash - -class fillVars(glob_attr): - addDn = lambda x,*y: ",".join(y) - genDn = lambda x,*y: "=".join(y) - - def get_ld_temp_dn(self): - #DN временного пользователя root (для инициализации базы данных) - return self.addDn(self.genDn("cn", "ldaproot"), self.Get('ld_base_dn')) - - def get_ld_temp_pw(self): - """пароль временного пользователя root""" - return genpassword() - - def get_ld_temp_hash(self): - """hash пароля временного root""" - return getHash(self.Get('ld_temp_pw'), self.Get('ld_encrypt')) - - def get_ld_ldap_access_pw_conf(self): - """строки доступа к аттрибуту userPassword в slapd.conf""" - return ' by dn="%s" write' %self.Get("ld_admin_dn") - - def get_ld_ldap_access_dn_conf(self): - """строки доступа к LDAP DN сервиса в slapd.conf""" - templStart = 'access to dn.regex=".*%(repl_dn)s$"\n'\ - ' by dn="%(admin_dn)s" write\n'\ - ' by dn="%(repl_dn)s" write\n'\ - ' by dn="%(bind_dn)s" read\n' - templMail = ' by dn="%(mail_dn)s" read\n' - templEnd = ' by * none' - templ = "" - if self.Get("ld_repl_set")=="on" and self.Get("ld_repl_id")!="": - templ += templStart - templDict = {'admin_dn':self.Get("ld_admin_dn"), - 'repl_dn':self.Get("ld_repl_dn"), - 'bind_dn':self.Get("ld_bind_dn")} - mailDn = self.clGetVar("calculate-mail", "cl_mail_dn") - if mailDn: - templDict.update({'mail_dn':mailDn}) - templ += templMail - templ += templEnd - return templ%templDict - return "" diff --git a/pym/cl_ldap_api.py b/pym/cl_ldap_api.py deleted file mode 100644 index f3bf5e0..0000000 --- a/pym/cl_ldap_api.py +++ /dev/null @@ -1,474 +0,0 @@ -#-*- 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("ac_ldap_update","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("ac_ldap_setup","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.apply_templates() - self.clVars.Write("sr_ldap_set","on",force=True) - self.printOK(_("LDAP service configured") + " ...") - return True - -REGISTERED_METHODS = ['access_pw', 'access_pw', '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)) - - - \ No newline at end of file diff --git a/pym/cl_ldap_service.py b/pym/cl_ldap_service.py deleted file mode 100644 index e0a2a3b..0000000 --- a/pym/cl_ldap_service.py +++ /dev/null @@ -1,53 +0,0 @@ -#-*- 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. - -from cl_ldap_api import allMethods, __app__ -from cl_utils import appendProgramToEnvFile, removeProgramToEnvFile - -import sys -from cl_lang import lang -lang().setLanguage(sys.modules[__name__]) - -class ldapService(allMethods): - - def installProg(self): - '''Install this program''' - apiDict = self.clVars.Get("cl_api") - apiDict.update({__app__:self.apiFile}) - self.clVars.Write("cl_api", force=True) - if not appendProgramToEnvFile(__app__, self.clVars): - self.printERROR(_("Can not save '%s'") %__app__ + " " +\ - _("to %s") %self.clVars.Get("cl_env_path")[0]) - return False - self.printOK(_("Save install variables")) - return True - - def uninstallProg(self): - '''Uninstall this program''' - apiDict = self.clVars.Get("cl_api") - if __app__ in apiDict: - apiDict.pop(__app__) - self.clVars.Write("cl_api", force=True) - if not removeProgramToEnvFile(__app__, self.clVars): - self.printERROR(_("Can not remove '%s' to %s")%(__app__, - self.clVars.Get("cl_env_path")[0])) - return False - self.printOK(_("Delete install variables")) - return True - - def printVars(self, *arg, **argv): - """Печать существующих переменных""" - self.clVars.printVars(*arg, **argv) diff --git a/pym/cl_ldap_setup_cmd.py b/pym/cl_ldap_setup_cmd.py deleted file mode 100644 index 7f93ee4..0000000 --- a/pym/cl_ldap_setup_cmd.py +++ /dev/null @@ -1,109 +0,0 @@ -#-*- coding: utf-8 -*- - -# Copyright 2010 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. -from cl_ldap_api import __app__, __version__ -from cl_ldap_service import ldapService -from cl_opt import opt -import sys -from cl_share_cmd import share_cmd - -# Перевод сообщений для программы -from cl_lang import lang -lang().setLanguage(sys.modules[__name__]) - -# Использование программы -USAGE = _("%prog [options]") - -# Коментарии к использованию программы -COMMENT_EXAMPLES = _("Create LDAP tree") - -# Пример использования программы -EXAMPLES = _("%prog") - -# Описание программы (что делает программа) -DESCRIPTION = _("Creating LDAP tree") - -# Опции командной строки -CMD_OPTIONS = [{'shortOption':"f", - 'longOption':"force", - 'help':_("forced setup service ldap")}, - {'longOption':"install", - 'help':_("configure the system to install this package")}, - {'longOption':"uninstall", - 'help':_("configure the system to uninstall this package")}] - -class ldap_setup_cmd(share_cmd): - def __init__(self): - # Объект опций командной строки - self.optobj = opt(package=__app__, - version=__version__, - usage=USAGE, - examples=EXAMPLES, - comment_examples=COMMENT_EXAMPLES, - description=DESCRIPTION, - option_list=CMD_OPTIONS +\ - opt.variable_control+opt.color_control, - check_values=self.checkOpts) - # Создаем объект логики - self.logicObj = ldapService() - # Создаем переменные - self.logicObj.createClVars() - # Названия несовместимых опций - self.optionsNamesIncompatible = ["install", "uninstall", "f"] - - def getIncompatibleOptions(self, optObj): - """Получаем несовместимые опции""" - retList = [] - for nameOpt in self.optionsNamesIncompatible: - retList.append(getattr(optObj, nameOpt)) - return retList - - def _getNamesAllSetOptions(self): - """Выдает словарь измененных опций""" - setOptDict = self.optobj.values.__dict__.items() - defaultOptDict = self.optobj.get_default_values().__dict__.items() - return dict(set(setOptDict) - set(defaultOptDict)).keys() - - def getStringIncompatibleOptions(self): - """Форматированная строка несовместимых опций разделенных ','""" - listOpt = list(set(self.optionsNamesIncompatible) &\ - set(self._getNamesAllSetOptions())) - return ", ".join(map(lambda x: len(x) == 1 and "'-%s'"%x or "'--%s'"%x,\ - listOpt)) - - def checkOpts(self, optObj, args): - """Check command line opt and arg""" - if len(filter(lambda x: x, self.getIncompatibleOptions(optObj)))>1: - errMsg = _("incompatible options")+":"+" %s"\ - %self.getStringIncompatibleOptions() - self.optobj.error(errMsg) - return False - if args: - errMsg = _("incorrect argument") + ":" + " %s" %" ".join(args) - self.optobj.error(errMsg) - return False - return optObj, args - - def setup(self, force=False): - """Setup program""" - return self.logicObj.setup(force=force) - - def install(self): - """Инсталяция программы""" - return self.logicObj.installProg() - - def uninstall(self): - """Удаление программы""" - return self.logicObj.uninstallProg() \ No newline at end of file diff --git a/pym/cl_share_cmd.py b/pym/cl_share_cmd.py deleted file mode 100644 index e1cf764..0000000 --- a/pym/cl_share_cmd.py +++ /dev/null @@ -1,83 +0,0 @@ -#-*- coding: utf-8 -*- - -# Copyright 2010 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 sys - -from cl_print import color_print -from cl_utils import _error - -# Перевод сообщений для программы -from cl_lang import lang -lang().setLanguage(sys.modules[__name__]) - -class share_cmd(color_print, _error): - """Класс общих методов обработки опций командной строки""" - - def printVars(self, optObj): - """Печать переменных""" - if optObj.v: - varsFilter = None - varsNames = [] - format = "default" - # Фильтрование переменных - if optObj.filter: - optCmd = optObj.filter - if ',' in optCmd: - varsNames = optCmd.split(",") - elif '*' in optCmd: - varsFilter = optCmd.replace("*", ".*") - else: - varsNames.append(optCmd) - if optObj.xml: - format = "xml" - try: - v = int(optObj.v) - except: - v = 1 - self.logicObj.printVars(varsFilter, varsNames, outFormat=format, - verbose=v) - - def setVars(self, optObj): - """Установка переменных""" - if optObj.set: - for vals in optObj.set: - for val in vals.split(','): - k,o,v = val.partition('=') - if self.logicObj.clVars.exists(k): - if not self.logicObj.clVars.SetWriteVar(k,v): - return False - else: - self.printERROR(_('variable %s not found')%k) - return False - return True - - def writeVars(self, optObj): - """Запись переменных""" - if optObj.set: - if not self.logicObj.clVars.WriteVars(): - errMsg = self.getError() - if errMsg: - self.printERROR(errMsg.strip()) - self.printERROR(_('Can not write template variables')) - return False - return True - - def setPrintNoColor(self, optObj): - """Установка печати сообщений без цвета""" - if optObj.color and optObj.color=="never": - color_print.colorPrint = lambda *arg : sys.stdout.write(arg[-1]) or\ - sys.stdout.flush() - diff --git a/pym/cl_vars_ldap.py b/pym/cl_vars_ldap.py deleted file mode 100644 index adf371e..0000000 --- a/pym/cl_vars_ldap.py +++ /dev/null @@ -1,108 +0,0 @@ -#-*- 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. - -from cl_ldap_api import __version__, __app__ - -class Data: - #базовый суффикс LDAP - ld_base_dn = {} - - #bind суффикс LDAP - ld_bind_dn = {} - - #пользователь только для чтения - ld_bind_login = {} - - #hash пароля для пользователя для чтения - ld_bind_hash = {} - - #пароль для пользователя для чтения - ld_bind_pw = {} - - #алгоритм шифрования паролей - ld_encrypt = {} - - #имя для базового суффикса LDAP - ld_base_root = {} - - #временный пользователь root для инициализации базы данных - ld_temp_dn = {} - - #hash пароля временного root - ld_temp_hash = {} - - #пароль временного пользователя root - ld_temp_pw = {} - - #DN пользователя root - ld_admin_dn = {} - - #имя пользователя root для LDAP - ld_admin_login = {} - - #hash пароля root - ld_admin_hash = {} - - #пароль root - ld_admin_pw = {} - - #Имя для всех сервисов - ld_services= {} - - #DN всех сервисов - ld_services_dn = {} - - #Настроен или нет сервис LDAP - sr_ldap_set = {'mode':"w",'value':'off'} - - # имя программы - cl_name = {'value':__app__} - - # версия программы - cl_ver = {'value':__version__} - - # действие программа устанавливает сервис - ac_ldap_setup = {'value':'down'} - - # действие программа обновляет конфигурационные файлы - ac_ldap_update = {'value':'down'} - - # include строки в slapd.conf - ld_ldap_scheme_conf = {'value':\ - "include\t\t/etc/openldap/schema/core.schema\n"\ - "include\t\t/etc/openldap/schema/cosine.schema\n"\ - "include\t\t/etc/openldap/schema/nis.schema\n"\ - "include\t\t/etc/openldap/schema/inetorgperson.schema\n"\ - "include\t\t/etc/openldap/schema/misc.schema"} - - # строки доступа к аттрибуту userPassword в slapd.conf - ld_ldap_access_pw_conf = {} - - # строки доступа к LDAP DN сервиса в slapd.conf - ld_ldap_access_dn_conf = {} - - ld_repl_set = {'value':'off'} - - ld_repl_id = {} - - ld_repl_servers_info = {} - - ld_repl_servers_ref = {} - - # lib vars - cl_pass_step = {} - cl_api = {} - cl_env_path = {} diff --git a/pym/__init__.py b/pym/ldap/__init__.py similarity index 100% rename from pym/__init__.py rename to pym/ldap/__init__.py diff --git a/pym/ldap/datavars.py b/pym/ldap/datavars.py new file mode 100644 index 0000000..bd62d03 --- /dev/null +++ b/pym/ldap/datavars.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- + +# Copyright 2016 Mir Calculate. 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 sys +from calculate.lib.datavars import DataVars +from calculate.lib.utils.tools import AddonError + +from calculate.lib.cl_lang import setLocalTranslate + +setLocalTranslate('cl_ldap3', sys.modules[__name__]) + +class DataVarsLdap(DataVars): + """Variable class for desktop package""" + var_module = "ldap" + + def importLdap(self, **args): + """Import desktop variables""" + self.importVariables() + self.importVariables('calculate.%s.variables' % self.var_module) + self.defaultModule = self.var_module diff --git a/pym/ldap/ldap.py b/pym/ldap/ldap.py new file mode 100644 index 0000000..bb925c8 --- /dev/null +++ b/pym/ldap/ldap.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- + +# Copyright 2016 Mir Calculate. 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 sys +from calculate.core.server.func import MethodsInterface + +_ = lambda x: x +from calculate.lib.cl_lang import (setLocalTranslate, getLazyLocalTranslate) + +setLocalTranslate('cl_ldap3', sys.modules[__name__]) +__ = getLazyLocalTranslate(_) + +class LdapError(Exception): + pass + +class Ldap(MethodsInterface): + """Основной объект для выполнения действий связанных + с настройкой LDAP сервиса + + """ + + class Method(object): + Setup = "ldap_setup" + All = (Setup,) + + def init(self): + pass diff --git a/pym/ldap/utils/__init__.py b/pym/ldap/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pym/ldap/utils/cl_ldap_setup.py b/pym/ldap/utils/cl_ldap_setup.py new file mode 100644 index 0000000..7d7fade --- /dev/null +++ b/pym/ldap/utils/cl_ldap_setup.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- + +# Copyright 2016 Mir Calculate. 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 sys +from calculate.core.server.func import Action, Tasks +from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate +from calculate.lib.cl_template import TemplatesError +from calculate.lib.utils.files import FilesError +from ..ldap import LdapError + +_ = lambda x: x +setLocalTranslate('cl_ldap3', sys.modules[__name__]) +__ = getLazyLocalTranslate(_) + + +class ClLdapSetupAction(Action): + """ + Действие обновление конфигурационных файлов + """ + # ошибки, которые отображаются без подробностей + native_error = (FilesError, + TemplatesError, + LdapError) + + successMessage = __("SUCCESS") + failedMessage = __("FAILED") + interruptMessage = __("INTERRUPT") + + # список задач для действия + tasks = [ + {'name': 'test', + 'message': 'test' + } + ] diff --git a/pym/ldap/variables/__init__.py b/pym/ldap/variables/__init__.py new file mode 100644 index 0000000..0617c7d --- /dev/null +++ b/pym/ldap/variables/__init__.py @@ -0,0 +1,20 @@ +#-*- coding: utf-8 -*- + +# Copyright 2016 Mir Calculate. 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 action +import ldap + +section = "ldap" diff --git a/pym/ldap/variables/action.py b/pym/ldap/variables/action.py new file mode 100644 index 0000000..bc844e4 --- /dev/null +++ b/pym/ldap/variables/action.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- + +# Copyright 2016 Mir Calculate. 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 sys +from calculate.lib.datavars import ActionVariable + +from calculate.lib.cl_lang import setLocalTranslate + +setLocalTranslate('cl_ldap3', sys.modules[__name__]) + + +class Actions(object): + Setup = "ldap_setup" + + +class VariableAcLdapSetup(ActionVariable): + """ + Action variable which has value "on" for prepare squash + """ + + def action(self, cl_action): + if cl_action == Actions.Setup: + return "on" + return "off" diff --git a/pym/ldap/variables/ldap.py b/pym/ldap/variables/ldap.py new file mode 100644 index 0000000..e1cdec8 --- /dev/null +++ b/pym/ldap/variables/ldap.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- + +# Copyright 2016 Mir Calculate. 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 sys +from calculate.lib.cl_lang import setLocalTranslate + +setLocalTranslate('cl_ldap3', sys.modules[__name__]) diff --git a/pym/ldap/wsdl_ldap.py b/pym/ldap/wsdl_ldap.py new file mode 100644 index 0000000..ff11336 --- /dev/null +++ b/pym/ldap/wsdl_ldap.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- + +# Copyright 2016 Mir Calculate. 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 sys + +from calculate.lib.datavars import VariableError, DataVarsError + +from calculate.core.server.func import WsdlBase +from .ldap import Ldap, LdapError +from .variables.action import Actions as LdapActions +from utils.cl_ldap_setup import ClLdapSetupAction + +_ = lambda x: x +from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate + +setLocalTranslate('cl_ldap3', sys.modules[__name__]) +__ = getLazyLocalTranslate(_) + + +class Wsdl(WsdlBase): + methods = [ + # + # Настроить службу + # + { + # идентификатор метода + 'method_name': Ldap.Method.Setup, + # категория метода + 'category': __('LDAP'), + # заголовок метода + 'title': __("Setup"), + # иконка для графической консоли + 'image': 'setup', + # метод присутствует в графической консоли + 'gui': True, + # консольная команда + 'command': 'cl-ldap-setup', + # права для запуска метода + 'rights': ['ldap'], + # объект содержащий модули для действия + 'logic': {'Ldap': Ldap}, + # описание действия + 'action': ClLdapSetupAction, + # объект переменных + 'datavars': "ldap", + 'native_error': (VariableError, DataVarsError, LdapError), + # значения по умолчанию для переменных этого метода + 'setvars': {'cl_action!': LdapActions.Setup}, + # описание груп (список лямбда функций) + 'groups': [ + lambda group: group( + _("Repository"), + brief=(), + hide=(), + normal=(), + expert=()), + ], + 'brief': {'next': __("Perform"), + 'name': __("Setup LDAP"),} + }, + ] diff --git a/scripts/cl-ldap-setup b/scripts/cl-ldap-setup deleted file mode 100644 index 5343aa3..0000000 --- a/scripts/cl-ldap-setup +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/python -#-*- coding: utf-8 -*- - -# Copyright 2010 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 sys -import os -sys.path.insert(0,os.path.abspath('/usr/lib/calculate-2.2/calculate-lib/pym')) -sys.path.insert(0,\ - os.path.abspath('/usr/lib/calculate-2.2/calculate-ldap/pym')) - -from cl_ldap_setup_cmd import ldap_setup_cmd - -from cl_lang import lang -tr = lang() -tr.setGlobalDomain('cl_ldap') -tr.setLanguage(sys.modules[__name__]) - -if __name__ == "__main__": - obj = ldap_setup_cmd() - ret = obj.optobj.parse_args() - if ret is False: - sys.exit(1) - opts, args = ret - # Установка цвета при печати сообщений - obj.setPrintNoColor(opts) - # Установка переменных - if not obj.setVars(opts): - sys.exit(1) - # Печать переменных - obj.printVars(opts) - # Если нет печати переменных выполняем логику программы - if not opts.v and not opts.filter and not opts.xml: - if not filter(lambda x: x[1], obj.optobj.values.__dict__.items()): - # Setup - if not obj.setup(): - sys.exit(1) - elif opts.f: - # Force setup - if not obj.setup(force=True): - sys.exit(1) - elif opts.install: - # Install - if not obj.install(): - sys.exit(1) - elif opts.uninstall: - # Uninstall - if not obj.uninstall(): - sys.exit(1) - # Запись переменных - if not obj.writeVars(opts): - sys.exit(1) - sys.exit(0) diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index b36081a..0000000 --- a/setup.cfg +++ /dev/null @@ -1,5 +0,0 @@ -[install] -install-scripts=/usr/bin -install-purelib=/usr/lib/calculate-2.2 -install-platlib=/usr/lib/calculate-2.2 -install-data=/usr/lib/calculate-2.2/calculate-ldap \ No newline at end of file diff --git a/setup.py b/setup.py index 1fdae5e..bc296d5 100755 --- a/setup.py +++ b/setup.py @@ -1,9 +1,10 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # -*- coding: utf-8 -*- # setup.py --- Setup script for calculate-ldap -#Copyright 2010 Calculate Pack, http://www.calculate-linux.org +# Copyright 2016 Mir Calculate. 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 @@ -16,67 +17,28 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os -import stat -from distutils.core import setup - - -__version__ = "2.2.0.0" __app__ = "calculate-ldap" +__version__ = "3.5.0_alpha1" +import os +from glob import glob +from distutils.core import setup +from distutils.command import install_data as module_install_data +from distutils.util import change_root, convert_path -data_files = [] - -data_dirs_ldif = ['ldif'] -data_dirs_share = ['i18n'] -share_calculate_dir = "/usr/share/calculate" - -def __scanDir(scanDir, prefix, replace_dirname, dirData, flagDir=False): - """Scan directory""" - files = [] - dirs = [] - if flagDir or stat.S_ISDIR(os.stat(scanDir)[stat.ST_MODE]): - for fileOrDir in os.listdir(scanDir): - absPath = os.path.join(scanDir,fileOrDir) - statInfo = os.stat(absPath)[stat.ST_MODE] - if stat.S_ISREG(statInfo): - files.append(absPath) - elif stat.S_ISDIR(statInfo): - dirs.append(absPath) - if replace_dirname: - listDirs = list(scanDir.partition("/"))[1:] - listDirs.insert(0,replace_dirname) - scanDir = "".join(listDirs) - if prefix: - scanDir = os.path.join(prefix,scanDir) - dirData.append((scanDir, files)) - for sDir in dirs: - __scanDir(sDir, prefix, replace_dirname, dirData, True) - return dirData - -def create_data_files(data_dirs, prefix="", replace_dirname=""): - """Create data_files""" - data_files = [] - for data_dir in data_dirs: - data = [] - data_files += __scanDir(data_dir, prefix, replace_dirname, data) - return data_files - -data_files += create_data_files (data_dirs_share, share_calculate_dir) -data_files += create_data_files (data_dirs_ldif) - +packages = [ + "calculate."+str('.'.join(root.split(os.sep)[1:])) + for root, dirs, files in os.walk('pym/ldap') + if '__init__.py' in files +] setup( - name = __app__, - version = __version__, - description = "The program for configuring LDAP server", - author = "Mir Calculate Ltd.", - author_email = "support@calculate.ru", - url = "http://calculate-linux.org", - license = "http://www.apache.org/licenses/LICENSE-2.0", - package_dir = {'calculate-ldap': "."}, - packages = ['calculate-ldap.pym'], - data_files = data_files, - scripts=["./scripts/cl-ldap-setup"] -) - + name=__app__, + version=__version__, + description="LDAP service for Calculate utilities", + author="Calculate Ltd.", + author_email="support@calculate.ru", + url="http://calculate-linux.org", + license="http://www.apache.org/licenses/LICENSE-2.0", + package_dir = {'calculate.ldap': "pym/ldap"}, + packages = packages)