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