blob: 66822345265f324414019c6c3520dc24ec1995a8 [file] [log] [blame]
#!/usr/bin/env python
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
'''
gpscp -- scp to multiple hosts at once
Usage: gpscp [--version] [-?v] [-r] [-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
-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='=']
'''
#disable deprecationwarnings
import warnings
warnings.simplefilter('ignore', DeprecationWarning)
import os
import sys
import getopt
import subprocess
from gppylib.util import ssh_utils
from gppylib.gpparseopts import OptParser
from gppylib.gpcoverage import GpCoverage
from gppylib.parseutils import canonicalize_address
progname = os.path.split(sys.argv[0])[-1]
if sys.version_info < (2, 5, 0):
sys.exit(
'''Error: %s is supported on Python versions 2.5 or greater
Please upgrade python installed on this machine.''' % progname)
#
# 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['--ignore-bad-hosts'] = False
filePath = []
GV = Global()
################
def usage(exitarg):
parser = OptParser()
try:
parser.print_help()
except:
print __doc__
sys.exit(0)
#############
def print_version():
print '%s version $Revision$' % GV.script_name
sys.exit(0)
#############
def parseCommandLine():
try:
(options, args) = getopt.getopt(sys.argv[1:], '?vrJ:p:u:h:f:', ['version', 'ignore-bad-hosts'])
except Exception, 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 == '--version'): print_version()
elif (switch == '--ignore-bad-hosts'): GV.opt[switch] = True
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
#############
def run(cmd, peer):
if GV.opt['-v']: print '[INFO]', cmd
p = subprocess.Popen(cmd, shell=True)
p.x_cmd = cmd
p.x_peer = peer
return p
#############
coverage = GpCoverage()
coverage.start()
try:
parseCommandLine()
hostlist = ssh_utils.HostList()
for h in GV.opt['-h']:
hostlist.add(h)
if GV.opt['-f']:
hostlist.parseFile(GV.opt['-f'])
if GV.opt['--ignore-bad-hosts']:
original_hostlist = hostlist.list
bad_hosts = hostlist.removeBadHosts()
if len(bad_hosts) == len(original_hostlist):
sys.exit('[ERROR]: Unable to SSH to any of the hosts {0}'.format(original_hostlist))
if len(bad_hosts) > 0:
print "[WARN]: Skipping syncing configuration file on hosts {0}, as ssh test failed".format(bad_hosts)
else:
try:
hostlist.checkSSH()
except ssh_utils.SSHError, 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')
scp = 'scp -o "BatchMode yes" -o "StrictHostKeyChecking no"'
if GV.opt['-r']: scp += ' -r'
proc = []
for peer in GV.opt['-h']:
peer = canonicalize_address(peer) # MPP-13617
cmd = scp + ' '
for f in GV.filePath:
cmd += f.replace(GV.opt['-J'], '%s:' % peer) + ' '
proc.append(run(cmd, peer))
errmsg = None
for p in proc:
p.communicate()
if p.returncode:
errmsg = '[ERROR %s] exit %d, cmd - %s' % (p.x_peer, p.returncode, p.x_cmd)
print errmsg
if errmsg: sys.exit(1)
if GV.opt['-v']: print '[INFO] completed successfully'
except KeyboardInterrupt:
sys.exit('\nInterrupted...')
finally:
coverage.stop()
coverage.generate_report()