|
|
#-*- 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
|
|
|
import time
|
|
|
|
|
|
from encrypt import encrypt
|
|
|
from signal import SIGTERM
|
|
|
|
|
|
Version = "calculate-client 2.1.11"
|
|
|
|
|
|
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:
|
|
|
pipe = subprocess.Popen('/usr/bin/Xdialog --progress "%s" 5 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
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
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):
|
|
|
self.progress.shutdownDialog()
|
|
|
|
|
|
class RsyncProgressBar:
|
|
|
'''Объект запуска 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
|
|
|
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.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.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.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.replLogoutFile = ".logout"
|
|
|
self.skipHomeFile = ["Home","Disks","FTP",
|
|
|
self.replLogoutFile,
|
|
|
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") + ": " +\
|
|
|
_("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:
|
|
|
self.umountUserResNoSync(self.userName, False, False, False, 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:
|
|
|
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 setUserPasswordToServer(self, options):
|
|
|
"""Установка пароля пользователя на сервере"""
|
|
|
# Проверяем на root
|
|
|
if self.isRoot(False):
|
|
|
self.printERROR(_("The user is root"))
|
|
|
self.printWARNING(\
|
|
|
_("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):
|
|
|
# Если нашли очищаем
|
|
|
if _cl_keys.clearKey(userName) == 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)
|
|
|
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 is 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.isCorrectProfileOnLocalServer(userName):
|
|
|
needSync = True
|
|
|
else:
|
|
|
exitStr = cl_base.iniParser(\
|
|
|
configFileName).getVar('main','status')
|
|
|
# проверяем logOutFile: не содержит ли он "process"
|
|
|
if exitStr != "process":
|
|
|
needSync = True
|
|
|
except:
|
|
|
# Удаляем файлы, мешающие работе dm
|
|
|
self.removeNoiseFiles(homeDir)
|
|
|
# Удаляем приватные файлы
|
|
|
self.removePrivateFiles(homeDir)
|
|
|
# Очищаем ключ в ядре
|
|
|
self.clearUserKey(userName)
|
|
|
# Отмонтируем пользовательские ресурсы в случае ошибки
|
|
|
self.errorAndUnmountUserRes = True
|
|
|
return False
|
|
|
|
|
|
if needSync and not self.syncUser(userName,homeDir,"logout",uid,gid):
|
|
|
# Удаляем файлы, мешающие работе 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
|
|
|
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:
|
|
|
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 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 isCorrectProfileOnLocalServer(self,userName):
|
|
|
"""Узнать находится ли актуальный профиль пользователя на локальном
|
|
|
сервере
|
|
|
"""
|
|
|
searchPrevHost = self.searchPrevHost(userName)
|
|
|
if searchPrevHost and searchPrevHost[0][0][1].has_key('host'):
|
|
|
prevHost = searchPrevHost[0][0][1]['host'][0]
|
|
|
else:
|
|
|
prevHost = None
|
|
|
# если местоположение актуального профиля найти не удалось
|
|
|
# или его местоположение не на локальном сервере
|
|
|
if not prevHost or prevHost == self.clVars.Get('cl_remote_host'):
|
|
|
return True
|
|
|
else:
|
|
|
return False
|
|
|
|
|
|
def setCurrentVersionToConfig(self, configFileName, uid, gid):
|
|
|
"""Записывает текущую версию в файл конфигурации"""
|
|
|
# Текущая версия программы
|
|
|
currentVersion = self.clVars.Get("cl_ver")
|
|
|
if self.setVarToConfig("main", {"version":currentVersion},
|
|
|
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 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":"process"},
|
|
|
configFileName, uid, gid)
|
|
|
# записываем в .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
|
|
|
# В случае включения репликации на сервере True
|
|
|
replOn = self.searchReplBranch()
|
|
|
# Путь к профилю пользователя по умолчанию
|
|
|
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 replOn and res=="unix":
|
|
|
defaultPath = path
|
|
|
# Монтируем Samba ресурс
|
|
|
textLine = self.mountSambaRes(userName,userPwd,uid,gid,res,path)
|
|
|
if not (textLine is None):
|
|
|
self.printERROR(_("Can not mount Samba resource [%s]")\
|
|
|
%res + " ...")
|
|
|
flagError = True
|
|
|
break
|
|
|
if flagError:
|
|
|
# Отмонтируем пользовательские ресурсы в случае ошибки
|
|
|
self.errorAndUnmountUserRes = True
|
|
|
return False
|
|
|
flagFirstSync = False
|
|
|
if replOn or sync:
|
|
|
# Ошибка при монтировании unix ресурса удаленного сервера при
|
|
|
# включенной репликации
|
|
|
replErrorMount = False
|
|
|
# Ошибка при cинхронизации unix ресурса удаленного сервера при
|
|
|
# включенной репликации
|
|
|
replErrorSync = False
|
|
|
# Синхронизируем настройки
|
|
|
if sync:
|
|
|
# Короткое имя системы
|
|
|
osLinuxShort = self.clVars.Get("os_linux_shortname")
|
|
|
# В случае репликации
|
|
|
prevHost = ""
|
|
|
# Монтирование по умолчанию (default - cвой сервер, remote - чужой)
|
|
|
mountServer = ""
|
|
|
if replOn:
|
|
|
searchPrevHost = self.searchPrevHost(userName)
|
|
|
if searchPrevHost and searchPrevHost[0][0][1].has_key('host'):
|
|
|
prevHost = searchPrevHost[0][0][1]['host'][0]
|
|
|
# Монтируем ресурс unix текущего сервера
|
|
|
mountServer = "default"
|
|
|
# Переносим настройки пользователя в новую директорию
|
|
|
# CLD
|
|
|
if not self.upgradeProfileClient(userName, homeDir):
|
|
|
# Отмонтируем пользовательские ресурсы в случае ошибки
|
|
|
self.errorAndUnmountUserRes = True
|
|
|
return False
|
|
|
# Если на текущем сервере в ресурсе unix есть файлы
|
|
|
# то синхронируем настройки
|
|
|
# Получаем директорию хранения профиля на сервере
|
|
|
homeProfile = os.path.join(home, "." + userName, osLinuxShort)
|
|
|
if os.listdir(homeProfile):
|
|
|
# Конфигурационный файл клинта на сервере desktop.env
|
|
|
configFileNameServer = os.path.join(homeProfile,
|
|
|
self.pathConfig,
|
|
|
self.configFileDesktop)
|
|
|
# Пишем версию клиента на сервер
|
|
|
if not self.setCurrentVersionToConfig(configFileNameServer,
|
|
|
uid,gid):
|
|
|
# Отмонтируем пользовательские ресурсы в случае ошибки
|
|
|
self.errorAndUnmountUserRes = True
|
|
|
return False
|
|
|
if not self.syncUser(userName, homeDir, "login", uid, gid,\
|
|
|
progress=progress,
|
|
|
host=self.clVars.Get('cl_remote_host')):
|
|
|
# Отмонтируем пользовательские ресурсы в случае ошибки
|
|
|
self.errorAndUnmountUserRes = True
|
|
|
return False
|
|
|
else:
|
|
|
# Удаляем ненужные файлы (очищаем домашнюю директорию)
|
|
|
if not self.clearHomeDir(homeDir):
|
|
|
self.errorAndUnmountUserRes = True
|
|
|
return False
|
|
|
if prevHost and prevHost != self.clVars.Get("cl_remote_host"):
|
|
|
# Отмонтируем ресурс
|
|
|
textLine = self.umountSleepPath(defaultPath)
|
|
|
if not textLine:
|
|
|
# Отмонтируем пользовательские ресурсы в случае ошибки
|
|
|
self.errorAndUnmountUserRes = True
|
|
|
return False
|
|
|
# Монтируем настройки пользователя удаленного сервера
|
|
|
# если сервер найден
|
|
|
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 is 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 is None):
|
|
|
self.printERROR(_("Can not mount Samba resource \
|
|
|
[%s]")%"unix" + " ...")
|
|
|
# Отмонтируем пользовательские ресурсы
|
|
|
# в случае ошибки
|
|
|
self.errorAndUnmountUserRes = True
|
|
|
return False
|
|
|
replErrorMount = True
|
|
|
if mountServer == "remote":
|
|
|
# Переносим настройки пользователя в новую директорию
|
|
|
# CLD
|
|
|
if not self.upgradeProfileClient(userName, homeDir):
|
|
|
# Отмонтируем пользовательские ресурсы в случае ошибки
|
|
|
self.errorAndUnmountUserRes = True
|
|
|
return False
|
|
|
# Получаем директорию хранения профиля на сервере
|
|
|
homeProfile = os.path.join(home, "." + userName,
|
|
|
osLinuxShort)
|
|
|
if os.listdir(homeProfile):
|
|
|
# Конфигурационный файл клинта на сервере
|
|
|
# desktop.env
|
|
|
configFileNameServer = os.path.join(homeProfile,
|
|
|
self.pathConfig,
|
|
|
self.configFileDesktop)
|
|
|
# Пишем версию клиента на сервер
|
|
|
if not self.setCurrentVersionToConfig(\
|
|
|
configFileNameServer,
|
|
|
uid,gid):
|
|
|
# Отмонтируем пользовательские ресурсы в случае ошибки
|
|
|
self.errorAndUnmountUserRes = True
|
|
|
return False
|
|
|
if not self.syncUser(userName,homeDir,"login",
|
|
|
uid,gid, progress=progress,
|
|
|
host=prevHost):
|
|
|
replErrorSync = True
|
|
|
else:
|
|
|
# Удаляем ненужные файлы (очищаем домашнюю директорию)
|
|
|
if not self.clearHomeDir(homeDir):
|
|
|
self.errorAndUnmountUserRes = True
|
|
|
return False
|
|
|
# Перемонтируем ресурс профилей
|
|
|
# на текущий сервер
|
|
|
textLine = self.umountSleepPath(defaultPath)
|
|
|
if not textLine:
|
|
|
# Отмонтируем пользовательские ресурсы в случае ошибки
|
|
|
self.errorAndUnmountUserRes = True
|
|
|
return False
|
|
|
textLine = self.mountSambaRes(userName,userPwd,uid,gid,
|
|
|
"unix",defaultPath)
|
|
|
if not (textLine is None):
|
|
|
self.printERROR(_("Can not mount Samba resource [%s]")\
|
|
|
%"unix" + " ...")
|
|
|
# Отмонтируем пользовательские ресурсы в случае ошибки
|
|
|
self.errorAndUnmountUserRes = True
|
|
|
return False
|
|
|
# если репликации нет
|
|
|
else:
|
|
|
curHost=self.clVars.Get('cl_remote_host')
|
|
|
# Синхронизируем настройки пользователя
|
|
|
|
|
|
# Переносим настройки пользователя в новую директорию
|
|
|
# CLD
|
|
|
if not self.upgradeProfileClient(userName, homeDir):
|
|
|
# Отмонтируем пользовательские ресурсы в случае ошибки
|
|
|
self.errorAndUnmountUserRes = True
|
|
|
return False
|
|
|
# Получаем директорию хранения профиля на сервере
|
|
|
homeProfile = os.path.join(home, "." + userName, osLinuxShort)
|
|
|
if os.listdir(homeProfile):
|
|
|
# Конфигурационный файл клинта на сервере desktop.env
|
|
|
configFileNameServer = os.path.join(homeProfile,
|
|
|
self.pathConfig,
|
|
|
self.configFileDesktop)
|
|
|
# Пишем версию клиента на сервер
|
|
|
if not self.setCurrentVersionToConfig(configFileNameServer,
|
|
|
uid,gid):
|
|
|
# Отмонтируем пользовательские ресурсы в случае ошибки
|
|
|
self.errorAndUnmountUserRes = True
|
|
|
return False
|
|
|
if not self.syncUser(userName, homeDir, "login", uid, gid,\
|
|
|
progress=progress,host=curHost):
|
|
|
# Отмонтируем пользовательские ресурсы
|
|
|
# в случае ошибки
|
|
|
self.errorAndUnmountUserRes = True
|
|
|
return False
|
|
|
else:
|
|
|
# Удаляем ненужные файлы (очищаем домашнюю директорию)
|
|
|
if not self.clearHomeDir(homeDir):
|
|
|
self.errorAndUnmountUserRes = True
|
|
|
return False
|
|
|
if replOn:
|
|
|
if replErrorMount or replErrorSync:
|
|
|
self.createUserFile(logOutFile,"ERROR", uid, gid)
|
|
|
self.setVarToConfig("main", {"status":"error"},
|
|
|
configFileName, uid, gid)
|
|
|
else:
|
|
|
self.setVarToConfig("main", {"status":"success"},
|
|
|
configFileName, uid, gid)
|
|
|
self.createUserFile(logOutFile,"SUCCESS", uid, gid)
|
|
|
else:
|
|
|
self.setVarToConfig("main", {"status":"success"},
|
|
|
configFileName, uid, gid)
|
|
|
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 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\
|
|
|
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):
|
|
|
"""Переносит данные клиента в директорию без точки
|
|
|
например: было /home/.user/.CLD стало /home/.user/CLD
|
|
|
|
|
|
Перед вызовом этого метода обязательно должен быть определен атрибут
|
|
|
объекта self.clVars - объект переменных
|
|
|
"""
|
|
|
# Директория хранения старых профилей
|
|
|
home = os.path.split(userHome)[0]
|
|
|
pathProfiles = os.path.join(home, "." + userName)
|
|
|
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, progress=False,\
|
|
|
host="default"):
|
|
|
"""Синхронизация пользовательских настроек
|
|
|
|
|
|
Перед вызовом этого метода обязательно должен быть определен атрибут
|
|
|
объекта self.clVars - объект переменных
|
|
|
"""
|
|
|
home = os.path.split(userHome)[0]
|
|
|
osLinuxShort = self.clVars.Get("os_linux_shortname")
|
|
|
homeProfile = os.path.join(home, "." + userName, osLinuxShort)
|
|
|
if not os.path.exists(homeProfile):
|
|
|
homeProfile = os.path.join(home, "." + userName,
|
|
|
"." + osLinuxShort)
|
|
|
flagError = False
|
|
|
execStr = ""
|
|
|
if sync == "login":
|
|
|
# исключаемые пути при синхронизации
|
|
|
# /.local/share/akonadi/db_data
|
|
|
# хранит базу acanadi
|
|
|
# /.mozilla/firefox/calculate.default/urlclassifier3.sqlite
|
|
|
# хранит БД для firefox
|
|
|
# /.local/share/mime/mime.cache
|
|
|
# отключение ошибочного кэширования изображений
|
|
|
# /.kde4/share/apps/nepomuk/repository/main/data
|
|
|
# база nepomuk
|
|
|
# /.VirtualBox
|
|
|
# содержит данные о виртуальных машинах
|
|
|
if os.path.exists(userHome) and\
|
|
|
os.path.exists(homeProfile):
|
|
|
execStr = '/usr/bin/rsync --delete-excluded --delete \
|
|
|
--exclude="/.googleearth" --exclude="/.kde4/share/config/phonondevicesrc" \
|
|
|
--exclude="*~" --exclude="/Home" --exclude="/Disks" --exclude="/FTP" \
|
|
|
--exclude="/.local/share/akonadi/db_data" --exclude="/.VirtualBox" \
|
|
|
--exclude="/.mozilla/firefox/calculate.default/urlclassifier3.sqlite" \
|
|
|
--exclude="/.local/share/mime/mime.cache" \
|
|
|
--exclude="/.kde4/share/apps/nepomuk/repository/main/data" \
|
|
|
--exclude="/.logout" \
|
|
|
--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/' %(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" \
|
|
|
--exclude="/.kde4/socket-*" --exclude="/.kde4/share/config/phonondevicesrc"\
|
|
|
-a -x -v -v -v -v %s/ %s/'%(userHome,homeProfile)
|
|
|
else:
|
|
|
self.printERROR(_("Method syncUser: option sync=%s incorrect")\
|
|
|
%str(sync))
|
|
|
return False
|
|
|
if execStr:
|
|
|
host = "<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 = 1
|
|
|
else:
|
|
|
numfiles = int(numfiles)
|
|
|
except:
|
|
|
numfiles = 1
|
|
|
rsync.maximum = numfiles
|
|
|
if progress:
|
|
|
rsync.run()
|
|
|
else:
|
|
|
rsync.runsilent()
|
|
|
if sync == "logout":
|
|
|
rsync.runsilent()
|
|
|
try:
|
|
|
if cl_base.iniParser(configFileName).setVar('rsync',
|
|
|
{'files':rsync.getFilesNum()}):
|
|
|
os.chmod(configFileName, 0600)
|
|
|
os.chown(configFileName,uid,gid)
|
|
|
except:
|
|
|
pass
|
|
|
rsync.close()
|
|
|
if rsync.getExitCode() != 0:
|
|
|
try:
|
|
|
if cl_base.iniParser(configFileName).setVar(\
|
|
|
'rsync',{'exitcode':rsync.getExitCode()}):
|
|
|
os.chmod(configFileName, 0600)
|
|
|
os.chown(configFileName,uid,gid)
|
|
|
except:
|
|
|
pass
|
|
|
self.printERROR(_("Can not 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
|
|
|
|