feat: Add support for switching image versions in runtime environments. (#13730)

This commit is contained in:
CityFun authored and GitHub committed 2026-09-07 18:30:27 +08:00
1 parent 50a54d0613
commit bad022f524
5 files changed
+82 -45

No files matched your search

+9 -8
View File
@@ -66,14 +66,15 @@ type RuntimeDelete struct {
}
type RuntimeUpdate struct {
Name string `json:"name"`
ID uint `json:"id"`
Image string `json:"image"`
Version string `json:"version"`
Rebuild bool `json:"rebuild"`
Source string `json:"source"`
CodeDir string `json:"codeDir"`
Remark string `json:"remark"`
AppDetailID uint `json:"appDetailId"`
Name string `json:"name"`
ID uint `json:"id"`
Image string `json:"image"`
Version string `json:"version"`
Rebuild bool `json:"rebuild"`
Source string `json:"source"`
CodeDir string `json:"codeDir"`
Remark string `json:"remark"`
Params map[string]interface{} `json:"params"`
NodeConfig
+47 -22
View File
@@ -640,6 +640,12 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
runtime.Version = req.Version
return runtimeRepo.Save(runtime)
}
appDetail, err := getRuntimeUpdateAppDetail(runtime, req)
if err != nil {
return err
}
versionChanged := appDetail.ID != runtime.AppDetailID || appDetail.Version != runtime.Version
req.Version = appDetail.Version
oldImage := runtime.Image
oldEnv := runtime.Env
var hostPorts []string
@@ -659,23 +665,6 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
}
}
appDetail, err := appDetailRepo.GetFirst(repo.WithByID(runtime.AppDetailID))
if err != nil {
return err
}
app, err := appRepo.GetFirst(repo.WithByID(appDetail.AppId))
if err != nil {
return err
}
fileOp := files.NewFileOp()
appVersionDir := path.Join(global.Dir.AppResourceDir, app.Resource, app.Key, appDetail.Version)
if !fileOp.Stat(appVersionDir) || appDetail.Update {
if err := downloadApp(app, appDetail, nil, nil); err != nil {
return err
}
_ = fileOp.Rename(path.Join(runtime.GetPath(), "run.sh"), path.Join(runtime.GetPath(), "run.sh.bak"))
_ = fileOp.CopyFile(path.Join(appVersionDir, "run.sh"), runtime.GetPath())
}
}
if containerName, ok := req.Params["CONTAINER_NAME"]; ok && containerName != getRuntimeEnv(runtime.Env, "CONTAINER_NAME") {
@@ -685,6 +674,36 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
runtime.ContainerName = containerName.(string)
}
app, err := appRepo.GetFirst(repo.WithByID(appDetail.AppId))
if err != nil {
return err
}
fileOp := files.NewFileOp()
appVersionDir := filepath.Join(app.GetAppResourcePath(), appDetail.Version)
refreshTemplate := !fileOp.Stat(appVersionDir) || appDetail.Update
if err = downloadApp(app, appDetail, nil, nil); err != nil {
return err
}
if versionChanged {
if err = updateRuntimeVersionFiles(runtime, appVersionDir); err != nil {
return err
}
} else if refreshTemplate && runtime.Type != constant.RuntimePHP {
if err = fileOp.CopyFile(filepath.Join(appVersionDir, "run.sh"), runtime.GetPath()); err != nil {
return err
}
}
if runtime.Type == constant.RuntimePHP {
composeContent, err := fileOp.GetContent(runtime.GetComposePath())
if err != nil {
return err
}
req.Environments, err = getDockerComposeEnvironments(composeContent)
if err != nil {
return err
}
}
projectDir := path.Join(global.Dir.RuntimeDir, runtime.Type, runtime.Name)
create := request.RuntimeCreate{
Image: req.Image,
@@ -702,19 +721,21 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
ExtraHosts: req.ExtraHosts,
},
}
composeContent, envContent, _, err := handleParams(create, projectDir)
composeContent, envContent, forms, err := handleParams(create, projectDir)
if err != nil {
return err
}
runtime.Remark = req.Remark
runtime.AppDetailID = appDetail.ID
runtime.Version = appDetail.Version
runtime.Env = string(envContent)
runtime.DockerCompose = string(composeContent)
switch runtime.Type {
case constant.RuntimePHP:
runtime.Image = req.Image
runtime.Params = string(forms)
runtime.Status = constant.StatusBuilding
_ = runtimeRepo.Save(runtime)
client, err := docker.NewClient()
if err != nil {
return err
@@ -724,14 +745,18 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
if err != nil {
return err
}
go buildRuntime(runtime, imageID, oldEnv, req.Rebuild)
if err = runtimeRepo.Save(runtime); err != nil {
return err
}
go buildRuntime(runtime, imageID, oldEnv, req.Rebuild || versionChanged)
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo, constant.RuntimePython, constant.RuntimeDotNet:
runtime.Version = req.Version
runtime.CodeDir = req.CodeDir
runtime.Port = strings.Join(hostPorts, ",")
runtime.Status = constant.StatusReCreating
runtime.ContainerName = req.Params["CONTAINER_NAME"].(string)
_ = runtimeRepo.Save(runtime)
if err = runtimeRepo.Save(runtime); err != nil {
return err
}
go reCreateRuntime(runtime)
}
return nil
+1 -1
View File
@@ -92,7 +92,7 @@ export namespace Runtime {
export interface RuntimeUpdate {
name: string;
appDetailID: number;
appDetailID?: number;
image: string;
params: object;
type: string;
@@ -1,10 +1,10 @@
<template>
<el-form-item :label="$t('app.app')" prop="appID">
<el-form-item :label="$t('app.app')" prop="appDetailID" :rules="Rules.requiredSelect">
<el-row :gutter="20">
<el-col :span="12">
<el-select
v-model="runtime.appID"
:disabled="mode === 'edit'"
:disabled="mode === 'edit' || loadingVersion"
@change="changeApp(runtime.appID)"
class="p-w-200"
>
@@ -14,7 +14,8 @@
<el-col :span="12">
<el-select
v-model="runtime.version"
:disabled="mode === 'edit'"
:disabled="loadingVersion"
:loading="loadingVersion"
@change="changeVersion()"
class="p-w-200"
>
@@ -36,6 +37,7 @@ import { getAppByKey, getAppDetail, getCurrentNodeCustomAppConfig, searchApp } f
import { useVModel } from '@vueuse/core';
import { useGlobalStore } from '@/composables/useGlobalStore';
import { resolveRuntimeAppResource } from '@/utils/runtime-app-resource';
import { Rules } from '@/global/form-rules';
const { isOffline, isXpackOrEE } = useGlobalStore();
const props = defineProps({
@@ -54,6 +56,7 @@ const props = defineProps({
});
const apps = ref<App.AppItem[]>([]);
const appVersions = ref<string[]>([]);
const loadingVersion = ref(false);
const emit = defineEmits(['update:modelValue']);
const runtime = useVModel(props, 'modelValue', emit);
const appReq = reactive({
@@ -73,10 +76,15 @@ const changeApp = (appID: number) => {
};
const changeVersion = async () => {
runtime.value.appDetailID = undefined;
loadingVersion.value = true;
try {
const res = await getAppDetail(runtime.value.appID, runtime.value.version, 'runtime');
runtime.value.appDetailID = res.data.id;
} catch (error) {}
} catch (error) {
} finally {
loadingVersion.value = false;
}
};
const getApp = async (appkey: string, mode: string) => {
@@ -33,7 +33,7 @@
</el-radio-group>
</el-form-item>
<div v-if="runtime.resource === 'appstore'">
<el-form-item :label="$t('app.app')" prop="appID">
<el-form-item :label="$t('app.app')" prop="appDetailID" :rules="Rules.requiredSelect">
<el-row :gutter="20">
<el-col :span="12">
<el-select
@@ -51,12 +51,7 @@
</el-select>
</el-col>
<el-col :span="12">
<el-select
v-model="runtime.version"
:disabled="mode === 'edit'"
@change="changeVersion()"
class="p-w-200"
>
<el-select v-model="runtime.version" @change="changeVersion()" class="p-w-200">
<el-option
v-for="(version, index) in appVersions"
:key="index"
@@ -390,19 +385,27 @@ const changePHPVersion = (version: string) => {
const changeVersion = () => {
loading.value = true;
initParam.value = false;
runtime.appDetailID = undefined;
extensions.value = undefined;
getAppDetail(runtime.appID, runtime.version, 'runtime')
.then((res) => {
runtime.appDetailID = res.data.id;
runtime.image = res.data.image + ':' + runtime.version;
if (mode.value === 'create') {
runtime.image = res.data.image + ':' + runtime.version;
}
appParams.value = res.data.params;
const fileds = res.data.params.formFields;
formFields.value = {};
for (const index in fileds) {
formFields.value[fileds[index]['envKey']] = fileds[index];
runtime.params[fileds[index]['envKey']] = fileds[index]['default'];
const key = fileds[index]['envKey'];
if (mode.value === 'create' || runtime.params[key] === undefined || key === 'PHP_VERSION') {
runtime.params[key] = fileds[index]['default'];
}
if (fileds[index]['envKey'] == 'PHP_VERSION') {
runtime.image = '1panel-php-fpm:' + fileds[index]['default'];
if (mode.value === 'create') {
runtime.image = '1panel-php-fpm:' + fileds[index]['default'];
}
}
}
initParam.value = true;