exec.py 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. from flask import Blueprint
  2. from apps.assets.models import Host
  3. from apps.deploy.models import App, DeployMenu
  4. from apps.configuration.models import Environment
  5. from libs.tools import json_response, JsonParser, Argument, QueuePool
  6. from libs.decorators import require_permission
  7. from libs.utils import Container
  8. from threading import Thread
  9. import uuid
  10. blueprint = Blueprint(__name__, __name__)
  11. @blueprint.route('/', methods=['POST'])
  12. @require_permission('publish_app_publish_deploy|publish_app_publish_menu_exec')
  13. def post():
  14. form, error = JsonParser(
  15. Argument('app_id', type=int),
  16. Argument('env_id', type=int),
  17. Argument('menu_id', type=int),
  18. Argument('message', default=''),
  19. Argument('host_ids', type=list)
  20. ).parse()
  21. if error is None:
  22. pro = App.query.get_or_404(form.app_id)
  23. env = Environment.query.get_or_404(form.env_id)
  24. menu = DeployMenu.query.get_or_404(form.menu_id)
  25. ctr_name = '%s.%s' % (pro.identify, env.identify)
  26. if menu.position == 2:
  27. cli = Host.query.get_or_404(form.host_ids[0])
  28. ctr = Container(cli.docker_uri, ctr_name)
  29. if menu.display_type == 2:
  30. exec_code, _ = ctr.exec_command_with_base64(menu.command, form.message, with_exit_code=True)
  31. return json_response(exec_code)
  32. elif menu.display_type == 1:
  33. token = uuid.uuid4().hex
  34. queue = QueuePool.make_queue(token, 1)
  35. queue.containers = [ctr]
  36. Thread(target=do_exec_with_stream,
  37. args=(token, ctr, menu.command, form.message, 10 * 60)).start()
  38. return json_response(token)
  39. # 发布区自定义菜单只允许通知成功与否,固无需判断display_type
  40. elif menu.position == 1:
  41. token = uuid.uuid4().hex
  42. hosts = Host.query.filter(Host.id.in_(form.host_ids)).all()
  43. queue = QueuePool.make_queue(token, len(hosts))
  44. for cli in hosts:
  45. ctr = Container(cli.docker_uri, ctr_name)
  46. Thread(target=do_exec, args=(queue, ctr, cli.name, menu.command, form.message)).start()
  47. return json_response({'token': token, 'data': [{'name': x.name} for x in hosts]})
  48. @blueprint.route('/<string:token>', methods=['DELETE'])
  49. @require_permission('publish_app_publish_deploy|publish_app_publish_menu_exec')
  50. def delete(token):
  51. queue = QueuePool.get_queue(token)
  52. if queue:
  53. for ctr in queue.containers:
  54. ctr.exec_command('/entrypoint.sh kill ' + token)
  55. queue.done()
  56. return json_response()
  57. def do_exec(queue, ctr, host_name, command, message, timeout=30):
  58. try:
  59. exec_code, _ = ctr.exec_command_with_base64(command, message, timeout=timeout, with_exit_code=True)
  60. queue.put({host_name: exec_code})
  61. except Exception as e:
  62. queue.put({host_name: '%s' % e})
  63. finally:
  64. queue.done()
  65. def do_exec_with_stream(token, ctr, command, message, timeout=30):
  66. queue = QueuePool.get_queue(token)
  67. try:
  68. for item in ctr.exec_command_with_base64(command, message, timeout=timeout, token=token, stream=True):
  69. queue.put({'message': item.decode()})
  70. except Exception as e:
  71. queue.put({'message': '%s' % e})
  72. finally:
  73. queue.done()