diff --git a/backend/app/dto/container.go b/backend/app/dto/container.go index 3b3be4ab1..db8cbbd68 100644 --- a/backend/app/dto/container.go +++ b/backend/app/dto/container.go @@ -37,6 +37,7 @@ type ResourceLimit struct { type ContainerOperate struct { ContainerID string `json:"containerID"` + ForcePull bool `json:"forcePull"` Name string `json:"name"` Image string `json:"image"` Network string `json:"network"` @@ -54,8 +55,9 @@ type ContainerOperate struct { } type ContainerUpgrade struct { - Name string `json:"name" validate:"required"` - Image string `json:"image" validate:"required"` + Name string `json:"name" validate:"required"` + Image string `json:"image" validate:"required"` + ForcePull bool `json:"forcePull"` } type ContainerListStats struct { diff --git a/backend/app/service/container.go b/backend/app/service/container.go index ac4d4f251..f641db2d9 100644 --- a/backend/app/service/container.go +++ b/backend/app/service/container.go @@ -317,9 +317,12 @@ func (u *ContainerService) ContainerCreate(req dto.ContainerOperate) error { global.LOG.Infof("new container info %s has been made, now start to create", req.Name) - if !checkImageExist(client, req.Image) { + if !checkImageExist(client, req.Image) || req.ForcePull { if err := pullImages(ctx, client, req.Image); err != nil { - return err + if !req.ForcePull { + return err + } + global.LOG.Errorf("force pull image %s failed, err: %v", req.Image, err) } } container, err := client.ContainerCreate(ctx, &config, &hostConf, &networkConf, &v1.Platform{}, req.Name) @@ -410,9 +413,12 @@ func (u *ContainerService) ContainerUpdate(req dto.ContainerOperate) error { if err != nil { return err } - if !checkImageExist(client, req.Image) { + if !checkImageExist(client, req.Image) || req.ForcePull { if err := pullImages(ctx, client, req.Image); err != nil { - return err + if !req.ForcePull { + return err + } + global.LOG.Errorf("force pull image %s failed, err: %v", req.Image, err) } } config := oldContainer.Config @@ -448,9 +454,12 @@ func (u *ContainerService) ContainerUpgrade(req dto.ContainerUpgrade) error { if err != nil { return err } - if !checkImageExist(client, req.Image) { + if !checkImageExist(client, req.Image) || req.ForcePull { if err := pullImages(ctx, client, req.Image); err != nil { - return err + if !req.ForcePull { + return err + } + global.LOG.Errorf("force pull image %s failed, err: %v", req.Image, err) } } config := oldContainer.Config diff --git a/backend/app/service/container_network.go b/backend/app/service/container_network.go index da28edf47..08f567447 100644 --- a/backend/app/service/container_network.go +++ b/backend/app/service/container_network.go @@ -89,6 +89,9 @@ func (u *ContainerService) ListNetwork() ([]dto.Options, error) { for _, item := range list { datas = append(datas, dto.Options{Option: item.Name}) } + sort.Slice(datas, func(i, j int) bool { + return datas[i].Option < datas[j].Option + }) return datas, nil } diff --git a/backend/app/service/container_volume.go b/backend/app/service/container_volume.go index ebc51cc45..46c9c5f41 100644 --- a/backend/app/service/container_volume.go +++ b/backend/app/service/container_volume.go @@ -80,13 +80,16 @@ func (u *ContainerService) ListVolume() ([]dto.Options, error) { if err != nil { return nil, err } - var data []dto.Options + var datas []dto.Options for _, item := range list.Volumes { - data = append(data, dto.Options{ + datas = append(datas, dto.Options{ Option: item.Name, }) } - return data, nil + sort.Slice(datas, func(i, j int) bool { + return datas[i].Option < datas[j].Option + }) + return datas, nil } func (u *ContainerService) DeleteVolume(req dto.BatchDelete) error { client, err := docker.NewDockerClient() diff --git a/frontend/src/api/interface/container.ts b/frontend/src/api/interface/container.ts index cd3ce21d9..f734372a7 100644 --- a/frontend/src/api/interface/container.ts +++ b/frontend/src/api/interface/container.ts @@ -20,6 +20,7 @@ export namespace Container { containerID: string; name: string; image: string; + forcePull: boolean; network: string; cmdStr: string; memoryItem: number; diff --git a/frontend/src/api/modules/container.ts b/frontend/src/api/modules/container.ts index de4d919ed..bd5700b5b 100644 --- a/frontend/src/api/modules/container.ts +++ b/frontend/src/api/modules/container.ts @@ -17,8 +17,8 @@ export const createContainer = (params: Container.ContainerHelper) => { export const updateContainer = (params: Container.ContainerHelper) => { return http.post(`/containers/update`, params, 3000000); }; -export const upgradeContainer = (name: string, image: string) => { - return http.post(`/containers/upgrade`, { name: name, image: image }, 3000000); +export const upgradeContainer = (name: string, image: string, forcePull: boolean) => { + return http.post(`/containers/upgrade`, { name: name, image: image, forcePull: forcePull }, 3000000); }; export const loadContainerInfo = (name: string) => { return http.post(`/containers/info`, { name: name }); diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 3229d6df2..bdb38cf82 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -504,6 +504,7 @@ const message = { appHelper: 'This container is sourced from the application store. Upgrading it may cause the service to be unavailable. Do you want to continue?', + forcePull: 'Pull the latest image', server: 'Host', serverExample: 'e.g. 80, 80-88, ip:80 or ip:80-88', containerExample: 'e.g. 80 or 80-88', diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts index e3d239363..bb77659de 100644 --- a/frontend/src/lang/modules/tw.ts +++ b/frontend/src/lang/modules/tw.ts @@ -493,6 +493,7 @@ const message = { targetImageHelper: '請輸入目標鏡像版本', appHelper: '該容器來源於應用商店,升級可能導致該服務不可用,是否繼續?', + forcePull: '拉取最新鏡像', server: '服務器', serverExample: '例: 80, 80-88, ip:80 或者 ip:80-88', containerExample: '例: 80 或者 80-88', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 0424899de..835ed9501 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -493,6 +493,7 @@ const message = { targetImageHelper: '请输入目标镜像版本', appHelper: '该容器来源于应用商店,升级可能导致该服务不可用,是否继续?', + forcePull: '拉取最新镜像', server: '服务器', serverExample: '例: 80, 80-88, ip:80 或者 ip:80-88', containerExample: '例: 80 或者 80-88', diff --git a/frontend/src/views/container/container/index.vue b/frontend/src/views/container/container/index.vue index 88ed796e1..4e4c76e00 100644 --- a/frontend/src/views/container/container/index.vue +++ b/frontend/src/views/container/container/index.vue @@ -129,7 +129,7 @@ /> + + + {{ $t('container.forcePull') }} + + {{ $t('container.exposePort') }} diff --git a/frontend/src/views/container/container/upgrade/index.vue b/frontend/src/views/container/container/upgrade/index.vue index d365a889e..85dbae877 100644 --- a/frontend/src/views/container/container/upgrade/index.vue +++ b/frontend/src/views/container/container/upgrade/index.vue @@ -38,6 +38,11 @@ {{ $t('container.upgradeHelper') }} + + + {{ $t('container.forcePull') }} + + @@ -71,6 +76,7 @@ const form = reactive({ oldTag: '', newTag: '', fromApp: false, + forcePull: false, }); const formRef = ref(); @@ -106,7 +112,7 @@ const onSubmit = async (formEl: FormInstance | undefined) => { cancelButtonText: i18n.global.t('commons.button.cancel'), }).then(async () => { loading.value = true; - await upgradeContainer(form.name, form.imageName + ':' + form.newTag) + await upgradeContainer(form.name, form.imageName + ':' + form.newTag, form.forcePull) .then(() => { loading.value = false; emit('search');