Множественные изменения

Отключено использование clt шаблонов при вводе/выводе из домена
Добавлено шифрование
Удаление профиля пользователя на локальной машине при отсутствии его в
домене
Исправлена проверка наличия samba ресурсов на сервере
Исправлено монтирование samba ресурсов от пользователя и от системы
Исправлена упаковка симлинков
master3.3
Mike khiretskiy 11 years ago
parent 30693225f3
commit 0489e5c32a

File diff suppressed because it is too large Load Diff

@ -1,148 +0,0 @@
#-*- coding: utf-8 -*-
# Copyright 2010 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.
from cl_client import client, __app__, __version__
from cl_opt import opt
import sys
from cl_share_cmd import share_cmd
# Перевод сообщений для программы
from cl_lang import lang
lang().setLanguage(sys.modules[__name__])
# Использование программы
USAGE = _("%prog [options] user")
# Коментарии к использованию программы
COMMENT_EXAMPLES = _("Mount resources and synchronize the user profile")
# Пример использования программы
EXAMPLES = _("%prog user_name")
# Описание программы (что делает программа)
DESCRIPTION = _("Mount resources and synchronize the user profile")
# Опции командной строки
CMD_OPTIONS = [{'longOption':"login",
'help':_("mount all user resources and synchronize the "
"user profile")},
{'longOption':"logout",
'help':_("synchronize the user profile and unmount "
"user resource")},
{'longOption':"nosync",
'help':_("do not synchronize user preferences; used "
"in conjunction with 'login' or 'logout'")},
{'longOption':"set"},
{'longOption':"progress",
'help':_("show the progress bar at xdm startup")}]
class sync_cmd(share_cmd):
def __init__(self):
setpos = \
filter(lambda x:x[1].get('longOption')=="set",
enumerate(CMD_OPTIONS))[0][0]
CMD_OPTIONS[setpos] = opt.variable_set[0]
# Объект опций командной строки
self.optobj = opt(\
package=__app__,
version=__version__,
usage=USAGE,
examples=EXAMPLES,
comment_examples=COMMENT_EXAMPLES,
description=DESCRIPTION,
option_list=CMD_OPTIONS + opt.variable_view+opt.color_control,
check_values=self.checkOpts)
# Создаем объект логики
self.logicObj = client()
# Создаем переменные
self.logicObj.createClVars()
# Названия несовместимых опций
self.optionsNamesIncompatible = ["login", "logout"]
# Названия обязательных опций
self.optionsNamesRequired = self.optionsNamesIncompatible
def getOptionsRequired(self, optObj):
"""Получаем обязательные опции"""
retList = []
for nameOpt in self.optionsNamesRequired:
retList.append(getattr(optObj, nameOpt))
return retList
def _getNamesAllSetOptions(self):
"""Выдает словарь измененных опций"""
setOptDict = self.optobj.values.__dict__.items()
defaultOptDict = self.optobj.get_default_values().__dict__.items()
return dict(set(setOptDict) - set(defaultOptDict)).keys()
def getStringIncompatibleOptions(self):
"""Форматированная строка несовместимых опций разделенных ','"""
listOpt = list(set(self.optionsNamesIncompatible) &\
set(self._getNamesAllSetOptions()))
return ", ".join(map(lambda x: len(x) == 1 and "'-%s'"%x or "'--%s'"%x,\
listOpt))
def checkOpts(self, optObj, args):
"""Проверка опций командной строки"""
optionsRequired = self.getOptionsRequired(optObj)
if not args:
options = [optObj.color, optObj.v, optObj.filter, optObj.xml]
if not filter(lambda x: x, options):
errMsg = _("no such argument")+":"+" %s" %USAGE.split(" ")[-1]
self.optobj.error(errMsg)
return False
elif len(filter(lambda x: x, optionsRequired))>1:
errMsg = _("incompatible options")+":"+" %s"\
%self.getStringIncompatibleOptions()
self.optobj.error(errMsg)
return False
elif not filter(lambda x: x, optionsRequired):
errMsg = _("required option")+":"+" %s"\
%" or ".join(map(lambda x:\
len(x) == 1 and "'-%s'"%x or "'--%s'"%x,\
self.optionsNamesRequired))
self.optobj.error(errMsg)
return False
if len(args)>1:
errMsg = _("incorrect argument") + ":" + " %s" %" ".join(args)
self.optobj.error(errMsg)
return False
if not optObj.v:
if optObj.filter:
errMsg = _("incorrect option") + ":" + " %s" %"--filter" +\
": " + _("used with option '-v'")
self.optobj.error(errMsg)
return False
if optObj.xml:
errMsg = _("incorrect option") + ":" + " %s" %"--xml" +\
": " + _("used with option '-v'")
self.optobj.error(errMsg)
return False
return optObj, args
def setUserName(self, userName):
"""Установка имени пользователя"""
self.logicObj.clVars.Set("ur_login", userName, True)
def mountUserResAndSync(self, sync=True, progress=False):
"""Монтирование ресурсов и синхронизация при входе"""
userName = self.logicObj.clVars.Get("ur_login")
return self.logicObj.mountUserResAndSync(userName, sync=sync,
progress=progress)
def umountUserResAndSync(self, sync=True, progress=False):
"""Отмонтирование ресурсов и синхронизация при выходе"""
userName = self.logicObj.clVars.Get("ur_login")
return self.logicObj.umountUserResAndSync(userName, sync=sync,
progress=progress)

