阿芬吖 發表於 2023-7-27 00:00:00

rsync 代码分发

<p>线上服务器既有Windows又有Linux的,代码的分发更新要规划下了。使用rsync来分发代码,同时考虑到不同系统平台,用法有些不同。将rsync命令进行了下封装,执行脚本即可。方便开发人员使用。</p>
<h3>1. rsync服务端配置</h3>
<p></p><pre class="brush:bash;toolbar:false"># 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 = *


    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</pre><p></p>
<h3>2. 客户端</h3>
<p>这里只说下Windows下的rsync用法,其实和Linux下相同,Windows上要安装cwRsync,同时将Python2.7也安装上,因为后面的Python脚本需要使用到Python环境。</p><pre class="brush:bash;toolbar:false"># 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= if arg.startswith(x) or arg.endswith(x)]
      if res:
            raise NUMARG_ERROR('ip格式错误!')

      err_arg=[',-','-,','--',',,']
      res=
      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:
            returne.__str__()
      except getopt.GetoptError,e:
            return '-%s %s\r\n\r\n%s'%(e,_help_d['-'+e],_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)
            returnerr_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('-').strip()),int(x.split('-').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('-').strip()),int(x.split('-').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') ornot kwargs.has_key('-s') ornot 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()
    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
    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</pre><p>IP支持192.168.1,3-5.100,111-122这种写法。</p>
<h3>3. 用法</h3>
<p><img src="https://zhuji.jb51.net/uploads/img/20230517/311d35ec9f098ef51eebfd70f830f898.jpg" width="300" height="201"></p>
頁: [1]
查看完整版本: rsync 代码分发