mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-19 08:19:15 +08:00
feat: http 仓库添加时增加授信操作
This commit is contained in:
parent
2cb1b57069
commit
f98f9a5872
@ -94,7 +94,7 @@ func (b *BaseApi) UpdateRepo(c *gin.Context) {
|
||||
|
||||
upMap := make(map[string]interface{})
|
||||
upMap["download_url"] = req.DownloadUrl
|
||||
upMap["repo_name"] = req.RepoName
|
||||
upMap["protocol"] = req.Protocol
|
||||
upMap["username"] = req.Username
|
||||
upMap["password"] = req.Password
|
||||
upMap["auth"] = req.Auth
|
||||
|
@ -19,7 +19,7 @@ type ImageRemove struct {
|
||||
}
|
||||
|
||||
type ImagePull struct {
|
||||
RepoID uint `josn:"repoID" validate:"required"`
|
||||
RepoID uint `josn:"repoID"`
|
||||
ImageName string `josn:"imageName" validate:"required"`
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ import "time"
|
||||
type ImageRepoCreate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
DownloadUrl string `json:"downloadUrl"`
|
||||
RepoName string `json:"repoName"`
|
||||
Protocol string `json:"protocol"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Auth bool `json:"auth"`
|
||||
@ -14,7 +14,7 @@ type ImageRepoCreate struct {
|
||||
type ImageRepoUpdate struct {
|
||||
ID uint `json:"id"`
|
||||
DownloadUrl string `json:"downloadUrl"`
|
||||
RepoName string `json:"repoName"`
|
||||
Protocol string `json:"protocol"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Auth bool `json:"auth"`
|
||||
@ -25,7 +25,7 @@ type ImageRepoInfo struct {
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Name string `json:"name"`
|
||||
DownloadUrl string `json:"downloadUrl"`
|
||||
RepoName string `json:"repoName"`
|
||||
Protocol string `json:"protocol"`
|
||||
Username string `json:"username"`
|
||||
Auth bool `json:"auth"`
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ type ImageRepo struct {
|
||||
|
||||
Name string `gorm:"type:varchar(64);not null" json:"name"`
|
||||
DownloadUrl string `gorm:"type:varchar(256)" json:"downloadUrl"`
|
||||
RepoName string `gorm:"type:varchar(256)" json:"repoName"`
|
||||
Protocol string `gorm:"type:varchar(64)" json:"protocol"`
|
||||
Username string `gorm:"type:varchar(256)" json:"username"`
|
||||
Password string `gorm:"type:varchar(256)" json:"password"`
|
||||
Auth bool `gorm:"type:varchar(256)" json:"auth"`
|
||||
|
@ -78,7 +78,20 @@ func (u *ImageService) ImagePull(req dto.ImagePull) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx := context.Background()
|
||||
if req.RepoID == 0 {
|
||||
go func() {
|
||||
out, err := client.ImagePull(context.TODO(), req.ImageName, types.ImagePullOptions{})
|
||||
if err != nil {
|
||||
global.LOG.Errorf("image %s pull failed, err: %v", req.ImageName, err)
|
||||
return
|
||||
}
|
||||
defer out.Close()
|
||||
buf := new(bytes.Buffer)
|
||||
_, _ = buf.ReadFrom(out)
|
||||
global.LOG.Debugf("image %s pull stdout: %v", req.ImageName, buf.String())
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
repo, err := imageRepoRepo.Get(commonRepo.WithByID(req.RepoID))
|
||||
if err != nil {
|
||||
return err
|
||||
@ -97,11 +110,8 @@ func (u *ImageService) ImagePull(req dto.ImagePull) error {
|
||||
options.RegistryAuth = authStr
|
||||
}
|
||||
image := repo.DownloadUrl + "/" + req.ImageName
|
||||
if len(repo.RepoName) != 0 {
|
||||
image = fmt.Sprintf("%s/%s/%s", repo.DownloadUrl, repo.RepoName, req.ImageName)
|
||||
}
|
||||
go func() {
|
||||
out, err := client.ImagePull(ctx, image, options)
|
||||
out, err := client.ImagePull(context.TODO(), image, options)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("image %s pull failed, err: %v", image, err)
|
||||
return
|
||||
|
@ -1,6 +1,9 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/constant"
|
||||
"github.com/jinzhu/copier"
|
||||
@ -48,10 +51,34 @@ func (u *ImageRepoService) List() ([]dto.ImageRepoOption, error) {
|
||||
}
|
||||
|
||||
func (u *ImageRepoService) Create(imageRepoDto dto.ImageRepoCreate) error {
|
||||
imageRepo, _ := imageRepoRepo.Get(commonRepo.WithByName(imageRepoDto.RepoName))
|
||||
imageRepo, _ := imageRepoRepo.Get(commonRepo.WithByName(imageRepoDto.Name))
|
||||
if imageRepo.ID != 0 {
|
||||
return constant.ErrRecordExist
|
||||
}
|
||||
if imageRepo.Protocol == "http" {
|
||||
file, err := ioutil.ReadFile(constant.DaemonJsonDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
deamonMap := make(map[string]interface{})
|
||||
if err := json.Unmarshal(file, &deamonMap); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, ok := deamonMap["insecure-registries"]; ok {
|
||||
if k, v := deamonMap["insecure-registries"].([]interface{}); v {
|
||||
k = append(k, imageRepoDto.DownloadUrl)
|
||||
deamonMap["insecure-registries"] = k
|
||||
}
|
||||
}
|
||||
newJson, err := json.Marshal(deamonMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(constant.DaemonJsonDir, newJson, 0777); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := copier.Copy(&imageRepo, &imageRepoDto); err != nil {
|
||||
return errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
@ -61,6 +88,10 @@ func (u *ImageRepoService) Create(imageRepoDto dto.ImageRepoCreate) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type DeamonJson struct {
|
||||
InsecureRegistries []string `json:"insecure-registries"`
|
||||
}
|
||||
|
||||
func (u *ImageRepoService) BatchDelete(ids []uint) error {
|
||||
for _, id := range ids {
|
||||
if id == 1 {
|
||||
|
@ -2,11 +2,14 @@ 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"
|
||||
)
|
||||
|
||||
@ -28,3 +31,34 @@ func TestImage(t *testing.T) {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -9,4 +9,6 @@ const (
|
||||
ContainerOpUnpause = "unPause"
|
||||
ContainerOpRename = "reName"
|
||||
ContainerOpRemove = "remove"
|
||||
|
||||
DaemonJsonDir = "/System/Volumes/Data/Users/slooop/.docker/daemon.json"
|
||||
)
|
||||
|
@ -53,7 +53,7 @@ export namespace Container {
|
||||
export interface RepoCreate {
|
||||
name: string;
|
||||
downloadUrl: string;
|
||||
repoName: string;
|
||||
protocol: string;
|
||||
username: string;
|
||||
password: string;
|
||||
auth: boolean;
|
||||
@ -61,6 +61,7 @@ export namespace Container {
|
||||
export interface RepoUpdate {
|
||||
id: number;
|
||||
downloadUrl: string;
|
||||
protocol: string;
|
||||
username: string;
|
||||
password: string;
|
||||
auth: boolean;
|
||||
@ -70,7 +71,7 @@ export namespace Container {
|
||||
createdAt: Date;
|
||||
name: string;
|
||||
downloadUrl: string;
|
||||
repoName: string;
|
||||
protocol: string;
|
||||
username: string;
|
||||
password: string;
|
||||
auth: boolean;
|
||||
|
@ -172,7 +172,6 @@ export default {
|
||||
last10Min: 'Last 10 Minutes',
|
||||
|
||||
image: 'Image',
|
||||
pullFromRepo: 'Pull from repo',
|
||||
imagePull: 'Image pull',
|
||||
imagePush: 'Image push',
|
||||
repoName: 'Repo Name',
|
||||
@ -189,11 +188,13 @@ export default {
|
||||
exportImage: 'ExportImage',
|
||||
version: 'Version',
|
||||
size: 'Size',
|
||||
from: 'From',
|
||||
|
||||
repo: 'Repo',
|
||||
name: 'Name',
|
||||
protocol: 'protocol',
|
||||
downloadUrl: 'Download URL',
|
||||
imageRepo: 'ImageRepo',
|
||||
imageRepo: 'Image repo',
|
||||
repoHelper: 'Does it include a mirror repository/organization/project?',
|
||||
auth: 'Auth',
|
||||
},
|
||||
|
@ -169,7 +169,6 @@ export default {
|
||||
last10Min: '最近 10 分钟',
|
||||
|
||||
image: '镜像',
|
||||
pullFromRepo: '从仓库中拉取',
|
||||
imagePull: '镜像拉取',
|
||||
imagePush: '镜像推送',
|
||||
repoName: '仓库名',
|
||||
@ -186,11 +185,13 @@ export default {
|
||||
exportImage: '导出镜像',
|
||||
version: '版本',
|
||||
size: '大小',
|
||||
from: '来源',
|
||||
|
||||
repo: '仓库',
|
||||
name: '名称',
|
||||
protocol: '协议',
|
||||
downloadUrl: '下载地址',
|
||||
imageRepo: '镜像库',
|
||||
imageRepo: '镜像仓库',
|
||||
repoHelper: '是否包含镜像仓库/组织/项目?',
|
||||
auth: '认证',
|
||||
},
|
||||
|
@ -3,10 +3,10 @@
|
||||
<el-card style="margin-top: 20px">
|
||||
<ComplexTable :pagination-config="paginationConfig" v-model:selects="selects" :data="data" @search="search">
|
||||
<template #toolbar>
|
||||
<el-button type="primary" @click="pullVisiable = true">
|
||||
{{ $t('container.pullFromRepo') }}
|
||||
<el-button @click="onOpenPull">
|
||||
{{ $t('container.imagePull') }}
|
||||
</el-button>
|
||||
<el-button @click="loadVisiable = true">
|
||||
<el-button @click="onOpenload">
|
||||
{{ $t('container.importImage') }}
|
||||
</el-button>
|
||||
<el-button @click="onBatchDelete(null)">
|
||||
@ -30,28 +30,30 @@
|
||||
</ComplexTable>
|
||||
</el-card>
|
||||
|
||||
<el-dialog v-model="pullVisiable" :destroy-on-close="true" :close-on-click-modal="false" width="50%">
|
||||
<el-dialog v-model="pullVisiable" :destroy-on-close="true" :close-on-click-modal="false" width="30%">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>{{ $t('container.imagePull') }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form ref="pullFormRef" :model="pullForm" label-width="80px">
|
||||
<el-form-item :label="$t('container.repoName')" :rules="Rules.requiredSelect" prop="repoID">
|
||||
<el-form-item :label="$t('container.from')">
|
||||
<el-checkbox v-model="pullForm.fromRepo">{{ $t('container.imageRepo') }}</el-checkbox>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="pullForm.fromRepo"
|
||||
:label="$t('container.repoName')"
|
||||
:rules="Rules.requiredSelect"
|
||||
prop="repoID"
|
||||
>
|
||||
<el-select style="width: 100%" filterable v-model="pullForm.repoID">
|
||||
<el-option
|
||||
v-for="item in repos"
|
||||
:key="item.id"
|
||||
:value="item.id"
|
||||
:label="item.name + ' [ ' + item.downloadUrl + ' ] '"
|
||||
/>
|
||||
<el-option v-for="item in repos" :key="item.id" :value="item.id" :label="item.name" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('container.imageName')" :rules="Rules.requiredInput" prop="imageName">
|
||||
<el-input v-model="pullForm.imageName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="pullForm.imageName !== ''">
|
||||
<el-tag>docker pull {{ loadDetailInfo(pullForm.repoID) }}/{{ pullForm.imageName }}</el-tag>
|
||||
<el-input v-model="pullForm.imageName">
|
||||
<template v-if="pullForm.fromRepo" #prepend>{{ loadDetailInfo(pullForm.repoID) }}/</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
@ -73,24 +75,13 @@
|
||||
<el-form ref="pushFormRef" :model="pushForm" label-width="80px">
|
||||
<el-form-item :label="$t('container.repoName')" :rules="Rules.requiredSelect" prop="repoID">
|
||||
<el-select style="width: 100%" filterable v-model="pushForm.repoID">
|
||||
<el-option
|
||||
v-for="item in repos"
|
||||
:key="item.id"
|
||||
:value="item.id"
|
||||
:label="item.name + ' [ ' + item.downloadUrl + ' ] '"
|
||||
/>
|
||||
<el-option v-for="item in repos" :key="item.id" :value="item.id" :label="item.name" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('container.label')" :rules="Rules.requiredInput" prop="tagName">
|
||||
<el-input v-model="pushForm.tagName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="pushForm.tagName !== ''">
|
||||
<el-tag>
|
||||
docker tag {{ pushForm.imageName }} {{ loadDetailInfo(pushForm.repoID) }}/{{ pushForm.tagName }}
|
||||
</el-tag>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="pushForm.tagName !== ''">
|
||||
<el-tag>docker push {{ loadDetailInfo(pushForm.repoID) }}/{{ pushForm.tagName }}</el-tag>
|
||||
<el-input v-model="pushForm.tagName">
|
||||
<template #prepend>{{ loadDetailInfo(pushForm.repoID) }}/</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
@ -198,6 +189,7 @@ type FormInstance = InstanceType<typeof ElForm>;
|
||||
const pullVisiable = ref(false);
|
||||
const pullFormRef = ref<FormInstance>();
|
||||
const pullForm = reactive({
|
||||
fromRepo: true,
|
||||
repoID: 1,
|
||||
imageName: '',
|
||||
});
|
||||
@ -248,12 +240,20 @@ const loadLoadDir = async (path: string) => {
|
||||
loadForm.path = path;
|
||||
};
|
||||
|
||||
const onOpenPull = () => {
|
||||
pullVisiable.value = true;
|
||||
pullForm.imageName = '';
|
||||
pullForm.repoID = 1;
|
||||
};
|
||||
const submitPull = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
try {
|
||||
loading.value = true;
|
||||
if (!pullForm.fromRepo) {
|
||||
pullForm.repoID = 0;
|
||||
}
|
||||
pullVisiable.value = false;
|
||||
await imagePull(pullForm);
|
||||
loading.value = false;
|
||||
@ -284,6 +284,10 @@ const submitPush = async (formEl: FormInstance | undefined) => {
|
||||
});
|
||||
};
|
||||
|
||||
const onOpenload = () => {
|
||||
loadVisiable.value = true;
|
||||
loadForm.path = '';
|
||||
};
|
||||
const submitLoad = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
|
@ -19,13 +19,7 @@
|
||||
min-width="100"
|
||||
fix
|
||||
/>
|
||||
<el-table-column
|
||||
:label="$t('container.imageRepo')"
|
||||
show-overflow-tooltip
|
||||
prop="repoName"
|
||||
min-width="70"
|
||||
fix
|
||||
/>
|
||||
<el-table-column :label="$t('container.protocol')" prop="protocol" min-width="60" fix />
|
||||
<el-table-column :label="$t('commons.table.createdAt')" min-width="80" fix>
|
||||
<template #default="{ row }">
|
||||
{{ dateFromat(0, 0, row.createdAt) }}
|
||||
@ -78,6 +72,7 @@ const onOpenDialog = async (
|
||||
title: string,
|
||||
rowData: Partial<Container.RepoInfo> = {
|
||||
auth: true,
|
||||
protocol: 'http',
|
||||
},
|
||||
) => {
|
||||
let params = {
|
||||
|
@ -24,9 +24,11 @@
|
||||
<el-form-item :label="$t('container.downloadUrl')" prop="downloadUrl">
|
||||
<el-input v-model="dialogData.rowData!.downloadUrl" :placeholder="'172.16.10.10:8081'"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('container.imageRepo')" prop="repoName">
|
||||
<el-checkbox v-model="hasRepo">{{ $t('container.repoHelper') }}</el-checkbox>
|
||||
<el-input v-if="hasRepo" v-model="dialogData.rowData!.repoName"></el-input>
|
||||
<el-form-item :label="$t('container.protocol')" prop="protocol">
|
||||
<el-radio-group v-model="dialogData.rowData!.protocol">
|
||||
<el-radio label="http">http</el-radio>
|
||||
<el-radio label="https">https</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
@ -61,16 +63,14 @@ const dialogData = ref<DialogProps>({
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
dialogData.value = params;
|
||||
title.value = i18n.global.t('commons.button.' + dialogData.value.title);
|
||||
hasRepo.value = params.rowData?.repoName ? params.rowData?.repoName.length !== 0 : false;
|
||||
repoVisiable.value = true;
|
||||
};
|
||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||
|
||||
const hasRepo = ref(false);
|
||||
const rules = reactive({
|
||||
name: [Rules.requiredInput, Rules.name],
|
||||
downloadUrl: [Rules.requiredInput],
|
||||
repoName: [Rules.requiredInput],
|
||||
protocol: [Rules.requiredSelect],
|
||||
username: [Rules.requiredInput],
|
||||
password: [Rules.requiredInput],
|
||||
auth: [Rules.requiredSelect],
|
||||
|
Loading…
x
Reference in New Issue
Block a user