From 53845e60b64aa864e57d804cfba70836275de041 Mon Sep 17 00:00:00 2001 From: ssongliu Date: Wed, 12 Oct 2022 18:55:47 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=B9=E5=99=A8=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/container.go | 25 ++ backend/app/api/v1/image.go | 9 + backend/app/dto/common_res.go | 4 + backend/app/dto/container.go | 25 ++ backend/app/service/container.go | 72 ++++ backend/app/service/image.go | 26 +- backend/app/service/image_test.go | 113 ++++++ backend/router/ro_container.go | 3 + frontend/src/api/interface/container.ts | 28 ++ frontend/src/api/modules/container.ts | 9 + frontend/src/lang/modules/en.ts | 28 ++ frontend/src/lang/modules/zh.ts | 27 ++ .../container/container/create/index.vue | 327 ++++++++++++------ .../src/views/container/container/index.vue | 2 +- .../src/views/container/image/build/index.vue | 13 +- .../views/container/network/create/index.vue | 14 +- .../views/container/volume/create/index.vue | 14 +- go.mod | 4 +- 18 files changed, 617 insertions(+), 126 deletions(-) create mode 100644 backend/app/service/image_test.go diff --git a/backend/app/api/v1/container.go b/backend/app/api/v1/container.go index 11be46fe2..748eaec20 100644 --- a/backend/app/api/v1/container.go +++ b/backend/app/api/v1/container.go @@ -30,6 +30,23 @@ func (b *BaseApi) SearchContainer(c *gin.Context) { }) } +func (b *BaseApi) ContainerCreate(c *gin.Context) { + var req dto.ContainerCreate + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := global.VALID.Struct(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := containerService.ContainerCreate(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, nil) +} + func (b *BaseApi) ContainerOperation(c *gin.Context) { var req dto.ContainerOperation if err := c.ShouldBindJSON(&req); err != nil { @@ -161,6 +178,14 @@ func (b *BaseApi) SearchVolume(c *gin.Context) { Total: total, }) } +func (b *BaseApi) ListVolume(c *gin.Context) { + list, err := containerService.ListVolume() + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, list) +} func (b *BaseApi) DeleteVolume(c *gin.Context) { var req dto.BatchDelete if err := c.ShouldBindJSON(&req); err != nil { diff --git a/backend/app/api/v1/image.go b/backend/app/api/v1/image.go index 729ffbe46..2bbcfae3a 100644 --- a/backend/app/api/v1/image.go +++ b/backend/app/api/v1/image.go @@ -31,6 +31,15 @@ func (b *BaseApi) SearchImage(c *gin.Context) { }) } +func (b *BaseApi) ListImage(c *gin.Context) { + list, err := imageService.List() + if err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, list) +} + func (b *BaseApi) ImageBuild(c *gin.Context) { var req dto.ImageBuild if err := c.ShouldBindJSON(&req); err != nil { diff --git a/backend/app/dto/common_res.go b/backend/app/dto/common_res.go index 6596a6b99..0e707df09 100644 --- a/backend/app/dto/common_res.go +++ b/backend/app/dto/common_res.go @@ -10,3 +10,7 @@ type Response struct { Msg string `json:"msg"` Data interface{} `json:"data"` } + +type Options struct { + Option string `json:"option"` +} diff --git a/backend/app/dto/container.go b/backend/app/dto/container.go index 40e287b93..dc8a1afaa 100644 --- a/backend/app/dto/container.go +++ b/backend/app/dto/container.go @@ -22,6 +22,31 @@ type ContainerInfo struct { RunTime string `json:"runTime"` } +type ContainerCreate struct { + Name string `json:"name"` + Image string `json:"image"` + PublishAllPorts bool `json:"publishAllPorts"` + ExposedPorts []PortHelper `json:"exposedPorts"` + Cmd []string `json:"cmd"` + NanoCPUs int64 `json:"nanoCPUs"` + Memory int64 `json:"memory"` + AutoRemove bool `json:"autoRemove"` + Volumes []VolumeHelper `json:"volumes"` + Labels []string `json:"labels"` + Env []string `json:"env"` + RestartPolicy string `json:"restartPolicy"` +} + +type VolumeHelper struct { + SourceDir string `json:"sourceDir"` + ContainerDir string `json:"containerDir"` + Mode string `json:"mode"` +} +type PortHelper struct { + ContainerPort int `json:"containerPort"` + HostPort int `json:"hostPort"` +} + type ContainerLog struct { ContainerID string `json:"containerID" validate:"required"` Mode string `json:"mode" validate:"required"` diff --git a/backend/app/service/container.go b/backend/app/service/container.go index 52d28bedc..8029cd05d 100644 --- a/backend/app/service/container.go +++ b/backend/app/service/container.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "io" + "strconv" "strings" "time" @@ -13,10 +14,13 @@ import ( "github.com/1Panel-dev/1Panel/constant" "github.com/1Panel-dev/1Panel/utils/docker" "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/volume" "github.com/docker/docker/pkg/stdcopy" + "github.com/docker/go-connections/nat" + v1 "github.com/opencontainers/image-spec/specs-go/v1" ) type ContainerService struct{} @@ -25,6 +29,8 @@ type IContainerService interface { Page(req dto.PageContainer) (int64, interface{}, error) PageNetwork(req dto.PageInfo) (int64, interface{}, error) PageVolume(req dto.PageInfo) (int64, interface{}, error) + ListVolume() ([]dto.Options, error) + ContainerCreate(req dto.ContainerCreate) error ContainerOperation(req dto.ContainerOperation) error ContainerLogs(param dto.ContainerLog) (string, error) Inspect(req dto.InspectReq) (string, error) @@ -101,6 +107,55 @@ func (u *ContainerService) Inspect(req dto.InspectReq) (string, error) { return string(bytes), nil } +func (u *ContainerService) ContainerCreate(req dto.ContainerCreate) error { + client, err := docker.NewDockerClient() + if err != nil { + return err + } + config := &container.Config{ + Image: req.Image, + Cmd: req.Cmd, + Env: req.Env, + Labels: stringsToMap(req.Labels), + } + hostConf := &container.HostConfig{ + AutoRemove: req.AutoRemove, + PublishAllPorts: req.PublishAllPorts, + RestartPolicy: container.RestartPolicy{Name: req.RestartPolicy}, + } + if req.RestartPolicy == "on-failure" { + hostConf.RestartPolicy.MaximumRetryCount = 5 + } + if req.NanoCPUs != 0 { + hostConf.NanoCPUs = req.NanoCPUs * 1000000000 + } + if req.Memory != 0 { + hostConf.Memory = req.Memory + } + if len(req.ExposedPorts) != 0 { + hostConf.PortBindings = make(nat.PortMap) + for _, port := range req.ExposedPorts { + bindItem := nat.PortBinding{HostPort: strconv.Itoa(port.HostPort)} + hostConf.PortBindings[nat.Port(fmt.Sprintf("%d/tcp", port.ContainerPort))] = []nat.PortBinding{bindItem} + } + } + if len(req.Volumes) != 0 { + config.Volumes = make(map[string]struct{}) + for _, volume := range req.Volumes { + config.Volumes[volume.ContainerDir] = struct{}{} + hostConf.Binds = append(hostConf.Binds, fmt.Sprintf("%s:%s:%s", volume.SourceDir, volume.ContainerDir, volume.Mode)) + } + } + container, err := client.ContainerCreate(context.TODO(), config, hostConf, &network.NetworkingConfig{}, &v1.Platform{}, req.Name) + if err != nil { + return err + } + if err := client.ContainerStart(context.TODO(), container.ID, types.ContainerStartOptions{}); err != nil { + return fmt.Errorf("create successful but start failed, err: %v", err) + } + return nil +} + func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error { var err error ctx := context.Background() @@ -293,6 +348,23 @@ func (u *ContainerService) PageVolume(req dto.PageInfo) (int64, interface{}, err return int64(total), data, nil } +func (u *ContainerService) ListVolume() ([]dto.Options, error) { + client, err := docker.NewDockerClient() + if err != nil { + return nil, err + } + list, err := client.VolumeList(context.TODO(), filters.NewArgs()) + if err != nil { + return nil, err + } + var data []dto.Options + for _, item := range list.Volumes { + data = append(data, dto.Options{ + Option: item.Name, + }) + } + return data, nil +} func (u *ContainerService) DeleteVolume(req dto.BatchDelete) error { client, err := docker.NewDockerClient() if err != nil { diff --git a/backend/app/service/image.go b/backend/app/service/image.go index eb849b4df..b31dd2869 100644 --- a/backend/app/service/image.go +++ b/backend/app/service/image.go @@ -23,6 +23,7 @@ type ImageService struct{} type IImageService interface { Page(req dto.PageInfo) (int64, interface{}, error) + List() ([]dto.Options, error) ImagePull(req dto.ImagePull) error ImageLoad(req dto.ImageLoad) error ImageSave(req dto.ImageSave) error @@ -43,7 +44,7 @@ func (u *ImageService) Page(req dto.PageInfo) (int64, interface{}, error) { if err != nil { return 0, nil, err } - list, err = client.ImageList(context.Background(), types.ImageListOptions{All: true}) + list, err = client.ImageList(context.Background(), types.ImageListOptions{}) if err != nil { return 0, nil, err } @@ -70,6 +71,29 @@ func (u *ImageService) Page(req dto.PageInfo) (int64, interface{}, error) { return int64(total), backDatas, nil } +func (u *ImageService) List() ([]dto.Options, error) { + var ( + list []types.ImageSummary + backDatas []dto.Options + ) + client, err := docker.NewDockerClient() + if err != nil { + return nil, err + } + list, err = client.ImageList(context.Background(), types.ImageListOptions{}) + if err != nil { + return nil, err + } + for _, image := range list { + for _, tag := range image.RepoTags { + backDatas = append(backDatas, dto.Options{ + Option: tag, + }) + } + } + return backDatas, nil +} + func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) { client, err := docker.NewDockerClient() if err != nil { diff --git a/backend/app/service/image_test.go b/backend/app/service/image_test.go new file mode 100644 index 000000000..33a515041 --- /dev/null +++ b/backend/app/service/image_test.go @@ -0,0 +1,113 @@ +package service + +import ( + "context" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "os" + "testing" + + "github.com/1Panel-dev/1Panel/constant" + "github.com/1Panel-dev/1Panel/utils/docker" + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/network" + "github.com/docker/docker/pkg/archive" + v1 "github.com/opencontainers/image-spec/specs-go/v1" +) + +func TestImage(t *testing.T) { + file, err := os.OpenFile(("/tmp/nginx.tar"), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666) + if err != nil { + fmt.Println(err) + } + defer file.Close() + + client, err := docker.NewDockerClient() + if err != nil { + fmt.Println(err) + } + out, err := client.ImageSave(context.TODO(), []string{"nginx:1.14.2"}) + fmt.Println(err) + defer out.Close() + if _, err = io.Copy(file, out); err != nil { + fmt.Println(err) + } +} + +func TestBuild(t *testing.T) { + client, err := docker.NewDockerClient() + if err != nil { + fmt.Println(err) + } + tar, err := archive.TarWithOptions("/tmp/testbuild/", &archive.TarOptions{}) + if err != nil { + fmt.Println(err) + } + + opts := types.ImageBuildOptions{ + Dockerfile: "Dockerfile", + Tags: []string{"hello/test:v1"}, + Remove: true, + } + res, err := client.ImageBuild(context.TODO(), tar, opts) + if err != nil { + fmt.Println(err) + } + defer res.Body.Close() +} + +func TestDeam(t *testing.T) { + file, err := ioutil.ReadFile(constant.DaemonJsonDir) + if err != nil { + fmt.Println(err) + } + deamonMap := make(map[string]interface{}) + err = json.Unmarshal(file, &deamonMap) + fmt.Println(err) + for k, v := range deamonMap { + fmt.Println(k, v) + } + if _, ok := deamonMap["insecure-registries"]; ok { + if k, v := deamonMap["insecure-registries"].(string); v { + fmt.Println("string ", k) + } + if k, v := deamonMap["insecure-registries"].([]interface{}); v { + fmt.Println("[]string ", k) + k = append(k, "172.16.10.111:8085") + deamonMap["insecure-registries"] = k + } + } + newss, err := json.Marshal(deamonMap) + if err != nil { + fmt.Println(err) + } + fmt.Println(string(newss)) + if err := ioutil.WriteFile(constant.DaemonJsonDir, newss, 0777); err != nil { + fmt.Println(err) + } +} + +func TestNetwork(t *testing.T) { + client, err := docker.NewDockerClient() + if err != nil { + fmt.Println(err) + } + _, err = client.NetworkCreate(context.TODO(), "test", types.NetworkCreate{}) + if err != nil { + fmt.Println(err) + } +} + +func TestContainer(t *testing.T) { + client, err := docker.NewDockerClient() + if err != nil { + fmt.Println(err) + } + _, err = client.ContainerCreate(context.TODO(), &container.Config{}, &container.HostConfig{}, &network.NetworkingConfig{}, &v1.Platform{}, "test") + if err != nil { + fmt.Println(err) + } +} diff --git a/backend/router/ro_container.go b/backend/router/ro_container.go index 07136a52e..447246250 100644 --- a/backend/router/ro_container.go +++ b/backend/router/ro_container.go @@ -22,6 +22,7 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) { { baRouter.POST("/search", baseApi.SearchContainer) baRouter.POST("/inspect", baseApi.Inspect) + baRouter.POST("", baseApi.ContainerCreate) withRecordRouter.POST("operate", baseApi.ContainerOperation) withRecordRouter.POST("/log", baseApi.ContainerLogs) @@ -32,6 +33,7 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) { withRecordRouter.POST("/repo/del", baseApi.DeleteRepo) baRouter.POST("/image/search", baseApi.SearchImage) + baRouter.GET("/image", baseApi.ListImage) baRouter.POST("/image/pull", baseApi.ImagePull) baRouter.POST("/image/push", baseApi.ImagePush) baRouter.POST("/image/save", baseApi.ImageSave) @@ -45,6 +47,7 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) { baRouter.POST("/network", baseApi.CreateNetwork) baRouter.POST("/volume/del", baseApi.DeleteVolume) baRouter.POST("/volume/search", baseApi.SearchVolume) + baRouter.GET("/volume", baseApi.ListVolume) baRouter.POST("/volume", baseApi.CreateVolume) } } diff --git a/frontend/src/api/interface/container.ts b/frontend/src/api/interface/container.ts index a78078a88..3d7b8948a 100644 --- a/frontend/src/api/interface/container.ts +++ b/frontend/src/api/interface/container.ts @@ -4,6 +4,31 @@ export namespace Container { operation: string; newName: string; } + export interface ContainerCreate { + name: string; + image: string; + cmd: Array; + publishAllPorts: boolean; + exposedPorts: Array; + nanoCPUs: number; + memory: number; + volumes: Array; + autoRemove: boolean; + labels: Array; + labelsStr: string; + env: Array; + envStr: string; + restartPolicy: string; + } + export interface Port { + containerPort: number; + hostPort: number; + } + export interface Volume { + sourceDir: string; + containerDir: string; + mode: string; + } export interface ContainerInfo { containerID: string; name: string; @@ -20,6 +45,9 @@ export namespace Container { id: string; type: string; } + export interface Options { + option: string; + } export interface ImageInfo { id: string; diff --git a/frontend/src/api/modules/container.ts b/frontend/src/api/modules/container.ts index 6bd6b57d5..bc748bd7e 100644 --- a/frontend/src/api/modules/container.ts +++ b/frontend/src/api/modules/container.ts @@ -5,6 +5,9 @@ import { Container } from '../interface/container'; export const getContainerPage = (params: ReqPage) => { return http.post>(`/containers/search`, params); }; +export const createContainer = (params: Container.ContainerCreate) => { + return http.post(`/containers`, params); +}; export const getContainerLog = (params: Container.ContainerLogSearch) => { return http.post(`/containers/log`, params); @@ -22,6 +25,9 @@ export const inspect = (params: Container.ContainerInspect) => { export const getImagePage = (params: ReqPage) => { return http.post>(`/containers/image/search`, params); }; +export const imageOptions = () => { + return http.get>(`/containers/image`); +}; export const imageBuild = (params: Container.ImageBuild) => { return http.post(`/containers/image/build`, params); }; @@ -59,6 +65,9 @@ export const createNetwork = (params: Container.NetworkCreate) => { export const getVolumePage = (params: ReqPage) => { return http.post>(`/containers/volume/search`, params); }; +export const volumeOptions = () => { + return http.get>(`/containers/volume`); +}; export const deleteVolume = (params: Container.BatchDelete) => { return http.post(`/containers/volume/del`, params); }; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 3e1908a82..2a25600ee 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -169,6 +169,30 @@ export default { lastHour: 'Last Hour', last10Min: 'Last 10 Minutes', + containerCreate: 'Container create', + port: 'Port', + exposePort: 'Expose port', + exposeAll: 'Expose all', + containerPort: 'Container port', + serverPort: 'Host port', + cmd: 'Command', + cmdHelper: 'one in a row, for example, echo "hello"', + autoRemove: 'Auto remove', + cpuQuota: 'NacosCPU', + memoryLimit: 'Memory', + limitHelper: 'If the limit is 0, the limit is turned off', + mount: 'Mount', + serverPath: 'Server path', + containerDir: 'Container path', + modeRW: 'Read-Write', + modeR: 'Read-Only', + mode: 'Mode', + env: 'Environment', + restartPolicy: 'Restart policy', + unlessStopped: 'unless-stopped', + onFailure: 'on-failure(five times by default)', + no: 'no', + image: 'Image', imagePull: 'Image pull', imagePush: 'Image push', @@ -179,6 +203,7 @@ export default { importImage: 'Image import', import: 'Import', build: 'Build', + imageBuild: 'Image build', label: 'Label', push: 'Push', fileName: 'FileName', @@ -187,6 +212,9 @@ export default { version: 'Version', size: 'Size', from: 'From', + tag: 'Tag', + tagHelper: 'one in a row, for example, key=value', + imageNameHelper: 'Image name and Tag, for example: nginx:latest', network: 'Network', createNetwork: 'Create network', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 538b6a6e7..97f825d4f 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -166,6 +166,30 @@ export default { lastHour: '最近 1 小时', last10Min: '最近 10 分钟', + containerCreate: '容器创建', + port: '端口', + exposePort: '暴露端口', + exposeAll: '暴露所有', + containerPort: '容器端口', + serverPort: '服务器端口', + cmd: '启动命令', + cmdHelper: '一行一个,例: echo "hello"', + autoRemove: '容器退出后自动删除容器', + cpuQuota: 'CPU 限制', + memoryLimit: '内存限制', + limitHelper: '限制为 0 则关闭限制', + mount: '挂载卷', + serverPath: '服务器目录', + containerDir: '容器目录', + modeRW: '读写', + modeR: '只读', + mode: '权限', + env: '环境变量', + restartPolicy: '重启规则', + unlessStopped: '关闭后重启', + onFailure: '失败后重启(默认重启 5 次)', + no: '不重启', + image: '镜像', imagePull: '拉取镜像', imagePush: '推送镜像', @@ -176,6 +200,7 @@ export default { path: '路径', importImage: '导入镜像', import: '导入', + imageBuild: '构建镜像', build: '构建镜像', edit: '编辑', pathSelect: '路径选择', @@ -188,6 +213,8 @@ export default { size: '大小', from: '来源', tag: '标签', + tagHelper: '一行一个,例: key=value', + imageNameHelper: '镜像名称及 Tag,例:nginx:latest', network: '网络', createNetwork: '添加网络', diff --git a/frontend/src/views/container/container/create/index.vue b/frontend/src/views/container/container/create/index.vue index 5f0df1405..261b28476 100644 --- a/frontend/src/views/container/container/create/index.vue +++ b/frontend/src/views/container/container/create/index.vue @@ -2,93 +2,174 @@ - - + + - - + + + + - + - 暴露端口 - 暴露所有 + {{ $t('container.exposePort') }} + {{ $t('container.exposeAll') }} - -
- - - - - - - - - -
- - - - - - {{ $t('commons.button.delete') }} - -
- {{ $t('commons.button.add') }} -
- - + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + {{ $t('commons.button.delete') }} + +
+ {{ $t('commons.button.add') }} +
+
+
+ + - 容器停止后自动删除容器 + {{ $t('container.autoRemove') }} - - + + + + + {{ $t('container.limitHelper') }} - - + + + + + {{ $t('container.limitHelper') }} - -
- - - - - - - - - - -
- - - - - - - - {{ $t('commons.button.delete') }} - -
- {{ $t('commons.button.add') }} -
+ + + + + + + + + + + + + + + + + + +
+ + + + + +
+ + + + + + + + + + + + + {{ $t('commons.button.delete') }} + +
+ {{ $t('commons.button.add') }} +
+
- - + + - - + + - - - 关闭后马上重启 - 错误时重启(默认重启 5 次) - 不重启 + + + {{ $t('container.unlessStopped') }} + {{ $t('container.onFailure') }} + {{ $t('container.no') }}
@@ -108,51 +189,47 @@ import { reactive, ref } from 'vue'; import { Rules } from '@/global/form-rules'; import i18n from '@/lang'; import { ElForm, ElMessage } from 'element-plus'; +import { imageOptions, volumeOptions, createContainer } from '@/api/modules/container'; +import { Container } from '@/api/interface/container'; const createVisiable = ref(false); const form = reactive({ name: '', image: '', - command: '', + cmdStr: '', + cmd: [] as Array, publishAllPorts: false, - ports: [], - cpusetCpus: 1, - memeryLimit: 100, - volumes: [], + exposedPorts: [] as Array, + nanoCPUs: 1, + memory: 100, + memoryItem: 100, + memoryUnit: 'MB', + volumes: [] as Array, autoRemove: false, - labels: '', - environment: '', - restartPolicy: { - value: '', - name: '', - maximumRetryCount: '', - }, + labels: [] as Array, + labelsStr: '', + env: [] as Array, + envStr: '', + restartPolicy: '', }); -const ports = ref(); +const images = ref(); const volumes = ref(); const acceptParams = (): void => { createVisiable.value = true; + form.restartPolicy = 'no'; + form.memoryUnit = 'MB'; + loadImageOptions(); + loadVolumeOptions(); }; const emit = defineEmits<{ (e: 'search'): void }>(); const rules = reactive({ name: [Rules.requiredInput, Rules.name], - type: [Rules.requiredSelect], - specType: [Rules.requiredSelect], - week: [Rules.requiredSelect, Rules.number], - day: [Rules.number, { max: 31, min: 1 }], - hour: [Rules.number, { max: 23, min: 0 }], - minute: [Rules.number, { max: 60, min: 1 }], - - script: [Rules.requiredInput], - website: [Rules.requiredSelect], - database: [Rules.requiredSelect], - url: [Rules.requiredInput], - sourceDir: [Rules.requiredSelect], - targetDirID: [Rules.requiredSelect, Rules.number], - retainCopies: [Rules.number], + image: [Rules.requiredSelect], + nanoCPUs: [Rules.number], + memoryItem: [Rules.number], }); type FormInstance = InstanceType; @@ -160,39 +237,61 @@ const formRef = ref(); const handlePortsAdd = () => { let item = { - key: '', - value: '', + containerPort: 80, + hostPort: 8080, }; - ports.value.push(item); + form.exposedPorts.push(item); }; const handlePortsDelete = (index: number) => { - ports.value.splice(index, 1); + form.exposedPorts.splice(index, 1); }; const handleVolumesAdd = () => { let item = { - from: '', - bind: '', - mode: '', + sourceDir: '', + containerDir: '', + mode: 'rw', }; - volumes.value.push(item); + form.volumes.push(item); }; const handleVolumesDelete = (index: number) => { - volumes.value.splice(index, 1); + form.volumes.splice(index, 1); }; -function restForm() { - if (formRef.value) { - formRef.value.resetFields(); - } -} +const loadImageOptions = async () => { + const res = await imageOptions(); + images.value = res.data; +}; +const loadVolumeOptions = async () => { + const res = await volumeOptions(); + volumes.value = res.data; +}; const onSubmit = async (formEl: FormInstance | undefined) => { if (!formEl) return; formEl.validate(async (valid) => { if (!valid) return; - + if (form.envStr.length !== 0) { + form.env = form.envStr.split('\n'); + } + if (form.labelsStr.length !== 0) { + form.labels = form.labelsStr.split('\n'); + } + if (form.cmdStr.length !== 0) { + form.cmd = form.cmdStr.split('\n'); + } + switch (form.memoryUnit) { + case 'KB': + form.memory = form.memoryItem * 1024; + break; + case 'MB': + form.memory = form.memoryItem * 1024 * 1024; + break; + case 'GB': + form.memory = form.memoryItem * 1024 * 1024 * 1024; + break; + } + await createContainer(form); ElMessage.success(i18n.global.t('commons.msg.operationSuccess')); - restForm(); emit('search'); createVisiable.value = false; }); diff --git a/frontend/src/views/container/container/index.vue b/frontend/src/views/container/container/index.vue index b1eb07ff9..20ca28a8b 100644 --- a/frontend/src/views/container/container/index.vue +++ b/frontend/src/views/container/container/index.vue @@ -156,7 +156,7 @@
- + diff --git a/frontend/src/views/container/image/build/index.vue b/frontend/src/views/container/image/build/index.vue index fa3e25a07..8a24dc843 100644 --- a/frontend/src/views/container/image/build/index.vue +++ b/frontend/src/views/container/image/build/index.vue @@ -8,12 +8,12 @@ > - + @@ -32,7 +32,12 @@ - + @@ -55,7 +60,7 @@ diff --git a/frontend/src/views/container/network/create/index.vue b/frontend/src/views/container/network/create/index.vue index b59b7105c..fee17a814 100644 --- a/frontend/src/views/container/network/create/index.vue +++ b/frontend/src/views/container/network/create/index.vue @@ -18,7 +18,12 @@ - + @@ -30,7 +35,12 @@ - +