mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-02-08 01:20:07 +08:00
feat: 容器创建编辑支持自定义网络 (#1582)
This commit is contained in:
parent
28bd0e3cc2
commit
7b297e824c
@ -489,6 +489,23 @@ func (b *BaseApi) SearchNetwork(c *gin.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Tags Container Network
|
||||||
|
// @Summary List networks
|
||||||
|
// @Description 获取容器网络列表
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {array} dto.Options
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /containers/network [get]
|
||||||
|
func (b *BaseApi) ListNetwork(c *gin.Context) {
|
||||||
|
list, err := containerService.ListNetwork()
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, list)
|
||||||
|
}
|
||||||
|
|
||||||
// @Tags Container Network
|
// @Tags Container Network
|
||||||
// @Summary Delete network
|
// @Summary Delete network
|
||||||
// @Description 删除容器网络
|
// @Description 删除容器网络
|
||||||
@ -578,11 +595,10 @@ func (b *BaseApi) SearchVolume(c *gin.Context) {
|
|||||||
// @Summary List volumes
|
// @Summary List volumes
|
||||||
// @Description 获取容器存储卷列表
|
// @Description 获取容器存储卷列表
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.PageInfo true "request"
|
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} dto.PageResult
|
// @Success 200 {array} dto.Options
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /containers/volume/search [get]
|
// @Router /containers/volume [get]
|
||||||
func (b *BaseApi) ListVolume(c *gin.Context) {
|
func (b *BaseApi) ListVolume(c *gin.Context) {
|
||||||
list, err := containerService.ListVolume()
|
list, err := containerService.ListVolume()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -39,6 +39,7 @@ type ContainerOperate struct {
|
|||||||
ContainerID string `json:"containerID"`
|
ContainerID string `json:"containerID"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Image string `json:"image"`
|
Image string `json:"image"`
|
||||||
|
Network string `json:"network"`
|
||||||
PublishAllPorts bool `json:"publishAllPorts"`
|
PublishAllPorts bool `json:"publishAllPorts"`
|
||||||
ExposedPorts []PortHelper `json:"exposedPorts"`
|
ExposedPorts []PortHelper `json:"exposedPorts"`
|
||||||
Cmd []string `json:"cmd"`
|
Cmd []string `json:"cmd"`
|
||||||
|
@ -37,6 +37,7 @@ type IContainerService interface {
|
|||||||
Page(req dto.PageContainer) (int64, interface{}, error)
|
Page(req dto.PageContainer) (int64, interface{}, error)
|
||||||
List() ([]string, error)
|
List() ([]string, error)
|
||||||
PageNetwork(req dto.SearchWithPage) (int64, interface{}, error)
|
PageNetwork(req dto.SearchWithPage) (int64, interface{}, error)
|
||||||
|
ListNetwork() ([]dto.Options, error)
|
||||||
PageVolume(req dto.SearchWithPage) (int64, interface{}, error)
|
PageVolume(req dto.SearchWithPage) (int64, interface{}, error)
|
||||||
ListVolume() ([]dto.Options, error)
|
ListVolume() ([]dto.Options, error)
|
||||||
PageCompose(req dto.SearchWithPage) (int64, interface{}, error)
|
PageCompose(req dto.SearchWithPage) (int64, interface{}, error)
|
||||||
@ -309,7 +310,8 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerOperate) error {
|
|||||||
|
|
||||||
var config container.Config
|
var config container.Config
|
||||||
var hostConf container.HostConfig
|
var hostConf container.HostConfig
|
||||||
if err := loadConfigInfo(req, &config, &hostConf); err != nil {
|
var networkConf network.NetworkingConfig
|
||||||
|
if err := loadConfigInfo(req, &config, &hostConf, &networkConf); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,7 +322,7 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerOperate) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
container, err := client.ContainerCreate(ctx, &config, &hostConf, &network.NetworkingConfig{}, &v1.Platform{}, req.Name)
|
container, err := client.ContainerCreate(ctx, &config, &hostConf, &networkConf, &v1.Platform{}, req.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = client.ContainerRemove(ctx, req.Name, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true})
|
_ = client.ContainerRemove(ctx, req.Name, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true})
|
||||||
return err
|
return err
|
||||||
@ -348,6 +350,12 @@ func (u *ContainerService) ContainerInfo(req dto.OperationWithName) (*dto.Contai
|
|||||||
data.ContainerID = oldContainer.ID
|
data.ContainerID = oldContainer.ID
|
||||||
data.Name = strings.ReplaceAll(oldContainer.Name, "/", "")
|
data.Name = strings.ReplaceAll(oldContainer.Name, "/", "")
|
||||||
data.Image = oldContainer.Config.Image
|
data.Image = oldContainer.Config.Image
|
||||||
|
if oldContainer.NetworkSettings != nil {
|
||||||
|
for network := range oldContainer.NetworkSettings.Networks {
|
||||||
|
data.Network = network
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
data.Cmd = oldContainer.Config.Cmd
|
data.Cmd = oldContainer.Config.Cmd
|
||||||
data.Env = oldContainer.Config.Env
|
data.Env = oldContainer.Config.Env
|
||||||
data.CPUShares = oldContainer.HostConfig.CPUShares
|
data.CPUShares = oldContainer.HostConfig.CPUShares
|
||||||
@ -409,7 +417,8 @@ func (u *ContainerService) ContainerUpdate(req dto.ContainerOperate) error {
|
|||||||
}
|
}
|
||||||
config := oldContainer.Config
|
config := oldContainer.Config
|
||||||
hostConf := oldContainer.HostConfig
|
hostConf := oldContainer.HostConfig
|
||||||
if err := loadConfigInfo(req, config, hostConf); err != nil {
|
var networkConf network.NetworkingConfig
|
||||||
|
if err := loadConfigInfo(req, config, hostConf, &networkConf); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := client.ContainerRemove(ctx, req.ContainerID, types.ContainerRemoveOptions{Force: true}); err != nil {
|
if err := client.ContainerRemove(ctx, req.ContainerID, types.ContainerRemoveOptions{Force: true}); err != nil {
|
||||||
@ -417,7 +426,7 @@ func (u *ContainerService) ContainerUpdate(req dto.ContainerOperate) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
global.LOG.Infof("new container info %s has been update, now start to recreate", req.Name)
|
global.LOG.Infof("new container info %s has been update, now start to recreate", req.Name)
|
||||||
container, err := client.ContainerCreate(ctx, config, hostConf, &network.NetworkingConfig{}, &v1.Platform{}, req.Name)
|
container, err := client.ContainerCreate(ctx, config, hostConf, &networkConf, &v1.Platform{}, req.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("recreate contianer failed, err: %v", err)
|
return fmt.Errorf("recreate contianer failed, err: %v", err)
|
||||||
}
|
}
|
||||||
@ -447,6 +456,13 @@ func (u *ContainerService) ContainerUpgrade(req dto.ContainerUpgrade) error {
|
|||||||
config := oldContainer.Config
|
config := oldContainer.Config
|
||||||
config.Image = req.Image
|
config.Image = req.Image
|
||||||
hostConf := oldContainer.HostConfig
|
hostConf := oldContainer.HostConfig
|
||||||
|
var networkConf network.NetworkingConfig
|
||||||
|
if oldContainer.NetworkSettings != nil {
|
||||||
|
for networkKey := range oldContainer.NetworkSettings.Networks {
|
||||||
|
networkConf.EndpointsConfig = map[string]*network.EndpointSettings{networkKey: {}}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
if err := client.ContainerRemove(ctx, req.Name, types.ContainerRemoveOptions{Force: true}); err != nil {
|
if err := client.ContainerRemove(ctx, req.Name, types.ContainerRemoveOptions{Force: true}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -743,7 +759,7 @@ func checkPortStats(ports []dto.PortHelper) (nat.PortMap, error) {
|
|||||||
return portMap, nil
|
return portMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadConfigInfo(req dto.ContainerOperate, config *container.Config, hostConf *container.HostConfig) error {
|
func loadConfigInfo(req dto.ContainerOperate, config *container.Config, hostConf *container.HostConfig, networkConf *network.NetworkingConfig) error {
|
||||||
portMap, err := checkPortStats(req.ExposedPorts)
|
portMap, err := checkPortStats(req.ExposedPorts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -758,6 +774,8 @@ func loadConfigInfo(req dto.ContainerOperate, config *container.Config, hostConf
|
|||||||
config.Labels = stringsToMap(req.Labels)
|
config.Labels = stringsToMap(req.Labels)
|
||||||
config.ExposedPorts = exposeds
|
config.ExposedPorts = exposeds
|
||||||
|
|
||||||
|
networkConf.EndpointsConfig = map[string]*network.EndpointSettings{req.Network: {}}
|
||||||
|
|
||||||
hostConf.AutoRemove = req.AutoRemove
|
hostConf.AutoRemove = req.AutoRemove
|
||||||
hostConf.CPUShares = req.CPUShares
|
hostConf.CPUShares = req.CPUShares
|
||||||
hostConf.PublishAllPorts = req.PublishAllPorts
|
hostConf.PublishAllPorts = req.PublishAllPorts
|
||||||
|
@ -75,6 +75,23 @@ func (u *ContainerService) PageNetwork(req dto.SearchWithPage) (int64, interface
|
|||||||
|
|
||||||
return int64(total), data, nil
|
return int64(total), data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *ContainerService) ListNetwork() ([]dto.Options, error) {
|
||||||
|
client, err := docker.NewDockerClient()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
list, err := client.NetworkList(context.TODO(), types.NetworkListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var datas []dto.Options
|
||||||
|
for _, item := range list {
|
||||||
|
datas = append(datas, dto.Options{Option: item.Name})
|
||||||
|
}
|
||||||
|
return datas, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (u *ContainerService) DeleteNetwork(req dto.BatchDelete) error {
|
func (u *ContainerService) DeleteNetwork(req dto.BatchDelete) error {
|
||||||
client, err := docker.NewDockerClient()
|
client, err := docker.NewDockerClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -61,10 +61,11 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) {
|
|||||||
baRouter.POST("/image/tag", baseApi.ImageTag)
|
baRouter.POST("/image/tag", baseApi.ImageTag)
|
||||||
baRouter.POST("/image/build", baseApi.ImageBuild)
|
baRouter.POST("/image/build", baseApi.ImageBuild)
|
||||||
|
|
||||||
baRouter.GET("/volume", baseApi.ListVolume)
|
baRouter.GET("/network", baseApi.ListNetwork)
|
||||||
baRouter.POST("/network/del", baseApi.DeleteNetwork)
|
baRouter.POST("/network/del", baseApi.DeleteNetwork)
|
||||||
baRouter.POST("/network/search", baseApi.SearchNetwork)
|
baRouter.POST("/network/search", baseApi.SearchNetwork)
|
||||||
baRouter.POST("/network", baseApi.CreateNetwork)
|
baRouter.POST("/network", baseApi.CreateNetwork)
|
||||||
|
baRouter.GET("/volume", baseApi.ListVolume)
|
||||||
baRouter.POST("/volume/del", baseApi.DeleteVolume)
|
baRouter.POST("/volume/del", baseApi.DeleteVolume)
|
||||||
baRouter.POST("/volume/search", baseApi.SearchVolume)
|
baRouter.POST("/volume/search", baseApi.SearchVolume)
|
||||||
baRouter.POST("/volume", baseApi.CreateVolume)
|
baRouter.POST("/volume", baseApi.CreateVolume)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Package docs GENERATED BY SWAG; DO NOT EDIT
|
// Code generated by swaggo/swag. DO NOT EDIT.
|
||||||
// This file was generated by swaggo/swag
|
|
||||||
package docs
|
package docs
|
||||||
|
|
||||||
import "github.com/swaggo/swag"
|
import "github.com/swaggo/swag"
|
||||||
@ -1992,6 +1992,35 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/containers/network": {
|
"/containers/network": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "获取容器网络列表",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Container Network"
|
||||||
|
],
|
||||||
|
"summary": "List networks",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/dto.Options"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
@ -2864,6 +2893,35 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/containers/volume": {
|
"/containers/volume": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "获取容器存储卷列表",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Container Volume"
|
||||||
|
],
|
||||||
|
"summary": "List volumes",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/dto.Options"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
@ -2948,43 +3006,6 @@ const docTemplate = `{
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/containers/volume/search": {
|
"/containers/volume/search": {
|
||||||
"get": {
|
|
||||||
"security": [
|
|
||||||
{
|
|
||||||
"ApiKeyAuth": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "获取容器存储卷列表",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Container Volume"
|
|
||||||
],
|
|
||||||
"summary": "List volumes",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"description": "request",
|
|
||||||
"name": "request",
|
|
||||||
"in": "body",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/dto.PageInfo"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/dto.PageResult"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
@ -11065,6 +11086,9 @@ const docTemplate = `{
|
|||||||
"nanoCPUs": {
|
"nanoCPUs": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"network": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"publishAllPorts": {
|
"publishAllPorts": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
@ -1985,6 +1985,35 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/containers/network": {
|
"/containers/network": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "获取容器网络列表",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Container Network"
|
||||||
|
],
|
||||||
|
"summary": "List networks",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/dto.Options"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
@ -2857,6 +2886,35 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/containers/volume": {
|
"/containers/volume": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "获取容器存储卷列表",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Container Volume"
|
||||||
|
],
|
||||||
|
"summary": "List volumes",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/dto.Options"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
@ -2941,43 +2999,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/containers/volume/search": {
|
"/containers/volume/search": {
|
||||||
"get": {
|
|
||||||
"security": [
|
|
||||||
{
|
|
||||||
"ApiKeyAuth": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "获取容器存储卷列表",
|
|
||||||
"consumes": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"produces": [
|
|
||||||
"application/json"
|
|
||||||
],
|
|
||||||
"tags": [
|
|
||||||
"Container Volume"
|
|
||||||
],
|
|
||||||
"summary": "List volumes",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"description": "request",
|
|
||||||
"name": "request",
|
|
||||||
"in": "body",
|
|
||||||
"required": true,
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/dto.PageInfo"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"200": {
|
|
||||||
"description": "OK",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/dto.PageResult"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
@ -11058,6 +11079,9 @@
|
|||||||
"nanoCPUs": {
|
"nanoCPUs": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"network": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"publishAllPorts": {
|
"publishAllPorts": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
},
|
},
|
||||||
|
@ -339,6 +339,8 @@ definitions:
|
|||||||
type: string
|
type: string
|
||||||
nanoCPUs:
|
nanoCPUs:
|
||||||
type: integer
|
type: integer
|
||||||
|
network:
|
||||||
|
type: string
|
||||||
publishAllPorts:
|
publishAllPorts:
|
||||||
type: boolean
|
type: boolean
|
||||||
restartPolicy:
|
restartPolicy:
|
||||||
@ -4817,6 +4819,24 @@ paths:
|
|||||||
- ApiKeyAuth: []
|
- ApiKeyAuth: []
|
||||||
summary: Load container stats
|
summary: Load container stats
|
||||||
/containers/network:
|
/containers/network:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 获取容器网络列表
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/dto.Options'
|
||||||
|
type: array
|
||||||
|
security:
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
summary: List networks
|
||||||
|
tags:
|
||||||
|
- Container Network
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
@ -5372,6 +5392,24 @@ paths:
|
|||||||
formatZH: 更新容器镜像 [name][image]
|
formatZH: 更新容器镜像 [name][image]
|
||||||
paramKeys: []
|
paramKeys: []
|
||||||
/containers/volume:
|
/containers/volume:
|
||||||
|
get:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 获取容器存储卷列表
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/dto.Options'
|
||||||
|
type: array
|
||||||
|
security:
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
summary: List volumes
|
||||||
|
tags:
|
||||||
|
- Container Volume
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
@ -5426,29 +5464,6 @@ paths:
|
|||||||
formatZH: 删除容器存储卷 [names]
|
formatZH: 删除容器存储卷 [names]
|
||||||
paramKeys: []
|
paramKeys: []
|
||||||
/containers/volume/search:
|
/containers/volume/search:
|
||||||
get:
|
|
||||||
consumes:
|
|
||||||
- application/json
|
|
||||||
description: 获取容器存储卷列表
|
|
||||||
parameters:
|
|
||||||
- description: request
|
|
||||||
in: body
|
|
||||||
name: request
|
|
||||||
required: true
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/dto.PageInfo'
|
|
||||||
produces:
|
|
||||||
- application/json
|
|
||||||
responses:
|
|
||||||
"200":
|
|
||||||
description: OK
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/dto.PageResult'
|
|
||||||
security:
|
|
||||||
- ApiKeyAuth: []
|
|
||||||
summary: List volumes
|
|
||||||
tags:
|
|
||||||
- Container Volume
|
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
|
@ -20,6 +20,7 @@ export namespace Container {
|
|||||||
containerID: string;
|
containerID: string;
|
||||||
name: string;
|
name: string;
|
||||||
image: string;
|
image: string;
|
||||||
|
network: string;
|
||||||
cmdStr: string;
|
cmdStr: string;
|
||||||
memoryItem: number;
|
memoryItem: number;
|
||||||
cmd: Array<string>;
|
cmd: Array<string>;
|
||||||
|
@ -75,6 +75,9 @@ export const imageRemove = (params: Container.BatchDelete) => {
|
|||||||
export const searchNetwork = (params: SearchWithPage) => {
|
export const searchNetwork = (params: SearchWithPage) => {
|
||||||
return http.post<ResPage<Container.NetworkInfo>>(`/containers/network/search`, params);
|
return http.post<ResPage<Container.NetworkInfo>>(`/containers/network/search`, params);
|
||||||
};
|
};
|
||||||
|
export const listNetwork = () => {
|
||||||
|
return http.get<Array<Container.Options>>(`/containers/network`);
|
||||||
|
};
|
||||||
export const deleteNetwork = (params: Container.BatchDelete) => {
|
export const deleteNetwork = (params: Container.BatchDelete) => {
|
||||||
return http.post(`/containers/network/del`, params);
|
return http.post(`/containers/network/del`, params);
|
||||||
};
|
};
|
||||||
|
@ -82,6 +82,16 @@
|
|||||||
</table>
|
</table>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('container.network')" prop="network">
|
||||||
|
<el-select v-model="dialogData.rowData!.network">
|
||||||
|
<el-option
|
||||||
|
v-for="(item, indexV) of networks"
|
||||||
|
:key="indexV"
|
||||||
|
:value="item.option"
|
||||||
|
:label="item.option"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item :label="$t('container.cmd')" prop="cmdStr">
|
<el-form-item :label="$t('container.cmd')" prop="cmdStr">
|
||||||
<el-input :placeholder="$t('container.cmdHelper')" v-model="dialogData.rowData!.cmdStr" />
|
<el-input :placeholder="$t('container.cmdHelper')" v-model="dialogData.rowData!.cmdStr" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -222,7 +232,14 @@ import { Rules, checkNumberRange } from '@/global/form-rules';
|
|||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
import { ElForm } from 'element-plus';
|
import { ElForm } from 'element-plus';
|
||||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||||
import { listImage, listVolume, createContainer, updateContainer, loadResourceLimit } from '@/api/modules/container';
|
import {
|
||||||
|
listImage,
|
||||||
|
listVolume,
|
||||||
|
createContainer,
|
||||||
|
updateContainer,
|
||||||
|
loadResourceLimit,
|
||||||
|
listNetwork,
|
||||||
|
} 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 { checkIpV4V6, checkPort } from '@/utils/util';
|
import { checkIpV4V6, checkPort } from '@/utils/util';
|
||||||
@ -263,12 +280,14 @@ const acceptParams = (params: DialogProps): void => {
|
|||||||
loadLimit();
|
loadLimit();
|
||||||
loadImageOptions();
|
loadImageOptions();
|
||||||
loadVolumeOptions();
|
loadVolumeOptions();
|
||||||
|
loadNetworkOptions();
|
||||||
drawerVisiable.value = true;
|
drawerVisiable.value = true;
|
||||||
};
|
};
|
||||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||||
|
|
||||||
const images = ref();
|
const images = ref();
|
||||||
const volumes = ref();
|
const volumes = ref();
|
||||||
|
const networks = ref();
|
||||||
const limits = ref<Container.ResourceLimit>({
|
const limits = ref<Container.ResourceLimit>({
|
||||||
cpu: null as number,
|
cpu: null as number,
|
||||||
memory: null as number,
|
memory: null as number,
|
||||||
@ -279,6 +298,7 @@ const handleClose = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const rules = reactive({
|
const rules = reactive({
|
||||||
|
network: [Rules.requiredSelect],
|
||||||
cpuShares: [Rules.number, checkNumberRange(0, 262144)],
|
cpuShares: [Rules.number, checkNumberRange(0, 262144)],
|
||||||
name: [Rules.requiredInput, Rules.name],
|
name: [Rules.requiredInput, Rules.name],
|
||||||
image: [Rules.requiredSelect],
|
image: [Rules.requiredSelect],
|
||||||
@ -329,6 +349,10 @@ const loadVolumeOptions = async () => {
|
|||||||
const res = await listVolume();
|
const res = await listVolume();
|
||||||
volumes.value = res.data;
|
volumes.value = res.data;
|
||||||
};
|
};
|
||||||
|
const loadNetworkOptions = async () => {
|
||||||
|
const res = await listNetwork();
|
||||||
|
networks.value = res.data;
|
||||||
|
};
|
||||||
const onSubmit = async (formEl: FormInstance | undefined) => {
|
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||||
if (dialogData.value.rowData!.volumes.length !== 0) {
|
if (dialogData.value.rowData!.volumes.length !== 0) {
|
||||||
for (const item of dialogData.value.rowData!.volumes) {
|
for (const item of dialogData.value.rowData!.volumes) {
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
:model="form"
|
:model="form"
|
||||||
:rules="rules"
|
:rules="rules"
|
||||||
label-width="80px"
|
label-width="80px"
|
||||||
|
@submit.prevent
|
||||||
>
|
>
|
||||||
<el-form-item :label="$t('commons.table.name')" prop="name">
|
<el-form-item :label="$t('commons.table.name')" prop="name">
|
||||||
<el-input clearable v-model.trim="form.name" />
|
<el-input clearable v-model.trim="form.name" />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user