manage.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. import os
  2. import io
  3. import sys
  4. import platform
  5. import shutil
  6. import time
  7. import subprocess
  8. import json
  9. import datetime
  10. import socket
  11. import re
  12. from threading import Thread
  13. from api.utils import shell_execute, network, docker, const
  14. from api.model.app import App
  15. from api.model.response import Response
  16. from api.utils import lock
  17. def get_app_detail(app_id):
  18. ret = Response(code=const.RETURN_FAIL, message="app查询失败")
  19. # get all info
  20. cmd = "docker compose ls -a --format json"
  21. output = shell_execute.execute_command_output_all(cmd)
  22. if int(output["code"]) == 0:
  23. output_list = json.loads(output["result"])
  24. list = []
  25. list = set_app_info(output_list)
  26. flag = 0
  27. for app in list:
  28. if app["app_id"] == app_id:
  29. list.clear()
  30. list.append(app)
  31. flag = 1
  32. break
  33. if flag == 1:
  34. ret = Response(code=const.RETURN_SUCCESS, message="app查询成功", data=list)
  35. ret = ret.dict()
  36. return ret
  37. # 获取所有app的信息
  38. def get_my_app():
  39. ret = Response(code=const.RETURN_FAIL, message="app查询失败")
  40. # get all info
  41. cmd = "docker compose ls -a --format json"
  42. output = shell_execute.execute_command_output_all(cmd)
  43. if int(output["code"]) == 0:
  44. output_list = json.loads(output["result"])
  45. list = []
  46. list = set_app_info(output_list)
  47. ret = Response(code=const.RETURN_SUCCESS, message="app查询成功", data=list)
  48. ret = ret.dict()
  49. return ret
  50. def set_app_info(output_list):
  51. ip_result = shell_execute.execute_command_output_all("curl ifconfig.me")
  52. ip = ip_result["result"]
  53. app_list = []
  54. has_add = []
  55. for app_info in output_list:
  56. volume = app_info["ConfigFiles"] # volume
  57. app_name = volume.split('/')[3]
  58. real_name = docker.read_var(app_name, 'name')
  59. image_url = get_Image_url(real_name)
  60. # get trade_mark
  61. trade_mark = docker.read_var(app_name, 'trademark')
  62. app_id = real_name + "_" + app_name # app_id
  63. case = app_info["Status"].split("(")[0] # case
  64. if case == "running":
  65. case_code = const.RETURN_RUNNING # case_code
  66. elif case == "exited":
  67. case = "stop"
  68. case_code = const.RETURN_STOP
  69. elif case == "created":
  70. case_code = const.RETURN_READY
  71. case = "installing"
  72. else:
  73. case_code = const.RETURN_ERROR
  74. # get env info
  75. path = "/data/apps/" + app_name + "/.env"
  76. port = 0
  77. url = "-"
  78. admin_url = "-"
  79. # get port and url
  80. try:
  81. http_port = list(docker.read_env(
  82. path, "APP_HTTP_PORT").values())[0]
  83. port = int(http_port)
  84. easy_url = "http://" + ip + ":" + str(port)
  85. url = get_url(real_name, easy_url)
  86. admin_url = get_admin_url(real_name, url)
  87. except IndexError:
  88. try:
  89. db_port = list(docker.read_env(
  90. path, "APP_DB.*_PORT").values())[0]
  91. port = int(db_port)
  92. except IndexError:
  93. pass
  94. # get user_name
  95. user_name = "-"
  96. try:
  97. user_name = list(docker.read_env(path, "APP_USER").values())[0]
  98. except IndexError:
  99. pass
  100. # get password
  101. password = "-"
  102. try:
  103. password = list(docker.read_env(
  104. path, "POWER_PASSWORD").values())[0]
  105. except IndexError:
  106. pass
  107. has_add.append(app_name)
  108. app = App(app_id=app_id, name=real_name, customer_name=app_name, status_code=case_code, status=case, port=port, volume=volume, url=url,
  109. image_url=image_url, admin_url=admin_url, trade_mark=trade_mark, user_name=user_name, password=password)
  110. app_list.append(app.dict())
  111. file_path = "/data/apps/running_apps.txt"
  112. if os.path.exists(file_path) and os.path.getsize(file_path):
  113. with open(file_path, "r", encoding="utf-8") as f:
  114. for running_app_name in f:
  115. running_app_name = re.sub("\n", "", running_app_name)
  116. if running_app_name not in has_add and running_app_name != "":
  117. trade_mark = docker.read_var(running_app_name, 'trademark')
  118. real_name = docker.read_var(running_app_name, 'name')
  119. image_url = get_Image_url(real_name)
  120. app = App(app_id=real_name + "_" + running_app_name, name=real_name, customer_name=running_app_name, status_code=const.RETURN_READY, status="installing", port=0, volume="-",
  121. url="-", image_url=image_url, admin_url="-", trade_mark=trade_mark, user_name="-", password="-")
  122. app_list.append(app.dict())
  123. return app_list
  124. def get_Image_url(app_name):
  125. image_url = "/static/" + app_name + "-websoft9.png"
  126. return image_url
  127. def get_url(app_name, easy_url):
  128. url = easy_url
  129. if app_name == "joomla":
  130. url = easy_url + "/administrator"
  131. elif app_name == "other":
  132. url = easy_url + "/administrator"
  133. else:
  134. url = easy_url
  135. return url
  136. def get_admin_url(app_name, url):
  137. admin_url = "-"
  138. if app_name == "wordpress":
  139. admin_url = url + "/wp-admin"
  140. elif app_name == "other":
  141. admin_url = url + "/admin"
  142. else:
  143. admin_url = "-"
  144. return admin_url
  145. def install_app_process(app_id):
  146. app_name = split_app_id(app_id)
  147. real_name = docker.read_var(app_name, 'name')
  148. if docker.check_app_directory(app_name):
  149. percentage = docker.get_process_perc(app_name, real_name)
  150. ret = Response(code=const.RETURN_SUCCESS, message=percentage)
  151. ret = ret.dict()
  152. else:
  153. ret = Response(code=const.RETURN_FAIL, message="目前没有安装此App")
  154. ret = ret.dict()
  155. return ret
  156. def check_app(app_name, customer_app_name, app_version):
  157. message = " "
  158. code = const.RETURN_FAIL
  159. install_path = "/data/apps/" + customer_app_name
  160. if app_name==None or customer_app_name==None or app_version==None:
  161. message = "请将APP信息填写完整"
  162. elif not docker.check_app_directory(app_name):
  163. message = "不支持安装该APP"
  164. elif re.match('^[a-z0-9]+$', customer_app_name)==None:
  165. message = "应用名称必须为小写字母和数字"
  166. elif docker.check_app_directory(install_path):
  167. message = "APP名称已经使用,请指定其他名称重新安装。"
  168. elif not docker.check_vm_resource(app_name):
  169. message = "系统资源(内存、CPU、磁盘)不足,继续安装可能导致应用无法运行或服务器异常!"
  170. else:
  171. code = const.RETURN_SUCCESS
  172. return code, message
  173. def prepare_app(app_name, customer_app_name):
  174. library_path = "/data/apps/docker-library/" + app_name
  175. install_path = "/data/apps/" + customer_app_name
  176. message = " "
  177. code = const.RETURN_SUCCESS
  178. output = shell_execute.execute_command_output_all("cp -r " + library_path + " " + install_path)
  179. if int(output["code"]) != 0:
  180. message = "创建" + customer_app_name + "目录失败"
  181. code = const.RETURN_FAIL
  182. return code, message
  183. def install_app(app_name, customer_app_name, app_version):
  184. ret = Response(code=const.RETURN_FAIL, message=" ")
  185. ret.code, ret.message = check_app(app_name, customer_app_name, app_version)
  186. if ret.code == const.RETURN_SUCCESS:
  187. ret.code, ret.message = prepare_app(app_name, customer_app_name)
  188. if ret.code == const.RETURN_SUCCESS:
  189. t1 = Thread(target=install_app_job, args=(customer_app_name, app_version,))
  190. t1.start()
  191. ret.message="应用正在启动中,请过几分钟再查询"
  192. ret = ret.dict()
  193. return ret
  194. def install_app_job(customer_app_name, app_version):
  195. file_path = "/data/apps/running_apps.txt"
  196. with open(file_path, "a", encoding="utf-8") as f:
  197. f.write(customer_app_name + "\n")
  198. # modify env
  199. env_path = "/data/apps/" + customer_app_name + "/.env"
  200. docker.modify_env(env_path, 'APP_NAME', customer_app_name)
  201. docker.modify_env(env_path, "APP_VERSION", app_version)
  202. # check port
  203. docker.check_app_compose(customer_app_name)
  204. # modify running_apps.txt
  205. cmd = "cd /data/apps/" + customer_app_name + " && sudo docker compose up -d"
  206. shell_execute.execute_command_output_all(cmd)
  207. file_data = ""
  208. with open(file_path, "r", encoding="utf-8") as f:
  209. for line in f:
  210. if re.match("^" + customer_app_name + "$", line):
  211. line = line.replace(line, "")
  212. file_data += line
  213. with open("test.txt", "w", encoding="utf-8") as f:
  214. f.write(file_data)
  215. def if_app_exits(app_id, app_name):
  216. cmd = "docker compose ls -a | grep \'"+app_name+"\\b\'"
  217. output = shell_execute.execute_command_output_all(cmd)
  218. if int(output["code"]) == -1:
  219. return False
  220. else:
  221. real_name = docker.read_var(app_name, "name")
  222. real_id = real_name + "_" + app_name
  223. if app_id == real_id:
  224. return True
  225. else:
  226. return False
  227. def start_app(app_id):
  228. ret = Response(code=const.RETURN_FAIL, message="")
  229. app_name = split_app_id(app_id)
  230. if if_app_exits(app_id, app_name):
  231. docker.check_app_compose(app_name)
  232. cmd = "docker compose -f /data/apps/"+app_name+"/docker-compose.yml start"
  233. output = shell_execute.execute_command_output_all(cmd)
  234. if int(output["code"]) == 0:
  235. ret.code = const.RETURN_SUCCESS
  236. ret.message = "应用启动成功"
  237. else:
  238. ret.message = "应用启动失败"
  239. else:
  240. ret.message = "app应用没有安装"
  241. ret = ret.dict()
  242. return ret
  243. def stop_app(app_id):
  244. ret = Response(code=const.RETURN_FAIL, message="")
  245. app_name = split_app_id(app_id)
  246. if if_app_exits(app_id, app_name):
  247. cmd = "docker compose -f /data/apps/"+app_name+"/docker-compose.yml stop"
  248. output = shell_execute.execute_command_output_all(cmd)
  249. if int(output["code"]) == 0:
  250. ret.code = const.RETURN_SUCCESS
  251. ret.message = "应用停止成功"
  252. else:
  253. ret.message = "应用停止失败"
  254. else:
  255. ret.message = "app应用没有安装"
  256. ret = ret.dict()
  257. return ret
  258. def restart_app(app_id):
  259. ret = Response(code=const.RETURN_FAIL, message="")
  260. app_name = split_app_id(app_id)
  261. if if_app_exits(app_id, app_name):
  262. cmd = "docker compose -f /data/apps/"+app_name+"/docker-compose.yml restart"
  263. output = shell_execute.execute_command_output_all(cmd)
  264. if int(output["code"]) == 0:
  265. ret.code = const.RETURN_SUCCESS
  266. ret.message = "应用重启成功"
  267. else:
  268. ret.message = "应用重启失败"
  269. else:
  270. ret.message = "app应用没有安装"
  271. ret = ret.dict()
  272. return ret
  273. def uninstall_app(app_id):
  274. ret = Response(code=const.RETURN_FAIL, message="")
  275. if_stopped = stop_app(app_id) # stop_app
  276. app_name = split_app_id(app_id)
  277. real_name = app_id.split("_")[0]
  278. if if_stopped["code"] == 0:
  279. cmd = "docker compose -f /data/apps/"+app_name+"/docker-compose.yml down -v"
  280. if real_name != app_name:
  281. cmd = cmd + " && sudo rm -rf /data/apps/" + app_name
  282. output = shell_execute.execute_command_output_all(cmd)
  283. if int(output["code"]) == 0:
  284. ret.code = 0
  285. ret.message = "应用删除成功"
  286. else:
  287. ret.message = "应用删除失败"
  288. else:
  289. ret.message = if_stopped["message"]
  290. ret = ret.dict()
  291. return ret
  292. def split_app_id(app_id):
  293. return app_id.split("_")[1]