Guest User

Untitled

a guest
Dec 21st, 2017
123
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.67 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. import paramiko
  4. from paramiko.ssh_exception import SSHException
  5. import threading
  6. import select
  7. import time
  8. import logging
  9. import re
  10. import os
  11.  
  12. SSH_PORT = 22
  13. SSH_CONNECT_TIMEOUT = 60
  14. SSH_COMMAND_TIMEOUT = 60
  15. SSH_HEARTBEAT_COMMAND = 'sleep 10'
  16. SSH_HEARTBEAT_COMMAND_TIMEOUT = 5
  17. SSH_HEARTBEAT_INTERVAL = 5
  18.  
  19.  
  20. LOG = logging.getLogger()
  21. LOG_FILE = re.sub(r'\.py$', r'.log', os.path.basename(__file__))
  22.  
  23.  
  24. class Heartbeat(threading.Thread):
  25. def __init__(self, interval, function, args=None, kwargs=None):
  26. threading.Thread.__init__(self, name='Thread-heartbeat')
  27. self.interval = interval
  28. self.function = function
  29. if args is None:
  30. self.args = []
  31. else:
  32. self.args = args
  33. if kwargs is None:
  34. self.kwargs = {}
  35. else:
  36. self.kwargs = kwargs
  37. self.finished = threading.Event()
  38.  
  39. def cancel(self):
  40. self.finished.set()
  41.  
  42. def run(self):
  43. LOG.info('%s starting', self.name)
  44. while not self.finished.wait(self.interval):
  45. self.function(*self.args, **self.kwargs)
  46. LOG.info('%s exiting', self.name)
  47.  
  48.  
  49. class AutoBotCmd(object):
  50. def __init__(
  51. self,
  52. hostname,
  53. username,
  54. password,
  55. port=SSH_PORT,
  56. timeout=SSH_CONNECT_TIMEOUT,
  57. heartbeat_interval=SSH_HEARTBEAT_INTERVAL):
  58. self.hostname = hostname
  59. self.username = username
  60. self.password = password
  61. self.port = port
  62. self.timeout = timeout
  63. self._client = paramiko.SSHClient()
  64. self._client.load_system_host_keys()
  65. self._client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  66. self._heartbeat = None
  67. self._heartbeat_interval = heartbeat_interval
  68.  
  69. def connect(self):
  70. self._client.connect(hostname=self.hostname, port=self.port)
  71.  
  72. def keep_alive(self):
  73. if self._heartbeat is not None:
  74. self._heartbeat.cancel()
  75. self._heartbeat.join()
  76. self._heartbeat = Heartbeat(
  77. self._heartbeat_interval,
  78. self._exec_heartbeat)
  79. self._heartbeat.start()
  80.  
  81. def close(self):
  82. if self._heartbeat is not None:
  83. self._heartbeat.cancel()
  84. self._heartbeat.join()
  85. if self._client.get_transport() is not None:
  86. self._client.close()
  87.  
  88. def exec_command(
  89. self,
  90. command,
  91. combine_stderr=False,
  92. timeout=SSH_COMMAND_TIMEOUT):
  93. stdin, stdout, _ = self._client.exec_command(command)
  94. stdin.close()
  95. channel = stdout.channel
  96. if combine_stderr:
  97. channel.set_combine_stderr(True)
  98. elapsed = 0
  99. all_stdout = ''
  100. all_stderr = ''
  101. select_timeout = 1
  102. while not channel.exit_status_ready():
  103. rlist, _, _ = select.select([channel], [], [], select_timeout)
  104. if rlist:
  105. elapsed = 0
  106. while channel.recv_ready():
  107. all_stdout += channel.recv(1024)
  108. while channel.recv_stderr_ready():
  109. all_stderr += channel.recv_stderr(1024)
  110. else:
  111. elapsed += select_timeout
  112. if elapsed > timeout:
  113. channel.close()
  114. raise RuntimeError('Command execution timed out')
  115. LOG.debug(
  116. 'Command: %s, elapsed: %d, rlist: %s',
  117. command,
  118. elapsed,
  119. rlist)
  120. status = channel.recv_exit_status()
  121. while channel.recv_ready():
  122. all_stdout += channel.recv(1024)
  123. while channel.recv_stderr_ready():
  124. all_stderr += channel.recv_stderr(1024)
  125. return all_stdout, all_stderr, status
  126.  
  127. def _send_heartbeat(self):
  128. try:
  129. LOG.info('Sending heartbeat...')
  130. _, _, status = self.exec_command(
  131. SSH_HEARTBEAT_COMMAND, timeout=SSH_HEARTBEAT_COMMAND_TIMEOUT)
  132. except Exception as ex:
  133. LOG.error('Sending heartbeat...error, exception: %s', ex)
  134. return False
  135. if status != 0:
  136. return False
  137. return True
  138.  
  139. def _exec_heartbeat(self):
  140. if self._send_heartbeat():
  141. LOG.info('Sending heartbeat...done')
  142. return
  143. # Heartbeat failed
  144. if self._client.get_transport() is not None:
  145. self._client.close()
  146. LOG.info('Re-connecting...')
  147. try:
  148. self.connect()
  149. except SSHException as ex:
  150. LOG.error('Re-connecting...error, exception: %s', ex)
  151. self.close()
  152. return
  153. LOG.info('Re-connecting...done')
  154.  
  155.  
  156. def _config_logging(verbose=False):
  157. LOG.setLevel(logging.DEBUG)
  158. file_hdl = logging.FileHandler(LOG_FILE)
  159. file_hdl.setFormatter(logging.Formatter(
  160. '%(asctime)s - %(funcName)s:%(lineno)d - %(levelname)s - %(message)s'))
  161. file_hdl.setLevel(logging.DEBUG)
  162. cons_hdl = logging.StreamHandler()
  163. cons_hdl.setFormatter(logging.Formatter(
  164. '%(asctime)s - %(levelname)s - %(message)s'))
  165. if verbose:
  166. cons_hdl.setLevel(logging.DEBUG)
  167. else:
  168. cons_hdl.setLevel(logging.INFO)
  169. LOG.addHandler(file_hdl)
  170. LOG.addHandler(cons_hdl)
  171.  
  172.  
  173. def test():
  174. a = AutoBotCmd('localhost', 'yuezhu', 'm@cPasswd')
  175. a.connect()
  176. a.keep_alive()
  177. stdout, stderr, status = a.exec_command('echo abc')
  178. LOG.info('\nstdout: %s\nstderr: %s\nstatus: %d', stdout, stderr, status)
  179. stdout, stderr, status = a.exec_command('hostname')
  180. LOG.info('\nstdout: %s\nstderr: %s\nstatus: %d', stdout, stderr, status)
  181. time.sleep(30)
  182. a.close()
  183.  
  184.  
  185. if __name__ == '__main__':
  186. _config_logging(False)
  187. test()
Add Comment
Please, Sign In to add comment