Compare commits

..

94 Commits

Author SHA1 Message Date
root 4b1853c10a TG-230
1 year ago
root a5b6585684 Fix: изменение текста ненадежного пароля
1 year ago
root d238a632f3 Fix: теперь идет попытка примонтировать все доступные ресурсы, несмотря на ошибки монтирования в некоторых из них
1 year ago
root f2b6237246 Добавление возможности указывать дополнительные точки монтирования
1 year ago
root 3299c91b38 TG-4
1 year ago
root f90dd04db1 изменено: pym/client/client.py
2 years ago
root bc6332a994 Изменения ssh доступа к домену
2 years ago
idziubenko f17052d205 fixed more typos
2 years ago
idziubenko a3e3b179b7 FIX: fixed multiple typos
2 years ago
idziubenko 2ffc59f626 FEAT: added exception for rsync error 24
2 years ago
idziubenko b229afbad8 FIX: fixed a typo in mountSambaRes
2 years ago
idziubenko a369316aa3 added ensure_unicode
3 years ago
Иван Дзюбенко d47088d807 fixed rsync
3 years ago
Иван Дзюбенко 48c35ad6c9 fixed sync login encoding error
3 years ago
Иван Дзюбенко 2d29a566a0 fixed LDAP error message
3 years ago
idziubenko 8370d73da2 minor error message fix
3 years ago
idziubenko 1e6506f529 changed imports to relative
3 years ago
idziubenko b8384dd985 py3 fixes
3 years ago
idziubenko eeaad7c2b5 py3 changes
3 years ago
Хирецкий Михаил 437a8af872 Fix setup.py
3 years ago
Хирецкий Михаил a2114fea8d xdm -> display-manager
3 years ago
Хирецкий Михаил 0965e278a0 Исправлена ошибка отключения ресурсов в случае сбоя rsync
3 years ago
Хирецкий Михаил 0be421ff8f Remove old resume-remount
3 years ago
Хирецкий Михаил 8f6aa5bf83 Добавлен параметр, позволяющий запретить отключать удалённые ресурсы, в случае ошибки при синхронизации профиля
3 years ago
Хирецкий Михаил a6c10d8709 Увеличено время ожидание сети при подключении доменных ресурсов
3 years ago
Хирецкий Михаил 915951abec Синхронизация удалённого профиля при помощи zstd
3 years ago
Хирецкий Михаил a2674d482e Исправлено подключение ресуров при --sync off
3 years ago
Хирецкий Михаил 254004da89 Добавлено обновление путей fastlogin-domain
3 years ago
Хирецкий Михаил b57d09fca4 Исправлена первичная загрузка доменного профиля
3 years ago
Хирецкий Михаил 0fbd098e79 Отключение указание версии при монтировании ресурсов share,ftp,homes,remote
3 years ago
Хирецкий Михаил fb8a68f4ed Добавлена поддержка ssh+rsync для синхронизации профиля
3 years ago
Хирецкий Михаил 6887f7bc5f Использование параметра forcemandatory при монтировании cifs ресурсов только для remote
4 years ago
Хирецкий Михаил fa8006d207 Добавлена поддержка нормальной работы с блокировками с samba 4.11
4 years ago
Хирецкий Михаил e7f1b95d45 Рефакторинг: работа с файлами
6 years ago
Хирецкий Михаил b1f426c145 Добавлена проверка значения sr_samba_host при вводе в домен
6 years ago
Хирецкий Михаил 08891037bc Исправлена проверка пароля SMB ресурса
6 years ago
Хирецкий Михаил a3b86b4f91 Revert "Отключно указание версии используемой cifs"
6 years ago
Хирецкий Михаил 00f4800ed3 Исправлено использование переменной вместо автоматического определения домена
6 years ago
Хирецкий Михаил ccb76adeaf Отключно указание версии используемой cifs
6 years ago
Хирецкий Михаил 23f9d51922 Исправлена работа в домена на samba 4.8
6 years ago
Хирецкий Михаил f258e34299 Исправлена синхронизация профилей пользователей при reboot
6 years ago
Хирецкий Михаил 92da4ea6b6 Исправлена проверка наличия ресурсов на сервере в роли домена
6 years ago
Mike Khiretskiy 1ef0a80103 Исправлен bin/logout
7 years ago
Хирецкий Михаил 31bfec7c31 Рефакторинг
7 years ago
Хирецкий Михаил 6067a03d77 Рефакторинг
7 years ago
Хирецкий Михаил a6304942fc Рефакторинг. Вынос логики чтения /sys через отдельный класс.
7 years ago
Хирецкий Михаил 64c251adf6 Использование vers=1.0 при монтирование cifs
7 years ago
Хирецкий Михаил c411bf8558 Исправлен вызов метода
7 years ago
Хирецкий Михаил 19b495cf6b Исправлен доступ к ресурсам доменного пользователя во время синхронизации профиля
7 years ago
Хирецкий Михаил bd82db684f Удаление папки /home/.пользователь при отключении
7 years ago
Хирецкий Михаил 4b9f881860 Закрыт доступ к удалённому профилю доменного пользователя
7 years ago
Хирецкий Михаил 8734311aed Исправлено использование переменных домена
7 years ago
Хирецкий Михаил 2cf6b3915c Исключение запуска init.d/client в контейнере
7 years ago
Хирецкий Михаил e3801d4024 Увеличен интервал ожидания сети при загрузке перед запуском cl-client --mount
7 years ago
Хирецкий Михаил 537226c23e Исправлен скрипт восстановления точек монтирования удалённых ресурсов
7 years ago
Хирецкий Михаил 83e2646017 Добавлена переменная cl_sync_moved_set для возможности отключения
7 years ago
Хирецкий Михаил ce43769d3e Добавлен неудаляемый путь Laptop
7 years ago
Хирецкий Михаил dcf6da8dbf Добавлена переменная указывающая cache= при монтировании cifs
7 years ago
Хирецкий Михаил 95147f7427 Revert "Удалён метод смены пароля пользователя домена"
7 years ago
Хирецкий Михаил 1ca60a1591 Исправлен скрипт logout
8 years ago
Хирецкий Михаил d0b69787b0 Добавлено отключение доменных ресурсов у пользователей, которые
8 years ago
Хирецкий Михаил a9125f0c51 Исправление скриптов для новых путей
8 years ago
Хирецкий Михаил ed86b6b35e Удалён метод смены пароля пользователя домена
8 years ago
Хирецкий Михаил dbc1563f84 Обновлены иконки
8 years ago
Хирецкий Михаил fc021c453b Merge remote-tracking branch 'origin/master3.4'
8 years ago
Хирецкий Михаил 59e3b05237 Исправления для переводов
8 years ago
Хирецкий Михаил 9621c134b4 Измения связанные с порядком выполнения шаблонов.
8 years ago
Хирецкий Михаил e9002ecfe9 Исправлен сценарий init.d
8 years ago
Хирецкий Михаил 09efab834e Update copyrights.
8 years ago
Хирецкий Михаил 4fd61c7e0f Изменено получение параметров /proc/cmdline
9 years ago
Хирецкий Михаил 91f8affaa2 Исправлены переменные
9 years ago
Mike Khiretskiy 32b05656b1 Исправлено получение профиля с сервера.
9 years ago
Mike Khiretskiy 76171566a9 Refactoring
9 years ago
Mike Khiretskiy b0ce98e865 Исправления для совместимости с calculate-lib
9 years ago
Mike Khiretskiy 404ce951c3 Исправлен вход в домен с использованием wifi
9 years ago
Mike Khiretskiy aefe9d2a1a Изменен путь отладочного логгирования
9 years ago
Mike Khiretskiy ca85e24168 Добавлена отладка при ожидаении сети в init.d/client
9 years ago
Mike Khiretskiy 07911f92a9 Переход на cl-variable
9 years ago
Mike Khiretskiy dcfd826d43 Исправлены скрипты входа в сеанс для изменённого xdm login
9 years ago
Mike Khiretskiy 2d262a73d7 Удаление init.d/client из автозапуска при выводе из домена
9 years ago
Mike Khiretskiy 4bf835a216 Исправлен вывод rsync при ошибке
9 years ago
Mike Khiretskiy 38f5bb26fc Исправлена переменная выполнения шаблонов при вводе в домен
9 years ago
Mike Khiretskiy d1ad78ea30 Добавлена совместимость с rsync 3.1.0
9 years ago
Mike Khiretskiy ee3cc1cf05 Обновление перевода
9 years ago
Mike Khiretskiy 65ed2597e9 Исправлена зависимость setup.py от модуля calculate-lib
9 years ago
Mike Khiretskiy eb4e79488e Восстановлен запрос пароля при загрузке системы
9 years ago
Mike Khiretskiy 471b172924 Исправлен init.d/client
9 years ago
Mike Khiretskiy e7179a30bb Исправлено вычисление переменных
9 years ago
Mike Khiretskiy 9c80e47c40 Исправлено наложение шаблонов при входе в домен с livecd
9 years ago
Mike Khiretskiy bbb6f0b3c1 Исправлено условие для события ac_client_undomain
9 years ago
Mike Khiretskiy 45f6ef1ae5 Отключно наложение шаблонов при каждом cl-client --mount
9 years ago
Mike Khiretskiy 7c376cbfec Исправлен вывод из домена
9 years ago
Mike Khiretskiy 4ebd8efa30 Удалено использование os_remote_client
9 years ago
Mike Khiretskiy 277fa3d408 Добавлена опция монитрования cifs nomapposix для ядер 3.18
10 years ago

6
.gitignore vendored

@ -0,0 +1,6 @@
revert_changes_to_vmachine
push_to_vmachine*
.vscode
*.pyc
*.pyo
*.bak

