manage.py 12 KB

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