ai / bt-source /panel /mod /project /docker /runtime /runtimeManage.py
GGSheng's picture
feat: deploy Gemma 4 to hf space
17e971c verified
# coding: utf-8
# -------------------------------------------------------------------
# 宝塔Linux面板
# -------------------------------------------------------------------
# Copyright (c) 2015-2099 宝塔软件(http://bt.cn) All rights reserved.
# -------------------------------------------------------------------
# Author: wzz <wzz@bt.cn>
# -------------------------------------------------------------------
# ------------------------------
# docker模型 - docker runtime 业务类
# ------------------------------
import json
import os
import sys
import time
if "/www/server/panel/class" not in sys.path:
sys.path.insert(0, "/www/server/panel/class")
import public
from btdockerModel import dk_public as dp
from mod.project.docker.runtime.base import Runtime
class RuntimeManage(Runtime):
def __init__(self):
super(RuntimeManage, self).__init__()
self.runtime_path = "/www/dk_project/runtime"
self.runtime_templates_path = "{}/templates".format(self.runtime_path)
self.exts_file = "{}/php/exts.json".format(self.runtime_templates_path)
self.versions_file = "{}/versions.json".format(self.runtime_templates_path)
self.service_templates_path = "{}/".format(self.runtime_templates_path) + "{}"
self.runtime_build_path = "{}/build".format(self.runtime_path)
if not os.path.exists(self.runtime_build_path): os.makedirs(self.runtime_build_path, 384, True)
self.php_build_path = "{}/php".format(self.runtime_build_path)
if not os.path.exists(self.php_build_path): os.makedirs(self.php_build_path, 384, True)
self.runtime_run_path = "{}/run".format(self.runtime_path)
self.service_run_path = "{}/".format(self.runtime_run_path) + "{}"
self.site_path = "/www/dk_project/wwwroot"
self.site_path_pl = "/www/dk_project/wwwroot.pl"
if os.path.exists(self.site_path_pl):
self.site_path = public.readFile(self.site_path_pl).strip()
if not os.path.exists(self.site_path): os.makedirs(self.site_path, 384, True)
# 2024/11/1 10:33 下载模板到指定目录
def download_templates(self):
'''
@name 下载模板到指定目录
'''
if os.path.exists(self.runtime_templates_path):
public.ExecShell("rm -rf {}".format(self.runtime_templates_path))
app_url = "{}/src/dk_app/runtime/templates.zip".format(public.get_url())
to_file = '/tmp/templates.zip'
if os.path.exists(to_file): public.ExecShell("rm -f {}".format(to_file))
public.downloadFile(app_url, to_file)
if not os.path.exists(to_file) or os.path.getsize(to_file) < 10:
return public.returnResult(False, msg="模板更新失败!")
public.ExecShell("unzip -o -d {} {}".format(self.runtime_path, to_file))
return public.returnResult(True, "模板更新成功!")
# 2024/11/1 10:18 检查模板是否存在
def check_templates(self, get):
'''
@name 检查模板是否存在
'''
get.force_update = int(get.get("force_update", 0))
if get.force_update == 1:
return self.download_templates()
if not os.path.exists(self.runtime_templates_path):
return self.download_templates()
# 2024/11/1 09:16 构建指定的PHP镜像
def build_php_image(self, get):
'''
@name 构建指定的PHP镜像
'''
self.service_templates_path = self.service_templates_path.format("php")
self.project_path = "{}/{}".format(self.php_build_path, get.runtime_name)
if not os.path.exists(self.project_path): os.makedirs(self.project_path, 384, True)
self.compose_file = "{}/docker-compose.yml".format(self.project_path)
self.build_log = "{}/build.log".format(self.project_path)
public.ExecShell("rm -f {}".format(self.build_log))
if get.runtime_version.startswith("8."):
public.ExecShell("\cp -r {}/php8/* {}/".format(self.service_templates_path, self.project_path))
public.ExecShell("\cp -r {}/php8/.env {}/".format(self.service_templates_path, self.project_path))
if not os.path.exists(self.compose_file):
return public.returnResult(False, msg="PHP8模板不存在")
elif get.runtime_version.startswith("7."):
if get.runtime_version in ("7.0", "7.1"):
public.ExecShell("\cp -r {}/php70/* {}/".format(self.service_templates_path, self.project_path))
public.ExecShell("\cp -r {}/php70/.env {}/".format(self.service_templates_path, self.project_path))
else:
public.ExecShell("\cp -r {}/php72/* {}/".format(self.service_templates_path, self.project_path))
public.ExecShell("\cp -r {}/php72/.env {}/".format(self.service_templates_path, self.project_path))
if not os.path.exists(self.compose_file):
return public.returnResult(False, msg="PHP7模板不存在")
elif get.runtime_version.startswith("5."):
public.ExecShell("\cp -r {}/php5/* {}/".format(self.service_templates_path, self.project_path))
public.ExecShell("\cp -r {}/php5/.env {}/".format(self.service_templates_path, self.project_path))
if not os.path.exists(self.compose_file):
return public.returnResult(False, msg="PHP5模板不存在")
else:
return public.returnResult(False, msg="PHP版本: 【{}】错误".format(get.runtime_version))
exts = get.exts.replace(",", " ")
public.ExecShell("sed -i 's/^VERSION=.*/VERSION={}/' {}/.env".format(get.runtime_version, self.project_path))
public.ExecShell("sed -i 's/^REPO_URL=.*/REPO_URL={}/' {}/.env".format(get.repo_url, self.project_path))
public.ExecShell("sed -i 's/^EXTS=.*/EXTS=\"{}\"/' {}/.env".format(exts, self.project_path))
public.ExecShell("sed -i 's/btphp:/{}:/g' {}/.env".format(get.runtime_name, self.project_path))
public.ExecShell("sed -i 's/btphp:/{}/g' {}/*.yml".format(get.runtime_name, self.project_path))
cmd = ("nohup echo '正在构建【{runtime_name}】,可能需要等待1-5分钟以上...' >> {build_log};"
"docker-compose -f {compose_file} build --progress=plain >> {build_log} 2>&1 && "
"echo 'bt_successful' >> {build_log} || echo 'bt_failed' >> {build_log} &"
.format(
runtime_name=get.runtime_name,
build_log=self.build_log,
compose_file=self.compose_file,
))
import subprocess
subprocess.Popen(cmd, shell=True)
public.set_module_logs('build_runtime_php', 'runtime_buildphp_{}'.format(get.runtime_version), 1)
# 2024/11/6 16:01 运行指定php项目
def run_php_project(self, get):
'''
@name 运行指定php项目
'''
self.service_templates_path = self.service_templates_path.format("php")
run_php_templates_path = os.path.join(self.service_templates_path, "runphp")
self.service_run_path = self.service_run_path.format("php")
if not os.path.exists(self.service_run_path): os.makedirs(self.service_run_path, 384, True)
get.project_name = get.site_name.replace(".", "_")
self.project_path = "{}/{}".format(self.service_run_path, get.project_name)
if not os.path.exists(self.project_path): os.makedirs(self.project_path, 384, True)
self.compose_file = "{}/docker-compose.yml".format(self.project_path)
self.create_log = "{}/create.log".format(self.project_path)
get.php_version = get.name.split(":")[1]
get.project_path = self.project_path
if get.php_version.startswith("8."):
public.ExecShell("\cp -r {}/php8/* {}/".format(run_php_templates_path, self.project_path))
public.ExecShell("\cp -r {}/php8/.env {}/".format(run_php_templates_path, self.project_path))
if not os.path.exists(self.compose_file):
return public.returnResult(False, msg="PHP8模板不存在")
elif get.php_version.startswith("7."):
if get.php_version in ("7.0", "7.1"):
public.ExecShell("\cp -r {}/php70/* {}/".format(run_php_templates_path, self.project_path))
public.ExecShell("\cp -r {}/php70/.env {}/".format(run_php_templates_path, self.project_path))
else:
public.ExecShell("\cp -r {}/php72/* {}/".format(run_php_templates_path, self.project_path))
public.ExecShell("\cp -r {}/php72/.env {}/".format(run_php_templates_path, self.project_path))
if not os.path.exists(self.compose_file):
return public.returnResult(False, msg="PHP7模板不存在")
elif get.php_version.startswith("5."):
public.ExecShell("\cp -r {}/php5/* {}/".format(run_php_templates_path, self.project_path))
public.ExecShell("\cp -r {}/php5/.env {}/".format(run_php_templates_path, self.project_path))
if not os.path.exists(self.compose_file):
return public.returnResult(False, msg="PHP5模板不存在")
else:
return public.returnResult(False, msg="PHP版本: 【{}】错误".format(get.php_version))
public.ExecShell("sed -i 's/^IMAGE_NAME=.*/IMAGE_NAME={}/' {}/.env".format(get.name, self.project_path))
public.ExecShell(
"sed -i 's/^WEB_HTTP_PORT=.*/WEB_HTTP_PORT={}/' {}/.env".format(get.runtime_port, self.project_path))
public.ExecShell("sed -i 's,^SITE_PATH=.*,SITE_PATH={},' {}/.env".format(get.site_path, self.project_path))
cmd = ("nohup echo '正在创建【{site_name}】,可能需要等待1-5分钟以上...' >> {build_log};"
"docker-compose -f {compose_file} up -d >> {build_log} 2>&1 && "
"echo 'bt_successful' >> {build_log} || echo 'bt_failed' >> {build_log} &"
.format(
site_name=get.site_name,
build_log=self.create_log,
compose_file=self.compose_file,
))
import subprocess
subprocess.Popen(cmd, shell=True)
# public.set_module_logs('runtime_runphp_{}'.format(get.version), 'run_php', 1)
return public.returnResult()
# 2024/11/1 15:02 运行python项目
def run_python_project(self, get):
'''
@name 运行python项目
'''
self.service_templates_path = self.service_templates_path.format("python")
self.service_run_path = self.service_run_path.format("python")
if not os.path.exists(self.service_run_path): os.makedirs(self.service_run_path, 384, True)
self.project_path = "{}/{}".format(self.service_run_path, get.runtime_name)
if not os.path.exists(self.project_path): os.makedirs(self.project_path, 384, True)
self.compose_file = "{}/docker-compose.yml".format(self.project_path)
self.create_log = "{}/create.log".format(self.project_path)
public.ExecShell("rm -f {}".format(self.create_log))
public.ExecShell("\cp -r {}/python3/* {}/".format(self.service_templates_path, self.project_path))
public.ExecShell("\cp -r {}/python3/.env {}/".format(self.service_templates_path, self.project_path))
if not os.path.exists(self.compose_file):
return public.returnResult(False, msg="Python模板不存在")
public.ExecShell("sed -i 's/^VERSION=.*/VERSION={}/' {}/.env".format(get.runtime_version, self.project_path))
public.ExecShell("sed -i 's/^REPO_URL=.*/REPO_URL={}/' {}/.env".format(get.repo_url, self.project_path))
public.ExecShell("sed -i 's,^SITE_PATH=.*,SITE_PATH={},' {}/.env".format(get.site_path, self.project_path))
public.ExecShell("sed -i 's/btpython:/{}/g' {}/*.yml".format(get.runtime_name, self.project_path))
port_conf = self.handle_ports(get.ports)
public.ExecShell("sed -i 's,:BTPORT_CONF:,{},g' {}/*.yml".format(port_conf, self.project_path))
try:
import yaml
import glob
yaml_files = glob.glob("{}/*.yml".format(self.project_path))
for yf in yaml_files:
data = public.readFile(yf)
if data:
data = yaml.safe_load(data)
data["services"]["{}-python3".format(get.runtime_name)]["environment"][1] = "COMMAND={}".format(get.command)
public.writeFile(yf, yaml.dump(data))
except:
public.ExecShell("sed -i 's/:COMMAND:/{}/g' {}/*.yml".format(get.command, self.project_path))
cmd = ("nohup echo '正在创建【{runtime_name}】,可能需要等待1-5分钟以上...' >> {build_log};"
"docker-compose -f {compose_file} up -d >> {build_log} 2>&1 && "
"echo 'bt_successful' >> {build_log} || echo 'bt_failed' >> {build_log} &"
.format(
runtime_name=get.runtime_name,
build_log=self.create_log,
compose_file=self.compose_file,
))
import subprocess
subprocess.Popen(cmd, shell=True)
public.set_module_logs('runtime_python', 'runtime_python_{}'.format(get.runtime_version), 1)
# 2024/11/4 14:46 运行golang项目
def run_go_project(self, get):
'''
@name 运行golang项目
'''
self.service_templates_path = self.service_templates_path.format("go")
self.service_run_path = self.service_run_path.format("go")
if not os.path.exists(self.service_run_path): os.makedirs(self.service_run_path, 384, True)
self.project_path = "{}/{}".format(self.service_run_path, get.runtime_name)
if not os.path.exists(self.project_path): os.makedirs(self.project_path, 384, True)
self.compose_file = "{}/docker-compose.yml".format(self.project_path)
self.create_log = "{}/create.log".format(self.project_path)
public.ExecShell("rm -f {}".format(self.create_log))
public.ExecShell("\cp -r {}/go/* {}/".format(self.service_templates_path, self.project_path))
public.ExecShell("\cp -r {}/go/.env {}/".format(self.service_templates_path, self.project_path))
if not os.path.exists(self.compose_file):
return public.returnResult(False, msg="Golang模板不存在")
public.ExecShell("sed -i 's/^VERSION=.*/VERSION={}/' {}/.env".format(get.runtime_version, self.project_path))
public.ExecShell("sed -i 's,^SITE_PATH=.*,SITE_PATH={},' {}/.env".format(get.site_path, self.project_path))
public.ExecShell("sed -i 's/btgo:/{}/g' {}/*.yml".format(get.runtime_name, self.project_path))
port_conf = self.handle_ports(get.ports)
public.ExecShell("sed -i 's,:BTPORT_CONF:,{},g' {}/*.yml".format(port_conf, self.project_path))
try:
import yaml
import glob
yaml_files = glob.glob("{}/*.yml".format(self.project_path))
for yf in yaml_files:
data = public.readFile(yf)
if data:
data = yaml.safe_load(data)
data["services"]["{}-golang".format(get.runtime_name)]["environment"][0] = "COMMAND={}".format(get.command)
public.writeFile(yf, yaml.dump(data))
except:
public.ExecShell("sed -i 's/:COMMAND:/{}/g' {}/*.yml".format(get.command, self.project_path))
cmd = ("nohup echo '正在创建【{runtime_name}】,可能需要等待1-5分钟以上...' >> {build_log};"
"docker-compose -f {compose_file} up -d >> {build_log} 2>&1 && "
"echo 'bt_successful' >> {build_log} || echo 'bt_failed' >> {build_log} &"
.format(
runtime_name=get.runtime_name,
build_log=self.create_log,
compose_file=self.compose_file,
))
import subprocess
subprocess.Popen(cmd, shell=True)
public.set_module_logs('runtime_go', 'runtime_go_{}'.format(get.runtime_version), 1)
# 2024/11/4 14:54 运行java项目
def run_java_project(self, get):
'''
@name 运行java项目
'''
self.service_templates_path = self.service_templates_path.format("java")
self.service_run_path = self.service_run_path.format("java")
if not os.path.exists(self.service_run_path): os.makedirs(self.service_run_path, 384, True)
self.project_path = "{}/{}".format(self.service_run_path, get.runtime_name)
if not os.path.exists(self.project_path): os.makedirs(self.project_path, 384, True)
self.compose_file = "{}/docker-compose.yml".format(self.project_path)
self.create_log = "{}/create.log".format(self.project_path)
public.ExecShell("rm -f {}".format(self.create_log))
public.ExecShell("\cp -r {}/java/* {}/".format(self.service_templates_path, self.project_path))
public.ExecShell("\cp -r {}/java/.env {}/".format(self.service_templates_path, self.project_path))
if not os.path.exists(self.compose_file):
return public.returnResult(False, msg="Java模板不存在")
public.ExecShell("sed -i 's/^VERSION=.*/VERSION={}/' {}/.env".format(get.runtime_version, self.project_path))
public.ExecShell("sed -i 's,^SITE_PATH=.*,SITE_PATH={},' {}/.env".format(get.site_path, self.project_path))
public.ExecShell("sed -i 's/btjava:/{}/g' {}/*.yml".format(get.runtime_name, self.project_path))
port_conf = self.handle_ports(get.ports)
public.ExecShell("sed -i 's,:BTPORT_CONF:,{},g' {}/*.yml".format(port_conf, self.project_path))
try:
import yaml
import glob
yaml_files = glob.glob("{}/*.yml".format(self.project_path))
for yf in yaml_files:
data = public.readFile(yf)
if data:
data = yaml.safe_load(data)
data["services"]["{}-java".format(get.runtime_name)]["environment"][0] = "COMMAND={}".format(get.command)
public.writeFile(yf, yaml.dump(data))
except:
public.ExecShell("sed -i 's/:COMMAND:/{}/g' {}/*.yml".format(get.command, self.project_path))
cmd = ("nohup echo '正在创建【{runtime_name}】,可能需要等待1-5分钟以上...' >> {build_log};"
"docker-compose -f {compose_file} up -d >> {build_log} 2>&1 && "
"echo 'bt_successful' >> {build_log} || echo 'bt_failed' >> {build_log} &"
.format(
runtime_name=get.runtime_name,
build_log=self.create_log,
compose_file=self.compose_file,
))
import subprocess
subprocess.Popen(cmd, shell=True)
public.set_module_logs('runtime_java', 'runtime_java_{}'.format(get.runtime_version), 1)
def run_nodejs_project(self, get):
'''
@name 运行nodejs项目
'''
self.service_templates_path = self.service_templates_path.format("nodejs")
self.service_run_path = self.service_run_path.format("nodejs")
if not os.path.exists(self.service_run_path): os.makedirs(self.service_run_path, 384, True)
self.project_path = "{}/{}".format(self.service_run_path, get.runtime_name)
if not os.path.exists(self.project_path): os.makedirs(self.project_path, 384, True)
self.compose_file = "{}/docker-compose.yml".format(self.project_path)
self.create_log = "{}/create.log".format(self.project_path)
public.ExecShell("rm -f {}".format(self.create_log))
public.ExecShell("\cp -r {}/nodejs/* {}/".format(self.service_templates_path, self.project_path))
public.ExecShell("\cp -r {}/nodejs/.env {}/".format(self.service_templates_path, self.project_path))
if not os.path.exists(self.compose_file):
return public.returnResult(False, msg="Nodejs模板不存在")
repo_url = '"{}"'.format(get.repo_url.replace("/","\\/"))
public.ExecShell("sed -i 's/^VERSION=.*/VERSION={}/' {}/.env".format(get.runtime_version, self.project_path))
public.ExecShell("sed -i 's/^REPO_URL=.*/REPO_URL={}/' {}/.env".format(repo_url, self.project_path))
public.ExecShell("sed -i 's,^SITE_PATH=.*,SITE_PATH={},' {}/.env".format(get.site_path, self.project_path))
public.ExecShell("sed -i 's/btnodejs:/{}/g' {}/*.yml".format(get.runtime_name, self.project_path))
port_conf = self.handle_ports(get.ports)
public.ExecShell("sed -i 's,:BTPORT_CONF:,{},g' {}/*.yml".format(port_conf, self.project_path))
public.ExecShell("sed -i 's/:COMMAND:/{}/g' {}/*.yml".format(get.command, self.project_path))
cmd = ("nohup echo '正在创建【{runtime_name}】,可能需要等待1-5分钟以上...' >> {build_log};"
"docker-compose -f {compose_file} up -d >> {build_log} 2>&1 && "
"echo 'bt_successful' >> {build_log} || echo 'bt_failed' >> {build_log} &"
.format(
runtime_name=get.runtime_name,
build_log=self.create_log,
compose_file=self.compose_file,
))
import subprocess
subprocess.Popen(cmd, shell=True)
public.set_module_logs('runtime_nodejs', 'runtime_nodejs_{}'.format(get.runtime_version), 1)
# 2024/11/1 15:29 处理端口配置信息
def handle_ports(self, ports):
'''
@name 处理端口配置信息
'''
# {"2362/tcp":"6236","646/tcp":["127.0.0.1","734"]}
ports = json.loads(ports)
# 构造 - ${HOST_IP}:${WEB_HTTP_PORT}:${APP_PORT} 用在docker-compose.yml中
ports_str = ""
for port in ports:
if ports_str != "" and not "\n" in ports_str:
ports_str += "\\n"
ports_str += " - "
if isinstance(ports[port], list):
if "tcp/udp" in port:
ports_str += "127.0.0.1:{}:{}".format(ports[port][1], port.split("/")[0])
else:
ports_str += "127.0.0.1:{}:{}".format(ports[port][1], port)
else:
if "tcp/udp" in port:
ports_str += "0.0.0.0:{}:{}".format(ports[port], port.split("/")[0])
else:
ports_str += "0.0.0.0:{}:{}".format(ports[port], port)
return ports_str
# 2024/11/20 10:11 添加默认的PHP扩展模板
def add_default_php_ext_template(self):
'''
@name 添加默认的PHP扩展模板
'''
ext_templates = {
"wordpress": "exif,igbinary,imagick,intl,apcu,memcached,opcache,shmop,mysqli,pdo_mysql,gd",
"flarum": "curl,gd,pdo_mysql,mysqli,bz2,exif,yaf,imap",
"苹果CMS-V10": "mysqli,pdo_mysql,zip,gd,redis,memcache,memcached",
"SeaCMS": "mysqli,pdo_mysql,gd,curl",
}
top_php = "8.3"
if os.path.exists(self.versions_file):
try:
top_php = json.loads(public.readFile(self.versions_file))["php"][0]
except:
pass
for name in ext_templates.keys():
args = public.dict_obj()
args.exts = ext_templates[name]
args.name = "{}_{}".format(name, top_php)
args.version = top_php
self.create_php_ext_template(args)
args.name = "{}_7.4".format(name)
args.version = "7.4"
self.create_php_ext_template(args)
# 2024/10/31 10:29 获取指定运行环境列表
def get_runtime_list(self, get):
'''
@name 获取指定运行环境列表
'''
get.runtime_type = get.get("runtime_type", "all")
get.p = get.get("p", 1)
get.row = get.get("row", 10)
if not os.path.exists(self.exts_file):
self.check_templates(get)
from mod.project.docker.app.base import App
cbnet = App().check_baota_net()
if not cbnet["status"]: return cbnet
if get.runtime_type == "all":
all_runtime_list = dp.sql('runtime').order('addtime desc').select()
else:
all_runtime_list = dp.sql('runtime').where('type=?', get.runtime_type).order('addtime desc').select()
all_runtime_list = self.check_runtime_status(all_runtime_list)
all_runtime_list = self.get_page(all_runtime_list, get)
return self.pageResult(data=all_runtime_list["data"], page=all_runtime_list["page"])
# 2024/11/1 11:40 检查运行环境的状态
def check_runtime_status(self, all_runtime_list):
'''
@name 检查运行环境的状态
'''
from btdockerModel.dockerSock import image
sk_image = image.dockerImage()
all_images = sk_image.get_images()
for runtime in all_runtime_list:
runtime["status"] = "abnormal"
if runtime["type"] == "php":
stdout, stderr = public.ExecShell("grep 'bt_successful' {}".format(runtime["log_file"]))
if not stdout:
runtime["status"] = "initializing"
stdout, stderr = public.ExecShell("grep 'bt_failed' {}".format(runtime["log_file"]))
if stdout:
runtime["status"] = "abnormal"
continue
# 检查是否存在 runtime["name"]:runtime["version"]的镜像
for image in all_images:
if "{}:{}".format(runtime["name"], runtime["version"]) in image["RepoTags"]:
runtime["status"] = "normal"
break
elif runtime["type"] in ["java", "go", "python","nodejs"]:
runtime["status"] = "running"
# 检查是否存在运行中的容器
stdout, stderr = public.ExecShell(
"docker-compose -f {} ps --format ".format(runtime["compose"]) + "\"{{.State}}\"")
runtime["status"] = stdout.strip() if stdout.strip() else "exited"
return all_runtime_list
# 2024/10/31 10:30 创建指定运行环境
def create_runtime(self, get):
'''
@name 创建指定运行环境
'''
get.runtime_name = get.get("runtime_name", None)
if get.runtime_name is None: return public.returnResult(False, msg="请传运行环境名称:runtime_name")
get.runtime_type = get.get("runtime_type", None)
if get.runtime_type is None: return public.returnResult(False, msg="请传运行环境类型:runtime_type")
get.runtime_version = get.get("runtime_version", None)
if get.runtime_version is None: return public.returnResult(False, msg="请传运行环境版本:runtime_version")
get.remark = get.get("remark", "")
if get.runtime_type in ["php", "python","nodejs"]:
get.repo_url = get.get("repo_url", None)
if get.repo_url is None: return public.returnResult(False, msg="请传源加速地址:repo_url")
get.exts = get.get("exts", None)
if get.runtime_type in ["java", "go", "python","nodejs"]:
get.site_path = get.get("site_path", None)
if get.site_path is None: return public.returnResult(False, msg="请传站点路径:site_path")
get.command = get.get("command", None)
if get.command is None: return public.returnResult(False, msg="请传启动命令:command")
get.ports = get.get("ports", None)
if get.ports is None: return public.returnResult(False, msg="请传端口映射:ports")
posts_dict = json.loads(get.ports)
get.ports_dict = {}
for p in posts_dict.keys():
if type(posts_dict[p]) == list:
get.ports_dict[p] = [{"HostIp": posts_dict[p][0], "HostPort": posts_dict[p][1]}]
else:
get.ports_dict[p] = [{"HostIp": "0.0.0.0", "HostPort": posts_dict[p]}]
find_result = dp.sql("runtime").where("name=? and type=?", (get.runtime_name, get.runtime_type)).find()
if find_result:
return public.returnResult(False, msg="运行环境【{}】已存在,请更换其他名称!".format(get.runtime_name))
self.check_templates(get)
public.set_module_logs('runtime'.format(get.runtime_version), 'create_runtime', 1)
if get.runtime_type == "php":
self.build_php_image(get)
dp.sql("runtime").insert({
"name": get.runtime_name,
"type": get.runtime_type,
"version": get.runtime_version,
"repo_url": get.repo_url,
"exts": get.exts,
"addtime": int(time.time()),
"runtime_path": self.project_path,
"compose": self.compose_file,
"log_file": self.build_log,
"remark": public.xssencode2(get.remark)
})
else:
if get.runtime_type == "python":
self.run_python_project(get)
elif get.runtime_type == "go":
self.run_go_project(get)
elif get.runtime_type == "java":
self.run_java_project(get)
elif get.runtime_type == "nodejs":
self.run_nodejs_project(get)
dp.sql("runtime").insert({
"name": get.runtime_name,
"type": get.runtime_type,
"version": get.runtime_version,
"repo_url": get.get('repo_url',''),
"path": get.site_path,
"command": get.command,
"ports": json.dumps(get.ports_dict),
"addtime": int(time.time()),
"runtime_path": self.project_path,
"compose": self.compose_file,
"log_file": self.create_log,
"remark": public.xssencode2(get.remark)
})
return public.returnResult(msg="创建运行环境【{}】成功".format(get.runtime_name))
# 2024/11/19 11:59
def remove_image(self, get):
'''
@name
'''
image_name = "{}:{}".format(get.runtime_name, get.runtime_version)
stdout, stderr = public.ExecShell("docker ps -a |grep {}".format(image_name))
if stdout: return False
public.ExecShell("docker image rm -f {}".format(image_name))
return True
# 2024/10/31 10:33 编辑指定运行环境
def modify_runtime(self, get):
'''
@name 编辑指定运行环境
'''
get.id = get.get("id", None)
if get.id is None: return public.returnResult(False, msg="请传运行环境ID:id")
get.runtime_name = get.get("runtime_name", None)
if get.runtime_name is None: return public.returnResult(False, msg="请传运行环境名称:runtime_name")
get.runtime_type = get.get("runtime_type", None)
if get.runtime_type is None: return public.returnResult(False, msg="请传运行环境类型:runtime_type")
get.runtime_version = get.get("runtime_version", None)
if get.runtime_version is None: return public.returnResult(False, msg="请传运行环境版本:runtime_version")
get.remark = get.get("remark", "")
if get.runtime_type in ["php", "python"]:
get.repo_url = get.get("repo_url", None)
if get.repo_url is None: return public.returnResult(False, msg="请传代码仓库地址:repo_url")
get.exts = get.get("exts", None)
if get.runtime_type in ["java", "go", "python","nodejs"]:
get.site_path = get.get("site_path", None)
if get.site_path is None: return public.returnResult(False, msg="请传站点路径:site_path")
get.command = get.get("command", None)
if get.command is None: return public.returnResult(False, msg="请传启动命令:command")
get.ports = get.get("ports", None)
if get.ports is None: return public.returnResult(False, msg="请传端口映射:ports")
posts_dict = json.loads(get.ports)
get.ports_dict = {}
for p in posts_dict.keys():
if type(posts_dict[p]) == list:
get.ports_dict[p] = [{"HostIp": posts_dict[p][0], "HostPort": posts_dict[p][1]}]
else:
get.ports_dict[p] = [{"HostIp": "0.0.0.0", "HostPort": posts_dict[p]}]
find_result = dp.sql("runtime").where("id=? and type=?", (get.id, get.runtime_type)).find()
if not find_result: return public.returnResult(False, msg="运行环境不存在")
if not self.remove_image(get):
return public.returnResult(False,
msg="原删除镜像失败,请手动删除:{} 后再尝试编辑".format(find_result["name"]))
if get.runtime_type == "php":
self.build_php_image(get)
dp.sql("runtime").where("id=? and type=?", (get.id, get.runtime_type)).update({
"repo_url": get.repo_url,
"exts": get.exts
})
else:
if get.runtime_type == "python":
self.run_python_project(get)
elif get.runtime_type == "java":
self.run_java_project(get)
elif get.runtime_type == "nodejs":
self.run_nodejs_project(get)
elif get.runtime_type == "go":
self.run_go_project(get)
else:
return public.returnResult(False, msg="不支持的运行环境类型:{}".format(get.runtime_type))
dp.sql("runtime").where("id=? and type=?", (get.id, get.runtime_type)).update({
"path": get.site_path,
"repo_url": get.get("repo_url", ""),
"command": get.command,
"ports": json.dumps(get.ports_dict)
})
return public.returnResult(msg="编辑成功")
# 2024/11/1 14:29 删除指定运行环境
def delete_runtime(self, get):
'''
@name 删除指定运行环境
'''
get.id = get.get("id", None)
if get.id is None: return public.returnResult(False, msg="请传运行环境ID:id")
find_result = dp.sql("runtime").where("id=?", get.id).find()
if not find_result: return public.returnResult(False, msg="运行环境不存在")
if find_result["type"] == "php":
public.ExecShell("docker-compose -f {} down".format(find_result["compose"]))
public.ExecShell("docker-compose -f {} rm -f".format(find_result["compose"]))
public.ExecShell("docker image rm -f {}:{}".format(find_result["name"], find_result["version"]))
public.ExecShell("rm -rf {}".format(find_result["runtime_path"]))
elif find_result["type"] in ["java", "go", "python"]:
public.ExecShell("docker-compose -f {} down".format(find_result["compose"]))
public.ExecShell("docker-compose -f {} rm -f".format(find_result["compose"]))
public.ExecShell("rm -rf {}".format(find_result["runtime_path"]))
dp.sql("runtime").where("id=?", get.id).delete()
find_result = dp.sql("runtime").where("id=?", get.id).find()
if find_result: return public.returnResult(False, msg="删除失败")
return public.returnResult(msg="删除成功")
# 2024/11/1 14:33 批量删除指定运行环境
def batch_delete_runtime(self, get):
'''
@name 批量删除指定运行环境
'''
get.ids = get.get("ids", None)
if get.ids is None: return public.returnResult(False, msg="请传运行环境ID:ids")
get.ids = get.ids.split(",")
delete_result = []
for id in get.ids:
find_result = dp.sql("runtime").where("id=?", id).find()
if not find_result:
delete_result.append({"id": id, "status": False, "msg": "运行环境不存在"})
continue
if find_result["type"] == "php":
public.ExecShell("docker-compose -f {} down".format(find_result["compose"]))
public.ExecShell("docker-compose -f {} rm -f".format(find_result["compose"]))
public.ExecShell("docker image rm -f {}:{}".format(find_result["name"], find_result["version"]))
public.ExecShell("rm -rf {}".format(find_result["runtime_path"]))
elif find_result["type"] in ["java", "go", "python"]:
public.ExecShell("docker-compose -f {} down".format(find_result["compose"]))
public.ExecShell("docker-compose -f {} rm -f".format(find_result["compose"]))
public.ExecShell("rm -rf {}".format(find_result["runtime_path"]))
dp.sql("runtime").where("id=?", id).delete()
find_result = dp.sql("runtime").where("id=?", id).find()
if find_result:
delete_result.append({"id": id, "status": False, "msg": "删除失败"})
continue
delete_result.append({"id": id, "status": True, "msg": "删除成功"})
return public.returnResult(msg="批量删除成功", data=delete_result)
# 2024/10/31 10:30 清理构建缓存
def build_prune(self, get):
'''
@name 清理构建缓存
'''
from btdockerModel.dockerSock import image
sk_image = image.dockerImage()
sk_image.build_prune()
get.force_update = 1
self.check_templates(get)
return public.returnResult(msg="清理所有构建缓存成功")
# 2024/10/31 10:33 设置运行环境运行状态(仅java/go/python/nodejs)
def set_runtime_status(self, get):
'''
@name 设置运行环境运行状态(仅java/go/python/nodejs)
'''
get.compose_file = get.get("compose_file", None)
if get.compose_file is None: return public.returnResult(False, msg="请传compose文件路径:compose_file")
get.runtime_status = get.get("runtime_status", None)
if get.runtime_status is None: return public.returnResult(False, msg="请传运行状态:runtime_status")
if not get.compose_file.endswith(".yml"): return public.returnResult(False, msg="compose文件路径错误")
self.path = get.compose_file
if get.runtime_status == "stop":
cmd = self.get_compose_stop()
opt_status = "停止"
elif get.runtime_status == "start":
cmd = self.get_compose_up()
opt_status = "启动"
elif get.runtime_status == "restart":
cmd = self.get_compose_restart()
opt_status = "重启"
else:
return public.returnResult(False, msg="运行状态【{}】错误".format(get.runtime_status))
public.ExecShell(cmd)
return public.returnResult(msg="{}成功".format(opt_status))
# 2024/10/31 10:33 获取指定运行环境的日志
def get_runtime_logs(self, get):
'''
@name 获取指定运行环境的日志
'''
get.log_type = get.get("log_type", "run")
get.compose_file = get.get("compose_file", None)
get.log_file = get.get("log_file", None)
if get.log_type == "run":
if get.compose_file is None:
return public.returnResult(False, msg="请传compose文件路径:compose_file")
command = self.set_type(0).set_path(get.compose_file).set_tail("500").get_tail_compose_log()
stdout, stderr = public.ExecShell(command)
return public.returnResult(True, data=stdout)
else:
if get.log_file is None:
return public.returnResult(False, msg="请传日志文件路径:log_file")
log_body = public.readFile(get.log_file)
return public.returnResult(True, data=log_body)
# 2024/10/31 10:33 获取运行环境版本信息
def get_runtime_versions(self, get):
'''
@name 获取运行环境版本信息
'''
get.runtime_type = get.get("runtime_type", "all")
if get.runtime_type == "": return public.returnResult(False, msg="请传运行环境类型:runtime_type")
if not get.runtime_type in ("all", "php", "java", "go", "python","nodejs"):
return public.returnResult(False, msg="运行环境类型【{}】错误,仅支持:all、php、java、go、python、nodejs".format(get.runtime_type))
repo_urls = [
{
"name": "中国科技大学",
"repo": "mirrors.ustc.edu.cn"
},
{
"name": "网易",
"repo": "mirrors.163.com"
},
{
"name": "阿里云",
"repo": "mirrors.aliyun.com"
},
{
"name": "清华大学",
"repo": "mirrors.tuna.tsinghua.edu.cn"
}]
versions = {
"php": ["8.3", "8.2", "8.1", "8.0", "7.4", "7.3", "7.2", "7.1", "7.0", "5.6"],
"java": ["22", "21", "17", "11", "1.8"],
"go": ["1.22", "1.21"],
"python": ["3.13", "3.12", "3.11", "3.10", "3.9", "3.8", "3.7"],
"nodejs": ["25.1.0","25","24", "23", "22.21.1","21.7.3","20.19.5","18.20.8"],
"repo_urls": repo_urls
}
if os.path.exists(self.versions_file):
new_versions = public.readFile(self.versions_file)
if new_versions:
try:
new_versions = json.loads(new_versions)
if new_versions.get(get.runtime_type,"") != "":
versions = new_versions
else:
get.force_update = 1
self.check_templates(get)
except:
pass
if get.runtime_type != "all":
versions = {get.runtime_type: versions.get(get.runtime_type, [])}
if get.runtime_type == "nodejs":
versions["repo_urls"] = [
{"name": "淘宝源","repo": "https://registry.npmmirror.com/"},
{"name": "阿里源","repo": "https://npm.aliyun.com/"},
{"name": "网易源","repo": "https://mirrors.163.com/npm/"},
{"name": "中国科学技术大学源","repo": "https://mirrors.ustc.edu.cn/npm/"},
{"name": "清华大学源","repo": "https://mirrors.tuna.tsinghua.edu.cn/npm/"},
]
else:
versions["repo_urls"] = repo_urls
return public.returnResult(data=versions)
# 2024/10/31 10:34 获取扩展模板列表
def get_php_ext_list(self, get):
'''
@name 获取扩展模板列表
'''
get.p = get.get("p", 1)
get.row = get.get("row", 10)
exts = dp.sql("ext_templates").select()
page_data = self.get_page(exts, get)
return self.pageResult(True, data=page_data["data"], page=page_data["page"])
# 2024/10/31 15:56 获取所有支持的扩展列表
def get_all_exts(self, get):
'''
@name 获取所有支持的扩展列表
'''
get.version = get.get("version", "all")
if not os.path.exists(self.exts_file): self.check_templates(get)
try:
exts = json.loads(public.readFile(self.exts_file))
if get.version != "all": exts = {get.version: exts.get(get.version, [])}
return public.returnResult(data=exts)
except:
import traceback
return public.returnResult(False, data={}, msg=traceback.format_exc())
# 2024/10/31 10:34 创建扩展模板
def create_php_ext_template(self, get):
'''
@name 创建扩展模板
'''
get.name = get.get("name", None)
if get.name is None: return public.returnResult(False, msg="请传模板名称:name")
get.version = get.get("version", None)
if get.version is None: return public.returnResult(False, msg="请传模板版本:version")
get.exts = get.get("exts", None)
if get.exts is None: return public.returnResult(False, msg="请传模板扩展:exts")
find_result = dp.sql("ext_templates").where("name=?", get.name).find()
if find_result: return public.returnResult(False, msg="模板【{}】已存在,请更换其他名称!".format(get.name))
dp.sql("ext_templates").insert({
"name": get.name,
"version": get.version,
"exts": get.exts,
"addtime": int(time.time())
})
return public.returnResult(msg="创建扩展【{}】成功".format(get.name))
# 2024/10/31 10:34 删除指定扩展模板
def delete_php_ext_template(self, get):
'''
@name 删除指定扩展模板
'''
get.id = get.get("id", None)
if get.id is None: return public.returnResult(False, msg="请传模板ID:id")
find_result = dp.sql("ext_templates").where("id=?", get.id).find()
if not find_result: return public.returnResult(False, msg="模板不存在")
dp.sql("ext_templates").where("id=?", get.id).delete()
find_result = dp.sql("ext_templates").where("id=?", get.id).find()
if find_result: return public.returnResult(False, msg="删除失败")
return public.returnResult(msg="删除成功")
# 2024/10/31 10:34 批量删除指定扩展模板
def batch_delete_php_ext_template(self, get):
'''
@name 批量删除指定扩展模板
'''
get.ids = get.get("ids", None)
if get.ids is None: return public.returnResult(False, msg="请传模板ID:ids")
get.ids = get.ids.split(",")
delete_result = []
for id in get.ids:
find_result = dp.sql("ext_templates").where("id=?", id).find()
if not find_result:
delete_result.append({"id": id, "status": False, "msg": "模板不存在"})
continue
dp.sql("ext_templates").where("id=?", id).delete()
find_result = dp.sql("ext_templates").where("id=?", id).find()
if find_result:
delete_result.append({"id": id, "status": False, "msg": "删除失败"})
continue
delete_result.append({"id": id, "status": True, "msg": "删除成功"})
return public.returnResult(msg="批量删除成功", data=delete_result)
# 2024/10/31 10:35 编辑扩展模板
def modify_php_ext_template(self, get):
'''
@name 编辑扩展模板
'''
get.id = get.get("id", None)
if get.id is None: return public.returnResult(False, msg="请传模板ID:id")
get.version = get.get("version", None)
if get.version is None: return public.returnResult(False, msg="请传模板版本:version")
get.exts = get.get("exts", None)
if get.exts is None: return public.returnResult(False, msg="请传模板扩展:exts")
find_result = dp.sql("ext_templates").where("id=?", get.id).find()
if not find_result: return public.returnResult(False, msg="模板不存在")
dp.sql("ext_templates").where("id=?", get.id).update({
"version": get.version,
"exts": get.exts
})
return public.returnResult(msg="编辑成功")