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

3058 lines
136 KiB

#-*- 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
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 subprocess
from encrypt import encrypt
from signal import SIGTERM
Version = "calculate-client 2.1.18"
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 NoneProgressBar:
"""Abstract class of progress bar. It do nothing."""
def __init__(self,title,dialog=None):
pass
def openDialog(self,title,max=None):
"""Create dialog with progress bar, prepare date"""
pass
def shutdownDialog(self):
"""Destroy dialog"""
pass
def setValue(self,value):
"""Set value of progress bar relative of maximum"""
pass
def setMaximum(self,max):
"""Set maximum value of progress bar"""
pass
def setTitle(self,title):
"""Set title of progress dialog"""
pass
class GProgressBar(NoneProgressBar):
"""GProgressBar uses Xdialog program for display progressbar."""
def __init__(self,title,xdialog=None):
self.title = title
self.bgPID = 0
self.value = 0
self.pipein = None
if xdialog == None:
self.openDialog(self.title)
def openDialog(self,title,max=None):
if max != None:
self.setMaximum(max)
title = re.sub("<[^>]+>", "", title)
self.title = title
if os.system('which Xdialog &>/dev/null') == 0:
14 years ago
pipe = subprocess.Popen('/usr/bin/Xdialog --progress "%s" 6 80'\
%(self.title),
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=True,
env=os.environ, shell=True)
self.pipein = pipe.stdin
self._set(1)
pipe.stdout.close()
pipe.stderr.close()
def shutdownDialog(self):
'''Принудительно уничтожить процесс dialog'''
if self.pipein:
self._set(100)
time.sleep(0.1)
self.pipein.close()
self.pipein = None
def _set(self,value):
if self.pipein:
self.pipein.write("%02d\n"%value)
self.pipein.flush()
def setValue(self,value):
'''Установить текущее значения для прогресса'''
if self.pipein and value <= self.max:
progress_value = int(value / self.kmax)
if progress_value > int(self.value / self.kmax) and progress_value < 100:
self._set(progress_value)
self.value = value
def setMaximum(self,max):
'''Установить максимальное значения для прогресса'''
self.max = max
self.kmax = (max / 100.0) or 1.0
def setTitle(self,title):
'''Установить описания прогресса'''
pass
class KProgressBar(NoneProgressBar):
"""KProgressBar uses kdialog program and dbus for display 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
self.value = 0
if kdialog is 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()
# wait for terminate kdialog, which say dbus dialog id
if pipe.poll() is None:
# ожидание в 5 сек
for t in range(500):
time.sleep(0.01)
if pipe.poll() != None:
break
# waiting is ok
if pipe.poll() == 0:
self.kdialog = pipe.stdout.readline().strip()
while not "org.kde.kdialog" in self.kdialog:
s = pipe.stdout.readline()
# if bad result of kdialog then shutdown dialog
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()
# waiting is failed
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)) + " "
oldperc = int(self.value / self.kmax)
newperc = int(value / self.kmax)
if newperc > oldperc:
os.system(env + '/usr/bin/qdbus %s %s value %d >/dev/null'\
%(self.kdialog,self.suffixSet, newperc))
self.value = value
def setMaximum(self,max):
'''Установить максимальное значения для прогресса'''
if self.kdialog and self.max == 0 and max != 0:
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, 100))
self.max = max
self.kmax = (max / 100.0) or 1.0
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 ProgressBar(*args,**kwarg):
"""Return instance of object for progress bar"""
if os.system('which kdialog &>/dev/null') == 0:
return KProgressBar(*args,**kwarg)
elif os.system('which Xdialog &>/dev/null') == 0:
return GProgressBar(*args,**kwarg)
return NoneProgressBar(*args,**kwarg)
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
def close(self):
14 years ago
self.progress.shutdownDialog()
class RsyncProgressBar:
'''Объект запуска rsync для получения количества созданных файлов и
при необходимости вывода progressbar
'''
# получение номера получаемого файла из потока 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
self.progress = ProgressBar(title,1)
self.progress.setMaximum(self.maximum)
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.progress.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.receiverre.search(s)
if q:
if not self.copyStarting:
self.progress.shutdownDialog()
self.progress.openDialog(self.secondtitle)
self.progress.setMaximum(self.maximum)
self.copyStarting = True
value = int(q.groups()[0])
self.progress.setValue(value)
def close(self):
self.progress.shutdownDialog()
# Импортированные классы в 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, encrypt):
"""Основной класс для работы клиентских приложений"""
# Пути к профилям объединяемых с системными
# относительный путь при объединении '/'
rootProfilePaths=['/usr/lib/calculate/calculate-client/profiles',
'/var/calculate/remote/profiles',
'/var/calculate/profiles']
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,
'cl-passwd':3
}
# 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")
},
{
'progAccess':(3,),
'helpChapter':_("Usage"),
'help': cmdName
},
# 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")
},
{
'progAccess':(3,),
'helpChapter':"Function",
'help':_("Change user password")
},
# 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 )
},
{
'progAccess':(3,),
'helpChapter':_("Examples"),
'help':pcs(" cl-passwd", self.column_width,
"# "+_("change password of user for Samba and Unix services")+".",
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,3),
'longOption':"vars",
'optVal':_("TYPE_VAR"),
'helpChapter':_("Common options"),
'help':_("print variables (TYPE_VAR - all:full var)")
},
{'progAccess':(0,1,2,3),
'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 profiles 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'")
}
]
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 сервисов относительно базового
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
# файл с дополнительной информацией о профиле
# на данный момент только количество файлов для rsync
# используемое для прогрессбара
self.configFileDesktop = "desktop.env"
self.configFileServer = "server.env"
# Файл - список файлов профиля пользователя
self.listProfFile = ".calculate/files.txt"
# Путь относительно домашней директории в котором находятся
# конфигурационные файлы
self.pathConfig = ".calculate"
# При включениии репликации
# Временные задержки для монтирования в секундах
self.sleeps = [0.5, 2, 5]
# Название ветки хранения последнего посещенного пользователя
self.replBranchName = "Worked"
# Аттрибут ветки хранения последнего посещенного пользователя
self.replAttr = "ou"
# DN системной ветки
self.sysDN = self.addDN("ou=Replication","ou=LDAP", ServicesDN)
replBranch = self.replAttr + "=" + self.replBranchName
# DN хранения последнего посещенного пользователя
self.replHostsDN = self.addDN(replBranch,self.sysDN)
self.logOutFile = ".logout"
self.skipHomeFile = ["Home","Disks","FTP",
self.logOutFile,
os.path.join(self.pathConfig,self.configFileDesktop)]
# Если атрибут установлен то значит (ошибка и отмонтируются
# пользовательские ресурсы)
self.errorAndUnmountUserRes = False
# Имя пользователя
self.userName = ""
def getUserPwd(self, options, optDialog, optStdIn, pwDialog=False):
"""Получить пароль у пользователя
options - полученные опции командной строки
optDialog - опция командной строки для вывода диалога для получения
пароля
optStdIn - опция командной строки для получения пароля из
стандартного ввода (stdin)
pwDialog - структура для вывода приглашения в режиме диалога
"""
userPwd = ""
if optStdIn and options.has_key(optStdIn):
pwdA = sys.stdin.readline().rstrip()
pwdB = sys.stdin.readline().rstrip()
elif optDialog and options.has_key(optDialog):
if not pwDialog:
pwDialog = [_("New password"),
_("Retype new password")]
pwdA = getpass.getpass(pwDialog[0]+":")
pwdB = getpass.getpass(pwDialog[1]+":")
if (optStdIn and options.has_key(optStdIn)) or\
(optDialog and options.has_key(optDialog)):
if not pwdA or not (pwdA == pwdB):
self.printERROR (_("ERROR") + ": " +\
14 years ago
_("passwords do not match"))
return False
userPwd = pwdA
return userPwd
def exit(self, exitCode):
"""Метод выхода при ошибке"""
self.errorExit()
sys.exit(exitCode)
def errorExit(self):
"""Отмонтирование пользовательских ресурсов при ошибке"""
if self.errorAndUnmountUserRes and self.userName:
14 years ago
# Установка ошибки в профиль пользователя на сервере
# и отмонтирование ресурсов
self.umountUserResNoSync(self.userName, False, False, False, True,
flagErrorSync=True)
def __del__(self):
"""Выполняется при удалении объекта"""
self.errorExit()
def isRoot(self, printError=True):
"""Определяет является ли пользователь root"""
if os.getuid() == 0 and os.getgid() == 0:
return True
else:
if printError:
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):
"""Находит сервер к которому был подключен пользователь"""
# Короткое имя системы
osLinuxShort = self.clVars.Get("os_linux_shortname")
# Имя для поиска в служебной ветке репликации
userLogin = "%s@%s"%(userName,osLinuxShort)
resSearch = self.searchLdapDN(userLogin, self.replHostsDN, "uid")
return resSearch
def searchReplBranch(self):
"""Находит ветку создаваемую при включении репликации
В ветке находятся ((имя пользователя, имя системы, хост) ....)
"""
resSearch = self.searchLdapDN(self.replBranchName,
self.sysDN,
self.replAttr)
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 = 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 = ""
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 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.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 checkUserPwdLDAP(self, server, userDN, password):
"""Проверка пароля Unix пользователя на сервере"""
ldapInit = ldap.initialize("ldap://%s"%server)
errMessage = ""
try:
ldapInit.bind_s(userDN, password)
except ldap.INVALID_CREDENTIALS:
14 years ago
errMessage = _("Password incorrect")
return False, errMessage
except ldap.LDAPError, e:
errMessage = e[0]['desc']
return False, errMessage
return True, errMessage
def getServerDataUser(self):
"""Получение имени LDAP сервера и DN пользователей под пользователем"""
fileName = "/etc/ldap.conf"
serverName = ""
usersDN = ""
strServer = ("host","HOST")
lenStrServer = len(strServer[0])
strDN = ("nss_base_passwd","NSS_BASE_PASSWD")
lenStrDN = len(strDN[0])
splList = (" ", "\t")
try:
for i in open(fileName):
if not serverName and\
filter(lambda x: i.startswith(x),strServer) and\
len(i)>lenStrServer:
spl = i[lenStrServer]
if spl in splList:
serverName = i.rpartition(spl)[2].strip()
if not usersDN and filter(lambda x: i.startswith(x), strDN) and\
len(i)>lenStrDN:
spl = i[lenStrDN]
if spl in splList:
usersDN = i.rpartition(spl)[2].partition('?')[0].strip()
if serverName and usersDN:
break
except:
self.printERROR(_("Can not open %s")%fileName)
return False
if serverName and usersDN:
return (serverName, usersDN)
else:
return ()
def setServerCommand(self, command, varsCommand, fileConfig,
uid=None, gid=None):
"""Установить команду для сервера"""
pathConfig = os.path.split(fileConfig)[0]
# Создаем директорию если ее нет
if not os.path.exists(pathConfig):
os.makedirs(pathConfig)
if not uid is None and not gid is None:
os.chown(pathConfig, uid, gid)
objConfig = cl_base.iniParser(fileConfig)
varsRun = {"run":"on"}
varsRun.update(varsCommand)
if not objConfig.setVar(["command"]+command, varsRun):
self.printERROR(_("Can not write variables in file %s")\
%fileConfig)
return False
if not uid is None and not gid is None:
os.chown(fileConfig, uid, gid)
return True
def getDataInConfig(self, section, listVars, objConfig):
"""Читаем переменные listVars из секции section конф. файла"""
varsConfig = {}
for varName in listVars:
varsConfig[varName] = objConfig.getVar(section,varName)
if objConfig.getError():
return False
return varsConfig
def setUserPasswordToServer(self, options):
"""Установка пароля пользователя на сервере"""
# Проверяем на root
if self.isRoot(False):
self.printERROR(_("The user is root"))
self.printWARNING(\
14 years ago
_("The program can be executed from a non-root user only"))
return False
# DNS имя хоста
data = self.getServerDataUser()
if not data:
self.printERROR(_("The computer is not in domain"))
self.printWARNING(_("Use passwd"))
return False
server, usersDN = data
# Получаем старый пароль пользователя
curPassword = self.getUserPassword(_("Enter current password"))
if not curPassword:
self.printERROR(_("Current password is empty"))
return False
userDN = self.addDN("uid=%s"%os.environ["USER"], usersDN)
# Проверяем в LDAP сервере текущий пароль пользователя
ret, err = self.checkUserPwdLDAP(server, userDN, curPassword)
if not ret:
self.printERROR(err)
return False
optPasswd = options
if not options:
optPasswd = {"p":""}
password = self.getUserPwd(optPasswd, "p", False)
if password is False:
return False
# Переменные для записи в env файл
varsConfig = {"unix_hash":self.getHashPasswd(password,"ssha"),
"samba_lm_hash":self.getHashPasswd(password,"lm"),
"samba_nt_hash":self.getHashPasswd(password,"nt"),
"samba_nt_hash_old":self.getHashPasswd(curPassword,"nt")}
if filter(lambda x: not x, varsConfig.values()):
return False
# ~/.calculate/server.env
fileConfig = os.path.join(os.environ["HOME"], self.pathConfig,
self.configFileServer)
if not self.setServerCommand(["passwd_samba"], varsConfig,
fileConfig):
return False
self.printOK(_("Changed password of user %s")%os.environ["USER"] + \
" ...")
self.printWARNING(_("Password will be changed when you logout from the \
X session"))
return True
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, envProg={}):
"""Выполняет внешнюю программу
Параметры:
cmdStrProg внешняя программа
inStr данные передаваемые программе на страндартный вход.
Возвращаемые параметры:
строка которую выведет внешняя программа или False в случае ошибки
"""
env_path = {"PATH":cl_utils.getpathenv()}
env = {}
env.update(os.environ.items() + env_path.items() + envProg.items())
retCode,programOut = cl_utils.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
# Создаем пользовательскую директорию
self.clVars.Set('cl_root_path',homeDir,True)
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 profiles") + " ...")
# Создаем домашнюю директорию
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(_("Can 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)
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 is 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 relevanceProfiles(self, hostAuth):
"""Определяем актуальность наложенных профилей
в зависимости от версии программы
Перед запуском обязательно должен быть определен объект переменных
self.clVars
Если актуальны - True, если нет False
"""
# 'local' или имя хоста
if hostAuth != self.clVars.Get("os_remote_auth"):
return False
clProf = cl_profile.profile(self.clVars)
# Текущая версия программы
currentVersion = self.clVars.Get("cl_ver")
# Версия программы которая ранее работала с профилями
previousVersion = self.clVars.Get("os_remote_client")
cVersion, pVersion = clProf._convertVers(currentVersion,previousVersion)
# Если версии программ не равны то профили не актуальные
if cVersion != pVersion:
return False
return True
def getPathProfiles(self, listPath):
"""Получаем список директорий хранения профилей"""
"""список накладываемых профилей при установке, наложении профилей"""
profpath = []
for profPath in listPath:
if os.path.isdir(profPath):
paths = os.listdir(profPath)
for path in paths:
ph = os.path.join(profPath,path)
filesAndDirs = os.listdir(ph)
if os.path.isdir(ph) and filesAndDirs:
profpath.append(ph)
return profpath
def applyRelevanceProfiles(self, hostAuth):
"""Накладывает релевантные профили
Перед запуском обязательно должен быть определен объект переменных
self.clVars
"""
if not self.relevanceProfiles(hostAuth):
# Обнуляем переменную удаленный хост
if hostAuth == "local":
self.clVars.Set("cl_remote_host","",True)
# Изменяем базовую директорию наложения профилей
self.clVars.Set("cl_root_path","/",True)
# Устанавливаем действие profiles_domain
self.clVars.Set("cl_pass_type","domain",True)
# Наложим профили profiles/domain
# Новые пути к профилям
profPaths = self.getPathProfiles(self.rootProfilePaths)
if not profPaths:
self.printERROR(_("Empty profile paths %s")\
%", "(self.rootProfilePaths))
return False
# Изменяем переменную хранения профилей
self.clVars.Set("cl_profile_path",profPaths,True)
# Наложим профили
dirsAndFiles = self.applyProfilesFromSystem()
if not dirsAndFiles:
self.printERROR(_("Can not apply 'profiles/domain' profiles"))
return False
if hostAuth == "local":
self.printOK(_("Set profiles of local mode"))
else:
self.printOK(_("Set profiles 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.applyRelevanceProfiles("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.applyRelevanceProfiles(domain):
return False
return True
flagLocalProfile = 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})
if not (textLine is None):
self.printWARNING(_("Can not mount Samba resource [%s]")%\
"remote" + " ...")
flagLocalProfile = True
# Если профили не актуальны накладываем новую версию профилей
if not self.applyRelevanceProfiles("local"):
return False
if foundMountHome:
umountStr = "umount /home"
textLine = self.execProg(umountStr)
if not (textLine is None):
self.printERROR(_("Can not unmount") + " /home")
return False
return True
self.printSUCCESS(_("Mount Samba resource [%s]") % "remote" +\
" ...")
if (not foundMountHome) and (not flagLocalProfile):
if not os.path.exists(pathHome):
os.makedirs(pathHome)
mountStr = "mount -o bind %s /home" %pathHome
textLine = self.execProg(mountStr)
if not (textLine is None):
self.printERROR(_("Can not mount") + " " + str(pathHome) +\
" ...")
return False
self.printSUCCESS(_("Mount") + " " + str(pathHome) + " " +\
" ...")
# Накладываем сетевые профили
if domain:
self.clVars.flIniFile()
if not self.applyRelevanceProfiles(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)
# Изменяем базовую директорию наложения профилей
self.clVars.Set("cl_root_path","/",True)
# Наложим профили profiles/domain
# Новые пути к профилям
# Устанавливаем действие profiles_domain
self.clVars.Set("cl_pass_type","domain",True)
# Новые пути к профилям
profPaths = self.getPathProfiles(self.rootProfilePaths)
if not profPaths:
self.printERROR(_("Empty profile paths %s")\
%", "(self.rootProfilePaths))
return False
# Изменяем переменную хранения профилей
self.clVars.Set("cl_profile_path",profPaths,True)
# Наложим профили
dirsAndFiles = self.applyProfilesFromSystem()
if not dirsAndFiles:
self.printERROR(_("Can not apply 'profiles/domain' profiles"))
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)
# Изменяем базовую директорию наложения профилей
clVars.Set("cl_root_path","/",True)
# Устанавливаем действие profiles_client
clVars.Set("cl_pass_type","install",True)
# Новые пути к профилям
profPaths = self.getPathProfiles(self.rootProfilePaths)
if not profPaths:
self.printERROR(_("Empty profile paths %s")\
%", "(self.rootProfilePaths))
return False
# Изменяем переменную хранения профилей
clVars.Set("cl_profile_path",profPaths,True)
# Наложим профили
dirsAndFiles = self.applyProfilesFromSystem()
if not dirsAndFiles:
self.printERROR(_("Can not apply 'profiles/client' profiles"))
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)
# Изменяем базовую директорию наложения профилей
clVars.Set("cl_root_path","/",True)
# Устанавливаем действие profiles_client
clVars.Set("cl_pass_type","install",True)
# Новые пути к профилям
profPaths = self.getPathProfiles(self.rootProfilePaths)
if not profPaths:
self.printERROR(_("Empty profile paths %s")\
%", "(self.rootProfilePaths))
return False
# Изменяем переменную хранения профилей
clVars.Set("cl_profile_path",profPaths,True)
# Наложим профили
dirsAndFiles = self.applyProfilesFromSystem()
if not dirsAndFiles:
self.printERROR(_("Can not apply 'profiles/client' profiles"))
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 is 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 is 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
# Наложим профили profiles/client
if not self.installClient(self.clVars, False):
return False
# Наложим профили profiles/domain
# Устанавливаем действие profiles_client
self.clVars.Set("cl_pass_type","domain",True)
# Новые пути к профилям
profPaths = self.getPathProfiles(self.rootProfilePaths)
if not profPaths:
self.printERROR(_("Empty profile paths %s")\
%", "(self.rootProfilePaths))
return False
# Изменяем переменную хранения профилей
self.clVars.Set("cl_profile_path",profPaths,True)
# Наложим профили
dirsAndFiles = self.applyProfilesFromSystem()
if not dirsAndFiles:
self.printERROR(_("Can not apply 'profiles/domain' profiles"))
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 removeNoiseFiles(self, userHome):
"""Удаление файлов, создающих помехи работе dm"""
noiseFiles = ['.dmrc']
for nsFile in noiseFiles:
rmFile = os.path.join(userHome, nsFile)
if os.path.exists(rmFile):
os.remove(rmFile)
return True
def removePrivateFiles(self, userHome):
"""Удаление приватных файлов"""
privateFiles = ['.kde4/share/apps/kwallet/kdewallet.kwl',
os.path.join(self.pathConfig,
self.configFileServer)]
# файлы в .ssh
sshHome = ".ssh"
sshPath = os.path.join(userHome,sshHome)
if os.path.isdir(sshPath):
# .ssh файлы относительно домашней директории пользователя
privateFiles += map(lambda x:os.path.join(sshHome,x),\
filter(lambda x:\
os.path.isfile(os.path.join(sshPath,x)),\
os.listdir(sshPath)))
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 clearUserKey(self, userName):
"""Очищает пользовательский ключ ядра"""
# Ищем ключ в ядре
if _cl_keys.getKey(userName):
# Если нашли очищаем
ret = _cl_keys.clearKey(userName)
if ret == 0:
return True
else:
self.printERROR(_("Can not clear kernel key from user %s")\
%userName)
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]
# Файл хранения настроек пакета
configFileName = os.path.join(homeDir, self.pathConfig,
self.configFileDesktop)
# Получаем монтируемые директории
names, dictRes = self.getUserMountResources(userName, homeDir, False)
if os.path.exists(homeDir):
self.moveHomeDir(homeDir)
else:
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
self.printERROR(_("Directory %s not found") % homeDir)
return False
# Синхронизируем настройки
pathUnix = dictRes["profile"]["path"]
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 is None):
self.printERROR(_("Can not mount Samba resource [%s]")\
%"unix" + " ...")
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
return False
# проверяем произведен ли корректный вход в систему -
# в этом случае закачиваем профиль с локальной машины на сервер
# необходима ли синхронизация с локальным сервером
needSync = False
try:
# если актуальный профиль хранится не на локальном сервере
# то на локальный сервер закачиваем профиль
# так как даже если он будет поврежден на другом сервере
# остаётся правильная копия
if self.getNameRemoteServer(userName):
needSync = True
else:
exitStr = cl_base.iniParser(\
configFileName).getVar('main','status_sync')
# проверяем cтатус синхронизации: не содержит ли он "process"
if exitStr != "process":
needSync = True
except:
# Удаляем файлы, мешающие работе dm
self.removeNoiseFiles(homeDir)
# Удаляем приватные файлы
self.removePrivateFiles(homeDir)
# Очищаем ключ в ядре
self.clearUserKey(userName)
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
return False
osLinuxShort = self.clVars.Get("os_linux_shortname")
homeProfile = os.path.join(pathUnix, osLinuxShort)
if needSync and not self.syncUser(userName, homeDir,"logout",uid,gid,
homeProfile):
# Удаляем файлы, мешающие работе dm
self.removeNoiseFiles(homeDir)
# Удаляем приватные файлы
self.removePrivateFiles(homeDir)
# Очищаем ключ в ядре
self.clearUserKey(userName)
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
return False
# Удаляем файлы, мешающие работе dm
self.removeNoiseFiles(homeDir)
# Удаляем приватные файлы
self.removePrivateFiles(homeDir)
# Очищаем ключ в ядре
self.clearUserKey(userName)
flagError = False
# Отмонтируем директории
14 years ago
for name in reversed(names):
path = dictRes[name]["path"]
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:
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,
14 years ago
isXsession=True, killRsync=False, progress=False,
flagErrorSync=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]
# Получаем монтируемые директории
names, dictRes = self.getUserMountResources(userName, homeDir, True)
serverHomePath = dictRes["home"]["path"]
flagError = False
if self.isMount(serverHomePath, "cifs"):
self.moveHomeDir(homeDir)
14 years ago
# Записываем ошибку синхронизации
if flagErrorSync:
pathProfileCurr = dictRes["profile"]["path"]
osLinuxShort = self.clVars.Get("os_linux_shortname")
# Находим директорию профиля
14 years ago
homeProfile = os.path.join(pathProfileCurr, osLinuxShort)
14 years ago
if not os.path.exists(homeProfile):
14 years ago
homeProfile = os.path.join(pathProfileCurr, "." + osLinuxShort)
14 years ago
if os.path.exists(homeProfile):
configFileName = os.path.join(homeProfile, self.pathConfig,
self.configFileDesktop)
logOutFile = os.path.join(homeProfile,self.logOutFile)
uid = os.stat(homeProfile).st_uid
gid = os.stat(homeProfile).st_gid
self.createUserFile(logOutFile,"ERROR", uid, gid)
self.setVarToConfig("main", {"status_sync":"error"},
configFileName, uid, gid)
14 years ago
for name in reversed(names):
path = dictRes[name]["path"]
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 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 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 getNameRemoteServer(self,userName):
"""Если профиль на удаленном сервере, то выдать DNS имя этого сервера
"""
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 False
else:
return prevHost
def setDateAndVersionToConfig(self, configFileName, uid, gid, strTime):
"""Записывает текущую версию в файл конфигурации"""
# Текущая версия программы
currentVersion = self.clVars.Get("cl_ver")
if self.setVarToConfig("main", {"version":currentVersion,
"date":strTime},
configFileName, uid, gid):
return True
self.printERROR(_("can not write the version number in the file %s")\
%configFileName)
return False
def setVarToConfig(self, nameSection, varsDict, configFileName, uid, gid):
"""Записывает переменную в файл конфигурации"""
# Создаем директорию для конфигурационных файлов
pathConfig = os.path.split(configFileName)[0]
if not os.path.exists(pathConfig):
self.createUserDir(uid, gid, pathConfig, mode=False)
try:
if cl_base.iniParser(configFileName).setVar(nameSection, varsDict):
os.chmod(configFileName, 0600)
os.chown(configFileName,uid,gid)
except:
return False
return True
def clearHomeDir(self, homeDir):
"""Очистка домашней директории от файлов"""
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):
return False
elif stat.S_ISSOCK(os.stat(delFile)[stat.ST_MODE]):
os.remove(delFile)
return True
def getUserMountResources(self, userName, homeDir, flagRemoteServer):
"""Получение монтируемых ресурсов для пользователя"""
home = os.path.split(homeDir)[0]
dictResources = {}
names = []
# Pесурс share
name = "share"
dictResources[name] = {"resource":"share",
"path":os.path.join(homeDir,"Disks")}
names.append(name)
# Ресурс профилей
name = "profile"
dictResources[name] = {"resource":"unix",
"path":os.path.join(home,"."+userName)}
names.append(name)
# Ресурс - домашняя директория (файлы пользователя на сервере)
name = "home"
dictResources[name] = {"resource":"homes",
"path":os.path.join(homeDir,"Home")}
names.append(name)
if self.clVars.Get("cl_remote_ftp"):
# Ресурс ftp
name = "ftp"
dictResources[name] = {"resource":"ftp",
"path":os.path.join(homeDir,"FTP")}
names.append(name)
if flagRemoteServer:
# Ресурс профилей на удаленном сервере
name = "remote_profile"
dictResources[name] = {"resource":"unix",
"path":os.path.join(home,"."+userName+"."+"remote")}
names.append(name)
return names, dictResources
def syncLoginProfile(self, userName, homeDir, homeProfile, uid, gid,
progress, flagClearHomeDir=True):
"""Синхронизация профиля пользователя с сервера
в переменной 'cl_remote_host' хост для прогрессбара
"""
home = os.path.split(homeDir)[0]
# Если на текущем сервере в ресурсе unix есть файлы
# то синхронируем настройки
if os.listdir(homeProfile):
if not self.syncUser(userName, homeDir, "login", uid, gid,\
homeProfile, progress=progress,
host=self.clVars.Get('cl_remote_host')):
return False
else:
if flagClearHomeDir:
# Удаляем ненужные файлы (очищаем домашнюю директорию)
if not self.clearHomeDir(homeDir):
return False
return True
def fileReader(self, fileName, stdin, progressObj=False):
"""Читает файл блоками в поток"""
fd = os.open(fileName, os.O_RDONLY)
if progressObj:
currSize = 0
# Размер файлового буфера в байтах
buffSize=131072
dataBlock = os.read(fd, buffSize)
while dataBlock:
if progressObj:
currSize += len(dataBlock)
progressObj.setValue(currSize)
stdin.write(dataBlock)
dataBlock = os.read(fd, buffSize)
stdin.close()
os.close(fd)
def unpackProfile(self, homeDir, archFile, progress=False,\
remoteServer=False):
"""Распаковка архива в домашнюю директорию пользователя"""
# Создаем прогрессбар
if progress:
title = _("Unpacking the archive from server")
if remoteServer:
title += " " + remoteServer
title += " ..."
progressObj = ProgressBar(title)
archiveSize = os.stat(archFile).st_size
progressObj.setMaximum(archiveSize)
execStr = "tar -C '%s' -xzf -" %homeDir
# Выполняем разархивацию
pipe = subprocess.Popen(execStr,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=True,
env=os.environ, shell=True)
# Чтение файла в поток
if progress:
self.fileReader(archFile, pipe.stdin, progressObj)
else:
self.fileReader(archFile, pipe.stdin)
ret = pipe.wait()
pipe.stdout.close()
pipe.stderr.close()
if progress:
progressObj.shutdownDialog()
#ret = os.system(execStr)
if ret:
self.printERROR(_("Can not execute %s") %execStr)
self.printERROR(_("Can not unpack %s") %archFile)
return False
return True
def scanDirectory(self, scanDir, listFiles, skipPath=[], prefix=False,
flagDir=False):
"""Генерация списка файлов и директорий"""
if not prefix:
prefix = os.path.join(scanDir,"")
if flagDir or stat.S_ISDIR(os.lstat(scanDir)[stat.ST_MODE]):
for fileOrDir in os.listdir(scanDir):
absPath = os.path.join(scanDir,fileOrDir)
relPath = absPath.split(prefix)[1]
if relPath in skipPath:
continue
listFiles.append(relPath)
stInfo = os.lstat(absPath)
statInfo = stInfo[stat.ST_MODE]
if stat.S_ISDIR(statInfo):
self.scanDirectory(absPath, listFiles,
skipPath, prefix, True)
def getListFilesProfile(self, homeDir):
"""Генерация списка файлов в домашней директориии
Исключая монтируемые директории
"""
home = os.path.join(homeDir, "")
execStr = "mount"
textLines = self.execProg(execStr,False,False)
# Пропускаемые директории для сканирования
skipPaths = []
if textLines:
for line in textLines:
if home in line:
skipPath =\
line.partition(home)[2].rpartition(" type")[0]
skipPaths.append(skipPath)
# Список файлов в профиле пользователя
listFiles = []
if not skipPaths:
self.printERROR(_("Not found the mount point of server resources"))
return False
self.scanDirectory(homeDir, listFiles, skipPaths)
return listFiles
def removeFilesInProfile(self, homeDir, pathListFile):
"""Удаляем файлы которых нет в профиле пользователя"""
# Получаем файлы профиля на сервере
try:
filesProfileTxt = open(pathListFile).read()
except:
self.printERROR(_("Can not open %s")%pathListFile)
return False
listFilesProfile = filter(lambda x: x.strip(),
filesProfileTxt.split("\n"))
filesProfile = set(listFilesProfile)
# Получаем файлы в домашней директории
listFilesHome = self.getListFilesProfile(homeDir)
if listFilesHome is False:
return False
filesHome = set(listFilesHome)
filesRemove = list(filesHome - filesProfile)
filesRemove.sort(lambda x, y: cmp(len(y), len(x)))
rmPath = ""
try:
for rmFile in filesRemove:
rmPath = os.path.join(homeDir, rmFile)
14 years ago
if os.path.islink(rmPath):
os.unlink(rmPath)
14 years ago
elif os.path.isfile(rmPath):
14 years ago
os.remove(rmPath)
elif os.path.isdir(rmPath):
os.rmdir(rmPath)
else:
os.remove(rmPath)
except:
self.printERROR(_("Can nor remove %s")%rmPath)
return False
return True
def foundArchFile(self,strCurrentTime,archPathProcess,
archPathSuccess, progress=False,
remoteServer=False):
"""Поиск архива профиля пользователя"""
# Ищем архив профиля
# Задержки при поиске файла архива .process
if progress:
title = _("Packing the archive at the server")
if remoteServer:
title += " " + remoteServer
title += " ..."
progressObj = ProgressBar(title, 0)
progressObj.openDialog(title, 0)
sleepsFindProcess = [0.1, 0.2, 0.5]
# Задержки при проверке размера архива
sleepsArch = [0.5, 1, 2]
lenFP = len(sleepsFindProcess)
lenA = len(sleepsArch)
i = 0
# Ждем появления файла архива
while(not (os.path.exists(archPathProcess) or\
os.path.exists(archPathSuccess)) and i<lenFP):
time.sleep(sleepsFindProcess[i])
i +=1
# Если нет архива применяем rsync синхронизацию
if not (os.path.exists(archPathProcess) or\
os.path.exists(archPathSuccess)):
# Архив не найден rsync схема синхронизации
if progress:
progressObj.shutdownDialog()
return False
# Ожидание создания архива
if os.path.exists(archPathProcess):
i = 0
while(os.path.exists(archPathProcess)):
if os.path.exists(archPathSuccess):
break
if i>=lenA:
# rsync схема синхронизации
if progress:
progressObj.shutdownDialog()
return False
startSize = os.stat(archPathProcess).st_size
time.sleep(sleepsArch[i])
if os.path.exists(archPathSuccess):
break
endSize = os.stat(archPathProcess).st_size
if startSize == endSize:
i += 1
if progress:
progressObj.shutdownDialog()
return True
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]
# Файл хранения настроек пакета
configFileName = os.path.join(homeDir, self.pathConfig,
self.configFileDesktop)
# При отсуствии создаем домашнюю директорию
if not os.path.exists(homeDir):
os.makedirs(homeDir)
os.chown(homeDir,uid,gid)
os.chmod(homeDir,0700)
# записываем в конфигурационный файл статус "в процессе"
self.setVarToConfig("main", {"status_sync":"process"},
configFileName, uid, gid)
# Получаем пароль пользователя из ключей ядра
userPwd = _cl_keys.getKey(userName)
if not userPwd:
self.printERROR(_("Not found user password"))
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
return False
# Флаг ошибки
flagError = False
# Имя удаленного сервера
remoteServer = ""
# В случае включения репликации на сервере True
replOn = self.searchReplBranch()
if replOn:
remoteServer = self.getNameRemoteServer(userName)
# Получаем монтируемые директории
names, dictRes = self.getUserMountResources(userName, homeDir,
remoteServer)
# Путь к профилю пользователя по умолчанию
defaultPath = ""
# Хост пользователя по умолчанию
defaultHost = self.clVars.Get("cl_remote_host")
# Флаг - будет использован инкрементальный архив
flagIncrArch = True
# Ошибка при монтировании удаленного сервера
flagErrorMountRemote = False
# Ошибка при cинхронизации с удаленного сервера
flagErrorSyncRemote = False
# Статус синхронизации
syncStatus = True
osLinuxShort = self.clVars.Get("os_linux_shortname")
# Если профиль на удаленном сервере
if remoteServer and replOn:
# имя файла архива в процессе архивации
archPathProcess = ""
# имя файла архива - после архивации
archPathSuccess = ""
# Создаем инкрементальный архив в случае репликации
prevHost = ""
# Дата профиля на текущем сервере
dateDefaultProfile = ""
# Текущее время
currTime = str(float(time.time()))
# Создаваемые пути при монтировании
for name in names:
path = dictRes[name]["path"]
res = dictRes[name]["resource"]
# Создаем пользовательскую директории для профиля
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
# Монтируем Samba ресурс
if name == "remote_profile":
self.clVars.Set("cl_remote_host", remoteServer, True)
textLine = self.mountSleepRes(userName,userPwd,uid,gid,
res,path)
if name == "remote_profile":
self.clVars.Set("cl_remote_host", defaultHost, True)
if not (textLine is None):
if name == "remote_profile":
flagErrorMountRemote = True
break
else:
self.printERROR(_("Can not mount Samba resource [%s]")\
%res + " ...")
flagError = True
break
if name == "profile" or name == "remote_profile":
# Находим директорию профиля
homeProfile = os.path.join(path, osLinuxShort)
if not os.path.exists(homeProfile):
homeProfile = os.path.join(path, "." + osLinuxShort)
# Примонтирована директория профиля с текущего сервера
if name == "profile":
# Перенос профиля на сервере в директорию без точки
if not self.upgradeProfileClient(userName, homeDir,
path):
flagError = True
break
fileConfig = os.path.join(homeProfile,
self.pathConfig,
self.configFileDesktop)
if os.path.exists(fileConfig):
objConfig = cl_base.iniParser(fileConfig)
data = self.getDataInConfig("main", ["status_sync",
"date"],
objConfig)
if data:
status = data.get("status_sync")
date = data.get("date")
if date and status=="success":
dateDefaultProfile = date
# Примонтирована директория профиля с удаленного сервера
# и есть дата профиля текущего сервера
if name == "remote_profile" and dateDefaultProfile:
# Даем команду на создание инкрементального архива проф.
fileConfig = os.path.join(homeProfile,
self.pathConfig,
self.configFileServer)
varsConfig = {"arch_date":dateDefaultProfile,
"curr_time":currTime}
self.setServerCommand(["pack"], varsConfig, fileConfig)
# Отмонтируем директорию профиля с удаленного сервера
textLine = self.umountSleepPath(path)
if not textLine:
flagError = True
break
pathProfileCurr = dictRes["profile"]["path"]
homeProfileCurr = os.path.join(pathProfileCurr,osLinuxShort)
# Синхронизация профиля с текущего сервера
if not self.syncLoginProfile(userName,homeDir,
homeProfileCurr,
uid, gid, progress):
flagError = True
break
# Монтируем директорию профиля с удаленного сервера
self.clVars.Set("cl_remote_host", remoteServer, True)
textLine = self.mountSleepRes(userName,userPwd,uid,gid,
res,path)
self.clVars.Set("cl_remote_host", defaultHost, True)
if not (textLine is None):
self.printERROR(_("Can not mount Samba resource [%s]")\
%res + " ...")
flagError = True
break
extSuccess = "gz"
extProcess = "process"
strCurrentTime = currTime.replace(".","_")
archPathTmp = os.path.join(path, "profile.%s.%s.tar"\
%(osLinuxShort, strCurrentTime))
# имя файла архива в процессе архивации
archPathSuccess = "%s.%s"%(archPathTmp,extSuccess)
# имя файла архива - после архивации
archPathProcess = "%s.%s"%(archPathTmp,extProcess)
# Ищем файл архива
if not self.foundArchFile(strCurrentTime, archPathProcess,
archPathSuccess, progress,
remoteServer):
flagIncrArch = False
break
# Если нет архива применяем rsync синхронизацию
if not os.path.exists(archPathSuccess):
flagIncrArch = False
break
else:
# Распаковываем архив в домашнюю директорию
if not self.unpackProfile(homeDir, archPathSuccess,
progress, remoteServer):
flagError = True
14 years ago
if archPathSuccess:
# Удаление архивного файла
if os.path.exists(archPathSuccess):
# Удаляем файл архива
os.remove(archPathSuccess)
break
# Cканирование домашней директории и получение списка
# файлов
pathListFile = os.path.join(homeProfile,
self.listProfFile)
14 years ago
if not self.removeFilesInProfile(homeDir, pathListFile):
self.errorAndUnmountUserRes = True
return False
else:
if name == "remote_profile":
flagIncrArch = False
if archPathProcess or archPathSuccess:
# Удаление архивных файлов
rmFiles = [archPathProcess, archPathSuccess]
for rmFile in rmFiles:
if os.path.exists(rmFile):
# Удаляем файл архива
os.remove(archPathSuccess)
# Если не удалось замонтировать удаленный профиль
if flagErrorMountRemote:
syncStatus = False
# Если не удалось использовать инкрементальный архив
elif flagIncrArch is False:
# Синхронизируем удаленный профиль
14 years ago
pathProfile = dictRes["remote_profile"]["path"]
homeProfile = os.path.join(pathProfile, osLinuxShort)
if not self.upgradeProfileClient(userName, homeDir,
14 years ago
pathProfile):
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
return False
# Синхронизация профиля с удаленного сервера
self.clVars.Set("cl_remote_host", remoteServer, True)
ret = self.syncLoginProfile(userName, homeDir, homeProfile,
uid, gid, progress, False)
self.clVars.Set("cl_remote_host", defaultHost, True)
if not ret:
flagErrorSyncRemote = True
syncStatus = False
# Если не удалось синхронизировать удаленный синхронизируем
# текущий
homeProfile = os.path.join(dictRes["profile"]["path"],
osLinuxShort)
if not self.syncLoginProfile(userName, homeDir, homeProfile,
uid, gid, progress):
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
return False
# Отмонтируем директорию профиля пользователя на удаленном сервере
if "remote_profile" in dictRes:
umountPath = dictRes["remote_profile"]["path"]
textLine = self.umountSleepPath(umountPath)
if not textLine:
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
return False
# Удаляем директорию удаленного профиля у клиента
if os.path.exists(umountPath):
os.rmdir(umountPath)
# Если профиль на текущем сервере
elif not remoteServer and replOn or not replOn:
# Создаваемые пути при монтировании
for name in names:
path = dictRes[name]["path"]
res = dictRes[name]["resource"]
# Создаем пользовательскую директории для профиля
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
textLine = self.mountSleepRes(userName,userPwd,uid,gid,
res, path)
if not (textLine is None):
self.printERROR(_("Can not mount Samba resource [%s]")\
%res + " ...")
flagError = True
break
if name == "profile":
pathProfile = path
# Перенос профиля на сервере в директорию без точки
if not self.upgradeProfileClient(userName, homeDir,
pathProfile):
flagError = True
break
# Директория профиля
homeProfile = os.path.join(path, osLinuxShort)
# Синхронизируем
if not self.syncLoginProfile(userName, homeDir, homeProfile,
uid, gid, progress):
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
return False
if flagError:
# Отмонтируем пользовательские ресурсы в случае ошибки
self.errorAndUnmountUserRes = True
return False
logOutFile = os.path.join(homeDir,self.logOutFile)
if syncStatus:
self.setVarToConfig("main", {"status_sync":"success"},
configFileName, uid, gid)
self.createUserFile(logOutFile,"SUCCESS", uid, gid)
else:
self.createUserFile(logOutFile,"ERROR", uid, gid)
self.setVarToConfig("main", {"status_sync":"error"},
configFileName, uid, gid)
self.printWARNING(_("Error in sync with the remote server %s")\
%remoteServer)
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 is 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 is None)):
# Задержка перед следующей попыткой
time.sleep(self.sleeps[i])
# Монтируем Samba ресурс
textLine = self.mountSambaRes(userName,userPwd,uid,
gid,res,path)
if not (textLine is 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\
14 years ago
not os.path.split(x)[1].startswith('.') 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 is None):
self.printERROR(_("Can not exec") + " " + str(execStr) +\
" ...")
return False
execStr = "rm -rf '%s'" %fd
textLine = self.execProg(execStr)
if not (textLine is 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 copyProfileDir(self, srcDir, destDir):
"""Перенос директории srcDir в директорию destDir
При копировании сохраняются владелец, группа, права
"""
if os.system("mv %s %s &>/dev/null"%(srcDir, destDir)) != 0:
self.printERROR(_("Can not move %s")%srcDir + " " +\
_("to %s")%destDir)
return False
return True
def upgradeProfileClient(self, userName, userHome, pathProfiles):
"""Переносит данные клиента в директорию без точки
например: было /home/.user/.CLD стало /home/.user/CLD
Перед вызовом этого метода обязательно должен быть определен атрибут
объекта self.clVars - объект переменных
"""
# Директория хранения старых профилей
home = os.path.split(userHome)[0]
if os.path.exists(pathProfiles):
osLinuxShort = self.clVars.Get("os_linux_shortname")
pathNewProfile = os.path.join(pathProfiles, osLinuxShort)
pathOldProfile = os.path.join(pathProfiles, "."+osLinuxShort)
if not os.path.exists(pathNewProfile) and\
os.path.exists(pathOldProfile) and\
os.listdir(pathOldProfile):
# Переносим профиль
if not self.copyProfileDir(pathOldProfile,
pathNewProfile):
return False
if not os.path.exists(pathNewProfile):
# Создаем директорию для хранения профиля
os.mkdir(pathNewProfile)
os.chmod(pathNewProfile, 0700)
if os.path.exists(pathOldProfile) and\
not os.listdir(pathOldProfile):
os.rmdir(pathOldProfile)
return True
def syncUser(self, userName, userHome, sync, uid, gid, homeProfile, \
progress=False, host="default"):
"""Синхронизация пользовательских настроек
Перед вызовом этого метода обязательно должен быть определен атрибут
объекта self.clVars - объект переменных
"""
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" \
--exclude="/.Xauthority" \
14 years ago
--exclude="/.thumbnails" \
--exclude="/.mozilla/firefox/*/Cache" \
--exclude="/.cache" \
--exclude="/.opera/cache" \
--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" \
14 years ago
--filter="P /.thumbnails" \
--filter="P /.mozilla/firefox/*/Cache" \
--filter="P /.cache" \
--filter="P /.opera/cache" \
--filter="P /FTP" -a -x -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="/.Xauthority" \
--exclude="/.kde4/share/apps/nepomuk/repository/main/data" \
14 years ago
--exclude="/.kde4/socket-*" --exclude="/.kde4/share/config/phonondevicesrc" \
--exclude="/.thumbnails" \
--exclude="/.mozilla/firefox/*/Cache" \
--exclude="/.cache" \
--exclude="/.opera/cache" \
-a -x -v -v -v %s/ %s/'%(userHome,homeProfile)
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)
pathConfig = os.path.join(homeProfile,
self.pathConfig)
# Удаляем предыдущий ini файл
prevIniFile = os.path.join(homeProfile,".calculate.ini")
if os.path.exists(prevIniFile):
os.remove(prevIniFile)
# Создаем директорию для конфигурационных файлов
if not os.path.exists(pathConfig):
self.createUserDir(uid, gid, pathConfig, mode=False)
configFileName = os.path.join(pathConfig, self.configFileDesktop)
if sync == "login":
# получить переменную files из секции Rsync файла
# .calculate.ini
try:
numfiles = cl_base.iniParser(\
configFileName).getVar('rsync','files')
if numfiles is False:
if os.path.exists(configFileName):
os.remove(configFileName)
numfiles = 0
else:
numfiles = int(numfiles)
except:
numfiles = 0
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 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")%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 выдавать ошибку при отсутствии опций командной строки
optUser проверять хвост командной строки на наличие пользователя
"""
def __init__(self, helpObj, notOptError=False, optUser=True):
# от 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
else:
if optUser and self.params.has_key('user'):
if len(self.nameParams) != self.__iter:
self.handlerErrOpt()
# В случае остсутствия опций командной строки и имени пользователя
if notOptError:
if not self.opt:
self.printErrorNotOpt()
self.flagHelp = True
if optUser and not self.params.has_key('user'):
print helpObj.getHelp(helpObj.relOptions['h'])
self.flagHelp = True
elif optUser and not self.opt and not self.params.has_key('user'):
print helpObj.getHelp(helpObj.relOptions['h'])
self.flagHelp = True
if not optUser and 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