#-*- coding: utf-8 -*- #Copyright 2008 Calculate Pack, http://www.calculate-linux.ru # # 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 import re import sys import cl_base import cl_profile import cl_utils2 import cl_utils import ldap import types import getpass import _cl_keys import time import stat import popen2 import time Version = "calculate-client 2.0.17" tr = cl_base.lang() tr.setLanguage(sys.modules[__name__]) pcs = cl_utils.prettyColumnStr class printNoColor: def colorPrint(self,attr,fg,bg,string): sys.stdout.write(string) class ProgressBar: suffixSet = 'org.freedesktop.DBus.Properties.Set \ org.kde.kdialog.ProgressDialog' execenv = 'HOME="/root" ' max = 100 kdialog = None label = None def __init__(self,title,kdialog=None): self.title = title if kdialog == None: self.openDialog(self.title) def openDialog(self,title,max=None): if max != None: self.max = max self.title = title if os.system('which kdialog >/dev/null') == 0: self.label ="LOGINKDIALOG=%d" % os.getpid() pipe = popen2.Popen4(self.execenv + " %s " % self.label +\ '/usr/bin/kdialog --progressbar "%s" %d' % (\ " "*(len(title)+20),self.max)) if pipe.poll() != 0: time.sleep(0.5) if pipe.poll() == 0: self.kdialog = pipe.fromchild.readline().strip() while not "org.kde.kdialog" in self.kdialog: s = fout.fromchild.readline() if s == "": self.shutdownDialog() self.kdialog = s.strip() self.setTitle(self.title) else: self.shutdownDialog() def shutdownDialog(self): '''Принудительно уничтожить процесс kdialog''' self.kdialog = None if self.label != None: for s in os.popen('/bin/ps axeo pid,cmd'): if self.label in s: try: os.kill( int(s.split()[0]), 9 ) except (OSError,ValueError): pass self.label = None def setValue(self,value): '''Установить текущее значения для прогресса''' if self.kdialog and value <= self.max: os.system(self.execenv+ '/usr/bin/qdbus %s %s value %d >/dev/null' % (\ self.kdialog,self.suffixSet, value)); def setMaximum(self,max): '''Установить максимальное значения для прогресса''' self.max = max if self.kdialog: os.system(self.execenv+ '/usr/bin/qdbus %s %s maximum %d >/dev/null' % (\ self.kdialog,self.suffixSet, self.max)); def setTitle(self,title): '''Установить описания прогресса''' self.title = title if self.kdialog: os.system(self.execenv+ '/usr/bin/qdbus %s setLabelText "%s" >/dev/null' % \ (self.kdialog,self.title)) def close(self): '''Закрыть прогресс''' self.shutdownDialog() class ProgressProfile(cl_profile.profile): def __init__(self, vars): cl_profile.profile.__init__(self,vars) self.progress = ProgressBar(_("Setting up user profile") + " ...") def numberAllProfiles(self, number): self.progress.setMaximum(number) return True def numberProcessProfiles(self,number): self.progress.setValue(number) return True class RsyncProgressBar(ProgressBar): '''Объект запуска rsync для получения количества созданных файлов и при необходимости вывода progressbar ''' # получение номера передаваемого файла из инф потока rsync senderre = re.compile("\[sender\] i=(\d+) ", re.S) # получение номера получаемого файла из потока rsync receiverre = re.compile("recv_generator\(.+,([0-9]+)\)", re.S) pipe = None maximum = 1 copyStarting = False def __init__(self, title, secondtitle, rsyncstr, maximum=1): self.title = title self.secondtitle = secondtitle self.maximum = maximum self.rsyncstr = rsyncstr def getFilesNum(self): '''Получить количество файлов созданных генератором''' if self.pipe: return self.value def getExitCode(self): '''Получить код выхода rsync''' if self.pipe: return os.WEXITSTATUS(self.pipe.wait()) def runsilent(self): '''Запустить rsync без progressbar''' self.pipe = popen2.Popen4(self.rsyncstr) while True: s = self.pipe.fromchild.readline() if len(s) == 0: break q = self.receiverre.search(s) if q: self.value = int(q.groups()[0]) def run(self): '''Запустить rsync с progressbar''' self.openDialog(self.title,0) self.pipe = popen2.Popen4(self.rsyncstr) oldpercent = 0 while True: s = self.pipe.fromchild.readline() if len(s) == 0: break q = self.senderre.search(s) if q: maximum = int(q.groups()[0]) if self.maximum < maximum: self.maximum = maximum continue q = self.receiverre.search(s) if q: if not self.copyStarting: self.shutdownDialog() self.max = 100 self.openDialog(self.secondtitle) self.copyStarting = True self.value = int(q.groups()[0]) newpercent = self.value * 100 / self.maximum if oldpercent < newpercent: oldpercent = newpercent self.setValue(oldpercent) # Импортированные классы в cl_ldap # Запись ошибок imp_cl_err = cl_profile._error # Работа с XML imp_cl_xml = cl_profile.xmlShare # Обработка параметров командной строки imp_cl_help = cl_utils2.cl_help # Форматированный вывод imp_cl_smcon = cl_utils2.cl_smartcon class cl_client(imp_cl_err, imp_cl_xml, imp_cl_help, imp_cl_smcon): """Основной класс для работы клиентских приложений""" def __init__(self, cmdName): # объект для форматированного вывода imp_cl_help.__init__(self, cmdName) servName = "" if "user" in cmdName: servName = _("user") self.chapter = [\ # расположение разделов на странице # имя раздела, видимый или невидимый, кол. "\n" после # названия раздела, кол. "\n" после раздела # тип раздела ("Copyright",False,0,2,""), (_("Usage"),True,0,1,""), ("Function",False,0,2,""), (_("Examples"),True,1,1,""), (_("Common options"),True,1,0,"options"), ] # имена используемых программ и их номера для доступа к переменным # self.data self.progName = { 'cl-client':0, 'cl-createhome':1, 'cl-sync':2, } # Cвязь длинных опций помощи и выводимых разделов помощи с опциями self.relOptions = {"h":[_("Common options")],} # список разделов, которые на наличие в ней информации # используется для автоматического отображения/скрытия # опций help-имя # Пример: self.relOption = # { "help-all":[_("Common options"], _("Unix service options"), # _("Samba service options"), _("LDAP service options")}] # self.relChapterPass = (_("Common options"),) # это означается что опция будет активна, если только в разделах # кроме Common options есть хоть одна доступная опция. self.relChapterPass = (_("Common options"),) self.data = [\ { #Copyright #'progAccess':(3,), 'helpChapter':"Copyright", 'help':Version }, #Usage { 'progAccess':(0,), 'helpChapter':_("Usage"), 'help': cmdName + " [" + _("options") + "] " + _("domain") }, { 'progAccess':(1,), 'helpChapter':_("Usage"), 'help': cmdName + " " + _("user") }, { 'progAccess':(2,), 'helpChapter':_("Usage"), 'help': cmdName + " [" + _("options") + "] " + _("user") }, # Function { 'progAccess':(0,), 'helpChapter':"Function", 'help':_("Changes settings for connecting to domain \ (calculate-server)") }, { 'progAccess':(1,), 'helpChapter':"Function", 'help':_("Create home directory for the new user account") }, { 'progAccess':(2,), 'helpChapter':"Function", 'help':_("Mounting directories and synchronize the user preferences") }, # Examples { 'progAccess':(0,), 'helpChapter':_("Examples"), 'help':pcs( " cl-client 192.168.0.1", self.column_width, "# " + _("Adds settings for connecting to domain \ (ip 192.168.0.1)"), self.consolewidth-self.column_width ) }, # Options {'shortOption':"h", 'longOption':"help", 'helpChapter':_("Common options"), 'help':_("display this help and exit") }, {'shortOption':"h", 'longOption':"help", 'helpChapter':_("Common options"), 'help':_("display this help and exit") }, {'progAccess':(0,), 'shortOption':"r", 'helpChapter':_("Common options"), 'help':_("Removes the settings for connecting to a domain") }, {'progAccess':(2,), 'longOption':'progress', 'helpChapter':_("Common options"), 'help':_("Show progress bar for kde startup (works only with options \ --login)") }, {'progAccess':(1,), 'longOption':'progress', 'helpChapter':_("Common options"), 'help':_("Show progress bar for kde startup") }, {'progAccess':(0,1,2), 'longOption':"vars", 'optVal':_("TYPE_VAR"), 'helpChapter':_("Common options"), 'help':_("print variables (TYPE_VAR - all:full var)") }, {'progAccess':(0,1,2), 'longOption':"color", 'optVal':_("WHEN"), 'helpChapter':_("Common options"), 'help':_("control whether color is used to distinguish file types. \ WHEN may be 'never', 'always', or 'auto'") }, {'progAccess':(1,), 'shortOption':"f", 'longOption':"force", 'helpChapter':_("Common options"), 'help':_("always join the user profiles and preferences") }, {'progAccess':(0,), 'longOption':"install", 'helpChapter':_("Common options"), 'help':_("Adds use of scripts this package for window manager") }, {'progAccess':(0,), 'longOption':"mount", 'helpChapter':_("Common options"), 'help':_("mount [remote] resource for Samba (calculate-server)") }, {'progAccess':(2,), 'longOption':"login", 'helpChapter':_("Common options"), 'help':_("mount user resource")+ " " +\ _("and synchronize the user preferences") }, {'progAccess':(2,), 'longOption':"logout", 'helpChapter':_("Common options"), 'help':_("synchronize the user preferences") + " " +\ _("and umount user resource") }, {'progAccess':(2,), 'longOption':"nosync", 'helpChapter':_("Common options"), 'help':_("not synchronize the user preferences, is used in \ conjunction with the 'login' or 'logout'") }, #{'progAccess':(0,), #'shortOption':"p", #'longOption':"prvar", #'optVal':_("TYPES_VAR"), #'helpChapter':_("Common options"), #'help':_("print variable (filter type - comma delimited)") #}, ] self._cl_help__setParamHelp() # Удаляем ненужный аттрибут класса cl_profile.xmlShare self._createElement = False delattr(self, "_createElement") # Переменная объект Vars self.clVars = False # Переменная объект ldapFunction self.ldapObj = False # Переменная соединение с LDAP сервером self.conLdap = False # Базовый DN LDAP сервера self.baseDN = False # DN сервисов относительно базового self.ServicesDN = "ou=Services" self.relGrDN = 'ou=Groups' self.relUsDN = 'ou=Users' self.relServDN = 'ou=Unix' self.relDN = self.addDN(self.relServDN,self.ServicesDN) # DN пользователей, относительно базового DN self.relUsersDN = self.addDN(self.relUsDN, self.relDN) # DN групп, относительно базового DN self.relGroupsDN = self.addDN(self.relGrDN, self.relDN) # Объект хранения переменных self.clVars = False # Файл в ресурсе share для обработки подключения клиента self.replRunFileShare = ".reprun" # файл с дополнительной информацией о профиле # на данный момент только количество файлов для rsync # используемое для прогрессбара self.configFile = ".calculate.ini" # При включениии репликации # Временные задержки для монтирования в секундах self.sleeps = [0.5, 2, 5] # DN хранения последнего посещенного пользователя self.replHostsDN = self.addDN("ou=Worked","ou=Replication", "ou=LDAP", self.ServicesDN) self.replLogoutFile = ".logout" # Если атрибут установлен то значит (ошибка и отмонтируются # пользовательские ресурсы) self.errorAndUnmountUserRes = False # Имя пользователя self.userName = "" def exit(self, exitCode): """Метод выхода при ошибке""" self.errorExit() sys.exit(exitCode) def errorExit(self): """Отмонтирование пользовательских ресурсов при ошибке""" # TODO: добавить удаление приватных файлов if self.errorAndUnmountUserRes and self.userName: self.umountUserResNoSync(self.userName, False, False, False, True) def __del__(self): """Выполняется при удалении объекта""" self.errorExit() def isRoot(self): """Определяет является ли пользователь root""" if os.getuid() == 0 and os.getgid() == 0: return True else: self.printERROR("The user is not root") return False def createClVars(self, clVars=False): """Создает объект Vars""" if not clVars: clVars = cl_base.DataVars() clVars.flClient() clVars.flIniFile() # Устанавливаем у объекта объект Vars self.clVars = clVars return True def addDN(self, *arg): """Складывает текстовые элементы DN""" DNs = [] for dn in arg: if dn: DNs.append(dn) return ','.join(DNs) def searchLdapDN(self, name, relDN, attr, retAttr=None): """Находит DN в LDAP""" baseDN = self.clVars.Get("ld_base_dn") DN = self.addDN(relDN,baseDN) #searchScope = ldap.SCOPE_SUBTREE searchScope = ldap.SCOPE_ONELEVEL searchFilter = "%s=%s" %(attr,name) retrieveAttributes = retAttr resSearch = self.ldapObj.ldapSearch(DN, searchScope, searchFilter, retrieveAttributes) return resSearch def searchPrevHost(self, userName): """Находит сервер к которому был подключен пользователь""" resSearch = self.searchLdapDN(userName, self.replHostsDN, "uid") return resSearch def searchUnixUser(self, userName): """Находит пользователя сервиса Unix""" resSearch = self.searchLdapDN(userName, self.relUsersDN, "uid") return resSearch def searchUnixGid(self, groupId): """Находит группу сервиса Unix по ёе id""" resSearch = self.searchLdapDN(str(groupId), self.relGroupsDN, "gidNumber") return resSearch def getLdapObjBind(self, host, printError=True): """Получаем объект ldapFunction Соединяемся пользователем bind В выходном объекте есть соединение с LDAP сервером: self.conLdap """ self.createClVars(self.clVars) bindDn = self.clVars.Get("ld_bind_dn") bindPw = self.clVars.Get("ld_bind_pw") if not (bindDn or bindPw): if printError: self.printERROR(_("Not found LDAP bind DN or password") +\ " ...") return False ldapObj = cl_utils2.ldapFun(bindDn, bindPw, host) if ldapObj.getError(): if printError: self.printERROR (_("LDAP connect error") + ": " +\ ldapObj.getError().strip()) return False # Устанавливаем у объекта соединение и объект LDAP функций self.ldapObj = ldapObj self.conLdap = ldapObj.conLdap return True def searchLineInFile(self, name, fileName, numEl=0): """Ищет строку в которой есть название разделенное ':' в файле похожем на /etc/passwd""" if os.path.exists(fileName): FD = open(fileName) lines = FD.readlines() FD.close() lineFound = "" for line in lines: if name == line.split(":")[numEl]: lineFound = line break if lineFound: return lineFound else: return False def searchPasswdUser(self, userName): """Ищет пользователей в /etc/passwd""" filePasswd = "/etc/passwd" return self.searchLineInFile(userName, filePasswd) def searchGroupGid(self, groupId): """Ищет gid в /etc/group""" gid = str(groupId) fileGroup = "/etc/group" return self.searchLineInFile(gid, fileGroup, 2) def getUserLdapInfo(self, userName, printError=True): """Выдаем uid и gid пользователя""" searchUser = self.searchUnixUser(userName) if not searchUser: if printError: self.printERROR(_("User %s not found in Unix service")\ %str(userName)) return False uid = False gid = False fullName = "" mail = "" jid = "" if searchUser[0][0][1].has_key('uidNumber'): uid = searchUser[0][0][1]['uidNumber'][0] if searchUser[0][0][1].has_key('gidNumber'): gid = searchUser[0][0][1]['gidNumber'][0] searchGroup = self.searchUnixGid(gid) if searchGroup and searchGroup[0][0][1].has_key('cn'): group = searchGroup[0][0][1]['cn'][0] if searchUser[0][0][1].has_key('cn'): fullName = searchUser[0][0][1]['cn'][0] if searchUser[0][0][1].has_key('mail'): mail = searchUser[0][0][1]['mail'][0] if searchUser[0][0][1].has_key('registeredAddress'): jid = searchUser[0][0][1]['registeredAddress'][0] if searchUser[0][0][1].has_key('homeDirectory'): home = searchUser[0][0][1]['homeDirectory'][0] if uid and gid: return (uid, gid, fullName, mail, jid ,home, group) else: return () def createUserDir(self, uid, gid, userDir, mode=0700): """Создание пользовательской директории""" if not os.path.exists(userDir): os.makedirs(userDir) if mode: os.chmod(userDir,mode) os.chown(userDir,uid,gid) return True else: self.printERROR(_("Path %s exists") %userDir) return False def applyProfilesFromUser(self,progress=False): """Применяем профили для пользователя""" # Cоздаем объект профиль if progress: clProf = ProgressProfile(self.clVars) else: clProf = cl_profile.profile(self.clVars) # Объединяем профили dirsFiles = clProf.applyProfiles() if progress: clProf.progress.close() if clProf.getError(): self.printERROR(clProf.getError()) return False else: return dirsFiles def applyProfilesFromSystem(self): """Применяем профили для cистемы""" # Cоздаем объект профиль clProf = cl_profile.profile(self.clVars) # Объединяем профили dirsFiles = clProf.applyProfiles() if clProf.getError(): self.printERROR(clProf.getError()) return False else: return dirsFiles def getUserPassword(self, pwDialog=False): """Получить пароль у пользователя pwDialog - приглашение ввода пароля """ if not pwDialog: pwDialog = _("Password") userPwd = getpass.getpass(pwDialog+":") return userPwd def chownR(self, directory, uid, gid, dirsAndFiles=False): """изменяет владельца и группу для всех файлов и директорий внутри directory """ if dirsAndFiles: dirs, files = dirsAndFiles # меняем владельца домашней директории os.chown(directory, uid,gid) # Меняем владельца директорий for dirCh in dirs: if os.path.exists(dirCh): os.chown(dirCh, uid,gid) # Меняем владельца файлов for fileCh in files: if os.path.exists(fileCh): if os.path.islink(fileCh): os.lchown(fileCh, uid, gid) else: os.chown(fileCh, uid,gid) return True else: fileObj = cl_profile._file() scanObjs = fileObj.scanDirs([directory]) # меняем владельца домашней директории os.chown(directory, uid,gid) # Меняем владельца директорий for dirCh in scanObjs[0].dirs: os.chown(dirCh, uid,gid) # Меняем владельца файлов for fileCh in scanObjs[0].files: os.chown(fileCh, uid,gid) # Меняем владельца ссылок for linkCh in scanObjs[0].links: os.lchown(linkCh[1], uid, gid) return True def execProg(self, cmdStrProg, inStr=False, retFull=True): """Выполняет внешнюю программу Параметры: cmdStrProg внешняя программа inStr данные передаваемые программе на страндартный вход. Возвращаемые параметры: строка которую выведет внешняя программа """ return cl_utils.runOsCommand(cmdStrProg, inStr, retFull) #def getUidAndGidUser(self, userName): #strRes = self.execProg("id %s" %userName) #reFind = re.compile("uid=(\d+)\(.+gid=(\d+)\(") #res = reFind.search(strRes) #if res: #return res.group(1), res.group(2) #else: #self.printERROR(_("User %s not found")\ #%str(userName)) #return False def getUserPasswdInfo(self, userName): """получаем uid и gid пользователя из /etc/passwd""" resPasswd = self.searchPasswdUser(userName) if resPasswd: uid = resPasswd.split(":")[2] gid = resPasswd.split(":")[3] fullName = resPasswd.split(":")[4] mail = "" group = "" jid = "" home = os.path.join("/home",userName) resGroup = self.searchGroupGid(gid) if resGroup: group = resGroup.split(":")[0] return (uid, gid, fullName, mail, jid, home, group) else: return False def getAlwaysProfilePath(self): """Получаем пути к профилям которые применяются постоянно""" profilePath = self.clVars.Get('cl_profile_path') alwProfilePath = [] for prPath in profilePath: if os.path.split(prPath)[1] == "always": alwProfilePath.append(prPath) return alwProfilePath def setDaemonAutostart(self, daemon): """Прописывает демона в автозагрузку""" execStr = "rc-update add %s default" %daemon textLine = self.execProg(execStr) if "added to runlevel" in textLine or\ "already installed in runlevel" in textLine: return True else: self.printERROR(_("ERROR") + ": " + execStr) self.printERROR(_("Can not add at default runlevel")) return False def delDaemonAutostart(self, daemon): """Удаляет демона из автозагрузки""" execStr = "rc-update del %s default" %daemon textLine = self.execProg(execStr) if "removed from the following runlevels" in textLine or\ "not found in any of the specified runlevels" in textLine: return True #Для openrc elif "removed from runlevel" in textLine or\ "is not in the runlevel" in textLine: return True else: self.printERROR(_("ERROR") + ": " + execStr) self.printERROR(_("Not deleted from default runlevel")) return False def createHome(self, userName, applyAlways=False, progress=False): """Создание пользовательской директории с настройками для kde4""" # Имя пользователя self.userName = userName # Проверяем на root if not self.isRoot(): return False # Создаем объект переменных self.createClVars() uidGid = False # Подсоединяемся к серверу domain = self.clVars.Get("cl_remote_host") connectLdap = False if domain: if not self.getLdapObjBind(domain): return False connectLdap = True if connectLdap: # uid и gid и mail из Ldap uidGid = self.getUserLdapInfo(userName,False) if not domain: # uid и gid и mail из passwd uidGid = self.getUserPasswdInfo(userName) if not uidGid: # Отмонтируем пользовательские ресурсы в случае ошибки self.errorAndUnmountUserRes = True self.printERROR(_("Not found user uid and gid")) return False uid = int(uidGid[0]) gid = int(uidGid[1]) fullName = uidGid[2] mail = uidGid[3] jid = uidGid[4] homeDir = uidGid[5] group = uidGid[6] # Создаем пользовательскую директорию self.clVars.Set('cl_root_path',homeDir,True) homeExists = os.path.exists(homeDir) if homeExists: self.printWARNING(_("Home dir %s exists")%homeDir) if set(os.listdir(homeDir))-set(["Home","Disks","FTP",\ self.replLogoutFile]): if not applyAlways: # Получаем пути к профилям постоянного наложения alwProfilePath = self.getAlwaysProfilePath() if not alwProfilePath: return True # Записываем пути к профилям постоянного наложения #в переменную self.printSUCCESS(_("Apply always profiles") + " ...") self.clVars.Set('cl_profile_path',alwProfilePath, True) if not os.path.exists(homeDir): self.createUserDir(uid, gid, homeDir) # Записываем переменные self.clVars.Set('ur_login', userName) self.clVars.Set('ur_fullname', fullName) self.clVars.Set('ur_mail', mail) self.clVars.Set('ur_jid', jid) self.clVars.Set('ur_group', group) # Применяем профили для пользователя dirsAndFiles = self.applyProfilesFromUser(progress) if not dirsAndFiles: # Отмонтируем пользовательские ресурсы в случае ошибки self.errorAndUnmountUserRes = True self.printERROR(_("Not apply user profile")) return False self.chownR(homeDir, uid, gid, dirsAndFiles) if not homeExists: self.printSUCCESS(_("Created home dir %s")%homeDir + " ...") self.printSUCCESS(_("User account is configured") + " ...") return True def isDomain(self): """Находится ли компьютер в домене""" self.createClVars(self.clVars) foundMountRemote =self.isMount("/var/calculate/remote" ,"cifs") foundMountHome =self.isMount("/var/calculate/client-home","none",False) if not (self.clVars.Get("cl_remote_host") and foundMountRemote and\ foundMountHome): self.printERROR("The computer is not in domain") return False return (foundMountRemote,foundMountHome) def killRsync(self): """Убивает все процессы rsync и cl-sync --login""" listProcess = self.execProg("ps ax",False,False) killPid = [] flagError = False for process in listProcess: if "rsync" in process: killPid.append(process.split(" ")[0]) if "--login" in process and "cl-sync" in process: killPid.append(process.split(" ")[0]) if killPid and " ".join(killPid).strip(): textLine = self.execProg("kill -9 %s" %" ".join(killPid)) if not (textLine == None): self.printERROR(_("Can not 'kill %s'")\ %" ".join(killPid)) flagError = True if flagError: return False else: return True def isMount(self, pathMount ,typeMount, secondPath=True): """Примонтирована ли директория""" path = os.path.realpath(pathMount) foundMount = False if secondPath: reFoundMount = re.compile("on\s+%s\s+type\s+%s"%(path,typeMount)) else: reFoundMount = re.compile("%s\s+.+type\s+%s"%(path,typeMount)) resMount = self.execProg("mount",False,False) if resMount and type(resMount) == types.ListType: for string in resMount: if reFoundMount.search(string): foundMount = string break return foundMount def mountRemote(self): """Монтирование remote и домашней директории если компьютер в домене""" # Проверяем на root if not self.isRoot(): return False self.createClVars(self.clVars) domain = self.clVars.Get("cl_remote_host") if domain: foundMountRemote = self.isMount("/var/calculate/remote" ,"cifs") foundMountHome = self.isMount("/var/calculate/client-home","none", False) else: self.printERROR("The computer is not in domain") return False pathHome = "/var/calculate/client-home" if foundMountRemote: self.printWARNING(_("Samba resource [remote] is mount") + \ " ...") if foundMountHome: self.printWARNING(str(pathHome) + " " +_("is mount")+ " ...") if foundMountHome and foundMountRemote: return True if not foundMountRemote: pathRemote = "/var/calculate/remote" pwdRemote = self.clVars.Get("cl_remote_pw") if not (domain and pwdRemote): self.printERROR(_("Not found vaiable: cl_remote_pw") + " ...") return False if not os.path.exists(pathRemote): os.makedirs(pathRemote) #Экранируем символы escPwdRemote = re.sub("(\W)", r"\\\1",pwdRemote) mountStr = "PASSWD=%s mount -t cifs -o user=client \ //%s/remote %s" %(escPwdRemote,domain,pathRemote) textLine = self.execProg(mountStr) if not (textLine == None): self.printERROR(_("Can not mount Samba resource [remote]") +\ " ...") return False self.printSUCCESS(_("Mount Samba resource [remote]") +\ " ...") if not foundMountHome: if not os.path.exists(pathHome): os.makedirs(pathHome) mountStr = "mount -o bind %s /home" %pathHome textLine = self.execProg(mountStr) if not (textLine == None): self.printERROR(_("Can not mount") + " " + str(pathHome) +\ " ...") return False self.printSUCCESS(_("Mount") + " " + str(pathHome) + " " +\ " ...") return True def delDomain(self): """выводим из домена""" # Проверяем на root if not self.isRoot(): return False self.createClVars() pathRemote = "/var/calculate/remote" pathHome = "/var/calculate/client-home" foundMountRemote = self.isMount(pathRemote ,"cifs") foundMountHome = self.isMount(pathHome ,"none",False) domain = self.clVars.Get("cl_remote_host") if not domain: self.printWARNING("The computer is not in domain") return True if foundMountRemote: textLineUmount = self.umountSleepPath(pathRemote) if not textLineUmount: return False if foundMountHome: textLineUmount = self.umountSleepPath(pathHome ,"none", False) if not textLineUmount: return False self.clVars.Delete("cl_remote_host","local") self.clVars.Delete("cl_remote_pw","local") self.clVars.Set("cl_remote_host","",True) self.clVars.Set("cl_remote_pw","",True) # Наложим профили install/domain # Новые пути к профилям profPaths=['/usr/lib/calculate/calculate-client/profile/install/domain', '/var/calculate/remote/client-profile/install/domain', '/var/calculate/client-profile/install/domain'] # Изменяем переменную хранения профилей self.clVars.Set("cl_profile_path",profPaths,True) # Наложим профили dirsAndFiles = self.applyProfilesFromSystem() if not dirsAndFiles: self.printERROR(_("Not apply 'install/domain' profiles")) return False if not self.delDaemonAutostart("client"): return False self.printOK(_("Computer removed from domain %s")%domain + " ...") return True def getProfilePath(self, profPaths): """список накладываемых профилей""" profpath = [] for profPath in profPaths: if os.path.exists(profPath): profpath.append(profPath) return profpath def applyProfilesClient(self, clVars=False, printSuccess=True): """Наложение профиля клиента""" if not clVars: #Создаем объект переменных self.createClVars() clVars = self.clVars # Изменяем базовую директорию наложения профилей clVars.Set("cl_root_path","/",True) # Новые пути к профилям profPaths=['/usr/lib/calculate/calculate-client/profile/install/client', '/var/calculate/remote/client-profile/install/client', '/var/calculate/client-profile/install/client'] # Изменяем переменную хранения профилей clVars.Set("cl_profile_path",profPaths,True) # Наложим профили dirsAndFiles = self.applyProfilesFromSystem() if not dirsAndFiles: self.printERROR(_("Not apply 'install/client' profiles")) return False if printSuccess: self.printOK(_("Added use of scripts this package for window \ manager") + " ...") return True def addDomain(self, domainName): """Вводим в домен""" # Проверяем на root if not self.isRoot(): return False # Создаем объект переменных self.createClVars() netDomain = self.clVars.Get("os_net_domain") # Получам имя сервера (домена) if "." in domainName: domain = domainName else: domain = "%s.%s" %(domainName,netDomain) resPing = self.execProg("ping -c 2 -i 0.3 %s" %domain,False,False) foudHost = False foudHostSamba = False foundMountRemote = False reFoundHost = re.compile("(\d+)\% packet loss") if resPing and type(resPing) == types.ListType and len(resPing)>=2: pingStr = resPing[-2].strip() reSearch = reFoundHost.search(pingStr) if reSearch and reSearch.group(1) == "0": foudHost = True if not foudHost: self.printERROR(_("Not found domain %s")%domain) return False reFoundHostSamba = re.compile("Server=\[Samba.+\]") resSmbClient = self.execProg("smbclient -N -L %s" %domain, False,False) if resSmbClient and type(resSmbClient) == types.ListType: for string in resSmbClient: if reFoundHostSamba.search(string): foudHostSamba = True break if not foudHostSamba: self.printERROR(_("Not found Samba server in %s")%domain) return False pwd = False if self.clVars.Get("cl_remote_host") and \ self.clVars.Get("cl_remote_host") != domain: if not self.delDomain(): return False elif self.clVars.Get("cl_remote_host") and \ self.clVars.Get("cl_remote_host") == domain: pwd = self.clVars.Get("cl_remote_pw") foundMountRemote =self.isMount("/var/calculate/remote" ,"cifs") foundMountHome =self.isMount("/var/calculate/client-home","none",False) if foundMountRemote: self.printWARNING(_("Samba resource [remote] mount") + \ " ...") else: if pwd: userPwd = pwd else: userPwd=self.getUserPassword("Domain password for the desktop") pathRemote = "/var/calculate/remote" pwdRemote = userPwd if not os.path.exists(pathRemote): os.makedirs(pathRemote) # Экранируем символы escPwdRemote = re.sub("(\W)", r"\\\1",pwdRemote) mountStr = "PASSWD=%s mount -t cifs -o user=client \ //%s/remote %s" %(escPwdRemote,domain,pathRemote) textLine = self.execProg(mountStr) if not (textLine == None): self.printERROR(_("Can not mount Samba resource [remote]") + \ " ...") return False else: self.printSUCCESS(_("Mount Samba resource [remote]") + \ " ...") self.clVars.Write("cl_remote_host", domain, False, "local") self.clVars.Write("cl_remote_pw", userPwd, False, "local") pathHome = "/var/calculate/client-home" if foundMountHome: self.printWARNING(str(pathHome)+ " " +_("is mount")+ " ...") else: if not os.path.exists(pathHome): os.makedirs(pathHome) mountStr = "mount -o bind %s /home" %pathHome textLine = self.execProg(mountStr) if not (textLine == None): self.printERROR(_("Can not mount") + " " + str(pathHome) +\ " ...") return False self.printSUCCESS(_("Mount") + " " + str(pathHome) + " " +\ " ...") self.clVars.flIniFile() #считаем переменные для клиента servDn = self.clVars.Get("ld_services_dn") unixDN = self.clVars.Get("ld_unix_dn") bindDn = self.clVars.Get("ld_bind_dn") bindPw = self.clVars.Get("ld_bind_pw") # запишем их if not (servDn and unixDN and bindDn and bindPw): self.printERROR(_("Not found variables:")) self.printERROR("ld_services_dn or ld_unix_dn \ or ld_bind_dn or ld_bind_pw") return False # Наложим профили install/client if not self.applyProfilesClient(self.clVars, False): return False # Наложим профили install/domain # Новые пути к профилям profPaths=['/usr/lib/calculate/calculate-client/profile/install/domain', '/var/calculate/remote/client-profile/install/domain', '/var/calculate/client-profile/install/domain'] # Изменяем переменную хранения профилей self.clVars.Set("cl_profile_path",profPaths,True) # Наложим профили dirsAndFiles = self.applyProfilesFromSystem() if not dirsAndFiles: self.printERROR(_("Not apply 'install/domain' profiles")) return False # Рестартуем dbus if os.path.exists('/etc/init.d/dbus'): textLines = self.execProg("/etc/init.d/dbus restart", False, False) if not (textLines and type(textLines) == types.ListType and\ "ok" in textLines[-1] or textLines and "ok" in textLines): self.printWARNING(_("Error restarting /etc/init.d/dbus")+ " ...") return False if not self.setDaemonAutostart("client"): return False self.printOK(_("Computer added to domain %s")%domain + " ...") return True def removePrivateFiles(self, userHome): """Удаление приватных файлов""" privateFiles = ['.kde4/share/apps/kwallet/kdewallet.kwl'] for prFile in privateFiles: rmFile = os.path.join(userHome, prFile) if os.path.exists(rmFile): os.remove(rmFile) return True def umountSleepPath(self, path, typeMount='cifs', secondPath=True): """Отмонтирует путь при неудаче задержка потом повтор""" #Проверяем на монтирование директории if self.isMount(path, typeMount, secondPath): textLine = self.execProg("umount %s"%path) if textLine != None: i = 0 flagError = False while (i1: foundTwoSession = True self.printERROR(\ _("Second X session for user %s can not be opened.")\ %userName) break return foundTwoSession def mountSambaRes(self,userName,userPwd,uid,gid,res,path, mountUidList=['ftp','share']): """Монтирует Samba ресурсы""" #Экранируем символы escUserPwd = re.sub("(\W)", r"\\\1",userPwd) if res in mountUidList: # Монтируем директории c uid mountStr="PASSWD=%s mount -t cifs -o user=%s,uid=%s,gid=%s"\ %(escUserPwd,userName,uid,gid) +\ " //%s/%s %s" %(self.clVars.Get("cl_remote_host"), res, path) else: # Монтируем директории mountStr="PASSWD=%s mount -t cifs -o user=%s"%(escUserPwd, userName)+\ " //%s/%s %s" %(self.clVars.Get("cl_remote_host"), res, path) textLine = self.execProg(mountStr) return textLine def removeDir(self, rmDirOrScanObjs): """Рекурсивное удаление директории входной параметр директория или результат сканирования файлов (объект) """ rmDir = False if type(rmDirOrScanObjs) == types.StringType: rmDir = rmDirOrScanObjs if not os.path.exists(rmDir): self.printERROR(_("Not found remove dir %s") %rmDir) return False fileObj = cl_profile._file() # Сканируем директорию scanObjs = fileObj.scanDirs([rmDir]) else: scanObjs = rmDirOrScanObjs for socketRm in scanObjs[0].sockets: # Удаляем сокеты if os.path.exists(socketRm): os.remove(socketRm) for linkRm in scanObjs[0].links: # Удаляем ссылки os.unlink(linkRm[1]) for fileRm in scanObjs[0].files: # Удаляем файлы os.remove(fileRm) scanObjs[0].dirs.sort(lambda x, y: cmp(len(y), len(x))) for dirRm in scanObjs[0].dirs: # Удаляем директории os.rmdir(dirRm) if rmDir: os.rmdir(rmDir) return True def isCorrectProfileOnLocalServer(self,userName): """Узнать находится ли актуальный профиль пользователя на локальном сервере """ searchPrevHost = self.searchPrevHost(userName) if searchPrevHost and searchPrevHost[0][0][1].has_key('host'): prevHost = searchPrevHost[0][0][1]['host'][0] else: prevHost = None # если местоположение актуального профиля найти не удалось # или его местоположение не на локальном сервере if not prevHost or prevHost == self.clVars.Get('cl_remote_host'): return True else: return False def mountUserRes(self, userName, sync=True, progress=False): """Монтирование пользовательских ресурсов и синхронизация настроек""" # Имя пользователя self.userName = userName # Проверяем на root if not self.isRoot(): return False # Проверка на повторный вход пользователя if self.isTwoSessionsUser(userName): return False self.createClVars() # В случае компьютера вне домена if not self.clVars.Get("cl_remote_host"): self.printSUCCESS(_("To be used by local profile.")) return True # Проверим что компьютер в домене и смонтирован [remote] connectDomain = self.isDomain() if not connectDomain: # Отмонтируем пользовательские ресурсы в случае ошибки self.errorAndUnmountUserRes = True return False elif not connectDomain[0]: self.printERROR(_("Can not mount Samba resource [remote]") + \ " ...") # Отмонтируем пользовательские ресурсы в случае ошибки self.errorAndUnmountUserRes = True return False # Подсоединяемся к серверу domain = self.clVars.Get("cl_remote_host") if not self.getLdapObjBind(domain): # Отмонтируем пользовательские ресурсы в случае ошибки self.errorAndUnmountUserRes = True return False # homeDir из LDAP resLdap = self.getUserLdapInfo(userName) if not resLdap: # Отмонтируем пользовательские ресурсы в случае ошибки self.errorAndUnmountUserRes = True return False uid = int(resLdap[0]) gid = int(resLdap[1]) homeDir = resLdap[5] # При отсуствии создаем домашнюю директорию if not os.path.exists(homeDir): os.makedirs(homeDir) os.chown(homeDir,uid,gid) os.chmod(homeDir,0700) # записываем в .logout файл статус "в процессе" logOutFile = os.path.join(homeDir,self.replLogoutFile) self.createUserFile(logOutFile,"PROCESS", uid, gid) # Получаем пароль пользователя из ключей ядра userPwd = _cl_keys.getKey(userName) if not userPwd: self.printERROR(_("Not found user password")) # Отмонтируем пользовательские ресурсы в случае ошибки self.errorAndUnmountUserRes = True return False home = os.path.split(homeDir)[0] pathRemote = [] # Удаленный ресурс share pathRemote.append((os.path.join(homeDir,"Disks"), "share")) # Удаленный ресурс профилей pathRemote.append((os.path.join(home,"." + userName), "unix")) # Удаленный ресурс home pathRemote.append((os.path.join(homeDir,"Home"), "homes")) if self.clVars.Get("cl_remote_ftp"): # Удаленный ресурс ftp pathRemote.append((os.path.join(homeDir,"FTP"), "ftp")) flagError = False # Запускаемый файл на сервере в случае репликации pathReplRun = "" # Путь к профилю пользователя по умолчанию defaultPath = "" # Ност пользователя по умолчанию defaultHost = self.clVars.Get("cl_remote_host") for path, res in pathRemote: # Создаем директории для монтирования if not os.path.exists(path): try: os.mkdir(path) os.chown(path, uid, gid) os.chmod(path,0700) except OSError: self.printERROR(_("Error creating directory")) self.printERROR(_("Permission denied: '%s'")%path) flagError = True break # Проверяем на монтирование директории if self.isMount(path, 'cifs'): continue # В случае репликации не монтируем профиль пользователя if pathReplRun and res=="unix": defaultPath = path continue # Монтируем Samba ресурс textLine = self.mountSambaRes(userName,userPwd,uid,gid,res,path) if not (textLine == None): self.printERROR(_("Can not mount Samba resource [%s]")\ %res + " ...") flagError = True break # В случае репликации if res == "share": # Проверка на репликацию pathReplRun = os.path.join(path, self.replRunFileShare) if os.path.exists(pathReplRun): FD = open(pathReplRun) # Создание директорий пользователя на сервере # в случае если их нет FD.close() else: pathReplRun = "" if flagError: # Отмонтируем пользовательские ресурсы в случае ошибки self.errorAndUnmountUserRes = True return False # Синхронизируем настройки if sync: # Ошибка при монтировании unix ресурса удаленного сервера при # включенной репликации replErrorMount = False # Ошибка при cинхронизации unix ресурса удаленного сервера при # включенной репликации replErrorSync = False # В случае репликации prevHost = "" # Монтирование по умолчанию (default - cвой сервер, remote - чужой) mountServer = "" if pathReplRun: searchPrevHost = self.searchPrevHost(userName) if searchPrevHost and searchPrevHost[0][0][1].has_key('host'): prevHost = searchPrevHost[0][0][1]['host'][0] # Монтируем ресурс unix текущего сервера mountServer = "default" textLine = self.mountSleepRes(userName,userPwd,uid,gid, "unix",defaultPath) if not (textLine == None): self.printERROR(_("Can not mount Samba resource [%s]")\ %"unix" + " ...") # Отмонтируем пользовательские ресурсы в случае ошибки self.errorAndUnmountUserRes = True return False # Переносим настройки пользователя в новую директорию # .CLD self.upgradeProfileClient(userName, homeDir) # Если на текущем сервере в ресурсе unix есть файлы # то синхронируем настройки if os.listdir(defaultPath): if not self.syncUser(userName, homeDir, "login", uid, gid,\ progress=progress, host=self.clVars.Get('cl_remote_host')): # Отмонтируем пользовательские ресурсы в случае ошибки self.errorAndUnmountUserRes = True return False else: #Удаляем ненужные файлы rmFiles = list(set(os.listdir(homeDir))-\ set(["Home","Disks","FTP",\ self.replLogoutFile])) for rmFile in rmFiles: delFile = os.path.join(homeDir,rmFile) if os.path.islink(delFile): os.unlink(delFile) elif os.path.isfile(delFile): os.remove(delFile) elif os.path.isdir(delFile): if not self.removeDir(delFile): # Отмонтируем пользовательские ресурсы # в случае ошибки self.errorAndUnmountUserRes = True return False elif stat.S_ISSOCK(os.stat(delFile)[stat.ST_MODE]): os.remove(delFile) # Отмонтируем ресурс textLine = self.umountSleepPath(defaultPath) if not textLine: # Отмонтируем пользовательские ресурсы в случае ошибки self.errorAndUnmountUserRes = True return False if prevHost and prevHost != self.clVars.Get("cl_remote_host"): # Монтируем настройки пользователя удаленного сервера # если сервер найден self.clVars.Set("cl_remote_host", prevHost, True) mountServer = "remote" textLine = self.mountSleepRes(userName,userPwd,uid,gid, "unix",defaultPath) self.clVars.Set("cl_remote_host", defaultHost, True) if not (textLine == None): if self.isMount(defaultPath, 'cifs'): textLine = self.umountSleepPath(defaultPath) if not textLine: # Отмонтируем пользовательские ресурсы # в случае ошибки self.errorAndUnmountUserRes = True return False # Монтируем текущий сервер если ошибка подключения к # к найденному серверу mountServer = "default" textLine = self.mountSleepRes(userName,userPwd,uid,gid, "unix",defaultPath) if not (textLine == None): self.printERROR(_("Can not mount Samba resource \ [%s]")%"unix" + " ...") # Отмонтируем пользовательские ресурсы # в случае ошибки self.errorAndUnmountUserRes = True return False replErrorMount = True else: mountServer = "default" # Монтируем текущий сервер если сервер не найден в LDAP textLine = self.mountSleepRes(userName,userPwd,uid,gid, "unix",defaultPath) if not (textLine == None): self.printERROR(_("Can not mount Samba resource \ [%s]")%"unix" + " ...") # Отмонтируем пользовательские ресурсы в случае ошибки self.errorAndUnmountUserRes = True return False # если репликации нет, то prevHost и remote_host одинаковые else: prevHost=self.clVars.Get('cl_remote_host') # Синхронизируем настройки пользователя if not (pathReplRun and mountServer == "default"): # Переносим настройки пользователя в новую директорию # .CLD self.upgradeProfileClient(userName, homeDir) if not self.syncUser(userName, homeDir, "login", uid, gid,\ progress=progress,host=prevHost): if pathReplRun and mountServer == "remote": replErrorSync = True else: # Отмонтируем пользовательские ресурсы в случае ошибки self.errorAndUnmountUserRes = True return False if pathReplRun and mountServer == "remote": # В случае репликации перемонтируем ресурс профилей # на текущий сервер (в случае необходимости) textLine = self.umountSleepPath(defaultPath) if not textLine: # Отмонтируем пользовательские ресурсы в случае ошибки self.errorAndUnmountUserRes = True return False textLine = self.mountSambaRes(userName,userPwd,uid,gid, "unix",defaultPath) if not (textLine == None): self.printERROR(_("Can not mount Samba resource [%s]")\ %"unix" + " ...") # Отмонтируем пользовательские ресурсы в случае ошибки self.errorAndUnmountUserRes = True return False if pathReplRun: if replErrorMount or replErrorSync: self.createUserFile(logOutFile,"ERROR", uid, gid) else: self.createUserFile(logOutFile,"SUCCESS", uid, gid) else: self.createUserFile(logOutFile,"SUCCESS", uid, gid) self.printSUCCESS(_("Mount user resource in domain")) self.printOK(_("Get a user profile in the domain") + " ...") return True def mountSleepRes(self,userName,userPwd,uid,gid,res,path): """Монтирует ресурс при неудаче задержка потом повторное монитрование""" textLine = self.mountSambaRes(userName,userPwd,uid,gid,res,path) if not (textLine == None): # Проверяем на монтирование директории if self.isMount(path, 'cifs'): textLineUmount = self.umountSleepPath(path) if not textLineUmount: return False i = 0 while (i1: src = destDir + srcDestList[1] else: src = linkCreate[0] os.symlink(src,dst) if os.path.exists(dst): mode,uid,gid = fileObj.getModeFile(dst) #Изменение прав на ссылки os.lchown(dst, uid, gid) # Удаляем сокеты for rmSocket in scanObjs[0].sockets: os.remove(rmSocket) mode,uid,gid = fileObj.getModeFile(srcDir) os.chmod(destDir, 0700) os.chown(destDir, uid,gid) # Удаляем директории и файлы предыдущего профиля self.removeDir(scanObjs) return True def upgradeProfileClient(self, userName, userHome): """Переносит данные клиента в директорию .CLD Перед вызовом этого метода обязательно должен быть определен атрибут объекта self.clVars - объект переменных """ # Директория хранения старых профилей home = os.path.split(userHome)[0] pathOldProfile = os.path.join(home, "." + userName) if os.path.exists(pathOldProfile): osLinuxShort = self.clVars.Get("os_linux_shortname") # В случае пустой директории профиля if not os.listdir(pathOldProfile): pathNewProfile = os.path.join(pathOldProfile, "." + osLinuxShort) # Создаем директорию для хранения профиля os.mkdir(pathNewProfile) os.chmod(pathNewProfile, 0700) return True skipDirs = [".CLD", ".CLDX", "." + osLinuxShort] # Если есть скрытые файлы кроме skipDir # а так-же нет файлов skipDir - делаем апгрейд if filter(lambda x: x[0]==".", list(set(os.listdir(pathOldProfile))-set(skipDirs))) and\ len(filter(lambda x: not os.path.exists(os.path.join(pathOldProfile,x)), skipDirs))==len(skipDirs): pathNewProfile = os.path.join(pathOldProfile,".CLD") # Копируем профиль в новое место try: self.copyProfileDir(pathNewProfile, pathOldProfile) except: self.printERROR(_("Error updating user profile")) self.printERROR(_("path: %s")%pathNewProfile) return False pathNewProfile = os.path.join(pathOldProfile, "." + osLinuxShort) if not os.path.exists(pathNewProfile): # Создаем директорию для хранения профиля os.mkdir(pathNewProfile) os.chmod(pathNewProfile, 0700) return True def syncUser(self, userName, userHome, sync, uid, gid, progress=False,\ host="default"): """Синхронизация пользовательских настроек Перед вызовом этого метода обязательно должен быть определен атрибут объекта self.clVars - объект переменных """ home = os.path.split(userHome)[0] osLinuxShort = self.clVars.Get("os_linux_shortname") homeProfile = os.path.join(home, "." + userName, osLinuxShort) if not os.path.exists(homeProfile): homeProfile = os.path.join(home, "." + userName, "." + osLinuxShort) flagError = False execStr = "" if sync == "login": # исключаемые пути при синхронизации # /.local/share/akonadi/db_data # хранит базу acanadi # /.mozilla/firefox/calculate.default/urlclassifier3.sqlite # хранит БД для firefox # /.local/share/mime/mime.cache # отключение ошибочного кэширования изображений # /.kde4/share/apps/nepomuk/repository/main/data # база nepomuk # /.VirtualBox # содержит данные о виртуальных машинах if os.path.exists(userHome) and\ os.path.exists(homeProfile): execStr = '/usr/bin/rsync --delete-excluded --delete \ --exclude="/.googleearth" --exclude="/.kde4/share/config/phonondevicesrc" \ --exclude="*~" --exclude="/Home" --exclude="/Disks" --exclude="/FTP" \ --exclude="/.local/share/akonadi/db_data" --exclude="/.VirtualBox" \ --exclude="/.mozilla/firefox/calculate.default/urlclassifier3.sqlite" \ --exclude="/.local/share/mime/mime.cache" \ --exclude="/.kde4/share/apps/nepomuk/repository/main/data" \ --exclude="/.logout" \ --filter="P /.googleearth" --filter="P /Home" --filter="P /Disks" \ --filter="P /.local/share/akonadi/db_data" --filter="P /.VirtualBox" \ --filter="P /.mozilla/firefox/calculate.default/urlclassifier3.sqlite" \ --filter="P /.local/share/mime/mime.cache" \ --filter="P /.kde4/share/apps/nepomuk/repository/main/data" \ --filter="P /.logout" \ --filter="P /FTP" -a -x -v -v -v -v %s/ %s/' %(homeProfile,userHome) elif sync == "logout": if os.path.exists(userHome) and os.listdir(userHome) and\ os.path.exists(homeProfile): execStr = '/usr/bin/rsync --delete-excluded --delete \ --exclude="/.googleearth" --exclude="/Home" --exclude="/Disks" --exclude="/FTP"\ --exclude="*~" --exclude="/.kde4/cache-*" --exclude="/.kde4/tmp-*" \ --exclude="/.local/share/akonadi/db_data" --exclude="/.VirtualBox" \ --exclude="/.mozilla/firefox/calculate.default/urlclassifier3.sqlite" \ --exclude="/.local/share/mime/mime.cache" \ --exclude="/.kde4/share/apps/nepomuk/repository/main/data" \ --exclude="/.kde4/socket-*" --exclude="/.kde4/share/config/phonondevicesrc"\ -a -x -v -v -v -v %s/ %s/'%(userHome,homeProfile) else: self.printERROR(_("Method syncUser: option sync=%s incorrect")\ %str(sync)) return False if execStr: host = "" + host +"" rsync = RsyncProgressBar(\ _("Receiving file list from %s") % host + " ...", _("Downloading the user profile from %s") % host \ + " ...", execStr) configFileName = os.path.join(homeProfile,self.configFile) if sync == "login": # получить переменную files из секции Rsync файла # .calculate.ini try: numfiles = cl_base.iniParser( \ configFileName).getVar('rsync','files') if numfiles == False: if os.path.exists(configFileName): os.remove(configFileName) numfiles = 1 else: numfiles = int(numfiles) except: numfiles = 1 rsync.maximum = numfiles if progress: rsync.run() else: rsync.runsilent() if sync == "logout": rsync.runsilent() try: if cl_base.iniParser(configFileName).setVar('rsync', {'files':rsync.getFilesNum()}): os.chmod(configFileName, 0600) os.chown(configFileName,uid,gid) except: pass rsync.close() if rsync.getExitCode() != 0: try: if cl_base.iniParser(configFileName).setVar(\ 'rsync',{'exitcode':rsync.getExitCode()}): os.chmod(configFileName, 0600) os.chown(configFileName,uid,gid) except: pass self.printERROR(_("Can not rsync") + " " + str(sync) +\ " ...") flagError = True else: if sync == "login": if not (os.path.exists(userHome)): self.printERROR(_("Directory %s not exists")%userHome) else: self.printERROR(_("Directory %s not exists")%homeProfile) elif sync == "logout": if not (os.path.exists(userHome)): self.printERROR(_("Directory %s is empty or not exists")\ %userHome) else: self.printERROR(_("Directory %s not exists")%homeProfile) flagError = True if flagError: return False else: # Изменим если нужно права на директории fileObj = cl_profile._file() # Домашняя директория и директория хранения профиля changeDirs = [userHome, homeProfile] for changeDir in changeDirs: # Получаем права на директорию mode,uid,gid = fileObj.getModeFile(changeDir) # Если права не равны 0700 меняем их if mode != 0700: os.chmod(changeDir,0700) return True class tsOpt(cl_base.opt): """Класс для обработки параметров и вывода help Параметры: helpObj объект-справка содержащий необходимые опции notOptError выдавать ошибку при отсутствии опций командной строки """ def __init__(self, helpObj, notOptError=False): # от cl_help получаем короткие и длинные опции shortOpt,longOpt = helpObj.getAllOpt('all', helpObj.relOptions['h']) # вызвать конструктор объекта, распознающего опции cl_base.opt.__init__(self,shortOpt,longOpt) self.nameParams = ['user'] self.sysArgv = sys.argv[1:] self.helpObj = helpObj self.__iter = 0 self.opt = {} self.params = {} self.getopt() # Обработка help self.flagHelp = False # определяем есть ли среди опций опции, которые влияют на показ # опциональных разделов (метод пересечения множеств) helpopt = \ tuple(set(self.opt.keys()).intersection(helpObj.relOptions.keys())) #Если есть опции help if len(helpopt) > 0: print helpObj.getHelp(helpObj.relOptions[helpopt[0]]) self.flagHelp = True #Если нет хвостов #elif not self.params: #print helpObj.getHelp(helpObj.relOptions['h']) #self.flagHelp = True else: if self.params.has_key('user'): if len(self.nameParams) != self.__iter: self.handlerErrOpt() # В случае остсутствия опций командной строки и имени пользователя if notOptError: if not self.opt: self.printErrorNotOpt() self.flagHelp = True elif not self.opt and not self.params.has_key('user'): print helpObj.getHelp(helpObj.relOptions['h']) self.flagHelp = True def printErrorNotOpt(self): """Сообщение в случае отсутствия опций""" print _("Options are absent.") def handlerOpt(self,option,value): # Обработчик (опция значение) #print option, value shortOpt = self.helpObj.getShortOpt(option) if not shortOpt: shortOpt = option if not shortOpt in self.opt: self.opt[shortOpt] = value def handlerErrOpt(self): # Обработчик ошибок argv = " ".join(sys.argv[1:]) print _("Unrecognized option") + ' "' + argv + '"\n' + \ _("Try") + ' "' + sys.argv[0].split("/")[-1] + ' --help" ' +\ _("for more information.") def handlerParam(self,param): # Обработчик хвостов (значение) self.__iter += 1 if self.__iter<=len(self.nameParams): self.params[self.nameParams[self.__iter-1]] = param