mirror of
https://gitee.com/fit2cloud-feizhiyun/1Panel.git
synced 2024-12-02 20:08:03 +08:00
feat: 创建容器时,端口支持多种形式 (#790)
This commit is contained in:
parent
14cc97eb44
commit
dd0ca4bcaf
@ -63,8 +63,10 @@ type VolumeHelper struct {
|
|||||||
Mode string `json:"mode"`
|
Mode string `json:"mode"`
|
||||||
}
|
}
|
||||||
type PortHelper struct {
|
type PortHelper struct {
|
||||||
ContainerPort int `json:"containerPort"`
|
HostIP string `json:"hostIP"`
|
||||||
HostPort int `json:"hostPort"`
|
HostPort string `json:"hostPort"`
|
||||||
|
ContainerPort string `json:"containerPort"`
|
||||||
|
Protocol string `json:"protocol"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContainerLog struct {
|
type ContainerLog struct {
|
||||||
|
@ -168,8 +168,19 @@ func (u *ContainerService) Inspect(req dto.InspectReq) (string, error) {
|
|||||||
func (u *ContainerService) ContainerCreate(req dto.ContainerCreate) error {
|
func (u *ContainerService) ContainerCreate(req dto.ContainerCreate) error {
|
||||||
if len(req.ExposedPorts) != 0 {
|
if len(req.ExposedPorts) != 0 {
|
||||||
for _, port := range req.ExposedPorts {
|
for _, port := range req.ExposedPorts {
|
||||||
if common.ScanPort(port.HostPort) {
|
if strings.Contains(port.HostPort, "-") {
|
||||||
return buserr.WithDetail(constant.ErrPortInUsed, port.HostPort, nil)
|
portStart, _ := strconv.Atoi(strings.Split(port.HostPort, "-")[0])
|
||||||
|
portEnd, _ := strconv.Atoi(strings.Split(port.HostPort, "-")[1])
|
||||||
|
for i := portStart; i <= portEnd; i++ {
|
||||||
|
if common.ScanPort(i) {
|
||||||
|
return buserr.WithDetail(constant.ErrPortInUsed, i, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
portItem, _ := strconv.Atoi(port.HostPort)
|
||||||
|
if common.ScanPort(portItem) {
|
||||||
|
return buserr.WithDetail(constant.ErrPortInUsed, portItem, nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,8 +213,8 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerCreate) error {
|
|||||||
if len(req.ExposedPorts) != 0 {
|
if len(req.ExposedPorts) != 0 {
|
||||||
hostConf.PortBindings = make(nat.PortMap)
|
hostConf.PortBindings = make(nat.PortMap)
|
||||||
for _, port := range req.ExposedPorts {
|
for _, port := range req.ExposedPorts {
|
||||||
bindItem := nat.PortBinding{HostPort: strconv.Itoa(port.HostPort)}
|
bindItem := nat.PortBinding{HostPort: port.HostPort, HostIP: port.HostIP}
|
||||||
hostConf.PortBindings[nat.Port(fmt.Sprintf("%d/tcp", port.ContainerPort))] = []nat.PortBinding{bindItem}
|
hostConf.PortBindings[nat.Port(fmt.Sprintf("%s/%s", port.ContainerPort, port.Protocol))] = []nat.PortBinding{bindItem}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(req.Volumes) != 0 {
|
if len(req.Volumes) != 0 {
|
||||||
|
@ -27,8 +27,11 @@ export namespace Container {
|
|||||||
restartPolicy: string;
|
restartPolicy: string;
|
||||||
}
|
}
|
||||||
export interface Port {
|
export interface Port {
|
||||||
containerPort: number;
|
host: string;
|
||||||
hostPort: number;
|
hostIP: string;
|
||||||
|
containerPort: string;
|
||||||
|
hostPort: string;
|
||||||
|
protocol: string;
|
||||||
}
|
}
|
||||||
export interface Volume {
|
export interface Volume {
|
||||||
sourceDir: string;
|
sourceDir: string;
|
||||||
|
@ -455,10 +455,11 @@ const message = {
|
|||||||
containerTerminal: 'Terminal',
|
containerTerminal: 'Terminal',
|
||||||
|
|
||||||
port: 'Port',
|
port: 'Port',
|
||||||
|
server: 'Host',
|
||||||
|
serverExample: 'e.g. 80, 80-88, ip:80 or ip:80-88',
|
||||||
|
contianerExample: 'e.g. 80 or 80-88',
|
||||||
exposePort: 'Expose port',
|
exposePort: 'Expose port',
|
||||||
exposeAll: 'Expose all',
|
exposeAll: 'Expose all',
|
||||||
containerPort: 'Container port',
|
|
||||||
serverPort: 'Host port',
|
|
||||||
cmd: 'Command',
|
cmd: 'Command',
|
||||||
cmdHelper: 'Example: echo "hello"',
|
cmdHelper: 'Example: echo "hello"',
|
||||||
autoRemove: 'Auto remove',
|
autoRemove: 'Auto remove',
|
||||||
|
@ -472,10 +472,11 @@ const message = {
|
|||||||
emptyUser: '为空时,将使用容器默认的用户登录',
|
emptyUser: '为空时,将使用容器默认的用户登录',
|
||||||
|
|
||||||
port: '端口',
|
port: '端口',
|
||||||
|
server: '服务器',
|
||||||
|
serverExample: '例如: 80, 80-88, ip:80 或者 ip:80-88',
|
||||||
|
contianerExample: '例如: 80 或者 80-88',
|
||||||
exposePort: '暴露端口',
|
exposePort: '暴露端口',
|
||||||
exposeAll: '暴露所有',
|
exposeAll: '暴露所有',
|
||||||
containerPort: '容器端口',
|
|
||||||
serverPort: '服务器端口',
|
|
||||||
cmd: '启动命令',
|
cmd: '启动命令',
|
||||||
cmdHelper: '例:echo "hello"',
|
cmdHelper: '例:echo "hello"',
|
||||||
autoRemove: '容器退出后自动删除容器',
|
autoRemove: '容器退出后自动删除容器',
|
||||||
|
@ -29,33 +29,38 @@
|
|||||||
<el-card style="width: 100%">
|
<el-card style="width: 100%">
|
||||||
<table style="width: 100%" class="tab-table">
|
<table style="width: 100%" class="tab-table">
|
||||||
<tr v-if="form.exposedPorts.length !== 0">
|
<tr v-if="form.exposedPorts.length !== 0">
|
||||||
<th scope="col" width="48%" align="left">
|
<th scope="col" width="45%" align="left">
|
||||||
<label>{{ $t('container.serverPort') }}</label>
|
<label>{{ $t('container.server') }}</label>
|
||||||
</th>
|
</th>
|
||||||
<th scope="col" width="48%" align="left">
|
<th scope="col" width="35%" align="left">
|
||||||
<label>{{ $t('container.containerPort') }}</label>
|
<label>{{ $t('container.container') }}</label>
|
||||||
|
</th>
|
||||||
|
<th scope="col" width="20%" align="left">
|
||||||
|
<label>{{ $t('container.protocol') }}</label>
|
||||||
</th>
|
</th>
|
||||||
<th align="left"></th>
|
<th align="left"></th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="(row, index) in form.exposedPorts" :key="index">
|
<tr v-for="(row, index) in form.exposedPorts" :key="index">
|
||||||
<td width="48%">
|
<td width="45%">
|
||||||
<el-input-number
|
<el-input
|
||||||
:min="0"
|
:placeholder="$t('container.serverExample')"
|
||||||
:max="65535"
|
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
controls-position="right"
|
v-model="row.host"
|
||||||
v-model.number="row.hostPort"
|
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td width="48%">
|
<td width="35%">
|
||||||
<el-input-number
|
<el-input
|
||||||
:min="0"
|
:placeholder="$t('container.contianerExample')"
|
||||||
:max="65535"
|
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
controls-position="right"
|
v-model="row.containerPort"
|
||||||
v-model.number="row.containerPort"
|
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
|
<td width="20%">
|
||||||
|
<el-select v-model="row.protocol" style="width: 100%">
|
||||||
|
<el-option label="tcp" value="tcp" />
|
||||||
|
<el-option label="upd" value="upd" />
|
||||||
|
</el-select>
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<el-button link style="font-size: 10px" @click="handlePortsDelete(index)">
|
<el-button link style="font-size: 10px" @click="handlePortsDelete(index)">
|
||||||
{{ $t('commons.button.delete') }}
|
{{ $t('commons.button.delete') }}
|
||||||
@ -204,6 +209,7 @@ import DrawerHeader from '@/components/drawer-header/index.vue';
|
|||||||
import { listImage, listVolume, createContainer } from '@/api/modules/container';
|
import { listImage, listVolume, createContainer } from '@/api/modules/container';
|
||||||
import { Container } from '@/api/interface/container';
|
import { Container } from '@/api/interface/container';
|
||||||
import { MsgError, MsgSuccess } from '@/utils/message';
|
import { MsgError, MsgSuccess } from '@/utils/message';
|
||||||
|
import { checkIp, checkPort } from '@/utils/util';
|
||||||
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
@ -277,8 +283,11 @@ const formRef = ref<FormInstance>();
|
|||||||
|
|
||||||
const handlePortsAdd = () => {
|
const handlePortsAdd = () => {
|
||||||
let item = {
|
let item = {
|
||||||
containerPort: null,
|
host: '',
|
||||||
hostPort: null,
|
hostIP: '',
|
||||||
|
containerPort: '',
|
||||||
|
hostPort: '',
|
||||||
|
protocol: 'tcp',
|
||||||
};
|
};
|
||||||
form.exposedPorts.push(item);
|
form.exposedPorts.push(item);
|
||||||
};
|
};
|
||||||
@ -327,6 +336,9 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
|
|||||||
if (form.cmdStr.length !== 0) {
|
if (form.cmdStr.length !== 0) {
|
||||||
form.cmd = form.cmdStr.split(' ');
|
form.cmd = form.cmdStr.split(' ');
|
||||||
}
|
}
|
||||||
|
if (!checkPortValid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
switch (form.memoryUnit) {
|
switch (form.memoryUnit) {
|
||||||
case 'KB':
|
case 'KB':
|
||||||
form.memory = form.memoryItem * 1024;
|
form.memory = form.memoryItem * 1024;
|
||||||
@ -352,6 +364,54 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const checkPortValid = async () => {
|
||||||
|
if (form.exposedPorts.length === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (const port of form.exposedPorts) {
|
||||||
|
if (port.host.indexOf(':') !== -1) {
|
||||||
|
port.hostIP = port.host.split(':')[0];
|
||||||
|
if (checkIp(port.hostIP)) {
|
||||||
|
MsgError(i18n.global.t('firewall.addressFormatError'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
port.hostPort = port.host.split(':')[1];
|
||||||
|
} else {
|
||||||
|
port.hostPort = port.host;
|
||||||
|
}
|
||||||
|
if (port.hostPort.indexOf('-') !== -1) {
|
||||||
|
if (checkPort(port.hostPort.split('-')[0])) {
|
||||||
|
MsgError(i18n.global.t('firewall.portFormatError'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (checkPort(port.hostPort.split('-')[1])) {
|
||||||
|
MsgError(i18n.global.t('firewall.portFormatError'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (checkPort(port.hostPort)) {
|
||||||
|
MsgError(i18n.global.t('firewall.portFormatError'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (port.containerPort.indexOf('-') !== -1) {
|
||||||
|
if (checkPort(port.containerPort.split('-')[0])) {
|
||||||
|
MsgError(i18n.global.t('firewall.portFormatError'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (checkPort(port.containerPort.split('-')[1])) {
|
||||||
|
MsgError(i18n.global.t('firewall.portFormatError'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (checkPort(port.containerPort)) {
|
||||||
|
MsgError(i18n.global.t('firewall.portFormatError'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
defineExpose({
|
defineExpose({
|
||||||
acceptParams,
|
acceptParams,
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user