Guest User

Untitled

a guest
Jul 13th, 2018
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.99 KB | None | 0 0
  1. # This module contains class that represents a host reachable by SSH.
  2.  
  3. import paramiko
  4. import platform
  5. import os
  6. import sys
  7. import select
  8. import re
  9. import socket
  10. import time
  11. sys.path.insert(0, '/xyz')
  12. from logger import Logger
  13. LOG = Logger(__name__)
  14.  
  15. class RemoteClient(object):
  16. # Representation of a host reachable by SSH
  17.  
  18. def __init__(self, host_ip, user, password=None, ilom=False, pki=False):
  19. '''
  20. :param host_ip: IP address of host
  21. :param user: Username of user to login with
  22. :param password: Password of user to login with
  23. '''
  24.  
  25. self.host_ip = host_ip
  26. self.user = user
  27. self.password = password
  28. self.client = None
  29. self.last_exit_status = None
  30. self.pki = pki
  31.  
  32. def _set_client(self):
  33. self.client = paramiko.SSHClient()
  34. self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  35.  
  36. LOG.debug("remote client:%s, username:%s, password:%s"
  37. % (self.host_ip, self.user, self.password))
  38.  
  39. if self.pki:
  40. privatekeyfile = os.path.expanduser('~/.ssh/id_rsa')
  41. mykey = paramiko.RSAKey.from_private_key_file(privatekeyfile)
  42. self.client.connect(self.host_ip, username=self.user, pkey=mykey)
  43. else:
  44. self.client.connect(self.host_ip, username=self.user,
  45. password=self.password)
  46.  
  47.  
  48. def run_as_sudo(self, cmd, verify=False):
  49. if not self.client:
  50. self._set_client()
  51.  
  52. if self.user != "root":
  53. command = "sudo -S -p '' %s" % cmd
  54. stdin, stdout, stderr = self.client.exec_command(command)
  55. stdin.write(self.password + "\n")
  56. stdin.flush()
  57. self.last_exit_status = stdout.channel.recv_exit_status()
  58.  
  59. for line in stdout:
  60. LOG.debug('[%s] out: %s' % (self.host_ip, line.rstrip()))
  61. else:
  62. self.run(cmd, capture=True, verify=verify)
  63. return
  64. if verify:
  65. self._verify_exit_status(cmd, stdout.readlines())
  66.  
  67. def myexec(self, cmd, timeout=60, want_exitcode=False):
  68. # one channel per command
  69. stdin, stdout, stderr = self.client.exec_command(cmd)
  70. # get the shared channel for stdout/stderr/stdin
  71. channel = stdout.channel
  72. # we do not need stdin.
  73. stdin.close()
  74. # indicate that we're not going to write to that channel anymore
  75. channel.shutdown_write()
  76.  
  77. # read stdout/stderr in order to prevent read block hangs
  78. stdout_chunks = []
  79. stdout_chunks.append(stdout.channel.recv(len(stdout.channel.in_buffer)))
  80. # chunked read to prevent stalls
  81. while not channel.closed or channel.recv_ready() or channel.recv_stderr_ready():
  82. # while not channel.closed or channel.recv_stderr_ready():
  83. # stop if channel was closed prematurely, and there is no data in the buffers.
  84. got_chunk = False
  85. readq, _, _ = select.select([stdout.channel], [], [], timeout)
  86. for c in readq:
  87. if c.recv_ready():
  88. stdout_chunks.append(stdout.channel.recv(len(c.in_buffer)))
  89. got_chunk = True
  90. if c.recv_stderr_ready():
  91. # make sure to read stderr to prevent stall
  92. stderr.channel.recv_stderr(len(c.in_stderr_buffer))
  93. got_chunk = True
  94. '''
  95. 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).
  96. 2) if no data arrived in the last loop, check if we already received the exit code
  97. 3) check if input buffers are empty
  98. 4) exit the loop
  99. '''
  100. if not got_chunk \
  101. and stdout.channel.exit_status_ready() \
  102. and not stderr.channel.recv_stderr_ready() \
  103. and not stdout.channel.recv_ready():
  104. # indicate that we're not going to read from this channel anymore
  105. stdout.channel.shutdown_read()
  106. # close the channel
  107. stdout.channel.close()
  108. break # exit as remote side is finished and our bufferes are empty
  109.  
  110. # close all the pseudofiles
  111. stdout.close()
  112. stderr.close()
  113.  
  114. if want_exitcode:
  115. # exit code is always ready at this point
  116. print (''.join(stdout_chunks), stdout.channel.recv_exit_status())
  117. print ''.join(stdout_chunks)
  118.  
  119. def _verify_exit_status(self, cmd, output):
  120. """This checks if the cmd sent was successful if not
  121. this method will throw an error
  122. """
  123. if self.last_exit_status == 0:
  124. LOG.info("Successfully executed: %s \n output: %s"
  125. % (cmd, output))
  126. else:
  127. raise Exception("Bad exit status \nexecuted cmd: "
  128. "%s\n output: %s" % (cmd, output))
  129.  
  130. def run13(self, capture=True, verify=False):
  131. if not self.client:
  132. self._set_client()
  133.  
  134. self.client.exec_command('. .profile ; echo $EVRHOME')
  135.  
  136.  
  137. def run(self, cmd, capture=True, verify=False):
  138. if not self.client:
  139. self._set_client()
  140.  
  141. channel = self.client.invoke_shell()
  142. channel.send(cmd + '\n')
  143.  
  144. def has_newline(bytelist):
  145. return '\r' in bytelist or '\n' in bytelist
  146.  
  147. buffer_ = []
  148. r, w, e = select.select([channel], [], [])
  149. while not channel.exit_status_ready():
  150. try:
  151. console_data = ""
  152. while channel.recv_ready():
  153. console_data += channel.recv(4096)
  154. if len(console_data) == 0:
  155. break
  156. buffer_.append(console_data)
  157. print console_data
  158. time.sleep(3)
  159. # Search console_data for console prompt
  160. # If found, we dont need to read data anymore
  161. if re.search("[' ']FAILED[' ']", console_data):
  162. raise Exception("PCU failed")
  163. elif re.search("]#[' ']$", console_data):
  164. break
  165. except socket.timeout:
  166. raise Exception("Failed to read infro node output socket timeout")
  167.  
  168. output = ''.join(buffer_)
  169.  
  170. #if verify:
  171. # self._verify_exit_status(cmd, output)
  172. return output
  173.  
  174. def run4(self, cmd, capture=True, verify=False):
  175. if not self.client:
  176. self._set_client()
  177. channel = self.client.invoke_shell()
  178. stdin, stdout, stderr = self.client.exec_command(cmd)
  179. self.last_exit_status = stdout.channel.recv_exit_status()
  180. buffer_ = []
  181. while True:
  182. r, w, e = select.select([channel], [], [])
  183. try:
  184. console_data = ""
  185. while channel.recv_ready():
  186. console_data += channel.recv(1024)
  187. if len(console_data) == 0:
  188. break
  189. # Search console_data for console prompt
  190. # If found, we dont need to read data anymore
  191. buffer_.append(console_data)
  192. if not channel.recv_ready():
  193. break
  194. except socket.timeout:
  195. raise Exception("Failed to read ilom output socket timeout")
  196.  
  197. output = ''.join(buffer_)
  198.  
  199. if verify:
  200. self._verify_exit_status(cmd, output)
  201. return output
  202.  
  203. def run3(self, cmd):
  204. if not self.client:
  205. self._set_client()
  206. stdin, stdout, stderr = self.client.exec_command(cmd)
  207. while not stdout.channel.exit_status_ready():
  208. # Only print data if there is data to read in the channel
  209. if stdout.channel.recv_ready():
  210. rl, wl, xl = select.select([stdout.channel], [], [], 0.0)
  211. if len(rl) > 0:
  212. # Print data from stdout
  213. print stdout.channel.recv(1024)
  214. print "Command done, closing SSH connection"
  215. self.client.close()
  216.  
  217. def run10(self, cmd):
  218. if not self.client:
  219. self._set_client()
  220. stdin, stdout, stderr = self.client.exec_command(cmd)
  221. stdin.close()
  222. print "output of run10 command is: " , repr(stdout.read())
  223. output = repr(stdout.read())
  224. stdout.close()
  225. stderr.close()
  226. self.client.close()
  227. return output
  228.  
  229. def run2(self, cmd, capture=True, verify=False):
  230. ''' Run a command on the host and return its output
  231. :param cmd: Command to run on host
  232. :param capture: Whether to save and return output from command run
  233. :param verify: Will verify and throw exception if command failed
  234. :return: output
  235. '''
  236. if not self.client:
  237. self._set_client()
  238. transport = self.client.get_transport()
  239. channel = transport.open_session()
  240. channel.set_combine_stderr(True)
  241.  
  242. LOG.debug('[%s] run: %s' % (self.host_ip, cmd))
  243. channel.exec_command(cmd)
  244.  
  245. buffer_ = [] # This should probably be a limited-length buffer
  246. line = []
  247. seen_cr = False
  248.  
  249. def flush(text):
  250. LOG.debug('[%s] out: %s' % (self.host_ip, text.rstrip()))
  251.  
  252. def has_newline(bytelist):
  253. return '\r' in bytelist or '\n' in bytelist
  254.  
  255. while True:
  256. bytelist = channel.recv(512)
  257. if capture:
  258. buffer_.append(bytelist)
  259.  
  260. # empty byte signifies EOS
  261. if bytelist == '':
  262. if line:
  263. flush(''.join(line))
  264. break
  265.  
  266. if bytelist[-1] == '\r':
  267. seen_cr = True
  268.  
  269. if bytelist[0] == '\n' and seen_cr:
  270. bytelist = bytelist[1:]
  271. seen_cr = False
  272.  
  273. while has_newline(bytelist) and bytelist != '':
  274. # at most 1 split !
  275. cr = re.search('(\r\n|\r|\n)', bytelist)
  276. if cr is None:
  277. break
  278. end_of_line = bytelist[:cr.start(0)]
  279. bytelist = bytelist[cr.end(0):]
  280.  
  281. if has_newline(end_of_line):
  282. end_of_line = ''
  283.  
  284. flush(''.join(line) + end_of_line + '\n')
  285. line = []
  286.  
  287. line += [bytelist]
  288. self.last_exit_status = channel.recv_exit_status()
  289. output = ''.join(buffer_)
  290. if verify:
  291. self._verify_exit_status(cmd, output)
  292. return output
  293.  
  294. def check_if_host_reachable(netaddr):
  295. """Sends a single ICMP packet to check if host is reachable. Blocks all
  296. execution in current thread."""
  297. # Maximum time to wait for ping reply (in seconds)
  298. max_wait = 5
  299. # On Mac, ping -W flag is specified in milliseconds
  300. if platform.system() == 'Darwin':
  301. max_wait = max_wait * 1000
  302.  
  303. return_code, output = utils.local('ping -c1 -W%s %s' % (max_wait, netaddr))
  304. if 'ttl=' not in output:
  305. raise Exception("Host %s did not respond within %s ms" % (netaddr,
  306. max_wait))
  307. LOG.info("Host: %s is alive output: %s" % (netaddr, output))
Add Comment
Please, Sign In to add comment