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

1825 lines
85 KiB

This file contains ambiguous Unicode characters!

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

#-*- coding: utf-8 -*-
# Copyright 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.
__version__ = "2.2.0"
__app__ = "calculate-client"
import os
import re
import sys
import pwd
import subprocess
import ldap
import time
import types
import getpass
from cl_lang import lang
from cl_template import template, iniParser
from cl_datavars import DataVars
from cl_print import color_print
from cl_ldap import ldapUser
from client.progressbar import ProgressBar
from cl_utils import runOsCommand, getpathenv, getModeFile, removeDir
from _cl_keys import getKey, clearKey
lang().setLanguage(sys.modules[__name__])
class DataVarsClient(DataVars):
"""Хранение переменных"""
def flClient(self, **args):
'''Заполнить конфигурацию переменных, для десктопа'''
# Имя секции в calculate.env
envSection = "client"
# заполнить переменные окружения алгоритмом по умолнанию
self.importData(envSection, ('cl_vars_client','cl_fill_client'))
class share(color_print):
"""Общие методы"""
# Объект хранения переменных
clVars = False
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 = DataVarsClient()
clVars.flClient()
clVars.flIniFile()
# Устанавливаем у объекта объект Vars
self.clVars = clVars
return True
def applyTemplatesFromSystem(self):
"""Применяем шаблоны для cистемы"""
# Cоздаем объект обработки шаблонов
clTempl = template(self.clVars)
# Объединяем шаблоны
dirsFiles = clTempl.applyTemplates()
if clTempl.getError():
self.printERROR(clTempl.getError().strip())
return False
else:
return dirsFiles
def printVars(self, opts):
"""Печать существующих переменных"""
if opts == ["all"]:
self.clVars.printVars()
else:
self.clVars.printVars(opts)
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()
class ldapData(ldapUser):
"""Методы для LDAP"""
def addDN(self, *arg):
"""Складывает текстовые элементы DN"""
DNs = []
for dn in arg:
if dn:
DNs.append(dn)
return ','.join(DNs)
def getReplDN(self):
"""Получаем DN ветки хранения последнего посещенного сервера
В ветке находятся ((имя пользователя, имя системы, хост) ....)
"""
usersDN = self.getUsersDN()
if usersDN:
partDN = "ou=Worked,ou=Replication,ou=LDAP"
servicesDN = "ou=Services"
baseDN = usersDN.rpartition(servicesDN+",")[2]
replDN = self.addDN(partDN, servicesDN, baseDN)
return replDN
return False
def searchPrevHost(self, userName, osLinuxShort):
"""Находит сервер к которому был подключен пользователь"""
connectData = self.getBindConnectData()
if connectData:
bindDn, bindPw, host = connectData
replDN = self.getReplDN()
# cтрока для поиска в служебной ветке репликации
userAndOsName = "%s@%s"%(userName,osLinuxShort)
findAttr = "uid=%s"%userAndOsName
# Соединяемся с LDAP
if not self.ldapConnect(bindDn, bindPw, host):
return False
resSearch = self.ldapObj.ldapSearch(replDN, ldap.SCOPE_ONELEVEL,
findAttr, ["host"])
return resSearch
return False
def getNameRemoteServer(self,userName, osLinuxShort):
"""Если профиль на удаленном сервере, то выдать DNS имя этого сервера
"""
searchPrevHost = self.searchPrevHost(userName, osLinuxShort)
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 == osLinuxShort:
return False
else:
return prevHost
def isRepl(self):
"""Включена ли репликация на сервере"""
connectData = self.getBindConnectData()
if connectData:
bindDn, bindPw, host = connectData
usersDN = self.getUsersDN()
partDN = "ou=Replication,ou=LDAP"
servicesDN = "ou=Services"
baseDN = usersDN.rpartition(servicesDN+",")[2]
replDN = self.addDN(partDN, servicesDN, baseDN)
findAttr = "ou=Worked"
# Соединяемся с LDAP
if not self.ldapConnect(bindDn, bindPw, host):
return False
resSearch = self.ldapObj.ldapSearch(replDN, ldap.SCOPE_ONELEVEL,
findAttr,
[findAttr.partition("=")[0]])
if resSearch:
return True
return False
class client(share):
"""Методы работы для подключения пользователя к серверу и синхронизации"""
# Объект для поиска пользовательских данных в LDAP
ldapDataObj = ldapData()
# Путь относительно домашней директории в котором находятся
# конфигурационные файлы
pathConfig = ".calculate"
# Конфигурационный файл для клиента
configFileDesktop = os.path.join(pathConfig, "desktop.env")
# Конфигурационный файл для сервера
configFileServer = os.path.join(pathConfig, "server.env")
# Файл - список файлов профиля пользователя
listTemplFile = os.path.join(pathConfig, "files.txt")
logOutFile = ".logout"
# Файлы котороые не удаляются при очистке домашней директории
skipHomeFile = ["Home","Disks","FTP",logOutFile,configFileDesktop]
# словарь опций сервисов из /var/calculate/remote/calculate.env
optionsInfo = {}
def removeVars(self):
"""Удаление переменных шаблонов
при удалении пакета и выходе из домена"""
self.clVars.Delete("cl_remote_host", "local")
self.clVars.Delete("cl_remote_pw", "local")
self.clVars.Delete("os_remote_auth")
self.clVars.Delete("os_remote_client")
self.clVars.Set("cl_remote_host", "", True)
self.clVars.Set("cl_remote_pw", "", True)
self.clVars.Set("os_remote_auth", "", True)
self.clVars.Set("os_remote_client", "", True)
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 isDomain(self):
"""Находится ли компьютер в домене"""
foundMountRemote = os.path.ismount("/var/calculate/remote")
foundMountHome = os.path.ismount("/home")
remoteHost = self.clVars.Get("cl_remote_host")
if remoteHost and foundMountRemote and foundMountHome:
return True
self.printERROR(_("The computer is not in domain"))
return False
def getUserMountResources(self, userName, homeDir, flagRemoteServer):
"""Получение монтируемых ресурсов для пользователя"""
home = os.path.split(homeDir)[0]
dictResources = {}
names = []
# Pесурс share
name = "share"
dictResources[name] = {"resource":"share",
"path":os.path.join(homeDir,"Disks")}
names.append(name)
# Ресурс шаблонов
name = "profile"
dictResources[name] = {"resource":"unix",
"path":os.path.join(home,"."+userName)}
names.append(name)
# Ресурс - домашняя директория (файлы пользователя на сервере)
name = "home"
dictResources[name] = {"resource":"homes",
"path":os.path.join(homeDir,"Home")}
names.append(name)
if self.getInfoService("ftp", "host"):
# Ресурс ftp
name = "ftp"
dictResources[name] = {"resource":"ftp",
"path":os.path.join(homeDir,"FTP")}
names.append(name)
if flagRemoteServer:
# Ресурс шаблонов на удаленном сервере
name = "remote_profile"
dictResources[name] = {"resource":"unix",
"path":os.path.join(home,"."+userName+"."+"remote")}
names.append(name)
return names, dictResources
def mountSambaRes(self,host,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" %(host, res, path)
else:
# Монтируем директории
mountStr = "mount -t cifs -o user=%s"%(userName)+\
" //%s/%s %s" %(host, res, path)
textLine = self.execProg(mountStr, None, True, {"PASSWD":userPwd})
return textLine
def mountSleepRes(self,host,userName,userPwd,uid,gid,res,path):
"""Монтирует ресурс при неудаче задержка потом повторное монитрование"""
textLine = self.mountSambaRes(host,userName,userPwd,uid,gid,res,path)
if not (textLine is None):
# Проверяем на монтирование директории
if os.path.ismount(path):
textLineUmount = self.umountSleepPath(path)
if not textLineUmount:
return False
i = 0
sleeps = [0.5, 2, 5]
while (i<len(sleeps) and not (textLine is None)):
# Задержка перед следующей попыткой
time.sleep(sleeps[i])
# Монтируем Samba ресурс
textLine = self.mountSambaRes(host,userName,userPwd,uid,
gid,res,path)
if not (textLine is None):
# Проверяем на монтирование директории
if os.path.ismount(path):
textLineUmount = self.umountSleepPath(path)
if not textLineUmount:
return False
i += 1
return textLine
def copyTemplateDir(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 upgradeTemplateClient(self, userName, userHome, pathTemplates):
"""Переносит данные клиента в директорию без точки
например: было /home/.user/.CLD стало /home/.user/CLD
Перед вызовом этого метода обязательно должен быть определен атрибут
объекта self.clVars - объект переменных
"""
# Директория хранения старых шаблонов
home = os.path.split(userHome)[0]
if os.path.exists(pathTemplates):
osLinuxShort = self.clVars.Get("os_linux_shortname")
pathNewTemplate = os.path.join(pathTemplates, osLinuxShort)
pathOldTemplate = os.path.join(pathTemplates, "."+osLinuxShort)
if not os.path.exists(pathNewTemplate) and\
os.path.exists(pathOldTemplate) and\
os.listdir(pathOldTemplate):
# Переносим профиль
if not self.copyTemplateDir(pathOldTemplate,
pathNewTemplate):
return False
if not os.path.exists(pathNewTemplate):
# Создаем директорию для хранения профиля
os.mkdir(pathNewTemplate)
os.chmod(pathNewTemplate, 0700)
if os.path.exists(pathOldTemplate) and\
not os.listdir(pathOldTemplate):
os.rmdir(pathOldTemplate)
return True
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 syncUser(self, userName, userHome, sync, uid, gid, homeTemplate, \
progress=False, host="default"):
"""Синхронизация пользовательских настроек
Перед вызовом этого метода обязательно должен быть определен атрибут
объекта self.clVars - объект переменных
"""
flagError = False
execStr = ""
if sync == "login":
# исключаемые пути при синхронизации
# /.local/share/akonadi/db_data
# хранит базу acanadi
# /.mozilla/firefox/calculate.default/urlclassifier3.sqlite
# хранит БД для firefox
# /.local/share/mime/mime.cache
# отключение ошибочного кэширования изображений
# /.kde4/share/apps/nepomuk/repository/main/data
# база nepomuk
# /.VirtualBox
# содержит данные о виртуальных машинах
if os.path.exists(userHome) and\
os.path.exists(homeTemplate):
execStr = '/usr/bin/rsync --delete-excluded --delete \
--exclude="/.googleearth" --exclude="/.kde4/share/config/phonondevicesrc" \
--exclude="*~" --exclude="/Home" --exclude="/Disks" --exclude="/FTP" \
--exclude="/.local/share/akonadi/db_data" --exclude="/.VirtualBox" \
--exclude="/.mozilla/firefox/calculate.default/urlclassifier3.sqlite" \
--exclude="/.local/share/mime/mime.cache" \
--exclude="/.kde4/share/apps/nepomuk/repository/main/data" \
--exclude="/.logout" \
--exclude="/.Xauthority" \
--exclude="/.thumbnails" \
--exclude="/.mozilla/firefox/*/Cache" \
--filter="P /.googleearth" --filter="P /Home" --filter="P /Disks" \
--filter="P /.local/share/akonadi/db_data" --filter="P /.VirtualBox" \
--filter="P /.mozilla/firefox/calculate.default/urlclassifier3.sqlite" \
--filter="P /.local/share/mime/mime.cache" \
--filter="P /.kde4/share/apps/nepomuk/repository/main/data" \
--filter="P /.logout" \
--filter="P /.Xauthority" \
--filter="P /.thumbnails" \
--filter="P /.mozilla/firefox/*/Cache" \
--filter="P /FTP" -a -x -v -v -v -v %s/ %s/' %(homeTemplate,userHome)
elif sync == "logout":
if os.path.exists(userHome) and os.listdir(userHome) and\
os.path.exists(homeTemplate):
execStr = '/usr/bin/rsync --delete-excluded --delete \
--exclude="/.googleearth" --exclude="/Home" --exclude="/Disks" --exclude="/FTP"\
--exclude="*~" --exclude="/.kde4/cache-*" --exclude="/.kde4/tmp-*" \
--exclude="/.local/share/akonadi/db_data" --exclude="/.VirtualBox" \
--exclude="/.mozilla/firefox/calculate.default/urlclassifier3.sqlite" \
--exclude="/.local/share/mime/mime.cache" \
--exclude="/.Xauthority" \
--exclude="/.kde4/share/apps/nepomuk/repository/main/data" \
--exclude="/.kde4/socket-*" --exclude="/.kde4/share/config/phonondevicesrc" \
--exclude="/.thumbnails" \
--exclude="/.mozilla/firefox/*/Cache" \
-a -x -v -v -v -v %s/ %s/'%(userHome,homeTemplate)
else:
self.printERROR(_("Method syncUser: option sync=%s incorrect")\
%str(sync))
return False
if execStr:
host = "<i>" + host +"</i>"
rsync = RsyncProgressBar(\
_("Receiving file list from %s") % host + " ...",
_("Downloading the user profile from %s") % host \
+ " ...", execStr)
pathConfig = os.path.join(homeTemplate,
self.pathConfig)
# Удаляем предыдущий ini файл
prevIniFile = os.path.join(homeTemplate,".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 = 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 iniParser(configFileName).setVar('rsync',
{'files':rsync.getFilesNum()}):
os.chmod(configFileName, 0600)
os.chown(configFileName,uid,gid)
except:
pass
rsync.close()
if rsync.getExitCode() != 0:
try:
if iniParser(configFileName).setVar(\
'rsync',{'exitcode':rsync.getExitCode()}):
os.chmod(configFileName, 0600)
os.chown(configFileName,uid,gid)
except:
pass
self.printERROR(_("Can not execute rsync") + " " + str(sync) +\
" ...")
flagError = True
else:
if sync == "login":
if not (os.path.exists(userHome)):
self.printERROR(_("Directory %s not exists")%userHome)
else:
self.printERROR(_("Directory %s not exists")%homeTemplate)
elif sync == "logout":
if not (os.path.exists(userHome)):
self.printERROR(_("Directory %s is empty or not exists")\
%userHome)
else:
self.printERROR(_("Directory %s not exists")%homeTemplate)
flagError = True
if flagError:
return False
else:
# Домашняя директория и директория хранения профиля
changeDirs = [userHome, homeTemplate]
for changeDir in changeDirs:
# Получаем права на директорию
mode = getModeFile(changeDir, mode="mode")
# Если права не равны 0700 меняем их
if mode != 0700:
os.chmod(changeDir,0700)
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 removeDir(delFile):
return False
elif stat.S_ISSOCK(os.stat(delFile)[stat.ST_MODE]):
os.remove(delFile)
return True
def syncLoginTemplate(self, host, userName, homeDir, homeTemplate, uid, gid,
progress, flagClearHomeDir=True):
"""Синхронизация профиля пользователя с сервера
в переменной 'cl_remote_host' хост для прогрессбара
"""
home = os.path.split(homeDir)[0]
# Если на текущем сервере в ресурсе unix есть файлы
# то синхронируем настройки
if os.listdir(homeTemplate):
if not self.syncUser(userName, homeDir, "login", uid, gid,\
homeTemplate, progress=progress,
host=host):
return False
else:
if flagClearHomeDir:
# Удаляем ненужные файлы (очищаем домашнюю директорию)
if not self.clearHomeDir(homeDir):
return False
return True
def getDataInConfig(self, section, listVars, objConfig):
"""Читаем переменные listVars из секции section конф. файла"""
varsConfig = {}
for varName in listVars:
varsConfig[varName] = objConfig.getVar(section,varName)
if objConfig.getError():
return False
return varsConfig
def 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 = 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 foundArchFile(self,strCurrentTime,archPathProcess,
archPathSuccess, progress=False,
remoteServer=False):
"""Поиск архива профиля пользователя"""
# Ищем архив профиля
# Задержки при поиске файла архива .process
if progress:
title = _("Packing the archive at the server")
if remoteServer:
title += " " + remoteServer
title += " ..."
progressObj = ProgressBar(title, 0)
progressObj.openDialog(title, 0)
sleepsFindProcess = [0.1, 0.2, 0.5]
# Задержки при проверке размера архива
sleepsArch = [0.5, 1, 2]
lenFP = len(sleepsFindProcess)
lenA = len(sleepsArch)
i = 0
# Ждем появления файла архива
while(not (os.path.exists(archPathProcess) or\
os.path.exists(archPathSuccess)) and i<lenFP):
time.sleep(sleepsFindProcess[i])
i +=1
# Если нет архива применяем rsync синхронизацию
if not (os.path.exists(archPathProcess) or\
os.path.exists(archPathSuccess)):
# Архив не найден rsync схема синхронизации
if progress:
progressObj.shutdownDialog()
return False
# Ожидание создания архива
if os.path.exists(archPathProcess):
i = 0
while(os.path.exists(archPathProcess)):
if os.path.exists(archPathSuccess):
break
if i>=lenA:
# rsync схема синхронизации
if progress:
progressObj.shutdownDialog()
return False
startSize = os.stat(archPathProcess).st_size
time.sleep(sleepsArch[i])
if os.path.exists(archPathSuccess):
break
endSize = os.stat(archPathProcess).st_size
if startSize == endSize:
i += 1
if progress:
progressObj.shutdownDialog()
return True
def fileReader(self, fileName, stdin, progressObj=False):
"""Читает файл блоками в поток"""
fd = os.open(fileName, os.O_RDONLY)
if progressObj:
currSize = 0
# Размер файлового буфера в байтах
buffSize=131072
dataBlock = os.read(fd, buffSize)
while dataBlock:
if progressObj:
currSize += len(dataBlock)
progressObj.setValue(currSize)
stdin.write(dataBlock)
dataBlock = os.read(fd, buffSize)
stdin.close()
os.close(fd)
def unpackTemplate(self, homeDir, archFile, progress=False,\
remoteServer=False):
"""Распаковка архива в домашнюю директорию пользователя"""
# Создаем прогрессбар
if progress:
title = _("Unpacking the archive from server")
if remoteServer:
title += " " + remoteServer
title += " ..."
progressObj = ProgressBar(title)
archiveSize = os.stat(archFile).st_size
progressObj.setMaximum(archiveSize)
execStr = "tar -C '%s' -xzf -" %homeDir
# Выполняем разархивацию
pipe = subprocess.Popen(execStr,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=True,
env=os.environ, shell=True)
# Чтение файла в поток
if progress:
self.fileReader(archFile, pipe.stdin, progressObj)
else:
self.fileReader(archFile, pipe.stdin)
ret = pipe.wait()
pipe.stdout.close()
pipe.stderr.close()
if progress:
progressObj.shutdownDialog()
if ret:
self.printERROR(_("Can not execute %s") %execStr)
self.printERROR(_("Can not unpack %s") %archFile)
return False
return True
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 iniParser(configFileName).setVar(nameSection, varsDict):
os.chmod(configFileName, 0600)
os.chown(configFileName,uid,gid)
except:
return False
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 = open(fileName, "w")
modeFile, uidFile, gidFile = getModeFile(fileName)
if mode != modeFile:
os.chmod(fileName, mode)
if (uidFile, gidFile) != (uid, gid):
os.chown(fileName,uid,gid)
if fileTxt:
FD.write(fileTxt)
FD.close()
return True
def mountUserResAndSync(self, userName, sync=True, progress=False):
"""Монтирование пользовательских ресурсов и синхронизация настроек"""
# Проверяем на root
if not self.isRoot():
return False
# Проверка на повторный вход пользователя
if self.isTwoSessionsUser(userName):
return False
domain = self.clVars.Get("cl_remote_host")
hostAuth = self.clVars.Get("os_remote_auth")
# В случае компьютера вне домена
if not hostAuth or not domain:
self.printSUCCESS(_("To be used local profile."))
return True
# Проверим что компьютер в домене и смонтирован [remote]
connectDomain = self.isDomain()
if not connectDomain:
# Отмонтируем пользовательские ресурсы в случае ошибки
self.umountUserRes()
return False
# Информация о пользователе из LDAP
userLdapInfo = self.ldapDataObj.getUserLdapInfo(userName)
if userLdapInfo:
uid = int(userLdapInfo['uid'])
gid = int(userLdapInfo['uid'])
homeDir = userLdapInfo['home']
else:
self.printERROR(_("Can not found user %s in LDAP")%userName)
self.umountUserRes()
return False
rootPath = self.clVars.Get('cl_root_path')
# Реальный путь к домашней директории
homeDir = os.path.join(rootPath, homeDir[1:])
# Файл хранения настроек пакета
configFileName = os.path.join(homeDir, self.configFileDesktop)
# При отсуствии создаем домашнюю директорию
if not os.path.exists(homeDir):
os.makedirs(homeDir)
os.chown(homeDir,uid,gid)
os.chmod(homeDir,0700)
# записываем в конфигурационный файл статус "в процессе"
self.setVarToConfig("main", {"status_sync":"process"},
configFileName, uid, gid)
# Получаем пароль пользователя из ключей ядра
userPwd = getKey(userName)
if not userPwd:
self.printERROR(_("Not found user password"))
# Отмонтируем пользовательские ресурсы в случае ошибки
self.umountUserRes(homeDir)
return False
# Флаг ошибки
flagError = False
# Имя удаленного сервера
remoteServer = ""
# В случае включения репликации на сервере True
replOn = self.ldapDataObj.isRepl()
if replOn:
osLinuxShort = self.clVars.Get("os_linux_shortname")
remoteServer = self.ldapDataObj.getNameRemoteServer(userName,
osLinuxShort)
# Получаем монтируемые директории
names, dictRes = self.getUserMountResources(userName, homeDir,
remoteServer)
# Путь к профилю пользователя по умолчанию
defaultPath = ""
# Хост пользователя по умолчанию
defaultHost = domain
# Флаг - будет использован инкрементальный архив
flagIncrArch = True
# Ошибка при монтировании удаленного сервера
flagErrorMountRemote = False
# Ошибка при cинхронизации с удаленного сервера
flagErrorSyncRemote = False
# Статус синхронизации
syncStatus = True
osLinuxShort = self.clVars.Get("os_linux_shortname")
# Если профиль на удаленном сервере
if remoteServer and replOn:
# имя файла архива в процессе архивации
archPathProcess = ""
# имя файла архива - после архивации
archPathSuccess = ""
# Создаем инкрементальный архив в случае репликации
prevHost = ""
# Дата профиля на текущем сервере
dateDefaultTemplate = ""
# Текущее время
currTime = str(float(time.time()))
# Создаваемые пути при монтировании
for name in names:
# Пропускаем монтирование директории если нет синхронизации
if not sync and name == "remote_profile":
continue
path = dictRes[name]["path"]
res = dictRes[name]["resource"]
# Создаем пользовательскую директории для профиля
if not os.path.exists(path):
try:
os.mkdir(path)
os.chown(path, uid, gid)
os.chmod(path,0700)
except OSError:
self.printERROR(_("Error creating directory"))
self.printERROR(_("Permission denied: '%s'")%path)
flagError = True
break
#Проверяем на монтирование директории
if os.path.ismount(path):
continue
# Имя хоста для монтирования ресурса
hostConnect = defaultHost
if name == "remote_profile":
hostConnect = remoteServer
# Монтируем Samba ресурс
textLine = self.mountSleepRes(hostConnect, userName, userPwd,
uid, gid, res, path)
if not (textLine is None):
if name == "remote_profile":
flagErrorMountRemote = True
break
else:
self.printERROR(_("Can not mount Samba resource [%s]")\
%res + " ...")
flagError = True
break
# Если нет синхронизации отменяем обработку
if not sync:
continue
if name == "profile" or name == "remote_profile":
# Находим директорию профиля
homeTemplate = os.path.join(path, osLinuxShort)
if not os.path.exists(homeTemplate):
homeTemplate = os.path.join(path, "." + osLinuxShort)
# Примонтирована директория профиля с текущего сервера
if name == "profile":
# Перенос профиля на сервере в директорию без точки
if not self.upgradeTemplateClient(userName, homeDir,
path):
flagError = True
break
fileConfig = os.path.join(homeTemplate,
self.configFileDesktop)
if os.path.exists(fileConfig):
objConfig = iniParser(fileConfig)
data = self.getDataInConfig("main", ["status_sync",
"date"],
objConfig)
if data:
status = data.get("status_sync")
date = data.get("date")
if date and status=="success":
dateDefaultTemplate = date
# Примонтирована директория профиля с удаленного сервера
# и есть дата профиля текущего сервера
if name == "remote_profile" and dateDefaultTemplate:
# Даем команду на создание инкрементального архива проф.
fileConfig = os.path.join(homeTemplate,self.configFileServer)
varsConfig = {"arch_date":dateDefaultTemplate,
"curr_time":currTime}
self.setServerCommand(["pack"], varsConfig, fileConfig)
# Отмонтируем директорию профиля с удаленного сервера
textLine = self.umountSleepPath(path)
if not textLine:
flagError = True
break
pathTemplateCurr = dictRes["profile"]["path"]
homeTemplateCurr = os.path.join(pathTemplateCurr,osLinuxShort)
# Синхронизация профиля с текущего сервера
hostConnect = defaultHost
if not self.syncLoginTemplate(hostConnect, userName,homeDir,
homeTemplateCurr, uid, gid,
progress):
flagError = True
break
# Монтируем директорию профиля с удаленного сервера
hostConnect = remoteServer
textLine = self.mountSleepRes(hostConnect,userName,userPwd,
uid,gid,res,path)
if not (textLine is None):
self.printERROR(_("Can not mount Samba resource [%s]")\
%res + " ...")
flagError = True
break
extSuccess = "gz"
extProcess = "process"
strCurrentTime = currTime.replace(".","_")
archPathTmp = os.path.join(path, "profile.%s.%s.tar"\
%(osLinuxShort, strCurrentTime))
# имя файла архива в процессе архивации
archPathSuccess = "%s.%s"%(archPathTmp,extSuccess)
# имя файла архива - после архивации
archPathProcess = "%s.%s"%(archPathTmp,extProcess)
# Ищем файл архива
if not self.foundArchFile(strCurrentTime, archPathProcess,
archPathSuccess, progress,
remoteServer):
flagIncrArch = False
break
# Если нет архива применяем rsync синхронизацию
if not os.path.exists(archPathSuccess):
flagIncrArch = False
break
else:
# Распаковываем архив в домашнюю директорию
if not self.unpackTemplate(homeDir, archPathSuccess,
progress, remoteServer):
flagError = True
if archPathSuccess:
# Удаление архивного файла
if os.path.exists(archPathSuccess):
# Удаляем файл архива
os.remove(archPathSuccess)
break
# Cканирование домашней директории и получение списка
# файлов
pathListFile = os.path.join(homeTemplate,
self.listTemplFile)
if not self.removeFilesInTemplate(homeDir, pathListFile):
# Отмонтируем пользовательские ресурсы в
# случае ошибки
self.umountUserRes(homeDir)
return False
else:
if name == "remote_profile":
flagIncrArch = False
if archPathProcess or archPathSuccess:
# Удаление архивных файлов
rmFiles = [archPathProcess, archPathSuccess]
for rmFile in rmFiles:
if os.path.exists(rmFile):
# Удаляем файл архива
os.remove(archPathSuccess)
# Если не удалось замонтировать удаленный профиль
if flagErrorMountRemote:
syncStatus = False
# Если не удалось использовать инкрементальный архив
elif flagIncrArch is False:
# Синхронизируем удаленный профиль
pathTemplate = dictRes["remote_profile"]["path"]
homeTemplate = os.path.join(pathTemplate, osLinuxShort)
if not self.upgradeTemplateClient(userName, homeDir,
pathTemplate):
# Отмонтируем пользовательские ресурсы в случае ошибки
self.umountUserRes(homeDir)
return False
# Синхронизация профиля с удаленного сервера
hostConnect = remoteServer
ret = self.syncLoginTemplate(hostConnect, userName, homeDir,
homeTemplate, uid, gid, progress,
False)
if not ret:
flagErrorSyncRemote = True
syncStatus = False
# Если не удалось синхронизировать удаленный синхронизируем
# текущий
homeTemplate = os.path.join(dictRes["profile"]["path"],
osLinuxShort)
# Синхронизация профиля пользователя с текущего сервера
hostConnect = defaultHost
if not self.syncLoginTemplate(hostConnect,userName,homeDir,
homeTemplate,uid,gid,progress):
# Отмонтируем пользовательские ресурсы в случае ошибки
self.umountUserRes(homeDir)
return False
# Отмонтируем директорию профиля пользователя на удаленном сервере
if sync and "remote_profile" in dictRes:
umountPath = dictRes["remote_profile"]["path"]
textLine = self.umountSleepPath(umountPath)
if not textLine:
# Отмонтируем пользовательские ресурсы в случае ошибки
self.umountUserRes(homeDir)
return False
# Удаляем директорию удаленного профиля у клиента
if os.path.exists(umountPath):
os.rmdir(umountPath)
# Если профиль на текущем сервере
elif not remoteServer and replOn or not replOn:
# Создаваемые пути при монтировании
for name in names:
path = dictRes[name]["path"]
res = dictRes[name]["resource"]
# Создаем пользовательскую директории для профиля
if not os.path.exists(path):
try:
os.mkdir(path)
os.chown(path, uid, gid)
os.chmod(path,0700)
except OSError:
self.printERROR(_("Error creating directory"))
self.printERROR(_("Permission denied: '%s'")%path)
flagError = True
break
# Проверяем на монтирование директории
if os.path.ismount(path):
continue
# Имя хоста для монтирования ресурса
hostConnect = defaultHost
textLine = self.mountSleepRes(hostConnect, userName, userPwd,
uid, gid, res, path)
if not (textLine is None):
self.printERROR(_("Can not mount Samba resource [%s]")\
%res + " ...")
flagError = True
break
# Если нет синхронизации отменяем обработку
if not sync:
continue
if name == "profile":
pathTemplate = path
# Перенос профиля на сервере в директорию без точки
if not self.upgradeTemplateClient(userName, homeDir,
pathTemplate):
flagError = True
break
# Директория профиля
homeTemplate = os.path.join(path, osLinuxShort)
# Синхронизация профиля пользователя с текущего сервера
hostConnect = defaultHost
if not self.syncLoginTemplate(hostConnect, userName, homeDir,
homeTemplate, uid, gid,
progress):
# Отмонтируем пользовательские ресурсы в случае ошибки
self.umountUserRes(homeDir)
return False
if flagError:
# Отмонтируем пользовательские ресурсы в случае ошибки
self.umountUserRes(homeDir)
return False
if sync:
logOutFile = os.path.join(homeDir,self.logOutFile)
if syncStatus:
self.setVarToConfig("main", {"status_sync":"success"},
configFileName, uid, gid)
self.createUserFile(logOutFile,"SUCCESS", uid, gid)
else:
self.createUserFile(logOutFile,"ERROR", uid, gid)
self.setVarToConfig("main", {"status_sync":"error"},
configFileName, uid, gid)
self.printWARNING(_("Error in sync with the remote server %s")\
%remoteServer)
self.printSUCCESS(_("Mounted user resource of the domain"))
if sync:
self.printOK(_("Get a user profile from the domain") + " ...")
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 moveHomeDir(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 os.path.split(x)[1].startswith('.') and\
not x.rpartition('.')[2]=='desktop',
map(lambda x: os.path.join(pathDesktop,x),\
os.listdir(pathDesktop)))
movedPathDesk = os.path.join(movedPath, pathDesktop)
filesDir += filesDirDesk
if not filesDir or not os.path.exists("Home"):
# Удаляем пустую папку Moved
if os.path.exists(movedPath) and not os.listdir(movedPath):
os.rmdir(movedPath)
# Удалям ссылку на Moved в домашней директории
if os.path.islink(movedLink) and not os.path.exists(movedPath):
os.unlink(movedLink)
return True
if not os.path.exists(movedPath):
os.mkdir(movedPath)
directFile = os.path.join(movedPath,".directory")
if not os.path.exists(directFile):
txt = "[Desktop Entry]\nIcon=folder-development"
fd = os.open(directFile, os.O_CREAT)
os.close(fd)
FD = open (directFile, "r+")
FD.write(txt)
FD.close()
if not os.path.exists(movedLink):
os.symlink(movedPath, movedLink)
for fd in filesDir:
execStr = "cp -r '%s' '%s'" %(fd, movedPath)
textLine = self.execProg(execStr)
if not (textLine is None):
self.printERROR(_("Can not exec") + " " + str(execStr) +\
" ...")
return False
execStr = "rm -rf '%s'" %fd
textLine = self.execProg(execStr)
if not (textLine is None):
self.printERROR(_("Can not exec") + " " + str(execStr) +\
" ...")
return False
os.chdir(pathProg)
return True
def 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',
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 clearUserKey(self, userName):
"""Очищает пользовательский ключ ядра"""
# Ищем ключ в ядре
if getKey(userName):
# Если нашли очищаем
ret = clearKey(userName)
if ret == 0:
return True
else:
self.printERROR(_("Can not clear kernel key from user %s")\
%userName)
return False
return True
def umountUserResAndSync(self, userName, progress=False, sync=True):
"""Отмонтирование пользовательских ресурсов и синхронизация настроек"""
# Проверяем на root
if not self.isRoot():
return False
domain = self.clVars.Get("cl_remote_host")
hostAuth = self.clVars.Get("os_remote_auth")
# В случае компьютера вне домена
if not hostAuth or not domain:
self.printSUCCESS(_("To be used local profile."))
return True
connectDomain = self.isDomain()
if not connectDomain:
# Отмонтируем пользовательские ресурсы в случае ошибки
self.umountUserRes()
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
# Информация о пользователе из LDAP
userLdapInfo = self.ldapDataObj.getUserLdapInfo(userName)
if userLdapInfo:
uid = int(userLdapInfo['uid'])
gid = int(userLdapInfo['uid'])
homeDir = userLdapInfo['home']
else:
self.printERROR(_("Can not found user %s in LDAP")%userName)
self.umountUserRes()
return False
# Файл хранения настроек пакета
configFileName = os.path.join(homeDir, self.configFileDesktop)
if os.path.exists(homeDir):
self.moveHomeDir(homeDir)
else:
# Отмонтируем пользовательские ресурсы в случае ошибки
self.printERROR(_("Directory %s not found") % homeDir)
self.umountUserRes(homeDir)
return False
# необходима ли синхронизация с локальным сервером
needSync = sync
# проверяем произведен ли корректный вход в систему -
# в этом случае закачиваем профиль с локальной машины на сервер
exitStr = iniParser(configFileName).getVar('main','status_sync')
# проверяем cтатус синхронизации: не содержит ли он "process"
if exitStr == "process" or exitStr == "error":
needSync = False
osLinuxShort = self.clVars.Get("os_linux_shortname")
# Получаем монтируемые директории
names, dictRes = self.getUserMountResources(userName, homeDir, False)
pathUnix = dictRes["profile"]["path"]
homeTemplate = os.path.join(pathUnix, osLinuxShort)
if needSync:
# Синхронизация профиля пользователя на сервер
if not self.syncUser(userName, homeDir, "logout", uid, gid,
homeTemplate):
# Удаляем файлы, мешающие работе dm
self.removeNoiseFiles(homeDir)
# Удаляем приватные файлы
self.removePrivateFiles(homeDir)
# Очищаем ключ в ядре
self.clearUserKey(userName)
# Отмонтируем пользовательские ресурсы в случае ошибки
self.umountUserRes(homeDir)
return False
# Удаляем файлы, мешающие работе dm
self.removeNoiseFiles(homeDir)
# Удаляем приватные файлы
self.removePrivateFiles(homeDir)
# Очищаем ключ в ядре
self.clearUserKey(userName)
# Отмонтируем директории
if not self.umountUserRes(homeDir):
return False
# Удаляем пустые директории
for name in names:
path = dictRes[name]["path"]
if os.path.exists(path) and not os.listdir(path):
try:
os.rmdir(path)
except:
self.printERROR(_("Can not remove dir %s")% path)
return False
if needSync:
self.printSUCCESS(_("Saved a user profile in the domain"))
self.printOK(_("Umounted user resource in domain") + " ...")
return True
def getMountUserPaths(self, homeDir=False):
"""Находит пользовательские примонтированные пути"""
# Имя пользователя
if not homeDir:
userName = self.clVars.Get("ur_login")
try:
homeDir = pwd.getpwnam(userName).pw_dir
except:
homeDir = os.path.join("/home",userName)
dirStart, dirEnd = os.path.split(homeDir)
mountTemplateDir = os.path.join(dirStart, ".%s" %dirEnd)
mountRemoteTemplateDir = os.path.join(dirStart, ".%s.remote" %dirEnd)
return filter(lambda x: x.startswith(homeDir) or\
x.startswith(mountTemplateDir) or\
x.startswith(mountRemoteTemplateDir),
map(lambda x: x.split(" ")[1],\
open("/proc/mounts").readlines()))
def execProg(self, cmdStrProg, inStr=False, retFull=True, envProg={}):
"""Выполняет внешнюю программу
Параметры:
cmdStrProg внешняя программа
inStr данные передаваемые программе на страндартный вход.
Возвращаемые параметры:
строка которую выведет внешняя программа или False в случае ошибки
"""
env_path = {"PATH":getpathenv()}
env = {}
env.update(os.environ.items() + env_path.items() + envProg.items())
retCode,programOut = runOsCommand(cmdStrProg,inStr,retFull,env)
if not retCode:
return programOut
return False
def umountSleepPath(self, path):
"""Отмонтирует путь при неудаче задержка потом повтор"""
# Задержки при отмонтированиии директории
sleeps = [0.5, 2, 5]
# Проверяем на монтирование директорию
if os.path.ismount(path):
textLine = self.execProg("umount %s"%path)
if textLine is False:
i = 0
flagError = False
while (i<len(sleeps) and textLine is False):
# Задержка перед следующей попыткой
time.sleep(sleeps[i])
# Отмонтируем Samba ресурс
if os.path.ismount(path):
textLine = self.execProg("umount %s"%path)
else:
textLine = None
break
i += 1
if textLine != None:
self.printERROR(_("Can not unmount path %s")%path + " ...")
return False
return True
def umountUserRes(self, homeDir=False):
"""Отмонтируем пользовательские директории если они есть"""
umountPaths = self.getMountUserPaths(homeDir)
ret = True
for umountPath in umountPaths:
if not self.umountSleepPath(umountPath):
ret = False
break
return ret
def installClient(self):
"""Наложение шаблонов на систему при инсталяции"""
# Проверяем на root
if not self.isRoot():
return False
# Действие инсталяция
self.clVars.Set("cl_pass_action", "install", True)
if not self.applyTemplatesFromSystem():
self.printERROR(_("Can not apply install templates"))
return False
self.printOK(_("Added use of scripts this package for window \
manager") + " ...")
return True
def getDefaultRunlevelDaemons(self):
"""Получаем всех демонов в default уровне"""
execStr = "rc-update show"
textLine = self.execProg(execStr, None, False)
if textLine == False:
self.printERROR(_("ERROR") + ": " + execStr)
return False
else:
splLines = filter(lambda x: len(x)==2 and "default" in x[1],\
map(lambda x: x.split("|"),textLine))
splLines = map(lambda x: x[0].strip(), splLines)
return splLines
def uninstallClient(self):
"""Наложение шаблонов на систему при деинсталяции"""
# Проверяем на root
if not self.isRoot():
return False
# Действие деинсталяция
self.clVars.Set("cl_pass_action", "uninstall", True)
# Устанавливаем шаг выход из домена
self.clVars.Set("cl_pass_step", "undomain", True)
# Удаляем переменные из env файлов
self.removeVars()
if not self.applyTemplatesFromSystem():
self.printERROR(_("Can not apply uninstall templates"))
return False
if not self.delDaemonAutostart("client"):
return False
self.printOK(_("Apply uninstall templates"))
return True
def delDaemonAutostart(self, daemon):
"""Удаляет демона из автозагрузки"""
defaultDaemons = self.getDefaultRunlevelDaemons()
if defaultDaemons is False:
return False
if daemon in defaultDaemons:
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
return True
def delDomain(self):
"""выводим из домена"""
# Проверяем на root
if not self.isRoot():
return False
pathRemote = "/var/calculate/remote"
pathHome = "/home"
foundMountRemote = os.path.ismount(pathRemote)
foundMountHome = os.path.ismount(pathHome)
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)
if not textLineUmount:
return False
# Удаляем переменные из env файлов
self.removeVars()
# Устанавливаем шаг выход из домена
self.clVars.Set("cl_pass_step", "undomain", True)
if not self.applyTemplatesFromSystem():
self.printERROR(_("Can not apply undomain templates"))
return False
self.printSUCCESS(_("Apply undomain templates"))
if not self.delDaemonAutostart("client"):
return False
self.printOK(_("Computer removed from domain %s")%domain + " ...")
return True
def getUserPassword(self, pwDialog=False):
"""Получить пароль у пользователя
pwDialog - приглашение ввода пароля
"""
if not pwDialog:
pwDialog = _("Password")
userPwd = getpass.getpass(pwDialog+":")
return userPwd
def addDaemonAutostart(self, daemon):
"""Прописывает демона в автозагрузку"""
defaultDaemons = self.getDefaultRunlevelDaemons()
if defaultDaemons is False:
return False
if daemon in defaultDaemons:
return True
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 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 getInfoService(self, service, option):
"""Получить параметр сервиса из env"""
if not self.optionsInfo:
# файл /var/calculate/remote/server.env
envFile = self.clVars.Get("cl_env_server_path")
optInfo = self.clVars.GetRemoteInfo(envFile)
if optInfo is False:
return False
if optInfo:
self.optionsInfo = optInfo
value = ''
if service in self.optionsInfo and option in self.optionsInfo[service]:
value = self.optionsInfo[service][option]
return value
def addDomain(self, domainName):
"""Вводим в домен"""
# Проверяем на root
if not self.isRoot():
return False
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 = os.path.ismount("/var/calculate/remote")
foundMountHome = os.path.ismount("/home")
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, True, "local")
self.clVars.Write("cl_remote_pw", userPwd, True, "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) + " " +\
" ...")
#servDn = self.clVars.Get("ld_services_dn")
servDn = self.getInfoService("ldap", "services_dn")
#unixDn = self.clVars.Get("ld_unix_dn")
unixDn = self.getInfoService("unix", "dn")
# bindDn = self.clVars.Get("ld_bind_dn")
bindDn = self.getInfoService("unix", "bind_dn")
#bindPw = self.clVars.Get("ld_bind_pw")
bindPw = self.getInfoService("unix", "bind_pw")
# запишем их
if not (servDn and unixDn and bindDn and bindPw):
self.printERROR(_("Not found server info") + ": " +\
_("services DN or unix DN or bind DN or bind password"))
return False
# Наложим шаблоны - install, domain
# Действие - инсталяция
self.clVars.Set("cl_pass_action", "install", True)
# Шаг - ввод в домен
self.clVars.Set("cl_pass_step", "domain", True)
# Доменная авторизация
self.clVars.Set("os_remote_auth", domain)
if not self.applyTemplatesFromSystem():
self.printERROR(_("Can not apply install or domain templates"))
return False
# Рестартуем dbus
self.restartDBus()
if not self.addDaemonAutostart("client"):
return False
# Записываем переменную
self.clVars.Write("os_remote_auth", domain, True)
# Записываем текущую версию программы
currentVersion = self.clVars.Get("cl_ver")
self.clVars.Write("os_remote_client", currentVersion, True)
self.printOK(_("Computer added to domain %s")%domain + " ...")
return True
def relevanceTemplates(self, hostAuth):
"""Определяем актуальность наложенных шаблонов
в зависимости от версии программы
Перед запуском обязательно должен быть определен объект переменных
self.clVars
Если актуальны - True, если нет False
"""
# '' или имя хоста
if hostAuth != self.clVars.Get("os_remote_auth"):
return False
clTempl = template(self.clVars)
# Текущая версия программы
currentVersion = self.clVars.Get("cl_ver")
# Версия программы которая ранее работала с шаблонами
previousVersion = self.clVars.Get("os_remote_client")
cVersion,pVersion = clTempl._convertVers(currentVersion,previousVersion)
# Если версии программ не равны то шаблоны не актуальные
if cVersion != pVersion:
return False
return True
def applyRelevanceTemplates(self, hostAuth=""):
"""Накладывает релевантные шаблоны
Перед запуском обязательно должен быть определен объект переменных
self.clVars
"""
if not self.relevanceTemplates(hostAuth):
if hostAuth:
# Устанавливаем шаг вход в домен
self.clVars.Set("cl_pass_step","domain",True)
else:
# Устанавливаем шаг выход из домена
self.clVars.Set("cl_pass_step","undomain",True)
self.clVars.Set("os_remote_auth", hostAuth)
# Наложим шаблоны
dirsAndFiles = self.applyTemplatesFromSystem()
if not dirsAndFiles:
if hostAuth:
self.printERROR(_("Can not apply domain templates"))
else:
self.printERROR(_("Can not apply undomain templates"))
return False
if hostAuth:
self.printOK(_("Set templates of network mode"))
currentVersion = self.clVars.Get("cl_ver")
self.clVars.Write("os_remote_client", currentVersion, True)
self.clVars.Write("os_remote_auth", hostAuth, True)
else:
self.printOK(_("Set templates of local mode"))
self.clVars.Delete("os_remote_auth")
self.clVars.Delete("os_remote_client")
return True
def mountRemote(self):
"""Монтирование remote и домашней директории если компьютер в домене
а так-же ввод в домен если найдено имя хоста и пароль для подключения
"""
# Проверяем на root
if not self.isRoot():
return False
domain = self.clVars.Get("cl_remote_host")
if domain:
foundMountRemote = os.path.ismount("/var/calculate/remote")
foundMountHome = os.pathismount("/home")
else:
self.printWARNING(_("This computer is not in domain"))
# Если шаблоны не актуальны накладываем новую версию шаблонов
if not self.applyRelevanceTemplates():
return False
return True
pathHome = "/var/calculate/client-home"
if foundMountRemote:
self.printWARNING(_("Samba resource [%s] is mount")%"remote" + \
" ...")
if foundMountHome:
self.printWARNING(str(pathHome) + " " +_("is mount")+
" ...")
if foundMountHome and foundMountRemote:
# Накладываем сетевые шаблоны
if domain:
self.clVars.flIniFile()
if not self.applyRelevanceTemplates(domain):
return False
return True
flagLocalTemplate = False
if not foundMountRemote:
pathRemote = "/var/calculate/remote"
pwdRemote = self.clVars.Get("cl_remote_pw")
if not (domain and pwdRemote):
self.printERROR(_("Not found variable")+\
": cl_remote_pw ...")
return False
if not os.path.exists(pathRemote):
os.makedirs(pathRemote)
mountStr = "mount -t cifs -o user=client //%s/remote %s"\
%(domain,pathRemote)
textLine = self.execProg(mountStr, None, True, {"PASSWD":pwdRemote})
if not (textLine is None):
self.printWARNING(_("Can not mount Samba resource [%s]")%\
"remote" + " ...")
flagLocalTemplate = True
# Если шаблоны не актуальны накладываем новую версию шаблонов
if not self.applyRelevanceTemplates():
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 flagLocalTemplate:
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.applyRelevanceTemplates(domain):
return False
self.restartDBus()
return True