#-*- coding: utf-8 -*- # Copyright 2013 Calculate Ltd. http://www.calculate-linux.org # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import sys from os import path from calculate.core.server.func import Action,Tasks from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate from calculate.lib.utils.files import FilesError from calculate.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__]) __ = getLazyLocalTranslate(_) class ClClientSyncLoginAction(Action): """ Синхронизировать локальный профиль с удаленным, подключить удаленные ресурсы пользователя """ 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,' 'cl_remote_host)', '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 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 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 " "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') & (Tasks.hasnot('repl_profile') | Tasks.has('pack_remote'))) }, # синхронизируем с профилем локального домена {'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 " "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 " "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,' '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 " "{cl_replication_host} remote server"), 'depend': ~Tasks.success_one_of('unpack_profile','sync_remote') }, {'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') | (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') } ] class ClClientSyncLogoutAction(Action): """ Синхронизировать локальный профиль с удаленным, отключить удаленные ресурсы пользователя """ 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 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",' '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: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)', } ]