Compare commits

..

No commits in common. 'master' and 'master3.3' have entirely different histories.

6
.gitignore vendored

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

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

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

@ -1,5 +1,5 @@
#! /bin/sh #! /bin/sh
# Copyright 2010-2016 Mir Calculate. http://www.calculate-linux.org # Copyright 2010 Calculate Ltd. http://www.calculate-linux.org
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -13,19 +13,21 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
run_script() { /usr/sbin/env-update
if [ -e '/usr/bin/cl-client-sync-login' ]; source /etc/profile
source /usr/share/calculate/xdm/functions
if [ -e '/usr/sbin/cl-client-sync-login' ];
then then
if [[ "${DOMAIN_USER}" == "on" ]] if [[ "${DOMAIN_USER}" == "on" ]]
then then
ERRORLOG=`/usr/bin/cl-client-sync-login --gui-progress --gui-warning $USER 2>&1` ERRORLOG=`/usr/sbin/cl-client-sync-login --gui-progress --gui-warning $USER 2>&1`
# log error # log error
if [ "$?" -gt "0" ]; if [ "$?" -gt "0" ];
then then
echo "$ERRORLOG" >> $FILE_LOG echo "$ERRORLOG" >> $FILE_LOG
return 1 exit 1
fi fi
fi fi
fi fi
return 0 exit 0
}

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