File diff suppressed because it is too large Load Diff

@ -0,0 +1,484 @@
#-*- coding: utf-8 -*-
# Copyright 2010-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_desktop3',sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class ClClientAction(Action):
"""
Ввести машину в домен или вывести
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError,ClientError,DesktopError,TemplatesError)
successMessage = None
failedMessage = None
interruptMessage = __("Configuration manually interrupted")
# список задач для действия
tasks = [
# команда вызвана только для монтировния remote ресурсов
{'name':'only_mount',
'condition':lambda Get:Get('cl_client_mount_set') == 'on'
},
# ввод в домен
{'name':'domain',
'condition':lambda Get:Get('cl_localhost_set') == 'off',
'depend':Tasks.hasnot('only_mount')
},
# вывод из домена
{'name':'undomain',
'condition':lambda Get:Get('cl_localhost_set') == 'on',
'depend':Tasks.hasnot('only_mount')
},
# машина не доменная
{'name':'only_mount:localpc',
'warning':__("This computer is not in the domain"),
'condition':lambda Get:not Get('cl_remote_host')
},
# проверить может ли указанный сервер являться доменом
{'name':'domain:check_domain',
'message':__("Check {cl_remote_host_new} for domain resources"),
'method':'Client.checkDomainServer(cl_remote_host_new,os_net_domain)',
},
# получить пароль для ввода в домен (или воспользоваться кэшированным)
{'name':'domain:get_password',
'method':'Client.getDomainPassword(cl_remote_host_new)'
},
{'name':'domain:set_remote_host',
'method':'Client.setVariable("cl_remote_host",cl_remote_host_new)'
},
# машина доменная
{'name':'mount_remote',
'method':'Client.mountRemoteRes(cl_remote_pw,cl_client_remote_path,'
'cl_remote_host)',
'depend':Tasks.success() & Tasks.hasnot('localpc','undomain')
},
# отключить удаленный доменный ресурс
{'name':'undomain:unmount_remote',
'method':'Client.umountSleepPath(cl_client_remote_path)',
},
# удалить переменные клиента
{'name':'undomain:remove_vars',
'method':'Client.removeVars()'
},
# наложить шаблоны если они не актуальны
{'name':'need_templates',
'condition':lambda Get:Get('cl_client_relevance_set') == 'off'
},
# проверить информацию для ldap расположенную в домене
{'name':'domain:check_domain_info',
'method':'Client.checkDomainInfo(cl_remote_host)',
},
# наложить доменные шаблоны, если успешно подключен удаленный ресурс
{'name':'need_templates:apply_templates',
'message':__("Applying domain templates"),
'method':'Client.applyClientTemplates(cl_remote_host)',
'depend':Tasks.success_all('mount_remote')
},
# наложить недоменные шаблоны в случае локального режима
# или были проблемы с подключением удаленноых ресурсов
{'name':'need_templates:apply_templates',
'message':__("Applying non-domain templates"),
'method':'Client.applyClientTemplates("")',
'depend':Tasks.result('mount_remote',ne=True)
},
# удалить записи из /etc/passwd и синхронизировать кэш
{'name':'del_sync_cache',
'method':'Client.cDelLdapSysUsersAndSyncCache()',
'condition':lambda Get:Get('cl_remote_host'),
'depend':Tasks.success_all('mount_remote','need_templates')
},
# удалить записи из /etc/passwd и очистить кэш
{'name':'undomain:del_clear_cache',
'message':__("Clearing the user cache"),
'method':'Client.cDelLdapSysUsersAndClearCache()'
},
# синхронизировать кэш, добавить записи в /etc/passwd
{'name':'only_mount:add_sync_cache',
'method':'Client.cAddCacheUsersFromSystem()',
'depend':Tasks.failed_all('mount_remote')
},
# добавить службу client в автозапуск
{'name':'domain:autorun_client',
'method':'Client.addDaemonAutostart("client")'
},
# записать переменные клиента
{'name':'domain:write_vars',
'method':'Client.writeClientVars(cl_remote_host,cl_ver,cl_remote_pw)',
},
# сообщения о результатах работы действия
{'name':'domain:success',
'message':__("Computer added to domain {cl_remote_host}")
},
{'name':'domain:failed',
'error':__("Failed to add the computer to domain {cl_remote_host}"),
'depend':Tasks.failed() & Tasks.hasnot("interrupt"),
},
{'name':'undomain:success',
'message':__("Computer removed from domain {cl_remote_host}")
},
{'name':'undomain:failed',
'error':__("Failed to remove the computer from domain"),
'depend':Tasks.failed() & Tasks.hasnot("interrupt"),
},
]
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
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':__("Second X session for user %s cannot be opened."),
'condition':lambda Get:Get('ur_login') in \
Get('desktop.cl_desktop_online_user') and \
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:check_clock_scew',
# 'method':'Client.checkClockScew('
# 'failed_warning':__("Profile synchronization will be applied "
# "without archiving")
#},
# отправить команду архивирования профиля на удаленном домене
# если он новее локального профиля
{'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 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 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 from {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 remote server "
"{cl_replication_host}"),
'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': __("Get 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())
},
# распаковать ссылки
{'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':__("Get the user profile from 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':__("Changings in the user profile 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 is used")
},
# проверка на попытку отключить ресурсы пользователя в X сессии
{'name':'domain_user:in_xsession',
'error':__("User {ur_login} is already in 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':__("User home directory {ur_home_path} not found"),
},
# проверить наличие подключенных ресурсов
{'name':'check_mount',
'condition':lambda Get:any(x and isMount(x)
for x in Get('cl_client_user_mount_path')),
'else_error':__("User remote 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':__("Profile will not be upload to domain")
},
# переместить файлы из профиля в Moved
{'name':'domain_user:move_home_dir',
'message':__("Moving not profile files to 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':'skip:clear_user_key',
'message':__("Clearing user key"),
'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)',
}
]
class ClPasswdAction(Action):
"""
Изменить пароль доменного пользователя
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError,DesktopError,TemplatesError)
successMessage = (__("{cl_client_login}'s password changed\n"
"The password will be changed when you log out"
"from the X session"))
failedMessage = __("Failed to change password")
interruptMessage = __("Logout manually interrupted")
# список задач для действия
tasks = [
{'name':'change_passwd',
'method':'Client.clientPasswd(cl_client_login,ur_uid,ur_gid,'
'ur_home_path,ur_user_new_pw,ur_user_pw)',
}]

