You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
calculate-utils-3-client/pym/client/utils/cl_client_sync.py

473 lines
24 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# -*- 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)',
}
]