manage.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  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. if running_app_name not in has_add:
  128. trade_mark = docker.read_var(running_app_name, 'trademark')
  129. real_name = docker.read_var(running_app_name, 'name')
  130. image_url = get_Image_url(real_name)
  131. 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="-",
  132. url="-", image_url=image_url, admin_url="-", trade_mark=trade_mark, user_name="-", password="-")
  133. app_list.append(app.dict())
  134. return app_list
  135. def get_Image_url(app_name):
  136. image_url = "/static/" + app_name + "-websoft9.png"
  137. return image_url
  138. def get_url(app_name, easy_url):
  139. url = easy_url
  140. if app_name == "joomla":
  141. url = easy_url + "/administrator"
  142. elif app_name == "other":
  143. url = easy_url + "/administrator"
  144. else:
  145. url = easy_url
  146. return url
  147. def get_admin_url(app_name, url):
  148. admin_url = "-"
  149. if app_name == "wordpress":
  150. admin_url = url + "/wp-admin"
  151. elif app_name == "other":
  152. admin_url = url + "/admin"
  153. else:
  154. admin_url = "-"
  155. return admin_url
  156. def install_app_process(app_id):
  157. app_name = split_app_id(app_id)
  158. real_name = docker.read_var(app_name, 'name')
  159. if docker.check_app_directory(app_name):
  160. percentage = docker.get_process_perc(app_name, real_name)
  161. ret = Response(code=const.RETURN_SUCCESS, message=percentage)
  162. ret = ret.dict()
  163. else:
  164. ret = Response(code=const.RETURN_FAIL, message="目前没有安装此App")
  165. ret = ret.dict()
  166. return ret
  167. def install_app(app_name, customer_app_name, app_version):
  168. app_id = app_name + "_" + customer_app_name
  169. library_path = "/data/library/"+app_name
  170. install_path = "/data/apps/"+customer_app_name
  171. ret = Response(code=const.RETURN_FAIL, message=" ")
  172. if app_name==None or customer_app_name==None or app_version==None:
  173. ret.message = "请将APP信息填写完整"
  174. elif not docker.check_app_directory(app_name):
  175. ret.message = "不支持安装该APP"
  176. elif re.match('^[a-z0-9]+$', customer_app_name)==None:
  177. ret.message = "应用名称必须为小写字母和数字"
  178. elif docker.check_app_directory(install_path):
  179. ret.message = "APP名称已经使用,请指定其他名称重新安装。"
  180. elif not docker.check_vm_resource(app_name):
  181. ret.message = "系统资源(内存、CPU、磁盘)不足,继续安装可能导致应用无法运行或服务器异常!"
  182. else:
  183. output = shell_execute.execute_command_output_all("cp -r " + library_path + " " + install_path)
  184. if int(output["code"]) != 0:
  185. ret.message = "创建" + customer_app_name + "目录失败"
  186. else:
  187. t1 = Thread(target=record_and_install_app, args=(customer_app_name, app_version,))
  188. t1.start()
  189. ret.message="应用正在启动中,请过几分钟再查询"
  190. ret = ret.dict()
  191. return ret
  192. # def install_app(app_name, customer_app_name, app_version):
  193. # app_file_path = '/data/apps/' + app_name
  194. # running_file_path = "/data/apps/running_apps.txt"
  195. # unique_app_path = "/data/apps/" + customer_app_name
  196. # is_lock = lock.install_mutex.acquire(False)
  197. # if is_lock and not (os.path.exists(running_file_path) and os.path.getsize(running_file_path)):
  198. # # if os.path.exists(running_file_path) and os.path.getsize(running_file_path):
  199. # # ret = Response(code=const.RETURN_SUCCESS, message="已有应用正在启动,请稍后再试")
  200. # # ret = ret.dict()
  201. #
  202. # # 防止app名重复
  203. # app_id = app_name + "_" + customer_app_name
  204. # if if_app_exits(app_id, customer_app_name):
  205. # ret = Response(code=const.RETURN_FAIL,
  206. # message="APP名称已经使用,请指定其他名称重新安装。")
  207. # ret = ret.dict()
  208. # lock.install_mutex.release()
  209. # return ret
  210. #
  211. # elif docker.check_app_directory(app_name):
  212. # if docker.check_vm_resource(app_name) == False:
  213. # ret = Response(code=const.RETURN_FAIL, message="系统资源(内存、CPU、磁盘)不足,继续安装可能导致应用无法运行或服务器异常!")
  214. # ret = ret.dict()
  215. # lock.install_mutex.release()
  216. # return ret
  217. #
  218. # if app_name != customer_app_name:
  219. # output = shell_execute.execute_command_output_all(
  220. # "cp -r /data/apps/" + app_name + " /data/apps/" + customer_app_name)
  221. # if int(output["code"]) != 0:
  222. # ret.code = const.RETURN_FAIL
  223. # ret.message = "创建" + customer_app_name + "目录失败."
  224. # ret = ret.dict()
  225. # lock.install_mutex.release()
  226. # return ret
  227. # env_file = unique_app_path + '/.env'
  228. # docker.modify_env(env_file, 'APP_NAME', customer_app_name)
  229. #
  230. # # check port
  231. # docker.check_app_compose(customer_app_name)
  232. # if app_version != None:
  233. # path = "/data/apps/"+customer_app_name+"/.env"
  234. # docker.modify_env(path, "APP_VERSION", app_version)
  235. # file_path = "/data/apps/running_apps.txt"
  236. # with open(file_path, "w", encoding="utf-8") as f:
  237. # f.write(customer_app_name)
  238. # t1 = Thread(target=record_and_install_app, args=(customer_app_name,))
  239. # t1.start()
  240. # ret = Response(code=const.RETURN_SUCCESS, message="应用正在启动中,请过几分钟再查询")
  241. # ret = ret.dict()
  242. # else:
  243. # ret = Response(code=const.RETURN_FAIL, message="目前不支持安装此App")
  244. # ret = ret.dict()
  245. # lock.install_mutex.release()
  246. # return ret
  247. # else:
  248. # ret = Response(code=const.RETURN_SUCCESS, message="已有应用正在启动,请稍后再试")
  249. # ret = ret.dict()
  250. # return ret
  251. def record_and_install_app(customer_app_name, app_version):
  252. file_path = "/data/apps/running_apps.txt"
  253. with open(file_path, "a", encoding="utf-8") as f:
  254. f.write(customer_app_name + "\n")
  255. # modify env
  256. env_path = "/data/apps/" + customer_app_name + "/.env"
  257. docker.modify_env(env_path, 'APP_NAME', customer_app_name)
  258. docker.modify_env(env_path, "APP_VERSION", app_version)
  259. # check port
  260. docker.check_app_compose(customer_app_name)
  261. # modify running_apps.txt
  262. cmd = "cd /data/apps/" + customer_app_name + " && sudo docker compose up -d"
  263. shell_execute.execute_command_output_all(cmd)
  264. file_data = ""
  265. with open(file_path, "r", encoding="utf-8") as f:
  266. for line in f:
  267. if re.match("^" + customer_app_name + "$", line):
  268. line = line.replace(line, "")
  269. file_data += line
  270. with open("test.txt", "w", encoding="utf-8") as f:
  271. f.write(file_data)
  272. def if_app_exits(app_id, app_name):
  273. cmd = "docker compose ls -a | grep \'"+app_name+"\\b\'"
  274. output = shell_execute.execute_command_output_all(cmd)
  275. if int(output["code"]) == -1:
  276. return False
  277. else:
  278. real_name = docker.read_var(app_name, "name")
  279. real_id = real_name + "_" + app_name
  280. if app_id == real_id:
  281. return True
  282. else:
  283. return False
  284. def start_app(app_id):
  285. ret = Response(code=const.RETURN_FAIL, message="")
  286. app_name = split_app_id(app_id)
  287. if if_app_exits(app_id, app_name):
  288. docker.check_app_compose(app_name)
  289. cmd = "docker compose -f /data/apps/"+app_name+"/docker-compose.yml start"
  290. output = shell_execute.execute_command_output_all(cmd)
  291. if int(output["code"]) == 0:
  292. ret.code = const.RETURN_SUCCESS
  293. ret.message = "应用启动成功"
  294. else:
  295. ret.message = "应用启动失败"
  296. else:
  297. ret.message = "app应用没有安装"
  298. ret = ret.dict()
  299. return ret
  300. def stop_app(app_id):
  301. ret = Response(code=const.RETURN_FAIL, message="")
  302. app_name = split_app_id(app_id)
  303. if if_app_exits(app_id, app_name):
  304. cmd = "docker compose -f /data/apps/"+app_name+"/docker-compose.yml stop"
  305. output = shell_execute.execute_command_output_all(cmd)
  306. if int(output["code"]) == 0:
  307. ret.code = const.RETURN_SUCCESS
  308. ret.message = "应用停止成功"
  309. else:
  310. ret.message = "应用停止失败"
  311. else:
  312. ret.message = "app应用没有安装"
  313. ret = ret.dict()
  314. return ret
  315. def restart_app(app_id):
  316. ret = Response(code=const.RETURN_FAIL, message="")
  317. app_name = split_app_id(app_id)
  318. if if_app_exits(app_id, app_name):
  319. cmd = "docker compose -f /data/apps/"+app_name+"/docker-compose.yml restart"
  320. output = shell_execute.execute_command_output_all(cmd)
  321. if int(output["code"]) == 0:
  322. ret.code = const.RETURN_SUCCESS
  323. ret.message = "应用重启成功"
  324. else:
  325. ret.message = "应用重启失败"
  326. else:
  327. ret.message = "app应用没有安装"
  328. ret = ret.dict()
  329. return ret
  330. def uninstall_app(app_id):
  331. ret = Response(code=const.RETURN_FAIL, message="")
  332. if_stopped = stop_app(app_id) # stop_app
  333. app_name = split_app_id(app_id)
  334. real_name = app_id.split("_")[0]
  335. if if_stopped["code"] == 0:
  336. cmd = "docker compose -f /data/apps/"+app_name+"/docker-compose.yml down -v"
  337. if real_name != app_name:
  338. cmd = cmd + " && sudo rm -rf /data/apps/" + app_name
  339. output = shell_execute.execute_command_output_all(cmd)
  340. if int(output["code"]) == 0:
  341. ret.code = 0
  342. ret.message = "应用删除成功"
  343. else:
  344. ret.message = "应用删除失败"
  345. else:
  346. ret.message = if_stopped["message"]
  347. ret = ret.dict()
  348. return ret
  349. def split_app_id(app_id):
  350. return app_id.split("_")[1]