@ -0,0 +1,25 @@
#! /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-2016 Mir Calculate. http://www.calculate-linux.org # Copyright 2012-2013 Calculate Ltd. http://www.calculate-linux.org
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -14,39 +14,22 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import os import os, sys, time
import sys
import time
from calculate.lib.utils.files import getModeFile 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
from functools import reduce
_ = lambda x: x from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_client3',sys.modules[__name__]) setLocalTranslate('cl_client3',sys.modules[__name__])
class _shareData(color_print):
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(Printable):
"""Share class""" """Share class"""
fileName = ""
template = ""
lenData = 0
data = [] data = []
def getDataInFile(self, fileName='', lenData=0): def getDataInFile(self, fileName='', lenData=0):
"""Get data list from file""" """Get data list from file"""
return [z for z in [x.rstrip().split(":") for x in open(fileName)] if len(z) == lenData] return filter(lambda x: len(x)==lenData,
map(lambda x: x.rstrip().split(":"), open(fileName)))
def getFileAccess(self, perm="READ"): def getFileAccess(self, perm="READ"):
if perm == "READ": if perm == "READ":
@ -78,7 +61,7 @@ class _shareData(Printable):
def save(self): def save(self):
if self.getFileAccess(perm="WRITE"): if self.getFileAccess(perm="WRITE"):
buff = "\n".join((":".join(x) for x in self.data)) + "\n" buff = "\n".join(map(lambda x: ":".join(x), self.data)) + "\n"
FD = open(self.fileName, "w+") FD = open(self.fileName, "w+")
FD.write(buff) FD.write(buff)
FD.close() FD.close()
@ -90,10 +73,9 @@ class _shareData(Printable):
if self.getData() is False: if self.getData() is False:
return False return False
else: else:
self.data = [x for x in self.data if x[0] != name] self.data = filter(lambda x: x[0]!=name, self.data)
return True return True
@ensure_unicode
def replace(self, name, listData): def replace(self, name, listData):
if self.getData() is False: if self.getData() is False:
return False return False
@ -119,21 +101,18 @@ class _shareData(Printable):
if self.getData() is False: if self.getData() is False:
return False return False
else: 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: if listData:
return listData[0] return listData[0]
else: else:
return [] return []
class passwd(_shareData): class passwd(_shareData):
'''Class for working with the file /etc/passwd''' '''Class for working with the file /etc/passwd'''
fileName = "/etc/passwd" fileName = "/etc/passwd"
template = "%(login)s:x:%(uid)s:%(gid)s:%(gecos)s:%(directory)s:%(shell)s" template = "%(login)s:x:%(uid)s:%(gid)s:%(gecos)s:%(directory)s:%(shell)s"
lenData = 7 lenData = 7
@ensure_unicode
def add(self, name, uid, gid, gecos="", directory="", shell="/bin/bash"): def add(self, name, uid, gid, gecos="", directory="", shell="/bin/bash"):
if not directory: if not directory:
directory = "/home/%s" %name directory = "/home/%s" %name
@ -151,15 +130,13 @@ class passwd(_shareData):
self.data.append(userList) self.data.append(userList)
return True return True
class group(_shareData): class group(_shareData):
'''Class for working with the file /etc/group''' '''Class for working with the file /etc/group'''
fileName = "/etc/group" fileName = "/etc/group"
template = "%(group_name)s:x:%(gid)s:%(user_list)s" template = "%(group_name)s:x:%(gid)s:%(user_list)s"
lenData = 4 lenData = 4
@ensure_unicode def add(self, name, gid, userList=[]):
def add(self, name, gid, userList=()):
groupData = self.template%{'group_name':name, 'gid':gid, groupData = self.template%{'group_name':name, 'gid':gid,
'user_list':','.join(userList)} 'user_list':','.join(userList)}
groupList = groupData.split(":") groupList = groupData.split(":")
@ -173,12 +150,11 @@ class group(_shareData):
self.data.append(groupList) self.data.append(groupList)
return True return True
@ensure_unicode
def replace(self, name, listData): def replace(self, name, listData):
if self.getData() is False: if self.getData() is False:
return False return False
else: else:
delEmpty = lambda y: [x for x in y if x.strip()] delEmpty = lambda y: filter(lambda x: x.strip(), y)
flagFound = False flagFound = False
for index, listDataOld in enumerate(self.data): for index, listDataOld in enumerate(self.data):
if name == listDataOld[0]: if name == listDataOld[0]:
@ -189,7 +165,7 @@ class group(_shareData):
# Constant gid # Constant gid
listDataWork[2] = self.data[index][2] listDataWork[2] = self.data[index][2]
# Join user list # Join user list
userList = delEmpty(self.data[index][3].split(',') + userList = delEmpty(self.data[index][3].split(',') +\
listDataWork[3].split(',')) listDataWork[3].split(','))
# unique list # unique list
userList = reduce(lambda x,y:\ userList = reduce(lambda x,y:\
@ -223,7 +199,8 @@ class group(_shareData):
if self.getData() is False: if self.getData() is False:
return False return False
else: else:
dataGroup = [x[3].split(",") for x in self.data if x[0] == name] dataGroup = map(lambda x: x[3].split(","),
filter(lambda x: x[0]==name, self.data))
if dataGroup: if dataGroup:
return dataGroup[0] return dataGroup[0]
else: else:
@ -237,23 +214,20 @@ class group(_shareData):
for dataList in self.data: for dataList in self.data:
groupName, x, gid, userList = dataList groupName, x, gid, userList = dataList
if groupName in groups: if groupName in groups:
# usersList = ",".join(filter(lambda x: x != userName, usersList = ",".join(filter(lambda x: x!=userName,
# userList.split(","))) userList.split(",")))
usersList = ",".join([x for x in userList.split(",") if x != userName])
dataList[3] = usersList dataList[3] = usersList
data.append(dataList) data.append(dataList)
self.data = data self.data = data
return self.data return self.data
class shadow(_shareData): class shadow(_shareData):
'''Class for working with the file /etc/shadow''' '''Class for working with the file /etc/shadow'''
fileName = "/etc/shadow" fileName = "/etc/shadow"
template = ("%(login)s:%(hash)s:%(shadowLastChange)s:" template = "%(login)s:%(hash)s:%(shadowLastChange)s:\
"%(shadowMin)s:%(shadowMax)s:%(shadowWarning)s:::") %(shadowMin)s:%(shadowMax)s:%(shadowWarning)s:::"
lenData = 9 lenData = 9
@ensure_unicode
def add(self, name, pwdHash, def add(self, name, pwdHash,
shadowLastChange=str(int(time.time()/86400)), shadowMin="0", shadowLastChange=str(int(time.time()/86400)), shadowMin="0",
shadowMax="99999", shadowWarning="7"): shadowMax="99999", shadowWarning="7"):
@ -278,27 +252,27 @@ class shadow(_shareData):
return _shareData.equally(self, getData(listDataA), return _shareData.equally(self, getData(listDataA),
getData(listDataB)) getData(listDataB))
class _shareCache():
class _shareCache(_shareData):
def save(self): def save(self):
path = os.path.dirname(self.fileName) path = os.path.dirname(self.fileName)
if not os.path.exists(path): if not os.path.exists(path):
try: try:
os.makedirs(path) os.makedirs(path)
except OSError: except:
self.printERROR(_("Failed to create directory %s")%path) self.printERROR(_("Failed to create directory %s")%path)
return False return False
if not os.path.exists(self.fileName): if not os.path.exists(self.fileName):
try: try:
open(self.fileName, "w").close() open(self.fileName, "w")
except IOError: except:
self.printERROR(_("Failed to create file %s")%self.fileName) self.printERROR(_("Failed to create file %s")%self.fileName)
return False return False
if self.getFileAccess(perm="WRITE"): if self.getFileAccess(perm="WRITE"):
modeFile = 0o600 modeFile = 0600
if getModeFile(self.fileName, mode="mode") != modeFile: if getModeFile(self.fileName, mode="mode") != modeFile:
os.chmod(self.fileName, modeFile) os.chmod(self.fileName, modeFile)
buff = "\n".join((":".join(x) for x in self.data)) + "\n" buff = "\n".join(map(lambda x: ":".join(x), self.data)) + "\n"
FD = open(self.fileName, "w+") FD = open(self.fileName, "w+")
FD.write(buff) FD.write(buff)
FD.close() FD.close()
@ -320,11 +294,9 @@ class _shareCache(_shareData):
else: else:
return False return False
class cachePasswd(_shareCache, passwd): class cachePasswd(_shareCache, passwd):
fileName = "/var/lib/calculate/calculate-client/cache/passwd" fileName = "/var/lib/calculate/calculate-client/cache/passwd"
class cacheGroup(_shareCache, group): class cacheGroup(_shareCache, group):
fileName = "/var/lib/calculate/calculate-client/cache/group" fileName = "/var/lib/calculate/calculate-client/cache/group"
@ -334,20 +306,16 @@ class cacheGroup(_shareCache, group):
def equally(self, listDataA, listDataB): def equally(self, listDataA, listDataB):
return _shareData.equally(self, listDataA, listDataB) return _shareData.equally(self, listDataA, listDataB)
class cacheShadow(_shareCache, shadow): class cacheShadow(_shareCache, shadow):
fileName = "/var/lib/calculate/calculate-client/cache/shadow" fileName = "/var/lib/calculate/calculate-client/cache/shadow"
class cacheCreateGroup(cacheGroup): class cacheCreateGroup(cacheGroup):
fileName = "/var/lib/calculate/calculate-client/cache/create_group" fileName = "/var/lib/calculate/calculate-client/cache/create_group"
class cacheCreatePasswd(cachePasswd): class cacheCreatePasswd(cachePasswd):
fileName = "/var/lib/calculate/calculate-client/cache/create_passwd" fileName = "/var/lib/calculate/calculate-client/cache/create_passwd"
class userCache(color_print):
class userCache(Printable):
ldapObj = ldapUser() ldapObj = ldapUser()
def addUserToCache(self, userName, pwdHash): def addUserToCache(self, userName, pwdHash):
@ -358,7 +326,7 @@ class userCache(Printable):
return False return False
groupName = ldapData['group'] groupName = ldapData['group']
# Add user # Add user
cachePasswdObj = cachePasswd(self) cachePasswdObj = cachePasswd()
if not cachePasswdObj.add(userName, ldapData['uid'], ldapData['gid'], if not cachePasswdObj.add(userName, ldapData['uid'], ldapData['gid'],
gecos=ldapData['fullName'], gecos=ldapData['fullName'],
directory=ldapData['home'], directory=ldapData['home'],
@ -366,7 +334,7 @@ class userCache(Printable):
return False return False
if not cachePasswdObj.save(): if not cachePasswdObj.save():
return False return False
cacheGroupObj = cacheGroup(self) cacheGroupObj = cacheGroup()
# Add primary group # Add primary group
if not cacheGroupObj.add(groupName,ldapData['gid']): if not cacheGroupObj.add(groupName,ldapData['gid']):
return False return False
@ -392,7 +360,7 @@ class userCache(Printable):
if not cacheGroupObj.save(): if not cacheGroupObj.save():
return False return False
# Add shadow user # Add shadow user
cacheShadowObj = cacheShadow(self) cacheShadowObj = cacheShadow()
if not cacheShadowObj.add(userName, pwdHash, if not cacheShadowObj.add(userName, pwdHash,
shadowLastChange=ldapData['shadowLastChange'], shadowLastChange=ldapData['shadowLastChange'],
shadowMin=ldapData['shadowMin'], shadowMin=ldapData['shadowMin'],
@ -405,14 +373,14 @@ class userCache(Printable):
def delUserFromCacheCreate(self, userName): def delUserFromCacheCreate(self, userName):
'''Delete LDAP user from createCache''' '''Delete LDAP user from createCache'''
cacheCreatePasswdObj = cacheCreatePasswd(self) cacheCreatePasswdObj = cacheCreatePasswd()
cacheUserData = cacheCreatePasswdObj.get(userName) cacheUserData = cacheCreatePasswdObj.get(userName)
if cacheUserData is False: if cacheUserData is False:
return False return False
if not cacheUserData: if not cacheUserData:
return True return True
gid = cacheUserData[3] gid = cacheUserData[3]
cacheCreateGroupObj = cacheCreateGroup(self) cacheCreateGroupObj = cacheCreateGroup()
cacheSecondGroups = cacheCreateGroupObj.getSecondUserGroups(userName) cacheSecondGroups = cacheCreateGroupObj.getSecondUserGroups(userName)
if cacheSecondGroups is False: if cacheSecondGroups is False:
return False return False
@ -426,8 +394,10 @@ class userCache(Printable):
if not cacheCreatePasswdObj.save(): if not cacheCreatePasswdObj.save():
return False return False
#delete groups #delete groups
usersGids = [x[3] for x in cacheCreatePasswdObj.data] usersGids = map(lambda x: x[3], cacheCreatePasswdObj.data)
deleteGroups = [x[0] for x in cacheCreateGroupObj.data if not x[2] in usersGids and not x[3]] deleteGroups = map(lambda x: x[0],
filter(lambda x: not x[2] in usersGids and not x[3],
cacheCreateGroupObj.data))
for delGroupName in deleteGroups: for delGroupName in deleteGroups:
if not cacheCreateGroupObj.delete(delGroupName): if not cacheCreateGroupObj.delete(delGroupName):
return False return False
@ -437,14 +407,14 @@ class userCache(Printable):
def delUserFromCache(self, userName): def delUserFromCache(self, userName):
'''Delete LDAP user from cache''' '''Delete LDAP user from cache'''
cachePasswdObj = cachePasswd(self) cachePasswdObj = cachePasswd()
cacheUserData = cachePasswdObj.get(userName) cacheUserData = cachePasswdObj.get(userName)
if cacheUserData is False: if cacheUserData is False:
return False return False
if not cacheUserData: if not cacheUserData:
return True return True
gid = cacheUserData[3] gid = cacheUserData[3]
cacheGroupObj = cacheGroup(self) cacheGroupObj = cacheGroup()
cacheSecondGroups = cacheGroupObj.getSecondUserGroups(userName) cacheSecondGroups = cacheGroupObj.getSecondUserGroups(userName)
if cacheSecondGroups is False: if cacheSecondGroups is False:
return False return False
@ -457,15 +427,17 @@ class userCache(Printable):
if not cachePasswdObj.save(): if not cachePasswdObj.save():
return False return False
#delete groups #delete groups
usersGids = [x[3] for x in cachePasswdObj.data] usersGids = map(lambda x: x[3], cachePasswdObj.data)
deleteGroups = [x[0] for x in cacheGroupObj.data if not x[2] in usersGids and not x[3]] deleteGroups = map(lambda x: x[0],
filter(lambda x: not x[2] in usersGids and not x[3],
cacheGroupObj.data))
for delGroupName in deleteGroups: for delGroupName in deleteGroups:
if not cacheGroupObj.delete(delGroupName): if not cacheGroupObj.delete(delGroupName):
return False return False
if not cacheGroupObj.save(): if not cacheGroupObj.save():
return False return False
# delete shadow user # delete shadow user
cacheShadowObj = cacheShadow(self) cacheShadowObj = cacheShadow()
if not cacheShadowObj.delete(userName): if not cacheShadowObj.delete(userName):
return False return False
if not cacheShadowObj.save(): if not cacheShadowObj.save():
@ -474,13 +446,13 @@ class userCache(Printable):
def delUserFromSystem(self, userName): def delUserFromSystem(self, userName):
'''Delete LDAP user from system files ( passwd, group, shadow )''' '''Delete LDAP user from system files ( passwd, group, shadow )'''
cacheCreatePasswdObj = cacheCreatePasswd(self) cacheCreatePasswdObj = cacheCreatePasswd()
cacheCreatePasswdData = cacheCreatePasswdObj.get(userName) cacheCreatePasswdData = cacheCreatePasswdObj.get(userName)
if cacheCreatePasswdData is False: if cacheCreatePasswdData is False:
return False return False
if not cacheCreatePasswdData: if not cacheCreatePasswdData:
return True return True
passwdObj = passwd(self) passwdObj = passwd()
userData = passwdObj.get(userName) userData = passwdObj.get(userName)
if userData is False: if userData is False:
return False return False
@ -492,17 +464,17 @@ class userCache(Printable):
if not passwdObj.save(): if not passwdObj.save():
return False return False
# delete user group # delete user group
groupObj = group(self) groupObj = group()
listGroupData = groupObj.getData() listGroupData = groupObj.getData()
if listGroupData is False: if listGroupData is False:
return False return False
cacheCreateGroupObj = cacheCreateGroup(self) cacheCreateGroupObj = cacheCreateGroup()
secondUsersGroups = groupObj.getSecondUserGroups(userName) secondUsersGroups = groupObj.getSecondUserGroups(userName)
usersGids = [x[3] for x in passwdObj.data] usersGids = map(lambda x: x[3], passwdObj.data)
listGroupDataWork = [] listGroupDataWork = []
for index, groupData in enumerate(listGroupData): for index, groupData in enumerate(listGroupData):
groupName, x, gid, listUsers = groupData groupName, x, gid, listUsers = groupData
listUsers = [x.strip() for x in listUsers.split(',')] listUsers = filter(lambda x: x.strip(), listUsers.split(','))
listUsers = ",".join(filter(lambda x: x!=userName, listUsers)) listUsers = ",".join(filter(lambda x: x!=userName, listUsers))
cacheCreateGroupData = cacheCreateGroupObj.get(groupName) cacheCreateGroupData = cacheCreateGroupObj.get(groupName)
if cacheCreateGroupData is False: if cacheCreateGroupData is False:
@ -515,7 +487,7 @@ class userCache(Printable):
if not groupObj.save(): if not groupObj.save():
return False return False
# delete user shadow # delete user shadow
shadowObj = shadow(self) shadowObj = shadow()
shadowData = shadowObj.get(userName) shadowData = shadowObj.get(userName)
if shadowData is False: if shadowData is False:
return False return False
@ -543,11 +515,11 @@ class userCache(Printable):
def deleteCacheUsersFromSystem(self): def deleteCacheUsersFromSystem(self):
'''Delete cache users from system''' '''Delete cache users from system'''
cacheCreatePasswdObj = cacheCreatePasswd(self) cacheCreatePasswdObj = cacheCreatePasswd()
cacheCreateListPasswdData = cacheCreatePasswdObj.getData() cacheCreateListPasswdData = cacheCreatePasswdObj.getData()
if cacheCreateListPasswdData is False: if cacheCreateListPasswdData is False:
return False return False
delUsersPasswd = [x[0] for x in cacheCreateListPasswdData] delUsersPasswd = map(lambda x: x[0], cacheCreateListPasswdData)
for delUser in delUsersPasswd: for delUser in delUsersPasswd:
if not self.delUserFromSystem(delUser): if not self.delUserFromSystem(delUser):
return False return False
@ -555,7 +527,7 @@ class userCache(Printable):
def getLoginDomainUsers(self): def getLoginDomainUsers(self):
'''Get all domain login users''' '''Get all domain login users'''
cacheCreatePasswdObj = cacheCreatePasswd(self) cacheCreatePasswdObj = cacheCreatePasswd()
cacheListCreatePasswdData = cacheCreatePasswdObj.getData() cacheListCreatePasswdData = cacheCreatePasswdObj.getData()
if cacheListCreatePasswdData is False: if cacheListCreatePasswdData is False:
return False return False
@ -563,19 +535,19 @@ class userCache(Printable):
def addCacheUsersFromSystem(self): def addCacheUsersFromSystem(self):
'''Add cache users from system''' '''Add cache users from system'''
cachePasswdObj = cachePasswd(self) cachePasswdObj = cachePasswd()
cacheListPasswdData = cachePasswdObj.getData() cacheListPasswdData = cachePasswdObj.getData()
if not isinstance(cacheListPasswdData, (list, tuple)): if cacheListPasswdData is False:
return False return False
# Add cache passwd users to system # Add cache passwd users to system
passwdObj = passwd(self) passwdObj = passwd()
cacheCreatePasswdObj = cacheCreatePasswd(self) cacheCreatePasswdObj = cacheCreatePasswd()
cacheListCreatePasswdData = cacheCreatePasswdObj.getData() cacheListCreatePasswdData = cacheCreatePasswdObj.getData()
if cacheListCreatePasswdData is False: if cacheListCreatePasswdData is False:
return False return False
# remove deleted users # remove deleted users
cacheUsers = [x[0] for x in cacheListPasswdData] cacheUsers = map(lambda x: x[0], cacheListPasswdData)
createUsers = [x[0] for x in cacheListCreatePasswdData] createUsers = map(lambda x: x[0], cacheListCreatePasswdData)
deletedUsers = list(set(createUsers) - set(cacheUsers)) deletedUsers = list(set(createUsers) - set(cacheUsers))
for delUser in deletedUsers: for delUser in deletedUsers:
if not self.delUserFromSystem(delUser): if not self.delUserFromSystem(delUser):
@ -614,12 +586,12 @@ class userCache(Printable):
return False return False
if not cacheCreatePasswdObj.save(): if not cacheCreatePasswdObj.save():
return False return False
cacheShadowObj = cacheShadow(self) cacheShadowObj = cacheShadow()
cacheListShadowData = cacheShadowObj.getData() cacheListShadowData = cacheShadowObj.getData()
if not isinstance(cacheListShadowData, (list, tuple)): if cacheListShadowData is False:
return False return False
# Add cache shadow users to system # Add cache shadow users to system
shadowObj = shadow(self) shadowObj = shadow()
for cacheShadowData in cacheListShadowData: for cacheShadowData in cacheListShadowData:
userName, pwdHash, shadowLastChange, shadowMin, shadowMax,\ userName, pwdHash, shadowLastChange, shadowMin, shadowMax,\
shadowWarning, x,x,x = cacheShadowData shadowWarning, x,x,x = cacheShadowData
@ -633,24 +605,22 @@ class userCache(Printable):
if shadowObj.data: if shadowObj.data:
if not shadowObj.save(): if not shadowObj.save():
return False return False
cacheGroupObj = cacheGroup(self) cacheGroupObj = cacheGroup()
cacheListGroupData = cacheGroupObj.getData() cacheListGroupData = cacheGroupObj.getData()
if not isinstance(cacheListGroupData, (list, tuple)): if cacheListGroupData is False:
return False return False
cacheCreateGroupObj = cacheCreateGroup(self) cacheCreateGroupObj = cacheCreateGroup()
# Add cache group users to system # Add cache group users to system
groupObj = group(self) groupObj = group()
setAddUsers = set(addUsers) setAddUsers = set(addUsers)
for cacheGroupData in cacheListGroupData: for cacheGroupData in cacheListGroupData:
groupName, x, gid, listUsers = cacheGroupData groupName, x, gid, listUsers = cacheGroupData
retGroup = groupObj.get(groupName) retGroup = groupObj.get(groupName)
if retGroup is False: if retGroup is False:
return 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: 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 retGroup:
if not cacheCreateGroupObj.add(groupName, gid, listUsers): if not cacheCreateGroupObj.add(groupName, gid, listUsers):
return False return False
@ -671,18 +641,17 @@ class userCache(Printable):
if not self.isConnectToLdap(): if not self.isConnectToLdap():
self.printERROR(_("Failed to connect to the LDAP server")) self.printERROR(_("Failed to connect to the LDAP server"))
return False return False
cachePasswdObj = cachePasswd(self) cachePasswdObj = cachePasswd()
cacheListPasswdData = cachePasswdObj.getData() cacheListPasswdData = cachePasswdObj.getData()
if cacheListPasswdData is False: if cacheListPasswdData is False:
return False return False
if (not isinstance(cacheListPasswdData, (tuple, list)) or if not cacheListPasswdData:
not cacheListPasswdData):
return True return True
cacheGroupObj = cacheGroup(self) cacheGroupObj = cacheGroup()
cacheListGroupData = cacheGroupObj.getData() cacheListGroupData = cacheGroupObj.getData()
if cacheListGroupData is False: if cacheListGroupData is False:
return False return False
cacheShadowObj = cacheShadow(self) cacheShadowObj = cacheShadow()
deletedCacheUsers = [] deletedCacheUsers = []
for cachePasswdData in cacheListPasswdData: for cachePasswdData in cacheListPasswdData:
userName, x, uid, gid, gecos, directory, shell = cachePasswdData userName, x, uid, gid, gecos, directory, shell = cachePasswdData
@ -690,7 +659,8 @@ class userCache(Printable):
if not ldapData: if not ldapData:
deletedCacheUsers.append(userName) deletedCacheUsers.append(userName)
continue continue
cacheGroupData = [x[0] for x in cacheListGroupData if x[2] == gid] cacheGroupData = map(lambda x: x[0], filter(lambda x: x[2]==gid,
cacheListGroupData))
if not cacheGroupData: if not cacheGroupData:
deletedCacheUsers.append(userName) deletedCacheUsers.append(userName)
continue continue
@ -704,7 +674,9 @@ class userCache(Printable):
x,x, shadowLastChange, shadowMin, shadowMax, shadowWarning,\ x,x, shadowLastChange, shadowMin, shadowMax, shadowWarning,\
x,x,x = cacheShadowData x,x,x = cacheShadowData
groups = cacheGroupObj.getSecondUserGroups(userName) groups = cacheGroupObj.getSecondUserGroups(userName)
gidsGroups = [x[2] for x in cacheGroupObj.data if x[0] in groups] gidsGroups = map(lambda x: x[2],
filter(lambda x : x[0] in groups,
cacheGroupObj.data))
userShadowDict = {'uid': uid, userShadowDict = {'uid': uid,
'gid': gid, 'gid': gid,
'fullName': gecos, 'fullName': gecos,
@ -720,7 +692,8 @@ class userCache(Printable):
for attr, value in userShadowDict.items(): for attr, value in userShadowDict.items():
if attr == "groups": if attr == "groups":
for index, val in enumerate(value): for index, val in enumerate(value):
if set([x[index] for x in ldapData[attr]]) != set(val): if set(map(lambda x: x[index],
ldapData[attr])) != set(val):
flagDeleteUser = True flagDeleteUser = True
break break
else: else:
@ -738,8 +711,8 @@ class userCache(Printable):
def clearCache(self): def clearCache(self):
'''Clear cache files''' '''Clear cache files'''
cacheObjs = (cachePasswd(self), cacheShadow(self), cacheGroup(self), cacheObjs = (cachePasswd(), cacheShadow(), cacheGroup(),
cacheCreateGroup(self), cacheCreatePasswd(self)) cacheCreateGroup(), cacheCreatePasswd())
for cacheObj in cacheObjs: for cacheObj in cacheObjs:
if not cacheObj.save(): if not cacheObj.save():
return False return False

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*- #-*- coding: utf-8 -*-
# Copyright 2012-2016 Mir Calculate. http://www.calculate-linux.org # Copyright 2012-2013 Calculate Ltd. http://www.calculate-linux.org
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -15,16 +15,15 @@
# limitations under the License. # limitations under the License.
__app__ = 'calculate-client' __app__ = 'calculate-client'
__version__ = '3.4.2' __version__ = '3.1.8'
import os
import sys import sys
from calculate.lib.datavars import DataVars from calculate.lib.datavars import DataVars
from calculate.lib.cl_lang import setLocalTranslate from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_client3',sys.modules[__name__]) setLocalTranslate('cl_client3',sys.modules[__name__])
class DataVarsClient(DataVars): class DataVarsClient(DataVars):
"""Variable class for client package""" """Variable class for client package"""

@ -1,92 +0,0 @@
# -*- 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-2016 Mir Calculate. http://www.calculate-linux.org # Copyright 2013 Calculate Ltd. http://www.calculate-linux.org
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -15,26 +15,24 @@
# limitations under the License. # limitations under the License.
import sys import sys
from os import path
from calculate.core.server.func import Action,Tasks from calculate.core.server.func import Action,Tasks
from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate
from calculate.lib.utils.files import FilesError from calculate.lib.utils.files import FilesError
from calculate.desktop.desktop import DesktopError from calculate.desktop.desktop import DesktopError
from ..client import ClientError from calculate.client.client import ClientError
from calculate.lib.utils.samba import SambaError
from calculate.lib.cl_template import TemplatesError from calculate.lib.cl_template import TemplatesError
from calculate.lib.utils.files import isMount
_ = lambda x: x
setLocalTranslate('cl_client3',sys.modules[__name__]) setLocalTranslate('cl_client3',sys.modules[__name__])
__ = getLazyLocalTranslate(_) __ = getLazyLocalTranslate(_)
class ClClientAction(Action): class ClClientAction(Action):
""" """
Ввести машину в домен или вывести Ввести машину в домен или вывести
""" """
# ошибки, которые отображаются без подробностей # ошибки, которые отображаются без подробностей
native_error = (FilesError, ClientError, DesktopError, TemplatesError, native_error = (FilesError,ClientError,DesktopError,TemplatesError)
SambaError)
successMessage = None successMessage = None
failedMessage = None failedMessage = None
@ -58,12 +56,12 @@ class ClClientAction(Action):
}, },
# машина не доменная # машина не доменная
{'name':'only_mount:localpc', {'name':'only_mount:localpc',
'warning': __("This workstation is not in the domain"), 'warning':__("This computer is not in the domain"),
'condition':lambda Get:not Get('cl_remote_host') 'condition':lambda Get:not Get('cl_remote_host')
}, },
# проверить может ли указанный сервер являться доменом # проверить может ли указанный сервер являться доменом
{'name':'domain:check_domain', {'name':'domain:check_domain',
'message': __("Checking {cl_remote_host_new} for domain resources"), 'message':__("Check {cl_remote_host_new} for domain resources"),
'method':'Client.checkDomainServer(cl_remote_host_new,os_net_domain)', 'method':'Client.checkDomainServer(cl_remote_host_new,os_net_domain)',
}, },
# получить пароль для ввода в домен (или воспользоваться кэшированным) # получить пароль для ввода в домен (или воспользоваться кэшированным)
@ -102,11 +100,6 @@ class ClClientAction(Action):
'method':'Client.applyClientTemplates(cl_remote_host)', 'method':'Client.applyClientTemplates(cl_remote_host)',
'depend':Tasks.success_all('mount_remote') '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', {'name':'need_templates:apply_templates',
@ -130,10 +123,6 @@ class ClClientAction(Action):
'method':'Client.cAddCacheUsersFromSystem()', 'method':'Client.cAddCacheUsersFromSystem()',
'depend':Tasks.failed_all('mount_remote') 'depend':Tasks.failed_all('mount_remote')
}, },
# удалить службу client из автозапуска
{'name': 'undomain:noautorun_client',
'method': 'Client.delDaemonAutostart("client")'
},
# добавить службу client в автозапуск # добавить службу client в автозапуск
{'name':'domain:autorun_client', {'name':'domain:autorun_client',
'method':'Client.addDaemonAutostart("client")' 'method':'Client.addDaemonAutostart("client")'
@ -144,18 +133,17 @@ class ClClientAction(Action):
}, },
# сообщения о результатах работы действия # сообщения о результатах работы действия
{'name':'domain:success', {'name':'domain:success',
'message': __("Workstation added to domain {cl_remote_host}") 'message':__("Computer added to domain {cl_remote_host}")
}, },
{'name':'domain:failed', {'name':'domain:failed',
'error': __( 'error':__("Failed to add the computer to domain {cl_remote_host}"),
"Failed to add the workstation to domain {cl_remote_host}"),
'depend':Tasks.failed() & Tasks.hasnot("interrupt"), 'depend':Tasks.failed() & Tasks.hasnot("interrupt"),
}, },
{'name':'undomain:success', {'name':'undomain:success',
'message': __("Workstation removed from domain {cl_remote_host}") 'message':__("Computer removed from domain {cl_remote_host}")
}, },
{'name':'undomain:failed', {'name':'undomain:failed',
'error': __("Failed to remove the workstation from the domain"), 'error':__("Failed to remove the computer from the domain"),
'depend':Tasks.failed() & Tasks.hasnot("interrupt"), 'depend':Tasks.failed() & Tasks.hasnot("interrupt"),
}, },
] ]

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*- #-*- coding: utf-8 -*-
# Copyright 2013-2016 Mir Calculate. http://www.calculate-linux.org # Copyright 2013 Calculate Ltd. http://www.calculate-linux.org
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -16,40 +16,89 @@
import sys import sys
from os import path from os import path
from calculate.core.server.func import Action, Tasks, AllTasks from calculate.core.server.func import Action,Tasks
from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate
from calculate.lib.utils.files import FilesError from calculate.lib.utils.files import FilesError
from calculate.desktop.desktop import DesktopError from calculate.desktop.desktop import DesktopError
from calculate.lib.utils.samba import SambaError from calculate.client.client import ClientError
from ..client import ClientError
from calculate.lib.cl_template import TemplatesError from calculate.lib.cl_template import TemplatesError
from calculate.lib.utils.mount import isMount from calculate.lib.utils.files import isMount
_ = lambda x: x
setLocalTranslate('cl_client3',sys.modules[__name__]) setLocalTranslate('cl_client3',sys.modules[__name__])
__ = getLazyLocalTranslate(_) __ = getLazyLocalTranslate(_)
class ClClientSyncLoginAction(Action): class ClClientSyncLoginAction(Action):
""" """
Синхронизировать локальный профиль с удаленным, подключить удаленные Синхронизировать локальный профиль с удаленным, подключить удаленные
ресурсы пользователя ресурсы пользователя
""" """
native_error = (FilesError, ClientError, DesktopError, TemplatesError, native_error = (FilesError,ClientError,DesktopError,TemplatesError)
SambaError)
successMessage = None successMessage = None
failedMessage = None failedMessage = None
interruptMessage = __("Synchronization manually interrupted") interruptMessage = __("Synchronization manually interrupted")
old_sync = [ 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': 'oldsync:mount_resources', {'name':'domain_user:mount_resources',
'message':__("Mounting user resources"), 'message':__("Mounting user resources"),
'method':'Client.mountUserDomainRes(ur_login,' 'method':'Client.mountUserDomainRes(ur_login,'
'desktop.ur_password,' 'desktop.ur_password,'
'ur_uid,ur_gid,"unix","share","homes","ftp")', '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', {'name':'domain_sync:repl_profile',
@ -65,7 +114,7 @@ class ClClientSyncLoginAction(Action):
'cl_client_profile_name,ur_uid,ur_gid)', 'cl_client_profile_name,ur_uid,ur_gid)',
'condition':lambda Get:Get('cl_client_sync_replication_set') == 'on', 'condition':lambda Get:Get('cl_client_sync_replication_set') == 'on',
'else_message':__("The local user profile does not " 'else_message':__("The local user profile does not "
"need to be synchronized with the remote domain") "need to be synchronized with remote domain")
}, },
# монтируем профиль локального домена, если локальный профиль # монтируем профиль локального домена, если локальный профиль
# старее удаленного доменного или актуальный профиль # старее удаленного доменного или актуальный профиль
@ -84,12 +133,11 @@ class ClClientSyncLoginAction(Action):
'ur_gid,ur_home_path,"unix",cl_client_profile_name)', 'ur_gid,ur_home_path,"unix",cl_client_profile_name)',
'condition':lambda Get:Get('cl_client_sync_local_set') == 'on', 'condition':lambda Get:Get('cl_client_sync_local_set') == 'on',
'else_message':__("The local user profile does not " 'else_message':__("The local user profile does not "
"need to be synchronized with the local domain") "need to be synchronized with local domain")
}, },
# ошибка синхронизации с локальным доменом # ошибка синхронизации с локальным доменом
{'name':'local_sync_error', {'name':'local_sync_error',
'warning': __( 'warning':__("Error synchronizing with the local server {cl_remote_host}"),
"Error synchronizing with the local server {cl_remote_host}"),
'depend':Tasks.failed_one_of("mount_local","sync_local") 'depend':Tasks.failed_one_of("mount_local","sync_local")
}, },
# подключить удаленный профиль пользователя с "репликации" # подключить удаленный профиль пользователя с "репликации"
@ -103,7 +151,7 @@ class ClClientSyncLoginAction(Action):
'method':'Client.waitingArchFile(cl_client_pack_time,' 'method':'Client.waitingArchFile(cl_client_pack_time,'
'cl_client_profile_name,"remote_profile")', 'cl_client_profile_name,"remote_profile")',
'failed_warning':__("Failed to find the profile " 'failed_warning':__("Failed to find the profile "
"archive of {cl_replication_host}") "archive from {cl_replication_host}")
}, },
# распаковать архив из удаленного домена и удалить # распаковать архив из удаленного домена и удалить
# файлы которые отсутствуют в удаленном профиле # файлы которые отсутствуют в удаленном профиле
@ -126,8 +174,7 @@ class ClClientSyncLoginAction(Action):
'method':'Client.syncLoginProfile(cl_replication_host,ur_uid,' 'method':'Client.syncLoginProfile(cl_replication_host,ur_uid,'
'ur_gid,ur_home_path,"remote_profile",' 'ur_gid,ur_home_path,"remote_profile",'
'cl_client_profile_name)', 'cl_client_profile_name)',
'depend': Tasks.failed_one_of('pack_remote', 'mount_local', 'depend':Tasks.failed_one_of('pack_remote','mount_local','sync_local',
'sync_local',
'wait_archive','unpack_profile'), 'wait_archive','unpack_profile'),
'condition':lambda Select:isMount( 'condition':lambda Select:isMount(
Select('cl_client_user_mount_path', Select('cl_client_user_mount_path',
@ -138,8 +185,8 @@ class ClClientSyncLoginAction(Action):
# синхронизировать локальный профиль с локальным доменом # синхронизировать локальный профиль с локальным доменом
# как запасной профиль # как запасной профиль
{'name':'pack_remote:fallback_warning', {'name':'pack_remote:fallback_warning',
'warning': __("Error synchronizing with the " 'warning':__("Error synchronizing with the remote server "
"{cl_replication_host} remote server"), "{cl_replication_host}"),
'depend': ~Tasks.success_one_of('unpack_profile','sync_remote') 'depend': ~Tasks.success_one_of('unpack_profile','sync_remote')
}, },
{'name':'pack_remote:fallback_sync', {'name':'pack_remote:fallback_sync',
@ -154,182 +201,43 @@ class ClClientSyncLoginAction(Action):
# сообщение о том, что будет использоваться запасной профиль # сообщение о том, что будет использоваться запасной профиль
# с локального домена # с локального домена
{'name':'fallback_sync!:fallback_success', {'name':'fallback_sync!:fallback_success',
'message': __("Got a user fallback profile from the " 'message': __("Get a user fallback profile from the "
"{cl_remote_host} domain") "{cl_remote_host} domain")
}, },
# ошибка синхронизации профиль не готов! к использованию # ошибка синхронизации профиль не готов! к использованию
{'name':'failed', {'name':'failed',
'error':__("Failed to get the user profile from the domain"), 'error':__("Failed to get the user profile from the domain"),
'method':'Client.setSyncStatus(ur_home_path,ur_uid,ur_gid,"error")', 'method':'Client.setSyncStatus(ur_home_path,ur_uid,ur_gid,"error")',
'depend': Tasks.failed_all('sync_remote', 'sync_local', 'depend':Tasks.failed_all('sync_remote','sync_local','fallback_sync') |
'fallback_sync') |
(Tasks.hasnot('domain_sync') & Tasks.failed()) | (Tasks.hasnot('domain_sync') & Tasks.failed()) |
Tasks.failed_one_of('mount_resources','two_session') 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', {'name':'domain_sync:unpack_links',
'method':'Client.unpackLinks(ur_home_path)', 'method':'Client.unpackLinks(ur_home_path)',
'failed_warning': __("Failed to unpack the links archive"), 'failed_warning': __("Failed to unpack the links archive"),
'depend': Tasks.hasnot('failed') & Tasks.success_one_of("domain_sync", "domain_sync2") 'depend':Tasks.hasnot('failed')
}, },
# синхронизация профиля завершилась успешно # синхронизация профиля завершилась успешно
{'name': 'success_sync', {'name':'domain_sync:success_sync',
'message':__("User profile fetched from the domain"), 'message':__("User profile fetched from the domain"),
'method':'Client.setSyncStatus(ur_home_path,ur_uid,ur_gid,"success")', 'method':'Client.setSyncStatus(ur_home_path,ur_uid,ur_gid,"success")',
'depend': Tasks.success_all('sync_remote','unpack_links') | 'depend': Tasks.success_all('sync_remote','unpack_links') |
Tasks.success() & Tasks.success_one_of("domain_sync", "domain_sync2") Tasks.success()
}, },
# во время синхронизации профиля произошли ошибки, которые не # во время синхронизации профиля произошли ошибки, которые не
# гарантируют целостность профиля # гарантируют целостность профиля
{'name': 'error_sync', {'name':'domain_sync:error_sync',
'warning': __("User profile modifications will not " 'warning':__("Changings in the user profile will not "
"be saved to the domain"), "be saved to the domain"),
'method':'Client.setSyncStatus(ur_home_path,ur_uid,ur_gid,"error")', '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") 'depend': Tasks.hasnot('success_sync','failed')
},
# отключить удалённый профиль
{'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', {'name':'umount_remote_res',
'message':__("Umounting user resources"), 'message':__("Umounting user resources"),
'method':'Client.umountUserRes(desktop.ur_mount_dirs)', 'method':'Client.umountUserRes(desktop.ur_mount_dirs)',
'depend': Tasks.has('failed'), 'depend':Tasks.has('failed')
'condition': lambda GetBool: not GetBool('cl_client_ignore_errors_set')
} }
] ]
@ -353,49 +261,21 @@ class ClClientSyncLogoutAction(Action):
Get('desktop.ur_domain_set') == 'on'), Get('desktop.ur_domain_set') == 'on'),
'else_message':__("The local profile will be used") '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 сессии # проверка на попытку отключить ресурсы пользователя в X сессии
{'name':'domain_user:in_xsession', {'name':'domain_user:in_xsession',
'error': __("User {ur_login} is already on the X session"), 'error':__("User {ur_login} is already in X session"),
'condition': lambda Get: Get('ur_login') in 'condition':lambda Get:Get('ur_login') in \
Get('desktop.cl_desktop_online_user'), Get('desktop.cl_desktop_online_user'),
}, },
# проверить наличие домашней директории # проверить наличие домашней директории
{'name':'domain_user:check_homedir', {'name':'domain_user:check_homedir',
'condition':lambda Get:path.exists(Get('ur_home_path')), 'condition':lambda Get:path.exists(Get('ur_home_path')),
'else_error': __("Home directory {ur_home_path} not found"), 'else_error':__("User 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', {'name':'domain_user:check_mount',
'condition':lambda Get:any(x and isMount(x) 'condition':lambda Get:any(x and isMount(x)
for x in for x in Get('cl_client_user_mount_path')),
Get('cl_client_user_mount_path')),
'else_error':__("Remote user resources not found") 'else_error':__("Remote user resources not found")
}, },
# установить время выхода из сеанса # установить время выхода из сеанса
@ -406,14 +286,13 @@ class ClClientSyncLogoutAction(Action):
{'name':'domain_user:domain_sync', {'name':'domain_user:domain_sync',
'condition':lambda Get:Get('cl_client_sync_status') == 'success' and 'condition':lambda Get:Get('cl_client_sync_status') == 'success' and
Get('cl_client_sync') == 'on', Get('cl_client_sync') == 'on',
'else_warning': __("The profile will not be uploaded to the domain") 'else_warning':__("The profile will not be uploaded to domain")
}, },
# переместить файлы из профиля в Moved # переместить файлы из профиля в Moved
{'name':'domain_user:move_home_dir', {'name':'domain_user:move_home_dir',
'message': __("Moving non-profile files to the Home/Moved directory"), 'message':__("Moving non-profile files to Home/Moved directory"),
'method':'Client.moveHomeDir(ur_home_path,"Moved","homes",' 'method':'Client.moveHomeDir(ur_home_path,"Moved","homes",'
'cl_moved_skip_path)', 'cl_moved_skip_path)',
'condition': lambda Get: Get('cl_sync_moved_set') == 'on'
}, },
# архивировать симлинки # архивировать симлинки
{'name':'domain_sync:tar_symlinks', {'name':'domain_sync:tar_symlinks',
@ -426,12 +305,6 @@ class ClClientSyncLogoutAction(Action):
'method':'Client.syncLogoutProfile(cl_remote_host,ur_uid,' 'method':'Client.syncLogoutProfile(cl_remote_host,ur_uid,'
'ur_gid,ur_home_path,"unix",cl_client_profile_name,' 'ur_gid,ur_home_path,"unix",cl_client_profile_name,'
'cl_client_symlinks)', 'cl_client_symlinks)',
'depend': Tasks.has('oldsync')
},
{'name': 'domain_sync:sync_logout',
'method': 'Client.syncLogoutProfileNew(cl_remote_host,ur_login,desktop.ur_password,ur_uid,'
'ur_gid,ur_home_path,cl_client_profile_name,cl_client_symlinks)',
'depend': Tasks.has('newsync')
}, },
# удалить файлы, которые могут помешать следующему входу в сеанс # удалить файлы, которые могут помешать следующему входу в сеанс
{'name':'domain_sync:remove_noise_files', {'name':'domain_sync:remove_noise_files',

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*- #-*- coding: utf-8 -*-
# Copyright 2013-2016 Mir Calculate. http://www.calculate-linux.org # Copyright 2013 Calculate Ltd. http://www.calculate-linux.org
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -15,31 +15,28 @@
# limitations under the License. # limitations under the License.
import sys import sys
from calculate.core.server.func import Action from os import path
from calculate.core.server.func import Action,Tasks
from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate from calculate.lib.cl_lang import setLocalTranslate,getLazyLocalTranslate
from calculate.lib.utils.files import FilesError from calculate.lib.utils.files import FilesError
from calculate.desktop.desktop import DesktopError from calculate.desktop.desktop import DesktopError
from ..client import ClientError from calculate.client.client import ClientError
from calculate.lib.utils.samba import SambaError
from calculate.lib.cl_template import TemplatesError from calculate.lib.cl_template import TemplatesError
_ = lambda x: x
setLocalTranslate('cl_client3',sys.modules[__name__]) setLocalTranslate('cl_client3',sys.modules[__name__])
__ = getLazyLocalTranslate(_) __ = getLazyLocalTranslate(_)
class ClPasswdAction(Action): class ClPasswdAction(Action):
""" """
Изменить пароль доменного пользователя Изменить пароль доменного пользователя
""" """
# ошибки, которые отображаются без подробностей # ошибки, которые отображаются без подробностей
native_error = (FilesError, ClientError, DesktopError, TemplatesError, native_error = (FilesError,DesktopError,TemplatesError,ClientError)
SambaError)
successMessage = (__("{cl_client_login}'s password changed\n" successMessage = (__("{cl_client_login}'s password changed\n"
"This modification will be applied when " "The password will be changed when you log out"
"you quit the X session")) "from the X session"))
failedMessage = __("Failed to change the password") failedMessage = __("Failed to change password")
interruptMessage = __("Password changing manually interrupted") interruptMessage = __("Password changing manually interrupted")
# список задач для действия # список задач для действия

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*- #-*- coding: utf-8 -*-
# Copyright 2008-2016 Mir Calculate. http://www.calculate-linux.org # Copyright 2008-2013 Calculate Ltd. http://www.calculate-linux.org
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -14,9 +14,7 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from __future__ import absolute_import import action
import client
from . import action
from . import client
section = "client" section = "client"

@ -1,6 +1,6 @@
#-*- coding: utf-8 -*- #-*- coding: utf-8 -*-
# Copyright 2008-2016 Mir Calculate. http://www.calculate-linux.org # Copyright 2008-2013 Calculate Ltd. http://www.calculate-linux.org
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -14,23 +14,56 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import os
import sys import sys
from calculate.lib.datavars import ActionVariable from os import path
from calculate.lib.datavars import (Variable,VariableError,ReadonlyVariable,
ActionVariable)
from calculate.lib.cl_lang import setLocalTranslate from calculate.lib.cl_lang import setLocalTranslate
setLocalTranslate('cl_client3',sys.modules[__name__]) setLocalTranslate('cl_client3',sys.modules[__name__])
class VariableAcClientMerge(ActionVariable):
"""
Action variable which has value "up" for package install and
install this package
"""
nonchroot = True
def action(self,cl_action):
if cl_action in ("merge","domain","undomain"):
ret = "on"
return "off"
class VariableAcClientConfigure(ActionVariable): class VariableAcClientDomain(ActionVariable):
""" """
Action variable which has value "on" for domain action Action variable which has value "on" for domain action
""" """
nonchroot = True nonchroot = True
def action(self,cl_action): def action(self,cl_action):
if cl_action in ("domain", "undomain"): remoteHost = self.Get("cl_remote_host")
remoteAuth = self.Get("os_remote_auth")
if cl_action == "domain":
return "on"
elif ((cl_action in "merge" or
cl_action == 'sync' and self.Get('cl_merge_pkg'))
and remoteHost and remoteAuth):
return "on" return "on"
else:
return "off" return "off"
class VariableAcClientUndomain(ActionVariable):
"""
Action variable which has value "on" for undomain action
"""
nonchroot = True
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-2016 Mir Calculate. http://www.calculate-linux.org # Copyright 2008-2013 Calculate Ltd. http://www.calculate-linux.org
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -19,17 +19,11 @@ import sys
from os import path from os import path
import re import re
from calculate.lib.datavars import (Variable,VariableError,ReadonlyVariable, from calculate.lib.datavars import (Variable,VariableError,ReadonlyVariable,
ReadonlyTableVariable, FieldValue, ReadonlyTableVariable,FieldValue)
HumanReadable) from calculate.lib.cl_template import iniParser
from calculate.lib.cl_ini_parser import iniParser from calculate.lib.utils.files import readLinesFile,isMount,readFile, find
from calculate.lib.configparser import ConfigParser from calculate.lib.utils.common import getValueFromCmdLine,cmpVersion
import calculate.lib.utils.device as device from calculate.lib.variables.user import VariableUrLogin
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.convertenv import convertEnv
from calculate.lib.utils.ip import isOpenPort from calculate.lib.utils.ip import isOpenPort
import time import time
@ -38,15 +32,10 @@ from socket import gethostbyname
from calculate.lib.cl_ldap import ldapUser from calculate.lib.cl_ldap import ldapUser
from calculate.lib.variables.user import LdapHelper from calculate.lib.variables.user import LdapHelper
import pwd import pwd
from ..client import Client from calculate.client.client import Client
from ..rsync import ProfileSyncer, ProfileSyncerError
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate from calculate.lib.cl_lang import setLocalTranslate
_ = lambda x: x
setLocalTranslate('cl_client3',sys.modules[__name__]) setLocalTranslate('cl_client3',sys.modules[__name__])
__ = getLazyLocalTranslate(_)
class VariableClRemoteHost(Variable): class VariableClRemoteHost(Variable):
""" """
@ -54,12 +43,6 @@ class VariableClRemoteHost(Variable):
""" """
value = "" value = ""
class VariableClRemoteDomain(Variable):
"""
Имя домена
"""
value = ""
class VariableClRemoteHostNew(Variable): class VariableClRemoteHostNew(Variable):
""" """
IP or domain name of CDS IP or domain name of CDS
@ -79,20 +62,17 @@ class VariableClRemoteHostNew(Variable):
if self.Get('cl_localhost_set') == 'off': if self.Get('cl_localhost_set') == 'off':
if self.Get('cl_remote_host') == '': if self.Get('cl_remote_host') == '':
if not value: if not value:
raise VariableError(_("Please specify the domain")) raise VariableError(_("Need to specify the domain"))
elif not isOpenPort(value,445): elif not isOpenPort(value,445):
raise VariableError( raise VariableError(
_("The specified address is not available")) _("The specified address is not available"))
class VariableClRemoteHostLive(ReadonlyVariable): class VariableClRemoteHostLive(ReadonlyVariable):
""" """
Remote host from /proc/cmdline param domain Remote host from /proc/cmdline param domain
""" """
def get(self): def get(self):
return getValueFromCmdLine(CmdlineParams.Calculate, return getValueFromCmdLine("calculate","domain") or ""
CmdlineParams.Domain) or ""
class VariableOsRemoteAuth(Variable): class VariableOsRemoteAuth(Variable):
@ -116,13 +96,11 @@ class VariableClRemotePw(Variable):
opt = ["--domain-password"] opt = ["--domain-password"]
def init(self): def init(self):
self.label = __("Domain password") self.label = _("Domain password")
self.help = _("specify the domain password") self.help = _("specify the domain password")
def get(self): def get(self):
return getValueFromCmdLine(CmdlineParams.Calculate, return getValueFromCmdLine("calculate","domain_pw") or ""
CmdlineParams.DomainPassword) or ""
class VariableClMovedSkipPath(Variable): class VariableClMovedSkipPath(Variable):
""" """
@ -131,7 +109,6 @@ class VariableClMovedSkipPath(Variable):
type = "list" type = "list"
value = ['Disks','Home','Moved','FTP','Desktop', 'Share'] value = ['Disks','Home','Moved','FTP','Desktop', 'Share']
class VariableClSyncSkipPath(Variable): class VariableClSyncSkipPath(Variable):
""" """
Skip sync path Skip sync path
@ -145,7 +122,6 @@ class VariableClSyncSkipPath(Variable):
".Xauthority", ".thumbnails", ".mozilla/firefox/*/Cache", ".Xauthority", ".thumbnails", ".mozilla/firefox/*/Cache",
".kde4/socket-*", ".cache/", ".local/share/Trash"] ".kde4/socket-*", ".cache/", ".local/share/Trash"]
class VariableClSyncDelPath(Variable): class VariableClSyncDelPath(Variable):
""" """
Removed path on sync Removed path on sync
@ -154,12 +130,10 @@ class VariableClSyncDelPath(Variable):
value = [".kde4/share/config/phonondevicesrc", value = [".kde4/share/config/phonondevicesrc",
".kde4/cache-*", ".kde4/tmp-*"] ".kde4/cache-*", ".kde4/tmp-*"]
class VariableClProfileAllSet(Variable): class VariableClProfileAllSet(Variable):
type = "bool" type = "bool"
value = "off" value = "off"
class VariableClClientSync(Variable): class VariableClClientSync(Variable):
type = "bool" type = "bool"
value = "on" value = "on"
@ -171,7 +145,6 @@ class VariableClClientSync(Variable):
self.label = _("Synchronize the user profile") self.label = _("Synchronize the user profile")
self.help = _("synchronize user preferences") self.help = _("synchronize user preferences")
class VariableClLocalhostSet(Variable): class VariableClLocalhostSet(Variable):
""" """
Using autopartition Using autopartition
@ -184,7 +157,7 @@ class VariableClLocalhostSet(Variable):
untrusted = True untrusted = True
def init(self): def init(self):
self.label = _("Workstation role") self.label = _("Computer role")
self.help = _("remove the domain connection settings") self.help = _("remove the domain connection settings")
def choice(self): def choice(self):
@ -194,10 +167,9 @@ class VariableClLocalhostSet(Variable):
def check(self,value): def check(self,value):
if self.Get('cl_client_mount_set') == 'off': if self.Get('cl_client_mount_set') == 'off':
if self.Get('cl_remote_host') == '' and value == "on": if self.Get('cl_remote_host') == '' and value == "on":
raise VariableError(_("The workstation is not in the domain")) raise VariableError(_("The computer is not in the domain"))
if self.Get('cl_remote_host') != '' and value == "off": if self.Get('cl_remote_host') != '' and value == "off":
raise VariableError( raise VariableError(_("The computer is already in the domain %s")
_("The workstation is already in the domain %s")
%self.Get('cl_remote_host') + "\n" + %self.Get('cl_remote_host') + "\n" +
_("Before joining the domain, " _("Before joining the domain, "
"you need to remove it from the previous domain")) "you need to remove it from the previous domain"))
@ -208,7 +180,6 @@ class VariableClLocalhostSet(Variable):
# else: # else:
# return "off" # return "off"
class VariableClClientMountSet(Variable): class VariableClClientMountSet(Variable):
""" """
Mount remote by configured domain information Mount remote by configured domain information
@ -222,7 +193,6 @@ class VariableClClientMountSet(Variable):
self.label = _("Only mount the domain resource") self.label = _("Only mount the domain resource")
self.help = _("only mount the [remote] domain resource") self.help = _("only mount the [remote] domain resource")
class VariableUrUserPw(Variable,LdapHelper): class VariableUrUserPw(Variable,LdapHelper):
""" """
Current user password Current user password
@ -240,12 +210,14 @@ class VariableUrUserPw(Variable, LdapHelper):
def checkUserPwdLDAP(self, server, userDN, password): def checkUserPwdLDAP(self, server, userDN, password):
"""Check unix user password on server""" """Check unix user password on server"""
ldapInit = ldap.initialize("ldap://%s"%server) ldapInit = ldap.initialize("ldap://%s"%server)
errMessage = ""
try: try:
ldapInit.bind_s(userDN, password) ldapInit.bind_s(userDN, password)
except ldap.INVALID_CREDENTIALS: except ldap.INVALID_CREDENTIALS:
raise VariableError(_("Wrong password")) raise VariableError(_("Wrong password"))
except ldap.LDAPError as e: except ldap.LDAPError, e:
raise VariableError(f"{e.args[0]['desc']}; {e.args[0]['info']}") errMessage = e[0]['desc']
raise VariableError(errMessage)
return True return True
def check(self,value): def check(self,value):
@ -262,7 +234,6 @@ class VariableUrUserPw(Variable, LdapHelper):
usersDN) usersDN)
self.checkUserPwdLDAP(server,userDN,value) self.checkUserPwdLDAP(server,userDN,value)
class VariableUrUserNewPw(Variable): class VariableUrUserNewPw(Variable):
""" """
New user password New user password
@ -281,8 +252,7 @@ class VariableUrUserNewPw(Variable):
if not value: if not value:
raise VariableError(_("Empty password")) raise VariableError(_("Empty password"))
class VariableClClientLogin(VariableUrLogin):
class VariableClClientLogin(user.VariableUrLogin):
""" """
User Login User Login
""" """
@ -290,9 +260,9 @@ class VariableClClientLogin(user.VariableUrLogin):
alias = "ur_login" alias = "ur_login"
def choice(self): def choice(self):
loginChoice = user.VariableUrLogin.choice(self) loginChoice = VariableUrLogin.choice(self)
if self.Get('cl_action') == 'passwd': if self.Get('cl_action') == 'passwd':
return [x for x in loginChoice if x != "root"] return filter(lambda x:x != "root",loginChoice)
else: else:
return loginChoice return loginChoice
@ -301,13 +271,13 @@ class VariableClClientLogin(user.VariableUrLogin):
if not value in self.choice() and self.Get('cl_action') == 'logout': if not value in self.choice() and self.Get('cl_action') == 'logout':
raise VariableError(_("X session users not found")) raise VariableError(_("X session users not found"))
if value == "": if value == "":
raise VariableError(_("Please specify the user")) raise VariableError(_("Need to specify user"))
if value == "root" and self.Get('cl_action') == 'passwd': if value == "root" and self.Get('cl_action') == 'passwd':
raise VariableError( raise VariableError(\
_("This action can be executed by a non-root user only")) _("The action can be executed by a non-root user only"))
try: try:
pwd.getpwnam(value).pw_gid pwd.getpwnam(value).pw_gid
except (TypeError, KeyError): except:
raise VariableError(_("User %s does not exist")%value) raise VariableError(_("User %s does not exist")%value)
def get(self): def get(self):
@ -316,7 +286,6 @@ class VariableClClientLogin(user.VariableUrLogin):
return self.Get('ur_login') return self.Get('ur_login')
return "" return ""
class VariableClClientRelevanceSet(ReadonlyVariable): class VariableClClientRelevanceSet(ReadonlyVariable):
""" """
Актуальны ли сейчас выполненные шаблоны Актуальны ли сейчас выполненные шаблоны
@ -324,36 +293,33 @@ class VariableClClientRelevanceSet(ReadonlyVariable):
type = "bool" type = "bool"
def get(self): 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"): if self.Get('cl_remote_host') != self.Get("os_remote_auth"):
return "off" return "off"
if (self.Get('cl_remote_host') and if (self.Get('cl_remote_host') and
not isMount(self.Get('cl_client_remote_path'))): not isMount(self.Get('cl_client_remote_path'))):
return "off" return "off"
currentVersion = self.Get("cl_ver")
# версия программы, который были наложены шаблоны
previousVersion = self.Get("os_remote_client")
if cmpVersion(currentVersion,previousVersion):
return "off"
return "on" return "on"
class VariableClClientRemotePath(Variable): class VariableClClientRemotePath(Variable):
""" """
Путь для монитрования //domain/remote Путь для монитрования //domain/remote
""" """
value = "/var/calculate/remote" value = "/var/calculate/remote"
class VariableClClientProfileName(Variable): class VariableClClientProfileName(Variable):
""" """
Название удаленного профиля (CLD,CLDX,all) Название удаленного профиля (CLD,CLDX,all)
""" """
def get(self): def get(self):
return ("all" if self.Get('cl_profile_all_set') == 'on' return ("all" if self.Get('cl_profile_all_set') == 'on'
else self.Get('os_linux_shortname')) else self.Get('os_linux_shortname'))
class VariableClLdapData(ldapUser,ReadonlyVariable): class VariableClLdapData(ldapUser,ReadonlyVariable):
""" """
Внутренняя переменная, содержащая объект для доступа к данным LDAP Внутренняя переменная, содержащая объект для доступа к данным LDAP
@ -399,7 +365,8 @@ class VariableClLdapData(ldapUser, ReadonlyVariable):
def _gethostbyname(self,hostname): def _gethostbyname(self,hostname):
try: try:
return gethostbyname(hostname) return gethostbyname(hostname)
except Exception: except:
pass
return None return None
def getNameRemoteServer(self,userName, osLinuxShort, curHost): def getNameRemoteServer(self,userName, osLinuxShort, curHost):
@ -408,7 +375,7 @@ class VariableClLdapData(ldapUser, ReadonlyVariable):
current server current server
""" """
searchPrevHost = self.searchPrevHost(userName, osLinuxShort) searchPrevHost = self.searchPrevHost(userName, osLinuxShort)
if searchPrevHost and 'host' in searchPrevHost[0][0][1]: if searchPrevHost and searchPrevHost[0][0][1].has_key('host'):
prevHost = searchPrevHost[0][0][1]['host'][0] prevHost = searchPrevHost[0][0][1]['host'][0]
else: else:
prevHost = None prevHost = None
@ -449,13 +416,11 @@ class VariableClReplicationHost(ReadonlyVariable):
""" """
Удаленный сервер при репликации, который содержит актуальный профиль Удаленный сервер при репликации, который содержит актуальный профиль
""" """
def get(self): def get(self):
return self.Get('cl_ldap_data').getNameRemoteServer( 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')) self.Get('cl_remote_host'))
class VariableClClientUserMountData(ReadonlyTableVariable): class VariableClClientUserMountData(ReadonlyTableVariable):
""" """
Таблица монтирования ресурсов Таблица монтирования ресурсов
@ -465,67 +430,29 @@ class VariableClClientUserMountData(ReadonlyTableVariable):
'cl_client_user_mount_path', 'cl_client_user_mount_path',
'cl_client_user_mount_host'] 'cl_client_user_mount_host']
def get(self, hr=HumanReadable.No): def get(self):
home = path.split(self.Get('ur_home_path'))[0] home = path.split(self.Get('ur_home_path'))[0]
envFile = self.Get('cl_env_server_path') 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(): def generate():
yield ( yield ("share","share",path.join(self.Get('ur_home_path'),"Share"),
"share", "share", path.join(self.Get('ur_home_path'), "Share"), self.Get('cl_remote_host'))
samba_host) yield ("unix","unix",path.join(home,".%s"%self.Get('ur_login')),
yield ( self.Get('cl_remote_host'))
"unix", "unix", path.join(home, ".%s" % self.Get('ur_login'), yield ("homes","homes",path.join(self.Get('ur_home_path'),"Home"),
"profile"), self.Get('cl_remote_host'))
samba_host) if convertEnv().getVar("ftp","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"), yield ("ftp","ftp",path.join(self.Get('ur_home_path'),"FTP"),
ftp_host) self.Get('cl_remote_host'))
else: else:
yield ("ftp",'','','') yield ("ftp",'','','')
if self.Get('cl_replication_host'): if self.Get('cl_replication_host'):
yield ("remote_profile","unix", yield ("remote_profile","unix",
path.join(home, ".%s" % self.Get('ur_login'), path.join(home,".%s.remote"%self.Get('ur_login')),
"remote_profile"),
self.Get('cl_replication_host')) self.Get('cl_replication_host'))
else: 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()) return list(generate())
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): class VariableClClientUserMountName(FieldValue,ReadonlyVariable):
""" """
Название удаленного ресурса Название удаленного ресурса
@ -543,7 +470,6 @@ class VariableClClientUserMountResource(FieldValue, ReadonlyVariable):
source_variable = "cl_client_user_mount_data" source_variable = "cl_client_user_mount_data"
column = 1 column = 1
class VariableClClientUserMountPath(FieldValue,ReadonlyVariable): class VariableClClientUserMountPath(FieldValue,ReadonlyVariable):
""" """
Путь подключения удаленного ресурса Путь подключения удаленного ресурса
@ -552,7 +478,6 @@ class VariableClClientUserMountPath(FieldValue, ReadonlyVariable):
source_variable = "cl_client_user_mount_data" source_variable = "cl_client_user_mount_data"
column = 2 column = 2
class VariableClClientUserMountHost(FieldValue,ReadonlyVariable): class VariableClClientUserMountHost(FieldValue,ReadonlyVariable):
""" """
Удаленный сервер Удаленный сервер
@ -561,23 +486,11 @@ class VariableClClientUserMountHost(FieldValue, ReadonlyVariable):
source_variable = "cl_client_user_mount_data" source_variable = "cl_client_user_mount_data"
column = 3 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 файла Получить status_sync из desktop файла
@ -603,6 +516,7 @@ class SyncHelper():
return False return False
return varsConfig 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 Convert date from string format (dateformat) to stuct or None
@ -625,14 +539,14 @@ class SyncHelper():
objConfig) objConfig)
timeLogout = data["date_logout"] timeLogout = data["date_logout"]
timeConfig = data["date"] timeConfig = data["date"]
dates = [x for x in [self.convertDate(timeLogout), dates = filter(None,
self.convertDate(timeConfig)] if x] [self.convertDate(timeLogout),
self.convertDate(timeConfig)])
if dates: if dates:
return dates[0] return dates[0]
return "" return ""
def checkNeedSync(self, homeDir, rpath, curTimeObj, curStatusSync, def checkNeedSync(self,homeDir,rpath,curTimeObj,curStatusSync,osLinuxShort):
osLinuxShort):
""" """
Проверить необходимость синхронизации текущего профиля с удаленным Проверить необходимость синхронизации текущего профиля с удаленным
""" """
@ -660,81 +574,31 @@ class SyncHelper():
return False return False
return True return True
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): class VariableClClientSyncTime(SyncHelper,ReadonlyVariable):
""" """
Текущее время синхронизации профиля Текущее время синхронизации профиля
""" """
def get(self): def get(self):
return self.getDateObjClientConf(self.Get('ur_home_path')) return self.getDateObjClientConf(self.Get('ur_home_path'))
class VariableClClientPackTime(SyncHelper,ReadonlyVariable): class VariableClClientPackTime(SyncHelper,ReadonlyVariable):
""" """
Время комады упаковки профиля Время комады упаковки профиля
""" """
def get(self): def get(self):
return str(float(time.time())) return str(float(time.time()))
class VariableClClientSyncStatus(SyncHelper,ReadonlyVariable): class VariableClClientSyncStatus(SyncHelper,ReadonlyVariable):
""" """
Текущий статус синхронизации профиля Текущий статус синхронизации профиля
""" """
def get(self): def get(self):
return self.getSyncStatus(self.Get('ur_home_path')) return self.getSyncStatus(self.Get('ur_home_path'))
class VariableClClientLocalSyncTime(SyncHelper,ReadonlyVariable): class VariableClClientLocalSyncTime(SyncHelper,ReadonlyVariable):
""" """
Текущий статус синхронизации профиля Текущий статус синхронизации профиля
""" """
def get(self): def get(self):
return self.getDateObjClientConf( return self.getDateObjClientConf(
path.join( path.join(
@ -742,164 +606,57 @@ class VariableClClientLocalSyncTime(SyncHelper, ReadonlyVariable):
where='cl_client_user_mount_name',eq='unix', where='cl_client_user_mount_name',eq='unix',
limit=1),self.Get('cl_client_profile_name'))) limit=1),self.Get('cl_client_profile_name')))
class VariableClClientRsyncProfileSet(ReadonlyVariable):
"""
Используется rsync через ssh для синхронизации пользовательского профиля
"""
type = "bool"
value = "off"
class VariableClClientSyncReplicationSet(SyncHelper,ReadonlyVariable): class VariableClClientSyncReplicationSet(SyncHelper,ReadonlyVariable):
""" """
Нужно ли синхронизировать текущий профиль с удаленным доменом Нужно ли синхронизировать текущий профиль с удаленным доменом
""" """
type = "bool" type = "bool"
host_varname = "cl_replication_host" def get(self):
profile_type = "remote_profile" if not self.Get('cl_replication_host'):
return "off"
def old_synchronize(self):
profilePath = self.Select('cl_client_user_mount_path', profilePath = self.Select('cl_client_user_mount_path',
where='cl_client_user_mount_name', where='cl_client_user_mount_name',
eq=self.profile_type, limit=1) eq='remote_profile',limit=1)
if self.Get('cl_action') == 'login' and not isMount(profilePath): if self.Get('cl_action') == 'login' and not isMount(profilePath):
raise VariableError(_("Remote profile not mounted")) raise VariableError(_("Remote profile not mounted"))
return "on" if self.checkNeedSync(self.Get('ur_home_path'),profilePath, return "on" if self.checkNeedSync(self.Get('ur_home_path'),profilePath,
self.Get('cl_client_sync_time'), self.Get('cl_client_sync_time'),
self.Get('cl_client_sync_status'), self.Get('cl_client_sync_status'),
self.Get( self.Get('cl_client_profile_name')) else "off"
'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'): class VariableClClientSyncLocalSet(SyncHelper,ReadonlyVariable):
return self.new_synchronize()
else:
return self.old_synchronize()
class VariableClClientSyncLocalSet(VariableClClientSyncReplicationSet):
""" """
Нужно ли синхронизировать текущий профиль с локальным доменом Нужно ли синхронизировать текущий профиль с локальным доменом
""" """
type = "bool" type = "bool"
host_varname = "cl_remote_host" def get(self):
profile_type = "unix" 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"
class VariableClClientSymlinks(ReadonlyVariable): class VariableClClientSymlinks(ReadonlyVariable):
""" """
Список симлинков в пользовательском профиле Список симлинков в пользовательском профиле
""" """
def get(self): def get(self):
skipFiles = (self.Get('cl_sync_del_path') + skipFiles = (self.Get('cl_sync_del_path') +
self.Get('cl_sync_skip_path')) self.Get('cl_sync_skip_path'))
reSkip = re.compile("|".join((x.replace("*", ".*") for x in skipFiles))).search reSkip = re.compile("|".join(map(lambda x:x.replace("*",".*"),
return [x for x in find(self.Get('ur_home_path'), onefilesystem=True, skipFiles))).search
filetype=FindFileType.SymbolicLink) return filter(lambda x:not reSkip(x),
if not reSkip(x)] find(self.Get('ur_home_path'),onefilesystem=True,filetype='l'))
class VariableClClientNscdCache(Variable): class VariableClClientNscdCache(Variable):
""" """
Частота обновления кэша nscd при работе в домене в часах Частота обновления кэша 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-2016 Mir Calculate. http://www.calculate-linux.org # Copyright 2012-2013 Calculate Ltd. http://www.calculate-linux.org
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -13,24 +13,21 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from __future__ import absolute_import
import sys import sys
from calculate.lib.datavars import VariableError, DataVarsError from calculate.lib.datavars import VariableError, DataVarsError
from calculate.core.server.func import WsdlBase from calculate.core.server.func import WsdlBase
from calculate.desktop.desktop import DesktopError from calculate.desktop.desktop import DesktopError
from .client import ClientError from client import ClientError
from calculate.lib.utils.samba import SambaError from utils.cl_client import ClClientAction
from .utils.cl_client import ClClientAction from utils.cl_passwd import ClPasswdAction
from .utils.cl_passwd import ClPasswdAction from utils.cl_client_sync import (ClClientSyncLoginAction,
from .utils.cl_client_sync import (ClClientSyncLoginAction,
ClClientSyncLogoutAction) ClClientSyncLogoutAction)
import calculate.desktop.desktop as desktop import calculate.desktop.desktop as desktop
from . import client import calculate.client.client as client
from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate from calculate.lib.cl_lang import setLocalTranslate, getLazyLocalTranslate
_ = lambda x: x
setLocalTranslate('cl_client3', sys.modules[__name__]) setLocalTranslate('cl_client3', sys.modules[__name__])
__ = getLazyLocalTranslate(_) __ = getLazyLocalTranslate(_)
@ -48,7 +45,7 @@ class Wsdl(WsdlBase):
# заголовок метода # заголовок метода
'title': __("Domain"), 'title': __("Domain"),
# иконка для графической консоли # иконка для графической консоли
'image': 'calculate-client,network-server,network-workgroup', 'image': 'network-server,network-workgroup',
# метод присутствует в графической консоли # метод присутствует в графической консоли
'gui': True, 'gui': True,
# консольная команда # консольная команда
@ -63,10 +60,10 @@ class Wsdl(WsdlBase):
# объект переменных # объект переменных
'datavars': "client", 'datavars': "client",
'native_error': (VariableError, DataVarsError, 'native_error': (VariableError, DataVarsError,
SambaError,
ClientError, DesktopError), ClientError, DesktopError),
# значения по умолчанию для переменных этого метода # значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'domain', 'setvars': {'cl_action!': 'domain',
'cl_protect_use_set!':'off'
}, },
'guivars': {'cl_localhost_set!': lambda dv: ( 'guivars': {'cl_localhost_set!': lambda dv: (
"on" if dv.Get('cl_remote_host') == '' else 'off')}, "on" if dv.Get('cl_remote_host') == '' else 'off')},
@ -74,14 +71,13 @@ class Wsdl(WsdlBase):
'groups': [ 'groups': [
lambda group: group(_("Domain"), lambda group: group(_("Domain"),
normal=( normal=(
'cl_localhost_set', 'cl_localhost_set', 'cl_remote_host_new',
'cl_remote_host_new',
'cl_remote_pw'), 'cl_remote_pw'),
expert=('cl_client_mount_set', expert=('cl_client_mount_set',
'cl_templates_locate', 'cl_templates_locate',
'cl_verbose_set', 'cl_verbose_set',
'cl_dispatch_conf'), 'cl_dispatch_conf'),
next_label=_("Execute"))]}, next_label=_("Perform"))]},
# #
# подключить удаленные ресурсы пользователя # подключить удаленные ресурсы пользователя
# #
@ -93,7 +89,7 @@ class Wsdl(WsdlBase):
# заголовок метода # заголовок метода
'title': __("Domain User Login"), 'title': __("Domain User Login"),
# иконка для графической консоли # иконка для графической консоли
'image': 'calculate-client-sync-login,application-other', 'image': 'application-other',
# метод не присутствует в графической консоли # метод не присутствует в графической консоли
'gui': False, 'gui': False,
# консольная команда # консольная команда
@ -108,7 +104,6 @@ class Wsdl(WsdlBase):
# объект переменных # объект переменных
'datavars': "client", 'datavars': "client",
'native_error': (VariableError, DataVarsError, 'native_error': (VariableError, DataVarsError,
SambaError,
ClientError, DesktopError), ClientError, DesktopError),
# значения по умолчанию для переменных этого метода # значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'login'}, 'setvars': {'cl_action!': 'login'},
@ -116,8 +111,7 @@ class Wsdl(WsdlBase):
'groups': [ 'groups': [
lambda group: group(_("Domain user login"), lambda group: group(_("Domain user login"),
normal=('ur_login', 'cl_client_sync'), normal=('ur_login', 'cl_client_sync'),
expert=('cl_client_ignore_errors_set',), next_label=_("Perform"))]},
next_label=_("Execute"))]},
# #
# отключить удаленные ресурсы пользователя # отключить удаленные ресурсы пользователя
# #
@ -129,7 +123,7 @@ class Wsdl(WsdlBase):
# заголовок метода # заголовок метода
'title': __("Domain User Logout"), 'title': __("Domain User Logout"),
# иконка для графической консоли # иконка для графической консоли
'image': 'calculate-client-sync-logout,application-other', 'image': 'application-other',
# метод не присутствует в графической консоли # метод не присутствует в графической консоли
'gui': False, 'gui': False,
# консольная команда # консольная команда
@ -144,7 +138,6 @@ class Wsdl(WsdlBase):
# объект переменных # объект переменных
'datavars': "client", 'datavars': "client",
'native_error': (VariableError, DataVarsError, 'native_error': (VariableError, DataVarsError,
SambaError,
ClientError, DesktopError), ClientError, DesktopError),
# значения по умолчанию для переменных этого метода # значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'logout'}, 'setvars': {'cl_action!': 'logout'},
@ -152,7 +145,7 @@ class Wsdl(WsdlBase):
'groups': [ 'groups': [
lambda group: group(_("Domain user logout"), lambda group: group(_("Domain user logout"),
normal=('ur_login', 'cl_client_sync'), normal=('ur_login', 'cl_client_sync'),
next_label=_("Execute"))]}, next_label=_("Perform"))]},
# #
# сменить пароль доменного пользователя # сменить пароль доменного пользователя
# #
@ -162,9 +155,9 @@ class Wsdl(WsdlBase):
# категория метода # категория метода
'category': __('Client'), 'category': __('Client'),
# заголовок метода # заголовок метода
'title': __("Password Modification"), 'title': __("Change Password"),
# иконка для графической консоли # иконка для графической консоли
'image': 'calculate-client-passwd,preferences-system-privacy,system-users', 'image': 'preferences-system-privacy,system-users',
# метод присутствует в графической консоли # метод присутствует в графической консоли
'gui': True, 'gui': True,
# пользовательский метода # пользовательский метода
@ -181,13 +174,12 @@ class Wsdl(WsdlBase):
# объект переменных # объект переменных
'datavars': "client", 'datavars': "client",
'native_error': (VariableError, DataVarsError, 'native_error': (VariableError, DataVarsError,
SambaError,
ClientError, DesktopError), ClientError, DesktopError),
# значения по умолчанию для переменных этого метода # значения по умолчанию для переменных этого метода
'setvars': {'cl_action!': 'passwd'}, 'setvars': {'cl_action!': 'passwd'},
# описание груп (список лямбда функций) # описание груп (список лямбда функций)
'groups': [ 'groups': [
lambda group: group(_("Password modification"), lambda group: group(_("Change password"),
normal=('cl_client_login', 'ur_user_pw', normal=('cl_client_login', 'ur_user_pw',
'ur_user_new_pw'), 'ur_user_new_pw'),
next_label=_("Save"))]}, next_label=_("Save"))]},