@ -17,13 +17,22 @@
import os
import sys
from os import path
from calculate.lib.datavars import Variable,VariableError,ReadonlyVariable
from calculate.lib.utils.files import readLinesFile
from calculate.lib.utils.common import getValueFromCmdLine
import re
from calculate.lib.datavars import (Variable,VariableError,ReadonlyVariable,
ReadonlyTableVariable,FieldValue)
from calculate.lib.cl_template import iniParser
from calculate.lib.utils.files import readLinesFile,isMount,readFile, find
from calculate.lib.utils.common import getValueFromCmdLine,cmpVersion
from calculate.lib.variables.user import VariableUrLogin
from calculate.lib.convertenv import convertEnv
from calculate.lib.utils.ip import isOpenPort
import time
import ldap
from socket import gethostbyname
from calculate.lib.cl_ldap import ldapUser
from calculate.lib.variables.user import LdapHelper
import pwd
from calculate.client.client import Client
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_client3',sys.modules[__name__])
@ -145,6 +154,7 @@ class VariableClLocalhostSet(Variable):
value = "off"
opt = ["-r"]
metavalue = "ON/OFF"
untrusted = True
def init(self):
self.label = _("Computer role")
@ -155,13 +165,14 @@ class VariableClLocalhostSet(Variable):
("on",_("Local workstation"))]
def check(self,value):
if self.Get('cl_remote_host') == '' and value == "on":
raise VariableError(_("The computer is not in the domain"))
if self.Get('cl_remote_host') != '' and value == "off":
raise VariableError(_("The computer is already in the domain %s")
%self.Get('cl_remote_host') + "\n" +
_("Before joining the domain, "
"you need to remove it from the previous domain"))
if self.Get('cl_client_mount_set') == 'off':
if self.Get('cl_remote_host') == '' and value == "on":
raise VariableError(_("The computer is not in the domain"))
if self.Get('cl_remote_host') != '' and value == "off":
raise VariableError(_("The computer is already in the domain %s")
%self.Get('cl_remote_host') + "\n" +
_("Before joining the domain, "
"you need to remove it from the previous domain"))
#def get(self):
# if self.Get('cl_remote_host') == '':
@ -212,7 +223,10 @@ class VariableUrUserPw(Variable,LdapHelper):
def check(self,value):
if not value:
raise VariableError(_("Empty password"))
server = self.Get('cl_remote_host')
# читаем os_remote_auth, так как при смене пароля
# чтение должно выполняться от пользователя,
# cl_remote_host не может быть прочитан пользователем
server = self.Get('os_remote_auth')
ldapObj = self.getLdapUserObject()
if ldapObj:
usersDN = ldapObj.getUsersDN()
@ -237,3 +251,404 @@ class VariableUrUserNewPw(Variable):
def check(self,value):
if not value:
raise VariableError(_("Empty password"))
class VariableClClientLogin(VariableUrLogin):
"""
User Login
"""
opt = ["cl_client_login"]
alias = "ur_login"
def choice(self):
loginChoice = VariableUrLogin.choice(self)
if self.Get('cl_action') == 'passwd':
return filter(lambda x:x != "root",loginChoice)
else:
return loginChoice
def check(self,value):
"""Does user exist"""
if not value in self.choice() and self.Get('cl_action') == 'logout':
raise VariableError(_("X session users not found"))
if value == "":
raise VariableError(_("Need to specify user"))
if value == "root" and self.Get('cl_action') == 'passwd':
raise VariableError(\
_("The action can be executed by a non-root user only"))
try:
pwd.getpwnam(value).pw_gid
except:
raise VariableError(_("User %s does not exist")%value)
def get(self):
if (self.Get('cl_action') == 'passwd' and
self.Get('ur_login') != 'root'):
return self.Get('ur_login')
return ""
class VariableClClientRelevanceSet(ReadonlyVariable):
"""
Актуальны ли сейчас выполненные шаблоны
"""
type = "bool"
def get(self):
# если изменился домен
if self.Get('cl_remote_host') != self.Get("os_remote_auth"):
return "off"
currentVersion = self.Get("cl_ver")
# версия программы, который были наложены шаблоны
previousVersion = self.Get("os_remote_client")
if cmpVersion(currentVersion,previousVersion):
return "off"
return "on"
class VariableClClientRemotePath(Variable):
"""
Путь для монитрования //domain/remote
"""
value = "/var/calculate/remote"
class VariableClClientProfileName(Variable):
"""
Название удаленного профиля (CLD,CLDX,all)
"""
def get(self):
return ("all" if self.Get('cl_profile_all_set') == 'on'
else self.Get('os_linux_shortname'))
class VariableClLdapData(ldapUser,ReadonlyVariable):
"""
Внутренняя переменная, содержащая объект для доступа к данным LDAP
"""
type = "object"
def get(self):
return self
def getReplDN(self):
"""
Получить из LDAP домен на котором находится актуальный профиль
Get from LDAP last domain server
Branch has ((username,systemname,host))
"""
usersDN = self.getUsersDN()
if usersDN:
partDN = "ou=Worked,ou=Replication,ou=LDAP"
servicesDN = "ou=Services"
baseDN = usersDN.rpartition(servicesDN+",")[2]
replDN = self.addDN(partDN, servicesDN, baseDN)
return replDN
return False
def searchPrevHost(self, userName, osLinuxShort):
"""Find server which user use"""
connectData = self.getBindConnectData()
if connectData:
bindDn, bindPw, host = connectData
replDN = self.getReplDN()
# find string for service replication branch
userAndOsName = "%s@%s"%(userName,osLinuxShort)
findAttr = "uid=%s"%userAndOsName
# connect to LDAP
if not self.ldapConnect(bindDn, bindPw, host):
return False
resSearch = self.ldapObj.ldapSearch(replDN, ldap.SCOPE_ONELEVEL,
findAttr, ["host"])
return resSearch
return False
def _gethostbyname(self,hostname):
try:
return gethostbyname(hostname)
except:
pass
return None
def getNameRemoteServer(self,userName, osLinuxShort, curHost):
"""
Get remote domain hostname or empty if profile is keeped on
current server
"""
searchPrevHost = self.searchPrevHost(userName, osLinuxShort)
if searchPrevHost and searchPrevHost[0][0][1].has_key('host'):
prevHost = searchPrevHost[0][0][1]['host'][0]
else:
prevHost = None
# get ip address of previous server and current server
prevIp = self._gethostbyname(prevHost)
curIp = self._gethostbyname(curHost)
# if actual profile not found or on local
if not prevHost or curIp and prevIp == curIp:
return ""
else:
return prevHost
def isRepl(self):
"""
Is on or off replication on server
"""
connectData = self.getBindConnectData()
if connectData:
bindDn, bindPw, host = connectData
usersDN = self.getUsersDN()
partDN = "ou=Replication,ou=LDAP"
servicesDN = "ou=Services"
baseDN = usersDN.rpartition(servicesDN+",")[2]
replDN = self.addDN(partDN, servicesDN, baseDN)
findAttr = "ou=Worked"
# connect to LDAP
if not self.ldapConnect(bindDn, bindPw, host):
return False
resSearch = self.ldapObj.ldapSearch(replDN, ldap.SCOPE_ONELEVEL,
findAttr,
[findAttr.partition("=")[0]])
if resSearch:
return True
return False
class VariableClReplicationHost(ReadonlyVariable):
"""
Удаленный сервер при репликации, который содержит актуальный профиль
"""
def get(self):
return self.Get('cl_ldap_data').getNameRemoteServer(
self.Get('ur_login'),self.Get('cl_client_profile_name'),
self.Get('cl_remote_host'))
class VariableClClientUserMountData(ReadonlyTableVariable):
"""
Таблица монтирования ресурсов
"""
source = ['cl_client_user_mount_name',
'cl_client_user_mount_resource',
'cl_client_user_mount_path',
'cl_client_user_mount_host']
def get(self):
home = path.split(self.Get('ur_home_path'))[0]
envFile = self.Get('cl_env_server_path')
def generate():
yield ("share","share",path.join(self.Get('ur_home_path'),"Share"),
self.Get('cl_remote_host'))
yield ("unix","unix",path.join(home,".%s"%self.Get('ur_login')),
self.Get('cl_remote_host'))
yield ("homes","homes",path.join(self.Get('ur_home_path'),"Home"),
self.Get('cl_remote_host'))
if convertEnv().getVar("ftp","host"):
yield ("ftp","ftp",path.join(self.Get('ur_home_path'),"FTP"),
self.Get('cl_remote_host'))
else:
yield ("ftp",'','','')
if self.Get('cl_replication_host'):
yield ("remote_profile","unix",
path.join(home,".%s.remote"%self.Get('ur_login')),
self.Get('cl_replication_host'))
else:
yield ("remote_profile",'unix','','')
return list(generate())
class VariableClClientUserMountName(FieldValue,ReadonlyVariable):
"""
Название удаленного ресурса
"""
type = "list"
source_variable = "cl_client_user_mount_data"
column = 0
class VariableClClientUserMountResource(FieldValue,ReadonlyVariable):
"""
Название удаленного ресурса
"""
type = "list"
source_variable = "cl_client_user_mount_data"
column = 1
class VariableClClientUserMountPath(FieldValue,ReadonlyVariable):
"""
Путь подключения удаленного ресурса
"""
type = "list"
source_variable = "cl_client_user_mount_data"
column = 2
class VariableClClientUserMountHost(FieldValue,ReadonlyVariable):
"""
Удаленный сервер
"""
type = "list"
source_variable = "cl_client_user_mount_data"
column = 3
class SyncHelper:
"""
Вспомогательный объект для определения статуса синхронизации и времени
по конфигурационным файлам
"""
def getSyncStatus(self,rpath):
"""
Получить status_sync из desktop файла
"""
fileConfig = path.join(rpath, Client.configFileDesktop)
# get data from desktop config on success run get by archive
if os.path.exists(fileConfig):
objConfig = iniParser(fileConfig)
data = self.getDataInConfig("main", ["status_sync"],
objConfig)
if data:
return data.get("status_sync","")
return ""
def getDataInConfig(self, section, listVars, objConfig):
"""
Прочитать список переменных из области конфигурационного файла
"""
varsConfig = {}
for varName in listVars:
varsConfig[varName] = objConfig.getVar(section,varName)
if objConfig.getError():
return False
return varsConfig
def convertDate(self,strdate,dateformat="%Y-%m-%d %H:%M:%S"):
"""
Convert date from string format (dateformat) to stuct or None
"""
if strdate:
try:
return time.strptime(strdate,dateformat)
except ValueError:
pass
return ""
def getDateObjClientConf(self, rpath):
"""
Получить время синхронизации из .calculate/desktop.env
"""
fileConfig = path.join(rpath, Client.configFileDesktop)
if os.path.exists(fileConfig):
objConfig = iniParser(fileConfig)
data = self.getDataInConfig("main", ["date", "date_logout"],
objConfig)
timeLogout = data["date_logout"]
timeConfig = data["date"]
dates = filter(None,
[self.convertDate(timeLogout),
self.convertDate(timeConfig)])
if dates:
return dates[0]
return ""
def checkNeedSync(self,homeDir,rpath,curTimeObj,curStatusSync,osLinuxShort):
"""
Проверить необходимость синхронизации текущего профиля с удаленным
"""
# profile directory
#fileConfig = os.path.join(homeDir, Client.configFileServer)
pathProfile = os.path.join(rpath, osLinuxShort)
#if readFile(fileConfig).strip():
# return True
fileSoftConfigThis = os.path.join(pathProfile,
Client.configFileSoft)
fileSoftConfigCur = os.path.join(homeDir,
Client.configFileSoft)
xSessionCur = iniParser(fileSoftConfigCur).getVar('main','xsession')
xSessionThis = iniParser(fileSoftConfigThis).getVar('main','xsession')
# check profile date on current server
#fileConfigThis = os.path.join(pathProfile, Client.configFileDesktop)
#if iniParser(fileConfigThis).getVar('main','status_sync') == "success":
# self.setVarToConfig("main", {"status_sync":"success_mount"},
# fileConfigThis)
thisTimeObj = self.getDateObjClientConf(pathProfile)
if curStatusSync == "success_logout" and \
xSessionCur == xSessionThis and \
thisTimeObj and curTimeObj and \
curTimeObj >= thisTimeObj:
return False
return True
class VariableClClientSyncTime(SyncHelper,ReadonlyVariable):
"""
Текущее время синхронизации профиля
"""
def get(self):
return self.getDateObjClientConf(self.Get('ur_home_path'))
class VariableClClientPackTime(SyncHelper,ReadonlyVariable):
"""
Время комады упаковки профиля
"""
def get(self):
return str(float(time.time()))
class VariableClClientSyncStatus(SyncHelper,ReadonlyVariable):
"""
Текущий статус синхронизации профиля
"""
def get(self):
return self.getSyncStatus(self.Get('ur_home_path'))
class VariableClClientLocalSyncTime(SyncHelper,ReadonlyVariable):
"""
Текущий статус синхронизации профиля
"""
def get(self):
return self.getDateObjClientConf(
path.join(
self.Select('cl_client_user_mount_path',
where='cl_client_user_mount_name',eq='unix',
limit=1),self.Get('cl_client_profile_name')))
class VariableClClientSyncReplicationSet(SyncHelper,ReadonlyVariable):
"""
Нужно ли синхронизировать текущий профиль с удаленным доменом
"""
type = "bool"
def get(self):
if not self.Get('cl_replication_host'):
return "off"
profilePath = self.Select('cl_client_user_mount_path',
where='cl_client_user_mount_name',
eq='remote_profile',limit=1)
if self.Get('cl_action') == 'login' and not isMount(profilePath):
raise VariableError(_("Remote profile is not mounted"))
return "on" if self.checkNeedSync(self.Get('ur_home_path'),profilePath,
self.Get('cl_client_sync_time'),
self.Get('cl_client_sync_status'),
self.Get('cl_client_profile_name')) else "off"
class VariableClClientSyncLocalSet(SyncHelper,ReadonlyVariable):
"""
Нужно ли синхронизировать текущий профиль с локальным доменом
"""
type = "bool"
def get(self):
if not self.Get('cl_remote_host'):
return "off"
profilePath = self.Select('cl_client_user_mount_path',
where='cl_client_user_mount_name',
eq='unix',limit=1)
if self.Get('cl_action') == 'login' and not isMount(profilePath):
raise VariableError(_("Remote profile is not mounted"))
return "on" if self.checkNeedSync(self.Get('ur_home_path'),profilePath,
self.Get('cl_client_sync_time'),
self.Get('cl_client_sync_status'),
self.Get('cl_client_profile_name')) else "off"
class VariableClClientSymlinks(ReadonlyVariable):
"""
Список симлинков в пользовательском профиле
"""
def get(self):
skipFiles = (self.Get('cl_sync_del_path') +
self.Get('cl_sync_skip_path'))
reSkip = re.compile("|".join(map(lambda x:x.replace("*",".*"),
skipFiles))).search
return filter(lambda x:not reSkip(x),
find(self.Get('ur_home_path'),onefilesystem=True,filetype='l'))

