feat: 运行环境支持增加环境变量 (#6652)

Refs https://github.com/1Panel-dev/1Panel/issues/4262
This commit is contained in:
zhengkunwang 2024-10-08 21:56:55 +08:00 committed by GitHub
parent 6c3311ba3c
commit e3329597bc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 291 additions and 233 deletions

View file

@ -1,6 +1,8 @@
package request
import "github.com/1Panel-dev/1Panel/agent/app/dto"
import (
"github.com/1Panel-dev/1Panel/agent/app/dto"
)
type RuntimeSearch struct {
dto.PageInfo
@ -27,6 +29,12 @@ type NodeConfig struct {
Clean bool `json:"clean"`
Port int `json:"port"`
ExposedPorts []ExposedPort `json:"exposedPorts"`
Environments []Environment `json:"environments"`
}
type Environment struct {
Key string `json:"key"`
Value string `json:"value"`
}
type ExposedPort struct {

View file

@ -26,6 +26,7 @@ type RuntimeDTO struct {
Port int `json:"port"`
Path string `json:"path"`
ExposedPorts []request.ExposedPort `json:"exposedPorts"`
Environments []request.Environment `json:"environments"`
}
type PackageScripts struct {

View file

@ -618,10 +618,6 @@ func (a *AppInstallService) DeleteCheck(installID uint) ([]dto.AppResource, erro
if err != nil {
return nil, err
}
//app, err := appRepo.GetFirst(commonRepo.WithByID(appInstall.AppId))
//if err != nil {
// return nil, err
//}
websites, _ := websiteRepo.GetBy(websiteRepo.WithAppInstallId(appInstall.ID))
for _, website := range websites {
res = append(res, dto.AppResource{
@ -629,17 +625,14 @@ func (a *AppInstallService) DeleteCheck(installID uint) ([]dto.AppResource, erro
Name: website.PrimaryDomain,
})
}
//TODO 根据运行环境情况处理
//if app.Type == constant.Runtime {
// resources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithLinkId(appInstall.ID), commonRepo.WithByFrom(constant.AppResourceLocal))
// for _, resource := range resources {
// linkInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(resource.AppInstallId))
// res = append(res, dto.AppResource{
// Type: "app",
// Name: linkInstall.Name,
// })
// }
//}
resources, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithLinkId(appInstall.ID), commonRepo.WithByFrom(constant.AppResourceLocal))
for _, resource := range resources {
linkInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(resource.AppInstallId))
res = append(res, dto.AppResource{
Type: "app",
Name: linkInstall.Name,
})
}
return res, nil
}

View file

@ -161,7 +161,7 @@ func (r *RuntimeService) Create(create request.RuntimeCreate) (*model.Runtime, e
return nil, err
}
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo:
runtime.Port = create.Port
runtime.Port = int(create.Params["port"].(float64))
if err = handleNodeAndJava(create, runtime, fileOp, appVersionDir); err != nil {
return nil, err
}
@ -347,7 +347,7 @@ func (r *RuntimeService) Get(id uint) (*response.RuntimeDTO, error) {
}
for k, v := range envs {
switch k {
case "NODE_APP_PORT", "PANEL_APP_PORT_HTTP", "JAVA_APP_PORT", "GO_APP_PORT":
case "NODE_APP_PORT", "PANEL_APP_PORT_HTTP", "JAVA_APP_PORT", "GO_APP_PORT", "APP_PORT", "port":
port, err := strconv.Atoi(v)
if err != nil {
return nil, err
@ -379,6 +379,14 @@ func (r *RuntimeService) Get(id uint) (*response.RuntimeDTO, error) {
if v, ok := envs["CONTAINER_PACKAGE_URL"]; ok {
res.Source = v
}
composeByte, err := files.NewFileOp().GetContent(runtime.GetComposePath())
if err != nil {
return nil, err
}
res.Environments, err = getDockerComposeEnvironments(composeByte)
if err != nil {
return nil, err
}
}
return &res, nil
@ -395,6 +403,7 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
}
oldImage := runtime.Image
oldEnv := runtime.Env
req.Port = int(req.Params["port"].(float64))
switch runtime.Type {
case constant.RuntimePHP:
exist, _ := runtimeRepo.GetFirst(runtimeRepo.WithImage(req.Name), runtimeRepo.WithNotId(req.ID))
@ -451,6 +460,7 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error {
Port: req.Port,
Install: true,
ExposedPorts: req.ExposedPorts,
Environments: req.Environments,
},
}
composeContent, envContent, _, err := handleParams(create, projectDir)

View file

@ -207,6 +207,33 @@ func getRuntimeEnv(envStr, key string) string {
return ""
}
func getRuntimeEnvironments(composeByte []byte) ([]request.Environment, error) {
var environments []request.Environment
var composeMap map[string]interface{}
if err := yaml.Unmarshal(composeByte, &composeMap); err != nil {
return nil, err
}
services, ok := composeMap["services"].(map[string]interface{})
if !ok {
return nil, buserr.New(constant.ErrFileParse)
}
for _, service := range services {
envs, ok := service.(map[string]interface{})["environment"].([]interface{})
if !ok {
continue
}
for _, env := range envs {
envStr := env.(string)
envArray := strings.Split(envStr, "=")
environments = append(environments, request.Environment{
Key: envArray[0],
Value: envArray[1],
})
}
}
return environments, nil
}
func buildRuntime(runtime *model.Runtime, oldImageID string, oldEnv string, rebuild bool) {
runtimePath := runtime.GetPath()
composePath := runtime.GetComposePath()
@ -315,6 +342,11 @@ func handleParams(create request.RuntimeCreate, projectDir string) (composeConte
if err != nil {
return
}
for k := range env {
if strings.HasPrefix(k, "CONTAINER_PORT_") || strings.HasPrefix(k, "HOST_PORT_") {
delete(env, k)
}
}
switch create.Type {
case constant.RuntimePHP:
create.Params["IMAGE_NAME"] = create.Image
@ -357,7 +389,7 @@ func handleParams(create request.RuntimeCreate, projectDir string) (composeConte
create.Params["RUN_INSTALL"] = "0"
}
create.Params["CONTAINER_PACKAGE_URL"] = create.Source
create.Params["NODE_APP_PORT"] = create.Params["APP_PORT"]
composeContent, err = handleCompose(env, composeContent, create, projectDir)
if err != nil {
return
@ -366,6 +398,7 @@ func handleParams(create request.RuntimeCreate, projectDir string) (composeConte
create.Params["CODE_DIR"] = create.CodeDir
create.Params["JAVA_VERSION"] = create.Version
create.Params["PANEL_APP_PORT_HTTP"] = create.Port
create.Params["JAVA_APP_PORT"] = create.Params["APP_PORT"]
composeContent, err = handleCompose(env, composeContent, create, projectDir)
if err != nil {
return
@ -374,6 +407,7 @@ func handleParams(create request.RuntimeCreate, projectDir string) (composeConte
create.Params["CODE_DIR"] = create.CodeDir
create.Params["GO_VERSION"] = create.Version
create.Params["PANEL_APP_PORT_HTTP"] = create.Port
create.Params["GO_APP_PORT"] = create.Params["APP_PORT"]
composeContent, err = handleCompose(env, composeContent, create, projectDir)
if err != nil {
return
@ -416,7 +450,6 @@ func handleCompose(env gotenv.Env, composeContent []byte, create request.Runtime
_, ok := serviceValue["ports"].([]interface{})
if ok {
var ports []interface{}
switch create.Type {
case constant.RuntimeNode:
ports = append(ports, "${HOST_IP}:${PANEL_APP_PORT_HTTP}:${NODE_APP_PORT}")
@ -426,7 +459,6 @@ func handleCompose(env gotenv.Env, composeContent []byte, create request.Runtime
ports = append(ports, "${HOST_IP}:${PANEL_APP_PORT_HTTP}:${GO_APP_PORT}")
}
for i, port := range create.ExposedPorts {
containerPortStr := fmt.Sprintf("CONTAINER_PORT_%d", i)
hostPortStr := fmt.Sprintf("HOST_PORT_%d", i)
@ -438,6 +470,13 @@ func handleCompose(env gotenv.Env, composeContent []byte, create request.Runtime
}
serviceValue["ports"] = ports
}
var environments []interface{}
for _, e := range create.Environments {
environments = append(environments, fmt.Sprintf("%s:%s", e.Key, e.Value))
}
if len(environments) > 0 {
serviceValue["environment"] = environments
}
break
}
for k := range env {
@ -582,3 +621,30 @@ func restartRuntime(runtime *model.Runtime) (err error) {
}
return
}
func getDockerComposeEnvironments(yml []byte) ([]request.Environment, error) {
var (
composeProject docker.ComposeProject
err error
)
err = yaml.Unmarshal(yml, &composeProject)
if err != nil {
return nil, err
}
var res []request.Environment
for _, service := range composeProject.Services {
for _, env := range service.Environment {
envArray := strings.Split(env, ":")
key := envArray[0]
value := ""
if len(envArray) > 1 {
value = envArray[1]
}
res = append(res, request.Environment{
Key: key,
Value: value,
})
}
}
return res, nil
}

View file

@ -53,7 +53,8 @@ type ComposeProject struct {
}
type Service struct {
Image string `yaml:"image"`
Image string `yaml:"image"`
Environment []string `yaml:"environment"`
}
func replaceEnvVariables(input string, envVars map[string]string) string {

View file

@ -39,6 +39,7 @@ export namespace Runtime {
source?: string;
path?: string;
exposedPorts?: ExposedPort[];
environments?: Environment[];
}
export interface RuntimeCreate {
@ -56,6 +57,7 @@ export namespace Runtime {
codeDir?: string;
port?: number;
exposedPorts?: ExposedPort[];
environments?: Environment[];
}
export interface ExposedPort {
@ -63,6 +65,11 @@ export namespace Runtime {
containerPort: number;
}
export interface Environment {
key: string;
value: string;
}
export interface RuntimeUpdate {
name: string;
appDetailID: number;

View file

@ -34,7 +34,6 @@
{{ $t('file.download') }}
</el-button>
</div>
<div class="mt-2.5">
<highlightjs
ref="editorRef"
@ -57,8 +56,8 @@ import { GlobalStore } from '@/store';
import screenfull from 'screenfull';
import { DownloadFile } from '@/api/modules/container';
const logInfo = ref();
const terminalSocket = ref<WebSocket>();
const logInfo = ref('');
const logSocket = ref<WebSocket>();
const open = ref(false);
const resource = ref('');
const globalStore = GlobalStore();
@ -78,7 +77,7 @@ const logSearch = reactive({
});
const handleClose = () => {
terminalSocket.value?.send('close conn');
logSocket.value?.send('close conn');
open.value = false;
};
@ -120,16 +119,16 @@ const searchLogs = async () => {
MsgError(i18n.global.t('container.linesHelper'));
return;
}
terminalSocket.value?.send('close conn');
terminalSocket.value?.close();
logSocket.value?.send('close conn');
logSocket.value?.close();
logInfo.value = '';
const href = window.location.href;
const protocol = href.split('//')[0] === 'http:' ? 'ws' : 'wss';
const host = href.split('//')[1].split('/')[0];
terminalSocket.value = new WebSocket(
logSocket.value = new WebSocket(
`${protocol}://${host}/api/v2/containers/compose/search/log?compose=${logSearch.compose}&since=${logSearch.mode}&tail=${logSearch.tail}&follow=${logSearch.isWatch}`,
);
terminalSocket.value.onmessage = (event) => {
logSocket.value.onmessage = (event) => {
logInfo.value += event.data;
nextTick(() => {
console.log(scrollerElement.value);
@ -179,7 +178,6 @@ const acceptParams = (props: DialogProps): void => {
logSearch.mode = timeOptions.value[3].value;
logSearch.isWatch = true;
resource.value = props.resource;
searchLogs();
open.value = true;
if (!mobile.value) {
screenfull.on('change', () => {
@ -188,6 +186,7 @@ const acceptParams = (props: DialogProps): void => {
}
nextTick(() => {
if (editorRef.value) {
searchLogs();
scrollerElement.value = editorRef.value.$el as HTMLElement;
let hljsDom = scrollerElement.value.querySelector('.hljs') as HTMLElement;
hljsDom.style['min-height'] = '300px';

View file

@ -2530,6 +2530,9 @@ const message = {
start_servers: 'number of processes created at startup',
min_spare_servers: 'minimum number of idle processes',
max_spare_servers: 'maximum number of idle processes',
envKey: 'Name',
envValue: 'Value',
environment: 'Environment Variable',
},
process: {
pid: 'Process ID',

View file

@ -2347,6 +2347,9 @@ const message = {
start_servers: '啟動時所建立的進程數',
min_spare_servers: '最小空閒行程數',
max_spare_servers: '最大空閒行程數',
envKey: '名稱',
envValue: '值',
environment: '環境變數',
},
process: {
pid: '進程ID',

View file

@ -2346,6 +2346,9 @@ const message = {
start_servers: '启动时创建的进程数',
min_spare_servers: '最小空闲进程数',
max_spare_servers: '最大空闲进程数',
envKey: '名称',
envValue: '值',
environment: '环境变量',
},
process: {
pid: '进程ID',

View file

@ -0,0 +1,57 @@
<template>
<el-row :gutter="20">
<el-col :span="4">
<el-button @click="addEnv">{{ $t('commons.button.add') }}{{ $t('runtime.environment') }}</el-button>
</el-col>
</el-row>
<div class="mt-1.5">
<el-row :gutter="20" v-for="(env, index) in environments" :key="index">
<el-col :span="7">
<el-form-item :prop="`environments.${index}.key`" :rules="rules.value">
<el-input v-model="env.key" :placeholder="$t('runtime.envKey')" />
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item :prop="`environments.${index}.value`" :rules="rules.value">
<el-input v-model="env.value" :placeholder="$t('runtime.envValue')" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item>
<el-button type="primary" @click="removeEnv(index)" link>
{{ $t('commons.button.delete') }}
</el-button>
</el-form-item>
</el-col>
</el-row>
</div>
</template>
<script setup lang="ts">
import { defineProps, reactive } from 'vue';
import { FormRules } from 'element-plus';
import { Rules } from '@/global/form-rules';
import { Runtime } from '@/api/interface/runtime';
const props = defineProps({
environments: {
type: Array<Runtime.Environment>,
required: true,
},
});
const rules = reactive<FormRules>({
value: [Rules.requiredInput],
});
const addEnv = () => {
props.environments.push({
key: '',
value: '',
});
};
const removeEnv = (index: number) => {
props.environments.splice(index, 1);
};
</script>

View file

@ -77,67 +77,18 @@
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="7">
<el-form-item :label="$t('runtime.appPort')" prop="params.GO_APP_PORT">
<el-input v-model.number="runtime.params['GO_APP_PORT']" />
<span class="input-help">{{ $t('runtime.appPortHelper') }}</span>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item :label="$t('runtime.externalPort')" prop="port">
<el-input v-model.number="runtime.port" />
<span class="input-help">{{ $t('runtime.externalPortHelper') }}</span>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item :label="$t('commons.button.add') + $t('commons.table.port')">
<el-button @click="addPort">
<el-icon><Plus /></el-icon>
</el-button>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('app.allowPort')" prop="params.HOST_IP">
<el-switch
v-model="runtime.params['HOST_IP']"
:active-value="'0.0.0.0'"
:inactive-value="'127.0.0.1'"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" v-for="(port, index) of runtime.exposedPorts" :key="index">
<el-col :span="7">
<el-form-item :prop="'exposedPorts.' + index + '.containerPort'" :rules="rules.params.GO_APP_PORT">
<el-input v-model.number="port.containerPort" :placeholder="$t('runtime.appPort')" />
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item :prop="'exposedPorts.' + index + '.hostPort'" :rules="rules.params.GO_APP_PORT">
<el-input v-model.number="port.hostPort" :placeholder="$t('runtime.externalPort')" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item>
<el-button type="primary" @click="removePort(index)" link>
{{ $t('commons.button.delete') }}
</el-button>
</el-form-item>
</el-col>
</el-row>
<PortConfig :params="runtime.params" :exposedPorts="runtime.exposedPorts" :rules="rules" />
<Environment :environments="runtime.environments" />
<el-form-item :label="$t('app.containerName')" prop="params.CONTAINER_NAME">
<el-input v-model.trim="runtime.params['CONTAINER_NAME']"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span>
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
<el-button type="primary" @click="submit(runtimeForm)" :disabled="loading">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
<el-button type="primary" @click="submit(runtimeForm)" :disabled="loading">
{{ $t('commons.button.confirm') }}
</el-button>
</template>
</DrawerPro>
</template>
@ -152,6 +103,8 @@ import i18n from '@/lang';
import { MsgError, MsgSuccess } from '@/utils/message';
import { FormInstance } from 'element-plus';
import { reactive, ref, watch } from 'vue';
import PortConfig from '@/views/website/runtime/port/index.vue';
import Environment from '@/views/website/runtime/environment/index.vue';
interface OperateRrops {
id?: number;
@ -185,6 +138,7 @@ const initData = (type: string) => ({
codeDir: '/',
port: 8080,
exposedPorts: [],
environments: [],
});
let runtime = reactive<Runtime.RuntimeCreate>(initData('go'));
const rules = ref<any>({
@ -194,7 +148,7 @@ const rules = ref<any>({
port: [Rules.requiredInput, Rules.paramPort, checkNumberRange(1, 65535)],
source: [Rules.requiredSelect],
params: {
GO_APP_PORT: [Rules.requiredInput, Rules.paramPort, checkNumberRange(1, 65535)],
APP_PORT: [Rules.requiredInput, Rules.paramPort, checkNumberRange(1, 65535)],
HOST_IP: [Rules.requiredSelect],
CONTAINER_NAME: [Rules.requiredInput, Rules.containerName],
EXEC_SCRIPT: [Rules.requiredInput],
@ -204,7 +158,7 @@ const scripts = ref<Runtime.NodeScripts[]>([]);
const em = defineEmits(['close']);
watch(
() => runtime.params['GO_APP_PORT'],
() => runtime.params['APP_PORT'],
(newVal) => {
if (newVal && mode.value == 'create') {
runtime.port = newVal;
@ -233,17 +187,6 @@ const getPath = (codeDir: string) => {
runtime.codeDir = codeDir;
};
const addPort = () => {
runtime.exposedPorts.push({
hostPort: undefined,
containerPort: undefined,
});
};
const removePort = (index: number) => {
runtime.exposedPorts.splice(index, 1);
};
const searchApp = (appID: number) => {
SearchApp(appReq).then((res) => {
apps.value = res.data.items || [];
@ -303,7 +246,7 @@ const submit = async (formEl: FormInstance | undefined) => {
if (runtime.exposedPorts && runtime.exposedPorts.length > 0) {
const containerPortMap = new Map();
const hostPortMap = new Map();
containerPortMap[runtime.params['GO_APP_PORT']] = true;
containerPortMap[runtime.params['APP_PORT']] = true;
hostPortMap[runtime.port] = true;
for (const port of runtime.exposedPorts) {
if (containerPortMap[port.containerPort]) {
@ -363,6 +306,7 @@ const getRuntime = async (id: number) => {
port: data.port,
});
runtime.exposedPorts = data.exposedPorts || [];
runtime.environments = data.environments || [];
editParams.value = data.appParams;
searchApp(data.appID);
open.value = true;

View file

@ -76,58 +76,8 @@
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="7">
<el-form-item :label="$t('runtime.appPort')" prop="params.JAVA_APP_PORT">
<el-input v-model.number="runtime.params['JAVA_APP_PORT']" />
<span class="input-help">{{ $t('runtime.appPortHelper') }}</span>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item :label="$t('runtime.externalPort')" prop="port">
<el-input v-model.number="runtime.port" />
<span class="input-help">{{ $t('runtime.externalPortHelper') }}</span>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item :label="$t('commons.button.add') + $t('commons.table.port')">
<el-button @click="addPort">
<el-icon><Plus /></el-icon>
</el-button>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('app.allowPort')" prop="params.HOST_IP">
<el-switch
v-model="runtime.params['HOST_IP']"
:active-value="'0.0.0.0'"
:inactive-value="'127.0.0.1'"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" v-for="(port, index) of runtime.exposedPorts" :key="index">
<el-col :span="7">
<el-form-item
:prop="'exposedPorts.' + index + '.containerPort'"
:rules="rules.params.JAVA_APP_PORT"
>
<el-input v-model.number="port.containerPort" :placeholder="$t('runtime.appPort')" />
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item :prop="'exposedPorts.' + index + '.hostPort'" :rules="rules.params.JAVA_APP_PORT">
<el-input v-model.number="port.hostPort" :placeholder="$t('runtime.externalPort')" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item>
<el-button type="primary" @click="removePort(index)" link>
{{ $t('commons.button.delete') }}
</el-button>
</el-form-item>
</el-col>
</el-row>
<PortConfig :params="runtime.params" :exposedPorts="runtime.exposedPorts" :rules="rules" />
<Environment :environments="runtime.environments" />
<el-form-item :label="$t('app.containerName')" prop="params.CONTAINER_NAME">
<el-input v-model.trim="runtime.params['CONTAINER_NAME']"></el-input>
</el-form-item>
@ -153,6 +103,8 @@ import i18n from '@/lang';
import { MsgError, MsgSuccess } from '@/utils/message';
import { FormInstance } from 'element-plus';
import { reactive, ref, watch } from 'vue';
import PortConfig from '@/views/website/runtime/port/index.vue';
import Environment from '@/views/website/runtime/environment/index.vue';
interface OperateRrops {
id?: number;
@ -186,6 +138,7 @@ const initData = (type: string) => ({
codeDir: '/',
port: 8080,
exposedPorts: [],
environments: [],
});
let runtime = reactive<Runtime.RuntimeCreate>(initData('java'));
const rules = ref<any>({
@ -195,7 +148,6 @@ const rules = ref<any>({
port: [Rules.requiredInput, Rules.paramPort, checkNumberRange(1, 65535)],
source: [Rules.requiredSelect],
params: {
JAVA_APP_PORT: [Rules.requiredInput, Rules.paramPort, checkNumberRange(1, 65535)],
HOST_IP: [Rules.requiredSelect],
CONTAINER_NAME: [Rules.requiredInput, Rules.containerName],
EXEC_SCRIPT: [Rules.requiredInput],
@ -205,7 +157,7 @@ const scripts = ref<Runtime.NodeScripts[]>([]);
const em = defineEmits(['close']);
watch(
() => runtime.params['JAVA_APP_PORT'],
() => runtime.params['APP_PORT'],
(newVal) => {
if (newVal && mode.value == 'create') {
runtime.port = newVal;
@ -234,17 +186,6 @@ const getPath = (codeDir: string) => {
runtime.codeDir = codeDir;
};
const addPort = () => {
runtime.exposedPorts.push({
hostPort: undefined,
containerPort: undefined,
});
};
const removePort = (index: number) => {
runtime.exposedPorts.splice(index, 1);
};
const searchApp = (appID: number) => {
SearchApp(appReq).then((res) => {
apps.value = res.data.items || [];
@ -304,7 +245,7 @@ const submit = async (formEl: FormInstance | undefined) => {
if (runtime.exposedPorts && runtime.exposedPorts.length > 0) {
const containerPortMap = new Map();
const hostPortMap = new Map();
containerPortMap[runtime.params['JAVA_APP_PORT']] = true;
containerPortMap[runtime.params['APP_PORT']] = true;
hostPortMap[runtime.port] = true;
for (const port of runtime.exposedPorts) {
if (containerPortMap[port.containerPort]) {
@ -364,6 +305,7 @@ const getRuntime = async (id: number) => {
port: data.port,
});
runtime.exposedPorts = data.exposedPorts || [];
runtime.environments = data.environments || [];
editParams.value = data.appParams;
searchApp(data.appID);
open.value = true;

View file

@ -103,58 +103,8 @@
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="7">
<el-form-item :label="$t('runtime.appPort')" prop="params.NODE_APP_PORT">
<el-input v-model.number="runtime.params['NODE_APP_PORT']" />
<span class="input-help">{{ $t('runtime.appPortHelper') }}</span>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item :label="$t('runtime.externalPort')" prop="port">
<el-input v-model.number="runtime.port" />
<span class="input-help">{{ $t('runtime.externalPortHelper') }}</span>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item :label="$t('commons.button.add') + $t('commons.table.port')">
<el-button @click="addPort">
<el-icon><Plus /></el-icon>
</el-button>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('app.allowPort')" prop="params.HOST_IP">
<el-switch
v-model="runtime.params['HOST_IP']"
:active-value="'0.0.0.0'"
:inactive-value="'127.0.0.1'"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" v-for="(port, index) of runtime.exposedPorts" :key="index">
<el-col :span="7">
<el-form-item
:prop="'exposedPorts.' + index + '.containerPort'"
:rules="rules.params.NODE_APP_PORT"
>
<el-input v-model.number="port.containerPort" :placeholder="$t('runtime.appPort')" />
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item :prop="'exposedPorts.' + index + '.hostPort'" :rules="rules.params.NODE_APP_PORT">
<el-input v-model.number="port.hostPort" :placeholder="$t('runtime.externalPort')" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item>
<el-button type="primary" @click="removePort(index)" link>
{{ $t('commons.button.delete') }}
</el-button>
</el-form-item>
</el-col>
</el-row>
<PortConfig :params="runtime.params" :exposedPorts="runtime.exposedPorts" :rules="rules" />
<Environment :environments="runtime.environments" />
<el-form-item :label="$t('runtime.packageManager')" prop="params.PACKAGE_MANAGER">
<el-select v-model="runtime.params['PACKAGE_MANAGER']">
<el-option label="npm" value="npm"></el-option>
@ -201,6 +151,8 @@ import i18n from '@/lang';
import { MsgError, MsgSuccess } from '@/utils/message';
import { FormInstance } from 'element-plus';
import { computed, reactive, ref, watch } from 'vue';
import PortConfig from '@/views/website/runtime/port/index.vue';
import Environment from '@/views/website/runtime/environment/index.vue';
interface OperateRrops {
id?: number;
@ -237,6 +189,7 @@ const initData = (type: string) => ({
port: 3000,
source: 'https://registry.npmjs.org/',
exposedPorts: [],
environments: [],
});
let runtime = reactive<Runtime.RuntimeCreate>(initData('node'));
const rules = ref<any>({
@ -246,7 +199,6 @@ const rules = ref<any>({
port: [Rules.requiredInput, Rules.paramPort, checkNumberRange(1, 65535)],
source: [Rules.requiredSelect],
params: {
NODE_APP_PORT: [Rules.requiredInput, Rules.paramPort, checkNumberRange(1, 65535)],
PACKAGE_MANAGER: [Rules.requiredSelect],
HOST_IP: [Rules.requiredSelect],
EXEC_SCRIPT: [Rules.requiredSelect],
@ -279,7 +231,7 @@ const imageSources = [
];
watch(
() => runtime.params['NODE_APP_PORT'],
() => runtime.params['APP_PORT'],
(newVal) => {
if (newVal && mode.value == 'create') {
runtime.port = newVal;
@ -316,17 +268,6 @@ const changeScriptType = () => {
}
};
const addPort = () => {
runtime.exposedPorts.push({
hostPort: undefined,
containerPort: undefined,
});
};
const removePort = (index: number) => {
runtime.exposedPorts.splice(index, 1);
};
const getScripts = () => {
GetNodeScripts({ codeDir: runtime.codeDir }).then((res) => {
scripts.value = res.data;
@ -398,7 +339,7 @@ const submit = async (formEl: FormInstance | undefined) => {
if (runtime.exposedPorts && runtime.exposedPorts.length > 0) {
const containerPortMap = new Map();
const hostPortMap = new Map();
containerPortMap[runtime.params['NODE_APP_PORT']] = true;
containerPortMap[runtime.params['APP_PORT']] = true;
hostPortMap[runtime.port] = true;
for (const port of runtime.exposedPorts) {
if (containerPortMap[port.containerPort]) {
@ -458,6 +399,7 @@ const getRuntime = async (id: number) => {
port: data.port,
});
runtime.exposedPorts = data.exposedPorts || [];
runtime.environments = data.environments || [];
editParams.value = data.appParams;
searchApp(data.appID);
if (data.params['CUSTOM_SCRIPT'] == undefined || data.params['CUSTOM_SCRIPT'] == '0') {

View file

@ -0,0 +1,80 @@
<template>
<el-row :gutter="20">
<el-col :span="7">
<el-form-item :label="$t('runtime.appPort')" prop="params.APP_PORT" :rules="rules.port">
<el-input v-model.number="params.APP_PORT" />
<span class="input-help">{{ $t('runtime.appPortHelper') }}</span>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item :label="$t('runtime.externalPort')" prop="params.port" :rules="rules.port">
<el-input v-model.number="params.port" />
<span class="input-help">{{ $t('runtime.externalPortHelper') }}</span>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item :label="$t('commons.button.add') + $t('commons.table.port')">
<el-button @click="addPort">
<el-icon><Plus /></el-icon>
</el-button>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item :label="$t('app.allowPort')">
<el-switch v-model="params.HOST_IP" :active-value="'0.0.0.0'" :inactive-value="'127.0.0.1'" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" v-for="(port, index) in exposedPorts" :key="index">
<el-col :span="7">
<el-form-item :prop="`exposedPorts.${index}.containerPort`" :rules="rules.port">
<el-input v-model.number="port.containerPort" :placeholder="$t('runtime.appPort')" />
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item :prop="`exposedPorts.${index}.hostPort`" :rules="rules.port">
<el-input v-model.number="port.hostPort" :placeholder="$t('runtime.externalPort')" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item>
<el-button type="primary" @click="removePort(index)" link>
{{ $t('commons.button.delete') }}
</el-button>
</el-form-item>
</el-col>
</el-row>
</template>
<script setup lang="ts">
import { Rules, checkNumberRange } from '@/global/form-rules';
import { FormRules } from 'element-plus';
import { defineProps } from 'vue';
import { Runtime } from '@/api/interface/runtime';
const props = defineProps({
params: {
type: Object,
required: true,
},
exposedPorts: {
type: Array<Runtime.ExposedPort>,
required: true,
},
});
const rules = reactive<FormRules>({
port: [Rules.requiredInput, Rules.paramPort, checkNumberRange(1, 65535)],
});
const addPort = () => {
props.exposedPorts.push({
hostPort: undefined,
containerPort: undefined,
});
};
const removePort = (index: number) => {
props.exposedPorts.splice(index, 1);
};
</script>

View file

@ -49,7 +49,6 @@
</DrawerPro>
</template>
<script lang="ts" setup>
import DrawerHeader from '@/components/drawer-header/index.vue';
import { GetCA } from '@/api/modules/website';
import { ref } from 'vue';