manage.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  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, docker, const
  14. from api.model.app import App
  15. from api.model.response import Response
  16. from api.utils import lock
  17. # 获取所有app的信息
  18. def get_my_app():
  19. ret = Response(code=const.RETURN_FAIL, message="App query failed!")
  20. # get all info
  21. cmd = "docker compose ls -a --format json"
  22. output = shell_execute.execute_command_output_all(cmd)
  23. if int(output["code"]) == 0:
  24. output_list = json.loads(output["result"])
  25. list = []
  26. list = set_app_info(output_list)
  27. ret = Response(code=const.RETURN_SUCCESS, message="The app query is successful.", data=list)
  28. ret = ret.dict()
  29. return ret
  30. # 获取具体某个app的信息
  31. def get_app_detail(app_id):
  32. ret = Response(code=const.RETURN_FAIL, message="App query failed!")
  33. # get all info
  34. cmd = "docker compose ls -a --format json"
  35. output = shell_execute.execute_command_output_all(cmd)
  36. if int(output["code"]) == 0:
  37. output_list = json.loads(output["result"])
  38. list = []
  39. list = set_app_info(output_list)
  40. flag = 0
  41. for app in list:
  42. if app["app_id"] == app_id:
  43. list.clear()
  44. list.append(app)
  45. flag = 1
  46. break
  47. if flag == 1:
  48. ret = Response(code=const.RETURN_SUCCESS, message="The app query is successful.", data=list)
  49. ret = ret.dict()
  50. return ret
  51. # 查询某个正在安装的app的 具体状态:waiting(等待安装)pulling(拉取镜像)initing(初始化)running(正常运行)
  52. def install_app_process(app_id):
  53. app_name = split_app_id(app_id)
  54. var_path = "/data/apps/" + app_name + "/variables.json"
  55. real_name = docker.read_var(var_path, 'name')
  56. if docker.check_app_directory(app_name):
  57. percentage = docker.get_process_perc(app_name, real_name)
  58. ret = Response(code=const.RETURN_SUCCESS, message=percentage)
  59. ret = ret.dict()
  60. else:
  61. ret = Response(code=const.RETURN_FAIL, message="This app is not currently installed.")
  62. ret = ret.dict()
  63. return ret
  64. def install_app(app_name, customer_app_name, app_version):
  65. ret = Response(code=const.RETURN_FAIL, message=" ")
  66. ret.code, ret.message = check_app(app_name, customer_app_name, app_version)
  67. if ret.code == const.RETURN_SUCCESS:
  68. ret.code, ret.message = prepare_app(app_name, customer_app_name)
  69. if ret.code == const.RETURN_SUCCESS:
  70. t1 = Thread(target=install_app_job, args=(customer_app_name, app_version,))
  71. t1.start()
  72. ret.message="The app is starting, please check again in a few minutes."
  73. ret = ret.dict()
  74. return ret
  75. def start_app(app_id):
  76. ret = Response(code=const.RETURN_FAIL, message="")
  77. app_name = split_app_id(app_id)
  78. if if_app_exits(app_id, app_name):
  79. docker.check_app_compose(app_name)
  80. cmd = "docker compose -f /data/apps/"+app_name+"/docker-compose.yml start"
  81. output = shell_execute.execute_command_output_all(cmd)
  82. if int(output["code"]) == 0:
  83. ret.code = const.RETURN_SUCCESS
  84. ret.message = "The app starts successfully."
  85. else:
  86. ret.message = "The app failed to start!"
  87. else:
  88. ret.message = "The app is not installed!"
  89. ret = ret.dict()
  90. return ret
  91. def stop_app(app_id):
  92. ret = Response(code=const.RETURN_FAIL, message="")
  93. app_name = split_app_id(app_id)
  94. if if_app_exits(app_id, app_name):
  95. cmd = "docker compose -f /data/apps/"+app_name+"/docker-compose.yml stop"
  96. output = shell_execute.execute_command_output_all(cmd)
  97. if int(output["code"]) == 0:
  98. ret.code = const.RETURN_SUCCESS
  99. ret.message = "The app stopped successfully."
  100. else:
  101. ret.message = "App stop failed!"
  102. else:
  103. ret.message = "The app is not installed!"
  104. ret = ret.dict()
  105. return ret
  106. def restart_app(app_id):
  107. ret = Response(code=const.RETURN_FAIL, message="")
  108. app_name = split_app_id(app_id)
  109. if if_app_exits(app_id, app_name):
  110. cmd = "docker compose -f /data/apps/"+app_name+"/docker-compose.yml restart"
  111. output = shell_execute.execute_command_output_all(cmd)
  112. if int(output["code"]) == 0:
  113. ret.code = const.RETURN_SUCCESS
  114. ret.message = "The app restarts successfully."
  115. else:
  116. ret.message = "App restart failed!"
  117. else:
  118. ret.message = "The app is not installed!"
  119. ret = ret.dict()
  120. return ret
  121. def uninstall_app(app_id):
  122. ret = Response(code=const.RETURN_FAIL, message="")
  123. if_stopped = stop_app(app_id) # stop_app
  124. app_name = split_app_id(app_id)
  125. real_name = app_id.split("_")[0]
  126. if if_stopped["code"] == 0:
  127. cmd = "docker compose -f /data/apps/"+app_name+"/docker-compose.yml down -v"
  128. if real_name != app_name:
  129. cmd = cmd + " && sudo rm -rf /data/apps/" + app_name
  130. output = shell_execute.execute_command_output_all(cmd)
  131. if int(output["code"]) == 0:
  132. ret.code = 0
  133. ret.message = "The app is deleted successfully"
  134. else:
  135. ret.message = "App deletion failed!"
  136. else:
  137. ret.message = if_stopped["message"]
  138. ret = ret.dict()
  139. return ret
  140. def check_app(app_name, customer_app_name, app_version):
  141. message = " "
  142. code = const.RETURN_FAIL
  143. install_path = "/data/apps/" + customer_app_name
  144. if app_name==None or customer_app_name==None or app_version==None:
  145. message = "Please fill in the APP information completely!"
  146. elif not docker.check_app_directory(app_name):
  147. message = "Installing the app is not supported!"
  148. elif re.match('^[a-z0-9]+$', customer_app_name)==None:
  149. message = "App names must be lowercase letters and numbers!"
  150. elif docker.check_app_directory(install_path):
  151. message = "The APP name is already in use, please specify a different name to reinstall."
  152. elif not docker.check_vm_resource(app_name):
  153. message = "System resources (memory, CPU, disk) are insufficient, and continuing to install may cause the app to not run or the server to be abnormal!"
  154. else:
  155. code = const.RETURN_SUCCESS
  156. return code, message
  157. def prepare_app(app_name, customer_app_name):
  158. library_path = "/data/library/apps/" + app_name
  159. install_path = "/data/apps/" + customer_app_name
  160. message = " "
  161. code = const.RETURN_SUCCESS
  162. output = shell_execute.execute_command_output_all("cp -r " + library_path + " " + install_path)
  163. if int(output["code"]) != 0:
  164. message = "creating" + customer_app_name + "directory failed!"
  165. code = const.RETURN_FAIL
  166. return code, message
  167. def install_app_job(customer_app_name, app_version):
  168. file_path = "/data/apps/running_apps.txt"
  169. with open(file_path, "a", encoding="utf-8") as f:
  170. f.write(customer_app_name + "\n")
  171. # modify env
  172. env_path = "/data/apps/" + customer_app_name + "/.env"
  173. docker.modify_env(env_path, 'APP_NAME', customer_app_name)
  174. docker.modify_env(env_path, "APP_VERSION", app_version)
  175. # check port
  176. docker.check_app_compose(customer_app_name)
  177. # modify running_apps.txt
  178. cmd = "cd /data/apps/" + customer_app_name + " && sudo docker compose up --pull always -d"
  179. shell_execute.execute_command_output_all(cmd)
  180. file_data = ""
  181. with open(file_path, "r", encoding="utf-8") as f:
  182. for line in f:
  183. if re.match("^" + customer_app_name + "$", line):
  184. line = line.replace(line, "")
  185. file_data += line
  186. with open("test.txt", "w", encoding="utf-8") as f:
  187. f.write(file_data)
  188. def if_app_exits(app_id, app_name):
  189. cmd = "docker compose ls -a | grep \'"+app_name+"\\b\'"
  190. output = shell_execute.execute_command_output_all(cmd)
  191. if int(output["code"]) == -1:
  192. return False
  193. else:
  194. var_path = "/data/apps/" + app_name + "/variables.json"
  195. real_name = docker.read_var(var_path, "name")
  196. real_id = real_name + "_" + app_name
  197. if app_id == real_id:
  198. return True
  199. else:
  200. return False
  201. def split_app_id(app_id):
  202. return app_id.split("_")[1]
  203. def set_app_info(output_list):
  204. ip_result = shell_execute.execute_command_output_all("curl ifconfig.me")
  205. ip = ip_result["result"]
  206. app_list = []
  207. has_add = []
  208. for app_info in output_list:
  209. volume = app_info["ConfigFiles"] # volume
  210. app_name = volume.split('/')[3]
  211. app_path = "/data/apps/" + app_name
  212. var_path = app_path + "/variables.json"
  213. if not docker.check_directory(app_path):
  214. continue
  215. real_name = docker.read_var(var_path, 'name')
  216. image_url = get_Image_url(real_name)
  217. # get trade_mark
  218. trade_mark = docker.read_var(var_path, 'trademark')
  219. app_id = real_name + "_" + app_name # app_id
  220. case = app_info["Status"].split("(")[0] # case
  221. if case == "running":
  222. case_code = const.RETURN_RUNNING # case_code
  223. elif case == "exited":
  224. case = "stop"
  225. case_code = const.RETURN_STOP
  226. elif case == "created":
  227. case_code = const.RETURN_READY
  228. case = "installing"
  229. else:
  230. case_code = const.RETURN_ERROR
  231. # get env info
  232. path = "/data/apps/" + app_name + "/.env"
  233. port = 0
  234. url = "-"
  235. admin_url = "-"
  236. # get port and url
  237. try:
  238. http_port = list(docker.read_env(
  239. path, "APP_HTTP_PORT").values())[0]
  240. port = int(http_port)
  241. easy_url = "http://" + ip + ":" + str(port)
  242. url = get_url(real_name, easy_url)
  243. admin_url = get_admin_url(real_name, url)
  244. except IndexError:
  245. try:
  246. db_port = list(docker.read_env(
  247. path, "APP_DB.*_PORT").values())[0]
  248. port = int(db_port)
  249. except IndexError:
  250. pass
  251. # get user_name
  252. user_name = "-"
  253. try:
  254. user_name = list(docker.read_env(path, "APP_USER").values())[0]
  255. except IndexError:
  256. pass
  257. # get password
  258. password = "-"
  259. try:
  260. password = list(docker.read_env(
  261. path, "POWER_PASSWORD").values())[0]
  262. except IndexError:
  263. pass
  264. has_add.append(app_name)
  265. 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,
  266. image_url=image_url, admin_url=admin_url, trade_mark=trade_mark, user_name=user_name, password=password)
  267. app_list.append(app.dict())
  268. file_path = "/data/apps/running_apps.txt"
  269. if docker.check_directory(file_path):
  270. with open(file_path, "r", encoding="utf-8") as f:
  271. for running_app_name in f:
  272. running_app_name = re.sub("\n", "", running_app_name)
  273. if running_app_name not in has_add and running_app_name != "":
  274. var_path = "/data/apps/" + running_app_name + "/variables.json"
  275. trade_mark = docker.read_var(var_path, 'trademark')
  276. real_name = docker.read_var(var_path, 'name')
  277. image_url = get_Image_url(real_name)
  278. 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="-",
  279. url="-", image_url=image_url, admin_url="-", trade_mark=trade_mark, user_name="-", password="-")
  280. app_list.append(app.dict())
  281. return app_list
  282. def get_Image_url(app_name):
  283. image_url = "/static/" + app_name + "-websoft9.png"
  284. return image_url
  285. def get_url(app_name, easy_url):
  286. url = easy_url
  287. if app_name == "joomla":
  288. url = easy_url + "/administrator"
  289. elif app_name == "other":
  290. url = easy_url + "/administrator"
  291. else:
  292. url = easy_url
  293. return url
  294. def get_admin_url(app_name, url):
  295. admin_url = "-"
  296. if app_name == "wordpress":
  297. admin_url = url + "/wp-admin"
  298. elif app_name == "other":
  299. admin_url = url + "/admin"
  300. else:
  301. admin_url = "-"
  302. return admin_url