@ -1,4 +1,4 @@
# Copyright 2012 Calculate Ltd. http://www.calculate-linux.org
# Copyright 2012-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.
@ -11,201 +11,173 @@
# 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
import soaplib, sys, time, os
import threading
from calculate.lib.datavars import VariableError, DataVarsError
from calculate.core.server.func import WsdlBase
from calculate.desktop.desktop import DesktopError
from client import ClientError
from utils.cl_client import (ClClientAction, ClClientSyncLoginAction,
ClClientSyncLogoutAction, ClPasswdAction)
import calculate.desktop.desktop as desktop
import calculate.client.client as client
import calculate.install.install as install
from soaplib.serializers.primitive import String, Integer, Any, Boolean
from soaplib.serializers.clazz import Array
from soaplib.service import rpc, DefinitionBase
from calculate.core.server.api_types import ReturnedMessage,CommonInfo
from calculate.core.server.api_types import ChoiceValue, Table, Option, Field, \
GroupField, ViewInfo, ViewParams
from calculate.lib.datavars import VariableError,DataVarsError
from calculate.client.cl_client import ClientError
from cl_client import Client,DataVarsClient
import cl_client
from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate
from calculate.core.server.decorators import Dec
from calculate.core.server.func import catchExcept
core_method = Dec.core_method
setLocalTranslate('cl_client3',sys.modules[__name__])
import traceback
from functools import wraps,WRAPPER_ASSIGNMENTS
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
setLocalTranslate('cl_desktop3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class ClientInfo(CommonInfo):
"""Parameters for method install"""
cl_localhost_set = Boolean
cl_remote_host_new = String
cl_remote_pw = String
cl_client_mount_set = Boolean
class ClientPasswdInfo(CommonInfo):
"""Parameters for method install"""
ur_login = String
ur_user_pw = String
ur_user_new_pw = String
class SyncInfo(CommonInfo):
"""Parameters for method install"""
ur_login = String
cl_client_sync = Boolean
clientCatchExcept = catchExcept(VariableError,DataVarsError,
ClientError)
class Wsdl:
"""
cl-client
"""
@rpc(Integer, ClientInfo, _returns = Array(ReturnedMessage))
@core_method(category=__('Client'),title=__('Domain'),
image='network-workgroup',
gui=True,command='cl-client',
rights=['domain'])
def client(self, sid, info):
return self.callMethod(sid,info,method_name="client",
logicClass=Client,
method="domain")
def client_vars(self,dv=None):
if not dv:
dv = DataVarsClient()
dv.importClient()
dv.flIniFile()
dv.Set('cl_action','domain',True)
dv.Set('cl_dispatch_conf','usenew',True)
dv.addGroup(None,
normal=('cl_localhost_set','cl_remote_host_new',
'cl_remote_pw'),
expert=('cl_client_mount_set','cl_templates_locate',
'cl_verbose_set','cl_dispatch_conf'),
next_label=_("Configure"))
return dv
@rpc(Integer, ViewParams,_returns = ViewInfo)
def client_view (self, sid, params):
dv = self.get_cache(sid,"client","vars")
if not dv:
dv = self.client_vars()
if hasattr(params,"clienttype") and params.clienttype == "gui":
try:
if dv.Get('cl_remote_host') == '':
dv.Set('cl_localhost_set',"on")
else:
dv.Set('cl_localhost_set',"off")
except VariableError as e:
pass
else:
dv.processRefresh()
view = ViewInfo(dv,viewparams=params)
self.set_cache(sid, 'client', "vars",dv,smart=False)
return view
"""
cl-client-sync-login
"""
@rpc(Integer, SyncInfo, _returns = Array(ReturnedMessage))
@core_method(category=__('Client'),title=__('Domain user login'),
image='applications-other',
gui=False,command='cl-client-sync-login',
rights=['domainuser'])
def client_sync_login(self, sid, info):
return self.callMethod(sid,info,method_name="client_sync_login",
logicClass=Client,
method="mountUserResAndSync")
def client_sync_login_vars(self,dv=None):
if not dv:
dv = DataVarsClient()
dv.importClient()
dv.flIniFile()
dv.Set('cl_action','login',True)
dv.addGroup(None,
normal=('ur_login','cl_client_sync'),
next_label=_("Configure"))
return dv
@rpc(Integer, ViewParams,_returns = ViewInfo)
def client_sync_login_view (self, sid, params):
dv = self.get_cache(sid,"client_sync_login","vars")
if not dv:
dv = self.client_sync_login_vars()
else:
dv.processRefresh()
view = ViewInfo(dv,viewparams=params)
self.set_cache(sid, 'client_sync_login', "vars",dv,smart=False)
return view
"""
cl-client-sync-logout
"""
@rpc(Integer, SyncInfo, _returns = Array(ReturnedMessage))
@core_method(category=__('Client'),title=__('Domain user logout'),
image='applications-other',
gui=False,command='cl-client-sync-logout',
rights=['domainuser'])
def client_sync_logout(self, sid, info):
return self.callMethod(sid,info,method_name="client_sync_logout",
logicClass=Client,
method="umountUserResAndSync")
def client_sync_logout_vars(self,dv=None):
if not dv:
dv = DataVarsClient()
dv.importClient()
dv.flIniFile()
dv.Set('cl_action','logout',True)
dv.addGroup(None,
normal=('ur_login','cl_client_sync'),
next_label=_("Configure"))
return dv
@rpc(Integer, ViewParams,_returns = ViewInfo)
def client_sync_logout_view (self, sid, params):
dv = self.get_cache(sid,"client_sync_logout","vars")
if not dv:
dv = self.client_sync_logout_vars()
else:
dv.processRefresh()
view = ViewInfo(dv,viewparams=params)
self.set_cache(sid, 'client_sync_logout', "vars",dv,smart=False)
return view
"""
cl-passwd
"""
@rpc(Integer, ClientPasswdInfo, _returns = Array(ReturnedMessage))
@core_method(category=__('Client'),title=__('Change password'),
image='system-users',
gui=True,command='cl-passwd',
rights=['password'],user=True)
def clientpasswd(self, sid, info):
return self.callMethod(sid,info,method_name="clientpasswd",
logicClass=Client,
method="clientPasswd")
def clientpasswd_vars(self,dv=None):
if not dv:
dv = DataVarsClient()
dv.importClient()
dv.flIniFile()
dv.Set('cl_action','passwd',True)
dv.addGroup(None,
normal=('ur_login','ur_user_pw','ur_user_new_pw'),
next_label=_("Change password"))
return dv
@rpc(Integer, ViewParams,_returns = ViewInfo)
def clientpasswd_view (self, sid, params):
dv = self.get_cache(sid,"clientpasswd","vars")
if not dv:
dv = self.clientpasswd_vars()
else:
dv.processRefresh()
view = ViewInfo(dv,viewparams=params)
self.set_cache(sid, 'clientpasswd', "vars",dv,smart=False)
return view
class Wsdl(WsdlBase):
methods = [
#
# ввести машину в домен или вывести
#
{
# идентификатор метода
'method_name': "client",
# категория метода
'category': __('Client'),
# заголовок метода
'title': __("Domain"),
# иконка для графической консоли
'image': 'network-workgroup',
# метод присутствует в графической консоли
'gui': True,
# консольная команда
'command': 'cl-client',
# права для запуска метода
'rights': ['domain'],
# объект содержащий модули для действия
'logic': {'Desktop': desktop.Desktop,
'Client': client.Client},
# описание действия
'action': ClClientAction,
# объект переменных
'datavars': "client",
'native_error': (VariableError, DataVarsError,
ClientError, DesktopError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'domain',
'cl_protect_use_set!':'off'
},
'guivars': {'cl_localhost_set': lambda dv: (
"on" if dv.Get('cl_remote_host') == '' else 'off')},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Domain"),
normal=(
'cl_localhost_set', 'cl_remote_host_new',
'cl_remote_pw'),
expert=('cl_client_mount_set',
'cl_templates_locate',
'cl_verbose_set',
'cl_dispatch_conf'),
next_label=_("Configure"))]},
#
# подключить удаленные ресурсы пользователя
#
{
# идентификатор метода
'method_name': "client_sync_login",
# категория метода
'category': __('Client'),
# заголовок метода
'title': __("Domain user login"),
# иконка для графической консоли
'image': 'application-other',
# метод не присутствует в графической консоли
'gui': False,
# консольная команда
'command': 'cl-client-sync-login',
# права для запуска метода
'rights': ['domainuser'],
# объект содержащий модули для действия
'logic': {'Desktop': desktop.Desktop,
'Client': client.Client},
# описание действия
'action': ClClientSyncLoginAction,
# объект переменных
'datavars': "client",
'native_error': (VariableError, DataVarsError,
ClientError, DesktopError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'login'},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Domain user login"),
normal=('ur_login', 'cl_client_sync'),
next_label=_("Login"))]},
#
# отключить удаленные ресурсы пользователя
#
{
# идентификатор метода
'method_name': "client_sync_logout",
# категория метода
'category': __('Client'),
# заголовок метода
'title': __("Domain user logout"),
# иконка для графической консоли
'image': 'application-other',
# метод не присутствует в графической консоли
'gui': False,
# консольная команда
'command': 'cl-client-sync-logout',
# права для запуска метода
'rights': ['domainuser'],
# объект содержащий модули для действия
'logic': {'Desktop': desktop.Desktop,
'Client': client.Client},
# описание действия
'action': ClClientSyncLogoutAction,
# объект переменных
'datavars': "client",
'native_error': (VariableError, DataVarsError,
ClientError, DesktopError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'logout'},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Domain user logout"),
normal=('ur_login', 'cl_client_sync'),
next_label=_("Logout"))]},
#
# сменить пароль доменного пользователя
#
{
# идентификатор метода
'method_name': "client_passwd",
# категория метода
'category': __('Client'),
# заголовок метода
'title': __("Change password"),
# иконка для графической консоли
'image': 'system-users',
# метод присутствует в графической консоли
'gui': True,
# пользовательский метода
'user': True,
# консольная команда
'command': 'cl-passwd',
# права для запуска метода
'rights': ['password'],
# объект содержащий модули для действия
'logic': {'Desktop': desktop.Desktop,
'Client': client.Client},
# описание действия
'action': ClPasswdAction,
# объект переменных
'datavars': "client",
'native_error': (VariableError, DataVarsError,
ClientError, DesktopError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'passwd'},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Change password"),
normal=('cl_client_login', 'ur_user_pw',
'ur_user_new_pw'),
next_label=_("Change password"))]},
]

