You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
calculate-utils-2.1-client/pym/cl_client.py

2316 lines
104 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#-*- 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
import re
import sys
from cl_lang import lang
from cl_data import DataVars
from cl_template import iniParser, template, xmlShare, _file
from cl_help import opt, cl_help
from cl_utils import _error, getpathenv, runOsCommand
from cl_ldap import ldapFun
from cl_string import prettyColumnStr
from cl_lib import shareFile
import _cl_keys
from ldap import SCOPE_ONELEVEL
import types
import getpass
import time
import stat
import subprocess
Version = "calculate-client 2.2.0"
lang().setLanguage(sys.modules[__name__])
pcs = 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()
env = {}
env.update(os.environ.items() + self.execenv.items() +\
[tuple(self.label.split("="))])
pipe = subprocess.Popen('/usr/bin/kdialog --progressbar "%s" %d'\
%(" "*(len(title)+20), self.max),
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=True,
env=env, shell=True)
pipe.stdin.close()
if pipe.poll() == None:
# ожидание в 5 сек
for t in range(500):
time.sleep(0.01)
if pipe.poll() != None:
break
if pipe.poll() == 0:
self.kdialog = pipe.stdout.readline().strip()
while not "org.kde.kdialog" in self.kdialog:
s = pipe.stdout.readline()
if s == "":
pipe.stdout.close()
pipe.stderr.close()
self.shutdownDialog()
break
self.kdialog = s.strip()
self.setTitle(self.title)
pipe.stdout.close()
pipe.stderr.close()
else:
pipe.stdout.close()
pipe.stderr.close()
self.shutdownDialog()
def shutdownDialog(self):
'''Принудительно уничтожить процесс kdialog'''
self.kdialog = None
pipe = subprocess.Popen("/bin/ps axeo pid,cmd",
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=True, shell=True)
if self.label != None:
for s in pipe.stdout.readlines():
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:
env = ""
if self.execenv:
env = " ".join(map(lambda x: '%s="%s"'%(x[0],x[1]),\
self.execenv)) + " "
os.system(env + '/usr/bin/qdbus %s %s value %d >/dev/null'\
%(self.kdialog,self.suffixSet, value))
def setMaximum(self,max):
'''Установить максимальное значения для прогресса'''
self.max = max
if self.kdialog:
env = ""
if self.execenv:
env = " ".join(map(lambda x: '%s="%s"'%(x[0],x[1]),\
self.execenv)) + " "
os.system(env + '/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:
env = ""
if self.execenv:
env = " ".join(map(lambda x: '%s="%s"'%(x[0],x[1]),\
self.execenv)) + " "
os.system(env + '/usr/bin/qdbus %s setLabelText "%s" >/dev/null'\
%(self.kdialog,self.title))
def close(self):
'''Закрыть прогресс'''
self.shutdownDialog()
class ProgressTemplate(template):
def __init__(self, vars):
template.__init__(self,vars)
self.progress = ProgressBar(_("Setting up user profile") + " ...")
def numberAllTemplates(self, number):
self.progress.setMaximum(number)
return True
def numberProcessTemplates(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 = subprocess.Popen(self.rsyncstr, stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=True, shell=True)
while True:
s = self.pipe.stdout.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 = subprocess.Popen(self.rsyncstr, stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=True, shell=True)
oldpercent = 0
while True:
s = self.pipe.stdout.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)
class cl_client(_error, xmlShare, cl_help, shareFile):
"""Основной класс для работы клиентских приложений"""
# Пути к шаблонам объединяемых с системными
# относительный путь при объединении '/'
rootTemplatePaths=['/usr/lib/calculate/calculate-client/templates',
'/var/calculate/remote/templates',
'/var/calculate/templates']
def __init__(self, cmdName):
# объект для форматированного вывода
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 resources 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")
},
{'progAccess':(0,),
'shortOption':"r",
'helpChapter':_("Common options"),
'help':_("remove 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. \
WHEN may be 'never', 'always', or 'auto'")
},
{'progAccess':(1,),
'shortOption':"f",
'longOption':"force",
'helpChapter':_("Common options"),
'help':_("always join the user templates and preferences")
},
{'progAccess':(0,),
'longOption':"install",
'helpChapter':_("Common options"),
'help':_("add use of scripts this package for window manager")
},
{'progAccess':(0,),
'longOption':"uninstall",
'helpChapter':_("Common options"),
'help':_("remove use of scripts this package for window manager and, \
if necessary, removes from domain")
},
{'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()
# Удаляем ненужный аттрибут класса 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 сервисов относительно базового
ServicesDN = "ou=Services"
relGrDN = 'ou=Groups'
relUsDN = 'ou=Users'
relServDN = 'ou=Unix'
relDN = self.addDN(relServDN,ServicesDN)
# DN пользователей, относительно базового DN
self.relUsersDN = self.addDN(relUsDN, relDN)
# DN групп, относительно базового DN
self.relGroupsDN = self.addDN(relGrDN, relDN)
# DN Samba групп
self.relSambaGroupsDN = self.addDN(relGrDN,"ou=Samba",
ServicesDN)
# Объект хранения переменных
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", ServicesDN)
# Файл репликации
self.replLogoutFile = ".logout"
self.skipHomeFile = ["Home","Disks","FTP",
self.replLogoutFile]
# Если атрибут установлен то значит (ошибка и отмонтируются
# пользовательские ресурсы)
self.errorAndUnmountUserRes = False
# Имя пользователя
self.userName = ""
def exit(self, exitCode):
"""Метод выхода при ошибке"""
self.errorExit()
sys.exit(exitCode)
def errorExit(self):
"""Отмонтирование пользовательских ресурсов при ошибке"""
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 = 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 = SCOPE_ONELEVEL
searchFilter = "%s=%s" %(attr,name)
retrieveAttributes = retAttr
resSearch = self.ldapObj.ldapSearch(DN, searchScope,
searchFilter, retrieveAttributes)
return resSearch
def searchPrevHost(self, userName):
"""Находит сервер к которому был подключен пользователь"""
# Короткое имя системы
osLinuxShort = self.clVars.Get("os_linux_shortname")
# Имя для поиска в служебной ветке репликации
userLogin = "%s@%s"%(userName,osLinuxShort)
resSearch = self.searchLdapDN(userLogin, 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 в ветке Unix"""
resSearch = self.searchLdapDN(str(groupId), self.relGroupsDN,
"gidNumber")
return resSearch
def searchSambaGid(self, groupId):
"""Находит группу сервиса Unix по ёе id в ветке Samba"""
resSearch = self.searchLdapDN(str(groupId), self.relSambaGroupsDN,
"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 = 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 = ""
group = ""
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]
else:
searchGroup = self.searchSambaGid(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 applyTemplatesFromUser(self,progress=False):
"""Применяем шаблоны для пользователя"""
# Cоздаем объект шаблон
if progress:
clTempl = ProgressTemplate(self.clVars)
else:
clTempl = template(self.clVars)
# Объединяем шаблоны
dirsFiles = clTempl.applyTemplates()
if progress:
clTempl.progress.close()
if clTempl.getError():
self.printERROR(clTempl.getError())
return False
else:
return dirsFiles
def applyTemplatesFromSystem(self):
"""Применяем шаблоны для cистемы"""
# Cоздаем объект шаблон
clTempl = template(self.clVars)
# Объединяем шаблоны
dirsFiles = clTempl.applyTemplates()
if clTempl.getError():
self.printERROR(clTempl.getError())
return False
else:
return dirsFiles
def getUserPassword(self, pwDialog=False):
"""Получить пароль у пользователя
pwDialog - приглашение ввода пароля
"""
if not pwDialog:
pwDialog = _("Password")
userPwd = getpass.getpass(pwDialog+":")
return userPwd
def execProg(self, cmdStrProg, inStr=False, retFull=True, envProg={}):
"""Выполняет внешнюю программу
Параметры:
cmdStrProg внешняя программа
inStr данные передаваемые программе на страндартный вход.
Возвращаемые параметры:
строка которую выведет внешняя программа или False в случае ошибки
"""
env_path = {"PATH":getpathenv()}
env = {}
env.update(os.environ.items() + env_path.items() + envProg.items())
retCode,programOut = runOsCommand(cmdStrProg,inStr,retFull,env)
if not retCode:
return programOut
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 setDaemonAutostart(self, daemon):
"""Прописывает демона в автозагрузку"""
execStr = "rc-update add %s default" %daemon
textLine = self.execProg(execStr)
if 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 textLine:
return True
else:
self.printERROR(_("ERROR") + ": " + execStr)
self.printERROR(_("Can not delete 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]
if not group:
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
self.printERROR(_("Not found user primary group (gid=%s)"%str(gid)))
return False
# Создаем пользовательскую директорию
homeExists = os.path.exists(homeDir)
# Первый проход
self.clVars.Set('cl_pass_step','first',True)
if homeExists:
self.printWARNING(_("Home dir %s exists")%homeDir)
if set(os.listdir(homeDir))-set(self.skipHomeFile):
if not applyAlways:
# Второй и последующие проходы
self.clVars.Set('cl_pass_step','next',True)
self.printSUCCESS(_("Apply always templates") + " ...")
# Записываем переменные
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.applyTemplatesFromUser(progress)
if not dirsAndFiles:
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
self.printERROR(_("Can not apply user profile"))
return False
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)
if not listProcess:
return 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])
strPid = str(os.getpid())
# удалим свой pid из списка завершаемых процессов
if strPid in killPid:
killPid.remove(strPid)
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 relevanceTemplates(self, hostAuth):
"""Определяем актуальность наложенных шаблонов
в зависимости от версии программы
Перед запуском обязательно должен быть определен объект переменных
self.clVars
Если актуальны - True, если нет False
"""
# 'local' или имя хоста
if hostAuth != self.clVars.Get("os_remote_auth"):
return False
clTempl = template(self.clVars)
# Текущая версия программы
currentVersion = self.clVars.Get("cl_ver")
# Версия программы которая ранее работала с шаблонами
previousVersion = self.clVars.Get("os_remote_client")
cVersion, pVersion =clTempl._convertVers(currentVersion,previousVersion)
# Если версии программ не равны то шаблоны не актуальные
if cVersion != pVersion:
return False
return True
def getPathTemplates(self, listPath):
"""Получаем список директорий хранения шаблонов"""
"""список накладываемых шаблонов при установке, наложении шаблонов"""
profpath = []
for profPath in listPath:
if os.path.isdir(profPath):
profpath.append(profPath)
return profpath
def applyRelevanceTemplates(self, hostAuth):
"""Накладывает релевантные шаблоны
Перед запуском обязательно должен быть определен объект переменных
self.clVars
"""
if not self.relevanceTemplates(hostAuth):
# Обнуляем переменную удаленный хост
if hostAuth == "local":
self.clVars.Set("cl_remote_host","",True)
# Устанавливаем действие templates_domain
self.clVars.Set("cl_pass_type","domain",True)
# Наложим шаблоны templates/domain
# Новые пути к шаблонам
profPaths = self.getPathTemplates(self.rootTemplatePaths)
if not profPaths:
self.printERROR(_("Empty template paths %s")\
%", "(self.rootTemplatePaths))
return False
# Изменяем переменную хранения шаблонов
self.clVars.Set("cl_template_path",profPaths,True)
# Наложим шаблоны
dirsAndFiles = self.applyTemplatesFromSystem()
if not dirsAndFiles:
self.printERROR(_("Can not apply 'templates/domain' templates"))
return False
if hostAuth == "local":
self.printOK(_("Set templates of local mode"))
else:
self.printOK(_("Set templates of network mode"))
currentVersion = self.clVars.Get("cl_ver")
self.clVars.Write("os_remote_client", currentVersion)
self.clVars.Write("os_remote_auth", hostAuth)
return True
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.printWARNING(_("This computer is not in domain"))
# Если шаблоны не актуальны накладываем новую версию шаблонов
if not self.applyRelevanceTemplates("local"):
return False
return True
pathHome = "/var/calculate/client-home"
if foundMountRemote:
self.printWARNING(_("Samba resource [%s] is mount")%"remote" + \
" ...")
if foundMountHome:
self.printWARNING(str(pathHome) + " " +_("is mount")+
" ...")
if foundMountHome and foundMountRemote:
# Накладываем сетевые шаблоны
if domain:
self.clVars.flIniFile()
if not self.applyRelevanceTemplates(domain):
return False
return True
flagLocalTemplate = False
if not foundMountRemote:
pathRemote = "/var/calculate/remote"
pwdRemote = self.clVars.Get("cl_remote_pw")
if not (domain and pwdRemote):
self.printERROR(_("Not found variable")+\
": cl_remote_pw ...")
return False
if not os.path.exists(pathRemote):
os.makedirs(pathRemote)
#mountStr = "mount -t cifs -o user=client //%s/remote %s"\
# %(domain,pathRemote)
#textLine= self.execProg(mountStr, None, True, {"PASSWD":pwdRemote})
textLine = self.mountSleepRes("client", pwdRemote, None, None,
"remote", pathRemote)
if not (textLine == None):
self.printWARNING(_("Can not mount Samba resource [%s]")%\
"remote" + " ...")
flagLocalTemplate = True
# Если шаблоны не актуальны накладываем новую версию шаблонов
if not self.applyRelevanceTemplates("local"):
return False
if foundMountHome:
umountStr = "umount /home"
textLine = self.execProg(umountStr)
if not (textLine == None):
self.printERROR(_("Can not unmount") + " /home")
return False
return True
self.printSUCCESS(_("Mount Samba resource [%s]") % "remote" +\
" ...")
if (not foundMountHome) and (not flagLocalTemplate):
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) + " " +\
" ...")
# Накладываем сетевые шаблоны
if domain:
self.clVars.flIniFile()
if not self.applyRelevanceTemplates(domain):
return False
self.restartDBus()
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)
# Наложим шаблоны templates/domain
# Новые пути к шаблонам
# Устанавливаем действие templates_domain
self.clVars.Set("cl_pass_type","domain",True)
# Новые пути к шаблонам
profPaths = self.getPathTemplates(self.rootTemplatePaths)
if not profPaths:
self.printERROR(_("Empty template paths %s")\
%", "(self.rootTemplatePaths))
return False
# Изменяем переменную хранения шаблонов
self.clVars.Set("cl_template_path",profPaths,True)
# Наложим шаблоны
dirsAndFiles = self.applyTemplatesFromSystem()
if not dirsAndFiles:
self.printERROR(_("Can not apply 'templates/domain' templates"))
return False
if not self.delDaemonAutostart("client"):
return False
self.printOK(_("Computer removed from domain %s")%domain + " ...")
return True
def uninstallClient(self):
"""Наложение шаблона клиента по умолчанию и
при необходимости отключение от домена"""
if not self.isRoot():
return False
self.createClVars()
clVars = self.clVars
messageOk = _("Removed use of scripts this package for window \
manager") + " ..."
# Устанавливаем переменную шаблона
clVars.Set("cl_pass_run","off",True)
# Устанавливаем действие templates_client
clVars.Set("cl_pass_type","install",True)
# Новые пути к шаблонам
profPaths = self.getPathTemplates(self.rootTemplatePaths)
if not profPaths:
self.printERROR(_("Empty template paths %s")\
%", "(self.rootTemplatePaths))
return False
# Изменяем переменную хранения шаблонов
clVars.Set("cl_template_path",profPaths,True)
# Наложим шаблоны
dirsAndFiles = self.applyTemplatesFromSystem()
if not dirsAndFiles:
self.printERROR(_("Can not apply 'templates/client' templates"))
return False
remoteHost = clVars.Get("cl_remote_host")
if remoteHost:
if not self.delDomain():
return False
self.printOK(messageOk)
return True
def installClient(self, clVars=False, printSuccess=True):
"""Наложение шаблона клиента и при необходимости подключение к домену"""
if not self.isRoot():
return False
if not clVars:
#Создаем объект переменных
self.createClVars()
clVars = self.clVars
messageOk = _("Added use of scripts this package for window \
manager") + " ..."
# Устанавливаем переменную шаблона
clVars.Set("cl_pass_run","on",True)
# Устанавливаем действие templates_client
clVars.Set("cl_pass_type","install",True)
# Новые пути к шаблонам
profPaths = self.getPathTemplates(self.rootTemplatePaths)
if not profPaths:
self.printERROR(_("Empty template paths %s")\
%", "(self.rootTemplatePaths))
return False
# Изменяем переменную хранения шаблонов
clVars.Set("cl_template_path",profPaths,True)
# Наложим шаблоны
dirsAndFiles = self.applyTemplatesFromSystem()
if not dirsAndFiles:
self.printERROR(_("Can not apply 'templates/client' templates"))
return False
if printSuccess:
self.printOK(messageOk)
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)
execStr = "ping -c 2 -i 0.3 %s" %domain
resPing = self.execProg(execStr, False, False)
if not resPing:
self.printERROR(_('Can not execute "%s"')%execStr)
return 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 [%s] is mount")%\
"remote" + " ...")
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)
mountStr = "mount -t cifs -o user=client //%s/remote %s"\
%(domain,pathRemote)
textLine = self.execProg(mountStr, None, True, {"PASSWD":pwdRemote})
if not (textLine == None):
self.printERROR(_("Can not mount Samba resource [%s]")%\
"remote" + " ...")
return False
else:
self.printSUCCESS(_("Mount Samba resource [%s]")%"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
# Наложим шаблоны templates/client
if not self.installClient(self.clVars, False):
return False
# Наложим шаблоны templates/domain
# Устанавливаем действие templates_client
self.clVars.Set("cl_pass_type","domain",True)
# Новые пути к шаблонам
profPaths = self.getPathTemplates(self.rootTemplatePaths)
if not profPaths:
self.printERROR(_("Empty template paths %s")\
%", "(self.rootTemplatePaths))
return False
# Изменяем переменную хранения шаблонов
self.clVars.Set("cl_template_path",profPaths,True)
# Наложим шаблоны
dirsAndFiles = self.applyTemplatesFromSystem()
if not dirsAndFiles:
self.printERROR(_("Can not apply 'templates/domain' templates"))
return False
# Рестартуем dbus
self.restartDBus()
if not self.setDaemonAutostart("client"):
return False
self.printOK(_("Computer added to domain %s")%domain + " ...")
return True
def restartDBus(self):
"""Перезапускаем службу D-Bus"""
dbusDaemon = '/etc/init.d/dbus'
if os.path.exists(dbusDaemon):
if os.system(dbusDaemon + ' restart &>/dev/null') != 0:
self.printWARNING(_("Error restarting")+" "+dbusDaemon+" ...")
return False
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 (i<len(self.sleeps) and textLine != None):
# Задержка перед следующей попыткой
time.sleep(self.sleeps[i])
# Отмонтируем Samba ресурс
if self.isMount(path, typeMount, secondPath):
textLine = self.execProg("umount %s"%path)
else:
textLine = None
break
i += 1
if textLine != None:
self.printERROR(_("Can not unmount path %s")%path + " ...")
return False
return True
def umountUserRes(self, userName,progress=False):
"""Отмонтирование пользовательских ресурсов и синхронизация настроек"""
# Имя пользователя
self.userName = userName
# Проверяем на root
if not self.isRoot():
return False
self.createClVars()
# В случае компьютера вне домена
if not self.clVars.Get("cl_remote_host"):
self.printSUCCESS(_("To be used local profile."))
return True
connectDomain = self.isDomain()
if not connectDomain:
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
return False
elif not connectDomain[0]:
self.printERROR(_("Can not mount Samba resource [%s]")%"remote"+\
" ...")
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
return False
# Если пользователь в X сессии тогда не будем отмонтировать ресурсы
if self.isSessionUser(userName):
self.printERROR(_("User %s is in X session")%userName)
self.printERROR(_("Can not unmount user %s resource")%userName)
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]
home = os.path.split(homeDir)[0]
pathRemote = []
# Удаленный ресурс профиля пользователя
pathRemote.append((os.path.join(home,"." + userName), "unix"))
# Удаленный ресурс home
pathRemote.append((os.path.join(homeDir,"Home"), "homes"))
# Удаленный ресурс ftp
if self.clVars.Get("cl_remote_ftp"):
pathRemote.append((os.path.join(homeDir,"FTP"), "ftp"))
# Удаленный ресурс share
pathRemote.append((os.path.join(homeDir,"Disks"), "share"))
if os.path.exists(homeDir):
self.moveHomeDir(homeDir)
else:
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
self.printERROR(_("Directory %s not found") % homeDir)
return False
# Синхронизируем настройки
pathUnix = ""
for path, res in pathRemote:
if res == 'unix':
pathUnix = path
break
if pathUnix and self.isMount(pathUnix ,"cifs") and \
not(domain in self.isMount(pathUnix ,"cifs")):
# Убиваем rsync
if not self.killRsync():
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
return False
textLine = self.umountSleepPath(pathUnix)
if not textLine:
self.printERROR(_("Can not unmount path %s")%pathUnix+ " ...")
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
return False
# Монтируем ресурс Unix
# Получаем пароль пользователя из ключей ядра
userPwd = _cl_keys.getKey(userName)
if not userPwd:
self.printERROR(_("Not found user password"))
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
return False
textLine = self.mountSleepRes(userName,userPwd,uid,gid,
"unix",pathUnix)
if not (textLine == None):
self.printERROR(_("Can not mount Samba resource [%s]")\
%"unix" + " ...")
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
return False
# проверяем произведен ли корректный вход в систему -
# в этом случае закачиваем профиль пользователя
# с локальной машины на сервер
logOutFile = os.path.join(homeDir,self.replLogoutFile)
# необходима ли синхронизация с локальным сервером
needSync = False
try:
# если актуальный профиль пользователя
# хранится не на локальном сервере
# то на локальный сервер закачиваем профиль пользователя
# так как даже если он будет поврежден на другом сервере
# остаётся правильная копия
if not self.isCorrectTemplateOnLocalServer(userName):
needSync = True
else:
FD = open(logOutFile)
exitStr = FD.read().strip()
FD.close()
# проверяем logOutFile: не содержит ли он "PROCESS"
if exitStr != "PROCESS":
needSync = True
except:
# Удаляем приватные файлы
self.removePrivateFiles(homeDir)
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
return False
if needSync and not self.syncUser(userName,homeDir,"logout",uid,gid):
# Удаляем приватные файлы
self.removePrivateFiles(homeDir)
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
return False
# Удаляем приватные файлы
self.removePrivateFiles(homeDir)
flagError = False
for path, res in pathRemote:
if self.isMount(path ,"cifs"):
# В случае репликации
if res == "share":
# Проверка на репликацию
pathReplRun = os.path.join(path, self.replRunFileShare)
if os.path.exists(pathReplRun):
FD = open(pathReplRun)
# Записывает доменное имя сервера если
# с сервером корректно соединились
FD.close()
textLine = self.umountSleepPath(path)
if not textLine:
flagError = True
break
if os.path.exists(path) and not os.listdir(path):
try:
os.rmdir(path)
except:
self.printERROR(_("Can not remove dir %s")% path)
flagError = True
break
if flagError:
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
self.printERROR(_("Can not save a user profile in the domain"))
return False
self.printSUCCESS(_("Saved a user profile in the domain"))
self.printOK(_("Umounted user resource in domain") + " ...")
return True
def umountUserResNoSync(self, userName, printError=True, printSuccess=True,
isXsession=True, killRsync=False, progress=False):
"""Отмонтирование пользовательских ресурсов
без синхронизации настроек"""
# Имя пользователя
self.userName = userName
# Проверяем на root
if not self.isRoot():
return False
if killRsync:
self.killRsync()
self.createClVars(self.clVars)
# В случае компьютера вне домена
if not self.clVars.Get("cl_remote_host"):
if printSuccess:
self.printSUCCESS(_("To be used local profile."))
return True
# Подсоединяемся к серверу
domain = self.clVars.Get("cl_remote_host")
home = ""
homeDir = ""
if not self.getLdapObjBind(domain, printError):
home = "/home"
homeDir = os.path.join(home,userName)
# Если пользователь в X сессии тогда не будем отмонтировать ресурсы
if isXsession and self.isSessionUser(userName):
self.printERROR(_("User %s is in X session")%userName)
self.printERROR(_("Can not unmount user %s resource")%userName)
return False
if not homeDir:
# homeDir из LDAP
resLdap = self.getUserLdapInfo(userName, printError)
if not resLdap:
home = "/home"
homeDir = os.path.join(home,userName)
else:
homeDir = resLdap[5]
home = os.path.split(homeDir)[0]
pathRemote = []
# Удаленный ресурс - профиль пользователя
pathRemote.append((os.path.join(home,"." + userName), "unix"))
# Удаленный ресурс home
pathRemote.append((os.path.join(homeDir,"Home"), "homes"))
# Удаленный ресурс ftp
if self.clVars.Get("cl_remote_ftp"):
pathRemote.append((os.path.join(homeDir,"FTP"), "ftp"))
# Удаленный ресурс share
pathRemote.append((os.path.join(homeDir,"Disks"), "share"))
flagError = False
if self.isMount(pathRemote[1][0] ,"cifs"):
self.moveHomeDir(homeDir)
for path, res in pathRemote:
if self.isMount(path ,"cifs"):
textLine = self.umountSleepPath(path)
if not textLine:
flagError = True
break
if os.path.exists(path) and not os.listdir(path):
try:
os.rmdir(path)
except:
if printError:
self.printERROR(_("Can not remove dir %s")% path)
flagError = True
break
if flagError:
if printError:
self.printERROR(_("Can not unmount user %s resource")%userName)
return False
if printSuccess:
self.printOK(_("Umounted user %s resources") %userName + " ...")
return True
def isSessionUser(self, userName):
"""Проверка на вход пользователя в X"""
xSession = False
reFoundUser = re.compile("%s\s+:\d+\s+"%(userName))
resWho = self.execProg("who",False,False)
if resWho and type(resWho) == types.ListType:
for string in resWho:
if reFoundUser.search(string):
xSession = True
break
return xSession
def isTwoSessionsUser(self, userName):
"""Проверка на повторный вход пользователя"""
xSession = 0
foundTwoSession = False
reFoundUser = re.compile("%s\s+:\d+\s+"%(userName))
resWho = self.execProg("who",False,False)
if resWho and type(resWho) == types.ListType:
for string in resWho:
if reFoundUser.search(string):
xSession +=1
if xSession>1:
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','home','share']):
"""Монтирует Samba ресурсы"""
if not uid is None and not gid is None and res in mountUidList:
# Монтируем директории c uid
mountStr="mount -t cifs -o user=%s,uid=%s,gid=%s,noperm"\
%(userName,uid,gid) +\
" //%s/%s %s" %(self.clVars.Get("cl_remote_host"),
res, path)
else:
# Монтируем директории
mountStr="mount -t cifs -o user=%s"%(userName)+\
" //%s/%s %s" %(self.clVars.Get("cl_remote_host"),
res, path)
textLine = self.execProg(mountStr, None, True, {"PASSWD":userPwd})
return textLine
def isCorrectTemplateOnLocalServer(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 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 [%s]")%"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
flagFirstSync = False
if pathReplRun or sync:
# Ошибка при монтировании unix ресурса удаленного сервера при
# включенной репликации
replErrorMount = False
# Ошибка при cинхронизации unix ресурса удаленного сервера при
# включенной репликации
replErrorSync = False
# Синхронизируем настройки
if sync:
# Короткое имя системы
osLinuxShort = self.clVars.Get("os_linux_shortname")
# В случае репликации
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.upgradeTemplateClient(userName, homeDir)
# Если на текущем сервере в ресурсе unix есть файлы
# то синхронируем настройки
# Получаем директорию хранения профиля пользователя на сервере
homeTemplate = os.path.join(home, "." + userName, osLinuxShort)
if not os.path.exists(homeTemplate):
homeTemplate = os.path.join(home, "." + userName,
"." + osLinuxShort)
if os.listdir(homeTemplate):
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(self.skipHomeFile))
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.upgradeTemplateClient(userName, homeDir)
# Получаем директорию хранения профиля пользователя на сервере
homeTemplate = os.path.join(home, "." + userName, osLinuxShort)
if not os.path.exists(homeTemplate):
homeTemplate = os.path.join(home, "." + userName,
"." + osLinuxShort)
if os.listdir(homeTemplate):
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
else:
#Удаляем ненужные файлы
rmFiles = list(set(os.listdir(homeDir))-\
set(self.skipHomeFile))
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)
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(_("Mounted user resource of the domain"))
self.printOK(_("Get a user profile from 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 (i<len(self.sleeps) and not (textLine == None)):
# Задержка перед следующей попыткой
time.sleep(self.sleeps[i])
# Монтируем Samba ресурс
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 += 1
return textLine
def copyFilesToMovie(self, userHome):
"""Переносим файлы пользователя в Home/Moved"""
# Находим директории и файлы в домащней директории
pathProg = os.getcwd()
os.chdir(userHome)
dirs = []
files = []
movedLink = os.path.join('Moved')
movedPath = os.path.join('Home',"Moved")
filesAndDir = filter(lambda x: not ('.' in x[0] or x in\
['Disks','Home','Moved','FTP','Desktop'] or os.path.islink(x)),
os.listdir('.'))
filesDir = []
for fd in filesAndDir:
if os.path.islink(fd):
os.unlink(fd)
else:
filesDir.append(fd)
# Нахождение файлов отличных от иконок и ссылок в Desktop
pathDesktop = './Desktop'
filesDirDesk = []
if os.path.exists(pathDesktop):
filesDirDesk = filter(lambda x: not os.path.islink(x) and\
not x.rpartition('.')[2]=='desktop',\
map(lambda x: os.path.join(pathDesktop,x),\
os.listdir(pathDesktop)))
movedPathDesk = os.path.join(movedPath, pathDesktop)
filesDir += filesDirDesk
if not filesDir or not os.path.exists("Home"):
# Удаляем пустую папку Moved
if os.path.exists(movedPath) and not os.listdir(movedPath):
os.rmdir(movedPath)
# Удалям ссылку на Moved в домашней директории
if os.path.islink(movedLink) and not os.path.exists(movedPath):
os.unlink(movedLink)
return True
if not os.path.exists(movedPath):
os.mkdir(movedPath)
directFile = os.path.join(movedPath,".directory")
if not os.path.exists(directFile):
txt = "[Desktop Entry]\nIcon=folder-development"
fd = os.open(directFile, os.O_CREAT)
os.close(fd)
FD = open (directFile, "r+")
FD.write(txt)
FD.close()
if not os.path.exists(movedLink):
os.symlink(movedPath, movedLink)
for fd in filesDir:
execStr = "cp -r '%s' '%s'" %(fd, movedPath)
textLine = self.execProg(execStr)
if not (textLine == None):
self.printERROR(_("Can not exec") + " " + str(execStr) +\
" ...")
return False
execStr = "rm -rf '%s'" %fd
textLine = self.execProg(execStr)
if not (textLine == None):
self.printERROR(_("Can not exec") + " " + str(execStr) +\
" ...")
return False
os.chdir(pathProg)
return True
def moveHomeDir(self, userHome):
"""Переносим файлы пользователя в директорию Home/Moved если в домене"""
if self.isDomain():
return self.copyFilesToMovie(userHome)
return True
def createUserFile(self, fileName, fileTxt, uid, gid, mode=0644):
"""Создает пользовательский файл с содержимым
Если директория файла не существует то ошибка
"""
userDir = os.path.split(fileName)[0]
if not os.path.exists(userDir):
self.printERROR(_("Path %s not exists") %userDir)
return False
fd = os.open(fileName, os.O_CREAT|os.O_TRUNC)
os.close(fd)
os.chmod(fileName, mode)
os.chown(fileName,uid,gid)
FD = open(fileName, "r+")
FD.write(fileTxt)
FD.close()
return True
def copyTemplateDir(self, destDir, srcDir):
"""Перенос файлов и директорий в директории srcDir в директорию destDir
При копировании сохраняются владелец, группа, права
"""
if not os.path.exists(srcDir):
self.printERROR(_("Not found directory %s")%srcDir)
return False
files = os.listdir(srcDir)
if os.path.exists(destDir):
if not os.listdir(destDir):
os.rmdir(destDir)
else:
# Файловый объект
fileObj = _file()
os.makedirs(destDir)
mode,uid,gid = fileObj.getModeFile(srcDir)
os.chmod(destDir, 0700)
os.chown(destDir, uid,gid)
flagError=False
for nameFile in files:
srcFile = os.path.join(srcDir, nameFile)
destFile = os.path.join(destDir, nameFile)
# Создаем ссылки
if os.path.islink(srcFile):
dst = srcFile
src = os.readlink(srcFile)
os.symlink(src,destFile)
if os.path.exists(destFile):
mode,uid,gid = fileObj.getModeFile(destFile)
#Изменение прав на ссылки
os.lchown(destFile, uid, gid)
os.unlink(srcFile)
continue
# Удаляем сокеты
elif stat.S_ISSOCK(os.stat(srcFile)[stat.ST_MODE]):
os.remove(srcFile)
continue
# Переносим оставшиеся файлы и директории
if os.system("mv %s %s &>/dev/null"%(srcFile,destFile)) != 0:
self.printERROR(_("Can not move %s")%srcFile + " " +\
_("to %s")%destFile)
flagError=True
break
if flagError:
return False
return True
def upgradeTemplateClient(self, userName, userHome):
"""Переносит данные клиента в директорию .CLD
Перед вызовом этого метода обязательно должен быть определен атрибут
объекта self.clVars - объект переменных
"""
# Директория хранения старого профиля пользователя
home = os.path.split(userHome)[0]
pathOldTemplate = os.path.join(home, "." + userName)
if os.path.exists(pathOldTemplate):
osLinuxShort = self.clVars.Get("os_linux_shortname")
# В случае пустой директории профиля пользователя
if not os.listdir(pathOldTemplate):
pathNewTemplate = os.path.join(pathOldTemplate,
"." + osLinuxShort)
# Создаем директорию для хранения профиля пользователя
os.mkdir(pathNewTemplate)
os.chmod(pathNewTemplate, 0700)
return True
skipDirs = [".CLD", ".CLDX", "." + osLinuxShort]
# Если есть скрытые файлы кроме skipDir
# а так-же нет файлов skipDir - делаем апгрейд
if filter(lambda x: x[0]==".",
list(set(os.listdir(pathOldTemplate))-set(skipDirs))) and\
len(filter(lambda x: not os.path.exists(os.path.join(pathOldTemplate,x)),
skipDirs))==len(skipDirs):
pathNewTemplate = os.path.join(pathOldTemplate,".CLD")
# Копируем профиль пользователя в новое место
try:
self.copyTemplateDir(pathNewTemplate, pathOldTemplate)
except:
self.printERROR(_("Error updating user profile"))
self.printERROR(_("path: %s")%pathNewTemplate)
return False
pathNewTemplate = os.path.join(pathOldTemplate,
"." + osLinuxShort)
if not os.path.exists(pathNewTemplate):
# Создаем директорию для хранения профиля пользователя
os.mkdir(pathNewTemplate)
os.chmod(pathNewTemplate, 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")
homeTemplate = os.path.join(home, "." + userName, osLinuxShort)
if not os.path.exists(homeTemplate):
homeTemplate = 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(homeTemplate):
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" \
--exclude="/.Xauthority" \
--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 /.Xauthority" \
--filter="P /FTP" -a -x -v -v -v -v %s/ %s/' %(homeTemplate,userHome)
elif sync == "logout":
if os.path.exists(userHome) and os.listdir(userHome) and\
os.path.exists(homeTemplate):
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="/.Xauthority" \
--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,homeTemplate)
else:
self.printERROR(_("Method syncUser: option sync=%s incorrect")\
%str(sync))
return False
if execStr:
host = "<i>" + host +"</i>"
rsync = RsyncProgressBar(\
_("Receiving file list from %s") % host + " ...",
_("Downloading the user profile from %s") % host \
+ " ...", execStr)
configFileName = os.path.join(homeTemplate,self.configFile)
if sync == "login":
# получить переменную files из секции Rsync файла
# .calculate.ini
try:
numfiles = 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 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 iniParser(configFileName).setVar(\
'rsync',{'exitcode':rsync.getExitCode()}):
os.chmod(configFileName, 0600)
os.chown(configFileName,uid,gid)
except:
pass
self.printERROR(_("Can not execute 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")%homeTemplate)
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")%homeTemplate)
flagError = True
if flagError:
return False
else:
# Изменим если нужно права на директории
fileObj = _file()
# Домашняя директория и директория хранения профиля пользователя
changeDirs = [userHome, homeTemplate]
for changeDir in changeDirs:
# Получаем права на директорию
mode,uid,gid = fileObj.getModeFile(changeDir)
# Если права не равны 0700 меняем их
if mode != 0700:
os.chmod(changeDir,0700)
return True
class tsOpt(opt):
"""Класс для обработки параметров и вывода help
Параметры:
helpObj объект-справка содержащий необходимые опции
notOptError выдавать ошибку при отсутствии опций командной строки
"""
def __init__(self, helpObj, notOptError=False):
# от cl_help получаем короткие и длинные опции
shortOpt,longOpt = helpObj.getAllOpt('all', helpObj.relOptions['h'])
# вызвать конструктор объекта, распознающего опции
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