# -*- coding: utf-8 -*- # Copyright 2013-2016 Mir Calculate. 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, AllTasks from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate from calculate.lib.utils.files import FilesError from calculate.desktop.desktop import DesktopError from calculate.lib.utils.samba import SambaError from calculate.client.client import ClientError from calculate.lib.cl_template import TemplatesError from calculate.lib.utils.mount import isMount _ = lambda x: x setLocalTranslate('cl_client3', sys.modules[__name__]) __ = getLazyLocalTranslate(_) class ClClientSyncLoginAction(Action): """ Синхронизировать локальный профиль с удаленным, подключить удаленные ресурсы пользователя """ native_error = (FilesError, ClientError, DesktopError, TemplatesError, SambaError) successMessage = None failedMessage = None interruptMessage = __("Synchronization manually interrupted") old_sync = [ # подключить удаленные ресурсы пользователя {'name': 'oldsync:mount_resources', 'message': __("Mounting user resources"), 'method': 'Client.mountUserDomainRes(ur_login,' 'desktop.ur_password,' 'ur_uid,ur_gid,"unix","share","homes","ftp")', }, # подключить профиль пользователя на удаленном домене # если на нем находится актуальный профиль {'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') }, ] new_sync = [ # подключить удаленные ресурсы пользователя {'name': 'newsync:mount_resources2', 'message': __("Mounting user resources"), 'method': 'Client.mountUserDomainRes(ur_login,' 'desktop.ur_password,' 'ur_uid,ur_gid,"homes","share","ftp")', }, # монтируем профиль локального домена, если локальный профиль # старее удаленного доменного или актуальный профиль {'name': 'domain_sync2:mount_local2', # нет более ранних ошибок и локальный профиль нуждается # в синхронизации с удаленным или профиль на локальном домене 'depend': Tasks.success_all('mount_resources2') }, # синхронизируем с профилем локального домена {'name': 'mount_local2!:sync_local2', 'method': 'Client.syncLoginProfileNew(cl_remote_host,ur_login,desktop.ur_password,ur_uid,' 'ur_gid,ur_home_path,cl_client_profile_name)', }, # ошибка синхронизации с локальным доменом {'name': 'local_sync_error', 'warning': __( "Error synchronizing with the local server {cl_remote_host}"), 'depend': Tasks.failed_one_of("mount_local2", "sync_local2") }, {'name': 'sync_local2:sync_remote2', 'method': 'Client.syncLoginProfileNew(cl_replication_host,ur_login,desktop.ur_password,ur_uid,' 'ur_gid,ur_home_path,cl_client_profile_name,True)', 'condition': lambda Get: Get('cl_replication_host') }, # если синхронизация с удаленным доменом прошла с ошибкой # синхронизировать локальный профиль с локальным доменом # как запасной профиль {'name': 'fallback_warning2', 'warning': __("Error synchronizing with the " "{cl_replication_host} remote server"), 'depend': Tasks.failed_one_of('sync_remote2') }, {'name': 'fallback_warning2!:fallback_sync2', 'method': 'Client.syncLoginProfileNew(cl_remote_host,ur_login,desktop.ur_password,ur_uid,' 'ur_gid,ur_home_path,cl_client_profile_name)', }, # сообщение о том, что будет использоваться запасной профиль # с локального домена {'name': 'fallback_success2', 'message': __("Got a user fallback profile from the " "{cl_remote_host} domain"), 'depend': Tasks.success_one_of('fallback_sync2') }, # ошибка синхронизации профиль не готов! к использованию {'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_local2', 'sync_remote2', 'fallback_sync2') | Tasks.failed_one_of('mount_resources2', 'two_session')) }, ] 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': '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:check_sync', 'method': 'Client.checkSync(cl_remote_host)', 'essential': False, }, {'name': 'domain_user:oldsync', 'depend': AllTasks.failed_one_of('check_sync') }, {'name': 'domain_user:newsync', 'depend': AllTasks.success_one_of('check_sync') }, {'name': 'oldsync:domain_sync', 'method': 'Client.setSyncStatus(ur_home_path,ur_uid,ur_gid,"process")', 'condition': lambda Get: Get('cl_client_sync') == 'on', }, {'name': 'newsync:domain_sync2', 'method': 'Client.setSyncStatus(ur_home_path,ur_uid,ur_gid,"process")', 'condition': lambda Get: Get('cl_client_sync') == 'on', }, ] + old_sync + new_sync + [ # распаковать ссылки {'name': 'unpack_links', 'method': 'Client.unpackLinks(ur_home_path)', 'failed_warning': __("Failed to unpack the links archive"), 'depend': Tasks.hasnot('failed') & Tasks.success_one_of("domain_sync", "domain_sync2") }, # синхронизация профиля завершилась успешно {'name': '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() & Tasks.success_one_of("domain_sync", "domain_sync2") }, # во время синхронизации профиля произошли ошибки, которые не # гарантируют целостность профиля {'name': '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') & Tasks.success_one_of("domain_sync", "domain_sync2") }, # отключить удалённый профиль {'name': 'domain_sync:umount_unix', 'method': 'Client.umountRemoteUserRes(True,"unix","remote_profile")', 'depend': Tasks.hasnot('failed'), 'condition': lambda GetBool: not GetBool('cl_client_ignore_errors_set') }, # отключить ресурсы в случае ошибки {'name': 'umount_remote_res', 'message': __("Umounting user resources"), 'method': 'Client.umountUserRes(desktop.ur_mount_dirs)', 'depend': Tasks.has('failed'), 'condition': lambda GetBool: not GetBool('cl_client_ignore_errors_set') } ] 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") }, {'name': 'domain_user: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:check_sync', 'method': 'Client.checkSync(cl_remote_host)', 'essential': False, 'condition': lambda Get: Get('cl_client_sync') == 'on' }, {'name': 'domain_user:oldsync', 'depend': AllTasks.failed_one_of('check_sync') }, {'name': 'domain_user:newsync', 'depend': AllTasks.success_one_of('check_sync') }, # проверка на попытку отключить ресурсы пользователя в 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': 'oldsync:mount_local', 'method': 'Client.mountUserDomainRes(ur_login,desktop.ur_password,' 'ur_uid,ur_gid,"unix","homes","share","ftp")', }, {'name': 'newsync:mount_local', 'method': 'Client.mountUserDomainRes(ur_login,desktop.ur_password,' 'ur_uid,ur_gid,"homes","share","ftp")', }, # проверить наличие подключенных ресурсов {'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)', 'condition': lambda Get: Get('cl_sync_moved_set') == 'on' }, # архивировать симлинки {'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)', 'depend': Tasks.has('oldsync') }, {'name': 'domain_sync:sync_logout', 'method': 'Client.syncLogoutProfileNew(cl_remote_host,ur_login,desktop.ur_password,ur_uid,' 'ur_gid,ur_home_path,cl_client_profile_name,cl_client_symlinks)', 'depend': Tasks.has('newsync') }, # удалить файлы, которые могут помешать следующему входу в сеанс {'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)', } ]