@ -18,26 +18,22 @@
# limitations under the License.
__app__ = "calculate-client"
__version__ = "3.1.4"
__version__ = "3.1.6"
import os
import stat
from distutils.core import setup, Extension
from distutils.command.install_data import install_data
import distutils.command.build
import distutils.command.install
from os import system,path
import glob
import sys
data_files = []
data_files += [('/etc/init.d', ['data/client'])]
data_files += [('/usr/share/calculate/xdm/login.d',
['data/login.d/10client'])] +\
[('/usr/share/calculate/xdm/logout.d',
['data/logout.d/10client'])] +\
[('/usr/share/calculate/xdm/',['data/wait_domain'])]
data_files += ([('/usr/share/calculate/xdm/login.d',
['data/login.d/10client'])] +
[('/usr/share/calculate/xdm/logout.d',
['data/logout.d/10client'])] +
[('/usr/share/calculate/xdm/', ['data/wait_domain'])])
def __scanDir(scanDir, prefix, replace_dirname, dirData, flagDir=False):
"""Scan directory"""
@ -45,7 +41,7 @@ def __scanDir(scanDir, prefix, replace_dirname, dirData, flagDir=False):
dirs = []
if flagDir or stat.S_ISDIR(os.stat(scanDir)[stat.ST_MODE]):
for fileOrDir in os.listdir(scanDir):
absPath = os.path.join(scanDir,fileOrDir)
absPath = os.path.join(scanDir, fileOrDir)
statInfo = os.stat(absPath)[stat.ST_MODE]
if stat.S_ISREG(statInfo):
files.append(absPath)
@ -53,15 +49,16 @@ def __scanDir(scanDir, prefix, replace_dirname, dirData, flagDir=False):
dirs.append(absPath)
if replace_dirname:
listDirs = list(scanDir.partition("/"))[1:]
listDirs.insert(0,replace_dirname)
listDirs.insert(0, replace_dirname)
scanDir = "".join(listDirs)
if prefix:
scanDir = os.path.join(prefix,scanDir)
scanDir = os.path.join(prefix, scanDir)
dirData.append((scanDir, files))
for sDir in dirs:
__scanDir(sDir, prefix, replace_dirname,dirData, True)
__scanDir(sDir, prefix, replace_dirname, dirData, True)
return dirData
def create_data_files(data_dirs, prefix="", replace_dirname=""):
"""Create data_files"""
data_files = []
@ -70,18 +67,19 @@ def create_data_files(data_dirs, prefix="", replace_dirname=""):
data_files += __scanDir(data_dir, prefix, replace_dirname, data)
return data_files
class cl_install_data(install_data):
def run (self):
def run(self):
install_data.run(self)
data_file = [("/etc/init.d/client",0755),
("/usr/share/calculate/xdm/wait_domain",0755)]
data_file = [("/etc/init.d/client", 0755),
("/usr/share/calculate/xdm/wait_domain", 0755)]
fileNames = map(lambda x: os.path.split(x[0])[1], data_file)
listNames = map(lambda x: filter(lambda y: y, x[0].split("/")),
data_file)
data_find = {}
for i in range(len(fileNames)):
listNames[i].reverse()
data_find[fileNames[i]] =[listNames[i],data_file[i][1]]
data_find[fileNames[i]] = [listNames[i], data_file[i][1]]
for path in self.get_outputs():
nameFile = os.path.split(path)[1]
@ -99,19 +97,21 @@ class cl_install_data(install_data):
if flagFound:
os.chmod(path, mode)
setup(
name = __app__,
version = __version__,
description = "Mounting resources and synchronize the user profile",
author = "Calculate Ltd.",
author_email = "support@calculate.ru",
url = "http://calculate-linux.org",
license = "http://www.apache.org/licenses/LICENSE-2.0",
package_dir = {'calculate.client': "client"},
packages = ['calculate.client','calculate.client.variables'],
data_files = data_files,
ext_modules = [Extension('calculate.client._cl_keys',
library_dirs = ['/usr/lib'],
libraries = ['keyutils'],
sources = ['./lib/cl_keys.i', './lib/cl_keys.c'])],
name=__app__,
version=__version__,
description="Mounting resources and synchronize the user profile",
author="Calculate Ltd.",
author_email="support@calculate.ru",
url="http://calculate-linux.org",
license="http://www.apache.org/licenses/LICENSE-2.0",
package_dir={'calculate.client': "client"},
packages=['calculate.client', 'calculate.client.utils',
'calculate.client.variables'],
data_files=data_files,
ext_modules=[Extension('calculate.client._cl_keys',
library_dirs=['/usr/lib'],
libraries=['keyutils'],
sources=['./lib/cl_keys.i', './lib/cl_keys.c'])],
cmdclass={'install_data': cl_install_data})

Loading…
Cancel
Save