From 76171566a9522dea3b617db705e72caf099775de Mon Sep 17 00:00:00 2001 From: Mike Khiretskiy Date: Tue, 20 Oct 2015 14:15:09 +0300 Subject: [PATCH] Refactoring --- bin/cl-client-resume-remount | 59 ++- pym/client/client.py | 648 +++++++++++++++-------------- pym/client/client_cache.py | 245 ++++++----- pym/client/datavars.py | 11 +- pym/client/utils/cl_client.py | 237 +++++------ pym/client/utils/cl_client_sync.py | 542 ++++++++++++------------ pym/client/utils/cl_passwd.py | 21 +- pym/client/variables/action.py | 27 +- pym/client/variables/client.py | 310 ++++++++------ pym/client/wsdl_client.py | 12 +- 10 files changed, 1110 insertions(+), 1002 deletions(-) diff --git a/bin/cl-client-resume-remount b/bin/cl-client-resume-remount index 0efe516..74895ad 100644 --- a/bin/cl-client-resume-remount +++ b/bin/cl-client-resume-remount @@ -1,7 +1,7 @@ #!/usr/bin/env python -#-*- coding: utf-8 -*- +# -*- coding: utf-8 -*- -# Copyright 2013-2014 Calculate Ltd. http://www.calculate-linux.org +# Copyright 2013-2015 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. @@ -25,11 +25,11 @@ import os from os import path import dbus.mainloop.glib from calculate.lib.datavars import DataVars, VariableError -from calculate.lib.utils.files import isMount, getRunCommands from calculate.client.client import Client from argparse import ArgumentParser from time import sleep + class ResourceRemounter: """ Object contains one method for handle 'Resuming' dbus signal. @@ -37,30 +37,27 @@ class ResourceRemounter: 'handle_resuming' method checks and remounts user remote resources. Also the object refreshes NSS-cache. """ - def __init__(self,dv): + nscd_refresh = "/usr/sbin/nscd-refresh" + + def __init__(self, dv): self.dv = dv self.dv.defaultModule = 'client' self.client = Client() self.client.clVars = dv self.check_server(True) - def check_server(self,refresh_nscd=False): + def check_server(self, refresh_nscd=False): """ Check the available of domain server and refresh nscd cache """ if self.client.checkDomainServer( - self.dv.Get('cl_remote_host'), - self.dv.Get('os_net_domain')): - try: - if refresh_nscd and path.exists(self.nscd_refresh): - os.system(self.nscd_refresh) - except: - pass + self.dv.Get('cl_remote_host'), + self.dv.Get('os_net_domain')): + if refresh_nscd and path.exists(self.nscd_refresh): + os.system(self.nscd_refresh) return True return False - nscd_refresh = "/usr/sbin/nscd-refresh" - def remount_remote(self): """ Remount remote resource of the domain @@ -69,7 +66,7 @@ class ResourceRemounter: self.client.mountRemoteRes(self.dv.Get('cl_remote_pw'), self.dv.Get('cl_client_remote_path'), self.dv.Get('cl_remote_host')) - except: + except Exception: pass def remount_user_resources(self): @@ -78,21 +75,21 @@ class ResourceRemounter: """ try: self.client.mountUserDomainRes(self.dv.Get('ur_login'), - self.dv.Get('desktop.ur_password'), - int(self.dv.Get('ur_uid')), - int(self.dv.Get('ur_gid')), - "unix","share","homes","ftp") - except: + self.dv.Get('desktop.ur_password'), + int(self.dv.Get('ur_uid')), + int(self.dv.Get('ur_gid')), + "unix", "share", "homes", "ftp") + except Exception: pass - def handle_resuming(self,statename): - print("Restoring remote mounts for user %s"%self.dv.Get('ur_login')) + def handle_resuming(self, statename): + print("Restoring remote mounts for user %s" % self.dv.Get('ur_login')) # waiting for the domain - for wait in [1,2,5,10]: + for wait in [1, 2, 5, 10]: try: if self.check_server(True): break - except: + except Exception: pass sleep(wait) # check and remount remote resources @@ -103,7 +100,7 @@ class ResourceRemounter: def main(argv): # processing the user argument argp = ArgumentParser(add_help=True) - argp.add_argument("user",help="tracked user",metavar="USER") + argp.add_argument("user", help="tracked user", metavar="USER") namespace = argp.parse_args(argv[1:]) dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) @@ -114,17 +111,18 @@ def main(argv): dv = DataVars() dv.importData() dv.flIniFile() - dv.Set('ur_login',namespace.user) + dv.Set('ur_login', namespace.user) if dv.Get('desktop.ur_domain_set') == 'off': - print("%s isn't a domain user"%namespace.user) + print("%s isn't a domain user" % namespace.user) sys.exit(0) except VariableError as e: - sys.stderr.write(str(e)+'\n') + sys.stderr.write(str(e) + '\n') sys.exit(1) rm = ResourceRemounter(dv) - bus.add_signal_receiver(rm.handle_resuming,dbus_interface="org.freedesktop.UPower", - signal_name = "NotifyResume") + bus.add_signal_receiver(rm.handle_resuming, + dbus_interface="org.freedesktop.UPower", + signal_name="NotifyResume") loop = gobject.MainLoop() context = loop.get_context() while True: @@ -132,5 +130,6 @@ def main(argv): context.iteration(1) sleep(1) + if __name__ == '__main__': main(sys.argv) diff --git a/pym/client/client.py b/pym/client/client.py index dc69e62..c4a090c 100644 --- a/pym/client/client.py +++ b/pym/client/client.py @@ -1,4 +1,4 @@ -#-*- coding: utf-8 -*- +# -*- coding: utf-8 -*- # Copyright 2010-2013 Calculate Ltd. http://www.calculate-linux.org # @@ -18,29 +18,22 @@ import os import stat import re import sys -import pwd import subprocess import ldap import time -import types import getpass from os import path -from datavars import DataVarsClient, DataVars, __version__,__app__ - -from calculate.lib.cl_template import (Template, iniParser, TemplatesError, - ProgressTemplate) +from calculate.lib.cl_ini_parser import iniParser from calculate.lib.cl_print import color_print -from calculate.lib.cl_ldap import ldapUser -from calculate.lib.utils.ip import Pinger, isOpenPort, IPError +from calculate.lib.utils.ip import Pinger, IPError from calculate.lib.utils.files import (getModeFile, removeDir, - isMount, readFile, pathJoin, tarLinks, - listDirectory,process,find,STDOUT, - sambaPasswordCheck,checkUtils) -from calculate.lib.utils.common import (getpathenv, appendProgramToEnvFile, - removeProgramToEnvFile, cmpVersion) + isMount, pathJoin, tarLinks, + listDirectory, process, find, STDOUT, + sambaPasswordCheck, checkUtils) +from calculate.lib.utils.common import cmpVersion from calculate.desktop._cl_keys import getKey, clearKey from calculate.lib.convertenv import convertEnv from calculate.lib.encrypt import encrypt @@ -48,16 +41,19 @@ from client_cache import userCache from shutil import copy2 from socket import gethostbyname import tarfile -from collections import OrderedDict from calculate.desktop.desktop import Desktop -from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate -setLocalTranslate('cl_client3',sys.modules[__name__]) +from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate + +_ = lambda x: x +setLocalTranslate('cl_client3', sys.modules[__name__]) __ = getLazyLocalTranslate(_) + class ClientError(Exception): pass + class RsyncProgressBar: """ Rsync with using setProgress @@ -70,8 +66,8 @@ class RsyncProgressBar: maximum = 1 copyStarting = False - def __init__(self, title, secondtitle, rsyncstr, parent,maximum=1, - rsyncver="3.0.9"): + def __init__(self, title, secondtitle, rsyncstr, parent, maximum=1, + rsyncver="3.0.9"): self.title = title self.secondtitle = secondtitle self.maximum = maximum @@ -116,7 +112,7 @@ class RsyncProgressBar: """ Run rsync without progressbar """ - self.pipe = subprocess.Popen(self.rsyncstr+self.extraopts, + self.pipe = subprocess.Popen(self.rsyncstr + self.extraopts, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, @@ -136,8 +132,8 @@ class RsyncProgressBar: """ Run rsync with progressbar """ - self.parent.startTask(self.title,progress=True) - self.pipe = subprocess.Popen(self.rsyncstr+self.extraopts, + self.parent.startTask(self.title, progress=True) + self.pipe = subprocess.Popen(self.rsyncstr + self.extraopts, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, @@ -156,13 +152,13 @@ class RsyncProgressBar: if q: if not self.copyStarting: self.parent.endTask() - self.parent.startTask(self.secondtitle,progress=True) - #self.parent.setProgress(0) + self.parent.startTask(self.secondtitle, progress=True) + # self.parent.setProgress(0) self.copyStarting = True self.value = int(q.groups()[0]) if self.maximum: - newvalue = int(100*self.value / self.maximum) - newvalue = min(newvalue,99) + newvalue = int(100 * self.value / self.maximum) + newvalue = min(newvalue, 99) if newvalue > oldpercent: self.parent.setProgress(newvalue) oldpercent = newvalue @@ -171,6 +167,7 @@ class RsyncProgressBar: def close(self): self.parent.endTask() + class commandServer(color_print): """Server command object""" @@ -184,20 +181,20 @@ class commandServer(color_print): if not uid is None and not gid is None: os.chown(pathConfig, uid, gid) objConfig = iniParser(fileConfig) - varsRun = {"run":"on"} + varsRun = {"run": "on"} varsRun.update(varsCommand) - if not objConfig.setVar(["command"]+command, varsRun): - raise ClientError(_("Failed to write variables in file %s")\ - %fileConfig) + if not objConfig.setVar(["command"] + command, varsRun): + raise ClientError(_("Failed to write variables in file %s") \ + % fileConfig) if not uid is None and not gid is None: os.chown(fileConfig, uid, gid) return True def checkUserPwdLDAP(self, server, userDN, password): """Проверка пароля Unix пользователя на сервере""" - ldapInit = ldap.initialize("ldap://%s"%server) + ldapInit = ldap.initialize("ldap://%s" % server) errMessage = "" - try: + try: ldapInit.bind_s(userDN, password) except ldap.INVALID_CREDENTIALS: errMessage = _("Wrong password") @@ -217,7 +214,6 @@ class commandServer(color_print): стандартного ввода (stdin) pwDialog - структура для вывода приглашения в режиме диалога """ - userPwd = "" if optStdIn and options.has_key(optStdIn): pwdA = sys.stdin.readline().rstrip() pwdB = sys.stdin.readline().rstrip() @@ -225,17 +221,18 @@ class commandServer(color_print): if not pwDialog: pwDialog = [_("New password"), _("Retype the 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 + pwdA = getpass.getpass(pwDialog[0] + _(":")) + pwdB = getpass.getpass(pwDialog[1] + _(":")) + else: + return "" + if not pwdA or not (pwdA == pwdB): + self.printERROR(_("ERROR") + _(": ") + \ + _("passwords do not match")) + return False + userPwd = pwdA return userPwd + class Client(commandServer, encrypt, Desktop): """ Клиентский модуль работы с доменом @@ -253,7 +250,7 @@ class Client(commandServer, encrypt, Desktop): listTemplFile = os.path.join(pathConfig, "files.txt") # files which not cleaning from user home directory - skipHomeFile = ["Home","Disks","Share","FTP",configFileDesktop] + skipHomeFile = ["Home", "Disks", "Share", "FTP", configFileDesktop] # option dict of services from /var/calculate/remote/server.env optionsInfo = {} @@ -263,7 +260,7 @@ class Client(commandServer, encrypt, Desktop): # private user files privateFiles = [configFileServer] # private user directories - privateDirs = [] + privateDirs = [] def removeVars(self): """ @@ -278,36 +275,39 @@ class Client(commandServer, encrypt, Desktop): self.clVars.Set("os_remote_auth", "", True) return True - def mountSambaRes(self,host,userName,userPwd,res,rpath,uid=None,gid=None): + def mountSambaRes(self, host, userName, userPwd, res, rpath, uid=None, + gid=None): """ Подключить samba ресурс """ mountCmd = checkUtils('/bin/mount') - if cmpVersion(self.clVars.Get('cl_cifs_ver'),"2.05") < 0: - nomapposix="" + if cmpVersion(self.clVars.Get('cl_cifs_ver'), "2.05") < 0: + nomapposix = "" else: - nomapposix=",nomapposix" + nomapposix = ",nomapposix" if not uid is None: # mount by uid - p = process(mountCmd,"-t","cifs","-o", - "cache=loose,user=%s,uid=%d,gid=%d,noperm%s"%(userName,uid,gid,nomapposix), - "//%s/%s"%(host,res),rpath, - envdict={"PASSWD":userPwd},stderr=STDOUT) + p = process(mountCmd, "-t", "cifs", "-o", + "cache=loose,user=%s,uid=%d,gid=%d,noperm%s" % ( + userName, uid, gid, nomapposix), + "//%s/%s" % (host, res), rpath, + envdict={"PASSWD": userPwd}, stderr=STDOUT) return p.success() else: - p = process(mountCmd,"-t","cifs","-o", - "cache=loose,user=%s%s"%(userName,nomapposix), - "//%s/%s"%(host,res),rpath, - envdict={"PASSWD":userPwd},stderr=STDOUT) + p = process(mountCmd, "-t", "cifs", "-o", + "cache=loose,user=%s%s" % (userName, nomapposix), + "//%s/%s" % (host, res), rpath, + envdict={"PASSWD": userPwd}, stderr=STDOUT) return p.success() - def mountSleepRes(self,host,userName,userPwd,res,rpath,uid=None,gid=None): + def mountSleepRes(self, host, userName, userPwd, res, rpath, uid=None, + gid=None): """ Подключить пользовательский ресурс """ - for waittime in [0.5,2,5]: - if not self.mountSambaRes(host,userName,userPwd,res,rpath, - uid,gid): + for waittime in [0.5, 2, 5]: + if not self.mountSambaRes(host, userName, userPwd, res, rpath, + uid, gid): # check on mount path if isMount(rpath): if not self.umountSleepPath(rpath): @@ -319,75 +319,78 @@ class Client(commandServer, encrypt, Desktop): return False def syncUser(self, uid, gid, userHome, sync, remoteProfile, - host="default",skipList=[]): + host="default", skipList=()): """ Синхронизация профиля пользователя """ - flagError = False execStr = "" skipPaths = self.clVars.Get("cl_sync_skip_path") if not skipPaths: self.printERROR( - _("Variable 'cl_sync_skip_path' empty")%userHome) + _("Variable 'cl_sync_skip_path' empty") % userHome) return False deletePaths = self.clVars.Get("cl_sync_del_path") if not deletePaths: deletePaths = [] - excludePaths = " ".join(map(lambda x: '--exclude="/%s"'\ - %x.replace('"',"").replace("'",""), - skipPaths + deletePaths + skipList)) + excludePaths = " ".join(map( + lambda x: '--exclude="/%s"' % x.replace('"', "").replace( + "'", ""), + skipPaths + deletePaths + skipList)) if sync == "login": - if os.path.exists(userHome) and\ - os.path.exists(remoteProfile): - filterPath = " ".join(map(lambda x: '--filter="P /%s"'\ - %x.replace('"',"").replace("'",""), - skipPaths)) - execStr = '/usr/bin/rsync --delete-excluded --delete %s %s '\ - '-rlptgo -x -v -v -v %s/ %s/' \ - %(excludePaths, filterPath, remoteProfile, userHome) + if os.path.exists(userHome) and \ + os.path.exists(remoteProfile): + filterPath = " ".join(map( + lambda x: '--filter="P /%s"' % x.replace( + '"', "").replace("'", ""), + skipPaths)) + execStr = ('/usr/bin/rsync --delete-excluded --delete %s %s ' + '-rlptgo -x -v -v -v %s/ %s/' + % (excludePaths, filterPath, + remoteProfile, userHome)) elif sync == "logout": - if os.path.exists(userHome) and os.listdir(userHome) and\ - os.path.exists(remoteProfile): - execStr = '/usr/bin/rsync --delete-excluded --delete %s \ --rlpt -x -v -v -v %s/ %s/'%(excludePaths, userHome, remoteProfile) + if os.path.exists(userHome) and os.listdir(userHome) and \ + os.path.exists(remoteProfile): + execStr = ('/usr/bin/rsync --delete-excluded --delete %s ' + '-rlpt -x -v -v -v %s/ %s/' % ( + excludePaths, userHome, remoteProfile)) else: raise ClientError( - _("Method syncUser: wrong option sync=%s")%str(sync)) + _("Method syncUser: wrong option sync=%s") % str(sync)) if execStr: - host = "" + host +"" + host = "" + host + "" if sync == "login": - rsync = RsyncProgressBar(\ - _("Fetching the file list from %s") % host, - _("Fetching the user profile from %s") % host, - execStr,self, rsyncver=self.clVars.Get('cl_rsync_ver')) + rsync = RsyncProgressBar( + _("Fetching the file list from %s") % host, + _("Fetching the user profile from %s") % host, + execStr, self, rsyncver=self.clVars.Get('cl_rsync_ver')) else: - rsync = RsyncProgressBar(\ - _("Sending the file list to %s") % host, - _("Uploading the user profile to %s") % host, - execStr,self, rsyncver=self.clVars.Get('cl_rsync_ver')) + rsync = RsyncProgressBar( + _("Sending the file list to %s") % host, + _("Uploading the user profile to %s") % host, + execStr, self, rsyncver=self.clVars.Get('cl_rsync_ver')) pathConfig = os.path.join(remoteProfile, self.pathConfig) # remove old ini file - prevIniFile = os.path.join(remoteProfile,".calculate.ini") + prevIniFile = os.path.join(remoteProfile, ".calculate.ini") if os.path.exists(prevIniFile): os.remove(prevIniFile) # create home directory if not os.path.exists(pathConfig): - self.createUserDirectory(pathConfig,uid,gid) + self.createUserDirectory(pathConfig, uid, gid) numfiles = 0 configFileName = os.path.join(remoteProfile, self.configFileDesktop) if sync == "login": # get rsync files try: - numfiles = \ - iniParser(configFileName).getVar('rsync','files') + numfiles = iniParser( + configFileName).getVar('rsync', 'files') if numfiles is False: if os.path.exists(configFileName): os.remove(configFileName) numfiles = 0 else: numfiles = int(numfiles) - except: + except Exception: numfiles = 0 rsync.maximum = numfiles if sync == "login": @@ -395,43 +398,43 @@ class Client(commandServer, encrypt, Desktop): if sync == "logout": rsync.run() try: - if iniParser(configFileName).setVar('rsync', - {'files':rsync.getFilesNum()}): + if iniParser(configFileName).setVar( + 'rsync', {'files': rsync.getFilesNum()}): os.chmod(configFileName, 0600) - os.chown(configFileName,uid,gid) - except: + os.chown(configFileName, uid, gid) + except Exception: pass rsync.close() try: - if iniParser(configFileName).setVar(\ - 'rsync',{'exitcode':rsync.getExitCode()}): + if iniParser(configFileName).setVar( + 'rsync', {'exitcode': rsync.getExitCode()}): os.chmod(configFileName, 0600) - os.chown(configFileName,uid,gid) - except: + os.chown(configFileName, uid, gid) + except Exception: pass if rsync.getExitCode() != 0: self.printERROR(rsync.getErrMessage()) self.printERROR(_("Failed to execute rsync") + " " + \ - str(sync)) + str(sync)) return False # change permissions changeDirs = [userHome, remoteProfile] - for changeDir in filter(path.exists,changeDirs): + for changeDir in filter(path.exists, changeDirs): # get directory permissions mode = getModeFile(changeDir, mode="mode") # if permission wrong( not 0700) then change it if mode != 0700: - os.chmod(changeDir,0700) + os.chmod(changeDir, 0700) return True def clearHomeDir(self, homeDir): """ Очистить домашнюю директорию """ - rmFiles = list(set(os.listdir(homeDir))-\ - set(self.skipHomeFile)) + rmFiles = list(set(os.listdir(homeDir)) - \ + set(self.skipHomeFile)) for rmFile in rmFiles: - delFile = os.path.join(homeDir,rmFile) + delFile = os.path.join(homeDir, rmFile) if os.path.islink(delFile): os.unlink(delFile) elif os.path.isfile(delFile): @@ -444,7 +447,7 @@ class Client(commandServer, encrypt, Desktop): self.printSUCCESS(_("Cleaning the local user profile")) return True - def syncLoginProfile(self,host,uid,gid,homeDir,resourceName, + def syncLoginProfile(self, host, uid, gid, homeDir, resourceName, profileName, clearHomeDir=True): """ Получить профиль пользователя из домена @@ -452,10 +455,10 @@ class Client(commandServer, encrypt, Desktop): homeProfile = path.join( self.clVars.Select('cl_client_user_mount_path', where='cl_client_user_mount_name', - eq=resourceName,limit=1), + eq=resourceName, limit=1), profileName) # if currect server has any files then sync it - if any(not x in ('.calculate') for x in listDirectory(homeProfile)): + if any(x not in ('.calculate',) for x in listDirectory(homeProfile)): if not self.syncUser(uid, gid, homeDir, "login", homeProfile, host=host): return False @@ -467,27 +470,27 @@ class Client(commandServer, encrypt, Desktop): return False return True - def syncLogoutProfile(self,host,uid,gid,homeDir,resourceName, - profileName,skipList): + def syncLogoutProfile(self, host, uid, gid, homeDir, resourceName, + profileName, skipList): """ Закачать профиль пользователя в домен """ homeProfile = path.join( self.clVars.Select('cl_client_user_mount_path', where='cl_client_user_mount_name', - eq=resourceName,limit=1), + eq=resourceName, limit=1), profileName) # if currect server has any files then sync it if listDirectory(homeDir): if not path.exists(homeProfile): - self.createUserDirectory(homeProfile,uid,gid) + self.createUserDirectory(homeProfile, uid, gid) if not self.syncUser(uid, gid, homeDir, "logout", - homeProfile, host=host,skipList=skipList): + homeProfile, host=host, skipList=skipList): return False return True - def strftime(self,timeobj,dateformat="%Y-%m-%d %H:%M:%S"): - return time.strftime(dateformat,timeobj) + def strftime(self, timeobj, dateformat="%Y-%m-%d %H:%M:%S"): + return time.strftime(dateformat, timeobj) def packRemote(self, resourceName, localTime, currentTime, profileName, uid, gid): @@ -495,20 +498,21 @@ class Client(commandServer, encrypt, Desktop): Запаковать удаленный профиль """ remoteProfilePath = path.join( - self.clVars.Select('cl_client_user_mount_path', - where='cl_client_user_mount_name', eq=resourceName, - limit=1), profileName) + self.clVars.Select('cl_client_user_mount_path', + where='cl_client_user_mount_name', + eq=resourceName, + limit=1), profileName) fileServer = path.join(remoteProfilePath, - Client.configFileServer) + Client.configFileServer) if not localTime: return False - varsConfig = {"arch_date":self.strftime(localTime), - "curr_time":currentTime} + varsConfig = {"arch_date": self.strftime(localTime), + "curr_time": currentTime} - self.setServerCommand(["pack"],varsConfig,fileServer) + self.setServerCommand(["pack"], varsConfig, fileServer) fileDesktop = path.join(remoteProfilePath, - Client.configFileDesktop) - self.setVarToConfig(uid, gid, "main", {"status_sync":"success"}, + Client.configFileDesktop) + self.setVarToConfig(uid, gid, "main", {"status_sync": "success"}, fileDesktop) return self.umountRemoteUserRes(False, resourceName) @@ -516,32 +520,34 @@ class Client(commandServer, encrypt, Desktop): """ Ожидание архива профиля от домена """ - archPathSuccess,archPathProcess = \ - self._getArchNames(packTime,profileName,resourceName) - for sleeptime in [0.1,0.2,0.5]: + arch_fn_success, arch_fn_process = self._getArchNames( + packTime, profileName, resourceName) + + def arch_exists(): + return any(os.path.exists(x) for x in (arch_fn_process, + arch_fn_success)) + + for sleeptime in [0.1, 0.2, 0.5]: # archive in packing process found - if os.path.exists(archPathProcess) or \ - os.path.exists(archPathSuccess): + if arch_exists(): break time.sleep(sleeptime) else: return False # wait finish packing - if path.exists(archPathProcess) or \ - path.exists(archPathSuccess): - while path.exists(archPathProcess) or \ - path.exists(archPathSuccess): - for waittime in [0.5,1,2]: - if path.exists(archPathSuccess): + if arch_exists(): + while arch_exists(): + for waittime in [0.5, 1, 2]: + if path.exists(arch_fn_success): return True try: - startSize = os.stat(archPathProcess).st_size + startSize = os.stat(arch_fn_process).st_size time.sleep(waittime) - if startSize != os.stat(archPathProcess).st_size: + if startSize != os.stat(arch_fn_process).st_size: break - except OSError as e: - if path.exists(archPathSuccess): + except OSError: + if path.exists(arch_fn_success): return True else: return False @@ -551,6 +557,7 @@ class Client(commandServer, encrypt, Desktop): """ Распаковать архив с профилем """ + def fileReader(fileName, stdin, maxSize): """ Прочитать файл по блокам @@ -559,20 +566,20 @@ class Client(commandServer, encrypt, Desktop): fd = os.open(fileName, os.O_RDONLY) currSize = 0 # default buffer size - buffSize=131072 + buffSize = 131072 dataBlock = os.read(fd, buffSize) while dataBlock: currSize += len(dataBlock) - self.setProgress(currSize*100/maxSize) + self.setProgress(currSize * 100 / maxSize) stdin.write(dataBlock) dataBlock = os.read(fd, buffSize) stdin.close() os.close(fd) - archFile,drop = self._getArchNames(packTime,profileName,resourceName) + archFile, drop = self._getArchNames(packTime, profileName, resourceName) archiveSize = os.stat(archFile).st_size - #os.system('tar tf %s'%archFile) - execStr = "tar -C '%s' -xzf -" %homeDir + # os.system('tar tf %s'%archFile) + execStr = "tar -C '%s' -xzf -" % homeDir # запустить процесс распаковки pipe = subprocess.Popen(execStr, stdin=subprocess.PIPE, @@ -580,64 +587,67 @@ class Client(commandServer, encrypt, Desktop): stderr=subprocess.PIPE, close_fds=True, env=os.environ, shell=True) - # прочитать в конвеер - fileReader(archFile, pipe.stdin, archiveSize) - self.endTask() - ret = pipe.wait() - pipe.stdout.close() - pipe.stderr.close() + try: + # прочитать в конвеер + fileReader(archFile, pipe.stdin, archiveSize) + self.endTask() + finally: + ret = pipe.wait() + pipe.stdout.close() + pipe.stderr.close() if ret: return False removedFileList = path.join( - self.clVars.Select('cl_client_user_mount_path', - where='cl_client_user_mount_name', - eq=resourceName,limit=1),profileName, - self.listTemplFile) - return self.removeFilesInProfile(homeDir,removedFileList) + self.clVars.Select('cl_client_user_mount_path', + where='cl_client_user_mount_name', + eq=resourceName, limit=1), profileName, + self.listTemplFile) + return self.removeFilesInProfile(homeDir, removedFileList) def cleanArchs(self, packTime, profileName, resourceName): """ Удалить архивы использованные для синхронизации пользовательского профиля """ - for rmFile in filter(lambda x:x and path.exists(x), - self._getArchNames(packTime,profileName,resourceName)): + for rmFile in filter(lambda x: x and path.exists(x), + self._getArchNames(packTime, profileName, + resourceName)): os.remove(rmFile) return True - def _getArchNames(self,packTime,profileName,resourceName): + def _getArchNames(self, packTime, profileName, resourceName): """ Получить имена файлов архивов по времени, профилю и ресурсу """ remoteProfile = self.clVars.Select('cl_client_user_mount_path', - where='cl_client_user_mount_name', - eq=resourceName,limit=1) + where='cl_client_user_mount_name', + eq=resourceName, limit=1) extSuccess = "gz" extProcess = "process" - packTime = packTime.replace(".","_") + packTime = packTime.replace(".", "_") archPathTmp = os.path.join(remoteProfile, "profile.%s.%s.tar" - %(profileName, packTime)) + % (profileName, packTime)) # result archive file name - archPathSuccess = "%s.%s"%(archPathTmp,extSuccess) + archPathSuccess = "%s.%s" % (archPathTmp, extSuccess) # archive in pack process - archPathProcess = "%s.%s"%(archPathTmp,extProcess) - return archPathSuccess,archPathProcess + archPathProcess = "%s.%s" % (archPathTmp, extProcess) + return archPathSuccess, archPathProcess def setVarToConfig(self, uid, gid, nameSection, varsDict, configFileName): """Записывает переменную в файл конфигурации""" # Создаем директорию для конфигурационных файлов pathConfig = os.path.split(configFileName)[0] if not os.path.exists(pathConfig): - self.createUserDirectory(pathConfig,uid,gid) + self.createUserDirectory(pathConfig, uid, gid) try: if iniParser(configFileName).setVar(nameSection, varsDict): os.chmod(configFileName, 0600) - os.chown(configFileName,uid,gid) - except: + os.chown(configFileName, uid, gid) + except Exception: return False return True - def createUserDirectory(self,userdir,uid,gid): + def createUserDirectory(self, userdir, uid, gid): """ Создать директорию с правами пользователя """ @@ -645,71 +655,69 @@ class Client(commandServer, encrypt, Desktop): try: os.mkdir(userdir) os.chown(userdir, uid, gid) - os.chmod(userdir,0700) + os.chmod(userdir, 0700) except OSError: - raise ClientError(_("Failed to create the directory")+". "+ - _("Permission denied: '%s'")%userdir) + raise ClientError(_("Failed to create the directory") + ". " + + _("Permission denied: '%s'") % userdir) return True - def mountUserDomainRes(self,userName,userPwd,uid,gid,*resources): + def mountUserDomainRes(self, userName, userPwd, uid, gid, *resources): """ Mount all local samba resource """ - res = True - for rpath,res,host in \ - self.clVars.Select(['cl_client_user_mount_path', - 'cl_client_user_mount_resource', - 'cl_client_user_mount_host'], - where='cl_client_user_mount_name', - _in=resources): + for rpath, res, host in \ + self.clVars.Select(['cl_client_user_mount_path', + 'cl_client_user_mount_resource', + 'cl_client_user_mount_host'], + where='cl_client_user_mount_name', + _in=resources): if not rpath: continue - self.createUserDirectory(rpath,uid,gid) + self.createUserDirectory(rpath, uid, gid) if isMount(rpath): continue else: if not self.mountSleepRes(host, userName, userPwd, - res, rpath,uid,gid): + res, rpath, uid, gid): raise ClientError( - _("Failed to mount the Samba volume [%s]")%res) + _("Failed to mount the Samba volume [%s]") % res) else: return True - def setSyncStatus(self,userDir,uid,gid,status): + def setSyncStatus(self, userDir, uid, gid, status): """ Установить статус синхронизации """ # сохранение текущего статуса перед изменением self.clVars.Get('cl_client_sync_status') - fileDesktop = path.join(userDir,Client.configFileDesktop) + fileDesktop = path.join(userDir, Client.configFileDesktop) return self.setVarToConfig(uid, gid, "main", - {"status_sync":status}, fileDesktop) + {"status_sync": status}, fileDesktop) - def tarSymLinks(self,uid,gid,userHome,delPath,skipPath): + def tarSymLinks(self, uid, gid, userHome, delPath, skipPath): """ Создать tar архив с симлинками """ - linkArch = pathJoin(userHome,".calculate/links.tar.bz2") - symList = [] + linkArch = pathJoin(userHome, ".calculate/links.tar.bz2") try: - tarLinks(userHome,linkArch, skip=delPath+skipPath) + tarLinks(userHome, linkArch, skip=delPath + skipPath) if path.exists(linkArch): - os.chown(linkArch,uid,gid) - except Exception as e: + os.chown(linkArch, uid, gid) + except Exception: return False return True - def unpackLinks(self,userHome): + def unpackLinks(self, userHome): """ Распаковать архив с симлинками """ - linksArch = path.join(userHome,".calculate/links.tar.bz2") + linksArch = path.join(userHome, ".calculate/links.tar.bz2") try: if os.path.exists(linksArch): tf = tarfile.open(linksArch) tf.extractall(userHome) tf.close() - except Exception as e: + except Exception: return False return True @@ -720,21 +728,20 @@ class Client(commandServer, encrypt, Desktop): """ desktopDir = "Desktop" resourcePath = self.clVars.Select('cl_client_user_mount_path', - where='cl_client_user_mount_name', eq=resourceName, - limit=1) + where='cl_client_user_mount_name', + eq=resourceName, + limit=1) if not isMount(resourcePath): - raise ClientError(_("Unable to mount %s")%resourcePath) + raise ClientError(_("Unable to mount %s") % resourcePath) movedPath = path.join(resourcePath, movedDir) - movedLink = path.join(userHome,movedDir) - dirs = [] - files = [] + movedLink = path.join(userHome, movedDir) if not skipPaths: - skipPaths = ['Disks','Share','Home','Moved','FTP','Desktop'] + skipPaths = ['Disks', 'Share', 'Home', 'Moved', 'FTP', 'Desktop'] filesAndDir = filter(lambda x: not ( - path.islink(x) or - x[len(userHome)+1:].startswith('.') or - x[len(userHome)+1:] in skipPaths), - listDirectory(userHome,fullPath=True)) + path.islink(x) or + x[len(userHome) + 1:].startswith('.') or + x[len(userHome) + 1:] in skipPaths), + listDirectory(userHome, fullPath=True)) filesDir = [] for fd in filesAndDir: if os.path.islink(fd): @@ -742,14 +749,14 @@ class Client(commandServer, encrypt, Desktop): else: filesDir.append(fd) # find files in Desktop - pathDesktop = path.join(userHome,desktopDir) + pathDesktop = path.join(userHome, desktopDir) filesDirDesk = filter(lambda x: (not path.islink(x) and - not path.split(x)[1].startswith('.') and - not x.rpartition('.')[2]=='desktop'), - listDirectory(pathDesktop,fullPath=True)) - movedPathDesk = os.path.join(movedPath, desktopDir) + not path.split(x)[1].startswith( + '.') and + not x.rpartition('.')[2] == 'desktop'), + listDirectory(pathDesktop, fullPath=True)) filesDir += filesDirDesk - if not filesDir or not path.exists(movedPath): + if not filesDir or not path.exists(resourcePath): # remove empty Moved folder if path.exists(movedPath) and not listDirectory(movedPath): os.rmdir(movedPath) @@ -759,20 +766,20 @@ class Client(commandServer, encrypt, Desktop): return True if not path.exists(movedPath): os.mkdir(movedPath) - directFile = path.join(movedPath,".directory") + directFile = path.join(movedPath, ".directory") if not path.exists(directFile): - with open(directFile,'w') as f: + with open(directFile, 'w') as f: f.write("[Desktop Entry]\nIcon=folder-development") if not path.exists(movedLink): - os.symlink(movedPath[len(userHome)+1:], movedLink) - cpCmd, rmCmd = checkUtils('/bin/cp','/bin/rm') + os.symlink(movedPath[len(userHome) + 1:], movedLink) + cpCmd, rmCmd = checkUtils('/bin/cp', '/bin/rm') for fd in filesDir: - if process(cpCmd,'-xr',fd,movedPath).failed(): + if process(cpCmd, '-xr', fd, movedPath).failed(): self.printERROR(_("Failed to copy {ffrom} to {fto}") - .format(ffrom=fd,fto=movedPath)) + .format(ffrom=fd, fto=movedPath)) return False - if process(rmCmd,'-rf','--one-file-system',fd).failed(): - self.printERROR(_("Failed to remove "%fd)) + if process(rmCmd, '-rf', '--one-file-system', fd).failed(): + self.printERROR(_("Failed to remove " % fd)) return False return True @@ -793,13 +800,14 @@ class Client(commandServer, encrypt, Desktop): """ privateFiles = [] for privateHomeDir in self.privateDirs: - privateDir = os.path.join(userHome,privateHomeDir) + privateDir = os.path.join(userHome, privateHomeDir) if os.path.isdir(privateDir): # .ssh files relative user home directory - privateFiles += map(lambda x:os.path.join(privateHomeDir,x), - filter(lambda x:\ - os.path.isfile(os.path.join(privateDir,x)), - os.listdir(privateDir))) + privateFiles += map(lambda x: os.path.join(privateHomeDir, x), + filter(lambda x: \ + os.path.isfile( + os.path.join(privateDir, x)), + os.listdir(privateDir))) return self.privateFiles + privateFiles def removePrivateFiles(self, userHome): @@ -826,14 +834,15 @@ class Client(commandServer, encrypt, Desktop): if not os.path.exists(dstPath): listElPath = [] for el in filter(lambda x: x, - dstPath.partition(userHomeDir)[2].split("/")): + dstPath.partition(userHomeDir)[2].split( + "/")): listElPath.append(el) joinPath = "/".join(listElPath) dPath = os.path.join(userHomeDir, joinPath) if not os.path.exists(dPath): sPath = os.path.join(serverProfileDir, joinPath) sMode, sUid, sGid = getModeFile(sPath) - os.mkdir(dPath,sMode) + os.mkdir(dPath, sMode) os.chown(dPath, sUid, sGid) copy2(src, dst) sUid, sGid = getModeFile(src, mode="owner") @@ -844,9 +853,9 @@ class Client(commandServer, encrypt, Desktop): """ Generation file list in user home directory, exclude mount dirs """ - lHomeDir = len(homeDir)+1 - return map(lambda x:x[lHomeDir:], - find(homeDir,onefilesystem=True)) + lHomeDir = len(homeDir) + 1 + return map(lambda x: x[lHomeDir:], + find(homeDir, onefilesystem=True)) def removeFilesInProfile(self, homeDir, pathListFile): """ @@ -855,9 +864,9 @@ class Client(commandServer, encrypt, Desktop): # read file list from config try: filesProfileTxt = open(pathListFile).read() - except: + except IOError: return False - listFilesProfile = filter(lambda x: x.strip(), + listFilesProfile = filter(lambda x: x.strip(), filesProfileTxt.split("\n")) filesProfile = set(listFilesProfile) # get files in home directory @@ -866,9 +875,8 @@ class Client(commandServer, encrypt, Desktop): return False filesHome = set(listFilesHome) filesRemove = list(filesHome - filesProfile) - rmPath = "" try: - for rmFile in sorted(filesRemove,reverse=True): + for rmFile in sorted(filesRemove, reverse=True): rmPath = os.path.join(homeDir, rmFile) if path.ismount(rmPath): continue @@ -880,29 +888,30 @@ class Client(commandServer, encrypt, Desktop): os.rmdir(rmPath) else: os.remove(rmPath) - except Exception as e: + except Exception: return False return True def getRunCommandsWithEnv(self): """List run program""" + def getCmd(procNum): - cmdLineFile = '/proc/%s/cmdline'%procNum - environFile = '/proc/%s/environ'%procNum + cmdLineFile = '/proc/%s/cmdline' % procNum + environFile = '/proc/%s/environ' % procNum try: if os.path.exists(cmdLineFile) and \ - os.path.exists(environFile): - return (open(cmdLineFile,'r').read().strip(), - open(environFile,'r').read().strip()) - except: + os.path.exists(environFile): + return (open(cmdLineFile, 'r').read().strip(), + open(environFile, 'r').read().strip()) + except (OSError, IOError): pass - return ("","") - if not os.access('/proc',os.R_OK): + return "", "" + + if not os.access('/proc', os.R_OK): return [] return map(getCmd, - filter(lambda x:x.isdigit(), - os.listdir('/proc'))) - + filter(lambda x: x.isdigit(), + os.listdir('/proc'))) def clearUserKey(self, userName): """ @@ -910,46 +919,48 @@ class Client(commandServer, encrypt, Desktop): """ # find user key in kernel and check on relogout if getKey(userName) and not \ - filter(lambda x:"xdm/xdm\x00--login" in x[0] and \ - ("USER=%s"%userName) in x[1],self.getRunCommandsWithEnv()): + filter(lambda x: "xdm/xdm\x00--login" in x[0] and + ("USER=%s" % userName) in x[1], + self.getRunCommandsWithEnv()): # clean ret = clearKey(userName) if ret == 0: return True else: - self.printERROR(_("Failed to clear the kernel key for user %s")\ - %userName) + self.printERROR(_("Failed to clear the kernel key for user %s") \ + % userName) return False return True - def setLogoutDate(self,homeDir,uid,gid): + def setLogoutDate(self, homeDir, uid, gid): """ Установить дату выхода из сеанса """ - configFileName = path.join(homeDir,self.configFileDesktop) + configFileName = path.join(homeDir, self.configFileDesktop) currentDateStr = self.strftime(time.localtime()) return self.setVarToConfig(uid, gid, "main", - {"date_logout":currentDateStr}, - configFileName) + {"date_logout": currentDateStr}, + configFileName) - def umountRemoteUserRes(self,removeEmpty,*resourceNames): + def umountRemoteUserRes(self, removeEmpty, *resourceNames): """ Отключить пользовательский ресурс """ retRes = True for resourceName in resourceNames: resourcePath = self.clVars.Select('cl_client_user_mount_path', - where='cl_client_user_mount_name', eq=resourceName, - limit=1) + where='cl_client_user_mount_name', + eq=resourceName, + limit=1) if resourcePath: result = self.umountSleepPath(resourcePath) retRes &= result if (result and removeEmpty and path.exists(resourcePath) and - not listDirectory(resourcePath)): + not listDirectory(resourcePath)): os.rmdir(resourcePath) return retRes - def umountUserRes(self,umountPaths): + def umountUserRes(self, umountPaths): """ Отключить пользовательские ресурсы """ @@ -957,7 +968,7 @@ class Client(commandServer, encrypt, Desktop): if not self.umountSleepPath(umountPath): return False self.umountRemoteUserRes(True, - *self.clVars.Get('cl_client_user_mount_name')) + *self.clVars.Get('cl_client_user_mount_name')) return True def getDefaultRunlevelDaemons(self): @@ -965,16 +976,17 @@ class Client(commandServer, encrypt, Desktop): Получить все службы из default уровня загрузки """ rcUpdateCmd = checkUtils("/sbin/rc-update") - p = process(rcUpdateCmd,"show") + p = process(rcUpdateCmd, "show") if p.success(): # получить список названии служб default уровня - return map(lambda x:x[0].strip(), - # [\s*<название_службы>\s*,\s*default\s*] - filter(lambda x:len(x)>1 and "default" in x[1], - # [\s*<название_службы>\s*,\s*уровень запуска\s*] - map(lambda x:x.split('|'), - # \s*<название_службы>\s*|\s*<уроверь запуска>?\s* - p.readlines()))) + return map(lambda x: x[0].strip(), + # [\s*<название_службы>\s*,\s*default\s*] + filter(lambda x: len(x) > 1 and "default" in x[1], + # [\s*<название_службы>\s*,\s*уровень запуска\s*] + map(lambda x: x.split('|'), + # \s*<название_службы>\s*| + # \s*<уроверь запуска>?\s* + p.readlines()))) else: raise ClientError(_("ERROR") + _(": ") + p.read()) @@ -982,10 +994,10 @@ class Client(commandServer, encrypt, Desktop): """ Удалить службу из автозапуска """ - rcUpdateCmd = checkUtils('/sbin/rc-update') + rcUpdateCmd = checkUtils('/sbin/rc-update') defaultDaemons = self.getDefaultRunlevelDaemons() if daemon in defaultDaemons: - p = process(rcUpdateCmd,'del',daemon,'default') + p = process(rcUpdateCmd, 'del', daemon, 'default') if p.success(): return True else: @@ -998,10 +1010,10 @@ class Client(commandServer, encrypt, Desktop): """ Добавить службу в автозагрузку """ - rcUpdateCmd = checkUtils('/sbin/rc-update') + rcUpdateCmd = checkUtils('/sbin/rc-update') if daemon in self.getDefaultRunlevelDaemons(): return True - p = process(rcUpdateCmd,'add',daemon,'default') + p = process(rcUpdateCmd, 'add', daemon, 'default') if p.success(): return True else: @@ -1014,7 +1026,7 @@ class Client(commandServer, encrypt, Desktop): Получить параметр севирса из удаленного env """ if not envFile: - if self.convObj == None: + if self.convObj is None: # file /var/calculate/remote/server.env envFile = self.clVars.Get("cl_env_server_path") if os.access(envFile, os.R_OK): @@ -1034,10 +1046,10 @@ class Client(commandServer, encrypt, Desktop): self.optionsInfo = optInfo value = '' if service in self.optionsInfo and option in self.optionsInfo[service]: - value = self.optionsInfo[service][option] + value = self.optionsInfo[service][option] return value - def checkDomainServer(self,domainName,netDomain): + def checkDomainServer(self, domainName, netDomain): """ Проверить указанный адрес на то, что он может быть доменом """ @@ -1046,53 +1058,54 @@ class Client(commandServer, encrypt, Desktop): domain = domainName else: import socket - domain = "%s.%s" %(domainName,netDomain) + + domain = "%s.%s" % (domainName, netDomain) try: gethostbyname(domain) except socket.gaierror as e: domain = domainName # check domain by ping - for i in range(0,1): + for i in range(0, 1): try: - Pinger().ping(domain,1000,16) + Pinger().ping(domain, 1000, 16) break except IPError as e: pass else: - self.printERROR(_("Server %s does not respond")%domain) + self.printERROR(_("Server %s does not respond") % domain) return False reFoundHostSamba = re.compile("Server=\[Samba.+\]") smbClientCmd = checkUtils('/usr/bin/smbclient') - p = process(smbClientCmd,"-N","-L",domain,stderr=STDOUT) + p = process(smbClientCmd, "-N", "-L", domain, stderr=STDOUT) if p.success() and any(reFoundHostSamba.search(x) for x in p): return True else: - self.printERROR(_("Samba server not found in %s")%domain) + self.printERROR(_("Samba server not found in %s") % domain) return False - def getDomainPassword(self,domain): + def getDomainPassword(self, domain): """ Получить пароль для ввода в домен """ + def passwdQueue(): remotePw = self.clVars.Get('cl_remote_pw') if remotePw: yield remotePw if remotePw: self.printERROR(_("Wrong password")) - yield self.askPassword(\ - _("Domain password for the desktop"),False) + yield self.askPassword( + _("Domain password for the desktop"), False) self.printERROR(_("Wrong password")) - pathRemote = "/var/calculate/remote" for pwdRemote in passwdQueue(): pwdRemote = pwdRemote or "" - if sambaPasswordCheck("client",pwdRemote,domain,"remote"): - self.clVars.Set('cl_remote_pw',pwdRemote) + if sambaPasswordCheck("client", pwdRemote, domain, "remote"): + self.clVars.Set('cl_remote_pw', pwdRemote) return True return False - def writeClientVars(self,domain,currentVersion,pwdRemote): + def writeClientVars(self, domain, currentVersion, pwdRemote): """ Записать переменные переменные клиента """ @@ -1103,7 +1116,7 @@ class Client(commandServer, encrypt, Desktop): self.clVars.Write("cl_remote_pw", pwdRemote, True, "local") return True - def checkDomainInfo(self,domain): + def checkDomainInfo(self, domain): """ Проверить наличие настроек на сервере для конфигурации LDAP """ @@ -1114,7 +1127,8 @@ class Client(commandServer, encrypt, Desktop): # check info from server if not (servDn and unixDn and bindDn and bindPw): raise ClientError(_("Info not found on the server") + _(": ") + - _("services DN or unix DN or bind DN or bind password")) + _( + "services DN or unix DN or bind DN or bind password")) self.clVars.Set("os_remote_auth", domain) return True @@ -1130,21 +1144,20 @@ class Client(commandServer, encrypt, Desktop): """ if hostAuth: # add to domain - self.clVars.Set("cl_action","domain",True) + self.clVars.Set("cl_action", "domain", True) else: # del from domain - self.clVars.Set("cl_action","undomain",True) + self.clVars.Set("cl_action", "undomain", True) self.clVars.Set("os_remote_auth", hostAuth) # apply system templates - self.applyTemplates(None,False) + self.applyTemplates(None, False) if hostAuth: self.printSUCCESS(_("The workstation was configured for work " - "in the domain")) - currentVersion = self.clVars.Get("cl_ver") + "in the domain")) self.clVars.Write("os_remote_auth", hostAuth, True) else: self.printSUCCESS(_("The workstation was configured for work " - "outside the domain")) + "outside the domain")) self.clVars.Delete("os_remote_auth") return True @@ -1153,7 +1166,7 @@ class Client(commandServer, encrypt, Desktop): Удалить LDAP пользователей из системы (/etc/passwd и т.д.) и синхронизировать кэш """ - cacheObj = userCache() + cacheObj = userCache(self) if not cacheObj.deleteCacheUsersFromSystem(): return False if not cacheObj.syncCacheToLdap(): @@ -1164,7 +1177,7 @@ class Client(commandServer, encrypt, Desktop): """ Добавить кэш пользователей из системы """ - cacheObj = userCache() + cacheObj = userCache(self) if not cacheObj.addCacheUsersFromSystem(): return False return True @@ -1173,7 +1186,7 @@ class Client(commandServer, encrypt, Desktop): """ Добавить пользователя в кэш """ - cacheObj = userCache() + cacheObj = userCache(self) pwdHash = self.getHashPasswd(userPwd, "shadow_ssha256") if not cacheObj.addUserToCache(userName, pwdHash): return False @@ -1183,56 +1196,59 @@ class Client(commandServer, encrypt, Desktop): """ Удалить LDAP пользователей из системы и очистить кэш """ - cacheObj = userCache() + cacheObj = userCache(self) if not cacheObj.deleteCacheUsersFromSystem(): return False if not cacheObj.clearCache(): return False return True - def mountRemoteRes(self,pwdRemote,pathRemote,*domains): + def mountRemoteRes(self, pwdRemote, pathRemote, *domains): """ Подключить удаленный ресурс remote """ # первый домен из списка - domain = reduce(lambda x,y:x if x else y,domains,"") + domain = reduce(lambda x, y: x if x else y, domains, "") foundMountRemote = isMount(pathRemote) if foundMountRemote: - self.printWARNING(_("Samba volume [%s] mounted")%"remote") + self.printWARNING(_("Samba volume [%s] mounted") % "remote") return True else: if not (domain and pwdRemote): - self.printERROR(_("Variable not found")+ + self.printERROR(_("Variable not found") + _(": ") + "cl_remote_pw") return False if not os.path.exists(pathRemote): os.makedirs(pathRemote) - if not self.mountSambaRes(domain,"client",pwdRemote, - "remote",pathRemote): + if not self.mountSambaRes(domain, "client", pwdRemote, + "remote", pathRemote): self.printERROR( - _("Failed to mount the Samba volume [%s]")%"remote") + _("Failed to mount the Samba volume [%s]") % "remote") return False self.printSUCCESS(_("Samba volume [%s] mounted") % "remote") return True - def clientPasswd(self,userLogin,uid,gid,homeDir,password,curPassword): + def clientPasswd(self, userLogin, uid, gid, homeDir, password, curPassword): """ Изменить пароль пользователя. Пароль пользователя меняется на сервере после выхода из сеанса """ - 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")} + 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(homeDir, self.configFileServer) try: - res = self.setServerCommand(["passwd_samba"], varsConfig, fileConfig, - uid,gid) + res = self.setServerCommand(["passwd_samba"], varsConfig, + fileConfig, + uid, gid) except OSError as e: if e.errno == 13: self.printERROR(_("Permission denied")) return False + return False return res diff --git a/pym/client/client_cache.py b/pym/client/client_cache.py index 200d48d..35f208a 100644 --- a/pym/client/client_cache.py +++ b/pym/client/client_cache.py @@ -1,6 +1,6 @@ -#-*- coding: utf-8 -*- +# -*- coding: utf-8 -*- -# Copyright 2012-2013 Calculate Ltd. http://www.calculate-linux.org +# Copyright 2012-2015 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. @@ -14,21 +14,38 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os, sys, time +import os +import sys +import time from calculate.lib.utils.files import getModeFile -from calculate.lib.cl_print import color_print -from calculate.lib.cl_ldap import ldapUser +from calculate.lib.cl_ldap import ldapUser from calculate.lib.cl_lang import setLocalTranslate -setLocalTranslate('cl_client3',sys.modules[__name__]) -class _shareData(color_print): +_ = lambda x: x +setLocalTranslate('cl_client3', sys.modules[__name__]) + + +class Printable(object): + def __init__(self, parent): + if isinstance(parent, Printable): + self.parent = parent.parent + self.parent = parent + + def printERROR(self, s): + self.parent.printERROR(s) + + +class _shareData(Printable): """Share class""" + fileName = "" + template = "" + lenData = 0 data = [] def getDataInFile(self, fileName='', lenData=0): """Get data list from file""" - return filter(lambda x: len(x)==lenData, + return filter(lambda x: len(x) == lenData, map(lambda x: x.rstrip().split(":"), open(fileName))) def getFileAccess(self, perm="READ"): @@ -36,14 +53,14 @@ class _shareData(color_print): if os.access(self.fileName, os.R_OK): return True else: - self.printERROR(_("Failed to read the file")+_(": ") + + self.printERROR(_("Failed to read the file") + _(": ") + self.fileName) return False elif perm == "WRITE": if os.access(self.fileName, os.W_OK): return True else: - self.printERROR(_("Failed to write to file")+_(": ") + + self.printERROR(_("Failed to write to file") + _(": ") + self.fileName) return False @@ -55,14 +72,14 @@ class _shareData(color_print): elif self.getFileAccess(perm="READ"): self.data = self.getDataInFile(fileName=self.fileName, lenData=self.lenData) - return self.data + return self.data else: return False def save(self): if self.getFileAccess(perm="WRITE"): buff = "\n".join(map(lambda x: ":".join(x), self.data)) + "\n" - FD = open(self.fileName, "w+") + FD = open(self.fileName, "w+") FD.write(buff) FD.close() return True @@ -73,7 +90,7 @@ class _shareData(color_print): if self.getData() is False: return False else: - self.data = filter(lambda x: x[0]!=name, self.data) + self.data = filter(lambda x: x[0] != name, self.data) return True def replace(self, name, listData): @@ -101,12 +118,13 @@ class _shareData(color_print): if self.getData() is False: return False else: - listData = filter(lambda x: x[0]==name, self.data) + listData = filter(lambda x: x[0] == name, self.data) if listData: return listData[0] else: return [] + class passwd(_shareData): '''Class for working with the file /etc/passwd''' fileName = "/etc/passwd" @@ -115,10 +133,10 @@ class passwd(_shareData): def add(self, name, uid, gid, gecos="", directory="", shell="/bin/bash"): if not directory: - directory = "/home/%s" %name - userData = self.template%{'login':name, 'uid':uid, 'gid':gid, - 'gecos':gecos, 'directory':directory, - 'shell':shell} + directory = "/home/%s" % name + userData = self.template % {'login': name, 'uid': uid, 'gid': gid, + 'gecos': gecos, 'directory': directory, + 'shell': shell} userList = userData.split(":") if self.getData() is False: return False @@ -130,15 +148,16 @@ class passwd(_shareData): self.data.append(userList) return True + class group(_shareData): '''Class for working with the file /etc/group''' fileName = "/etc/group" template = "%(group_name)s:x:%(gid)s:%(user_list)s" lenData = 4 - def add(self, name, gid, userList=[]): - groupData = self.template%{'group_name':name, 'gid':gid, - 'user_list':','.join(userList)} + def add(self, name, gid, userList=()): + groupData = self.template % {'group_name': name, 'gid': gid, + 'user_list': ','.join(userList)} groupList = groupData.split(":") if self.getData() is False: return False @@ -165,12 +184,12 @@ class group(_shareData): # Constant gid listDataWork[2] = self.data[index][2] # Join user list - userList = delEmpty(self.data[index][3].split(',') +\ + userList = delEmpty(self.data[index][3].split(',') + listDataWork[3].split(',')) # unique list - userList = reduce(lambda x,y:\ - (y in x and x) or x +[y], - userList,[]) + userList = reduce(lambda x, y: \ + (y in x and x) or x + [y], + userList, []) listDataWork[3] = ','.join(userList) self.data[index] = listDataWork if flagFound: @@ -200,7 +219,7 @@ class group(_shareData): return False else: dataGroup = map(lambda x: x[3].split(","), - filter(lambda x: x[0]==name, self.data)) + filter(lambda x: x[0] == name, self.data)) if dataGroup: return dataGroup[0] else: @@ -214,28 +233,29 @@ class group(_shareData): for dataList in self.data: groupName, x, gid, userList = dataList if groupName in groups: - usersList = ",".join(filter(lambda x: x!=userName, - userList.split(","))) + usersList = ",".join(filter(lambda x: x != userName, + userList.split(","))) dataList[3] = usersList data.append(dataList) self.data = data return self.data + class shadow(_shareData): '''Class for working with the file /etc/shadow''' fileName = "/etc/shadow" - template = "%(login)s:%(hash)s:%(shadowLastChange)s:\ -%(shadowMin)s:%(shadowMax)s:%(shadowWarning)s:::" + template = ("%(login)s:%(hash)s:%(shadowLastChange)s:" + "%(shadowMin)s:%(shadowMax)s:%(shadowWarning)s:::") lenData = 9 def add(self, name, pwdHash, - shadowLastChange=str(int(time.time()/86400)), shadowMin="0", - shadowMax="99999", shadowWarning="7"): - shadowData = self.template%{'login':name, 'hash':pwdHash, - 'shadowLastChange':shadowLastChange, - 'shadowMin':shadowMin, - 'shadowMax':shadowMax, - 'shadowWarning':shadowWarning} + shadowLastChange=str(int(time.time() / 86400)), shadowMin="0", + shadowMax="99999", shadowWarning="7"): + shadowData = self.template % {'login': name, 'hash': pwdHash, + 'shadowLastChange': shadowLastChange, + 'shadowMin': shadowMin, + 'shadowMax': shadowMax, + 'shadowWarning': shadowWarning} shadowList = shadowData.split(":") if self.getData() is False: return False @@ -248,32 +268,32 @@ class shadow(_shareData): return True def equally(self, listDataA, listDataB): - getData = lambda x: x[:1] + x[2:] + getData = lambda x: x[:1] + x[2:] return _shareData.equally(self, getData(listDataA), getData(listDataB)) -class _shareCache(): +class _shareCache(_shareData): def save(self): path = os.path.dirname(self.fileName) if not os.path.exists(path): try: os.makedirs(path) - except: - self.printERROR(_("Failed to create directory %s")%path) + except OSError: + self.printERROR(_("Failed to create directory %s") % path) return False if not os.path.exists(self.fileName): try: open(self.fileName, "w") - except: - self.printERROR(_("Failed to create file %s")%self.fileName) + except IOError: + self.printERROR(_("Failed to create file %s") % self.fileName) return False if self.getFileAccess(perm="WRITE"): modeFile = 0600 if getModeFile(self.fileName, mode="mode") != modeFile: os.chmod(self.fileName, modeFile) buff = "\n".join(map(lambda x: ":".join(x), self.data)) + "\n" - FD = open(self.fileName, "w+") + FD = open(self.fileName, "w+") FD.write(buff) FD.close() return True @@ -294,9 +314,11 @@ class _shareCache(): else: return False + class cachePasswd(_shareCache, passwd): fileName = "/var/lib/calculate/calculate-client/cache/passwd" + class cacheGroup(_shareCache, group): fileName = "/var/lib/calculate/calculate-client/cache/group" @@ -306,27 +328,31 @@ class cacheGroup(_shareCache, group): def equally(self, listDataA, listDataB): return _shareData.equally(self, listDataA, listDataB) + class cacheShadow(_shareCache, shadow): fileName = "/var/lib/calculate/calculate-client/cache/shadow" + class cacheCreateGroup(cacheGroup): fileName = "/var/lib/calculate/calculate-client/cache/create_group" + class cacheCreatePasswd(cachePasswd): fileName = "/var/lib/calculate/calculate-client/cache/create_passwd" -class userCache(color_print): + +class userCache(Printable): ldapObj = ldapUser() def addUserToCache(self, userName, pwdHash): '''Add LDAP user to cache''' ldapData = self.ldapObj.getUserLdapInfo(userName, shadowAttr=True) if not ldapData: - self.printERROR(_("User %s not found in LDAP")%userName) + self.printERROR(_("User %s not found in LDAP") % userName) return False - groupName = ldapData['group'] + groupName = ldapData['group'] # Add user - cachePasswdObj = cachePasswd() + cachePasswdObj = cachePasswd(self) if not cachePasswdObj.add(userName, ldapData['uid'], ldapData['gid'], gecos=ldapData['fullName'], directory=ldapData['home'], @@ -334,9 +360,9 @@ class userCache(color_print): return False if not cachePasswdObj.save(): return False - cacheGroupObj = cacheGroup() + cacheGroupObj = cacheGroup(self) # Add primary group - if not cacheGroupObj.add(groupName,ldapData['gid']): + if not cacheGroupObj.add(groupName, ldapData['gid']): return False # Add second groups secondGroupsData = ldapData['groups'] @@ -353,14 +379,14 @@ class userCache(color_print): if not cacheGroupObj.add(groupName, gid, usersInGroup): return False allUsersSecondGroups.append(groupName) - deleteSecondGroups = list(set(cacheSecondUserGroups) -\ + deleteSecondGroups = list(set(cacheSecondUserGroups) - \ set(allUsersSecondGroups)) if not cacheGroupObj.deleteUserInGroups(userName, deleteSecondGroups): return False if not cacheGroupObj.save(): return False # Add shadow user - cacheShadowObj = cacheShadow() + cacheShadowObj = cacheShadow(self) if not cacheShadowObj.add(userName, pwdHash, shadowLastChange=ldapData['shadowLastChange'], shadowMin=ldapData['shadowMin'], @@ -373,14 +399,14 @@ class userCache(color_print): def delUserFromCacheCreate(self, userName): '''Delete LDAP user from createCache''' - cacheCreatePasswdObj = cacheCreatePasswd() + cacheCreatePasswdObj = cacheCreatePasswd(self) cacheUserData = cacheCreatePasswdObj.get(userName) if cacheUserData is False: return False if not cacheUserData: return True gid = cacheUserData[3] - cacheCreateGroupObj = cacheCreateGroup() + cacheCreateGroupObj = cacheCreateGroup(self) cacheSecondGroups = cacheCreateGroupObj.getSecondUserGroups(userName) if cacheSecondGroups is False: return False @@ -393,13 +419,13 @@ class userCache(color_print): return False if not cacheCreatePasswdObj.save(): return False - #delete groups + # delete groups usersGids = map(lambda x: x[3], cacheCreatePasswdObj.data) deleteGroups = map(lambda x: x[0], filter(lambda x: not x[2] in usersGids and not x[3], cacheCreateGroupObj.data)) for delGroupName in deleteGroups: - if not cacheCreateGroupObj.delete(delGroupName): + if not cacheCreateGroupObj.delete(delGroupName): return False if not cacheCreateGroupObj.save(): return False @@ -407,14 +433,14 @@ class userCache(color_print): def delUserFromCache(self, userName): '''Delete LDAP user from cache''' - cachePasswdObj = cachePasswd() + cachePasswdObj = cachePasswd(self) cacheUserData = cachePasswdObj.get(userName) if cacheUserData is False: return False if not cacheUserData: return True gid = cacheUserData[3] - cacheGroupObj = cacheGroup() + cacheGroupObj = cacheGroup(self) cacheSecondGroups = cacheGroupObj.getSecondUserGroups(userName) if cacheSecondGroups is False: return False @@ -426,18 +452,18 @@ class userCache(color_print): return False if not cachePasswdObj.save(): return False - #delete groups + # delete groups usersGids = map(lambda x: x[3], cachePasswdObj.data) deleteGroups = map(lambda x: x[0], filter(lambda x: not x[2] in usersGids and not x[3], cacheGroupObj.data)) for delGroupName in deleteGroups: - if not cacheGroupObj.delete(delGroupName): + if not cacheGroupObj.delete(delGroupName): return False if not cacheGroupObj.save(): return False # delete shadow user - cacheShadowObj = cacheShadow() + cacheShadowObj = cacheShadow(self) if not cacheShadowObj.delete(userName): return False if not cacheShadowObj.save(): @@ -446,13 +472,13 @@ class userCache(color_print): def delUserFromSystem(self, userName): '''Delete LDAP user from system files ( passwd, group, shadow )''' - cacheCreatePasswdObj = cacheCreatePasswd() + cacheCreatePasswdObj = cacheCreatePasswd(self) cacheCreatePasswdData = cacheCreatePasswdObj.get(userName) if cacheCreatePasswdData is False: return False if not cacheCreatePasswdData: return True - passwdObj = passwd() + passwdObj = passwd(self) userData = passwdObj.get(userName) if userData is False: return False @@ -464,18 +490,18 @@ class userCache(color_print): if not passwdObj.save(): return False # delete user group - groupObj = group() + groupObj = group(self) listGroupData = groupObj.getData() if listGroupData is False: return False - cacheCreateGroupObj = cacheCreateGroup() + cacheCreateGroupObj = cacheCreateGroup(self) secondUsersGroups = groupObj.getSecondUserGroups(userName) - usersGids = map(lambda x: x[3], passwdObj.data) + usersGids = map(lambda x: x[3], passwdObj.data) listGroupDataWork = [] for index, groupData in enumerate(listGroupData): groupName, x, gid, listUsers = groupData listUsers = filter(lambda x: x.strip(), listUsers.split(',')) - listUsers = ",".join(filter(lambda x: x!=userName, listUsers)) + listUsers = ",".join(filter(lambda x: x != userName, listUsers)) cacheCreateGroupData = cacheCreateGroupObj.get(groupName) if cacheCreateGroupData is False: return False @@ -487,7 +513,7 @@ class userCache(color_print): if not groupObj.save(): return False # delete user shadow - shadowObj = shadow() + shadowObj = shadow(self) shadowData = shadowObj.get(userName) if shadowData is False: return False @@ -515,7 +541,7 @@ class userCache(color_print): def deleteCacheUsersFromSystem(self): '''Delete cache users from system''' - cacheCreatePasswdObj = cacheCreatePasswd() + cacheCreatePasswdObj = cacheCreatePasswd(self) cacheCreateListPasswdData = cacheCreatePasswdObj.getData() if cacheCreateListPasswdData is False: return False @@ -527,7 +553,7 @@ class userCache(color_print): def getLoginDomainUsers(self): '''Get all domain login users''' - cacheCreatePasswdObj = cacheCreatePasswd() + cacheCreatePasswdObj = cacheCreatePasswd(self) cacheListCreatePasswdData = cacheCreatePasswdObj.getData() if cacheListCreatePasswdData is False: return False @@ -535,19 +561,19 @@ class userCache(color_print): def addCacheUsersFromSystem(self): '''Add cache users from system''' - cachePasswdObj = cachePasswd() + cachePasswdObj = cachePasswd(self) cacheListPasswdData = cachePasswdObj.getData() - if cacheListPasswdData is False: + if not isinstance(cacheListPasswdData, (list, tuple)): return False # Add cache passwd users to system - passwdObj = passwd() - cacheCreatePasswdObj = cacheCreatePasswd() + passwdObj = passwd(self) + cacheCreatePasswdObj = cacheCreatePasswd(self) cacheListCreatePasswdData = cacheCreatePasswdObj.getData() if cacheListCreatePasswdData is False: return False # remove deleted users cacheUsers = map(lambda x: x[0], cacheListPasswdData) - createUsers = map(lambda x: x[0], cacheListCreatePasswdData) + createUsers = map(lambda x: x[0], cacheListCreatePasswdData) deletedUsers = list(set(createUsers) - set(cacheUsers)) for delUser in deletedUsers: if not self.delUserFromSystem(delUser): @@ -573,9 +599,9 @@ class userCache(color_print): return False if retCacheCreate: if not passwdObj.add(userName, uid, gid, - gecos=gecos, - directory=directory, - shell=shell): + gecos=gecos, + directory=directory, + shell=shell): return False addUsers.append(userName) addUsersGid.append(gid) @@ -586,32 +612,32 @@ class userCache(color_print): return False if not cacheCreatePasswdObj.save(): return False - cacheShadowObj = cacheShadow() + cacheShadowObj = cacheShadow(self) cacheListShadowData = cacheShadowObj.getData() - if cacheListShadowData is False: + if not isinstance(cacheListShadowData, (list, tuple)): return False # Add cache shadow users to system - shadowObj = shadow() + shadowObj = shadow(self) for cacheShadowData in cacheListShadowData: - userName, pwdHash, shadowLastChange, shadowMin, shadowMax,\ - shadowWarning, x,x,x = cacheShadowData + userName, pwdHash, shadowLastChange, shadowMin, shadowMax, \ + shadowWarning, x, x, x = cacheShadowData if userName in addUsers: if not shadowObj.add(userName, pwdHash, - shadowLastChange=shadowLastChange, - shadowMin=shadowMin, - shadowMax=shadowMax, - shadowWarning=shadowWarning): + shadowLastChange=shadowLastChange, + shadowMin=shadowMin, + shadowMax=shadowMax, + shadowWarning=shadowWarning): return False if shadowObj.data: if not shadowObj.save(): return False - cacheGroupObj = cacheGroup() + cacheGroupObj = cacheGroup(self) cacheListGroupData = cacheGroupObj.getData() - if cacheListGroupData is False: + if not isinstance(cacheListGroupData, (list, tuple)): return False - cacheCreateGroupObj = cacheCreateGroup() + cacheCreateGroupObj = cacheCreateGroup(self) # Add cache group users to system - groupObj = group() + groupObj = group(self) setAddUsers = set(addUsers) for cacheGroupData in cacheListGroupData: groupName, x, gid, listUsers = cacheGroupData @@ -641,17 +667,18 @@ class userCache(color_print): if not self.isConnectToLdap(): self.printERROR(_("Failed to connect to the LDAP server")) return False - cachePasswdObj = cachePasswd() + cachePasswdObj = cachePasswd(self) cacheListPasswdData = cachePasswdObj.getData() if cacheListPasswdData is False: return False - if not cacheListPasswdData: + if (not isinstance(cacheListPasswdData, (tuple, list)) or + not cacheListPasswdData): return True - cacheGroupObj = cacheGroup() + cacheGroupObj = cacheGroup(self) cacheListGroupData = cacheGroupObj.getData() if cacheListGroupData is False: return False - cacheShadowObj = cacheShadow() + cacheShadowObj = cacheShadow(self) deletedCacheUsers = [] for cachePasswdData in cacheListPasswdData: userName, x, uid, gid, gecos, directory, shell = cachePasswdData @@ -659,8 +686,8 @@ class userCache(color_print): if not ldapData: deletedCacheUsers.append(userName) continue - cacheGroupData = map(lambda x: x[0], filter(lambda x: x[2]==gid, - cacheListGroupData)) + cacheGroupData = map(lambda x: x[0], filter(lambda x: x[2] == gid, + cacheListGroupData)) if not cacheGroupData: deletedCacheUsers.append(userName) continue @@ -671,29 +698,29 @@ class userCache(color_print): if not cacheShadowData: deletedCacheUsers.append(userName) continue - x,x, shadowLastChange, shadowMin, shadowMax, shadowWarning,\ - x,x,x = cacheShadowData + x, x, shadowLastChange, shadowMin, shadowMax, shadowWarning, \ + x, x, x = cacheShadowData groups = cacheGroupObj.getSecondUserGroups(userName) gidsGroups = map(lambda x: x[2], - filter(lambda x : x[0] in groups, + filter(lambda x: x[0] in groups, cacheGroupObj.data)) userShadowDict = {'uid': uid, 'gid': gid, 'fullName': gecos, 'home': directory, 'group': groupName, - 'groups': (groups,gidsGroups), - 'loginShell':shell, - 'shadowLastChange':shadowLastChange, - 'shadowMin':shadowMin, - 'shadowMax':shadowMax, - 'shadowWarning':shadowWarning} + 'groups': (groups, gidsGroups), + 'loginShell': shell, + 'shadowLastChange': shadowLastChange, + 'shadowMin': shadowMin, + 'shadowMax': shadowMax, + 'shadowWarning': shadowWarning} flagDeleteUser = False for attr, value in userShadowDict.items(): if attr == "groups": for index, val in enumerate(value): if set(map(lambda x: x[index], - ldapData[attr])) != set(val): + ldapData[attr])) != set(val): flagDeleteUser = True break else: @@ -711,8 +738,8 @@ class userCache(color_print): def clearCache(self): '''Clear cache files''' - cacheObjs = (cachePasswd(), cacheShadow(), cacheGroup(), - cacheCreateGroup(), cacheCreatePasswd()) + cacheObjs = (cachePasswd(self), cacheShadow(self), cacheGroup(self), + cacheCreateGroup(self), cacheCreatePasswd(self)) for cacheObj in cacheObjs: if not cacheObj.save(): return False diff --git a/pym/client/datavars.py b/pym/client/datavars.py index 86407bd..8b703bc 100644 --- a/pym/client/datavars.py +++ b/pym/client/datavars.py @@ -1,6 +1,6 @@ -#-*- coding: utf-8 -*- +# -*- coding: utf-8 -*- -# Copyright 2012-2013 Calculate Ltd. http://www.calculate-linux.org +# Copyright 2012-2015 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. @@ -15,14 +15,15 @@ # limitations under the License. __app__ = 'calculate-client' -__version__ = '3.1.8' +__version__ = '3.4.2' -import os import sys from calculate.lib.datavars import DataVars from calculate.lib.cl_lang import setLocalTranslate -setLocalTranslate('cl_client3',sys.modules[__name__]) + +setLocalTranslate('cl_client3', sys.modules[__name__]) + class DataVarsClient(DataVars): """Variable class for client package""" diff --git a/pym/client/utils/cl_client.py b/pym/client/utils/cl_client.py index b5619b9..68da0e1 100644 --- a/pym/client/utils/cl_client.py +++ b/pym/client/utils/cl_client.py @@ -1,6 +1,6 @@ -#-*- coding: utf-8 -*- +# -*- coding: utf-8 -*- -# Copyright 2013 Calculate Ltd. http://www.calculate-linux.org +# Copyright 2013-2015 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. @@ -15,24 +15,24 @@ # limitations under the License. import sys -from os import path -from calculate.core.server.func import Action,Tasks -from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate +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.desktop.desktop import DesktopError from calculate.client.client import ClientError from calculate.lib.cl_template import TemplatesError -from calculate.lib.utils.files import isMount -setLocalTranslate('cl_client3',sys.modules[__name__]) +_ = lambda x: x +setLocalTranslate('cl_client3', sys.modules[__name__]) __ = getLazyLocalTranslate(_) + class ClClientAction(Action): """ Ввести машину в домен или вывести """ # ошибки, которые отображаются без подробностей - native_error = (FilesError,ClientError,DesktopError,TemplatesError) + native_error = (FilesError, ClientError, DesktopError, TemplatesError) successMessage = None failedMessage = None @@ -40,114 +40,115 @@ class ClClientAction(Action): # список задач для действия tasks = [ - # команда вызвана только для монтировния remote ресурсов - {'name':'only_mount', - 'condition':lambda Get:Get('cl_client_mount_set') == 'on' - }, - # ввод в домен - {'name':'domain', - 'condition':lambda Get:Get('cl_localhost_set') == 'off', - 'depend':Tasks.hasnot('only_mount') - }, - # вывод из домена - {'name':'undomain', - 'condition':lambda Get:Get('cl_localhost_set') == 'on', - 'depend':Tasks.hasnot('only_mount') - }, - # машина не доменная - {'name':'only_mount:localpc', - 'warning':__("This workstation is not in the domain"), - 'condition':lambda Get:not Get('cl_remote_host') - }, - # проверить может ли указанный сервер являться доменом - {'name':'domain:check_domain', - 'message':__("Checking {cl_remote_host_new} for domain resources"), - 'method':'Client.checkDomainServer(cl_remote_host_new,os_net_domain)', - }, - # получить пароль для ввода в домен (или воспользоваться кэшированным) - {'name':'domain:get_password', - 'method':'Client.getDomainPassword(cl_remote_host_new)' - }, - {'name':'domain:set_remote_host', - 'method':'Client.setVariable("cl_remote_host",cl_remote_host_new)' - }, - # машина доменная - {'name':'mount_remote', - 'method':'Client.mountRemoteRes(cl_remote_pw,cl_client_remote_path,' + # команда вызвана только для монтировния remote ресурсов + {'name': 'only_mount', + 'condition': lambda Get: Get('cl_client_mount_set') == 'on' + }, + # ввод в домен + {'name': 'domain', + 'condition': lambda Get: Get('cl_localhost_set') == 'off', + 'depend': Tasks.hasnot('only_mount') + }, + # вывод из домена + {'name': 'undomain', + 'condition': lambda Get: Get('cl_localhost_set') == 'on', + 'depend': Tasks.hasnot('only_mount') + }, + # машина не доменная + {'name': 'only_mount:localpc', + 'warning': __("This workstation is not in the domain"), + 'condition': lambda Get: not Get('cl_remote_host') + }, + # проверить может ли указанный сервер являться доменом + {'name': 'domain:check_domain', + 'message': __("Checking {cl_remote_host_new} for domain resources"), + 'method': 'Client.checkDomainServer(cl_remote_host_new,os_net_domain)', + }, + # получить пароль для ввода в домен (или воспользоваться кэшированным) + {'name': 'domain:get_password', + 'method': 'Client.getDomainPassword(cl_remote_host_new)' + }, + {'name': 'domain:set_remote_host', + 'method': 'Client.setVariable("cl_remote_host",cl_remote_host_new)' + }, + # машина доменная + {'name': 'mount_remote', + 'method': 'Client.mountRemoteRes(cl_remote_pw,cl_client_remote_path,' 'cl_remote_host)', - 'depend':Tasks.success() & Tasks.hasnot('localpc','undomain') - }, - # отключить удаленный доменный ресурс - {'name':'undomain:unmount_remote', - 'method':'Client.umountSleepPath(cl_client_remote_path)', - }, - # удалить переменные клиента - {'name':'undomain:remove_vars', - 'method':'Client.removeVars()' - }, - # наложить шаблоны если они не актуальны - {'name':'need_templates', - 'condition':lambda Get:Get('cl_client_relevance_set') == 'off', - 'depend':Tasks.success(inessential=['mount_remote']) - }, - # проверить информацию для ldap расположенную в домене - {'name':'domain:check_domain_info', - 'method':'Client.checkDomainInfo(cl_remote_host)', - }, - # наложить доменные шаблоны, если успешно подключен удаленный ресурс - {'name':'need_templates:apply_templates', - 'message':__("Applying domain templates"), - 'method':'Client.applyClientTemplates(cl_remote_host)', - 'depend':Tasks.success_all('mount_remote') - }, - # наложить недоменные шаблоны в случае локального режима - # или были проблемы с подключением удаленноых ресурсов - {'name':'need_templates:apply_templates', - 'message':__("Applying non-domain templates"), - 'method':'Client.applyClientTemplates("")', - 'depend':Tasks.result('mount_remote',ne=True) - }, - # удалить записи из /etc/passwd и синхронизировать кэш - {'name':'del_sync_cache', - 'method':'Client.cDelLdapSysUsersAndSyncCache()', - 'condition':lambda Get:Get('cl_remote_host'), - 'depend':Tasks.success_all('mount_remote','need_templates') - }, - # удалить записи из /etc/passwd и очистить кэш - {'name':'undomain:del_clear_cache', - 'message':__("Clearing the user cache"), - 'method':'Client.cDelLdapSysUsersAndClearCache()' - }, - # синхронизировать кэш, добавить записи в /etc/passwd - {'name':'only_mount:add_sync_cache', - 'method':'Client.cAddCacheUsersFromSystem()', - 'depend':Tasks.failed_all('mount_remote') - }, - # удалить службу client из автозапуска - {'name':'undomain:noautorun_client', - 'method':'Client.delDaemonAutostart("client")' - }, - # добавить службу client в автозапуск - {'name':'domain:autorun_client', - 'method':'Client.addDaemonAutostart("client")' - }, - # записать переменные клиента - {'name':'domain:write_vars', - 'method':'Client.writeClientVars(cl_remote_host,cl_ver,cl_remote_pw)', - }, - # сообщения о результатах работы действия - {'name':'domain:success', - 'message':__("Workstation added to domain {cl_remote_host}") - }, - {'name':'domain:failed', - 'error':__("Failed to add the workstation to domain {cl_remote_host}"), - 'depend':Tasks.failed() & Tasks.hasnot("interrupt"), - }, - {'name':'undomain:success', - 'message':__("Workstation removed from domain {cl_remote_host}") - }, - {'name':'undomain:failed', - 'error':__("Failed to remove the workstation from the domain"), - 'depend':Tasks.failed() & Tasks.hasnot("interrupt"), - }, - ] + 'depend': Tasks.success() & Tasks.hasnot('localpc', 'undomain') + }, + # отключить удаленный доменный ресурс + {'name': 'undomain:unmount_remote', + 'method': 'Client.umountSleepPath(cl_client_remote_path)', + }, + # удалить переменные клиента + {'name': 'undomain:remove_vars', + 'method': 'Client.removeVars()' + }, + # наложить шаблоны если они не актуальны + {'name': 'need_templates', + 'condition': lambda Get: Get('cl_client_relevance_set') == 'off', + 'depend': Tasks.success(inessential=['mount_remote']) + }, + # проверить информацию для ldap расположенную в домене + {'name': 'domain:check_domain_info', + 'method': 'Client.checkDomainInfo(cl_remote_host)', + }, + # наложить доменные шаблоны, если успешно подключен удаленный ресурс + {'name': 'need_templates:apply_templates', + 'message': __("Applying domain templates"), + 'method': 'Client.applyClientTemplates(cl_remote_host)', + 'depend': Tasks.success_all('mount_remote') + }, + # наложить недоменные шаблоны в случае локального режима + # или были проблемы с подключением удаленноых ресурсов + {'name': 'need_templates:apply_templates', + 'message': __("Applying non-domain templates"), + 'method': 'Client.applyClientTemplates("")', + 'depend': Tasks.result('mount_remote', ne=True) + }, + # удалить записи из /etc/passwd и синхронизировать кэш + {'name': 'del_sync_cache', + 'method': 'Client.cDelLdapSysUsersAndSyncCache()', + 'condition': lambda Get: Get('cl_remote_host'), + 'depend': Tasks.success_all('mount_remote', 'need_templates') + }, + # удалить записи из /etc/passwd и очистить кэш + {'name': 'undomain:del_clear_cache', + 'message': __("Clearing the user cache"), + 'method': 'Client.cDelLdapSysUsersAndClearCache()' + }, + # синхронизировать кэш, добавить записи в /etc/passwd + {'name': 'only_mount:add_sync_cache', + 'method': 'Client.cAddCacheUsersFromSystem()', + 'depend': Tasks.failed_all('mount_remote') + }, + # удалить службу client из автозапуска + {'name': 'undomain:noautorun_client', + 'method': 'Client.delDaemonAutostart("client")' + }, + # добавить службу client в автозапуск + {'name': 'domain:autorun_client', + 'method': 'Client.addDaemonAutostart("client")' + }, + # записать переменные клиента + {'name': 'domain:write_vars', + 'method': 'Client.writeClientVars(cl_remote_host,cl_ver,cl_remote_pw)', + }, + # сообщения о результатах работы действия + {'name': 'domain:success', + 'message': __("Workstation added to domain {cl_remote_host}") + }, + {'name': 'domain:failed', + 'error': __( + "Failed to add the workstation to domain {cl_remote_host}"), + 'depend': Tasks.failed() & Tasks.hasnot("interrupt"), + }, + {'name': 'undomain:success', + 'message': __("Workstation removed from domain {cl_remote_host}") + }, + {'name': 'undomain:failed', + 'error': __("Failed to remove the workstation from the domain"), + 'depend': Tasks.failed() & Tasks.hasnot("interrupt"), + }, + ] diff --git a/pym/client/utils/cl_client_sync.py b/pym/client/utils/cl_client_sync.py index 375b0cd..dbdca76 100644 --- a/pym/client/utils/cl_client_sync.py +++ b/pym/client/utils/cl_client_sync.py @@ -1,6 +1,6 @@ -#-*- coding: utf-8 -*- +# -*- coding: utf-8 -*- -# Copyright 2013 Calculate Ltd. http://www.calculate-linux.org +# Copyright 2013-2015 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. @@ -16,230 +16,237 @@ import sys from os import path -from calculate.core.server.func import Action,Tasks -from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate +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.desktop.desktop import DesktopError from calculate.client.client import ClientError from calculate.lib.cl_template import TemplatesError from calculate.lib.utils.files import isMount -setLocalTranslate('cl_client3',sys.modules[__name__]) +_ = lambda x: x +setLocalTranslate('cl_client3', sys.modules[__name__]) __ = getLazyLocalTranslate(_) + class ClClientSyncLoginAction(Action): """ Синхронизировать локальный профиль с удаленным, подключить удаленные ресурсы пользователя """ - native_error = (FilesError,ClientError,DesktopError,TemplatesError) + native_error = (FilesError, ClientError, DesktopError, TemplatesError) successMessage = None failedMessage = None interruptMessage = __("Synchronization manually interrupted") tasks = [ - # подключить удаленный ресурс домена - {'name':'mount_remote', - 'method':'Client.mountRemoteRes(cl_remote_pw,cl_client_remote_path,' + # подключить удаленный ресурс домена + {'name': 'mount_remote', + 'method': 'Client.mountRemoteRes(cl_remote_pw,cl_client_remote_path,' 'cl_remote_host)', - 'condition':lambda Get: (Get('cl_remote_host') and - Get('os_remote_auth') and - not isMount(Get('cl_client_remote_path'))), + 'condition': lambda Get: (Get('cl_remote_host') and + Get('os_remote_auth') and + not isMount(Get('cl_client_remote_path'))), }, - # check on domain user - {'name':'domain_user', - 'condition':lambda Get: (Get('os_remote_auth') and + # check on domain user + {'name': 'domain_user', + 'condition': lambda Get: (Get('os_remote_auth') and Get('cl_remote_host') and Get('desktop.ur_domain_set') == 'on'), - 'else_message':__("The local profile will be used") - }, - {'name':'domain_user:create_home', - 'message':__("Creating the home directory for {ur_login}"), - 'method':'Client.createUserDirectory(ur_home_path,ur_uid,' - 'ur_gid)', - 'condition':lambda Get:not path.exists(Get('ur_home_path')) - }, - # password in kernel key - {'name':'domain_user:check_password', - 'condition':lambda Get:Get('desktop.ur_password'), - 'else_error':__("User password not found") - }, - {'name':'ecryptfs', - 'message':__("Mounting encrypted data"), - 'method':'Desktop.createCryptDir(ur_login,ur_uid,ur_gid,' - 'ur_home_path,True)', - 'condition':lambda Get:(Get('desktop.ur_home_crypt_set') == 'on' and - Get('install.cl_autologin') != Get('ur_login')) - }, - {'name':'domain_user:add_to_cache', - 'essential':False, - 'method':'Client.cAddUserToCache(ur_login,desktop.ur_password)', - 'failed_warning':__("Unable to cache user info") - }, - # подключить удаленные ресурсы пользователя - {'name':'domain_user:mount_resources', - 'message':__("Mounting user resources"), - 'method':'Client.mountUserDomainRes(ur_login,' - 'desktop.ur_password,' - 'ur_uid,ur_gid,"unix","share","homes","ftp")', - }, - # проверка на попытку открыть вторую сессию для этого пользователя - {'name':'two_session', - 'error': - __("A second X session cannot be opened for user {ur_login}."), - 'condition':lambda dv: (dv.Get('ur_login') in + 'else_message': __("The local profile will be used") + }, + {'name': 'domain_user:create_home', + 'message': __("Creating the home directory for {ur_login}"), + 'method': 'Client.createUserDirectory(ur_home_path,ur_uid,' + 'ur_gid)', + 'condition': lambda Get: not path.exists(Get('ur_home_path')) + }, + # password in kernel key + {'name': 'domain_user:check_password', + 'condition': lambda Get: Get('desktop.ur_password'), + 'else_error': __("User password not found") + }, + {'name': 'ecryptfs', + 'message': __("Mounting encrypted data"), + 'method': 'Desktop.createCryptDir(ur_login,ur_uid,ur_gid,' + 'ur_home_path,True)', + 'condition': lambda Get: (Get('desktop.ur_home_crypt_set') == 'on' and + Get('install.cl_autologin') != Get( + 'ur_login')) + }, + {'name': 'domain_user:add_to_cache', + 'essential': False, + 'method': 'Client.cAddUserToCache(ur_login,desktop.ur_password)', + 'failed_warning': __("Unable to cache user info") + }, + # подключить удаленные ресурсы пользователя + {'name': 'domain_user:mount_resources', + 'message': __("Mounting user resources"), + 'method': 'Client.mountUserDomainRes(ur_login,' + 'desktop.ur_password,' + 'ur_uid,ur_gid,"unix","share","homes","ftp")', + }, + # проверка на попытку открыть вторую сессию для этого пользователя + {'name': 'two_session', + 'error': + __("A second X session cannot be opened for user {ur_login}."), + 'condition': lambda dv: (dv.Get('ur_login') in dv.Get('desktop.cl_desktop_online_user') and - int(dv.Select('desktop.cl_desktop_online_count', - where='desktop.cl_desktop_online_user', - eq=dv.Get('ur_login'),limit=1) > 1) and - dv.Get('cl_client_sync') == 'on') - }, - {'name':'domain_user:domain_sync', - 'method':'Client.setSyncStatus(ur_home_path,ur_uid,ur_gid,"process")', - 'condition':lambda Get:Get('cl_client_sync') == 'on' - }, - # подключить профиль пользователя на удаленном домене - # если на нем находится актуальный профиль - {'name':'domain_sync:repl_profile', - 'method':'Client.mountUserDomainRes(ur_login,desktop.ur_password,' - 'ur_uid,ur_gid,"unix","remote_profile")', - 'condition':lambda Get:Get('cl_replication_host') - }, - # отправить команду архивирования профиля на удаленном домене - # если он новее локального профиля - {'name':'repl_profile:pack_remote', - 'method':'Client.packRemote("remote_profile",' - 'cl_client_local_sync_time,cl_client_pack_time,' - 'cl_client_profile_name,ur_uid,ur_gid)', - 'condition':lambda Get:Get('cl_client_sync_replication_set') == 'on', - 'else_message':__("The local user profile does not " + int(dv.Select( + 'desktop.cl_desktop_online_count', + where='desktop.cl_desktop_online_user', + eq=dv.Get('ur_login'), limit=1) > 1) and + dv.Get('cl_client_sync') == 'on') + }, + {'name': 'domain_user:domain_sync', + 'method': 'Client.setSyncStatus(ur_home_path,ur_uid,ur_gid,"process")', + 'condition': lambda Get: Get('cl_client_sync') == 'on' + }, + # подключить профиль пользователя на удаленном домене + # если на нем находится актуальный профиль + {'name': 'domain_sync:repl_profile', + 'method': 'Client.mountUserDomainRes(ur_login,desktop.ur_password,' + 'ur_uid,ur_gid,"unix","remote_profile")', + 'condition': lambda Get: Get('cl_replication_host') + }, + # отправить команду архивирования профиля на удаленном домене + # если он новее локального профиля + {'name': 'repl_profile:pack_remote', + 'method': 'Client.packRemote("remote_profile",' + 'cl_client_local_sync_time,cl_client_pack_time,' + 'cl_client_profile_name,ur_uid,ur_gid)', + 'condition': lambda Get: Get('cl_client_sync_replication_set') == 'on', + 'else_message': __("The local user profile does not " "need to be synchronized with the remote domain") }, - # монтируем профиль локального домена, если локальный профиль - # старее удаленного доменного или актуальный профиль - {'name':'domain_sync:mount_local', - 'method':'Client.mountUserDomainRes(ur_login,desktop.ur_password,' - 'ur_uid,ur_gid,"unix")', - # нет более ранних ошибок и локальный профиль нуждается - # в синхронизации с удаленным или профиль на локальном домене - 'depend':(Tasks.success_all('mount_resources') & + # монтируем профиль локального домена, если локальный профиль + # старее удаленного доменного или актуальный профиль + {'name': 'domain_sync:mount_local', + 'method': 'Client.mountUserDomainRes(ur_login,desktop.ur_password,' + 'ur_uid,ur_gid,"unix")', + # нет более ранних ошибок и локальный профиль нуждается + # в синхронизации с удаленным или профиль на локальном домене + 'depend': (Tasks.success_all('mount_resources') & (Tasks.hasnot('repl_profile') | Tasks.has('pack_remote'))) }, - # синхронизируем с профилем локального домена - {'name':'mount_local!:sync_local', - 'method':'Client.syncLoginProfile(cl_remote_host,ur_uid,' + # синхронизируем с профилем локального домена + {'name': 'mount_local!:sync_local', + 'method': 'Client.syncLoginProfile(cl_remote_host,ur_uid,' 'ur_gid,ur_home_path,"unix",cl_client_profile_name)', - 'condition':lambda Get:Get('cl_client_sync_local_set') == 'on', - 'else_message':__("The local user profile does not " + 'condition': lambda Get: Get('cl_client_sync_local_set') == 'on', + 'else_message': __("The local user profile does not " "need to be synchronized with the local domain") }, - # ошибка синхронизации с локальным доменом - {'name':'local_sync_error', - 'warning':__("Error synchronizing with the local server {cl_remote_host}"), - 'depend':Tasks.failed_one_of("mount_local","sync_local") - }, - # подключить удаленный профиль пользователя с "репликации" - {'name':'repl_profile:repeat_repl_profile', - 'method':'Client.mountUserDomainRes(ur_login,desktop.ur_password,' - 'ur_uid,ur_gid,"remote_profile")', - }, - # ждать архив от удаленного домена - {'name':'pack_remote:wait_archive', - 'message': __("Packing the archive on the server"), - 'method':'Client.waitingArchFile(cl_client_pack_time,' - 'cl_client_profile_name,"remote_profile")', - 'failed_warning':__("Failed to find the profile " + # ошибка синхронизации с локальным доменом + {'name': 'local_sync_error', + 'warning': __( + "Error synchronizing with the local server {cl_remote_host}"), + 'depend': Tasks.failed_one_of("mount_local", "sync_local") + }, + # подключить удаленный профиль пользователя с "репликации" + {'name': 'repl_profile:repeat_repl_profile', + 'method': 'Client.mountUserDomainRes(ur_login,desktop.ur_password,' + 'ur_uid,ur_gid,"remote_profile")', + }, + # ждать архив от удаленного домена + {'name': 'pack_remote:wait_archive', + 'message': __("Packing the archive on the server"), + 'method': 'Client.waitingArchFile(cl_client_pack_time,' + 'cl_client_profile_name,"remote_profile")', + 'failed_warning': __("Failed to find the profile " "archive of {cl_replication_host}") }, - # распаковать архив из удаленного домена и удалить - # файлы которые отсутствуют в удаленном профиле - {'name':'wait_archive:unpack_profile', - 'message':__("Unpacking the profile"), - 'method':'Client.unpackArch(ur_home_path,cl_client_pack_time,' - 'cl_client_profile_name,"remote_profile")', - 'failed_warning':__("Failed to unpack") - }, - # удалить временные архивы - {'name':'clean_archfiles', - 'method':'Client.cleanArchs(cl_client_pack_time,' - 'cl_client_profile_name,"remote_profile")', - 'failed_warning':__("Unable to remove useless files"), - 'essential':False, - 'depend': Tasks.has('pack_remote') - }, - # синхронизировать профиль с удаленным доменом в случае ошибки - {'name':'repl_profile:sync_remote', - 'method':'Client.syncLoginProfile(cl_replication_host,ur_uid,' + # распаковать архив из удаленного домена и удалить + # файлы которые отсутствуют в удаленном профиле + {'name': 'wait_archive:unpack_profile', + 'message': __("Unpacking the profile"), + 'method': 'Client.unpackArch(ur_home_path,cl_client_pack_time,' + 'cl_client_profile_name,"remote_profile")', + 'failed_warning': __("Failed to unpack") + }, + # удалить временные архивы + {'name': 'clean_archfiles', + 'method': 'Client.cleanArchs(cl_client_pack_time,' + 'cl_client_profile_name,"remote_profile")', + 'failed_warning': __("Unable to remove useless files"), + 'essential': False, + 'depend': Tasks.has('pack_remote') + }, + # синхронизировать профиль с удаленным доменом в случае ошибки + {'name': 'repl_profile:sync_remote', + 'method': 'Client.syncLoginProfile(cl_replication_host,ur_uid,' 'ur_gid,ur_home_path,"remote_profile",' 'cl_client_profile_name)', - 'depend':Tasks.failed_one_of('pack_remote','mount_local','sync_local', - 'wait_archive','unpack_profile'), - 'condition':lambda Select:isMount( - Select('cl_client_user_mount_path', - where='cl_client_user_mount_name',eq='remote_profile', - limit=1)) - }, - # если синхронизация с удаленным доменом прошла с ошибкой - # синхронизировать локальный профиль с локальным доменом - # как запасной профиль - {'name':'pack_remote:fallback_warning', - 'warning':__("Error synchronizing with the " + 'depend': Tasks.failed_one_of('pack_remote', 'mount_local', + 'sync_local', + 'wait_archive', 'unpack_profile'), + 'condition': lambda Select: isMount( + Select('cl_client_user_mount_path', + where='cl_client_user_mount_name', eq='remote_profile', + limit=1)) + }, + # если синхронизация с удаленным доменом прошла с ошибкой + # синхронизировать локальный профиль с локальным доменом + # как запасной профиль + {'name': 'pack_remote:fallback_warning', + 'warning': __("Error synchronizing with the " "{cl_replication_host} remote server"), - 'depend': ~Tasks.success_one_of('unpack_profile','sync_remote') + 'depend': ~Tasks.success_one_of('unpack_profile', 'sync_remote') }, - {'name':'pack_remote:fallback_sync', - 'method':'Client.syncLoginProfile(cl_remote_host,ur_uid,' + {'name': 'pack_remote:fallback_sync', + 'method': 'Client.syncLoginProfile(cl_remote_host,ur_uid,' 'ur_gid,ur_home_path,"unix",cl_client_profile_name)', - 'depend': ~Tasks.success_one_of('unpack_profile','sync_remote') - }, - # отключить профиль на удаленном домене - {'name':'repl_profile!:umount_remote_profile', - 'method':'Client.umountRemoteUserRes(True,"remote_profile")', - }, - # сообщение о том, что будет использоваться запасной профиль - # с локального домена - {'name':'fallback_sync!:fallback_success', - 'message': __("Got a user fallback profile from the " - "{cl_remote_host} domain") - }, - # ошибка синхронизации профиль не готов! к использованию - {'name':'failed', - 'error':__("Failed to get the user profile from the domain"), - 'method':'Client.setSyncStatus(ur_home_path,ur_uid,ur_gid,"error")', - 'depend':Tasks.failed_all('sync_remote','sync_local','fallback_sync') | + 'depend': ~Tasks.success_one_of('unpack_profile', 'sync_remote') + }, + # отключить профиль на удаленном домене + {'name': 'repl_profile!:umount_remote_profile', + 'method': 'Client.umountRemoteUserRes(True,"remote_profile")', + }, + # сообщение о том, что будет использоваться запасной профиль + # с локального домена + {'name': 'fallback_sync!:fallback_success', + 'message': __("Got a user fallback profile from the " + "{cl_remote_host} domain") + }, + # ошибка синхронизации профиль не готов! к использованию + {'name': 'failed', + 'error': __("Failed to get the user profile from the domain"), + 'method': 'Client.setSyncStatus(ur_home_path,ur_uid,ur_gid,"error")', + 'depend': Tasks.failed_all('sync_remote', 'sync_local', + 'fallback_sync') | (Tasks.hasnot('domain_sync') & Tasks.failed()) | - Tasks.failed_one_of('mount_resources','two_session') - }, - # распаковать ссылки - {'name':'domain_sync:unpack_links', - 'method':'Client.unpackLinks(ur_home_path)', - 'failed_warning': __("Failed to unpack the links archive"), - 'depend':Tasks.hasnot('failed') - }, - # синхронизация профиля завершилась успешно - {'name':'domain_sync:success_sync', - 'message':__("User profile fetched from the domain"), - 'method':'Client.setSyncStatus(ur_home_path,ur_uid,ur_gid,"success")', - 'depend': Tasks.success_all('sync_remote','unpack_links') | - Tasks.success() - }, - # во время синхронизации профиля произошли ошибки, которые не - # гарантируют целостность профиля - {'name':'domain_sync:error_sync', - 'warning':__("User profile modifications will not " - "be saved to the domain"), - 'method':'Client.setSyncStatus(ur_home_path,ur_uid,ur_gid,"error")', - 'depend': Tasks.hasnot('success_sync','failed') - }, - # отключить ресурсы в случае ошибки - {'name':'umount_remote_res', - 'message':__("Umounting user resources"), - 'method':'Client.umountUserRes(desktop.ur_mount_dirs)', - 'depend':Tasks.has('failed') + Tasks.failed_one_of('mount_resources', 'two_session') + }, + # распаковать ссылки + {'name': 'domain_sync:unpack_links', + 'method': 'Client.unpackLinks(ur_home_path)', + 'failed_warning': __("Failed to unpack the links archive"), + 'depend': Tasks.hasnot('failed') + }, + # синхронизация профиля завершилась успешно + {'name': 'domain_sync:success_sync', + 'message': __("User profile fetched from the domain"), + 'method': 'Client.setSyncStatus(ur_home_path,ur_uid,ur_gid,"success")', + 'depend': Tasks.success_all('sync_remote', 'unpack_links') | + Tasks.success() + }, + # во время синхронизации профиля произошли ошибки, которые не + # гарантируют целостность профиля + {'name': 'domain_sync:error_sync', + 'warning': __("User profile modifications will not " + "be saved to the domain"), + 'method': 'Client.setSyncStatus(ur_home_path,ur_uid,ur_gid,"error")', + 'depend': Tasks.hasnot('success_sync', 'failed') + }, + # отключить ресурсы в случае ошибки + {'name': 'umount_remote_res', + 'message': __("Umounting user resources"), + 'method': 'Client.umountUserRes(desktop.ur_mount_dirs)', + 'depend': Tasks.has('failed') } - ] + ] class ClClientSyncLogoutAction(Action): @@ -247,99 +254,100 @@ class ClClientSyncLogoutAction(Action): Синхронизировать локальный профиль с удаленным, отключить удаленные ресурсы пользователя """ - native_error = (FilesError,ClientError,DesktopError,TemplatesError) + native_error = (FilesError, ClientError, DesktopError, TemplatesError) successMessage = None failedMessage = None interruptMessage = __("Synchronization manually interrupted") tasks = [ - # проверка доменный ли пользователь - {'name':'domain_user', - 'condition':lambda Get: (Get('os_remote_auth') and - Get('cl_remote_host') and + # проверка доменный ли пользователь + {'name': 'domain_user', + 'condition': lambda Get: (Get('os_remote_auth') and + Get('cl_remote_host') and Get('desktop.ur_domain_set') == 'on'), - 'else_message':__("The local profile will be used") - }, - # проверка на попытку отключить ресурсы пользователя в X сессии - {'name':'domain_user:in_xsession', - 'error':__("User {ur_login} is already on the X session"), - 'condition':lambda Get:Get('ur_login') in \ - Get('desktop.cl_desktop_online_user'), - }, - # проверить наличие домашней директории - {'name':'domain_user:check_homedir', - 'condition':lambda Get:path.exists(Get('ur_home_path')), - 'else_error':__("Home directory {ur_home_path} not found"), - }, - # проверить наличие подключенных ресурсов - {'name':'domain_user:check_mount', - 'condition':lambda Get:any(x and isMount(x) - for x in Get('cl_client_user_mount_path')), - 'else_error':__("Remote user resources not found") - }, - # установить время выхода из сеанса - {'name':'domain_user:set_logout_date', - 'method':'Client.setLogoutDate(ur_home_path,ur_uid,ur_gid)' - }, - # выполнять ли синхронизацию - {'name':'domain_user:domain_sync', - 'condition':lambda Get:Get('cl_client_sync_status') == 'success' and - Get('cl_client_sync') == 'on', - 'else_warning':__("The profile will not be uploaded to the domain") - }, - # переместить файлы из профиля в Moved - {'name':'domain_user:move_home_dir', - 'message':__("Moving non-profile files to the Home/Moved directory"), - 'method':'Client.moveHomeDir(ur_home_path,"Moved","homes",' + 'else_message': __("The local profile will be used") + }, + # проверка на попытку отключить ресурсы пользователя в X сессии + {'name': 'domain_user:in_xsession', + 'error': __("User {ur_login} is already on the X session"), + 'condition': lambda Get: Get('ur_login') in + Get('desktop.cl_desktop_online_user'), + }, + # проверить наличие домашней директории + {'name': 'domain_user:check_homedir', + 'condition': lambda Get: path.exists(Get('ur_home_path')), + 'else_error': __("Home directory {ur_home_path} not found"), + }, + # проверить наличие подключенных ресурсов + {'name': 'domain_user:check_mount', + 'condition': lambda Get: any(x and isMount(x) + for x in + Get('cl_client_user_mount_path')), + 'else_error': __("Remote user resources not found") + }, + # установить время выхода из сеанса + {'name': 'domain_user:set_logout_date', + 'method': 'Client.setLogoutDate(ur_home_path,ur_uid,ur_gid)' + }, + # выполнять ли синхронизацию + {'name': 'domain_user:domain_sync', + 'condition': lambda Get: Get('cl_client_sync_status') == 'success' and + Get('cl_client_sync') == 'on', + 'else_warning': __("The profile will not be uploaded to the domain") + }, + # переместить файлы из профиля в Moved + {'name': 'domain_user:move_home_dir', + 'message': __("Moving non-profile files to the Home/Moved directory"), + 'method': 'Client.moveHomeDir(ur_home_path,"Moved","homes",' 'cl_moved_skip_path)', }, - # архивировать симлинки - {'name':'domain_sync:tar_symlinks', - 'method':'Client.tarSymLinks(ur_uid,ur_gid,ur_home_path,' - 'cl_sync_del_path,cl_sync_skip_path)', - 'failed_error':_("Failed to make a links archive") + # архивировать симлинки + {'name': 'domain_sync:tar_symlinks', + 'method': 'Client.tarSymLinks(ur_uid,ur_gid,ur_home_path,' + 'cl_sync_del_path,cl_sync_skip_path)', + 'failed_error': _("Failed to make a links archive") }, - # закачать профиль пользователя в домен - {'name':'domain_sync:sync_logout', - 'method':'Client.syncLogoutProfile(cl_remote_host,ur_uid,' + # закачать профиль пользователя в домен + {'name': 'domain_sync:sync_logout', + 'method': 'Client.syncLogoutProfile(cl_remote_host,ur_uid,' 'ur_gid,ur_home_path,"unix",cl_client_profile_name,' 'cl_client_symlinks)', }, - # удалить файлы, которые могут помешать следующему входу в сеанс - {'name':'domain_sync:remove_noise_files', - 'message':__("Removing hindering files"), - 'method':'Client.removeNoiseFiles(ur_home_path)' - }, - # удалить "личные" файлы - {'name':'domain_sync:remove_private_files', - 'message':__("Removing user private files"), - 'method':'Client.removePrivateFiles(ur_home_path)' - }, - # удалить пользовательские ключи ядра - {'name':'domain_user!:clear_user_key', - 'message':__("Clearing user keys"), - 'method':'Client.clearUserKey(ur_login)' - }, - # отключить пользовательские ресурсы - {'name':'check_mount!:umount_user_res', - 'message':__("Umounting user resources"), - 'method':'Client.umountUserRes(desktop.ur_mount_dirs)', - }, - # установить статус синхронизации - {'name':'domain_sync:success_sync', - 'message':__("Modified user profile saved in the domain"), - 'method':'Client.setSyncStatus(ur_home_path,ur_uid,ur_gid,' - '"success_logout")', - 'depend': Tasks.success_all('sync_logout','check_mount') - }, - {'name':'domain_sync:failed', - 'error':__("Modified user profile saved in the domain with errors"), - 'method':'Client.setSyncStatus(ur_home_path,ur_uid,ur_gid,' - '"error")', - 'depend': Tasks.hasnot('success_sync') - }, - {'name':'umount_allres', - 'method':'Desktop.umountUserRes(ur_home_path)', + # удалить файлы, которые могут помешать следующему входу в сеанс + {'name': 'domain_sync:remove_noise_files', + 'message': __("Removing hindering files"), + 'method': 'Client.removeNoiseFiles(ur_home_path)' + }, + # удалить "личные" файлы + {'name': 'domain_sync:remove_private_files', + 'message': __("Removing user private files"), + 'method': 'Client.removePrivateFiles(ur_home_path)' + }, + # удалить пользовательские ключи ядра + {'name': 'domain_user!:clear_user_key', + 'message': __("Clearing user keys"), + 'method': 'Client.clearUserKey(ur_login)' + }, + # отключить пользовательские ресурсы + {'name': 'check_mount!:umount_user_res', + 'message': __("Umounting user resources"), + 'method': 'Client.umountUserRes(desktop.ur_mount_dirs)', + }, + # установить статус синхронизации + {'name': 'domain_sync:success_sync', + 'message': __("Modified user profile saved in the domain"), + 'method': 'Client.setSyncStatus(ur_home_path,ur_uid,ur_gid,' + '"success_logout")', + 'depend': Tasks.success_all('sync_logout', 'check_mount') + }, + {'name': 'domain_sync:failed', + 'error': __("Modified user profile saved in the domain with errors"), + 'method': 'Client.setSyncStatus(ur_home_path,ur_uid,ur_gid,' + '"error")', + 'depend': Tasks.hasnot('success_sync') + }, + {'name': 'umount_allres', + 'method': 'Desktop.umountUserRes(ur_home_path)', } - ] + ] diff --git a/pym/client/utils/cl_passwd.py b/pym/client/utils/cl_passwd.py index 1fc237a..23f8bb4 100644 --- a/pym/client/utils/cl_passwd.py +++ b/pym/client/utils/cl_passwd.py @@ -1,6 +1,6 @@ -#-*- coding: utf-8 -*- +# -*- coding: utf-8 -*- -# Copyright 2013 Calculate Ltd. http://www.calculate-linux.org +# Copyright 2013-2015 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. @@ -15,23 +15,24 @@ # limitations under the License. import sys -from os import path -from calculate.core.server.func import Action,Tasks -from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate +from calculate.core.server.func import Action +from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate from calculate.lib.utils.files import FilesError from calculate.desktop.desktop import DesktopError from calculate.client.client import ClientError from calculate.lib.cl_template import TemplatesError -setLocalTranslate('cl_client3',sys.modules[__name__]) +_ = lambda x: x +setLocalTranslate('cl_client3', sys.modules[__name__]) __ = getLazyLocalTranslate(_) + class ClPasswdAction(Action): """ Изменить пароль доменного пользователя """ # ошибки, которые отображаются без подробностей - native_error = (FilesError,DesktopError,TemplatesError,ClientError) + native_error = (FilesError, DesktopError, TemplatesError, ClientError) successMessage = (__("{cl_client_login}'s password changed\n" "This modification will be applied when " @@ -41,7 +42,7 @@ class ClPasswdAction(Action): # список задач для действия tasks = [ - {'name':'change_passwd', - 'method':'Client.clientPasswd(cl_client_login,ur_uid,ur_gid,' - 'ur_home_path,ur_user_new_pw,ur_user_pw)', + {'name': 'change_passwd', + 'method': 'Client.clientPasswd(cl_client_login,ur_uid,ur_gid,' + 'ur_home_path,ur_user_new_pw,ur_user_pw)', }] diff --git a/pym/client/variables/action.py b/pym/client/variables/action.py index 96c9050..0717c84 100644 --- a/pym/client/variables/action.py +++ b/pym/client/variables/action.py @@ -1,4 +1,4 @@ -#-*- coding: utf-8 -*- +# -*- coding: utf-8 -*- # Copyright 2008-2013 Calculate Ltd. http://www.calculate-linux.org # @@ -14,14 +14,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os import sys -from os import path -from calculate.lib.datavars import (Variable,VariableError,ReadonlyVariable, - ActionVariable) +from calculate.lib.datavars import ActionVariable from calculate.lib.cl_lang import setLocalTranslate -setLocalTranslate('cl_client3',sys.modules[__name__]) + +setLocalTranslate('cl_client3', sys.modules[__name__]) + class VariableAcClientMerge(ActionVariable): """ @@ -30,34 +29,36 @@ class VariableAcClientMerge(ActionVariable): """ nonchroot = True - def action(self,cl_action): - if cl_action in ("merge","domain","undomain"): - ret = "on" + def action(self, cl_action): + if cl_action in ("merge", "domain", "undomain"): + return "on" return "off" + class VariableAcClientDomain(ActionVariable): """ Action variable which has value "on" for domain action """ nonchroot = True - def action(self,cl_action): + def action(self, cl_action): remoteHost = self.Get("cl_remote_host") remoteAuth = self.Get("os_remote_auth") if cl_action == "domain": return "on" - elif ((cl_action in ("merge",'sync') and self.Get('cl_merge_pkg')) - and remoteHost and remoteAuth): + elif ((cl_action in ("merge", 'sync') and self.Get('cl_merge_pkg')) + and remoteHost and remoteAuth): return "on" return "off" + class VariableAcClientUndomain(ActionVariable): """ Action variable which has value "on" for undomain action """ nonchroot = True - def action(self,cl_action): + def action(self, cl_action): if cl_action in ("undomain",): return "on" return "off" diff --git a/pym/client/variables/client.py b/pym/client/variables/client.py index 2cb6009..32fbae8 100644 --- a/pym/client/variables/client.py +++ b/pym/client/variables/client.py @@ -1,6 +1,6 @@ -#-*- coding: utf-8 -*- +# -*- coding: utf-8 -*- -# Copyright 2008-2013 Calculate Ltd. http://www.calculate-linux.org +# Copyright 2008-2015 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. @@ -18,12 +18,13 @@ import os import sys from os import path import re -from calculate.lib.datavars import (Variable,VariableError,ReadonlyVariable, - ReadonlyTableVariable,FieldValue) -from calculate.lib.cl_template import iniParser -from calculate.lib.utils.files import (readLinesFile,isMount,readFile, find, - FindFileType) -from calculate.lib.utils.common import getValueFromCmdLine,cmpVersion +from calculate.lib.datavars import (Variable, VariableError, ReadonlyVariable, + ReadonlyTableVariable, FieldValue, + HumanReadable) +from calculate.lib.cl_ini_parser import iniParser +from calculate.lib.utils.files import (isMount, readFile, find, + FindFileType) +from calculate.lib.utils.common import getValueFromCmdLine from calculate.lib.utils.portage import isPkgInstalled from calculate.lib.variables.user import VariableUrLogin from calculate.lib.convertenv import convertEnv @@ -37,7 +38,10 @@ import pwd from calculate.client.client import Client from calculate.lib.cl_lang import setLocalTranslate -setLocalTranslate('cl_client3',sys.modules[__name__]) + +_ = lambda x: x +setLocalTranslate('cl_client3', sys.modules[__name__]) + class VariableClRemoteHost(Variable): """ @@ -45,6 +49,7 @@ class VariableClRemoteHost(Variable): """ value = "" + class VariableClRemoteHostNew(Variable): """ IP or domain name of CDS @@ -59,22 +64,24 @@ class VariableClRemoteHostNew(Variable): self.label = _("Domain IP") self.help = _("domain") - def check(self,value): + def check(self, value): if self.Get('cl_client_mount_set') == 'off': if self.Get('cl_localhost_set') == 'off': if self.Get('cl_remote_host') == '': if not value: raise VariableError(_("Please specify the domain")) - elif not isOpenPort(value,445): + elif not isOpenPort(value, 445): raise VariableError( _("The specified address is not available")) + class VariableClRemoteHostLive(ReadonlyVariable): """ Remote host from /proc/cmdline param domain """ + def get(self): - return getValueFromCmdLine("calculate","domain") or "" + return getValueFromCmdLine("calculate", "domain") or "" class VariableOsRemoteAuth(Variable): @@ -102,14 +109,16 @@ class VariableClRemotePw(Variable): self.help = _("specify the domain password") def get(self): - return getValueFromCmdLine("calculate","domain_pw") or "" + return getValueFromCmdLine("calculate", "domain_pw") or "" + class VariableClMovedSkipPath(Variable): """ Skip "Moved" path """ type = "list" - value = ['Disks','Home','Moved','FTP','Desktop', 'Share'] + value = ['Disks', 'Home', 'Moved', 'FTP', 'Desktop', 'Share'] + class VariableClSyncSkipPath(Variable): """ @@ -117,12 +126,13 @@ class VariableClSyncSkipPath(Variable): """ type = "list" value = [".googleearth", "Home", "Disks", "FTP", - 'Share', ".local/share/akonadi/db_data", ".VirtualBox", - ".mozilla/firefox/calculate.default/urlclassifier3.sqlite", - ".local/share/mime/mime.cache", ".gvfs", - ".kde4/share/apps/nepomuk/repository/main/data", ".logout", - ".Xauthority", ".thumbnails", ".mozilla/firefox/*/Cache", - ".kde4/socket-*", ".cache/", ".local/share/Trash"] + 'Share', ".local/share/akonadi/db_data", ".VirtualBox", + ".mozilla/firefox/calculate.default/urlclassifier3.sqlite", + ".local/share/mime/mime.cache", ".gvfs", + ".kde4/share/apps/nepomuk/repository/main/data", ".logout", + ".Xauthority", ".thumbnails", ".mozilla/firefox/*/Cache", + ".kde4/socket-*", ".cache/", ".local/share/Trash"] + class VariableClSyncDelPath(Variable): """ @@ -132,10 +142,12 @@ class VariableClSyncDelPath(Variable): value = [".kde4/share/config/phonondevicesrc", ".kde4/cache-*", ".kde4/tmp-*"] + class VariableClProfileAllSet(Variable): type = "bool" value = "off" + class VariableClClientSync(Variable): type = "bool" value = "on" @@ -147,6 +159,7 @@ class VariableClClientSync(Variable): self.label = _("Synchronize the user profile") self.help = _("synchronize user preferences") + class VariableClLocalhostSet(Variable): """ Using autopartition @@ -163,24 +176,26 @@ class VariableClLocalhostSet(Variable): self.help = _("remove the domain connection settings") def choice(self): - return [("off",_("Domain workstation")), - ("on",_("Local workstation"))] + return [("off", _("Domain workstation")), + ("on", _("Local workstation"))] - def check(self,value): + def check(self, value): if self.Get('cl_client_mount_set') == 'off': if self.Get('cl_remote_host') == '' and value == "on": raise VariableError(_("The workstation is not in the domain")) if self.Get('cl_remote_host') != '' and value == "off": - raise VariableError(_("The workstation is already in the domain %s") - %self.Get('cl_remote_host') + "\n" + - _("Before joining the domain, " - "you need to remove it from the previous domain")) + raise VariableError( + _("The workstation is already in the domain %s") + % self.Get('cl_remote_host') + "\n" + + _("Before joining the domain, " + "you need to remove it from the previous domain")) + + # def get(self): + # if self.Get('cl_remote_host') == '': + # return "on" + # else: + # return "off" - #def get(self): - # if self.Get('cl_remote_host') == '': - # return "on" - # else: - # return "off" class VariableClClientMountSet(Variable): """ @@ -195,7 +210,8 @@ class VariableClClientMountSet(Variable): self.label = _("Only mount the domain resource") self.help = _("only mount the [remote] domain resource") -class VariableUrUserPw(Variable,LdapHelper): + +class VariableUrUserPw(Variable, LdapHelper): """ Current user password """ @@ -211,9 +227,8 @@ class VariableUrUserPw(Variable,LdapHelper): def checkUserPwdLDAP(self, server, userDN, password): """Check unix user password on server""" - ldapInit = ldap.initialize("ldap://%s"%server) - errMessage = "" - try: + ldapInit = ldap.initialize("ldap://%s" % server) + try: ldapInit.bind_s(userDN, password) except ldap.INVALID_CREDENTIALS: raise VariableError(_("Wrong password")) @@ -222,7 +237,7 @@ class VariableUrUserPw(Variable,LdapHelper): raise VariableError(errMessage) return True - def check(self,value): + def check(self, value): if not value: raise VariableError(_("Empty password")) # читаем os_remote_auth, так как при смене пароля @@ -232,9 +247,10 @@ class VariableUrUserPw(Variable,LdapHelper): ldapObj = self.getLdapUserObject() if ldapObj: usersDN = ldapObj.getUsersDN() - userDN = ldapObj.addDN("uid=%s"%self.Get('ur_login'), - usersDN) - self.checkUserPwdLDAP(server,userDN,value) + userDN = ldapObj.addDN("uid=%s" % self.Get('ur_login'), + usersDN) + self.checkUserPwdLDAP(server, userDN, value) + class VariableUrUserNewPw(Variable): """ @@ -250,10 +266,11 @@ class VariableUrUserNewPw(Variable): self.label = _("New password") self.help = _("new user password") - def check(self,value): + def check(self, value): if not value: raise VariableError(_("Empty password")) + class VariableClClientLogin(VariableUrLogin): """ User Login @@ -264,30 +281,31 @@ class VariableClClientLogin(VariableUrLogin): def choice(self): loginChoice = VariableUrLogin.choice(self) if self.Get('cl_action') == 'passwd': - return filter(lambda x:x != "root",loginChoice) + return filter(lambda x: x != "root", loginChoice) else: return loginChoice - def check(self,value): + def check(self, value): """Does user exist""" if not value in self.choice() and self.Get('cl_action') == 'logout': raise VariableError(_("X session users not found")) if value == "": raise VariableError(_("Please specify the user")) if value == "root" and self.Get('cl_action') == 'passwd': - raise VariableError(\ + raise VariableError( _("This action can be executed by a non-root user only")) try: pwd.getpwnam(value).pw_gid - except: - raise VariableError(_("User %s does not exist")%value) + except (TypeError, KeyError): + raise VariableError(_("User %s does not exist") % value) def get(self): - if (self.Get('cl_action') == 'passwd' and - self.Get('ur_login') != 'root'): + if (self.Get('cl_action') == 'passwd' and + self.Get('ur_login') != 'root'): return self.Get('ur_login') return "" + class VariableClClientRelevanceSet(ReadonlyVariable): """ Актуальны ли сейчас выполненные шаблоны @@ -296,32 +314,36 @@ class VariableClClientRelevanceSet(ReadonlyVariable): def get(self): # если происходят действия ввода или вывода из домена - if (self.Get('cl_action') in ("domain","undomain") and - self.Get('cl_client_mount_set') == 'off'): + if (self.Get('cl_action') in ("domain", "undomain") and + self.Get('cl_client_mount_set') == 'off'): return "off" # если изменился домен if self.Get('cl_remote_host') != self.Get("os_remote_auth"): return "off" if (self.Get('cl_remote_host') and - not isMount(self.Get('cl_client_remote_path'))): + not isMount(self.Get('cl_client_remote_path'))): return "off" return "on" + class VariableClClientRemotePath(Variable): """ Путь для монитрования //domain/remote """ value = "/var/calculate/remote" + class VariableClClientProfileName(Variable): """ Название удаленного профиля (CLD,CLDX,all) """ + def get(self): return ("all" if self.Get('cl_profile_all_set') == 'on' else self.Get('os_linux_shortname')) -class VariableClLdapData(ldapUser,ReadonlyVariable): + +class VariableClLdapData(ldapUser, ReadonlyVariable): """ Внутренняя переменная, содержащая объект для доступа к данным LDAP """ @@ -341,7 +363,7 @@ class VariableClLdapData(ldapUser,ReadonlyVariable): if usersDN: partDN = "ou=Worked,ou=Replication,ou=LDAP" servicesDN = "ou=Services" - baseDN = usersDN.rpartition(servicesDN+",")[2] + baseDN = usersDN.rpartition(servicesDN + ",")[2] replDN = self.addDN(partDN, servicesDN, baseDN) return replDN return False @@ -353,8 +375,8 @@ class VariableClLdapData(ldapUser,ReadonlyVariable): bindDn, bindPw, host = connectData replDN = self.getReplDN() # find string for service replication branch - userAndOsName = "%s@%s"%(userName,osLinuxShort) - findAttr = "uid=%s"%userAndOsName + userAndOsName = "%s@%s" % (userName, osLinuxShort) + findAttr = "uid=%s" % userAndOsName # connect to LDAP if not self.ldapConnect(bindDn, bindPw, host): return False @@ -363,14 +385,13 @@ class VariableClLdapData(ldapUser,ReadonlyVariable): return resSearch return False - def _gethostbyname(self,hostname): + def _gethostbyname(self, hostname): try: return gethostbyname(hostname) - except: - pass - return None + except Exception: + return None - def getNameRemoteServer(self,userName, osLinuxShort, curHost): + def getNameRemoteServer(self, userName, osLinuxShort, curHost): """ Get remote domain hostname or empty if profile is keeped on current server @@ -399,7 +420,7 @@ class VariableClLdapData(ldapUser,ReadonlyVariable): usersDN = self.getUsersDN() partDN = "ou=Replication,ou=LDAP" servicesDN = "ou=Services" - baseDN = usersDN.rpartition(servicesDN+",")[2] + baseDN = usersDN.rpartition(servicesDN + ",")[2] replDN = self.addDN(partDN, servicesDN, baseDN) findAttr = "ou=Worked" # connect to LDAP @@ -417,11 +438,13 @@ class VariableClReplicationHost(ReadonlyVariable): """ Удаленный сервер при репликации, который содержит актуальный профиль """ + def get(self): return self.Get('cl_ldap_data').getNameRemoteServer( - self.Get('ur_login'),self.Get('cl_client_profile_name'), + self.Get('ur_login'), self.Get('cl_client_profile_name'), self.Get('cl_remote_host')) + class VariableClClientUserMountData(ReadonlyTableVariable): """ Таблица монтирования ресурсов @@ -431,30 +454,36 @@ class VariableClClientUserMountData(ReadonlyTableVariable): 'cl_client_user_mount_path', 'cl_client_user_mount_host'] - def get(self): + def get(self, hr=HumanReadable.No): home = path.split(self.Get('ur_home_path'))[0] envFile = self.Get('cl_env_server_path') + def generate(): - yield ("share","share",path.join(self.Get('ur_home_path'),"Share"), - self.Get('cl_remote_host')) - yield ("unix","unix",path.join(home,".%s"%self.Get('ur_login')), - self.Get('cl_remote_host')) - yield ("homes","homes",path.join(self.Get('ur_home_path'),"Home"), - self.Get('cl_remote_host')) - if convertEnv().getVar("ftp","host"): - yield ("ftp","ftp",path.join(self.Get('ur_home_path'),"FTP"), - self.Get('cl_remote_host')) + yield ( + "share", "share", path.join(self.Get('ur_home_path'), "Share"), + self.Get('cl_remote_host')) + yield ( + "unix", "unix", path.join(home, ".%s" % self.Get('ur_login')), + self.Get('cl_remote_host')) + yield ( + "homes", "homes", path.join(self.Get('ur_home_path'), "Home"), + self.Get('cl_remote_host')) + if convertEnv().getVar("ftp", "host"): + yield ("ftp", "ftp", path.join(self.Get('ur_home_path'), "FTP"), + self.Get('cl_remote_host')) else: - yield ("ftp",'','','') + yield ("ftp", '', '', '') if self.Get('cl_replication_host'): - yield ("remote_profile","unix", - path.join(home,".%s.remote"%self.Get('ur_login')), + yield ("remote_profile", "unix", + path.join(home, ".%s.remote" % self.Get('ur_login')), self.Get('cl_replication_host')) else: - yield ("remote_profile",'unix','','') + yield ("remote_profile", 'unix', '', '') + return list(generate()) -class VariableClClientUserMountName(FieldValue,ReadonlyVariable): + +class VariableClClientUserMountName(FieldValue, ReadonlyVariable): """ Название удаленного ресурса """ @@ -463,7 +492,7 @@ class VariableClClientUserMountName(FieldValue,ReadonlyVariable): column = 0 -class VariableClClientUserMountResource(FieldValue,ReadonlyVariable): +class VariableClClientUserMountResource(FieldValue, ReadonlyVariable): """ Название удаленного ресурса """ @@ -471,7 +500,8 @@ class VariableClClientUserMountResource(FieldValue,ReadonlyVariable): source_variable = "cl_client_user_mount_data" column = 1 -class VariableClClientUserMountPath(FieldValue,ReadonlyVariable): + +class VariableClClientUserMountPath(FieldValue, ReadonlyVariable): """ Путь подключения удаленного ресурса """ @@ -479,7 +509,8 @@ class VariableClClientUserMountPath(FieldValue,ReadonlyVariable): source_variable = "cl_client_user_mount_data" column = 2 -class VariableClClientUserMountHost(FieldValue,ReadonlyVariable): + +class VariableClClientUserMountHost(FieldValue, ReadonlyVariable): """ Удаленный сервер """ @@ -487,12 +518,14 @@ class VariableClClientUserMountHost(FieldValue,ReadonlyVariable): source_variable = "cl_client_user_mount_data" column = 3 -class SyncHelper: + +class SyncHelper(object): """ Вспомогательный объект для определения статуса синхронизации и времени по конфигурационным файлам """ - def getSyncStatus(self,rpath): + + def getSyncStatus(self, rpath): """ Получить status_sync из desktop файла """ @@ -501,9 +534,9 @@ class SyncHelper: if os.path.exists(fileConfig): objConfig = iniParser(fileConfig) data = self.getDataInConfig("main", ["status_sync"], - objConfig) + objConfig) if data: - return data.get("status_sync","") + return data.get("status_sync", "") return "" def getDataInConfig(self, section, listVars, objConfig): @@ -512,19 +545,18 @@ class SyncHelper: """ varsConfig = {} for varName in listVars: - varsConfig[varName] = objConfig.getVar(section,varName) + varsConfig[varName] = objConfig.getVar(section, varName) if objConfig.getError(): return False return varsConfig - - def convertDate(self,strdate,dateformat="%Y-%m-%d %H:%M:%S"): + def convertDate(self, strdate, dateformat="%Y-%m-%d %H:%M:%S"): """ Convert date from string format (dateformat) to stuct or None """ if strdate: try: - return time.strptime(strdate,dateformat) + return time.strptime(strdate, dateformat) except ValueError: pass return "" @@ -541,73 +573,83 @@ class SyncHelper: timeLogout = data["date_logout"] timeConfig = data["date"] dates = filter(None, - [self.convertDate(timeLogout), - self.convertDate(timeConfig)]) + [self.convertDate(timeLogout), + self.convertDate(timeConfig)]) if dates: return dates[0] return "" - def checkNeedSync(self,homeDir,rpath,curTimeObj,curStatusSync,osLinuxShort): + def checkNeedSync(self, homeDir, rpath, curTimeObj, curStatusSync, + osLinuxShort): """ Проверить необходимость синхронизации текущего профиля с удаленным """ # profile directory - #fileConfig = os.path.join(homeDir, Client.configFileServer) + # fileConfig = os.path.join(homeDir, Client.configFileServer) pathProfile = os.path.join(rpath, osLinuxShort) - #if readFile(fileConfig).strip(): + # if readFile(fileConfig).strip(): # return True fileSoftConfigThis = os.path.join(pathProfile, - Client.configFileSoft) + Client.configFileSoft) fileSoftConfigCur = os.path.join(homeDir, - Client.configFileSoft) - xSessionCur = iniParser(fileSoftConfigCur).getVar('main','xsession') - xSessionThis = iniParser(fileSoftConfigThis).getVar('main','xsession') + Client.configFileSoft) + xSessionCur = iniParser(fileSoftConfigCur).getVar('main', 'xsession') + xSessionThis = iniParser(fileSoftConfigThis).getVar('main', 'xsession') # check profile date on current server - #fileConfigThis = os.path.join(pathProfile, Client.configFileDesktop) - #if iniParser(fileConfigThis).getVar('main','status_sync') == "success": + # fileConfigThis = os.path.join(pathProfile, Client.configFileDesktop) + # if iniParser(fileConfigThis).getVar('main','status_sync') == "success": # self.setVarToConfig("main", {"status_sync":"success_mount"}, # fileConfigThis) thisTimeObj = self.getDateObjClientConf(pathProfile) if curStatusSync == "success_logout" and \ - xSessionCur == xSessionThis and \ - thisTimeObj and curTimeObj and \ - curTimeObj >= thisTimeObj: + xSessionCur == xSessionThis and \ + thisTimeObj and curTimeObj and \ + curTimeObj >= thisTimeObj: return False return True -class VariableClClientSyncTime(SyncHelper,ReadonlyVariable): + +class VariableClClientSyncTime(SyncHelper, ReadonlyVariable): """ Текущее время синхронизации профиля """ + def get(self): return self.getDateObjClientConf(self.Get('ur_home_path')) -class VariableClClientPackTime(SyncHelper,ReadonlyVariable): + +class VariableClClientPackTime(SyncHelper, ReadonlyVariable): """ Время комады упаковки профиля """ + def get(self): return str(float(time.time())) -class VariableClClientSyncStatus(SyncHelper,ReadonlyVariable): + +class VariableClClientSyncStatus(SyncHelper, ReadonlyVariable): """ Текущий статус синхронизации профиля """ + def get(self): return self.getSyncStatus(self.Get('ur_home_path')) -class VariableClClientLocalSyncTime(SyncHelper,ReadonlyVariable): + +class VariableClClientLocalSyncTime(SyncHelper, ReadonlyVariable): """ Текущий статус синхронизации профиля """ + def get(self): return self.getDateObjClientConf( - path.join( + path.join( self.Select('cl_client_user_mount_path', - where='cl_client_user_mount_name',eq='unix', - limit=1),self.Get('cl_client_profile_name'))) + where='cl_client_user_mount_name', eq='unix', + limit=1), self.Get('cl_client_profile_name'))) -class VariableClClientSyncReplicationSet(SyncHelper,ReadonlyVariable): + +class VariableClClientSyncReplicationSet(SyncHelper, ReadonlyVariable): """ Нужно ли синхронизировать текущий профиль с удаленным доменом """ @@ -617,16 +659,18 @@ class VariableClClientSyncReplicationSet(SyncHelper,ReadonlyVariable): if not self.Get('cl_replication_host'): return "off" profilePath = self.Select('cl_client_user_mount_path', - where='cl_client_user_mount_name', - eq='remote_profile',limit=1) + where='cl_client_user_mount_name', + eq='remote_profile', limit=1) if self.Get('cl_action') == 'login' and not isMount(profilePath): raise VariableError(_("Remote profile not mounted")) - return "on" if self.checkNeedSync(self.Get('ur_home_path'),profilePath, - self.Get('cl_client_sync_time'), - self.Get('cl_client_sync_status'), - self.Get('cl_client_profile_name')) else "off" + return "on" if self.checkNeedSync(self.Get('ur_home_path'), profilePath, + self.Get('cl_client_sync_time'), + self.Get('cl_client_sync_status'), + self.Get( + 'cl_client_profile_name')) else "off" + -class VariableClClientSyncLocalSet(SyncHelper,ReadonlyVariable): +class VariableClClientSyncLocalSet(SyncHelper, ReadonlyVariable): """ Нужно ли синхронизировать текущий профиль с локальным доменом """ @@ -636,44 +680,52 @@ class VariableClClientSyncLocalSet(SyncHelper,ReadonlyVariable): if not self.Get('cl_remote_host'): return "off" profilePath = self.Select('cl_client_user_mount_path', - where='cl_client_user_mount_name', - eq='unix',limit=1) + where='cl_client_user_mount_name', + eq='unix', limit=1) if self.Get('cl_action') == 'login' and not isMount(profilePath): raise VariableError(_("Remote profile not mounted")) - return "on" if self.checkNeedSync(self.Get('ur_home_path'),profilePath, - self.Get('cl_client_sync_time'), - self.Get('cl_client_sync_status'), - self.Get('cl_client_profile_name')) else "off" + return "on" if self.checkNeedSync(self.Get('ur_home_path'), profilePath, + self.Get('cl_client_sync_time'), + self.Get('cl_client_sync_status'), + self.Get( + 'cl_client_profile_name')) else "off" + class VariableClClientSymlinks(ReadonlyVariable): """ Список симлинков в пользовательском профиле """ + def get(self): skipFiles = (self.Get('cl_sync_del_path') + - self.Get('cl_sync_skip_path')) - reSkip = re.compile("|".join(map(lambda x:x.replace("*",".*"), - skipFiles))).search - return filter(lambda x:not reSkip(x), - find(self.Get('ur_home_path'),onefilesystem=True, - filetype=FindFileType.SymbolicLink)) + self.Get('cl_sync_skip_path')) + reSkip = re.compile("|".join(map(lambda x: x.replace("*", ".*"), + skipFiles))).search + return filter(lambda x: not reSkip(x), + find(self.Get('ur_home_path'), onefilesystem=True, + filetype=FindFileType.SymbolicLink)) + class VariableClClientNscdCache(Variable): """ Частота обновления кэша nscd при работе в домене в часах """ + class VariableClCifsVer(ReadonlyVariable): """ Версия модуля CIFS """ + def get(self): return readFile("/sys/module/cifs/version") + class VariableClRsyncVer(ReadonlyVariable): """ Версия rsync """ + def get(self): data = isPkgInstalled('net-misc/rsync') if data: diff --git a/pym/client/wsdl_client.py b/pym/client/wsdl_client.py index 019baef..ce65175 100644 --- a/pym/client/wsdl_client.py +++ b/pym/client/wsdl_client.py @@ -1,6 +1,6 @@ -#-*- coding: utf-8 -*- +# -*- coding: utf-8 -*- -# Copyright 2012-2013 Calculate Ltd. http://www.calculate-linux.org +# Copyright 2012-2015 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. @@ -28,6 +28,7 @@ import calculate.client.client as client from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate +_ = lambda x: x setLocalTranslate('cl_client3', sys.modules[__name__]) __ = getLazyLocalTranslate(_) @@ -63,15 +64,16 @@ class Wsdl(WsdlBase): ClientError, DesktopError), # значения по умолчанию для переменных этого метода 'setvars': {'cl_action!': 'domain', - 'cl_protect_use_set!':'off' - }, + 'cl_protect_use_set!': 'off' + }, 'guivars': {'cl_localhost_set!': lambda dv: ( "on" if dv.Get('cl_remote_host') == '' else 'off')}, # описание груп (список лямбда функций) 'groups': [ lambda group: group(_("Domain"), normal=( - 'cl_localhost_set', 'cl_remote_host_new', + 'cl_localhost_set', + 'cl_remote_host_new', 'cl_remote_pw'), expert=('cl_client_mount_set', 'cl_templates_locate',