@ -1,136 +0,0 @@
#!/usr/bin/env python
#-*- coding: utf-8 -*-
# Copyright 2013-2014 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
import __future__
import gobject
import dbus
import os
from os import path
import dbus.mainloop.glib
from calculate.lib.datavars import DataVars, VariableError
from calculate.lib.utils.files import isMount, getRunCommands
from calculate.client.client import Client
from argparse import ArgumentParser
from time import sleep
class ResourceRemounter:
"""
Object contains one method for handle 'Resuming' dbus signal.
'handle_resuming' method checks and remounts user remote resources.
Also the object refreshes NSS-cache.
"""
def __init__(self,dv):
self.dv = dv
self.dv.defaultModule = 'client'
self.client = Client()
self.client.clVars = dv
self.check_server(True)
def check_server(self,refresh_nscd=False):
"""
Check the available of domain server and refresh nscd cache
"""
if self.client.checkDomainServer(
self.dv.Get('cl_remote_host'),
self.dv.Get('os_net_domain')):
try:
if refresh_nscd and path.exists(self.nscd_refresh):
os.system(self.nscd_refresh)
except:
pass
return True
return False
nscd_refresh = "/usr/sbin/nscd-refresh"
def remount_remote(self):
"""
Remount remote resource of the domain
"""
try:
self.client.mountRemoteRes(self.dv.Get('cl_remote_pw'),
self.dv.Get('cl_client_remote_path'),
self.dv.Get('cl_remote_host'))
except:
pass
def remount_user_resources(self):
"""
Remount user resource of the domain
"""
try:
self.client.mountUserDomainRes(self.dv.Get('ur_login'),
self.dv.Get('desktop.ur_password'),
int(self.dv.Get('ur_uid')),
int(self.dv.Get('ur_gid')),
"unix","share","homes","ftp")
except:
pass
def handle_resuming(self,statename):
print("Restoring remote mounts for user %s"%self.dv.Get('ur_login'))
# waiting for the domain
for wait in [1,2,5,10]:
try:
if self.check_server(True):
break
except:
pass
sleep(wait)
# check and remount remote resources
self.remount_remote()
self.remount_user_resources()
def main(argv):
# processing the user argument
argp = ArgumentParser(add_help=True)
argp.add_argument("user",help="tracked user",metavar="USER")
namespace = argp.parse_args(argv[1:])
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
bus = dbus.SystemBus()
# initialization calculate datavars and quitting on an error
try:
dv = DataVars()
dv.importData()
dv.flIniFile()
dv.Set('ur_login',namespace.user)
if dv.Get('desktop.ur_domain_set') == 'off':
print("%s isn't a domain user"%namespace.user)
sys.exit(0)
except VariableError as e:
sys.stderr.write(str(e)+'\n')
sys.exit(1)
rm = ResourceRemounter(dv)
bus.add_signal_receiver(rm.handle_resuming,dbus_interface="org.freedesktop.UPower",
signal_name = "NotifyResume")
loop = gobject.MainLoop()
context = loop.get_context()
while True:
# need for dbus processing
context.iteration(1)
sleep(1)
if __name__ == '__main__':
main(sys.argv)

