diff --git a/gpAux/releng/QAUTILS_FILES.txt b/gpAux/releng/QAUTILS_FILES.txt index f7930992053927f1cd24238b53af29031b1551c8..4477d86a276af47ddb9a3d5bf27217928d4913d2 100644 --- a/gpAux/releng/QAUTILS_FILES.txt +++ b/gpAux/releng/QAUTILS_FILES.txt @@ -1,6 +1,5 @@ bin/explain.pl bin/gpcheckmirrorseg.pl -bin/gpdebug bin/gpfaultinjector bin/gptorment.pl bin/lib/gpgetconfig.py diff --git a/gpAux/releng/SUPPORT_FILES.txt b/gpAux/releng/SUPPORT_FILES.txt index 7b58768487343c57241263f8df022435262ea922..c97d826530eff4e462b85b07e8326c1c163b4d63 100644 --- a/gpAux/releng/SUPPORT_FILES.txt +++ b/gpAux/releng/SUPPORT_FILES.txt @@ -1,3 +1,2 @@ bin/gpcheckmirrorseg.pl sbin/gprepairmirrorseg.py -bin/gpdebug diff --git a/gpMgmt/bin/gpdebug b/gpMgmt/bin/gpdebug deleted file mode 100755 index 7b565242cf3c114f469167e50f3643b790a0fc4f..0000000000000000000000000000000000000000 --- a/gpMgmt/bin/gpdebug +++ /dev/null @@ -1,356 +0,0 @@ -#!/usr/bin/env python -# Line too long - pylint: disable=C0301 -# Invalid name - pylint: disable=C0103 - -""" - gpdebug - Copyright (c) EMC/Greenplum Inc 2011. All Rights Reserved. -""" -import os, signal, time - -import psutil - -from gppylib import gplog, pgconf -from gppylib.db import dbconn -from gppylib.gparray import get_segment_hosts, get_session_ids -from gppylib.mainUtils import YamlMain, Exit -from gppylib.commands import gp -from gppylib.commands.unix import check_pid -from gppylib.commands.base import run_remote_commands, Command -from gppylib.gp_era import read_era -from gppylib.util.ssh_utils import get_hosts -from gppylib.utils import TableLogger - - -class GpDebugMain(YamlMain): - """ - Main class for the gpdebug utility. The yaml document below specifies - - * how command line options are parsed - * expected execution scenarios - * expected error conditions and messages - - %YAML 1.1 - --- - - # - # arguments - # - Usage: 'usage: %prog [options]' - Description: Investigate processes - Options: - Groups: - - Help Options - - Logging Options - - Connection Options - - Troubleshooting Options - - Orphan Options - - Help Options: - -h,-?,--help,--usage: - help: Show help message and exit. - action: help - Logging Options: - -q: Quiet Mode - only show problems on stdout - -v: Verbose Mode - include verbose debugging information - Connection Options: - -d,--master_data_directory: - type: string - dest: masterDataDirectory - metavar: 'MASTERDATADIR' - help: | - Optional. The master host data directory. - If not specified, the value set for $MASTER_DATA_DIRECTORY will be used. - Troubleshooting Options: - --pid: - help: Capture Troubleshooting information for specified process. - action: store_const - dest: scenario - const: Capture Troubleshooting Information - Orphan Options: - -f: - help: Hosts file - type: string - dest: hostsfile - --orphans: - help: Search cluster for orphan processes - action: store_const - dest: scenario - const: Check Cluster For Orphans - --all: - help: Count system processes as orphans - action: store_true - --detailed: - help: Report orphan details - action: store_true - - # gpdebug --orphans remotely executes gpdebug --orphans-host - # on each segment host with additional --era and --datadir parameters. - # note that --datadir may occur multiple times - - --orphans-host: - help: hidden - Check host for orphan processes - action: store_const - dest: scenario - const: Check Host For Orphans - --host: - help: hidden - Current host - type: string - dest: host - --era: - help: hidden - Current master era (or None) - type: string - dest: era - --datadir: - help: hidden - segment data directory - type: string - action: append - dest: dirlist - --sessid: - help: hidden - session id - type: string - action: append - dest: sessionids - - # - # scenarios - # - Default Scenario: Capture Troubleshooting Information - - Scenarios: - Capture Troubleshooting Information: - - 1. On Current Host: - - 1.1. Validate PID - - 1.2. Troubleshoot Process - - Check Cluster For Orphans: - - 1. On Current Host: - - 1.1. Identify Master - - 1.2. Identify Segments - - 1.3. Identify Sessions - - 1.4. Identify Current Era - - 1.5. Search for Orphans - - 1.6. Report Results - - 1.7. Generate Output File - - Check Host For Orphans: - - 1. On Current Host: - - 1.1. Identify Orphans - - 1.2. Return Orphan Details - - Errors: - nopid: 'no pid specified, consider --help' - badpid: 'invalid pid: %(pid)s' - get_segment_hosts: 'Unable to read hosts from master. Please investigate or consider -f hostfile option.' - """ - - - # GpDebugMain constructor - # - def __init__(self): - "Here we go..." - YamlMain.__init__(self) - - # generic state set by YamlMain.run() we also set here mainly to make code clearer - # - self.scenario_name = None # what we call what we're doing, e.g. 'Examine Process' - self.plan = None # plan object built from the yaml above - self.logger = None # helpful logger object reference - self.errmsg = None # helpful errmsg function reference - - # additional state we update during execution - self.pid = None # pid - - # Orphans (master host) - self.master_datadir = None # master data directory - self.master_port = None # master port - self.host_list = None # list of hosts - self.era = None # master era - self.results = None # execution results - - # Orphans (segment) - self.orphans = None - - - # - # Scenario: Capture Troubleshooting Information - # - - def validate_pid(self): - "" - - # user has to give us an argument - if len(self.args) != 1: - raise Exit(1, 'nopid') - - # the argument had better be a valid integer - pid = self.args[0] - try: - self.pid = int(pid) - except (ValueError), e: - raise Exit(1,'badpid') - - - def troubleshoot_process(self): - "" - - # use glider to capture the stack of the target process. - # we run it from a shell with an explicit ulimit to prevent - # this from taking too long (occasionally observed on osx). - # - pid = self.pid - shcmd = 'ulimit -t 4; $GPHOME/sbin/glider %(pid)s' % locals() - command = Command('Troubleshooting', shcmd) - - self.logger.info(command) - command.run(validateAfter = False) - - # log whatever output we get, stderr as error and stdout as info - # - for line in command.get_stderr_lines(): - self.logger.info(line) - for line in command.get_stdout_lines(): - self.logger.info(line) - - - # - # Scenario: Check Cluster For Orphans (master host) - # - - def identify_master(self): - "" - self.master_datadir = self.options.masterDataDirectory or gp.get_masterdatadir() - self.master_port = gp.get_masterport(self.master_datadir) - - def identify_segments(self): - "" - if self.options.hostsfile: - self.hosts_list = get_hosts(self.options.hostsfile) - else: - self.hosts_list = get_segment_hosts(self.master_port) - - - def identify_sessions(self): - "" - if self.options.hostsfile: - self.session_ids = set() - else: - self.session_ids = get_session_ids(self.master_port) - - for sess_id in self.session_ids: - self.logger.info('session id: %s' % sess_id) - - - def identify_current_era(self): - "" - self.era = read_era(self.master_datadir, self.logger) - - def search_for_orphans(self): - "" - commands = {} - for host in self.hosts_list: - cmdlist = [ - '$GPHOME/bin/gpdebug', - '-q', - '--orphans-host', - '--era', str(self.era), - '--host', str(host) - ] - if self.options.all: - cmdlist.append('--all') - if self.options.detailed: - cmdlist.append('--detailed') - for s in self.session_ids: - cmdlist.append('--sessid') - cmdlist.append(str(s)) - - commands[host] = " ".join(cmdlist) - - cmds = run_remote_commands('Search for Orphans', commands) - self.results = {} - for host, cmd in cmds.items(): - self.results[host] = cmd.get_stdout_lines() - - - def report_results(self): - "" - for host, lines in self.results.items(): - if len(lines) < 1: - self.logger.info('no orphans observed on %s' % host) - continue - self.logger.info('found %d orphans on %s' % (len(lines), host)) - - - # --detailed output - # - if self.options.detailed: - tabLog = None - for host, lines in self.results.items(): - prev = None - for line in lines: - host2, era, sessid, pid, detail = line.split('|') - assert host == host2 - if era != prev: - if tabLog: - self.logger.info("Era: %s" % prev) - tabLog.outputTable() - self.logger.info("--------------------------------------------") - tabLog = TableLogger() - tabLog.info(["Host","SessId","Pid","Detail"]) - prev = era - tabLog.info([host, sessid, pid, detail]) - if tabLog: - self.logger.info("Era: %s" % prev) - tabLog.outputTable() - self.logger.info("--------------------------------------------") - - # - # Scenario: Check Host For Orphans (segment hosts, via search for orphans) - # - - def identify_orphans(self): - "" - self.logger.info("Era: %s" % self.options.era) - self.orphans = [] - for p in psutil.process_iter(): - try: - d = p.environ() - command = ' '.join(p.cmdline()) - except psutil.Error: - continue - e = d.get('GPERA') - s = d.get('GPSESSID') - - # look for processes from another era - - if e is None: - continue - if e != self.options.era: - self.orphans.append((e, s, str(p.pid), command.strip())) - continue - - # look for process in same era with a session id not in - # the list of session ids known to the master - - if s is None: - continue - s = str(int(s)) # convert 0000000024 -> 24 - - # report all processes when --all is specified - # otherwise only show nonzero sessions not known at the master - # - if not self.options.all: - if s == '0' or s in (self.options.sessionids or []): - continue - - self.orphans.append((e, s, str(p.pid), command.strip())) - - def return_orphan_details(self): - "" - for era, sessid, pid, command in self.orphans: - result = "|".join([ self.options.host, era, sessid, pid, command ]) - print result - - -if __name__ == '__main__': - GpDebugMain().simple() diff --git a/gpMgmt/bin/gppylib/commands/gp.py b/gpMgmt/bin/gppylib/commands/gp.py index 94517f5ce4bb552b99916db43394c678381829db..5dac5da568123f3fe20ed2d696b6f003d62397f7 100644 --- a/gpMgmt/bin/gppylib/commands/gp.py +++ b/gpMgmt/bin/gppylib/commands/gp.py @@ -275,7 +275,7 @@ class PgCtlStartArgs(CmdArgs): """ CmdArgs.__init__(self, [ - "env", # variables examined by gpdebug/etc + "env", "GPSESSID=0000000000", # <- overwritten with gp_session_id to help identify orphans "GPERA=%s" % str(era), # <- master era used to help identify orphans "$GPHOME/bin/pg_ctl", diff --git a/gpMgmt/bin/gpssh-exkeys b/gpMgmt/bin/gpssh-exkeys index 1b117b832eb0ee2dce5fc9919226e58a84231e46..51e589efb62325c888eed6c3526844b6ca079b8a 100755 --- a/gpMgmt/bin/gpssh-exkeys +++ b/gpMgmt/bin/gpssh-exkeys @@ -1,10 +1,10 @@ -#!/usr/bin/env python +#!/usr/bin/env python # -*- indent-tabs-mode: nil; tab-width:4 -*- # vim:set tabstop=4 expandtab: ''' gpssh-exkeys -- exchange ssh public keys among friends -Usage: gpssh-exkeys [--version] [-?v] +Usage: gpssh-exkeys [--version] [-?v] { -f hostfile | -h host ... | -e hostfile -x hostfile } @@ -16,19 +16,19 @@ Usage: gpssh-exkeys [--version] [-?v] -f hostfile : a file listing all new hosts to connect to -e hostfile : a file listing all existing hosts for expansion -x hostfile : a file listing all new hosts for expansion - + Each line in a hostfile is expected to contain a single host name. Blank lines and comment lines (beginning with #) are ignored. The name of the - local host (as provided by hostname) is included automatically and need not - be specified unless it is the only host to process. During cluster expansion, + local host (as provided by hostname) is included automatically and need not + be specified unless it is the only host to process. During cluster expansion, the local host is always considered an existing host and should not be specified - in the "new host" list. Duplicate host names in either the new host list (-h, - -f, -x options) or the existing host list (-e option) are ignored. The same host - name cannot appear in the both the new and existing host lists. Host names + in the "new host" list. Duplicate host names in either the new host list (-h, + -f, -x options) or the existing host list (-e option) are ignored. The same host + name cannot appear in the both the new and existing host lists. Host names including a user name or port (username@hostname:port) are not accepted. ''' -from __future__ import with_statement +from __future__ import with_statement import os, sys progname = os.path.split(sys.argv[0])[-1] @@ -98,7 +98,7 @@ def print_version(): sys.exit(0) -class Host: +class Host: def __init__(self, host, localhost=False): self.m_host = host self.m_popen = None @@ -107,17 +107,17 @@ class Host: self.m_isLocalhost = localhost self.m_inetAddrs = None self.m_inet6Addrs = None - + def __repr__(self): - return ('(%s, { "popen" : %s, "remoteId" : %s, "popen_cmd" : "%s" })' + return ('(%s, { "popen" : %s, "remoteId" : %s, "popen_cmd" : "%s" })' % (self.m_host, (True if self.m_popen else False), self.m_remoteID, self.m_popen_cmd)) def host(self): return self.m_host def remoteID(self): return self.m_remoteID def popen_cmd(self): return self.m_popen_cmd; def isPclosed(self): return self.m_popen == None; - - + + def getAddrs(self): ''' Gets the INET and INET6 addresses for this host. @@ -127,13 +127,13 @@ class Host: self.m_inet6Addrs = [] try: hostAddrs = socket.getaddrinfo(self.m_host, 0, socket.AF_UNSPEC, socket.SOCK_STREAM, socket.IPPROTO_TCP, 0) - + if self.m_isLocalhost: try: hostAddrs.extend(socket.getaddrinfo('localhost', 0, socket.AF_UNSPEC, socket.SOCK_STREAM, socket.IPPROTO_TCP, 0)) except: pass - + for (family, socktype, proto, canonname, sockaddr) in hostAddrs: if family == socket.AF_INET: (addr, port) = sockaddr @@ -145,24 +145,24 @@ class Host: pass self.m_inetAddrs = tuple(self.m_inetAddrs) self.m_inet6Addrs = tuple(self.m_inet6Addrs) - + return (self.m_inetAddrs, self.m_inet6Addrs) - - + + def isSameHost(self, host): ''' Compares with this host by published address ''' (thisInetAddrs, thisInet6Addrs) = self.getAddrs() (thatInetAddrs, thatInet6Addrs) = host.getAddrs() - + for addr in thisInetAddrs: if addr in thatInetAddrs: return True for addr in thisInet6Addrs: if addr in thatInet6Addrs: return True - + return False @@ -200,7 +200,7 @@ class Host: if pwd: ok = self.tryParamikoConnect(p, pwd) if ok: passwd.append(pwd) - # Create .ssh directory and ensure content meets permission requirements + # Create .ssh directory and ensure content meets permission requirements # for password-less SSH # # note: we touch .ssh/iddummy.pub just before the chmod operations to @@ -229,7 +229,7 @@ class Host: print ' ', line.rstrip() print cout.close(); cerr.close() - + # If tempDir is specified, obtain a copy of the ssh # files that should be preserved for existing hosts. if tempDir: @@ -237,7 +237,7 @@ class Host: if GV.opt['-v']: print '[INFO %s]: %s' % (self.m_host, cmd) (cin, cout, cerr) = p.exec_command(cmd) cin.close() - + # Grab the tar stream from stdout tarfile = open(os.path.join(tempDir, '%s.tar' % self.m_host), 'wb') buf = array.array('B') @@ -257,21 +257,21 @@ class Host: exitStatus = cout.channel.recv_exit_status() cout.close() if exitStatus != 0: - print >> sys.stderr, ('[WARNING %s] cannot fetch existing authentication files: tar rc=%s;' + print >> sys.stderr, ('[WARNING %s] cannot fetch existing authentication files: tar rc=%s;' % (self.m_host, exitStatus)) for line in cerr: print >> sys.stderr, ' ', line.rstrip() print >> sys.stderr, ' One or more existing authentication files may be replaced on %s' % self.m_host - + cerr.close() - + # The tar file content is expected to be extacted by the caller. Doing it # here causes Paramiko Transport grief on Linux systems. (The Event.wait() # used can be interrupted by the SIGCHLD signal popped by destruction of the # process spawned to run the tar command -- Paramiko isn't ready for that to # happen. - - # Append the ID to authorized_keys; this is *temporary* -- + + # Append the ID to authorized_keys; this is *temporary* -- # authorized_keys is expected to be replaced when the master # .ssh content is shipped to the host. cmd = 'echo \"%s\" >> .ssh/authorized_keys && echo ok ok ok' % ID @@ -286,9 +286,9 @@ class Host: print >> sys.stderr, ' ', line.rstrip() print >> sys.stderr cout.close(); cerr.close() - + return ok - + finally: if cin: cin.close() if cout: cout.close() @@ -298,7 +298,7 @@ class Host: def popen(self, cmd): 'Run a command and save popen handle in this Host instance.' - if self.m_popen: + if self.m_popen: self.m_popen.close() self.m_popen = None if GV.opt['-v']: print '[INFO %s]: %s' % (self.m_host, cmd) @@ -377,10 +377,10 @@ def createLocalID(): print >> sys.stderr, ' ' + line.rstrip() sys.exit(rc) - f = None; + f = None; try: - try: - f = open(GV.id_rsa_pub_fname, 'r'); + try: + f = open(GV.id_rsa_pub_fname, 'r'); return f.readline().strip() except IOError: sys.exit('[ERROR] ssh-keygen failed - unable to read the generated file ' + GV.id_rsa_pub_fname) @@ -421,7 +421,7 @@ def testAccess(hostname): for line in efile: print >> sys.stderr, ' ', line.rstrip() return False - + return True @@ -447,7 +447,7 @@ def readAuthorizedKeys(tab=None, keysFile=None): def writeAuthorizedKeys(tab, keysFile=None): if not keysFile: keysFile = GV.authorized_keys_fname f = None - try: + try: f = open(keysFile, 'w') for IDKey in tab: f.write(tab[IDKey]) finally: @@ -473,7 +473,7 @@ def readKnownHosts(tab=None, hostsFile=None): def writeKnownHosts(tab, hostsFile=None): if not hostsFile: hostsFile = GV.known_hosts_fname f = None - try: + try: f = open(hostsFile, 'w') for key in tab: f.write(tab[key]) finally: @@ -500,19 +500,11 @@ coverage = GpCoverage() coverage.start() try: - if os.environ.has_key('_GPDEBUG'): - debugLog = logging.StreamHandler() - debugLog.setLevel(logging.DEBUG) - debugLog.setFormatter(logging.Formatter("%(asctime)s - %(name)s - %(module)s:%(funcName)s:%(lineno)d - %(levelname)s - %(message)s")) - paramiko_logger = logging.getLogger('paramiko.transport') - paramiko_logger.addHandler(debugLog) - paramiko_logger.setLevel(logging.DEBUG) - else: - nullFile = logging.FileHandler('/dev/null') - logging.getLogger('paramiko.transport').addHandler(nullFile) + nullFile = logging.FileHandler('/dev/null') + logging.getLogger('paramiko.transport').addHandler(nullFile) parseCommandLine() - + # Assemble a list of names used by the current host. SSH is sensitive to both name # and address so recognizing each name can prevent an SSH authenticitiy challenge. # @@ -531,13 +523,13 @@ try: for alias in aliases: addHost(alias, localhosts, True) localhosts = tuple(localhosts) - + # hostlist is the collection of "new" hosts; it is composed of hosts # identified by the -h or -f options for initial exchange processing # or by the -x option for expansion processing. (Only one of the -h, # -f, or -x options is expected to have values.) hostlist = ssh_utils.HostList() - + if len(GV.opt['-h']): for h in GV.opt['-h']: try: @@ -567,11 +559,11 @@ try: break else: GV.newHosts.append(host) - + if not GV.newHosts: print >> sys.stderr, '[ERROR] no valid new hosts specified; at least one new host must be specified for key exchange' sys.exit(1) - + GV.allHosts.extend( GV.newHosts ) # hostlist is now used for the collection of existing hosts. @@ -579,9 +571,9 @@ try: # for new hosts.) localhostInOld = False hostlist = ssh_utils.HostList() - if GV.opt['-e']: + if GV.opt['-e']: collectHosts(hostlist, GV.opt['-e']) - + for host in hostlist.get(): host = Host(host) for localhost in localhosts: @@ -594,13 +586,13 @@ try: break else: GV.existingHosts.append(host) - + if not GV.existingHosts: print >> sys.stderr, '[ERROR] no valid existing hosts specified; at least one existing host must be specified for expansion' sys.exit(1) GV.allHosts.extend( GV.existingHosts ) - + # Ensure there's no overlap between the new and existing hosts haveError = False for existingHost in GV.existingHosts: @@ -611,7 +603,7 @@ try: break if haveError: sys.exit(1) - + # Ensure the local host is in the "proper" host list -- old for expansion, new otherwise if GV.opt['-e']: if localhostInOld: @@ -636,9 +628,9 @@ try: tempDir = tempfile.mkdtemp('.tmp', 'gp_', os.path.expanduser('~')) else: tempDir = tempfile.mkdtemp() - if GV.opt['-v'] or os.environ.has_key('KEEPTEMP'): + if GV.opt['-v'] or os.environ.has_key('KEEPTEMP'): print '[INFO] tempDir=%s' % tempDir - + discovered_authorized_keys_file = os.path.join(tempDir, 'authorized_keys') ###################### @@ -650,7 +642,7 @@ try: print '[STEP 1 of 5] create local ID and authorize on local host' localID = createLocalID() authorizeLocalID(localID) - + # Ensure the local host's .ssh directory is prepared for password-less SSH login # # note: we touch .ssh/iddummy.pub just before the chmod operations to @@ -665,7 +657,7 @@ try: 'chmod 0644 .ssh/id*.pub .ssh/config') if GV.opt['-v']: print '[INFO]: %s' % cmd os.system(cmd) - + # Ensure the host key(s) for the local host are in known_hosts. Using ssh-keyscan # takes care of part of it; testAccess takes care of the rest. errfile = os.path.join(tempDir, "keyscan.err") @@ -706,7 +698,7 @@ try: if rc != 0: # If ssh-keyscan failed, it's typically because the host doesn't exist; # remove the host from further processing and inform the user - print >> sys.stderr, ('[ERROR] error %s obtaining RSA host key for %s host %s' + print >> sys.stderr, ('[ERROR] error %s obtaining RSA host key for %s host %s' % (rc, 'existing' if h in GV.existingHosts else 'new', h.host())) @@ -723,11 +715,11 @@ try: ###################### # step 3 # - # Temporarily append the localID to the authorized_keys file of + # Temporarily append the localID to the authorized_keys file of # each host to allow password-less SSH. This is a temporary measure -- # the authorized_keys file on each host is replaced in a later step. # - # This step also obtains a copy of any existing authorized_keys, + # This step also obtains a copy of any existing authorized_keys, # known_hosts, and id_rsa.pub files for existing hosts so they # may be updated rather than replaced (as is done for new hosts). # @@ -751,8 +743,8 @@ try: send_local_id = h.sendLocalID(localID, GV.passwd, tempDir if isExistingHost else None) except socket.error, e: errmsg = '[ERROR %s] %s' % (h.host(), e) - print >> sys.stderr, errmsg - if not send_local_id: + print >> sys.stderr, errmsg + if not send_local_id: errmsg = '[ERROR %s] skipping key exchange for %s' % (h.host(), h.host()) print >> sys.stderr, errmsg errmsg = '[ERROR %s] unable to authorize current user' % h.host() @@ -783,7 +775,7 @@ try: for line in hostPub: newKeys.write(line) newKeys.flush() - + # Ensure the proper password-less access to the remote host. if not testAccess(h.host()): errmsg = '*' # message already issued @@ -797,19 +789,19 @@ try: ###################### # step 4 # - # At this point, - # (1) the local known_hosts file has at least one + # At this point, + # (1) the local known_hosts file has at least one # host key for each new and existing host. # (2) the local authorized_keys file has an entry # for the current user on the local system AND # the public key from the current user on every # existing host. - # (3) a copy of any existing authorized_keys, known_hosts, - # and id_rsa.pub file from each existing host file, + # (3) a copy of any existing authorized_keys, known_hosts, + # and id_rsa.pub file from each existing host file, # exists in the / directory. # # Determine SSH authentication file content for each host. - # For new hosts, the authorized_keys, known_hosts, and + # For new hosts, the authorized_keys, known_hosts, and # id_rsa{,.pub} files are copied from this host. For # existing hosts, the existing authorized_keys and known_hosts # files from the existing host is merged with the files from @@ -833,7 +825,7 @@ try: if os.path.exists(discovered_authorized_keys_file): print ' ... merging discovered remote IDs into local authorized_keys' tab = readAuthorizedKeys(tab, discovered_authorized_keys_file) - except IOError: + except IOError: sys.exit('[ERROR] cannot read authorized_keys file') try: @@ -854,7 +846,7 @@ try: # print; print '[STEP 5 of 5] copy authentication files to all remote hosts' errmsg = None - + try: # MPP-13617 @@ -864,21 +856,21 @@ try: for h in GV.newHosts: - cmd = ('scp -q -o "BatchMode yes" -o "NumberOfPasswordPrompts 0" ' + - '%s %s %s %s %s:.ssh/ 2>&1' - % (GV.authorized_keys_fname, - GV.known_hosts_fname, - GV.id_rsa_fname, - GV.id_rsa_pub_fname, + cmd = ('scp -q -o "BatchMode yes" -o "NumberOfPasswordPrompts 0" ' + + '%s %s %s %s %s:.ssh/ 2>&1' + % (GV.authorized_keys_fname, + GV.known_hosts_fname, + GV.id_rsa_fname, + GV.id_rsa_pub_fname, canonicalize( h.host() ))) h.popen(cmd) - + if len(GV.existingHosts): localAuthKeys = readAuthorizedKeys() localKnownHosts = readKnownHosts() - + for h in GV.existingHosts: - + remoteAuthKeysFile = os.path.join(tempDir, h.host(), 'authorized_keys') if os.path.exists(remoteAuthKeysFile) and os.path.getsize(remoteAuthKeysFile): if GV.opt['-v']: print ' ... merging authorized_keys for %s' % h.host() @@ -886,7 +878,7 @@ try: writeAuthorizedKeys(remoteAuthKeys, remoteAuthKeysFile) else: remoteAuthKeysFile = GV.authorized_keys_fname - + remoteKnownHostsFile = os.path.join(tempDir, h.host(), 'known_hosts') if os.path.exists(remoteKnownHostsFile) and os.path.getsize(remoteKnownHostsFile): if GV.opt['-v']: print ' ... merging known_hosts for %s' % h.host() @@ -894,7 +886,7 @@ try: writeKnownHosts(remoteKnownHosts, remoteKnownHostsFile) else: remoteKnownHostsFile = GV.known_hosts_fname - + remoteIdentityPubFile = os.path.join(tempDir, h.host(), 'id_rsa.pub') if os.path.exists(remoteIdentityPubFile): if not filecmp.cmp(GV.id_rsa_pub_fname, remoteIdentityPubFile): @@ -904,33 +896,33 @@ try: else: remoteIdentity = GV.id_rsa_fname remoteIdentityPub = GV.id_rsa_pub_fname - + cmd = ('scp -q -o "BatchMode yes" -o "NumberOfPasswordPrompts 0" ' + - '%s %s %s %s %s:.ssh/ 2>&1' - % (remoteAuthKeysFile, - remoteKnownHostsFile, - remoteIdentity, - remoteIdentityPub, + '%s %s %s %s %s:.ssh/ 2>&1' + % (remoteAuthKeysFile, + remoteKnownHostsFile, + remoteIdentity, + remoteIdentityPub, canonicalize( h.host() ))) h.popen(cmd) - + except: errmsg = '[ERROR] cannot complete key exchange: %s' % sys.exc_info()[0] print >> sys.stderr, errmsg raise - + finally: for h in GV.allHosts: if not h.isPclosed(): (ok, content) = h.pclose() - if ok: + if ok: print ' ... finished key exchange with', h.host() else: errmsg = "[ERROR] unable to copy authentication files to %s" % h.host() print >> sys.stderr, errmsg for line in content.splitlines(): print >> sys.stderr, ' ', line - + if errmsg: sys.exit(1) print; print '[INFO] completed successfully' @@ -940,7 +932,7 @@ except KeyboardInterrupt: sys.exit('\n\nInterrupted...') finally: - # Discard the temporary working directory (borrowed from Python + # Discard the temporary working directory (borrowed from Python # doc for os.walk). if tempDir and not os.environ.has_key('KEEPTEMP'): if GV.opt['-v']: print '[INFO] deleting tempDir %s' % tempDir @@ -950,7 +942,7 @@ finally: for name in dirs: os.rmdir(os.path.join(root, name)) os.rmdir(tempDir) - + coverage.stop() coverage.generate_report()