Исправления

Исправлено шифрование
Исправлено отключение пользовательских ресурсов
Добавлены переменные ur_mount_dirs, ur_password,
cl_desktop_update_profile_set, cl_desktop_force_setup_set
Добавлена опция для принудительной настройки профиля пользователя
master3.3
Mike khiretskiy 11 years ago
parent 89353f34a0
commit 93f08d9d8a

@ -28,7 +28,8 @@ from datavars import DataVarsDesktop, DataVars, __version__,__app__
from calculate.lib.cl_template import (Template, ProgressTemplate,
TemplatesError,templateFunction,iniParser)
from calculate.lib.utils.files import (runOsCommand, isMount,process,
getRunCommands,STDOUT,childMounts)
getRunCommands,STDOUT,childMounts,getLoopFromPath,
getMdRaidDevices,listDirectory,removeDir)
from calculate.lib.utils.common import (getpathenv,appendProgramToEnvFile,
removeProgramToEnvFile,mountEcryptfs,
CommonError, isBootstrapDataOnly)
@ -41,6 +42,7 @@ from itertools import ifilter
import tarfile
import tempfile
import shutil
from itertools import count
class DesktopError(Exception):
@ -58,25 +60,55 @@ class Desktop:
self.clTempl = None
self.clVars = None
def createCryptDir(self,userName,uid,gud,userDir):
def createCryptDir(self,userName,uid,gid,userDir,recreateOnError=False):
"""
Создать шифрование домашней директории, или подключить существующую
userName,uid,gid,userDir: параметры пользовательской учётной записи
recreateOnError: пересоздать профиль при ошбиках (используется при доменной
ученой записи, так пользователь при этом ничего не теряет - профиль на сервере)
"""
userPwd = getKey(userName)
error = ""
# проверить наличие пароля в ключах ядра
if not userPwd or userPwd == "XXXXXXXX":
raise DesktopError(_("User password not found"))
ecryptfsPath = path.join('/home/.ecryptfs',userName)
# если шифрование уже используется
if path.exists(ecryptfsPath):
for d in (".ecryptfs",".Private"):
source,target = path.join(ecryptfsPath,d),path.join(userDir,d)
if not path.lexists(target):
os.symlink(source,target)
# попытаться подключить шифрованные данные
try:
if not mountEcryptfs(userName,userPwd,userDir):
raise DesktopError(_("Failed to mount ecrypted data"))
error = _("Failed to mount ecrypted data")
except CommonError as e:
raise DesktopError(_("Failed to mount ecrypted data")+": \"%s\""%str(e))
else:
error = _("Failed to mount ecrypted data")+": \"%s\""%str(e)
# если при подключении произошли ошибки
if error:
# заархивировать текущий профиль и удалить его
if recreateOnError:
self.printWARNING(_("Recreating the encryption data"))
if self.getMountUserPaths(userDir):
raise DesktopError(_("Failed to use directory encryption"))
for source in (userDir,ecryptfsPath):
if path.exists(source):
if listDirectory(source):
target = source+".bak"
newtarget = target
if path.exists(target):
removeDir(target)
os.rename(source,newtarget)
else:
os.rmdir(source)
self.createUserDir(userName,uid,gid,userDir)
# ошибка создания шифрования
else:
raise DesktopError(error)
# если нет шифрованных данных
if not path.exists(ecryptfsPath):
tf = None
try:
# если профиль содержит только данные от бутстрапа core
@ -106,6 +138,8 @@ class Desktop:
with tarfile.open(fileobj=tf,mode='r:') as tarf:
tarf.extractall(userDir)
except Exception as e:
# в случае ошибки сохраняем архив (с данными bootstrap)
# из памяти в файловую систему
if tf:
tf.seek(0)
bakArchName = path.join(userDir,".calculate.tar.bz2")
@ -116,6 +150,7 @@ class Desktop:
finally:
if tf:
tf.close()
return True
def createUserDir(self, userName, uid, gid, userDir, mode=0700):
"""
@ -130,89 +165,15 @@ class Desktop:
else:
raise DesktopError(_("Path %s exists") %userDir)
def applyTemplatesFromUser(self):
"""Apply templates for user"""
if self.clTempl:
self.closeClTemplate()
templates_locate = self.clVars.Get('cl_templates_locate')
self.clVars.Set("cl_template_path",
map(lambda x:x[1],
filter(lambda x:x[0] in templates_locate,
zip(self.clVars.Get('cl_template_location'),
self.clVars.Get('cl_template_path')))),
True)
self.clTempl = ProgressTemplate(self.setProgress,self.clVars,
cltObj=False,
printERROR=self.printERROR,
printWARNING=self.printWARNING,
askConfirm=self.askConfirm,
printSUCCESS=self.printSUCCESS,
userProfile=True)
dirsFiles = self.clTempl.applyTemplates()
if self.clTempl.getError():
self.printERROR(self.clTempl.getError().strip())
return False
else:
return dirsFiles
def closeClTemplate(self):
if self.clTempl:
if self.clTempl.cltObj:
self.clTempl.cltObj.closeFiles()
self.clTempl.closeFiles()
self.clTempl = None
def umountUserRes(self, error):
"""
Umount user directory
"""
self.closeClTemplate()
if error and self.homeDir:
umountPaths = self.getMountUserPaths(self.homeDir)
ret = True
for umountPath in umountPaths:
if not self.umountSleepPath(umountPath):
ret = False
break
return ret
#!!!!post_action=umountUserRes)
def createHome(self, userName,):
def umountUserRes(self, *umountPaths):
"""
Creating user profile and userdir
Отключить пользовательские ресурсы
"""
self.homeDir = self.clVars.Get('ur_home_path')
rootPath = self.clVars.Get('cl_root_path')
# real path to home dir
self.homeDir = path.join(rootPath, self.homeDir[1:])
if not path.exists(self.homeDir):
self.startTask(_("Creating the home directory for %s")%self.homeDir)
self.createUserDir(userName,uid,gid,self.homeDir)
self.endTask()
if (self.clVars.Get('ur_home_crypt_set') == 'on' and
self.clVars.Get('install.cl_autologin') != userName):
self.createCryptDir(userName,uid,gid,self.homeDir)
domainUser = self.clVars.Get('ur_domain_set') == 'on'
lastTimestamp = templateFunction.getLastElog()
iniEnv = path.join(self.homeDir,'.calculate/ini.env')
userIni = iniParser(iniEnv)
userTimestamp = userIni.getVar('main','elog').encode('utf-8')
if (domainUser or not path.exists(iniEnv) or
userTimestamp != lastTimestamp):
# action - "user profile configuration"
self.clVars.Set("cl_action", "desktop", True)
# apply user profiles
self.startTask(_("Setting up the user profile"),progress=True)
dirsAndFiles = self.applyTemplatesFromUser()
self.endTask()
if not dirsAndFiles:
raise DesktopError(_("Failed to apply user profile templates"))
self.printSUCCESS(_("User account %s is configured")%userName + " ...")
if umountPaths and type(umountPaths[0]) == list:
umountPaths = umountPaths[0]
for umountPath in umountPaths:
if not self.umountSleepPath(umountPath):
return False
return True
def getMountUserPaths(self, homeDir=False):
@ -247,9 +208,21 @@ class Desktop:
def umountSleepPath(self, rpath):
"""
Unmount path, sleep by failed and repeat
Отмонтировать указанный путь, а также отключить используемые
в этом пути loop устройства и raid
"""
# check for mount
loops = getLoopFromPath(rpath)
if loops:
setLoops = set(map(lambda x:x.partition('/dev/')[2],loops))
mdInfo = getMdRaidDevices()
for k,v in mdInfo.items():
if setLoops & set(v):
self.umountSleepPath('/dev/%s'%k)
process('/sbin/mdadm','--stop','/dev/%s'%k).success()
for loop in loops:
self.umountSleepPath(loop)
process('/sbin/losetup','-d',loop).success()
if isMount(rpath):
for waittime in [0,0.5,1,2]:
time.sleep(waittime)
@ -264,6 +237,7 @@ class Desktop:
or not isMount(rpath):
if not isMount(rpath):
return True
self.execProg("umount -l %s"%rpath)
else:
if isMount(rpath):
self.printERROR(_("Failed to unmount directory %s")%rpath)

@ -15,9 +15,10 @@
# limitations under the License.
import sys
from calculate.core.server.func import Action
from os import path
from calculate.core.server.func import Action,Tasks
from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate
from calculate.lib.utils.files import FilesError
from calculate.lib.utils.files import FilesError, isMount
from calculate.desktop.desktop import DesktopError
from calculate.lib.cl_template import TemplatesError
@ -53,20 +54,34 @@ class ClDesktopAction(Action):
native_error = (FilesError,DesktopError,TemplatesError)
successMessage = __("User account {ur_login} is configured")
#failedMessage = __("Failed to update system")
#interruptMessage = __("Configuration manually interrupted")
failedMessage = __("Failed to configure account")
interruptMessage = __("Configuration manually interrupted")
# список задач для действия
tasks = [
{'name':'create_home',
'message':__("Creating the home directory for {ur_home_path}"),
'method':'Desktop.createUserDir(ur_uid,ur_gid,ur_home_path)',
'message':__("Creating the home directory for {ur_login}"),
'method':'Desktop.createUserDir(ur_login,ur_uid,ur_gid,ur_home_path)',
'condition':lambda dv:not path.exists(dv.Get('ur_home_path'))
},
{'name':'ecryptfs',
'message':__("Mounting encrypted data"),
'method':'Desktop.createCryptDir(ur_login,ur_uid,ur_gid,'
'ur_home_path,False)',
'condition':lambda Get:(not isMount(Get('ur_home_path')) and \
Get('ur_home_crypt_set') == 'on' and
Get('install.cl_autologin') != Get('ur_login'))
},
{'name':'user_profile',
'message':__("Setting up the user profile"),
'method':'Install.applyTemplates(install.cl_source,False,'\
'method':'Desktop.applyTemplates(None,False,'\
'False,None)',
'condition':lambda dv:not path.exists(dv.Get('ur_home_path'))
'condition':lambda Get: Get('cl_desktop_force_setup_set') == 'on' or \
Get('cl_desktop_update_profile_set') == 'on'
},
{'name':'umount_userres',
'message': _("Unmouning user resources"),
'method':'Desktop.umountUserRes(ur_mount_dirs)',
'condition': lambda dv:dv.Get('ur_mount_dirs'),
'depend': (Tasks.failed(),)}
]

@ -7,7 +7,9 @@ from calculate.lib.datavars import Variable,VariableError,ReadonlyVariable, \
ReadonlyTableVariable,FieldValue
from calculate.lib.variables.user import VariableUrLogin
from calculate.lib.utils.files import readLinesFile,process
from calculate.desktop._cl_keys import getKey
from itertools import *
from calculate.lib.cl_template import (templateFunction,iniParser)
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_desktop3',sys.modules[__name__])
@ -26,6 +28,8 @@ class VariableUrDomainSet(ReadonlyVariable):
"""
Flag for determining domain user or local
"""
type = "bool"
def getUserDataInFile(self, login, filePasswd):
return filter(lambda x: x[0]==login,
map(lambda x: x.strip().split(':'),
@ -241,3 +245,62 @@ class VariableClDesktopLogin(VariableUrLogin):
def get(self):
return ""
class VariableUrMountDirs(ReadonlyVariable):
"""
Примонтированные директории в профиле пользователя
"""
type = "list"
def get(self):
homeDir = self.Get("ur_home_path")
if not homeDir:
return []
dirStart, dirEnd = path.split(homeDir)
mountProfileDir = path.join(dirStart, ".%s" %dirEnd)
mountRemoteProfileDir = path.join(dirStart, ".%s.remote" %dirEnd)
return filter(lambda x:x != homeDir,
filter(lambda x: (x.startswith(homeDir) or
x.startswith(mountProfileDir) or
x.startswith(mountRemoteProfileDir)),
map(lambda x: x.split(" ")[1],
readLinesFile('/proc/mounts'))))
class VariableUrPassword(ReadonlyVariable):
"""
Пароль пользователя, получаемый из ключей ядра
"""
def get(self):
return getKey(self.Get('ur_login')) or ""
class VariableClDesktopUpdateProfileSet(Variable):
"""
Нужно ли выполнять обновление профиля пользователя на основании
обновлении пакетов
"""
type = "bool"
def get(self):
lastTimestamp = templateFunction.getLastElog()
iniEnv = path.join(self.Get('ur_home_path'),'.calculate/ini.env')
userIni = iniParser(iniEnv)
userTimestamp = userIni.getVar('main','elog').encode('utf-8')
if self.Get('ur_domain_set') == 'on' or \
not path.exists(iniEnv) or userTimestamp != lastTimestamp:
return 'on'
else:
return 'off'
class VariableClDesktopForceSetupSet(Variable):
"""
Принудительно выполнить обновление пользовательского профиля
"""
type = "bool"
opt = ["--force-setup"]
metavalue = "ON/OFF"
value = "off"
def init(self):
self.label = _("Force setup")
self.help = _("force setup")

@ -1,3 +1,5 @@
#-*- coding: utf-8 -*-
# Copyright 2012 Calculate Ltd. http://www.calculate-linux.org
#
# Licensed under the Apache License, Version 2.0 (the "License");
@ -87,11 +89,13 @@ class Wsdl(WsdlBase):
'native_error':(VariableError,DataVarsError,
DesktopError),
# значения по умолчанию для переменных этого метода
'setvars':{'cl_action!':'desktop'},
'setvars':{'cl_action!':'desktop',
'cl_protect_use_set!':'off'},
# описание груп (список лямбда функций)
'groups':[
lambda group:group(_("Configure user"),
normal=('ur_login',),
expert=('cl_verbose_set','cl_templates_locate'),
expert=('cl_desktop_force_setup_set','cl_verbose_set',
'cl_templates_locate'),
next_label=_("Configure"))]},
]

Loading…
Cancel
Save