@ -1,4 +1,3 @@
# Calculate chmod=0755
#!/bin/bash
source /lib/rc/sh/functions.sh
@ -6,18 +5,39 @@ source /lib/rc/sh/functions.sh
variable_value()
{
local varname=$1
/usr/sbin/cl-core-variables-show --only-value $varname
/usr/libexec/calculate/cl-variable --value $varname
}
ONLINE_USERS="`variable_value desktop.cl_desktop_online_user`"
# получить доменных пользователей которые не online, но их ресурсы подключены
domain_users() {
for mp in $(grep -Po "^//.*/homes\s+.*Home" /proc/mounts |
awk '{print $2}');do
local username=$(basename $(dirname $mp))
for user in ${ONLINE_USERS//,/ }
do
if [[ $user == $username ]]
then
username=
fi
done
[[ -n $username ]] && echo $username
done | sort | uniq
}
DOMAIN_USERS=( $(domain_users) )
# если есть пользователи в сеансе или выполняется выход
if [[ -n $ONLINE_USERS ]] || pgrep -f 'xdm/xdm --logout' &>/dev/null
if [[ -n $ONLINE_USERS ]] || [[ -n $DOMAIN_USERS ]] || pgrep -f 'xdm/xdm --logout' &>/dev/null
then
if [[ -n $ONLINE_USERS ]] || [[ -n $DOMAIN_USERS ]]
then
ebegin "Logout users"
fi
# есть пользователи в сеансе
if [[ -n $ONLINE_USERS ]]
then
ebegin "Logout users"
# переменная online_data возвращает строки пользователь,дисплей
for user_disp in $(variable_value desktop.cl_desktop_online_data | sed -r "s/;/ /g")
do
@ -25,13 +45,30 @@ then
disp=$(echo $user_disp | cut -d: -f2)
# завершаем сессию пользователя
/usr/sbin/cl-core --method desktop_logout $user &>/dev/null
# удаляем запить о пользователе
/usr/bin/sessreg -d -l :$disp $user &>/dev/null
sleep 1
# если корректное завершение не удалось
if who | grep -q -P "$user.*:$disp"
then
# удаляем запить о пользователе
/usr/bin/sessreg -d -l :$disp $user &>/dev/null
# выполняем принудительный выход из сеанса
USER="$user" /usr/share/calculate/xdm/xdm --logout &>/dev/null &
fi
done
fi
if [[ -n "${DOMAIN_USERS[@]}" ]]
then
for user in ${DOMAIN_USERS[@]}
do
# выполняем принудительный выход из сеанса
USER="$user" /usr/share/calculate/xdm/xdm --logout &>/dev/null &
done
fi
if [[ -n $ONLINE_USERS ]] || [[ -n $DOMAIN_USERS ]]
then
eend 0
fi
# ожидаение завершения процесса выхода пользователя из сеанса
if pgrep -f 'xdm/xdm --logout' &>/dev/null
then

@ -1,5 +1,5 @@
#!/sbin/runscript
# Copyright 2008-2012 Calculate Ltd. http://www.calculate-linux.org
#!/sbin/openrc-run
# Copyright 2008-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.
@ -18,39 +18,42 @@ depend() {
after bootmisc consolefont modules netmount
after readahead-list ypbind autofs openvpn gpm lircmd
after cupsd fbcondecor sshd cron wicd
before xdm
before display-manager
after acpid consolekit hald xfs
keyword -timeout -docker -lxc -systemd-nspawn -vserver
}
variable_value()
{
local varname=$1
cl-core-variables-show --only-value client.$varname
/usr/libexec/calculate/cl-variable --value $*
}
start() {
# Mount remote Samba filesystems.
# Identifing domain server by cl-client variables
local SERVER=`variable_value cl_remote_host`
local SERVERLIVE=`variable_value cl_remote_host_live`
local SERVERPW=`variable_value cl_remote_pw`
OUT=$(variable_value client.cl_remote_host client.cl_remote_host_live client.cl_remote_pw main.cl_template_location)
local SERVER="$(echo "$OUT" | sed -n '1p')"
local SERVERLIVE="$(echo "$OUT" | sed -n '2p')"
local SERVERPW="$(echo "$OUT" | sed -n '3p')"
local TEMPLATES="$(echo "$OUT" | sed -n '4p')"
[[ -z $SERVERLIVE ]] && SERVERLIVE=$SERVER
if [[ -n $SERVERLIVE ]]
then
ebegin "Mounting domain resources"
local NET_CONF=`cl-core-variables-show --only-value install.os_install_net_conf`
local NET_CONF=`variable_value install.os_install_net_conf`
if [[ $NET_CONF = "networkmanager" ]] && type qdbus &>/dev/null
then
for COUNT in $( seq 0 24 )
for COUNT in $( seq 0 32 )
do
# https://developer.gnome.org/NetworkManager/stable/nm-dbus-types.html
NET_STATE=`qdbus --system org.freedesktop.NetworkManager /org/freedesktop/NetworkManager org.freedesktop.NetworkManager.state`
if [[ $NET_STATE = 40 ]]
then
ping -w4 -i0.5 -c3 $SERVERLIVE &>/dev/null && break || sleep 0.5
else
break
[[ $NET_STATE = 20 && $COUNT -lt 16 ]] && sleep 0.5 || break
fi
done
else
@ -61,10 +64,10 @@ start() {
fi
if [[ -z $SERVER ]]
then
LANG=C cl-client -T overlay,local $SERVERLIVE && res=$? &&
cl-setup-system -T remote &>/dev/null
LANG=C /usr/bin/cl-client -T ${TEMPLATES/,remote/} $SERVERLIVE && res=$? &&
/usr/bin/cl-setup-system -T remote &>/dev/null
else
LANG=C cl-client --mount
LANG=C /usr/bin/cl-client --mount
fi
res=$?
eend $res "Some samba remote resources to mount"

@ -1,5 +1,5 @@
#! /bin/sh
# Copyright 2010 Calculate Ltd. http://www.calculate-linux.org
# Copyright 2010-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.
@ -13,21 +13,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
/usr/sbin/env-update
source /etc/profile
source /usr/share/calculate/xdm/functions
if [ -e '/usr/sbin/cl-client-sync-login' ];
then
if [[ "${DOMAIN_USER}" == "on" ]]
then
ERRORLOG=`/usr/sbin/cl-client-sync-login --gui-progress --gui-warning $USER 2>&1`
# log error
if [ "$?" -gt "0" ];
then
echo "$ERRORLOG" >> $FILE_LOG
exit 1
fi
fi
fi
exit 0
run_script() {
if [ -e '/usr/bin/cl-client-sync-login' ];
then
if [[ "${DOMAIN_USER}" == "on" ]]
then
ERRORLOG=`/usr/bin/cl-client-sync-login --gui-progress --gui-warning $USER 2>&1`
# log error
if [ "$?" -gt "0" ];
then
echo "$ERRORLOG" >> $FILE_LOG
return 1
fi
fi
fi
return 0
}

@ -1,25 +0,0 @@
#! /bin/sh
# 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.
/usr/sbin/env-update
source /etc/profile
source /usr/share/calculate/xdm/functions
if [[ "${DOMAIN_USER}" == "on" ]]
then
/usr/sbin/cl-client-resume-remount ${USER} &
fi
exit 0

@ -1,5 +1,5 @@
#! /bin/sh
# Copyright 2010 Calculate Ltd. http://www.calculate-linux.org
# Copyright 2010-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.
@ -13,21 +13,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
/usr/sbin/env-update
source /etc/profile
source /usr/share/calculate/xdm/functions
if [ -e '/usr/sbin/cl-client-sync-logout' ];
then
if [[ "${DOMAIN_USER}" == "on" ]]
then
ERRORLOG=`/usr/sbin/cl-client-sync-logout $USER 2>&1`
# log errors
if [ "$?" -gt "0" ];
then
echo "$ERRORLOG" >> $FILE_LOG
exit 1
fi
fi
fi
exit 0
run_script() {
if [ -e '/usr/bin/cl-client-sync-logout' ];
then
if [[ "${DOMAIN_USER}" == "on" ]]
then
ERRORLOG=`/usr/bin/cl-client-sync-logout $USER 2>&1`
# log errors
if [ "$?" -gt "0" ];
then
echo "$ERRORLOG" >> $FILE_LOG
return 1
fi
fi
fi
return 0
}

@ -1,25 +0,0 @@
#! /bin/sh
# 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.
/usr/sbin/env-update
source /etc/profile
source /usr/share/calculate/xdm/functions
if [[ "${DOMAIN_USER}" == "on" ]]
then
pkill -f "cl-client-resume-remount ${USER}"
fi
exit 0

File diff suppressed because it is too large Load Diff

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
# Copyright 2012-2013 Calculate Ltd. http://www.calculate-linux.org
# Copyright 2012-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.
@ -14,36 +14,53 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import os, sys, time
import os
import sys
import time
from calculate.lib.utils.files import getModeFile
from calculate.lib.cl_print import color_print
from calculate.lib.cl_ldap import ldapUser
from calculate.lib.cl_ldap import ldapUser
from calculate.lib.utils.common import ensure_unicode
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_client3',sys.modules[__name__])
from functools import reduce
_ = lambda x: x
setLocalTranslate('cl_client3', sys.modules[__name__])
class Printable():
def __init__(self, parent):
if isinstance(parent, Printable):
self.parent = parent.parent
self.parent = parent
def printERROR(self, s):
self.parent.printERROR(s)
class _shareData(color_print):
class _shareData(Printable):
"""Share class"""
fileName = ""
template = ""
lenData = 0
data = []
def getDataInFile(self, fileName='', lenData=0):
"""Get data list from file"""
return filter(lambda x: len(x)==lenData,
map(lambda x: x.rstrip().split(":"), open(fileName)))
return [z for z in [x.rstrip().split(":") for x in open(fileName)] if len(z) == lenData]
def getFileAccess(self, perm="READ"):
if perm == "READ":
if os.access(self.fileName, os.R_OK):
return True
else:
self.printERROR(_("Failed to read the file")+_(": ") +
self.printERROR(_("Failed to read the file") + _(": ") +
self.fileName)
return False
elif perm == "WRITE":
if os.access(self.fileName, os.W_OK):
return True
else:
self.printERROR(_("Failed to write to file")+_(": ") +
self.printERROR(_("Failed to write to file") + _(": ") +
self.fileName)
return False
@ -55,14 +72,14 @@ class _shareData(color_print):
elif self.getFileAccess(perm="READ"):
self.data = self.getDataInFile(fileName=self.fileName,
lenData=self.lenData)
return self.data
return self.data
else:
return False
def save(self):
if self.getFileAccess(perm="WRITE"):
buff = "\n".join(map(lambda x: ":".join(x), self.data)) + "\n"
FD = open(self.fileName, "w+")
buff = "\n".join((":".join(x) for x in self.data)) + "\n"
FD = open(self.fileName, "w+")
FD.write(buff)
FD.close()
return True
@ -73,9 +90,10 @@ class _shareData(color_print):
if self.getData() is False:
return False
else:
self.data = filter(lambda x: x[0]!=name, self.data)
self.data = [x for x in self.data if x[0] != name]
return True
@ensure_unicode
def replace(self, name, listData):
if self.getData() is False:
return False
@ -101,24 +119,27 @@ class _shareData(color_print):
if self.getData() is False:
return False
else:
listData = filter(lambda x: x[0]==name, self.data)
# listData = filter(lambda x: x[0] == name, self.data)
listData = [x for x in self.data if x[0] == name]
if listData:
return listData[0]
else:
return []
class passwd(_shareData):
'''Class for working with the file /etc/passwd'''
fileName = "/etc/passwd"
template = "%(login)s:x:%(uid)s:%(gid)s:%(gecos)s:%(directory)s:%(shell)s"
lenData = 7
@ensure_unicode
def add(self, name, uid, gid, gecos="", directory="", shell="/bin/bash"):
if not directory:
directory = "/home/%s" %name
userData = self.template%{'login':name, 'uid':uid, 'gid':gid,
'gecos':gecos, 'directory':directory,
'shell':shell}
directory = "/home/%s" % name
userData = self.template % {'login': name, 'uid': uid, 'gid': gid,
'gecos': gecos, 'directory': directory,
'shell': shell}
userList = userData.split(":")
if self.getData() is False:
return False
@ -130,15 +151,17 @@ class passwd(_shareData):
self.data.append(userList)
return True
class group(_shareData):
'''Class for working with the file /etc/group'''
fileName = "/etc/group"
template = "%(group_name)s:x:%(gid)s:%(user_list)s"
lenData = 4
def add(self, name, gid, userList=[]):
groupData = self.template%{'group_name':name, 'gid':gid,
'user_list':','.join(userList)}
@ensure_unicode
def add(self, name, gid, userList=()):
groupData = self.template % {'group_name': name, 'gid': gid,
'user_list': ','.join(userList)}
groupList = groupData.split(":")
if self.getData() is False:
return False
@ -150,11 +173,12 @@ class group(_shareData):
self.data.append(groupList)
return True
@ensure_unicode
def replace(self, name, listData):
if self.getData() is False:
return False
else:
delEmpty = lambda y: filter(lambda x: x.strip(), y)
delEmpty = lambda y: [x for x in y if x.strip()]
flagFound = False
for index, listDataOld in enumerate(self.data):
if name == listDataOld[0]:
@ -165,12 +189,12 @@ class group(_shareData):
# Constant gid
listDataWork[2] = self.data[index][2]
# Join user list
userList = delEmpty(self.data[index][3].split(',') +\
userList = delEmpty(self.data[index][3].split(',') +
listDataWork[3].split(','))
# unique list
userList = reduce(lambda x,y:\
(y in x and x) or x +[y],
userList,[])
userList = reduce(lambda x, y: \
(y in x and x) or x + [y],
userList, [])
listDataWork[3] = ','.join(userList)
self.data[index] = listDataWork
if flagFound:
@ -199,8 +223,7 @@ class group(_shareData):
if self.getData() is False:
return False
else:
dataGroup = map(lambda x: x[3].split(","),
filter(lambda x: x[0]==name, self.data))
dataGroup = [x[3].split(",") for x in self.data if x[0] == name]
if dataGroup:
return dataGroup[0]
else:
@ -214,28 +237,31 @@ class group(_shareData):
for dataList in self.data:
groupName, x, gid, userList = dataList
if groupName in groups:
usersList = ",".join(filter(lambda x: x!=userName,
userList.split(",")))
# usersList = ",".join(filter(lambda x: x != userName,
# userList.split(",")))
usersList = ",".join([x for x in userList.split(",") if x != userName])
dataList[3] = usersList
data.append(dataList)
self.data = data
return self.data
class shadow(_shareData):
'''Class for working with the file /etc/shadow'''
fileName = "/etc/shadow"
template = "%(login)s:%(hash)s:%(shadowLastChange)s:\
%(shadowMin)s:%(shadowMax)s:%(shadowWarning)s:::"
template = ("%(login)s:%(hash)s:%(shadowLastChange)s:"
"%(shadowMin)s:%(shadowMax)s:%(shadowWarning)s:::")
lenData = 9
@ensure_unicode
def add(self, name, pwdHash,
shadowLastChange=str(int(time.time()/86400)), shadowMin="0",
shadowMax="99999", shadowWarning="7"):
shadowData = self.template%{'login':name, 'hash':pwdHash,
'shadowLastChange':shadowLastChange,
'shadowMin':shadowMin,
'shadowMax':shadowMax,
'shadowWarning':shadowWarning}
shadowLastChange=str(int(time.time() / 86400)), shadowMin="0",
shadowMax="99999", shadowWarning="7"):
shadowData = self.template % {'login': name, 'hash': pwdHash,
'shadowLastChange': shadowLastChange,
'shadowMin': shadowMin,
'shadowMax': shadowMax,
'shadowWarning': shadowWarning}
shadowList = shadowData.split(":")
if self.getData() is False:
return False
@ -248,32 +274,32 @@ class shadow(_shareData):
return True
def equally(self, listDataA, listDataB):
getData = lambda x: x[:1] + x[2:]
getData = lambda x: x[:1] + x[2:]
return _shareData.equally(self, getData(listDataA),
getData(listDataB))
class _shareCache():
class _shareCache(_shareData):
def save(self):
path = os.path.dirname(self.fileName)
if not os.path.exists(path):
try:
os.makedirs(path)
except:
self.printERROR(_("Failed to create directory %s")%path)
except OSError:
self.printERROR(_("Failed to create directory %s") % path)
return False
if not os.path.exists(self.fileName):
try:
open(self.fileName, "w")
except:
self.printERROR(_("Failed to create file %s")%self.fileName)
open(self.fileName, "w").close()
except IOError:
self.printERROR(_("Failed to create file %s") % self.fileName)
return False
if self.getFileAccess(perm="WRITE"):
modeFile = 0600
modeFile = 0o600
if getModeFile(self.fileName, mode="mode") != modeFile:
os.chmod(self.fileName, modeFile)
buff = "\n".join(map(lambda x: ":".join(x), self.data)) + "\n"
FD = open(self.fileName, "w+")
buff = "\n".join((":".join(x) for x in self.data)) + "\n"
FD = open(self.fileName, "w+")
FD.write(buff)
FD.close()
return True
@ -294,9 +320,11 @@ class _shareCache():
else:
return False
class cachePasswd(_shareCache, passwd):
fileName = "/var/lib/calculate/calculate-client/cache/passwd"
class cacheGroup(_shareCache, group):
fileName = "/var/lib/calculate/calculate-client/cache/group"
@ -306,27 +334,31 @@ class cacheGroup(_shareCache, group):
def equally(self, listDataA, listDataB):
return _shareData.equally(self, listDataA, listDataB)
class cacheShadow(_shareCache, shadow):
fileName = "/var/lib/calculate/calculate-client/cache/shadow"
class cacheCreateGroup(cacheGroup):
fileName = "/var/lib/calculate/calculate-client/cache/create_group"
class cacheCreatePasswd(cachePasswd):
fileName = "/var/lib/calculate/calculate-client/cache/create_passwd"
class userCache(color_print):
class userCache(Printable):
ldapObj = ldapUser()
def addUserToCache(self, userName, pwdHash):
'''Add LDAP user to cache'''
ldapData = self.ldapObj.getUserLdapInfo(userName, shadowAttr=True)
if not ldapData:
self.printERROR(_("User %s not found in LDAP")%userName)
self.printERROR(_("User %s not found in LDAP") % userName)
return False
groupName = ldapData['group']
groupName = ldapData['group']
# Add user
cachePasswdObj = cachePasswd()
cachePasswdObj = cachePasswd(self)
if not cachePasswdObj.add(userName, ldapData['uid'], ldapData['gid'],
gecos=ldapData['fullName'],
directory=ldapData['home'],
@ -334,9 +366,9 @@ class userCache(color_print):
return False
if not cachePasswdObj.save():
return False
cacheGroupObj = cacheGroup()
cacheGroupObj = cacheGroup(self)
# Add primary group
if not cacheGroupObj.add(groupName,ldapData['gid']):
if not cacheGroupObj.add(groupName, ldapData['gid']):
return False
# Add second groups
secondGroupsData = ldapData['groups']
@ -353,14 +385,14 @@ class userCache(color_print):
if not cacheGroupObj.add(groupName, gid, usersInGroup):
return False
allUsersSecondGroups.append(groupName)
deleteSecondGroups = list(set(cacheSecondUserGroups) -\
deleteSecondGroups = list(set(cacheSecondUserGroups) - \
set(allUsersSecondGroups))
if not cacheGroupObj.deleteUserInGroups(userName, deleteSecondGroups):
return False
if not cacheGroupObj.save():
return False
# Add shadow user
cacheShadowObj = cacheShadow()
cacheShadowObj = cacheShadow(self)
if not cacheShadowObj.add(userName, pwdHash,
shadowLastChange=ldapData['shadowLastChange'],
shadowMin=ldapData['shadowMin'],
@ -373,14 +405,14 @@ class userCache(color_print):
def delUserFromCacheCreate(self, userName):
'''Delete LDAP user from createCache'''
cacheCreatePasswdObj = cacheCreatePasswd()
cacheCreatePasswdObj = cacheCreatePasswd(self)
cacheUserData = cacheCreatePasswdObj.get(userName)
if cacheUserData is False:
return False
if not cacheUserData:
return True
gid = cacheUserData[3]
cacheCreateGroupObj = cacheCreateGroup()
cacheCreateGroupObj = cacheCreateGroup(self)
cacheSecondGroups = cacheCreateGroupObj.getSecondUserGroups(userName)
if cacheSecondGroups is False:
return False
@ -393,13 +425,11 @@ class userCache(color_print):
return False
if not cacheCreatePasswdObj.save():
return False
#delete groups
usersGids = map(lambda x: x[3], cacheCreatePasswdObj.data)
deleteGroups = map(lambda x: x[0],
filter(lambda x: not x[2] in usersGids and not x[3],
cacheCreateGroupObj.data))
# delete groups
usersGids = [x[3] for x in cacheCreatePasswdObj.data]
deleteGroups = [x[0] for x in cacheCreateGroupObj.data if not x[2] in usersGids and not x[3]]
for delGroupName in deleteGroups:
if not cacheCreateGroupObj.delete(delGroupName):
if not cacheCreateGroupObj.delete(delGroupName):
return False
if not cacheCreateGroupObj.save():
return False
@ -407,14 +437,14 @@ class userCache(color_print):
def delUserFromCache(self, userName):
'''Delete LDAP user from cache'''
cachePasswdObj = cachePasswd()
cachePasswdObj = cachePasswd(self)
cacheUserData = cachePasswdObj.get(userName)
if cacheUserData is False:
return False
if not cacheUserData:
return True
gid = cacheUserData[3]
cacheGroupObj = cacheGroup()
cacheGroupObj = cacheGroup(self)
cacheSecondGroups = cacheGroupObj.getSecondUserGroups(userName)
if cacheSecondGroups is False:
return False
@ -426,18 +456,16 @@ class userCache(color_print):
return False
if not cachePasswdObj.save():
return False
#delete groups
usersGids = map(lambda x: x[3], cachePasswdObj.data)
deleteGroups = map(lambda x: x[0],
filter(lambda x: not x[2] in usersGids and not x[3],
cacheGroupObj.data))
# delete groups
usersGids = [x[3] for x in cachePasswdObj.data]
deleteGroups = [x[0] for x in cacheGroupObj.data if not x[2] in usersGids and not x[3]]
for delGroupName in deleteGroups:
if not cacheGroupObj.delete(delGroupName):
if not cacheGroupObj.delete(delGroupName):
return False
if not cacheGroupObj.save():
return False
# delete shadow user
cacheShadowObj = cacheShadow()
cacheShadowObj = cacheShadow(self)
if not cacheShadowObj.delete(userName):
return False
if not cacheShadowObj.save():
@ -446,13 +474,13 @@ class userCache(color_print):
def delUserFromSystem(self, userName):
'''Delete LDAP user from system files ( passwd, group, shadow )'''
cacheCreatePasswdObj = cacheCreatePasswd()
cacheCreatePasswdObj = cacheCreatePasswd(self)
cacheCreatePasswdData = cacheCreatePasswdObj.get(userName)
if cacheCreatePasswdData is False:
return False
if not cacheCreatePasswdData:
return True
passwdObj = passwd()
passwdObj = passwd(self)
userData = passwdObj.get(userName)
if userData is False:
return False
@ -464,18 +492,18 @@ class userCache(color_print):
if not passwdObj.save():
return False
# delete user group
groupObj = group()
groupObj = group(self)
listGroupData = groupObj.getData()
if listGroupData is False:
return False
cacheCreateGroupObj = cacheCreateGroup()
cacheCreateGroupObj = cacheCreateGroup(self)
secondUsersGroups = groupObj.getSecondUserGroups(userName)
usersGids = map(lambda x: x[3], passwdObj.data)
usersGids = [x[3] for x in passwdObj.data]
listGroupDataWork = []
for index, groupData in enumerate(listGroupData):
groupName, x, gid, listUsers = groupData
listUsers = filter(lambda x: x.strip(), listUsers.split(','))
listUsers = ",".join(filter(lambda x: x!=userName, listUsers))
listUsers = [x.strip() for x in listUsers.split(',')]
listUsers = ",".join(filter(lambda x: x != userName, listUsers))
cacheCreateGroupData = cacheCreateGroupObj.get(groupName)
if cacheCreateGroupData is False:
return False
@ -487,7 +515,7 @@ class userCache(color_print):
if not groupObj.save():
return False
# delete user shadow
shadowObj = shadow()
shadowObj = shadow(self)
shadowData = shadowObj.get(userName)
if shadowData is False:
return False
@ -515,11 +543,11 @@ class userCache(color_print):
def deleteCacheUsersFromSystem(self):
'''Delete cache users from system'''
cacheCreatePasswdObj = cacheCreatePasswd()
cacheCreatePasswdObj = cacheCreatePasswd(self)
cacheCreateListPasswdData = cacheCreatePasswdObj.getData()
if cacheCreateListPasswdData is False:
return False
delUsersPasswd = map(lambda x: x[0], cacheCreateListPasswdData)
delUsersPasswd = [x[0] for x in cacheCreateListPasswdData]
for delUser in delUsersPasswd:
if not self.delUserFromSystem(delUser):
return False
@ -527,7 +555,7 @@ class userCache(color_print):
def getLoginDomainUsers(self):
'''Get all domain login users'''
cacheCreatePasswdObj = cacheCreatePasswd()
cacheCreatePasswdObj = cacheCreatePasswd(self)
cacheListCreatePasswdData = cacheCreatePasswdObj.getData()
if cacheListCreatePasswdData is False:
return False
@ -535,19 +563,19 @@ class userCache(color_print):
def addCacheUsersFromSystem(self):
'''Add cache users from system'''
cachePasswdObj = cachePasswd()
cachePasswdObj = cachePasswd(self)
cacheListPasswdData = cachePasswdObj.getData()
if cacheListPasswdData is False:
if not isinstance(cacheListPasswdData, (list, tuple)):
return False
# Add cache passwd users to system
passwdObj = passwd()
cacheCreatePasswdObj = cacheCreatePasswd()
passwdObj = passwd(self)
cacheCreatePasswdObj = cacheCreatePasswd(self)
cacheListCreatePasswdData = cacheCreatePasswdObj.getData()
if cacheListCreatePasswdData is False:
return False
# remove deleted users
cacheUsers = map(lambda x: x[0], cacheListPasswdData)
createUsers = map(lambda x: x[0], cacheListCreatePasswdData)
cacheUsers = [x[0] for x in cacheListPasswdData]
createUsers = [x[0] for x in cacheListCreatePasswdData]
deletedUsers = list(set(createUsers) - set(cacheUsers))
for delUser in deletedUsers:
if not self.delUserFromSystem(delUser):
@ -573,9 +601,9 @@ class userCache(color_print):
return False
if retCacheCreate:
if not passwdObj.add(userName, uid, gid,
gecos=gecos,
directory=directory,
shell=shell):
gecos=gecos,
directory=directory,
shell=shell):
return False
addUsers.append(userName)
addUsersGid.append(gid)
@ -586,41 +614,43 @@ class userCache(color_print):
return False
if not cacheCreatePasswdObj.save():
return False
cacheShadowObj = cacheShadow()
cacheShadowObj = cacheShadow(self)
cacheListShadowData = cacheShadowObj.getData()
if cacheListShadowData is False:
if not isinstance(cacheListShadowData, (list, tuple)):
return False
# Add cache shadow users to system
shadowObj = shadow()
shadowObj = shadow(self)
for cacheShadowData in cacheListShadowData:
userName, pwdHash, shadowLastChange, shadowMin, shadowMax,\
shadowWarning, x,x,x = cacheShadowData
userName, pwdHash, shadowLastChange, shadowMin, shadowMax, \
shadowWarning, x, x, x = cacheShadowData
if userName in addUsers:
if not shadowObj.add(userName, pwdHash,
shadowLastChange=shadowLastChange,
shadowMin=shadowMin,
shadowMax=shadowMax,
shadowWarning=shadowWarning):
shadowLastChange=shadowLastChange,
shadowMin=shadowMin,
shadowMax=shadowMax,
shadowWarning=shadowWarning):
return False
if shadowObj.data:
if not shadowObj.save():
return False
cacheGroupObj = cacheGroup()
cacheGroupObj = cacheGroup(self)
cacheListGroupData = cacheGroupObj.getData()
if cacheListGroupData is False:
if not isinstance(cacheListGroupData, (list, tuple)):
return False
cacheCreateGroupObj = cacheCreateGroup()
cacheCreateGroupObj = cacheCreateGroup(self)
# Add cache group users to system
groupObj = group()
groupObj = group(self)
setAddUsers = set(addUsers)
for cacheGroupData in cacheListGroupData:
groupName, x, gid, listUsers = cacheGroupData
retGroup = groupObj.get(groupName)
if retGroup is False:
return False
listUsers = filter(lambda x: x.strip(), listUsers.split(','))
# listUsers = filter(lambda x: x.strip(), listUsers.split(','))
listUsers = [x for x in listUsers.split(',') if x.strip()]
if setAddUsers & set(listUsers) or gid in addUsersGid:
listUsers = filter(lambda x: not x in notAddUsers, listUsers)
# listUsers = filter(lambda x: not x in notAddUsers, listUsers)
listUsers = [x for x in listUsers if not x in notAddUsers]
if not retGroup:
if not cacheCreateGroupObj.add(groupName, gid, listUsers):
return False
@ -641,17 +671,18 @@ class userCache(color_print):
if not self.isConnectToLdap():
self.printERROR(_("Failed to connect to the LDAP server"))
return False
cachePasswdObj = cachePasswd()
cachePasswdObj = cachePasswd(self)
cacheListPasswdData = cachePasswdObj.getData()
if cacheListPasswdData is False:
return False
if not cacheListPasswdData:
if (not isinstance(cacheListPasswdData, (tuple, list)) or
not cacheListPasswdData):
return True
cacheGroupObj = cacheGroup()
cacheGroupObj = cacheGroup(self)
cacheListGroupData = cacheGroupObj.getData()
if cacheListGroupData is False:
return False
cacheShadowObj = cacheShadow()
cacheShadowObj = cacheShadow(self)
deletedCacheUsers = []
for cachePasswdData in cacheListPasswdData:
userName, x, uid, gid, gecos, directory, shell = cachePasswdData
@ -659,8 +690,7 @@ class userCache(color_print):
if not ldapData:
deletedCacheUsers.append(userName)
continue
cacheGroupData = map(lambda x: x[0], filter(lambda x: x[2]==gid,
cacheListGroupData))
cacheGroupData = [x[0] for x in cacheListGroupData if x[2] == gid]
if not cacheGroupData:
deletedCacheUsers.append(userName)
continue
@ -671,29 +701,26 @@ class userCache(color_print):
if not cacheShadowData:
deletedCacheUsers.append(userName)
continue
x,x, shadowLastChange, shadowMin, shadowMax, shadowWarning,\
x,x,x = cacheShadowData
x, x, shadowLastChange, shadowMin, shadowMax, shadowWarning, \
x, x, x = cacheShadowData
groups = cacheGroupObj.getSecondUserGroups(userName)
gidsGroups = map(lambda x: x[2],
filter(lambda x : x[0] in groups,
cacheGroupObj.data))
gidsGroups = [x[2] for x in cacheGroupObj.data if x[0] in groups]
userShadowDict = {'uid': uid,
'gid': gid,
'fullName': gecos,
'home': directory,
'group': groupName,
'groups': (groups,gidsGroups),
'loginShell':shell,
'shadowLastChange':shadowLastChange,
'shadowMin':shadowMin,
'shadowMax':shadowMax,
'shadowWarning':shadowWarning}
'groups': (groups, gidsGroups),
'loginShell': shell,
'shadowLastChange': shadowLastChange,
'shadowMin': shadowMin,
'shadowMax': shadowMax,
'shadowWarning': shadowWarning}
flagDeleteUser = False
for attr, value in userShadowDict.items():
if attr == "groups":
for index, val in enumerate(value):
if set(map(lambda x: x[index],
ldapData[attr])) != set(val):
if set([x[index] for x in ldapData[attr]]) != set(val):
flagDeleteUser = True
break
else:
@ -711,8 +738,8 @@ class userCache(color_print):
def clearCache(self):
'''Clear cache files'''
cacheObjs = (cachePasswd(), cacheShadow(), cacheGroup(),
cacheCreateGroup(), cacheCreatePasswd())
cacheObjs = (cachePasswd(self), cacheShadow(self), cacheGroup(self),
cacheCreateGroup(self), cacheCreatePasswd(self))
for cacheObj in cacheObjs:
if not cacheObj.save():
return False

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
# Copyright 2012-2013 Calculate Ltd. http://www.calculate-linux.org
# Copyright 2012-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.
@ -15,14 +15,15 @@
# limitations under the License.
__app__ = 'calculate-client'
__version__ = '3.1.8'
__version__ = '3.4.2'
import os
import sys
from calculate.lib.datavars import DataVars
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_client3',sys.modules[__name__])
setLocalTranslate('cl_client3', sys.modules[__name__])
class DataVarsClient(DataVars):
"""Variable class for client package"""

@ -0,0 +1,92 @@
# -*- coding: utf-8 -*-
# Copyright 2010-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 pexpect
import sys
import os
import tempfile
from calculate.lib.utils.ip import check_port
from calculate.lib.utils.files import readFile
class ProfileSyncerError(Exception):
pass
class ProfileSyncer():
def __init__(self, hostname, port, username, passwd):
self.hostname = hostname
self.port = port
self.username = username
self.passwd = passwd
self.exitstatus = None
def check(self):
return check_port(self.hostname, self.port)
def create_process(self, source, target, *params):
#подключение к домену и синхрозизация
self.process = pexpect.spawn('/usr/bin/rsync',
['--rsh=/usr/bin/ssh -o "ControlMaster no" -o "StrictHostKeyChecking no" -p{port} {username}@{hostname}'.format(
port=self.port, hostname=self.hostname, username=self.username),
'--info=progress2'] + list(params) + [source, target])
def readfile(self, filename):
tmp_fn = tempfile.mktemp()
for i in self.sync(filename, tmp_fn):
pass
if self.exitstatus == 0:
data = readFile(tmp_fn)
if os.path.exists(tmp_fn):
os.unlink(tmp_fn)
return data
raise ProfileSyncerError("Profile server not found")
def exists(self, filename):
env = dict(os.environ)
env["LANG"] = "C"
#подключение к домену и синхрозизация
self.process = pexpect.spawn('/usr/bin/rsync',
['--rsh=/usr/bin/ssh -o "ControlMaster no" -o "StrictHostKeyChecking no" -p{port} {username}@{hostname}'.format(
port=self.port, hostname=self.hostname, username=self.username),
'--list-only',
filename], env=env)
i = self.process.expect(['[Pp]assword', '(\d+)%', pexpect.EOF])
if i == 0:
self.process.sendline("{}\n".format(self.passwd))
self.process.wait()
data = self.process.read()
self.process.close()
return b"No such file or directory (2)" not in data
def sync(self, source, target, *params):
num = -1
self.create_process(source, target, *params)
while True:
i = self.process.expect(['[Pp]assword', '(\d+)%', pexpect.EOF])
if i == 0:
self.process.sendline("{}\n".format(self.passwd))
elif i == 1:
newnum = int(self.process.match.group(1))
if newnum > num:
num = newnum
yield newnum
else:
self.output = self.process.before
self.process.close()
existatus = self.process.exitstatus
#error 24 - "files vanished" is not fatal
self.exitstatus = existatus if existatus != 24 else 0
yield 100
break

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
# Copyright 2013 Calculate Ltd. http://www.calculate-linux.org
# 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.
@ -15,24 +15,26 @@
# 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.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 ..client import ClientError
from calculate.lib.utils.samba import SambaError
from calculate.lib.cl_template import TemplatesError
from calculate.lib.utils.files import isMount
setLocalTranslate('cl_client3',sys.modules[__name__])
_ = lambda x: x
setLocalTranslate('cl_client3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class ClClientAction(Action):
"""
Ввести машину в домен или вывести
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError,ClientError,DesktopError,TemplatesError)
native_error = (FilesError, ClientError, DesktopError, TemplatesError,
SambaError)
successMessage = None
failedMessage = None
@ -40,110 +42,120 @@ class ClClientAction(Action):
# список задач для действия
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,'
# команда вызвана только для монтировния 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 workstation is not in the domain"),
'condition': lambda Get: not Get('cl_remote_host')
},
# проверить может ли указанный сервер являться доменом
{'name': 'domain:check_domain',
'message': __("Checking {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',
'depend':Tasks.success(inessential=['mount_remote'])
},
# проверить информацию для 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 the domain"),
'depend':Tasks.failed() & Tasks.hasnot("interrupt"),
},
]
'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',
'depend': Tasks.success(inessential=['mount_remote'])
},
# проверить информацию для 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')
},
# обновить информацию для fastlogin-domain
{'name': 'need_templates:update_fastlogin',
'method': 'Client.update_fastlogin_domain_path()',
'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': 'undomain:noautorun_client',
'method': 'Client.delDaemonAutostart("client")'
},
# добавить службу 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': __("Workstation added to domain {cl_remote_host}")
},
{'name': 'domain:failed',
'error': __(
"Failed to add the workstation to domain {cl_remote_host}"),
'depend': Tasks.failed() & Tasks.hasnot("interrupt"),
},
{'name': 'undomain:success',
'message': __("Workstation removed from domain {cl_remote_host}")
},
{'name': 'undomain:failed',
'error': __("Failed to remove the workstation from the domain"),
'depend': Tasks.failed() & Tasks.hasnot("interrupt"),
},
]

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
# Copyright 2013 Calculate Ltd. http://www.calculate-linux.org
# 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.
@ -16,230 +16,322 @@
import sys
from os import path
from calculate.core.server.func import Action,Tasks
from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate
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.client.client import ClientError
from calculate.lib.utils.samba import SambaError
from ..client import ClientError
from calculate.lib.cl_template import TemplatesError
from calculate.lib.utils.files import isMount
from calculate.lib.utils.mount import isMount
setLocalTranslate('cl_client3',sys.modules[__name__])
_ = lambda x: x
setLocalTranslate('cl_client3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class ClClientSyncLoginAction(Action):
"""
Синхронизировать локальный профиль с удаленным, подключить удаленные
ресурсы пользователя
"""
native_error = (FilesError,ClientError,DesktopError,TemplatesError)
native_error = (FilesError, ClientError, DesktopError, TemplatesError,
SambaError)
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 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') &
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,'
# синхронизируем с профилем локального домена
{'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,'
'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 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,'
'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': __("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') |
'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':__("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')
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):
@ -247,99 +339,134 @@ class ClClientSyncLogoutAction(Action):
Синхронизировать локальный профиль с удаленным, отключить удаленные
ресурсы пользователя
"""
native_error = (FilesError,ClientError,DesktopError,TemplatesError)
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
# проверка доменный ли пользователь
{'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 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':'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 domain")
},
# переместить файлы из профиля в Moved
{'name':'domain_user:move_home_dir',
'message':__("Moving non-profile files to Home/Moved directory"),
'method':'Client.moveHomeDir(ur_home_path,"Moved","homes",'
'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: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,'
# закачать профиль пользователя в домен
{'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)',
'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)',
}
]
]

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
# Copyright 2013 Calculate Ltd. http://www.calculate-linux.org
# 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.
@ -15,33 +15,36 @@
# 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.core.server.func import Action
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 ..client import ClientError
from calculate.lib.utils.samba import SambaError
from calculate.lib.cl_template import TemplatesError
setLocalTranslate('cl_client3',sys.modules[__name__])
_ = lambda x: x
setLocalTranslate('cl_client3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class ClPasswdAction(Action):
"""
Изменить пароль доменного пользователя
"""
# ошибки, которые отображаются без подробностей
native_error = (FilesError,DesktopError,TemplatesError,ClientError)
native_error = (FilesError, ClientError, DesktopError, TemplatesError,
SambaError)
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")
"This modification will be applied when "
"you quit the X session"))
failedMessage = __("Failed to change the password")
interruptMessage = __("Password changing 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)',
{'name': 'change_passwd',
'method': 'Client.clientPasswd(cl_client_login,ur_uid,ur_gid,'
'ur_home_path,ur_user_new_pw,ur_user_pw)',
}]

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*-
# Copyright 2008-2013 Calculate Ltd. http://www.calculate-linux.org
# Copyright 2008-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.
@ -14,7 +14,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import action
import client
from __future__ import absolute_import
from . import action
from . import client
section = "client"

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
# Copyright 2008-2013 Calculate Ltd. http://www.calculate-linux.org
# Copyright 2008-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.
@ -14,56 +14,23 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
from os import path
from calculate.lib.datavars import (Variable,VariableError,ReadonlyVariable,
ActionVariable)
from calculate.lib.datavars import ActionVariable
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_client3',sys.modules[__name__])
class VariableAcClientMerge(ActionVariable):
"""
Action variable which has value "up" for package install and
install this package
"""
nonchroot = True
setLocalTranslate('cl_client3', sys.modules[__name__])
def action(self,cl_action):
if cl_action in ("merge","domain","undomain"):
ret = "on"
return "off"
class VariableAcClientDomain(ActionVariable):
class VariableAcClientConfigure(ActionVariable):
"""
Action variable which has value "on" for domain action
"""
nonchroot = True
def action(self,cl_action):
remoteHost = self.Get("cl_remote_host")
remoteAuth = self.Get("os_remote_auth")
if cl_action == "domain":
def action(self, cl_action):
if cl_action in ("domain", "undomain"):
return "on"
elif ((cl_action in "merge" or
cl_action == 'sync' and self.Get('cl_merge_pkg'))
and remoteHost and remoteAuth):
return "on"
return "off"
class VariableAcClientUndomain(ActionVariable):
"""
Action variable which has value "on" for undomain action
"""
nonchroot = True
else:
return "off"
def action(self,cl_action):
remoteHost = self.Get("cl_remote_host")
remoteAuth = self.Get("os_remote_auth")
if cl_action in ("undomain",):
return "on"
elif cl_action in ("merge",) and \
(not remoteHost or not remoteAuth):
return "on"
return "off"

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
# Copyright 2008-2013 Calculate Ltd. http://www.calculate-linux.org
# Copyright 2008-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.
@ -18,12 +18,18 @@ import os
import sys
from os import path
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.datavars import (Variable, VariableError, ReadonlyVariable,
ReadonlyTableVariable, FieldValue,
HumanReadable)
from calculate.lib.cl_ini_parser import iniParser
from calculate.lib.configparser import ConfigParser
import calculate.lib.utils.device as device
from calculate.lib.utils.files import (readFile, find,
FindFileType)
from calculate.lib.utils.mount import isMount
from calculate.lib.utils.common import getValueFromCmdLine, CmdlineParams
from calculate.lib.utils.portage import isPkgInstalled
from calculate.lib.variables import user
from calculate.lib.convertenv import convertEnv
from calculate.lib.utils.ip import isOpenPort
import time
@ -32,10 +38,15 @@ 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 ..client import Client
from ..rsync import ProfileSyncer, ProfileSyncerError
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
_ = lambda x: x
setLocalTranslate('cl_client3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_client3',sys.modules[__name__])
class VariableClRemoteHost(Variable):
"""
@ -43,6 +54,12 @@ class VariableClRemoteHost(Variable):
"""
value = ""
class VariableClRemoteDomain(Variable):
"""
Имя домена
"""
value = ""
class VariableClRemoteHostNew(Variable):
"""
IP or domain name of CDS
@ -57,22 +74,25 @@ class VariableClRemoteHostNew(Variable):
self.label = _("Domain IP")
self.help = _("domain")
def check(self,value):
def check(self, value):
if self.Get('cl_client_mount_set') == 'off':
if self.Get('cl_localhost_set') == 'off':
if self.Get('cl_remote_host') == '':
if not value:
raise VariableError(_("Need to specify the domain"))
elif not isOpenPort(value,445):
raise VariableError(_("Please specify the domain"))
elif not isOpenPort(value, 445):
raise VariableError(
_("The specified address is not available"))
class VariableClRemoteHostLive(ReadonlyVariable):
"""
Remote host from /proc/cmdline param domain
"""
def get(self):
return getValueFromCmdLine("calculate","domain") or ""
return getValueFromCmdLine(CmdlineParams.Calculate,
CmdlineParams.Domain) or ""
class VariableOsRemoteAuth(Variable):
@ -96,18 +116,21 @@ class VariableClRemotePw(Variable):
opt = ["--domain-password"]
def init(self):
self.label = _("Domain password")
self.label = __("Domain password")
self.help = _("specify the domain password")
def get(self):
return getValueFromCmdLine("calculate","domain_pw") or ""
return getValueFromCmdLine(CmdlineParams.Calculate,
CmdlineParams.DomainPassword) or ""
class VariableClMovedSkipPath(Variable):
"""
Skip "Moved" path
"""
type = "list"
value = ['Disks','Home','Moved','FTP','Desktop', 'Share']
value = ['Disks', 'Home', 'Moved', 'FTP', 'Desktop', 'Share']
class VariableClSyncSkipPath(Variable):
"""
@ -115,12 +138,13 @@ class VariableClSyncSkipPath(Variable):
"""
type = "list"
value = [".googleearth", "Home", "Disks", "FTP",
'Share', ".local/share/akonadi/db_data", ".VirtualBox",
".mozilla/firefox/calculate.default/urlclassifier3.sqlite",
".local/share/mime/mime.cache", ".gvfs",
".kde4/share/apps/nepomuk/repository/main/data", ".logout",
".Xauthority", ".thumbnails", ".mozilla/firefox/*/Cache",
".kde4/socket-*", ".cache/", ".local/share/Trash"]
'Share', ".local/share/akonadi/db_data", ".VirtualBox",
".mozilla/firefox/calculate.default/urlclassifier3.sqlite",
".local/share/mime/mime.cache", ".gvfs",
".kde4/share/apps/nepomuk/repository/main/data", ".logout",
".Xauthority", ".thumbnails", ".mozilla/firefox/*/Cache",
".kde4/socket-*", ".cache/", ".local/share/Trash"]
class VariableClSyncDelPath(Variable):
"""
@ -130,10 +154,12 @@ class VariableClSyncDelPath(Variable):
value = [".kde4/share/config/phonondevicesrc",
".kde4/cache-*", ".kde4/tmp-*"]
class VariableClProfileAllSet(Variable):
type = "bool"
value = "off"
class VariableClClientSync(Variable):
type = "bool"
value = "on"
@ -145,6 +171,7 @@ class VariableClClientSync(Variable):
self.label = _("Synchronize the user profile")
self.help = _("synchronize user preferences")
class VariableClLocalhostSet(Variable):
"""
Using autopartition
@ -157,28 +184,30 @@ class VariableClLocalhostSet(Variable):
untrusted = True
def init(self):
self.label = _("Computer role")
self.label = _("Workstation role")
self.help = _("remove the domain connection settings")
def choice(self):
return [("off",_("Domain workstation")),
("on",_("Local workstation"))]
return [("off", _("Domain workstation")),
("on", _("Local workstation"))]
def check(self,value):
def check(self, value):
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"))
raise VariableError(_("The workstation 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"))
raise VariableError(
_("The workstation 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') == '':
# return "on"
# else:
# return "off"
#def get(self):
# if self.Get('cl_remote_host') == '':
# return "on"
# else:
# return "off"
class VariableClClientMountSet(Variable):
"""
@ -193,7 +222,8 @@ class VariableClClientMountSet(Variable):
self.label = _("Only mount the domain resource")
self.help = _("only mount the [remote] domain resource")
class VariableUrUserPw(Variable,LdapHelper):
class VariableUrUserPw(Variable, LdapHelper):
"""
Current user password
"""
@ -209,18 +239,16 @@ class VariableUrUserPw(Variable,LdapHelper):
def checkUserPwdLDAP(self, server, userDN, password):
"""Check unix user password on server"""
ldapInit = ldap.initialize("ldap://%s"%server)
errMessage = ""
try:
ldapInit = ldap.initialize("ldap://%s" % server)
try:
ldapInit.bind_s(userDN, password)
except ldap.INVALID_CREDENTIALS:
raise VariableError(_("Wrong password"))
except ldap.LDAPError, e:
errMessage = e[0]['desc']
raise VariableError(errMessage)
except ldap.LDAPError as e:
raise VariableError(f"{e.args[0]['desc']}; {e.args[0]['info']}")
return True
def check(self,value):
def check(self, value):
if not value:
raise VariableError(_("Empty password"))
# читаем os_remote_auth, так как при смене пароля
@ -230,9 +258,10 @@ class VariableUrUserPw(Variable,LdapHelper):
ldapObj = self.getLdapUserObject()
if ldapObj:
usersDN = ldapObj.getUsersDN()
userDN = ldapObj.addDN("uid=%s"%self.Get('ur_login'),
usersDN)
self.checkUserPwdLDAP(server,userDN,value)
userDN = ldapObj.addDN("uid=%s" % self.Get('ur_login'),
usersDN)
self.checkUserPwdLDAP(server, userDN, value)
class VariableUrUserNewPw(Variable):
"""
@ -248,11 +277,12 @@ class VariableUrUserNewPw(Variable):
self.label = _("New password")
self.help = _("new user password")
def check(self,value):
def check(self, value):
if not value:
raise VariableError(_("Empty password"))
class VariableClClientLogin(VariableUrLogin):
class VariableClClientLogin(user.VariableUrLogin):
"""
User Login
"""
@ -260,32 +290,33 @@ class VariableClClientLogin(VariableUrLogin):
alias = "ur_login"
def choice(self):
loginChoice = VariableUrLogin.choice(self)
loginChoice = user.VariableUrLogin.choice(self)
if self.Get('cl_action') == 'passwd':
return filter(lambda x:x != "root",loginChoice)
return [x for x in loginChoice if x != "root"]
else:
return loginChoice
def check(self,value):
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"))
raise VariableError(_("Please specify the user"))
if value == "root" and self.Get('cl_action') == 'passwd':
raise VariableError(\
_("The action can be executed by a non-root user only"))
raise VariableError(
_("This 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)
except (TypeError, KeyError):
raise VariableError(_("User %s does not exist") % value)
def get(self):
if (self.Get('cl_action') == 'passwd' and
self.Get('ur_login') != 'root'):
if (self.Get('cl_action') == 'passwd' and
self.Get('ur_login') != 'root'):
return self.Get('ur_login')
return ""
class VariableClClientRelevanceSet(ReadonlyVariable):
"""
Актуальны ли сейчас выполненные шаблоны
@ -293,34 +324,37 @@ class VariableClClientRelevanceSet(ReadonlyVariable):
type = "bool"
def get(self):
# если происходят действия ввода или вывода из домена
if (self.Get('cl_action') in ("domain", "undomain") and
self.Get('cl_client_mount_set') == 'off'):
return "off"
# если изменился домен
if self.Get('cl_remote_host') != self.Get("os_remote_auth"):
return "off"
if (self.Get('cl_remote_host') and
not isMount(self.Get('cl_client_remote_path'))):
return "off"
currentVersion = self.Get("cl_ver")
# версия программы, который были наложены шаблоны
previousVersion = self.Get("os_remote_client")
if cmpVersion(currentVersion,previousVersion):
not isMount(self.Get('cl_client_remote_path'))):
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):
class VariableClLdapData(ldapUser, ReadonlyVariable):
"""
Внутренняя переменная, содержащая объект для доступа к данным LDAP
"""
@ -340,7 +374,7 @@ class VariableClLdapData(ldapUser,ReadonlyVariable):
if usersDN:
partDN = "ou=Worked,ou=Replication,ou=LDAP"
servicesDN = "ou=Services"
baseDN = usersDN.rpartition(servicesDN+",")[2]
baseDN = usersDN.rpartition(servicesDN + ",")[2]
replDN = self.addDN(partDN, servicesDN, baseDN)
return replDN
return False
@ -352,8 +386,8 @@ class VariableClLdapData(ldapUser,ReadonlyVariable):
bindDn, bindPw, host = connectData
replDN = self.getReplDN()
# find string for service replication branch
userAndOsName = "%s@%s"%(userName,osLinuxShort)
findAttr = "uid=%s"%userAndOsName
userAndOsName = "%s@%s" % (userName, osLinuxShort)
findAttr = "uid=%s" % userAndOsName
# connect to LDAP
if not self.ldapConnect(bindDn, bindPw, host):
return False
@ -362,20 +396,19 @@ class VariableClLdapData(ldapUser,ReadonlyVariable):
return resSearch
return False
def _gethostbyname(self,hostname):
def _gethostbyname(self, hostname):
try:
return gethostbyname(hostname)
except:
pass
return None
except Exception:
return None
def getNameRemoteServer(self,userName, osLinuxShort, curHost):
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'):
if searchPrevHost and 'host' in searchPrevHost[0][0][1]:
prevHost = searchPrevHost[0][0][1]['host'][0]
else:
prevHost = None
@ -398,7 +431,7 @@ class VariableClLdapData(ldapUser,ReadonlyVariable):
usersDN = self.getUsersDN()
partDN = "ou=Replication,ou=LDAP"
servicesDN = "ou=Services"
baseDN = usersDN.rpartition(servicesDN+",")[2]
baseDN = usersDN.rpartition(servicesDN + ",")[2]
replDN = self.addDN(partDN, servicesDN, baseDN)
findAttr = "ou=Worked"
# connect to LDAP
@ -416,11 +449,13 @@ 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('ur_login'), self.Get('cl_client_profile_name'),
self.Get('cl_remote_host'))
class VariableClClientUserMountData(ReadonlyTableVariable):
"""
Таблица монтирования ресурсов
@ -430,30 +465,68 @@ class VariableClClientUserMountData(ReadonlyTableVariable):
'cl_client_user_mount_path',
'cl_client_user_mount_host']
def get(self):
def get(self, hr=HumanReadable.No):
home = path.split(self.Get('ur_home_path'))[0]
envFile = self.Get('cl_env_server_path')
samba_host = self.Get('sr_samba_host')
ftp_host = convertEnv().getVar("ftp", "host")
def map_names(name):
name_dct = {'domain.dmz': 'Санкт-Петербург', 'domain.spb': 'Санкт-Петербург',
'domain.msk': 'Москва', 'domain.verevo': 'Производство'}
for i in name_dct:
if i in name:
return name_dct[i]
else:
return 'error'
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'))
yield (
"share", "share", path.join(self.Get('ur_home_path'), "Share"),
samba_host)
yield (
"unix", "unix", path.join(home, ".%s" % self.Get('ur_login'),
"profile"),
samba_host)
yield (
"homes", "homes", path.join(self.Get('ur_home_path'), "Home"),
samba_host)
if ftp_host:
yield ("ftp", "ftp", path.join(self.Get('ur_home_path'), "FTP"),
ftp_host)
else:
yield ("ftp",'','','')
yield ("ftp", '', '', '')
if self.Get('cl_replication_host'):
yield ("remote_profile","unix",
path.join(home,".%s.remote"%self.Get('ur_login')),
yield ("remote_profile", "unix",
path.join(home, ".%s" % self.Get('ur_login'),
"remote_profile"),
self.Get('cl_replication_host'))
else:
yield ("remote_profile",'unix','','')
yield ("remote_profile", 'unix', '', '')
for host, mount_path in zip(self.Get('cl_share_hosts'), self.Get('cl_share_mounts')):
try:
resource = host.split('/')[-1]
host = host.replace('//', '', 1).split(f"/{resource}")[0]
if mount_path.startswith('~/'):
mount_path = f"{path.join(self.Get('ur_home_path'), mount_path.replace('~/', '', 1))}"
yield (resource, resource, mount_path, host)
except:
continue
return list(generate())
class VariableClClientUserMountName(FieldValue,ReadonlyVariable):
class VariableClClientUserMountUnixPath(ReadonlyVariable):
"""
Путь до подключенного unix ресурса данного пользователя
"""
def get(self):
return self.select('cl_client_user_mount_path',
cl_client_user_mount_name='unix', limit=1) or ""
class VariableClClientUserMountName(FieldValue, ReadonlyVariable):
"""
Название удаленного ресурса
"""
@ -462,7 +535,7 @@ class VariableClClientUserMountName(FieldValue,ReadonlyVariable):
column = 0
class VariableClClientUserMountResource(FieldValue,ReadonlyVariable):
class VariableClClientUserMountResource(FieldValue, ReadonlyVariable):
"""
Название удаленного ресурса
"""
@ -470,7 +543,8 @@ class VariableClClientUserMountResource(FieldValue,ReadonlyVariable):
source_variable = "cl_client_user_mount_data"
column = 1
class VariableClClientUserMountPath(FieldValue,ReadonlyVariable):
class VariableClClientUserMountPath(FieldValue, ReadonlyVariable):
"""
Путь подключения удаленного ресурса
"""
@ -478,7 +552,8 @@ class VariableClClientUserMountPath(FieldValue,ReadonlyVariable):
source_variable = "cl_client_user_mount_data"
column = 2
class VariableClClientUserMountHost(FieldValue,ReadonlyVariable):
class VariableClClientUserMountHost(FieldValue, ReadonlyVariable):
"""
Удаленный сервер
"""
@ -486,12 +561,24 @@ class VariableClClientUserMountHost(FieldValue,ReadonlyVariable):
source_variable = "cl_client_user_mount_data"
column = 3
class SyncHelper:
class VariableClShareHosts(Variable):
type = "list"
value = []
class VariableClShareMounts(Variable):
type = "list"
value = []
class SyncHelper():
"""
Вспомогательный объект для определения статуса синхронизации и времени
по конфигурационным файлам
"""
def getSyncStatus(self,rpath):
def getSyncStatus(self, rpath):
"""
Получить status_sync из desktop файла
"""
@ -500,9 +587,9 @@ class SyncHelper:
if os.path.exists(fileConfig):
objConfig = iniParser(fileConfig)
data = self.getDataInConfig("main", ["status_sync"],
objConfig)
objConfig)
if data:
return data.get("status_sync","")
return data.get("status_sync", "")
return ""
def getDataInConfig(self, section, listVars, objConfig):
@ -511,19 +598,18 @@ class SyncHelper:
"""
varsConfig = {}
for varName in listVars:
varsConfig[varName] = objConfig.getVar(section,varName)
varsConfig[varName] = objConfig.getVar(section, varName)
if objConfig.getError():
return False
return varsConfig
def convertDate(self,strdate,dateformat="%Y-%m-%d %H:%M:%S"):
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)
return time.strptime(strdate, dateformat)
except ValueError:
pass
return ""
@ -539,124 +625,281 @@ class SyncHelper:
objConfig)
timeLogout = data["date_logout"]
timeConfig = data["date"]
dates = filter(None,
[self.convertDate(timeLogout),
self.convertDate(timeConfig)])
dates = [x for x in [self.convertDate(timeLogout),
self.convertDate(timeConfig)] if x]
if dates:
return dates[0]
return ""
def checkNeedSync(self,homeDir,rpath,curTimeObj,curStatusSync,osLinuxShort):
def checkNeedSync(self, homeDir, rpath, curTimeObj, curStatusSync,
osLinuxShort):
"""
Проверить необходимость синхронизации текущего профиля с удаленным
"""
# profile directory
#fileConfig = os.path.join(homeDir, Client.configFileServer)
# fileConfig = os.path.join(homeDir, Client.configFileServer)
pathProfile = os.path.join(rpath, osLinuxShort)
#if readFile(fileConfig).strip():
# if readFile(fileConfig).strip():
# return True
fileSoftConfigThis = os.path.join(pathProfile,
Client.configFileSoft)
Client.configFileSoft)
fileSoftConfigCur = os.path.join(homeDir,
Client.configFileSoft)
xSessionCur = iniParser(fileSoftConfigCur).getVar('main','xsession')
xSessionThis = iniParser(fileSoftConfigThis).getVar('main','xsession')
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":
# 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:
xSessionCur == xSessionThis and \
thisTimeObj and curTimeObj and \
curTimeObj >= thisTimeObj:
return False
return True
class VariableClClientSyncTime(SyncHelper,ReadonlyVariable):
def getSyncDate(self, osLinuxShort, ps):
"""
Получить время синхронизации из ::profile/.calculate/desktop.env
"""
desktopEnvRemoteData = ps.readfile("::profile/{}/{}".format(
osLinuxShort, Client.configFileDesktop))
if desktopEnvRemoteData:
cpRemote = ConfigParser(strict=False)
cpRemote.read_string(desktopEnvRemoteData)
timeLogout = cpRemote.get("main", "date_logout", fallback=None)
timeConfig = cpRemote.get("main", "date", fallback=None)
dates = [x for x in [self.convertDate(timeLogout),
self.convertDate(timeConfig)] if x]
if dates:
return dates[0]
return ""
def checkNeedSyncNew(self, homeDir, rpath, curTimeObj, curStatusSync,
osLinuxShort, ps):
"""
Проверить необходимость синхронизации текущего профиля с удаленным
"""
iniEnvRemoteData = ps.readfile("::profile/{}/{}".format(
osLinuxShort, Client.configFileSoft))
fileConfigCur = os.path.join(homeDir, Client.configFileSoft)
iniEnvCurrentData = readFile(fileConfigCur)
cpCur = ConfigParser(strict=False)
cpCur.read_string(iniEnvCurrentData)
cpRemote = ConfigParser(strict=False)
cpRemote.read_string(iniEnvRemoteData)
xSessionCur = cpCur.get('main', 'xsession', fallback=None)
xSessionThis = cpRemote.get('main', 'xsession', fallback=None)
if curStatusSync == "success_logout" and \
xSessionCur == xSessionThis:
thisTimeObj = self.getSyncDate(osLinuxShort, ps)
if 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):
class VariableClClientPackTime(SyncHelper, ReadonlyVariable):
"""
Время комады упаковки профиля
"""
def get(self):
return str(float(time.time()))
class VariableClClientSyncStatus(SyncHelper,ReadonlyVariable):
class VariableClClientSyncStatus(SyncHelper, ReadonlyVariable):
"""
Текущий статус синхронизации профиля
"""
def get(self):
return self.getSyncStatus(self.Get('ur_home_path'))
class VariableClClientLocalSyncTime(SyncHelper,ReadonlyVariable):
class VariableClClientLocalSyncTime(SyncHelper, ReadonlyVariable):
"""
Текущий статус синхронизации профиля
"""
def get(self):
return self.getDateObjClientConf(
path.join(
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')))
where='cl_client_user_mount_name', eq='unix',
limit=1), self.Get('cl_client_profile_name')))
class VariableClClientSyncReplicationSet(SyncHelper,ReadonlyVariable):
class VariableClClientRsyncProfileSet(ReadonlyVariable):
"""
Используется rsync через ssh для синхронизации пользовательского профиля
"""
type = "bool"
value = "off"
class VariableClClientSyncReplicationSet(SyncHelper, ReadonlyVariable):
"""
Нужно ли синхронизировать текущий профиль с удаленным доменом
"""
type = "bool"
def get(self):
if not self.Get('cl_replication_host'):
return "off"
host_varname = "cl_replication_host"
profile_type = "remote_profile"
def old_synchronize(self):
profilePath = self.Select('cl_client_user_mount_path',
where='cl_client_user_mount_name',
eq='remote_profile',limit=1)
where='cl_client_user_mount_name',
eq=self.profile_type, limit=1)
if self.Get('cl_action') == 'login' and not isMount(profilePath):
raise VariableError(_("Remote profile 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"
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"
def new_synchronize(self):
user = self.Get('ur_login')
pwd = self.Get('desktop.ur_password')
remotehost = self.Get(self.host_varname)
ps = ProfileSyncer(remotehost, 2009, user, pwd)
#there was a typo before - profilePath was missing
profilePath = self.Select('cl_client_user_mount_path',
where='cl_client_user_mount_name',
eq=self.profile_type, limit=1)
if ps.check():
return "on" if self.checkNeedSyncNew(
self.Get('ur_home_path'), profilePath,
self.Get('cl_client_sync_time'),
self.Get('cl_client_sync_status'),
self.Get('cl_client_profile_name'),
ps) else "off"
return "off"
def get(self):
if not self.Get(self.host_varname):
return "off"
if self.GetBool('cl_client_rsync_profile_set'):
return self.new_synchronize()
else:
return self.old_synchronize()
class VariableClClientSyncLocalSet(SyncHelper,ReadonlyVariable):
class VariableClClientSyncLocalSet(VariableClClientSyncReplicationSet):
"""
Нужно ли синхронизировать текущий профиль с локальным доменом
"""
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 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"
host_varname = "cl_remote_host"
profile_type = "unix"
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'))
self.Get('cl_sync_skip_path'))
reSkip = re.compile("|".join((x.replace("*", ".*") for x in skipFiles))).search
return [x for x in find(self.Get('ur_home_path'), onefilesystem=True,
filetype=FindFileType.SymbolicLink)
if not reSkip(x)]
class VariableClClientNscdCache(Variable):
"""
Частота обновления кэша nscd при работе в домене в часах
"""
class VariableClCifsVer(ReadonlyVariable):
"""
Версия модуля CIFS
"""
def get(self):
return device.sysfs.read(device.sysfs.Path.Module, "cifs/version")
class VariableClCifsCache(Variable):
"""
Параметр cache= при монтировании cifs
"""
value = "loose"
class VariableClCifsMountVers(Variable):
"""
Параметр vers= для cifs
"""
value = "1.0"
class VariableClRsyncVer(ReadonlyVariable):
"""
Версия rsync
"""
def get(self):
data = isPkgInstalled('net-misc/rsync')
if data:
return data[0]['PVR']
return ""
class VariableClCifsutilsVer(ReadonlyVariable):
"""
Версия cifs-utils
"""
def get(self):
data = isPkgInstalled('net-fs/cifs-utils')
if data:
return data[0]['PV']
return ""
class VariableClClientIgnoreErrorsSet(Variable):
"""
Параметр, для отключения отмонтирования пользовательских ресурсов,
при ошбиках, возникших во вермя cl-client-sync-login
"""
type = "bool"
value = "on"
metavalue = "ON/OFF"
opt = ["--unmount-on-error"]
def init(self):
self.label = _("Unmount user resources on error")
self.help = _("unmount user resources on error")
class VariableClSyncMovedSet(Variable):
"""
Использовать или нет перенос файлов из домашней директории в Home/Moved при
синхронизации
"""
type = "bool"
value = "on"
class VariableSrSambaHost(Variable):
"""
Хост на котором находятся samba ресурсы
"""
def get(self):
return self.Get('cl_remote_host') or ''

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
# Copyright 2012-2013 Calculate Ltd. http://www.calculate-linux.org
# Copyright 2012-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.
@ -13,21 +13,24 @@
# 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 __future__ import absolute_import
import sys
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
from utils.cl_passwd import ClPasswdAction
from utils.cl_client_sync import (ClClientSyncLoginAction,
from .client import ClientError
from calculate.lib.utils.samba import SambaError
from .utils.cl_client import ClClientAction
from .utils.cl_passwd import ClPasswdAction
from .utils.cl_client_sync import (ClClientSyncLoginAction,
ClClientSyncLogoutAction)
import calculate.desktop.desktop as desktop
import calculate.client.client as client
from . import client
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
_ = lambda x: x
setLocalTranslate('cl_client3', sys.modules[__name__])
__ = getLazyLocalTranslate(_)
@ -45,7 +48,7 @@ class Wsdl(WsdlBase):
# заголовок метода
'title': __("Domain"),
# иконка для графической консоли
'image': 'network-server,network-workgroup',
'image': 'calculate-client,network-server,network-workgroup',
# метод присутствует в графической консоли
'gui': True,
# консольная команда
@ -60,24 +63,25 @@ class Wsdl(WsdlBase):
# объект переменных
'datavars': "client",
'native_error': (VariableError, DataVarsError,
SambaError,
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_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=_("Perform"))]},
next_label=_("Execute"))]},
#
# подключить удаленные ресурсы пользователя
#
@ -89,7 +93,7 @@ class Wsdl(WsdlBase):
# заголовок метода
'title': __("Domain User Login"),
# иконка для графической консоли
'image': 'application-other',
'image': 'calculate-client-sync-login,application-other',
# метод не присутствует в графической консоли
'gui': False,
# консольная команда
@ -104,6 +108,7 @@ class Wsdl(WsdlBase):
# объект переменных
'datavars': "client",
'native_error': (VariableError, DataVarsError,
SambaError,
ClientError, DesktopError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'login'},
@ -111,7 +116,8 @@ class Wsdl(WsdlBase):
'groups': [
lambda group: group(_("Domain user login"),
normal=('ur_login', 'cl_client_sync'),
next_label=_("Perform"))]},
expert=('cl_client_ignore_errors_set',),
next_label=_("Execute"))]},
#
# отключить удаленные ресурсы пользователя
#
@ -123,7 +129,7 @@ class Wsdl(WsdlBase):
# заголовок метода
'title': __("Domain User Logout"),
# иконка для графической консоли
'image': 'application-other',
'image': 'calculate-client-sync-logout,application-other',
# метод не присутствует в графической консоли
'gui': False,
# консольная команда
@ -138,6 +144,7 @@ class Wsdl(WsdlBase):
# объект переменных
'datavars': "client",
'native_error': (VariableError, DataVarsError,
SambaError,
ClientError, DesktopError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'logout'},
@ -145,7 +152,7 @@ class Wsdl(WsdlBase):
'groups': [
lambda group: group(_("Domain user logout"),
normal=('ur_login', 'cl_client_sync'),
next_label=_("Perform"))]},
next_label=_("Execute"))]},
#
# сменить пароль доменного пользователя
#
@ -155,9 +162,9 @@ class Wsdl(WsdlBase):
# категория метода
'category': __('Client'),
# заголовок метода
'title': __("Change Password"),
'title': __("Password Modification"),
# иконка для графической консоли
'image': 'preferences-system-privacy,system-users',
'image': 'calculate-client-passwd,preferences-system-privacy,system-users',
# метод присутствует в графической консоли
'gui': True,
# пользовательский метода
@ -174,12 +181,13 @@ class Wsdl(WsdlBase):
# объект переменных
'datavars': "client",
'native_error': (VariableError, DataVarsError,
SambaError,
ClientError, DesktopError),
# значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'passwd'},
# описание груп (список лямбда функций)
'groups': [
lambda group: group(_("Change password"),
lambda group: group(_("Password modification"),
normal=('cl_client_login', 'ur_user_pw',
'ur_user_new_pw'),
next_label=_("Save"))]},

