| #!/usr/bin/env python3 |
| |
| ''' |
| gpsync -- rsync to multiple hosts at once |
| |
| Usage: gpsync [--version] [-?v] [-r] [-a] [-p port] [-u user] |
| [-h host] [-f hostfile] [-J host_substitution_character] [[user@]host1:]file1 [...] [[user@]hosts2:]file2 |
| |
| --version : print version information |
| -? : print this help screen |
| -v : verbose mode |
| -r : recursively copy entire directories |
| -a : archive mode; equals -rlptgoD (no -H,-A,-X) |
| -h host : ssh host to connect to (multiple -h is okay) |
| -f file : a file listing all hosts to connect to |
| -J character : character to be substitute as hostname [default='='] |
| ''' |
| import os |
| import sys |
| import getopt |
| import subprocess |
| from gppylib.util import ssh_utils |
| from gppylib.gpparseopts import OptParser |
| from gppylib.parseutils import canonicalize_address |
| |
| progname = os.path.split(sys.argv[0])[-1] |
| |
| # |
| # all the command line options |
| # |
| class Global: |
| script_name = os.path.split(__file__)[-1] |
| USER = os.environ.get('LOGNAME') or os.environ.get('USER') |
| opt = {} |
| opt['-v'] = False |
| opt['-h'] = [] |
| opt['-f'] = None |
| opt['-J'] = '=:' |
| opt['-r'] = False |
| opt['-a'] = False |
| filePath = [] |
| |
| |
| GV = Global() |
| |
| |
| ################ |
| def usage(exitarg): |
| parser = OptParser() |
| try: |
| parser.print_help() |
| except: |
| print(__doc__) |
| sys.exit(exitarg) |
| |
| |
| ############# |
| def print_version(): |
| print('%s version $Revision$' % GV.script_name) |
| sys.exit(0) |
| |
| |
| ############# |
| def parseCommandLine(): |
| try: |
| (options, args) = getopt.getopt(sys.argv[1:], '?vraJ:p:u:h:f:', ['version']) |
| except Exception as e: |
| usage('Error: ' + str(e)) |
| |
| for (switch, val) in options: |
| if (switch == '-?'): |
| usage(0) |
| elif (switch == '-v'): |
| GV.opt[switch] = True |
| elif (switch == '-f'): |
| GV.opt[switch] = val |
| elif (switch == '-h'): |
| GV.opt[switch].append(val) |
| elif (switch == '-J'): |
| GV.opt[switch] = val + ':' |
| elif (switch == '-r'): |
| GV.opt[switch] = True |
| elif (switch == '-a'): |
| GV.opt[switch] = True |
| elif (switch == '--version'): |
| print_version() |
| |
| hf = (len(GV.opt['-h']) and 1 or 0) + (GV.opt['-f'] and 1 or 0) |
| if hf != 1: |
| usage('Error: please specify at least one of -h or -f args, but not both') |
| |
| if (len(args) < 2): |
| usage('Error: please specify local and remote file paths') |
| |
| GV.filePath = args |
| |
| |
| ############# |
| try: |
| parseCommandLine() |
| hostlist = ssh_utils.HostList() |
| for h in GV.opt['-h']: |
| hostlist.add(h) |
| if GV.opt['-f']: |
| hostlist.parseFile(GV.opt['-f']) |
| |
| try: |
| hostlist.checkSSH() |
| except ssh_utils.SSHError as e: |
| sys.exit('[ERROR] ' + str(e)) |
| |
| GV.opt['-h'] = hostlist.filterMultiHomedHosts() |
| if len(GV.opt['-h']) == 0: |
| usage('Error: missing hosts in -h and/or -f arguments') |
| |
| rsync = 'rsync -e "ssh -o BatchMode=yes -o StrictHostKeyChecking=no"' |
| if GV.opt['-r']: rsync += ' -r' |
| if GV.opt['-a']: rsync += ' -a' |
| |
| proc = [] |
| for peer in GV.opt['-h']: |
| peer = canonicalize_address(peer) # MPP-13617 |
| cmd = rsync + ' ' |
| for f in GV.filePath: |
| cmd += f.replace(GV.opt['-J'], '%s:' % peer) + ' ' |
| if GV.opt['-v']: print('[INFO]', cmd) |
| proc.append(subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)) |
| |
| withError = False |
| for p in proc: |
| for line in p.stdout.readlines(): |
| print('[OUT %s] %s' % ("".join(p.args), line)) |
| status = p.wait() |
| if status: |
| print('[ERROR %s] exit %d, cmd - %s' % (p.stderr.read(), status, "".join(p.args))) |
| withError=True |
| |
| if withError: sys.exit(1) |
| if GV.opt['-v']: print('[INFO] completed successfully') |
| |
| except KeyboardInterrupt: |
| sys.exit('\nInterrupted...') |