| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| 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) |
|
|
| |
| 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, "模板更新成功!") |
|
|
| |
| 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() |
|
|
| |
| 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) |
|
|
| |
| 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) |
|
|
| |
| return public.returnResult() |
|
|
| |
| 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) |
|
|
| |
| 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) |
|
|
| |
| 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) |
|
|
| |
| def handle_ports(self, ports): |
| ''' |
| @name 处理端口配置信息 |
| ''' |
| |
| ports = json.loads(ports) |
| |
| 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 |
|
|
| |
| 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) |
|
|
| |
| 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"]) |
|
|
| |
| 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 |
|
|
| |
| 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 |
|
|
| |
| 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)) |
|
|
| |
| 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 |
|
|
| |
| 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="编辑成功") |
|
|
| |
| 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="删除成功") |
|
|
| |
| 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) |
|
|
| |
| 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="清理所有构建缓存成功") |
|
|
| |
| 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)) |
|
|
| |
| 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) |
|
|
| |
| 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) |
|
|
| |
| 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"]) |
|
|
| |
| 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()) |
|
|
| |
| 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)) |
|
|
| |
| 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="删除成功") |
|
|
| |
| 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) |
|
|
| |
| 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="编辑成功") |
|
|