class Update: """ Update logic object Has fundamental method update for system update """ def __init__(self): self.homeDir = "" self.clTempl = None self.clVars = None def applyTemplates(self): """Apply templates for user""" if self.clTempl: self.closeClTemplate() self.clVars.Set("cl_chroot_path","/", True) self.clVars.Set("cl_merge_set","on",True) self.clTempl = ProgressTemplate(self.setProgress,self.clVars, cltObj=True,cltFilter=True, printSUCCESS=self.printSUCCESS, printWARNING=self.printWARNING, askConfirm=self.askConfirm, dispatchConf=self.dispatchConf, printERROR=self.printERROR) dirsFiles = self.clTempl.applyTemplates() if self.clTempl.getError(): self.printERROR(self.clTempl.getError().strip()) return False else: return dirsFiles def initVars(self,datavars=None): """Primary variables initialization""" if not datavars: self.clVars = DataVarsDesktop() self.clVars.importDesktop() self.clVars.flIniFile() else: self.clVars = datavars def closeClTemplate(self,*args): if self.clTempl: if self.clTempl.cltObj: self.clTempl.cltObj.closeFiles() self.clTempl.closeFiles() self.clTempl = None @safetyWrapper(native_errors=(TemplatesError,UpdateError), man_int=__("Update manually interrupted"), post_action=closeClTemplate, success_message=__("Update finished!")) def update(self, datavars=None): """ Creating user profile and userdir """ self.initVars(datavars) return bool(self.applyTemplates())
class Install(color_print): """Primary class for templates appling and system installation""" def __init__(self): self.clVars = None self.clTempl = None self.listDisksOptions = [] self.listBindsOptions = [] self.listSwapsOptions = [] self.startMessage = "" self.lenStartMessage = 0 self.stdoutHide = None self.stderrHide = None # refresh information about LVM refreshLVM() # refresh information about device in udevadm info refreshUdev() def setNoColor(self): self.color = False def initVars(self,datavars=None): """Primary initialization of variables""" if not datavars: self.clVars = DataVarsInstall() self.clVars.importInstall() self.clVars.flIniFile() else: self.clVars = datavars def canInstallGrub2(self,target): """Check that system has grub2 in current and installed system""" if self.clVars.Get('os_grub2_path'): return bool( filter(lambda x:x.startswith('grub-1.99') or \ x.startswith('grub-2'), listDirectory('/var/db/pkg/sys-boot'))) return False def prepareBoot(self,targetDistr): """Prepare system for boot""" if self.clVars.Get('os_install_root_type') == "flash": self.installSyslinuxBootloader(targetDistr) else: if self.canInstallGrub2(targetDistr): self.installGrub2Bootloader(targetDistr) else: self.installLegacyGrubBootloader(targetDistr) def closeClTemplate(self,error=None): if self.clTempl: if self.clTempl.cltObj: self.clTempl.cltObj.closeFiles() self.clTempl.closeFiles() self.clTempl = None def applyTemplatesStartup(self): """Apply templates for root of system.""" #self.clVars.Set("cl_root_path","/", True) self.clVars.Set("cl_chroot_path","/", True) templates_locate = self.clVars.Get('cl_templates_locate') # cltObj = True if 'clt' in templates_locate else False dirs_list, files_list = ([],[]) useClt = "clt" in templates_locate self.clVars.Set("cl_template_path", map(lambda x:x[1], filter(lambda x:x[0] in templates_locate, zip(self.clVars.Get('cl_template_location'), self.clVars.Get('cl_template_path')))), True) self.clTempl = ProgressTemplate(self.setProgress, self.clVars, cltObj=useClt, cltFilter=True if self.clVars.Get('cl_merge_set') == "on" \ else False, printSUCCESS=self.printSUCCESS, printWARNING=self.printWARNING, askConfirm=self.askConfirm, dispatchConf=self.dispatchConf, printERROR=self.printERROR) dirsFiles = self.clTempl.applyTemplates() try: if self.clTempl.getError(): self.printERROR(self.clTempl.getError()) return False except AttributeError: pass return dirsFiles def applyTemplatesFlash(self,directory): """Apply templates for root of system.""" #self.clVars.Set("cl_root_path",directory, True) self.clVars.Set("cl_chroot_path","/", True) self.clVars.Set("cl_chroot_grub","/", True) self.clVars.Set("cl_root_path",directory, True) self.clTempl = ProgressTemplate(self.setProgress,self.clVars, cltObj=False, printSUCCESS=self.printSUCCESS, printWARNING=self.printWARNING, askConfirm=self.askConfirm, printERROR=self.printERROR) dirsFiles = self.clTempl.applyTemplates() if self.clTempl.getError(): raise InstallError(self.clTempl.getError()) else: return dirsFiles def applyTemplates(self,directory,grubDirectory): """Apply templates for root of system.""" self.clVars.Set("cl_chroot_path",directory, True) self.clVars.Set("cl_chroot_grub",grubDirectory, True) clTemplateCltPath = \ filter(lambda x:path.exists(x), map(lambda x:pathJoin(directory,x), self.clVars.Get('cl_template_clt_path'))) self.clVars.Set('cl_template_clt_path',clTemplateCltPath,True) self.clTempl = ProgressTemplate(self.setProgress,self.clVars, cltFilter=False, printSUCCESS=self.printSUCCESS, printWARNING=self.printWARNING, askConfirm=self.askConfirm, printERROR=self.printERROR) dirsFiles = self.clTempl.applyTemplates() if self.clTempl.getError(): raise InstallError(self.clTempl.getError()) else: return dirsFiles def checkDuplicate(self,datalist,name,key=lambda x:x): """Check on duplicate and print error""" keydata = map(key,datalist) dupKey = set(filter(lambda x:keydata.count(x)>1, keydata)) if dupKey: self.printERROR(_("Duplicated {keyname}: {keylist}").format( keyname=name,keylist=",".join(dupKey))) return False return True def setVarList(self,varsList,matrix): """Set matrix to vars""" if not matrix: map(lambda x:self.clVars.Set(x,[],True),varsList) else: map(lambda x:self.clVars.Set(x[0],list(x[1]),True), zip(varsList,zip(*matrix))) def setDisks(self): """ TODO: remove check grub2_path in disk variables """ try: if not self.clVars.Get('os_grub2_path'): self.checkForLegacyGrub() else: self.checkForGrub2() except InstallError,e: error.append(e) return True
class Desktop: """ Desktop logic object Has fundamental method createHome for configure user profile """ # username userName = "" verbose = False def __init__(self): self.homeDir = "" self.clTempl = None self.clVars = None def createCryptDir(self,userName,uid,gud,userDir): """ Создать шифрование домашней директории, или подключить существующую """ userPwd = getKey(userName) if not userPwd or userPwd == "XXXXXXXX": raise DesktopError(_("User password not found")) ecryptfsPath = path.join('/home/.ecryptfs',userName) if path.exists(ecryptfsPath): for d in (".ecryptfs",".Private"): source,target = path.join(ecryptfsPath,d),path.join(userDir,d) if not path.lexists(target): os.symlink(source,target) try: if not mountEcryptfs(userName,userPwd,userDir): raise DesktopError(_("Failed to mount ecrypted data")) except CommonError as e: raise DesktopError(_("Failed to mount ecrypted data")+": \"%s\""%str(e)) else: tf = None try: # если профиль содержит только данные от бутстрапа core if isBootstrapDataOnly(userDir): if childMounts(userDir): raise DesktopError( _("Failed to create encrypt user profile")+":"+ _("User home directory contains mount points")) # поместить данные во временный tarfile calculateName = ".calculate" calculatePath = path.join(userDir,calculateName) tf = tempfile.TemporaryFile() with tarfile.open(fileobj=tf,mode='w:') as tarf: tarf.add(calculatePath,calculateName) tf.flush() tf.seek(0) # удалить эти данные shutil.rmtree(calculatePath) # создать шифрованные данные e = process('/usr/bin/ecryptfs-setup-private','-u',userName, '-b','-l',userPwd,stderr=STDOUT) if e.failed(): raise DesktopError(e.read()) # если были данные от бутстрапа, то распаковать их if tf: with tarfile.open(fileobj=tf,mode='r:') as tarf: tarf.extractall(userDir) except Exception as e: if tf: tf.seek(0) bakArchName = path.join(userDir,".calculate.tar.bz2") with open(bakArchName,'w') as f: f.write(tf.read()) raise DesktopError(str(e)+ _("Failed to create encrypt user profile")) finally: if tf: tf.close() def createUserDir(self, userName, uid, gid, userDir, mode=0700): """ Create user directory with need uid and gid """ if not path.exists(userDir): os.makedirs(userDir) if mode: os.chmod(userDir,mode) os.chown(userDir,uid,gid) return True else: raise DesktopError(_("Path %s exists") %userDir) def displayTemplatesApplied(self,dirsFiles): """ Display templates are applied (--verbose) """ self.printSUCCESS(_("The following files were changed")+":") for nameF in dirsFiles[1]: nameFile = nameF if nameFile[:1] != "/": nameFile = "/" + nameFile self.printSUCCESS(" "*5 + nameFile) def applyTemplatesFromUser(self): """Apply templates for user""" if self.clTempl: self.closeClTemplate() templates_locate = self.clVars.Get('cl_templates_locate') self.clVars.Set("cl_template_path", map(lambda x:x[1], filter(lambda x:x[0] in templates_locate, zip(self.clVars.Get('cl_template_location'), self.clVars.Get('cl_template_path')))), True) self.clTempl = ProgressTemplate(self.setProgress,self.clVars, cltObj=False, printERROR=self.printERROR, printWARNING=self.printWARNING, askConfirm=self.askConfirm, printSUCCESS=self.printSUCCESS, userProfile=True) dirsFiles = self.clTempl.applyTemplates() if self.clTempl.getError(): self.printERROR(self.clTempl.getError().strip()) return False else: return dirsFiles def initVars(self,datavars=None): """Primary variables initialization""" if not datavars: self.clVars = DataVarsDesktop() self.clVars.importDesktop() self.clVars.flIniFile() else: self.clVars = datavars def closeClTemplate(self): if self.clTempl: if self.clTempl.cltObj: self.clTempl.cltObj.closeFiles() self.clTempl.closeFiles() self.clTempl = None def umountUserRes(self, error): """ Umount user directory """ self.closeClTemplate() if error and self.homeDir: umountPaths = self.getMountUserPaths(self.homeDir) ret = True for umountPath in umountPaths: if not self.umountSleepPath(umountPath): ret = False break return ret @safetyWrapper(native_errors=(TemplatesError,DesktopError,CommonError), man_int=__("Configuration manually interrupted"), post_action=umountUserRes) def createHome(self, datavars=None): """ Creating user profile and userdir """ self.initVars(datavars) self.verbose = self.clVars.Get('cl_verbose_set') == 'on' #uid = os.getuid() #try: # realUserName = pwd.getpwuid(uid).pw_name #except: # realUserName = "" userName = self.clVars.Get("ur_login") uidGid = False if self.clVars.isModuleInstalled("client"): # domain host domain = self.clVars.Get("client.cl_remote_host") # authorized in domain or local hostAuth = self.clVars.Get("client.os_remote_auth") else: domain = "" hostAuth = "" uid = self.clVars.Get('ur_uid') gid = self.clVars.Get('ur_gid') if not uid or not gid: raise DesktopError(_("Failed to determine the user UID")) uid,gid = int(uid),int(gid) self.homeDir = self.clVars.Get('ur_home_path') rootPath = self.clVars.Get('cl_root_path') # real path to home dir self.homeDir = path.join(rootPath, self.homeDir[1:]) if not path.exists(self.homeDir): self.startTask(_("Creating the home directory for %s")%self.homeDir) self.createUserDir(userName,uid,gid,self.homeDir) self.endTask() if (self.clVars.Get('ur_home_crypt_set') == 'on' and self.clVars.Get('install.cl_autologin') != userName): self.createCryptDir(userName,uid,gid,self.homeDir) domainUser = self.clVars.Get('ur_domain_set') == 'on' lastTimestamp = templateFunction.getLastElog() iniEnv = path.join(self.homeDir,'.calculate/ini.env') userIni = iniParser(iniEnv) userTimestamp = userIni.getVar('main','elog').encode('utf-8') if (domainUser or not path.exists(iniEnv) or userTimestamp != lastTimestamp): # action - "user profile configuration" self.clVars.Set("cl_action", "desktop", True) # apply user profiles self.startTask(_("Setting up the user profile"),progress=True) dirsAndFiles = self.applyTemplatesFromUser() self.endTask() if not dirsAndFiles: raise DesktopError(_("Failed to apply user profile templates")) self.printSUCCESS(_("User account %s is configured")%userName + " ...") return True def getMountUserPaths(self, homeDir=False): """ Found user resources """ if not homeDir: userName = self.clVars.Get("ur_login") homeDir = self.clVars.Get("ur_home_path") if not homeDir: raise DesktopError(_("Failed to determine home directory")) dirStart, dirEnd = path.split(homeDir) mountProfileDir = path.join(dirStart, ".%s" %dirEnd) mountRemoteProfileDir = path.join(dirStart, ".%s.remote" %dirEnd) return filter(lambda x: x.startswith(homeDir) or\ x.startswith(mountProfileDir) or\ x.startswith(mountRemoteProfileDir), map(lambda x: x.split(" ")[1],\ open("/proc/mounts").readlines())) def execProg(self, cmdStrProg, inStr=False, envProg={}): """ Exec external program """ env_path = {"PATH":getpathenv()} env = {} env.update(os.environ.items() + env_path.items() + envProg.items()) retCode,programOut = runOsCommand(cmdStrProg,in_str=inStr,env_dict=env) if not retCode: return programOut return False def umountSleepPath(self, rpath): """ Unmount path, sleep by failed and repeat """ # check for mount if isMount(rpath): for waittime in [0,0.5,1,2]: time.sleep(waittime) if not self.execProg("umount %s"%rpath) is False \ or not isMount(rpath): if not isMount(rpath): return True self.execProg("fuser -km %s"%rpath) for waittime in [0.5, 0.5, 0.5, 0.5, 0.5, 0.5]: time.sleep(waittime) if not self.execProg("umount %s"%rpath) is False \ or not isMount(rpath): if not isMount(rpath): return True else: if isMount(rpath): self.printERROR(_("Failed to unmount directory %s")%rpath) return False return True @safetyWrapper(native_errors=(TemplatesError,DesktopError), man_int=__("Logout aborted"), post_action=umountUserRes, success_message=__("The user logged out from the session!"), failed_message=__("Unable to logout the user")) def userLogout(self, datavars=None): """ Raise user logout throught dbus """ self.initVars(datavars) if not self.clVars.Get('ur_login') in \ self.clVars.Get('cl_desktop_online_user'): raise DesktopError(_("X session users not found")) urLogin = self.clVars.Get('ur_login') display = self.clVars.Select('cl_desktop_online_display', where='cl_desktop_online_user',eq=urLogin,limit=1) session = self.clVars.Get('cl_desktop_xsession') if session == 'xfce': logoutCommand = "/usr/bin/qdbus org.xfce.SessionManager " \ "/org/xfce/SessionManager Logout False False" elif session == 'kde': logoutCommand = "/usr/bin/kquitapp ksmserver" elif session == 'gnome': logoutCommand = "/usr/bin/qdbus org.gnome.SessionManager " \ "/org/gnome/SessionManager Logout 1" else: raise DesktopError(_("Unable to detect the X session")) if process("su",urLogin,"-c", ("DISPLAY=:%s "%display)+logoutCommand).failed(): raise DesktopError(_("Unable to send the logout command")) for i in range(0,20): if filter(lambda x: "xdm/xdm\x00--logout" in x, getRunCommands()): break time.sleep(0.5) if filter(lambda x: "xdm/xdm\x00--logout" in x, getRunCommands()): self.startTask(_("Waiting for completion of the user logout")) for i in range(0,300): if not filter(lambda x: "xdm/xdm\x00--logout" in x, getRunCommands()): return True time.sleep(1) self.endTask() else: raise DesktopError(_("Unable to wait for completion " "of the user logout")) if self.clVars.Get('ur_login') in \ self.clVars.Get('cl_desktop_online_user'): raise DesktopError(_("Wrong logout")) return True