waller.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # @Author: wushuiyong
  4. # @Created Time : 日 1/ 1 23:43:12 2017
  5. # @Description:
  6. from fabric2 import Connection
  7. from flask import current_app
  8. from flask_socketio import emit
  9. from walle.model.record import RecordModel
  10. from invoke import Result
  11. from walle.service.code import Code
  12. class Waller(Connection):
  13. connections, success, errors = {}, {}, {}
  14. release_version_tar, release_version = None, None
  15. def run(self, command, wenv=None, sudo=False, **kwargs):
  16. '''
  17. # TODO
  18. pty=True/False是直接影响到输出.False较适合在获取文本,True更适合websocket
  19. :param command:
  20. :param wenv:
  21. :param sudo:
  22. :param kwargs:
  23. :return:
  24. '''
  25. message = 'deploying task_id=%s [%s@%s]$ %s ' % (wenv['task_id'], self.user, self.host, command)
  26. current_app.logger.info(message)
  27. try:
  28. if sudo:
  29. result = super(Waller, self).sudo(command, pty=False, **kwargs)
  30. else:
  31. result = super(Waller, self).run(command, pty=True, warn=True, **kwargs)
  32. if result.failed:
  33. exitcode, stdout, stderr = result.exited, '', result.stdout
  34. else:
  35. exitcode, stdout, stderr = 0, result.stdout, ''
  36. message = 'task_id=%s, host:%s command:%s status:%s, success:%s, error:%s' % (
  37. wenv['task_id'], self.host, command, exitcode, stdout, stderr
  38. )
  39. # TODO
  40. ws_dict = {
  41. 'user': self.user,
  42. 'host': self.host,
  43. 'cmd': command,
  44. 'status': exitcode,
  45. 'stage': wenv['stage'],
  46. 'sequence': wenv['sequence'],
  47. 'success': stdout,
  48. 'error': stderr,
  49. }
  50. if wenv['console']:
  51. emit('console', {'event': 'task:console', 'data': ws_dict}, room=wenv['task_id'])
  52. RecordModel().save_record(stage=wenv['stage'], sequence=wenv['sequence'], user_id=wenv['user_id'],
  53. task_id=wenv['task_id'], status=exitcode, host=self.host, user=self.user,
  54. command=result.command, success=stdout,
  55. error=stderr)
  56. current_app.logger.info(result)
  57. if exitcode != Code.Ok:
  58. current_app.logger.exception(result.stdout.strip())
  59. return result
  60. return result
  61. except Exception as e:
  62. current_app.logger.exception(e)
  63. # TODO 貌似可能的异常有很多种,需要分层才能完美解决 something wrong without e.result
  64. error = e.result if 'result' in e else e.message
  65. RecordModel().save_record(stage=wenv['stage'], sequence=wenv['sequence'], user_id=wenv['user_id'],
  66. task_id=wenv['task_id'], status=1, host=self.host, user=self.user,
  67. command=command, success='', error=error)
  68. if hasattr(e, 'reason') and hasattr(e, 'result'):
  69. message = 'task_id=%s, user:%s host:%s command:%s, status=1, reason:%s, result:%s exception:%s' % (
  70. wenv['task_id'], self.user, self.host, command, e.reason, error, e.message
  71. )
  72. else:
  73. message = 'task_id=%s, user:%s host:%s command:%s, status=1, message:%s' % (
  74. wenv['task_id'], self.user, self.host, command, e.message
  75. )
  76. current_app.logger.error(message, exc_info=1)
  77. # TODO
  78. ws_dict = {
  79. 'user': self.user,
  80. 'host': self.host,
  81. 'cmd': command,
  82. 'status': 1,
  83. 'stage': wenv['stage'],
  84. 'sequence': wenv['sequence'],
  85. 'success': '',
  86. 'error': error,
  87. }
  88. if wenv['console']:
  89. emit('console', {'event': 'task:console', 'data': ws_dict}, room=wenv['task_id'])
  90. return Result(exited=-1, stderr=error)
  91. def sudo(self, command, wenv=None, **kwargs):
  92. return self.run(command, wenv=wenv, sudo=True, **kwargs)
  93. def get(self, remote, local=None, wenv=None):
  94. return self.sync(wtype='get', remote=remote, local=local, wenv=wenv)
  95. def put(self, local, remote=None, wenv=None, *args, **kwargs):
  96. return self.sync(wtype='put', local=local, remote=remote, wenv=wenv, *args, **kwargs)
  97. def sync(self, wtype, remote=None, local=None, wenv=None):
  98. command = 'scp %s %s@%s:%s' % (local, self.user, self.host, remote) if wtype == 'put' \
  99. else 'scp %s@%s:%s %s' % (self.user, self.host, remote, local)
  100. message = 'deploying task_id=%s [%s@%s]$ %s ' % (wenv['task_id'], self.user, self.host, command)
  101. current_app.logger.info(message)
  102. try:
  103. if wtype == 'put':
  104. result = super(Waller, self).put(local=local, remote=remote)
  105. current_app.logger.info('put: local %s, remote %s', local, remote)
  106. op_user = current_app.config.get('LOCAL_SERVER_USER')
  107. op_host = current_app.config.get('LOCAL_SERVER_HOST')
  108. else:
  109. result = super(Waller, self).get(remote=remote, local=local)
  110. current_app.logger.info('get: local %s, remote %s', local, remote)
  111. current_app.logger.info('get: orig_local %s, local %s', result.orig_local, result.local)
  112. op_user = self.user
  113. op_host = self.host
  114. current_app.logger.info('put: %s, %s', result, dir(result))
  115. # TODO 可能会有非22端口的问题
  116. RecordModel().save_record(stage=wenv['stage'], sequence=wenv['sequence'], user_id=wenv['user_id'],
  117. task_id=wenv['task_id'], status=0, host=self.host, user=self.user,
  118. command=command, )
  119. # TODO
  120. ws_dict = {
  121. 'user': op_user,
  122. 'host': op_host,
  123. 'cmd': command,
  124. 'status': 1,
  125. 'stage': wenv['stage'],
  126. 'sequence': wenv['sequence'],
  127. 'success': '',
  128. 'error': '',
  129. }
  130. if wenv['console']:
  131. emit('console', {'event': 'task:console', 'data': ws_dict}, room=wenv['task_id'])
  132. return result
  133. except Exception as e:
  134. # TODO 收尾下
  135. current_app.logger.info('put: %s, %s', e, dir(e))
  136. # TODO command
  137. ws_dict = {
  138. 'user': self.user,
  139. 'host': self.host,
  140. 'cmd': command,
  141. 'status': 1,
  142. 'stage': wenv['stage'],
  143. 'sequence': wenv['sequence'],
  144. 'success': '',
  145. 'error': e.message,
  146. }
  147. if wenv['console']:
  148. emit('console', {'event': 'task:console', 'data': ws_dict}, room=wenv['task_id'])