docker.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. import os, io, sys, platform, shutil, time, json, datetime
  2. import re, docker, requests
  3. from api.utils import shell_execute
  4. from dotenv import load_dotenv, find_dotenv
  5. import dotenv
  6. from pathlib import Path
  7. from api.utils.common_log import myLogger
  8. from api.utils import shell_execute, const
  9. from api.exception.command_exception import CommandException
  10. def pull_images(app_name):
  11. # 备用方法
  12. # 为了防止安装前,用户服务器已经有了镜像。导致安装时镜像不重新拉取,镜像是老的(根据docker-compose.yml 和 .env 获取)
  13. myLogger.info_logger("Pull images complete ...")
  14. def delete_images(app_id):
  15. # 备用方法
  16. # 卸载APP时同时删除dockercompose里面对应的镜像(根据docker-compose.yml 和 .env 获取)
  17. myLogger.info_logger("Delete images complete ...")
  18. def get_process_perc(app_name, real_name):
  19. process_now = "pulling"
  20. if if_app_exits(app_name):
  21. process_now = "creating"
  22. if if_app_running(app_name):
  23. process_now = "initing"
  24. if if_app_access(app_name):
  25. process_now = "running"
  26. return process_now
  27. # 已经是running的app怎么知道它已经能够访问,如页面能进入,如mysql能被客户端连接
  28. def if_app_access(app_name):
  29. return True
  30. def if_app_exits(app_name):
  31. cmd = "docker compose ls -a | grep \'" + app_name + "\\b\'"
  32. output = shell_execute.execute_command_output_all(cmd)
  33. if int(output["code"]) == -1:
  34. return False
  35. else:
  36. return True
  37. def if_app_running(app_name):
  38. cmd = "docker compose ls -a |grep running | grep \'" + app_name + "\\b\'"
  39. output = shell_execute.execute_command_output_all(cmd)
  40. if int(output["code"]) == -1:
  41. return False
  42. else:
  43. return True
  44. def check_appid_exist(app_id):
  45. myLogger.info_logger("Checking check_appid_exist ...")
  46. appList = manage.get_my_app()
  47. find = False
  48. for app in appList:
  49. if app_id == app.app_id:
  50. find = True
  51. break
  52. myLogger.info_logger("Check complete.")
  53. return find
  54. def check_appid_include_rq(app_id):
  55. message = ""
  56. code = None
  57. if app_id == None:
  58. code = const.ERROR_CLIENT_PARAM_BLANK
  59. message = "AppID is null"
  60. elif re.match('^[a-zA-Z0-9]+_[a-z0-9]+$', app_id):
  61. code = const.ERROR_CLIENT_PARAM_Format
  62. message = "APP name can only be composed of numbers and lowercase letters"
  63. elif not docker.check_appid_exist(app_id):
  64. code = const.ERROR_CLIENT_PARAM_NOTEXIST
  65. message = "AppID is not exist"
  66. return code, message
  67. def check_app_id(app_id):
  68. message = ""
  69. code = None
  70. if app_id == None:
  71. code = const.ERROR_CLIENT_PARAM_BLANK
  72. message = "AppID is null"
  73. elif re.match('^[a-zA-Z0-9]+_[a-z0-9]+$', app_id):
  74. code = const.ERROR_CLIENT_PARAM_Format
  75. message = "APP name can only be composed of numbers and lowercase letters"
  76. # elif not docker.check_appid_exist(app_id):
  77. # code = const.ERROR_CLIENT_PARAM_NOTEXIST
  78. # message = "AppID is not exist"
  79. return code, message
  80. def check_app_id(app_id):
  81. message = ""
  82. code = None
  83. if app_id == None:
  84. code = const.ERROR_CLIENT_PARAM_BLANK
  85. message = "AppID is null"
  86. elif re.match('^[a-zA-Z0-9]+_[a-z0-9]+$', app_id):
  87. code = const.ERROR_CLIENT_PARAM_Format
  88. message = "APP name can only be composed of numbers and lowercase letters"
  89. # elif not docker.check_appid_exist(app_id):
  90. # code = const.ERROR_CLIENT_PARAM_NOTEXIST
  91. # message = "AppID is not exist"
  92. return code, message
  93. def check_vm_resource(app_name):
  94. myLogger.info_logger("Checking virtual memory resource ...")
  95. var_path = "/data/library/apps/" + app_name + "/variables.json"
  96. requirements_var = read_var(var_path, 'requirements')
  97. need_cpu_count = int(requirements_var['cpu'])
  98. cpu_count = int(shell_execute.execute_command_output_all("cat /proc/cpuinfo | grep \'core id\'| wc -l")["result"])
  99. if cpu_count < need_cpu_count:
  100. myLogger.info_logger("Check complete: The number of CPU cores is insufficient!")
  101. return False
  102. need_mem_total = int(requirements_var['memory'])
  103. mem = shell_execute.execute_command_output_all("free -m | grep Mem")["result"].split()
  104. mem_total = float(mem[1]) / 1024
  105. if round(mem_total) < need_mem_total:
  106. myLogger.info_logger("Check complete: The total amount of memory is insufficient!")
  107. return False
  108. mem_free = float(mem[3]) / 1024
  109. if need_mem_total > 4 and round(mem_free) < 4:
  110. myLogger.info_logger("Check complete: There is not enough memory left!")
  111. return False
  112. need_disk = int(requirements_var['disk'])
  113. disk_free = float(
  114. shell_execute.execute_command_output_all("df -m --output=avail /")["result"].split("\n")[1]) / 1024
  115. if round(disk_free) < need_disk - 17:
  116. myLogger.info_logger("Check complete: There are not enough disks left!")
  117. return False
  118. myLogger.info_logger("Check complete.")
  119. return True
  120. def check_app_websoft9(app_name):
  121. # websoft9's support applist
  122. myLogger.info_logger("Checking dir...")
  123. path = "/data/library/apps/" + app_name
  124. is_exists = check_directory(path)
  125. return is_exists
  126. def check_directory(path):
  127. try:
  128. shell_execute.execute_command_output_all("ls " + path)
  129. return True
  130. except CommandException as ce:
  131. return False
  132. def check_app_compose(path):
  133. myLogger.info_logger("Checking port...")
  134. port_dic = read_env(path, "APP_.*_PORT")
  135. # 1.判断/data/apps/app_name/.env中的port是否占用,没有被占用,方法结束(get_start_port方法)
  136. for port_name in port_dic:
  137. port_value = get_start_port(port_dic[port_name])
  138. modify_env(path, port_name, port_value)
  139. myLogger.info_logger("Port check complete")
  140. return
  141. def check_app_url(customer_app_name):
  142. myLogger.info_logger("Checking app url...")
  143. # 如果app的.env文件中含有HTTP_URL项目,需要如此设置 HTTP_URL=ip:port
  144. env_path = "/data/apps/" + customer_app_name + "/.env"
  145. if read_env(env_path, "HTTP_URL") != {}:
  146. ip = shell_execute.execute_command_output_all("curl ifconfig.me")["result"]
  147. http_port = list(read_env(path, "APP_HTTP_PORT").values())[0]
  148. url = ip + ":" + http_port
  149. modify_env(path, "HTTP_URL", url)
  150. myLogger.info_logger("App url check complete")
  151. return
  152. def read_env(path, key):
  153. myLogger.info_logger("Read " + path)
  154. output = shell_execute.execute_command_output_all("cat " + path + "|grep " + key)
  155. code = output["code"]
  156. env_dic = {}
  157. if int(code) == 0 and output["result"] != "":
  158. ret = output["result"]
  159. env_list = ret.split()
  160. for env in env_list:
  161. env_dic[env.split("=")[0]] = env.split("=")[1]
  162. myLogger.info_logger("Read " + path + ": " + str(env_dic))
  163. return env_dic
  164. def modify_env(path, env_name, value):
  165. myLogger.info_logger("Modify " + path + "...")
  166. output = shell_execute.execute_command_output_all("sed -n \'/^" + env_name + "/=\' " + path)
  167. if int(output["code"]) == 0 and output["result"] != "":
  168. line_num = output["result"].split("\n")[0]
  169. s = env_name + "=" + value
  170. output = shell_execute.execute_command_output_all("sed -i \'" + line_num + "c " + s + "\' " + path)
  171. if int(output["code"]) == 0:
  172. myLogger.info_logger("Modify " + path + ": Change " + env_name + " to " + value)
  173. def read_var(var_path, var_name):
  174. value = ""
  175. myLogger.info_logger("Read " + var_path)
  176. output = shell_execute.execute_command_output_all("cat " + var_path)
  177. if int(output["code"]) == 0:
  178. var = json.loads(output["result"])
  179. try:
  180. value = var[var_name]
  181. except KeyError:
  182. myLogger.warning_logger("Read " + var_path + ": No key " + var_name)
  183. else:
  184. myLogger.warning_logger(var_path + " not found")
  185. return value
  186. def get_start_port(port):
  187. use_port = port
  188. while True:
  189. cmd = "netstat -ntlp | grep -v only"
  190. output = shell_execute.execute_command_output_all(cmd)
  191. if output["result"].find(use_port) == -1:
  192. break
  193. else:
  194. use_port = str(int(use_port) + 1)
  195. return use_port