@ -1,9 +1,9 @@
#!/usr/bin/env python #!/usr/bin/env python2
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# setup.py --- Setup script for calculate-desktop # setup.py --- Setup script for calculate-desktop
# Copyright 2012-2021 Mir Calculate. http://www.calculate-linux.org # Copyright 2012 Calculate Ltd. http://www.calculate-linux.org
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -23,57 +23,18 @@ __version__ = "3.2.2"
import os import os
from glob import glob from glob import glob
from distutils.core import setup, Extension from distutils.core import setup, Extension
from distutils.command import install_data as module_install_data from calculate.install_data import 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', ('/usr/share/calculate/xdm/login.d',
['data/login.d/10client']), ['data/login.d/10client']),
('/usr/share/calculate/xdm/login.d',
['data/login.d/15resume_remount']),
('/usr/share/calculate/xdm/logout.d', ('/usr/share/calculate/xdm/logout.d',
['data/logout.d/10client']), ['data/logout.d/10client']),
('/usr/share/calculate/xdm/',[('data/wait_domain',0o755)])] ('/usr/share/calculate/xdm/logout.d',
['data/logout.d/15resume_remount']),
class install_data(module_install_data.install_data): ('/usr/share/calculate/xdm/',[('data/wait_domain',0755)])]
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 = [ packages = [
"calculate."+str('.'.join(root.split(os.sep)[1:])) "calculate."+str('.'.join(root.split(os.sep)[1:]))

Loading…
Cancel
Save