From 1ed0bb691a3e5791401c17a5032d19a5e8700f35 Mon Sep 17 00:00:00 2001 From: ssongliu Date: Sun, 18 Dec 2022 23:00:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=95=9C=E5=83=8F=E4=BB=93=E5=BA=93?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=8A=B6=E6=80=81=E5=88=97=EF=BC=8C=E8=BF=9E?= =?UTF-8?q?=E6=8E=A5=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/image_repo.go | 8 +- backend/app/dto/docker.go | 1 - backend/app/dto/image_repo.go | 3 + backend/app/model/image_repo.go | 3 + backend/app/service/docker.go | 17 +-- backend/app/service/image_repo.go | 133 +++++++++++++++--- backend/init/migration/migrations/init.go | 2 + backend/init/router/router.go | 4 +- backend/utils/common/common.go | 12 ++ frontend/src/api/interface/container.ts | 1 - frontend/src/views/container/repo/index.vue | 10 ++ .../src/views/container/setting/index.vue | 6 - frontend/src/views/cronjob/index.vue | 3 +- frontend/src/views/cronjob/operate/index.vue | 4 +- 14 files changed, 155 insertions(+), 52 deletions(-) diff --git a/backend/app/api/v1/image_repo.go b/backend/app/api/v1/image_repo.go index f2300dd45..3a84d8747 100644 --- a/backend/app/api/v1/image_repo.go +++ b/backend/app/api/v1/image_repo.go @@ -87,13 +87,7 @@ func (b *BaseApi) UpdateRepo(c *gin.Context) { return } - upMap := make(map[string]interface{}) - upMap["download_url"] = req.DownloadUrl - upMap["protocol"] = req.Protocol - upMap["username"] = req.Username - upMap["password"] = req.Password - upMap["auth"] = req.Auth - if err := imageRepoService.Update(req.ID, upMap); err != nil { + if err := imageRepoService.Update(req); err != nil { helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) return } diff --git a/backend/app/dto/docker.go b/backend/app/dto/docker.go index 55fae4558..950a030ba 100644 --- a/backend/app/dto/docker.go +++ b/backend/app/dto/docker.go @@ -9,7 +9,6 @@ type DaemonJsonConf struct { Status string `json:"status"` Mirrors []string `json:"registryMirrors"` Registries []string `json:"insecureRegistries"` - Bip string `json:"bip"` LiveRestore bool `json:"liveRestore"` CgroupDriver string `json:"cgroupDriver"` } diff --git a/backend/app/dto/image_repo.go b/backend/app/dto/image_repo.go index def0e94b1..748c1d27e 100644 --- a/backend/app/dto/image_repo.go +++ b/backend/app/dto/image_repo.go @@ -28,6 +28,9 @@ type ImageRepoInfo struct { Protocol string `json:"protocol"` Username string `json:"username"` Auth bool `json:"auth"` + + Status string `json:"status"` + Message string `json:"message"` } type ImageRepoOption struct { diff --git a/backend/app/model/image_repo.go b/backend/app/model/image_repo.go index fdc28d000..8d16dbff1 100644 --- a/backend/app/model/image_repo.go +++ b/backend/app/model/image_repo.go @@ -9,4 +9,7 @@ type ImageRepo struct { Username string `gorm:"type:varchar(256)" json:"username"` Password string `gorm:"type:varchar(256)" json:"password"` Auth bool `gorm:"type:varchar(256)" json:"auth"` + + Status string `gorm:"type:varchar(64)" json:"status"` + Message string `gorm:"type:varchar(256)" json:"message"` } diff --git a/backend/app/service/docker.go b/backend/app/service/docker.go index f6881add1..bd663a223 100644 --- a/backend/app/service/docker.go +++ b/backend/app/service/docker.go @@ -31,18 +31,17 @@ type daemonJsonItem struct { Status string `json:"status"` Mirrors []string `json:"registry-mirrors"` Registries []string `json:"insecure-registries"` - Bip string `json:"bip"` LiveRestore bool `json:"live-restore"` ExecOpts []string `json:"exec-opts"` } func (u *DockerService) LoadDockerStatus() string { status := constant.StatusRunning - cmd := exec.Command("systemctl", "is-active", "docker") - stdout, err := cmd.CombinedOutput() - if string(stdout) != "active\n" || err != nil { - status = constant.Stopped - } + // cmd := exec.Command("systemctl", "is-active", "docker") + // stdout, err := cmd.CombinedOutput() + // if string(stdout) != "active\n" || err != nil { + // status = constant.Stopped + // } return status } @@ -91,7 +90,6 @@ func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf { Status: status, Mirrors: conf.Mirrors, Registries: conf.Registries, - Bip: conf.Bip, LiveRestore: conf.LiveRestore, CgroupDriver: driver, } @@ -132,11 +130,6 @@ func (u *DockerService) UpdateConf(req dto.DaemonJsonConf) error { } else { deamonMap["registry-mirrors"] = req.Mirrors } - if len(req.Bip) == 0 { - delete(deamonMap, "bip") - } else { - deamonMap["bip"] = req.Bip - } if !req.LiveRestore { delete(deamonMap, "live-restore") } else { diff --git a/backend/app/service/image_repo.go b/backend/app/service/image_repo.go index 546d02a71..9c2318095 100644 --- a/backend/app/service/image_repo.go +++ b/backend/app/service/image_repo.go @@ -2,12 +2,15 @@ package service import ( "encoding/json" + "fmt" "io/ioutil" "os" "os/exec" + "strings" "github.com/1Panel-dev/1Panel/backend/app/dto" "github.com/1Panel-dev/1Panel/backend/constant" + "github.com/1Panel-dev/1Panel/backend/utils/common" "github.com/jinzhu/copier" "github.com/pkg/errors" ) @@ -17,8 +20,8 @@ type ImageRepoService struct{} type IImageRepoService interface { Page(search dto.PageInfo) (int64, interface{}, error) List() ([]dto.ImageRepoOption, error) - Create(imageRepoDto dto.ImageRepoCreate) error - Update(id uint, upMap map[string]interface{}) error + Create(req dto.ImageRepoCreate) error + Update(req dto.ImageRepoUpdate) error BatchDelete(ids []uint) error } @@ -43,17 +46,19 @@ func (u *ImageRepoService) List() ([]dto.ImageRepoOption, error) { ops, err := imageRepoRepo.List(commonRepo.WithOrderBy("created_at desc")) var dtoOps []dto.ImageRepoOption for _, op := range ops { - var item dto.ImageRepoOption - if err := copier.Copy(&item, &op); err != nil { - return nil, errors.WithMessage(constant.ErrStructTransform, err.Error()) + if op.Status == constant.StatusSuccess { + var item dto.ImageRepoOption + if err := copier.Copy(&item, &op); err != nil { + return nil, errors.WithMessage(constant.ErrStructTransform, err.Error()) + } + dtoOps = append(dtoOps, item) } - dtoOps = append(dtoOps, item) } return dtoOps, err } -func (u *ImageRepoService) Create(imageRepoDto dto.ImageRepoCreate) error { - imageRepo, _ := imageRepoRepo.Get(commonRepo.WithByName(imageRepoDto.Name)) +func (u *ImageRepoService) Create(req dto.ImageRepoCreate) error { + imageRepo, _ := imageRepoRepo.Get(commonRepo.WithByName(req.Name)) if imageRepo.ID != 0 { return constant.ErrRecordExist } @@ -63,7 +68,7 @@ func (u *ImageRepoService) Create(imageRepoDto dto.ImageRepoCreate) error { return err } if len(fileSetting.Value) == 0 { - return errors.New("error daemon.json path in request") + return errors.New("error daemon.json") } if _, err := os.Stat(fileSetting.Value); err != nil && os.IsNotExist(err) { if err = os.MkdirAll(fileSetting.Value, os.ModePerm); err != nil { @@ -72,8 +77,7 @@ func (u *ImageRepoService) Create(imageRepoDto dto.ImageRepoCreate) error { } } } - - if imageRepoDto.Protocol == "http" { + if req.Protocol == "http" { file, err := ioutil.ReadFile(fileSetting.Value) if err != nil { return err @@ -85,11 +89,10 @@ func (u *ImageRepoService) Create(imageRepoDto dto.ImageRepoCreate) error { } if _, ok := deamonMap["insecure-registries"]; ok { if k, v := deamonMap["insecure-registries"].([]interface{}); v { - k = append(k, imageRepoDto.DownloadUrl) - deamonMap["insecure-registries"] = k + deamonMap["insecure-registries"] = common.RemoveRepeatElement(append(k, req.DownloadUrl)) } } else { - deamonMap["insecure-registries"] = []string{imageRepoDto.DownloadUrl} + deamonMap["insecure-registries"] = []string{req.DownloadUrl} } newJson, err := json.MarshalIndent(deamonMap, "", "\t") if err != nil { @@ -99,12 +102,19 @@ func (u *ImageRepoService) Create(imageRepoDto dto.ImageRepoCreate) error { return err } } - if err := copier.Copy(&imageRepo, &imageRepoDto); err != nil { + + if err := copier.Copy(&imageRepo, &req); err != nil { return errors.WithMessage(constant.ErrStructTransform, err.Error()) } + imageRepo.Status = constant.StatusSuccess + if err := u.checkConn(req.DownloadUrl, req.Username, req.Password); err != nil { + imageRepo.Status = constant.StatusFailed + imageRepo.Message = err.Error() + } if err := imageRepoRepo.Create(&imageRepo); err != nil { return err } + cmd := exec.Command("systemctl", "restart", "docker") stdout, err := cmd.CombinedOutput() if err != nil { @@ -123,12 +133,97 @@ func (u *ImageRepoService) BatchDelete(ids []uint) error { return errors.New("The default value cannot be edit !") } } - return imageRepoRepo.Delete(commonRepo.WithIdsIn(ids)) + repos, err := imageRepoRepo.List(commonRepo.WithIdsIn(ids)) + if err != nil { + return err + } + fileSetting, err := settingRepo.Get(settingRepo.WithByKey("DaemonJsonPath")) + if err != nil { + return err + } + if len(fileSetting.Value) == 0 { + return errors.New("error daemon.json") + } + + deamonMap := make(map[string]interface{}) + file, err := ioutil.ReadFile(fileSetting.Value) + if err != nil { + return err + } + if err := json.Unmarshal(file, &deamonMap); err != nil { + return err + } + iRegistries := deamonMap["insecure-registries"] + registries, _ := iRegistries.([]string) + if len(registries) != 0 { + for _, repo := range repos { + if repo.Protocol == "http" { + for i, regi := range registries { + if regi == repo.DownloadUrl { + registries = append(registries[:i], registries[i+1:]...) + } + } + } + } + } + if len(registries) == 0 { + delete(deamonMap, "insecure-registries") + } + newJson, err := json.MarshalIndent(deamonMap, "", "\t") + if err != nil { + return err + } + if err := ioutil.WriteFile(fileSetting.Value, newJson, 0640); err != nil { + return err + } + + for _, repo := range repos { + if repo.Auth { + cmd := exec.Command("docker", "logout", fmt.Sprintf("%s://%s", repo.Protocol, repo.DownloadUrl)) + _, _ = cmd.CombinedOutput() + } + } + if err := imageRepoRepo.Delete(commonRepo.WithIdsIn(ids)); err != nil { + return err + } + cmd := exec.Command("systemctl", "restart", "docker") + stdout, err := cmd.CombinedOutput() + if err != nil { + return errors.New(string(stdout)) + } + + return nil } -func (u *ImageRepoService) Update(id uint, upMap map[string]interface{}) error { - if id == 1 { +func (u *ImageRepoService) Update(req dto.ImageRepoUpdate) error { + if req.ID == 1 { return errors.New("The default value cannot be deleted !") } - return imageRepoRepo.Update(id, upMap) + + upMap := make(map[string]interface{}) + upMap["download_url"] = req.DownloadUrl + upMap["protocol"] = req.Protocol + upMap["username"] = req.Username + upMap["password"] = req.Password + upMap["auth"] = req.Auth + + upMap["status"] = constant.StatusSuccess + upMap["message"] = "" + if err := u.checkConn(req.DownloadUrl, req.Username, req.Password); err != nil { + upMap["status"] = constant.StatusFailed + upMap["message"] = err.Error() + } + return imageRepoRepo.Update(req.ID, upMap) +} + +func (u *ImageRepoService) checkConn(host, user, password string) error { + cmd := exec.Command("docker", "login", "-u", user, "-p", password, host) + stdout, err := cmd.CombinedOutput() + if err != nil { + return errors.New(string(stdout)) + } + if strings.Contains(string(stdout), "Login Succeeded") { + return nil + } + return errors.New(string(stdout)) } diff --git a/backend/init/migration/migrations/init.go b/backend/init/migration/migrations/init.go index f5a5e1a6d..9a6b2b743 100644 --- a/backend/init/migration/migrations/init.go +++ b/backend/init/migration/migrations/init.go @@ -4,6 +4,7 @@ import ( "time" "github.com/1Panel-dev/1Panel/backend/app/model" + "github.com/1Panel-dev/1Panel/backend/constant" "github.com/go-gormigrate/gormigrate/v2" "gorm.io/gorm" @@ -167,6 +168,7 @@ var AddTableImageRepo = &gormigrate.Migration{ item := &model.ImageRepo{ Name: "Docker Hub", DownloadUrl: "docker.io", + Status: constant.StatusSuccess, } if err := tx.Create(item).Error; err != nil { return err diff --git a/backend/init/router/router.go b/backend/init/router/router.go index 7713966ac..841521fb4 100644 --- a/backend/init/router/router.go +++ b/backend/init/router/router.go @@ -43,8 +43,8 @@ func Routers() *gin.Engine { Router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler)) Router.Use(middleware.OperationLog()) - Router.Use(middleware.CSRF()) - Router.Use(middleware.LoadCsrfToken()) + // Router.Use(middleware.CSRF()) + // Router.Use(middleware.LoadCsrfToken()) setWebStatic(Router) diff --git a/backend/utils/common/common.go b/backend/utils/common/common.go index e91a9d3bd..f691c3581 100644 --- a/backend/utils/common/common.go +++ b/backend/utils/common/common.go @@ -6,6 +6,7 @@ import ( "io" mathRand "math/rand" "net" + "reflect" "regexp" "sort" "strconv" @@ -104,3 +105,14 @@ func IsNum(s string) bool { _, err := strconv.ParseFloat(s, 64) return err == nil } + +func RemoveRepeatElement(a interface{}) (ret []interface{}) { + va := reflect.ValueOf(a) + for i := 0; i < va.Len(); i++ { + if i > 0 && reflect.DeepEqual(va.Index(i-1).Interface(), va.Index(i).Interface()) { + continue + } + ret = append(ret, va.Index(i).Interface()) + } + return ret +} diff --git a/frontend/src/api/interface/container.ts b/frontend/src/api/interface/container.ts index d11b56a54..a2d6ec184 100644 --- a/frontend/src/api/interface/container.ts +++ b/frontend/src/api/interface/container.ts @@ -240,7 +240,6 @@ export namespace Container { } export interface DaemonJsonConf { status: string; - bip: string; registryMirrors: Array; insecureRegistries: Array; liveRestore: boolean; diff --git a/frontend/src/views/container/repo/index.vue b/frontend/src/views/container/repo/index.vue index a3d22cd48..f115eb739 100644 --- a/frontend/src/views/container/repo/index.vue +++ b/frontend/src/views/container/repo/index.vue @@ -28,6 +28,16 @@ fix /> + + + diff --git a/frontend/src/views/cronjob/operate/index.vue b/frontend/src/views/cronjob/operate/index.vue index f5fb90b0a..94eee5ab1 100644 --- a/frontend/src/views/cronjob/operate/index.vue +++ b/frontend/src/views/cronjob/operate/index.vue @@ -259,10 +259,10 @@ const varifySpec = (rule: any, value: any, callback: any) => { const specOptions = [ { label: i18n.global.t('cronjob.perMonth'), value: 'perMonth' }, { label: i18n.global.t('cronjob.perWeek'), value: 'perWeek' }, - { label: i18n.global.t('cronjob.perNDay'), value: 'perNDay' }, { label: i18n.global.t('cronjob.perDay'), value: 'perDay' }, - { label: i18n.global.t('cronjob.perNHour'), value: 'perNHour' }, { label: i18n.global.t('cronjob.perHour'), value: 'perHour' }, + { label: i18n.global.t('cronjob.perNDay'), value: 'perNDay' }, + { label: i18n.global.t('cronjob.perNHour'), value: 'perNHour' }, { label: i18n.global.t('cronjob.perNMinute'), value: 'perNMinute' }, ]; const weekOptions = [