Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # This module contains class that represents a host reachable by SSH.
- import paramiko
- import platform
- import os
- import sys
- import select
- import re
- import socket
- import time
- sys.path.insert(0, '/xyz')
- from logger import Logger
- LOG = Logger(__name__)
- class RemoteClient(object):
- # Representation of a host reachable by SSH
- def __init__(self, host_ip, user, password=None, ilom=False, pki=False):
- '''
- :param host_ip: IP address of host
- :param user: Username of user to login with
- :param password: Password of user to login with
- '''
- self.host_ip = host_ip
- self.user = user
- self.password = password
- self.client = None
- self.last_exit_status = None
- self.pki = pki
- def _set_client(self):
- self.client = paramiko.SSHClient()
- self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
- LOG.debug("remote client:%s, username:%s, password:%s"
- % (self.host_ip, self.user, self.password))
- if self.pki:
- privatekeyfile = os.path.expanduser('~/.ssh/id_rsa')
- mykey = paramiko.RSAKey.from_private_key_file(privatekeyfile)
- self.client.connect(self.host_ip, username=self.user, pkey=mykey)
- else:
- self.client.connect(self.host_ip, username=self.user,
- password=self.password)
- def run_as_sudo(self, cmd, verify=False):
- if not self.client:
- self._set_client()
- if self.user != "root":
- command = "sudo -S -p '' %s" % cmd
- stdin, stdout, stderr = self.client.exec_command(command)
- stdin.write(self.password + "\n")
- stdin.flush()
- self.last_exit_status = stdout.channel.recv_exit_status()
- for line in stdout:
- LOG.debug('[%s] out: %s' % (self.host_ip, line.rstrip()))
- else:
- self.run(cmd, capture=True, verify=verify)
- return
- if verify:
- self._verify_exit_status(cmd, stdout.readlines())
- def myexec(self, cmd, timeout=60, want_exitcode=False):
- # one channel per command
- stdin, stdout, stderr = self.client.exec_command(cmd)
- # get the shared channel for stdout/stderr/stdin
- channel = stdout.channel
- # we do not need stdin.
- stdin.close()
- # indicate that we're not going to write to that channel anymore
- channel.shutdown_write()
- # read stdout/stderr in order to prevent read block hangs
- stdout_chunks = []
- stdout_chunks.append(stdout.channel.recv(len(stdout.channel.in_buffer)))
- # chunked read to prevent stalls
- while not channel.closed or channel.recv_ready() or channel.recv_stderr_ready():
- # while not channel.closed or channel.recv_stderr_ready():
- # stop if channel was closed prematurely, and there is no data in the buffers.
- got_chunk = False
- readq, _, _ = select.select([stdout.channel], [], [], timeout)
- for c in readq:
- if c.recv_ready():
- stdout_chunks.append(stdout.channel.recv(len(c.in_buffer)))
- got_chunk = True
- if c.recv_stderr_ready():
- # make sure to read stderr to prevent stall
- stderr.channel.recv_stderr(len(c.in_stderr_buffer))
- got_chunk = True
- '''
- 1) make sure that there are at least 2 cycles with no data in the input buffers in order to not exit too early (i.e. cat on a >200k file).
- 2) if no data arrived in the last loop, check if we already received the exit code
- 3) check if input buffers are empty
- 4) exit the loop
- '''
- if not got_chunk \
- and stdout.channel.exit_status_ready() \
- and not stderr.channel.recv_stderr_ready() \
- and not stdout.channel.recv_ready():
- # indicate that we're not going to read from this channel anymore
- stdout.channel.shutdown_read()
- # close the channel
- stdout.channel.close()
- break # exit as remote side is finished and our bufferes are empty
- # close all the pseudofiles
- stdout.close()
- stderr.close()
- if want_exitcode:
- # exit code is always ready at this point
- print (''.join(stdout_chunks), stdout.channel.recv_exit_status())
- print ''.join(stdout_chunks)
- def _verify_exit_status(self, cmd, output):
- """This checks if the cmd sent was successful if not
- this method will throw an error
- """
- if self.last_exit_status == 0:
- LOG.info("Successfully executed: %s \n output: %s"
- % (cmd, output))
- else:
- raise Exception("Bad exit status \nexecuted cmd: "
- "%s\n output: %s" % (cmd, output))
- def run13(self, capture=True, verify=False):
- if not self.client:
- self._set_client()
- self.client.exec_command('. .profile ; echo $EVRHOME')
- def run(self, cmd, capture=True, verify=False):
- if not self.client:
- self._set_client()
- channel = self.client.invoke_shell()
- channel.send(cmd + '\n')
- def has_newline(bytelist):
- return '\r' in bytelist or '\n' in bytelist
- buffer_ = []
- r, w, e = select.select([channel], [], [])
- while not channel.exit_status_ready():
- try:
- console_data = ""
- while channel.recv_ready():
- console_data += channel.recv(4096)
- if len(console_data) == 0:
- break
- buffer_.append(console_data)
- print console_data
- time.sleep(3)
- # Search console_data for console prompt
- # If found, we dont need to read data anymore
- if re.search("[' ']FAILED[' ']", console_data):
- raise Exception("PCU failed")
- elif re.search("]#[' ']$", console_data):
- break
- except socket.timeout:
- raise Exception("Failed to read infro node output socket timeout")
- output = ''.join(buffer_)
- #if verify:
- # self._verify_exit_status(cmd, output)
- return output
- def run4(self, cmd, capture=True, verify=False):
- if not self.client:
- self._set_client()
- channel = self.client.invoke_shell()
- stdin, stdout, stderr = self.client.exec_command(cmd)
- self.last_exit_status = stdout.channel.recv_exit_status()
- buffer_ = []
- while True:
- r, w, e = select.select([channel], [], [])
- try:
- console_data = ""
- while channel.recv_ready():
- console_data += channel.recv(1024)
- if len(console_data) == 0:
- break
- # Search console_data for console prompt
- # If found, we dont need to read data anymore
- buffer_.append(console_data)
- if not channel.recv_ready():
- break
- except socket.timeout:
- raise Exception("Failed to read ilom output socket timeout")
- output = ''.join(buffer_)
- if verify:
- self._verify_exit_status(cmd, output)
- return output
- def run3(self, cmd):
- if not self.client:
- self._set_client()
- stdin, stdout, stderr = self.client.exec_command(cmd)
- while not stdout.channel.exit_status_ready():
- # Only print data if there is data to read in the channel
- if stdout.channel.recv_ready():
- rl, wl, xl = select.select([stdout.channel], [], [], 0.0)
- if len(rl) > 0:
- # Print data from stdout
- print stdout.channel.recv(1024)
- print "Command done, closing SSH connection"
- self.client.close()
- def run10(self, cmd):
- if not self.client:
- self._set_client()
- stdin, stdout, stderr = self.client.exec_command(cmd)
- stdin.close()
- print "output of run10 command is: " , repr(stdout.read())
- output = repr(stdout.read())
- stdout.close()
- stderr.close()
- self.client.close()
- return output
- def run2(self, cmd, capture=True, verify=False):
- ''' Run a command on the host and return its output
- :param cmd: Command to run on host
- :param capture: Whether to save and return output from command run
- :param verify: Will verify and throw exception if command failed
- :return: output
- '''
- if not self.client:
- self._set_client()
- transport = self.client.get_transport()
- channel = transport.open_session()
- channel.set_combine_stderr(True)
- LOG.debug('[%s] run: %s' % (self.host_ip, cmd))
- channel.exec_command(cmd)
- buffer_ = [] # This should probably be a limited-length buffer
- line = []
- seen_cr = False
- def flush(text):
- LOG.debug('[%s] out: %s' % (self.host_ip, text.rstrip()))
- def has_newline(bytelist):
- return '\r' in bytelist or '\n' in bytelist
- while True:
- bytelist = channel.recv(512)
- if capture:
- buffer_.append(bytelist)
- # empty byte signifies EOS
- if bytelist == '':
- if line:
- flush(''.join(line))
- break
- if bytelist[-1] == '\r':
- seen_cr = True
- if bytelist[0] == '\n' and seen_cr:
- bytelist = bytelist[1:]
- seen_cr = False
- while has_newline(bytelist) and bytelist != '':
- # at most 1 split !
- cr = re.search('(\r\n|\r|\n)', bytelist)
- if cr is None:
- break
- end_of_line = bytelist[:cr.start(0)]
- bytelist = bytelist[cr.end(0):]
- if has_newline(end_of_line):
- end_of_line = ''
- flush(''.join(line) + end_of_line + '\n')
- line = []
- line += [bytelist]
- self.last_exit_status = channel.recv_exit_status()
- output = ''.join(buffer_)
- if verify:
- self._verify_exit_status(cmd, output)
- return output
- def check_if_host_reachable(netaddr):
- """Sends a single ICMP packet to check if host is reachable. Blocks all
- execution in current thread."""
- # Maximum time to wait for ping reply (in seconds)
- max_wait = 5
- # On Mac, ping -W flag is specified in milliseconds
- if platform.system() == 'Darwin':
- max_wait = max_wait * 1000
- return_code, output = utils.local('ping -c1 -W%s %s' % (max_wait, netaddr))
- if 'ttl=' not in output:
- raise Exception("Host %s did not respond within %s ms" % (netaddr,
- max_wait))
- LOG.info("Host: %s is alive output: %s" % (netaddr, output))
Add Comment
Please, Sign In to add comment