mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2024-11-28 21:39:06 +08:00
fix: 增加 docker 仓库授信删除判断
This commit is contained in:
parent
bdecd777a7
commit
326941ad48
@ -59,7 +59,7 @@ func (b *BaseApi) CreateRepo(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (b *BaseApi) DeleteRepo(c *gin.Context) {
|
||||
var req dto.BatchDeleteReq
|
||||
var req dto.ImageRepoDelete
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
@ -69,7 +69,7 @@ func (b *BaseApi) DeleteRepo(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := imageRepoService.BatchDelete(req.Ids); err != nil {
|
||||
if err := imageRepoService.BatchDelete(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
|
@ -38,3 +38,8 @@ type ImageRepoOption struct {
|
||||
Name string `json:"name"`
|
||||
DownloadUrl string `json:"downloadUrl"`
|
||||
}
|
||||
|
||||
type ImageRepoDelete struct {
|
||||
DeleteInsecure bool `json:"deleteInsecure"`
|
||||
Ids []uint `json:"ids" validate:"required"`
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ type IImageRepoService interface {
|
||||
List() ([]dto.ImageRepoOption, error)
|
||||
Create(req dto.ImageRepoCreate) error
|
||||
Update(req dto.ImageRepoUpdate) error
|
||||
BatchDelete(ids []uint) error
|
||||
BatchDelete(req dto.ImageRepoDelete) error
|
||||
}
|
||||
|
||||
func NewIImageRepoService() IImageRepoService {
|
||||
@ -70,6 +70,13 @@ func (u *ImageRepoService) Create(req dto.ImageRepoCreate) error {
|
||||
if err := copier.Copy(&imageRepo, &req); err != nil {
|
||||
return errors.WithMessage(constant.ErrStructTransform, err.Error())
|
||||
}
|
||||
|
||||
cmd := exec.Command("systemctl", "restart", "docker")
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return errors.New(string(stdout))
|
||||
}
|
||||
|
||||
imageRepo.Status = constant.StatusSuccess
|
||||
if err := u.checkConn(req.DownloadUrl, req.Username, req.Password); err != nil {
|
||||
imageRepo.Status = constant.StatusFailed
|
||||
@ -79,21 +86,22 @@ func (u *ImageRepoService) Create(req dto.ImageRepoCreate) error {
|
||||
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) BatchDelete(ids []uint) error {
|
||||
for _, id := range ids {
|
||||
func (u *ImageRepoService) BatchDelete(req dto.ImageRepoDelete) error {
|
||||
for _, id := range req.Ids {
|
||||
if id == 1 {
|
||||
return errors.New("The default value cannot be edit !")
|
||||
}
|
||||
}
|
||||
repos, err := imageRepoRepo.List(commonRepo.WithIdsIn(ids))
|
||||
if !req.DeleteInsecure {
|
||||
if err := imageRepoRepo.Delete(commonRepo.WithIdsIn(req.Ids)); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
repos, err := imageRepoRepo.List(commonRepo.WithIdsIn(req.Ids))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -106,7 +114,7 @@ func (u *ImageRepoService) BatchDelete(ids []uint) error {
|
||||
_, _ = cmd.CombinedOutput()
|
||||
}
|
||||
}
|
||||
if err := imageRepoRepo.Delete(commonRepo.WithIdsIn(ids)); err != nil {
|
||||
if err := imageRepoRepo.Delete(commonRepo.WithIdsIn(req.Ids)); err != nil {
|
||||
return err
|
||||
}
|
||||
cmd := exec.Command("systemctl", "restart", "docker")
|
||||
@ -129,9 +137,14 @@ func (u *ImageRepoService) Update(req dto.ImageRepoUpdate) error {
|
||||
if repo.DownloadUrl != req.DownloadUrl {
|
||||
_ = u.handleRegistries(req.DownloadUrl, repo.DownloadUrl, "update")
|
||||
if repo.Auth {
|
||||
cmd := exec.Command("docker", "logout", fmt.Sprintf("%s://%s", repo.Protocol, repo.DownloadUrl))
|
||||
cmd := exec.Command("docker", "logout", repo.DownloadUrl)
|
||||
_, _ = cmd.CombinedOutput()
|
||||
}
|
||||
cmd := exec.Command("systemctl", "restart", "docker")
|
||||
stdout, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return errors.New(string(stdout))
|
||||
}
|
||||
}
|
||||
|
||||
upMap := make(map[string]interface{})
|
||||
|
@ -152,6 +152,10 @@ export namespace Container {
|
||||
password: string;
|
||||
auth: boolean;
|
||||
}
|
||||
export interface RepoDelete {
|
||||
ids: Array<number>;
|
||||
deleteInsecure: boolean;
|
||||
}
|
||||
export interface RepoInfo {
|
||||
id: number;
|
||||
createdAt: Date;
|
||||
|
@ -88,7 +88,7 @@ export const createImageRepo = (params: Container.RepoCreate) => {
|
||||
export const updateImageRepo = (params: Container.RepoUpdate) => {
|
||||
return http.post(`/containers/repo/update`, params);
|
||||
};
|
||||
export const deleteImageRepo = (params: { ids: number[] }) => {
|
||||
export const deleteImageRepo = (params: Container.RepoDelete) => {
|
||||
return http.post(`/containers/repo/del`, params);
|
||||
};
|
||||
|
||||
|
@ -439,6 +439,9 @@ export default {
|
||||
repo: 'Repo',
|
||||
name: 'Name',
|
||||
protocol: 'protocol',
|
||||
httpRepo: 'The http repository needs to restart the docker service to add credit',
|
||||
delInsecure: 'Deletion of credit',
|
||||
delInsecureHelper: 'docker service needs to be restarted to delete the credit. Do you want to delete it?',
|
||||
downloadUrl: 'Download URL',
|
||||
imageRepo: 'Image repo',
|
||||
repoHelper: 'Does it include a mirror repository/organization/project?',
|
||||
|
@ -415,6 +415,9 @@ export default {
|
||||
imageDelete: '删除镜像',
|
||||
repoName: '仓库名',
|
||||
imageName: '镜像名',
|
||||
httpRepo: 'http 仓库添加授信需要重启 docker 服务',
|
||||
delInsecure: '删除授信',
|
||||
delInsecureHelper: '删除授信需要重启 docker 服务,是否删除?',
|
||||
pull: '拉取',
|
||||
path: '路径',
|
||||
importImage: '导入镜像',
|
||||
|
@ -144,7 +144,7 @@ const search = async () => {
|
||||
};
|
||||
const loadRepos = async () => {
|
||||
const res = await listImageRepo();
|
||||
repos.value = res.data;
|
||||
repos.value = res.data || [];
|
||||
};
|
||||
|
||||
const onOpenPull = () => {
|
||||
|
@ -22,7 +22,7 @@
|
||||
prop="repoID"
|
||||
>
|
||||
<el-select style="width: 100%" filterable v-model="form.repoID">
|
||||
<el-option v-for="item in dialogData.repos" :key="item.id" :value="item.id" :label="item.name" />
|
||||
<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">
|
||||
@ -75,7 +75,7 @@ import { LoadFile } from '@/api/modules/files';
|
||||
const pullVisiable = ref(false);
|
||||
const form = reactive({
|
||||
fromRepo: true,
|
||||
repoID: 1,
|
||||
repoID: null as number,
|
||||
imageName: '',
|
||||
});
|
||||
|
||||
@ -89,16 +89,13 @@ let timer: NodeJS.Timer | null = null;
|
||||
interface DialogProps {
|
||||
repos: Array<Container.RepoOptions>;
|
||||
}
|
||||
const dialogData = ref<DialogProps>({
|
||||
repos: [] as Array<Container.RepoOptions>,
|
||||
});
|
||||
const repos = ref();
|
||||
|
||||
const acceptParams = async (params: DialogProps): Promise<void> => {
|
||||
pullVisiable.value = true;
|
||||
form.fromRepo = true;
|
||||
form.repoID = 1;
|
||||
form.imageName = '';
|
||||
dialogData.value.repos = params.repos;
|
||||
repos.value = params.repos;
|
||||
buttonDisabled.value = false;
|
||||
logInfo.value = '';
|
||||
};
|
||||
@ -138,7 +135,7 @@ const onCloseLog = async () => {
|
||||
};
|
||||
|
||||
function loadDetailInfo(id: number) {
|
||||
for (const item of dialogData.value.repos) {
|
||||
for (const item of repos.value) {
|
||||
if (item.id === id) {
|
||||
return item.downloadUrl;
|
||||
}
|
||||
|
66
frontend/src/views/container/repo/delete/index.vue
Normal file
66
frontend/src/views/container/repo/delete/index.vue
Normal file
@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<el-dialog v-model="repoVisiable" :destroy-on-close="true" :close-on-click-modal="false" width="30%">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>{{ $t('commons.button.delete') }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-form v-loading="loading" label-width="20px">
|
||||
<el-form-item>
|
||||
<el-checkbox v-model="isDelete">{{ $t('container.delInsecure') }}</el-checkbox>
|
||||
<span class="input-help">{{ $t('container.delInsecureHelper') }}</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button :disabled="loading" @click="repoVisiable = false">
|
||||
{{ $t('commons.button.cancel') }}
|
||||
</el-button>
|
||||
<el-button :disabled="loading" type="primary" @click="onSubmit()">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import i18n from '@/lang';
|
||||
import { ElForm, ElMessage } from 'element-plus';
|
||||
import { deleteImageRepo } from '@/api/modules/container';
|
||||
|
||||
const loading = ref(false);
|
||||
const isDelete = ref(false);
|
||||
|
||||
interface DialogProps {
|
||||
ids?: Array<number>;
|
||||
}
|
||||
const repoVisiable = ref(false);
|
||||
const ids = ref();
|
||||
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
ids.value = params.ids;
|
||||
repoVisiable.value = true;
|
||||
};
|
||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||
|
||||
const onSubmit = async () => {
|
||||
loading.value = true;
|
||||
await deleteImageRepo({ ids: ids.value, deleteInsecure: isDelete.value })
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||
emit('search');
|
||||
repoVisiable.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
return;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
@ -47,18 +47,19 @@
|
||||
</ComplexTable>
|
||||
</el-card>
|
||||
<OperatorDialog @search="search" ref="dialogRef" />
|
||||
<DeleteDialog @search="search" ref="dialogDeleteRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import ComplexTable from '@/components/complex-table/index.vue';
|
||||
import OperatorDialog from '@/views/container/repo/operator/index.vue';
|
||||
import DeleteDialog from '@/views/container/repo/delete/index.vue';
|
||||
import Submenu from '@/views/container/index.vue';
|
||||
import { reactive, onMounted, ref } from 'vue';
|
||||
import { dateFromat } from '@/utils/util';
|
||||
import { Container } from '@/api/interface/container';
|
||||
import { deleteImageRepo, loadDockerStatus, searchImageRepo } from '@/api/modules/container';
|
||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||
import { loadDockerStatus, searchImageRepo } from '@/api/modules/container';
|
||||
import i18n from '@/lang';
|
||||
import router from '@/routers';
|
||||
|
||||
@ -112,6 +113,7 @@ const onOpenDialog = async (
|
||||
dialogRef.value!.acceptParams(params);
|
||||
};
|
||||
|
||||
const dialogDeleteRef = ref();
|
||||
const onBatchDelete = async (row: Container.RepoInfo | null) => {
|
||||
let ids: Array<number> = [];
|
||||
if (row) {
|
||||
@ -121,8 +123,7 @@ const onBatchDelete = async (row: Container.RepoInfo | null) => {
|
||||
ids.push(item.id);
|
||||
});
|
||||
}
|
||||
await useDeleteData(deleteImageRepo, { ids: ids }, 'commons.msg.delete');
|
||||
search();
|
||||
dialogDeleteRef.value!.acceptParams({ ids: ids });
|
||||
};
|
||||
|
||||
const buttons = [
|
||||
|
@ -7,7 +7,11 @@
|
||||
</template>
|
||||
<el-form ref="formRef" v-loading="loading" :model="dialogData.rowData" :rules="rules" label-width="120px">
|
||||
<el-form-item :label="$t('container.name')" prop="name">
|
||||
<el-input :disabled="dialogData.title === 'edit'" v-model="dialogData.rowData!.name"></el-input>
|
||||
<el-input
|
||||
clearable
|
||||
:disabled="dialogData.title === 'edit'"
|
||||
v-model="dialogData.rowData!.name"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('container.auth')" prop="auth">
|
||||
<el-radio-group v-model="dialogData.rowData!.auth">
|
||||
@ -16,19 +20,29 @@
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="dialogData.rowData!.auth" :label="$t('commons.login.username')" prop="username">
|
||||
<el-input v-model="dialogData.rowData!.username"></el-input>
|
||||
<el-input clearable v-model="dialogData.rowData!.username"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="dialogData.rowData!.auth" :label="$t('commons.login.password')" prop="password">
|
||||
<el-input type="password" v-model="dialogData.rowData!.password"></el-input>
|
||||
<el-input clearable type="password" show-password v-model="dialogData.rowData!.password"></el-input>
|
||||
</el-form-item>
|
||||
<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-input
|
||||
clearable
|
||||
v-model="dialogData.rowData!.downloadUrl"
|
||||
:placeholder="'172.16.10.10:8081'"
|
||||
></el-input>
|
||||
<span v-if="dialogData.rowData!.downloadUrl" class="input-help">
|
||||
docker pull {{ dialogData.rowData!.downloadUrl }}/nginx
|
||||
</span>
|
||||
</el-form-item>
|
||||
<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>
|
||||
<span v-if="dialogData.rowData!.protocol === 'http'" class="input-help">
|
||||
{{ $t('container.httpRepo') }}
|
||||
</span>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
|
@ -282,6 +282,9 @@ const loadHost = async () => {
|
||||
const res = await getHostTree({});
|
||||
hostTree.value = res.data;
|
||||
for (const item of hostTree.value) {
|
||||
if (!item.children) {
|
||||
continue;
|
||||
}
|
||||
for (const host of item.children) {
|
||||
if (host.label.indexOf('127.0.0.1')) {
|
||||
localHostID.value = host.id;
|
||||
|
Loading…
Reference in New Issue
Block a user