host.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. from flask import Blueprint, request
  2. from apps.assets.models import Host, HostExtend
  3. from apps.deploy.models import AppHostRel
  4. from libs.tools import json_response, JsonParser, Argument
  5. from apps.setting import utils, Setting
  6. from libs import ssh
  7. from libs.utils import DockerClient, DockerException
  8. import math
  9. from public import db
  10. from libs.decorators import require_permission
  11. from apps.assets.utils import excel_parse
  12. blueprint = Blueprint(__name__, __name__)
  13. @blueprint.route('/', methods=['GET'])
  14. @require_permission('assets_host_view | publish_app_publish_host_select | '
  15. 'job_task_add | job_task_edit | assets_host_exec')
  16. def get():
  17. form, error = JsonParser(Argument('page', type=int, default=1, required=False),
  18. Argument('pagesize', type=int, default=10, required=False),
  19. Argument('host_query', type=dict, required=False), ).parse(request.args)
  20. if error is None:
  21. print('host_ng', form)
  22. host_data = Host.query
  23. if form.page == -1:
  24. return json_response({'data': [x.to_json() for x in host_data.all()], 'total': -1})
  25. if form.host_query.get('name_field'):
  26. host_data = host_data.filter(Host.name.like('%{}%'.format(form.host_query['name_field'])))
  27. if form.host_query.get('zone_field'):
  28. host_data = host_data.filter_by(zone=form.host_query['zone_field'])
  29. result = host_data.limit(form.pagesize).offset((form.page - 1) * form.pagesize).all()
  30. return json_response({'data': [x.to_json() for x in result], 'total': host_data.count()})
  31. return json_response(message=error)
  32. @blueprint.route('/', methods=['POST'])
  33. @require_permission('assets_host_add')
  34. def post():
  35. form, error = JsonParser('name', 'type', 'zone', 'docker_uri', 'ssh_ip', 'ssh_port',
  36. Argument('desc', nullable=True, required=False)).parse()
  37. if error is None:
  38. host = Host(**form)
  39. host.save()
  40. return json_response(host)
  41. return json_response(message=error)
  42. @blueprint.route('/<int:host_id>', methods=['DELETE'])
  43. @require_permission('assets_host_del')
  44. def delete(host_id):
  45. host = Host.query.get_or_404(host_id)
  46. if AppHostRel.query.filter_by(host_id=host_id).first():
  47. return json_response(message='请先取消与应用的关联后,再尝试删除该主机。')
  48. host.delete()
  49. return json_response()
  50. @blueprint.route('/<int:host_id>', methods=['PUT'])
  51. @require_permission('assets_host_edit')
  52. def put(host_id):
  53. form, error = JsonParser('name', 'type', 'zone', 'docker_uri', 'ssh_ip', 'ssh_port',
  54. Argument('desc', nullable=True, required=False)).parse()
  55. if error is None:
  56. host = Host.query.get_or_404(host_id)
  57. host.update(**form)
  58. return json_response(host)
  59. return json_response(message=error)
  60. @blueprint.route('/<int:host_id>/valid', methods=['GET'])
  61. @require_permission('assets_host_valid')
  62. def get_valid(host_id):
  63. cli = Host.query.get_or_404(host_id)
  64. if not Setting.has('ssh_private_key'):
  65. utils.generate_and_save_ssh_key()
  66. if ssh.ssh_ping(cli.ssh_ip, cli.ssh_port):
  67. try:
  68. sync_host_info(host_id, cli.docker_uri)
  69. except DockerException:
  70. return json_response(message='docker fail')
  71. else:
  72. return json_response(message='ssh fail')
  73. return json_response()
  74. @blueprint.route('/<int:host_id>/valid', methods=['POST'])
  75. @require_permission('assets_host_valid')
  76. def post_valid(host_id):
  77. form, error = JsonParser(Argument('secret', help='请输入root用户的密码!')).parse()
  78. if error is None:
  79. cli = Host.query.get_or_404(host_id)
  80. ssh.add_public_key(cli.ssh_ip, cli.ssh_port, form.secret)
  81. if ssh.ssh_ping(cli.ssh_ip, cli.ssh_port):
  82. try:
  83. sync_host_info(host_id, cli.docker_uri)
  84. except DockerException:
  85. return json_response(message='获取扩展信息失败,请检查docker是否可以正常连接!')
  86. else:
  87. return json_response(message='验证失败!')
  88. return json_response(message=error)
  89. @blueprint.route('/<int:host_id>/extend/', methods=['GET'])
  90. @require_permission('assets_host_valid')
  91. def get_extend(host_id):
  92. host_extend = HostExtend.query.filter_by(host_id=host_id).first()
  93. return json_response(host_extend)
  94. @blueprint.route('/zone/', methods=['GET'])
  95. @require_permission('assets_host_valid | assets_host_exec')
  96. def fetch_groups():
  97. zones = db.session.query(Host.zone.distinct().label('zone')).all()
  98. return json_response([x.zone for x in zones])
  99. @blueprint.route('/import', methods=['POST'])
  100. @require_permission('assets_host_add')
  101. def host_import():
  102. data = excel_parse()
  103. if data:
  104. index_map = {key: index for index, key in enumerate(data.keys())}
  105. for row in zip(*data.values()):
  106. print(row)
  107. Host(
  108. name=row[index_map['主机名称']],
  109. desc=row[index_map['备注信息']],
  110. type=row[index_map['主机类型']],
  111. zone=row[index_map['所属区域']],
  112. docker_uri=row[index_map['Docker连接地址']],
  113. ssh_ip=row[index_map['SSH连接地址']],
  114. ssh_port=row[index_map['SSH端口']],
  115. ).add()
  116. db.session.commit()
  117. return json_response(data='导入成功')
  118. def sync_host_info(host_id, uri):
  119. host_info = DockerClient(base_url=uri).docker_info()
  120. operate_system = host_info.get('OperatingSystem')
  121. memory = math.ceil(int(host_info.get('MemTotal'))/1024/1024/1024)
  122. cpu = host_info.get('NCPU')
  123. # outer_ip = 1
  124. # inner_ip = 2
  125. HostExtend.upsert({'host_id': host_id}, host_id=host_id, operate_system=operate_system, memory=memory, cpu=cpu)
  126. return True