mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-31 14:08:06 +08:00
feat: 镜像仓库增加状态列,连接判断
This commit is contained in:
parent
5945098844
commit
1ed0bb691a
@ -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
|
||||
}
|
||||
|
@ -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"`
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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"`
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -240,7 +240,6 @@ export namespace Container {
|
||||
}
|
||||
export interface DaemonJsonConf {
|
||||
status: string;
|
||||
bip: string;
|
||||
registryMirrors: Array<string>;
|
||||
insecureRegistries: Array<string>;
|
||||
liveRestore: boolean;
|
||||
|
@ -28,6 +28,16 @@
|
||||
fix
|
||||
/>
|
||||
<el-table-column :label="$t('container.protocol')" prop="protocol" min-width="60" fix />
|
||||
<el-table-column :label="$t('commons.table.status')" prop="status" min-width="60" fix>
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.status === 'Success'" type="success">
|
||||
{{ $t('commons.status.success') }}
|
||||
</el-tag>
|
||||
<el-tooltip v-else effect="dark" :content="row.message" placement="bottom">
|
||||
<el-tag type="danger">{{ $t('commons.status.failed') }}</el-tag>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('commons.table.createdAt')" min-width="80" fix>
|
||||
<template #default="{ row }">
|
||||
{{ dateFromat(0, 0, row.createdAt) }}
|
||||
|
@ -65,9 +65,6 @@
|
||||
v-model="form.registries"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="bip">
|
||||
<el-input clearable v-model="form.bip" />
|
||||
</el-form-item>
|
||||
<el-form-item label="live-restore" prop="liveRestore">
|
||||
<el-switch v-model="form.liveRestore"></el-switch>
|
||||
<span class="input-help">{{ $t('container.liveHelper') }}</span>
|
||||
@ -138,7 +135,6 @@ const loadLoadDir = async (path: string) => {
|
||||
|
||||
const form = reactive({
|
||||
status: '',
|
||||
bip: '',
|
||||
mirrors: '',
|
||||
registries: '',
|
||||
liveRestore: false,
|
||||
@ -212,7 +208,6 @@ const onSubmitSave = async () => {
|
||||
let itemRegistries = form.registries.split('\n');
|
||||
let param = {
|
||||
status: form.status,
|
||||
bip: form.bip,
|
||||
registryMirrors: itemMirrors.filter(function (el) {
|
||||
return el !== null && el !== '' && el !== undefined;
|
||||
}),
|
||||
@ -254,7 +249,6 @@ const changeMode = async () => {
|
||||
|
||||
const search = async () => {
|
||||
const res = await loadDaemonJson();
|
||||
form.bip = res.data.bip;
|
||||
form.status = res.data.status;
|
||||
form.cgroupDriver = res.data.cgroupDriver;
|
||||
form.liveRestore = res.data.liveRestore;
|
||||
|
@ -24,11 +24,10 @@
|
||||
@click="onChangeStatus(row.id, 'disable')"
|
||||
link
|
||||
type="success"
|
||||
icon="VideoPlay"
|
||||
>
|
||||
{{ $t('commons.status.enabled') }}
|
||||
</el-button>
|
||||
<el-button v-else link type="danger" @click="onChangeStatus(row.id, 'enable')" icon="VideoPause">
|
||||
<el-button v-else link type="danger" @click="onChangeStatus(row.id, 'enable')">
|
||||
{{ $t('commons.status.disabled') }}
|
||||
</el-button>
|
||||
</template>
|
||||
|
@ -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 = [
|
||||
|
Loading…
x
Reference in New Issue
Block a user