线上服务器既有Windows又有Linux的,代码的分发更新要规划下了。使用rsync来分发代码,同时考虑到不同系统平台,用法有些不同。将rsync命令进行了下封装,执行脚本即可。方便开发人员使用。
1. rsync服务端配置
# yum install rsync
# vim /etc/rsyncd.conf
uid = nobody
gid = nobody
use chroot = no
strict modes = no
max connections = 5
charset=utf8
secrets file = /etc/rsyncd.secrets
reverse lookup = no
transfer logging = yes
log format = %t [%p] %o %a %m %P %f %B %M %l (%u) [%C]
log file = /var/log/rsyncd.log
pid file = /var/run/rsyncd.pid
hosts allow = 10.0.100.162
hosts deny = *
[www_ttlsa_com]
path=/data/webroot/www.ttlsa.com
comment = WSGW
read only = no
ignore errors
exclude = .svn/
dont compress = *.gz *.tgz *.zip *.z *.bz2 *.tbz
# vim /etc/rc.local
rsync --daemon
2. 客户端
这里只说下Windows下的rsync用法,其实和Linux下相同,Windows上要安装cwRsync,同时将Python2.7也安装上,因为后面的Python脚本需要使用到Python环境。
# vim rsyncclient.py
#coding:utf-8
import sys
import os
import getopt
import itertools
import subprocess
import thread
import Queue
import platform
if platform.system()==\'Windows\':
_bin_path=r\'D:\\\"Program Files (x86)\"\\cwRsync_5.3.0_Free\\rsync.exe\'
else:
_bin_path=\'rsync\'
_default_user=\'rsyncuser\'
_default_arg=\'-vzrtopg --progress --delete\'
_thread_num=10
_help_d={\'-s\':\'(必选) 本地目录/文件。例如 E:\\\\tmp\',
\'-h\':\'(必选) 目的ip。支持\", -\"批量操作符,例如192.168.1,3-5.100\',
\'-m\':\'(必选) rsync模块名\',
\'-u\':\'(可选) rsync用户名。默认:%s\'%(_default_user),
\'-p\':\'(可选) 密码文件路径。例如 E:\\\\passwd\\\\userpasswd.txt\'}
_help=\'\\r\\n\'.join([\'%s %s\'%(k,v) for (k,v) in _help_d.iteritems()])
_help=\'全部参数:\\r\\n\'+_help
_help+=\'\'\'\\r\\n\\r\\n样例:
windows:
rsynclient.py -h 192.168.1.2 -s E:\\\\data\\\\xuhh -m xuhh
linux:
python26 rsynclient.py -h 192.168.1.2 -s /data/xuhh -m xuhh
[注意]
E:\\\\data\\\\xuhh目录后面加上\\\\与不加\\\\有区别。如E:\\\\data\\\\xuhh\\\\只同步xuhh目录下的内容不包含xuhh目录;E:\\\\data\\\\xuhh同步xuhh整个目录.\'\'\'
_help+=\'\\r\\n\\r\\n\'
def check_num(func):
def t(arg):
arg=arg.replace(\' \',\'\')
res=[x for x in [\',\',\'-\'] if arg.startswith(x) or arg.endswith(x)]
if res:
raise NUMARG_ERROR(\'ip格式错误!\')
err_arg=[\',-\',\'-,\',\'--\',\',,\']
res=[x for x in err_arg if x in arg]
if res:
raise NUMARG_ERROR(\'ip格式错误!\')
return func(arg)
return t
class NUMARG_ERROR(Exception):
def __init__(self,value):
self.value=value
def __str__(self):
return self.value+\'\\r\\n\\r\\n\'+_help
class ARG_ERROR(Exception):
def __init__(self,value):
self.value=value
def __str__(self):
return self.value+\'\\r\\n\\r\\n\'+_help
def catch_exception(func):
def t(*args,**kwargs):
try:
return func(*args,**kwargs)
except NUMARG_ERROR,e:
return e.__str__()
except ARG_ERROR,e:
return e.__str__()
except getopt.GetoptError,e:
return \'-%s %s\\r\\n\\r\\n%s\'%(e[1],_help_d[\'-\'+e[1]],_help)
except:
import cStringIO
import traceback
err_fp = cStringIO.StringIO()
traceback.print_exc(file=err_fp)
err_msg = err_fp.getvalue()
err_msg=\'\\r\\n\'.join(err_msg.split( \'\\n\'))
#self.response.out.write(err_msg)
return err_msg
return t
@check_num
def extend_num(arg):
res=[]
if \',\' in arg:
s=arg.split(\',\')
for x in s:
if \'-\' in x:
y=[ str(xx).decode(\'utf-8\') for xx in range(int(x.split(\'-\')[0].strip()),int(x.split(\'-\')[1].strip())+1)]
res.extend(y)
else:
res.append(x.strip())
elif \'-\' in arg:
x=arg
y=[ str(xx).decode(\'utf-8\') for xx in range(int(x.split(\'-\')[0].strip()),int(x.split(\'-\')[1].strip())+1)]
res.extend(y)
else:
res.append(arg.strip())
res=dict.fromkeys(res).keys()
res.sort()
return res
def to_rsync_path(path):
if platform.system()==\'Windows\':
rsync__path=os.path.abspath(path)
rsync__path=rsync__path.replace(\'\\\\\',\'/\')
rsync__path=rsync__path.replace(\':\',\'\')
rsync__path=\'/cygdrive/\'+rsync__path
if path.endswith(\'\\\\\'):
rsync__path+=\'/\'
return rsync__path
else:
return path
@catch_exception
def run(*argv):
opts,args=getopt.getopt(argv,\'h:m:s:u:p:\')
kwargs=dict(opts)
#检查参数是否足够
if not kwargs.has_key(\'-h\') or not kwargs.has_key(\'-s\') or not kwargs.has_key(\'-m\'):
raise ARG_ERROR(\'参数不足!\')
print \'--help\'
if kwargs.has_key(\'-u\') and not kwargs.has_key(\'-p\'):
raise ARG_ERROR(\'密码参数-p没有指定!\')
#使用默认用户认证
if kwargs.has_key(\'-p\') and not kwargs.has_key(\'-u\'):
kwargs[\'-u\']=_default_user
#将路径转换为rsync能识别的格式
kwargs[\'-s\']=to_rsync_path(kwargs[\'-s\'])
if kwargs.has_key(\'-p\'):
kwargs[\'-p\']=to_rsync_path(kwargs[\'-p\'])
#扩展ip
ips=[]
try:
ip_seq1,ip_seq2,ip_seq3,ip_seq4=kwargs[\'-h\'].split(\'.\')
for num1,num2,num3,num4 in itertools.product(extend_num(ip_seq1),extend_num(ip_seq2),extend_num(ip_seq3),extend_num(ip_seq4)):
ips.append(\'%s.%s.%s.%s\'%(num1,num2,num3,num4))
except:
raise NUMARG_ERROR(\'ip格式错误!\')
#启动线程
queue=Queue.Queue()
for x in range(_thread_num):
thread.start_new_thread(_work_thread,(queue,))
for ip in ips:
if kwargs.has_key(\'-u\'):
cmd=\'%s %s \"%s\" %s@%s::%s --password-file=%s\'%(_bin_path,_default_arg,kwargs[\'-s\'],kwargs[\'-u\'],ip,kwargs[\'-m\'],kwargs[\'-p\'])
else:
cmd=\'%s %s \"%s\" %s::%s\'%(_bin_path,_default_arg,kwargs[\'-s\'],ip,kwargs[\'-m\'])
queue.put([ip,cmd])
queue.join()
def _work_thread(queue):
while True:
ip,cmd=queue.get()
output=subprocess.Popen(cmd.encode(\'cp936\'),shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT).stdout.read()
output= \'**********%s**********\\r\\n%s\\r\\n%s\'%(ip,cmd,output)
if platform.system()==\'Windows\':
output=output.decode(\'utf-8\').encode(\'cp936\')
print output
queue.task_done()
if __name__==\'__main__\':
argv=sys.argv[1:]
if argv:
res=run(*argv)
if res:
if platform.system()==\'Windows\':
res=res.decode(\'utf-8\').encode(\'cp936\')
print res
else:
if platform.system()==\'Windows\':
_help=_help.decode(\'utf-8\').encode(\'cp936\')
print _help
IP支持192.168.1,3-5.100,111-122这种写法。