@ -1,9 +1,9 @@
#!/usr/bin/env python2
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# setup.py --- Setup script for calculate-desktop
# Copyright 2012 Calculate Ltd. http://www.calculate-linux.org
# Copyright 2012-2021 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.
@ -23,18 +23,57 @@ __version__ = "3.2.2"
import os
from glob import glob
from distutils.core import setup, Extension
from calculate.install_data import install_data
from distutils.command import install_data as module_install_data
from distutils.util import change_root, convert_path
data_files = [('/etc/init.d', [('data/client',0755)]),
data_files = [('/etc/init.d', [('data/client',0o755)]),
('/usr/share/calculate/xdm/login.d',
['data/login.d/10client']),
('/usr/share/calculate/xdm/login.d',
['data/login.d/15resume_remount']),
('/usr/share/calculate/xdm/logout.d',
['data/logout.d/10client']),
('/usr/share/calculate/xdm/logout.d',
['data/logout.d/15resume_remount']),
('/usr/share/calculate/xdm/',[('data/wait_domain',0755)])]
('/usr/share/calculate/xdm/',[('data/wait_domain',0o755)])]
class install_data(module_install_data.install_data):
def run (self):
self.mkpath(self.install_dir)
for f in self.data_files:
if isinstance(f, str):
# it's a simple file, so copy it
f = convert_path(f)
if self.warn_dir:
self.warn("setup script did not provide a directory for "
"'%s' -- installing right in '%s'" %
(f, self.install_dir))
(out, _) = self.copy_file(f, self.install_dir)
self.outfiles.append(out)
else:
# it's a tuple with path to install to and a list of files
dir = convert_path(f[0])
if not os.path.isabs(dir):
dir = os.path.join(self.install_dir, dir)
elif self.root:
dir = change_root(self.root, dir)
self.mkpath(dir)
if f[1] == []:
# If there are no files listed, the user must be
# trying to create an empty directory, so add the
# directory to the list of output files.
self.outfiles.append(dir)
else:
# Copy files, adding them to the list of output files.
for data in f[1]:
# is's a simple filename without chmod
if isinstance(data,str):
chmod = None
else:
data, chmod = data
data = convert_path(data)
(out, _) = self.copy_file(data, dir)
if chmod and os.stat(out).st_mode != chmod:
os.chmod(out,chmod)
self.outfiles.append(out)
packages = [
"calculate."+str('.'.join(root.split(os.sep)[1:]))

Loading…
Cancel
Save