feat: Complete the Docker proxy synchronization function (#8480)

This commit is contained in:
ssongliu 2025-04-25 22:37:54 +08:00 committed by GitHub
parent f485b1729c
commit 4aa628121c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 55 additions and 112 deletions

View file

@ -151,6 +151,7 @@ type ProxyUpdate struct {
ProxyUser string `json:"proxyUser"`
ProxyPasswd string `json:"proxyPasswd"`
ProxyPasswdKeep string `json:"proxyPasswdKeep"`
ProxyDocker bool `json:"proxyDocker"`
}
type CleanData struct {

View file

@ -199,6 +199,9 @@ func (u *SettingService) UpdateProxy(req dto.ProxyUpdate) error {
if err := settingRepo.Update("ProxyPasswdKeep", req.ProxyPasswdKeep); err != nil {
return err
}
if err := xpack.ProxyDocker(loadDockerProxy(req)); err != nil {
return err
}
go func() {
if err := xpack.Sync(constant.SyncSystemProxy); err != nil {
global.LOG.Errorf("sync proxy to node failed, err: %v", err)
@ -636,3 +639,18 @@ func (u *SettingService) GetLoginSetting() (*dto.SystemSetting, error) {
}
return res, nil
}
func loadDockerProxy(req dto.ProxyUpdate) string {
if len(req.ProxyType) == 0 || req.ProxyType == "close" || !req.ProxyDocker {
return ""
}
proxyPasswd := ""
if len(req.ProxyUser) != 0 {
proxyPasswd = req.ProxyPasswd + "@"
}
proxyUrl := req.ProxyType + "://" + req.ProxyUser + ":" + proxyPasswd + req.ProxyUrl + req.ProxyPort
if req.ProxyType == "http" || req.ProxyType == "https" {
req.ProxyUrl = req.ProxyType + "://" + req.ProxyUrl
}
return proxyUrl
}

View file

@ -45,6 +45,7 @@ const (
const (
SyncSystemProxy = "SyncSystemProxy"
SyncBackupAccounts = "SyncBackupAccounts"
SyncAlertSetting = "SyncAlertSetting"
)
var WebUrlMap = map[string]struct{}{

View file

@ -14,6 +14,8 @@ import (
func Proxy(c *gin.Context, currentNode string) {}
func ProxyDocker(proxyURL string) error { return nil }
func UpdateGroup(name string, group, newGroup uint) error { return nil }
func CheckBackupUsed(name string) error { return nil }

View file

@ -3265,8 +3265,9 @@ const message = {
nodeInfo: 'Node Information',
syncInfo: 'Data synchronization',
syncHelper: 'When master node data changes, it synchronizes to this child node in real-time',
syncBackupAccount: 'Backup account data',
syncProxy: 'System proxy data',
syncBackupAccount: 'Backup account settings',
syncProxy: 'System proxy settings',
syncAlertSetting: 'System alert settings',
syncNodeInfo: 'Node basic data,',
nodeSyncHelper: 'Node information synchronization will sync the following information:',
nodeSyncHelper1: '1. Public backup account information',

View file

@ -3124,8 +3124,9 @@ const message = {
nodeInfo: 'ノード情報',
syncInfo: 'データ同期,',
syncHelper: 'マスターノードのデータが変更されるとこの子ノードにリアルタイムで同期されます,',
syncBackupAccount: 'アカウントデータのバックアップ,',
syncProxy: 'システムプロキシデータ,',
syncBackupAccount: 'バックアップアカウント設定',
syncProxy: 'システムプロキシ設定',
syncAlertSetting: 'システムアラート設定',
syncNodeInfo: 'ノード基本データ,',
nodeSyncHelper: 'ノード情報の同期は以下の情報を同期します',
nodeSyncHelper1: '1. 公共のバックアップアカウント情報',

View file

@ -3072,8 +3072,9 @@ const message = {
nodeInfo: '노드 정보',
syncInfo: '데이터 동기화,',
syncHelper: '마스터 노드 데이터가 변경되면, 자식 노드에 실시간으로 동기화됩니다,',
syncBackupAccount: '계정 데이터 백업,',
syncProxy: '시스템 프록시 데이터,',
syncBackupAccount: '백업 계정 설정',
syncProxy: '시스템 프록시 설정',
syncAlertSetting: '시스템 경고 설정',
syncNodeInfo: '노드 기본 데이터,',
nodeSyncHelper: '노드 정보 동기화는 다음 정보를 동기화합니다:',
nodeSyncHelper1: '1. 공용 백업 계정 정보',

View file

@ -3193,8 +3193,9 @@ const message = {
nodeInfo: 'Maklumat Nod',
syncInfo: 'Penyegerakan data,',
syncHelper: 'Apabila data nod induk berubah, ia akan disegerakkan ke nod anak ini secara masa nyata,',
syncBackupAccount: 'Data akaun sandaran,',
syncProxy: 'Data proksi sistem,',
syncBackupAccount: 'Tetapan akaun sandaran',
syncProxy: 'Tetapan proksi sistem',
syncAlertSetting: 'Tetapan amaran sistem',
syncNodeInfo: 'Data asas nod,',
nodeSyncHelper: 'Penyelarasan maklumat nod akan menyelaraskan maklumat berikut:',
nodeSyncHelper1: '1. Maklumat akaun sandaran awam',

View file

@ -3199,8 +3199,9 @@ const message = {
nodeInfo: 'Informações do ',
syncInfo: 'Sincronização de dados,',
syncHelper: 'Quando os dados do mestre mudam, são sincronizados em tempo real para este filho,',
syncBackupAccount: 'Dados de conta de backup,',
syncProxy: 'Dados de proxy do sistema,',
syncBackupAccount: 'Configurações de conta de backup',
syncProxy: 'Configurações de proxy do sistema',
syncAlertSetting: 'Configurações de alerta do sistema',
syncNodeInfo: 'Dados básicos do ,',
nodeSyncHelper: 'A sincronização das informações do irá sincronizar as seguintes informações:',
nodeSyncHelper1: '1. Informações da conta de backup pública',

View file

@ -3188,8 +3188,9 @@ const message = {
syncInfo: 'Синхронизация данных,',
syncHelper:
'При изменении данных главного узла, происходит синхронизация с этим дочерним узлом в реальном времени,',
syncBackupAccount: 'Резервные данные аккаунта,',
syncProxy: 'Данные системного прокси,',
syncBackupAccount: 'Настройки резервной учётной записи',
syncProxy: 'Настройки системного прокси',
syncAlertSetting: 'Настройки системных предупреждений',
syncNodeInfo: 'Базовые данные узла,',
nodeSyncHelper: 'Синхронизация информации о узле будет синхронизировать следующую информацию:',
nodeSyncHelper1: '1. Информация о публичной резервной учетной записи',

View file

@ -3028,8 +3028,9 @@ const message = {
nodeInfo: '節點資訊',
syncInfo: '數據同步,',
syncHelper: '當主節點數據發生變化時實時同步到該子節點,',
syncBackupAccount: '備份帳號數據,',
syncProxy: '系統代理數據,',
syncBackupAccount: '備份帳號設定',
syncProxy: '系統代理設定',
syncAlertSetting: '系統告警設定',
syncNodeInfo: '節點基礎數據,',
nodeSyncHelper: '節點信息同步將同步以下信息',
nodeSyncHelper1: '1. 公用的備份帳號信息',

View file

@ -3011,8 +3011,9 @@ const message = {
nodeInfo: '节点信息',
syncInfo: '数据同步',
syncHelper: '主节点数据发生变化时实时同步到该子节点',
syncBackupAccount: '备份账号数据',
syncProxy: '系统代理数据',
syncBackupAccount: '备份账号设置',
syncProxy: '系统代理设置',
syncAlertSetting: '系统告警设置',
syncNodeInfo: '节点基础数据',
nodeSyncHelper: '节点信息同步将同步以下信息',
nodeSyncHelper1: '1. 公用的备份账号信息',

View file

@ -1,5 +1,5 @@
<template>
<DrawerPro v-model="passwordVisible" :header="$t('setting.proxy')" @close="handleClose" size="large">
<DrawerPro v-model="proxyVisible" :header="$t('setting.proxy')" @close="handleClose" size="large">
<el-form ref="formRef" label-position="top" :model="form" :rules="rules" v-loading="loading">
<el-alert class="common-prompt" :closable="false" type="warning">
<template #default>
@ -46,45 +46,13 @@
<el-checkbox v-model="form.proxyPasswdKeepItem" :label="$t('setting.proxyPasswdKeep')" />
</el-form-item>
<el-form-item v-if="isMasterProductPro">
<el-checkbox v-model="form.proxyDocker" @change="onChange" :label="$t('setting.proxyDocker')" />
<el-checkbox v-model="form.proxyDocker" :label="$t('setting.proxyDocker')" />
<span class="input-help">{{ $t('setting.proxyDockerHelper') }}</span>
</el-form-item>
<div v-if="form.proxyDocker">
<el-form-item prop="syncToNode">
<el-switch
@change="getNodes"
v-model="form.syncToNode"
active-value="Enable"
inactive-value="Disable"
></el-switch>
<span class="ml-2.5 el-checkbox">{{ $t('setting.syncToNode') }}</span>
<span class="input-help">{{ $t('setting.syncToNodeHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('setting.nodes')" prop="nodes" v-if="form.syncToNode === 'Enable'">
<el-row :gutter="20">
<el-col :span="12">
<el-select v-model="form.selectNode" class="p-w-200">
<el-option :label="$t('commons.table.all')" value="all"></el-option>
<el-option :label="$t('setting.selectNode')" value="select"></el-option>
</el-select>
</el-col>
<el-col :span="12" v-if="form.selectNode === 'select'">
<el-select v-model="form.nodes" multiple class="p-w-200">
<el-option
v-for="item in nodeList"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-col>
</el-row>
</el-form-item>
</div>
</div>
</el-form>
<template #footer>
<el-button :disabled="loading" @click="passwordVisible = false">
<el-button :disabled="loading" @click="proxyVisible = false">
{{ $t('commons.button.cancel') }}
</el-button>
<el-button :disabled="loading" type="primary" @click="submitChangePassword(formRef)">
@ -102,13 +70,10 @@ import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { FormInstance } from 'element-plus';
import { reactive, ref } from 'vue';
import { listNodeOptions, updateProxy } from '@/api/modules/setting';
import { updateProxy } from '@/api/modules/setting';
import { GlobalStore } from '@/store';
import { storeToRefs } from 'pinia';
import { updateDaemonJson } from '@/api/modules/container';
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import { escapeProxyURL } from '@/utils/util';
import { updateDockerProxySetting } from '@/xpack/api/modules/setting';
const globalStore = GlobalStore();
const emit = defineEmits<{ (e: 'search'): void }>();
@ -123,8 +88,7 @@ const rules = reactive({
});
const loading = ref(false);
const passwordVisible = ref<boolean>(false);
const proxyDockerVisible = ref<boolean>(false);
const proxyVisible = ref<boolean>(false);
const form = reactive({
proxyUrl: '',
proxyType: '',
@ -135,11 +99,7 @@ const form = reactive({
proxyPasswdKeep: '',
proxyPasswdKeepItem: false,
proxyDocker: false,
syncToNode: 'Enable',
selectNode: 'all',
nodes: [],
});
const nodeList = ref([]);
interface DialogProps {
url: string;
@ -149,8 +109,6 @@ interface DialogProps {
passwd: string;
passwdKeep: string;
proxyDocker: string;
proxyDockerSyncToNode: string;
proxyDockerSyncNodes: string;
}
const acceptParams = (params: DialogProps): void => {
if (params.url) {
@ -167,24 +125,11 @@ const acceptParams = (params: DialogProps): void => {
form.proxyUser = params.user;
form.proxyPasswd = params.passwd;
form.proxyDocker = params.proxyDocker !== '';
if (form.proxyDocker) {
getNodes();
form.syncToNode = params.proxyDockerSyncToNode;
form.nodes = params.proxyDockerSyncNodes ? JSON.parse(params.proxyDockerSyncNodes) : [];
form.selectNode = form.nodes.length > 0 ? 'select' : 'all';
}
proxyDockerVisible.value = params.proxyDocker !== '';
passwordVisible.value = true;
proxyVisible.value = true;
form.proxyPasswdKeepItem = params.passwdKeep === 'Enable';
};
const getNodes = () => {
if (form.syncToNode === 'Enable' && nodeList.value.length === 0) {
listNodes();
}
};
const submitChangePassword = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
@ -205,13 +150,7 @@ const submitChangePassword = async (formEl: FormInstance | undefined) => {
if (form.proxyType === 'http' || form.proxyType === 'https') {
params.proxyUrl = form.proxyType + '://' + form.proxyUrl;
}
if (
isMasterProductPro.value &&
(params.proxyDocker ||
(proxyDockerVisible.value && isClose) ||
(proxyDockerVisible.value && !isClose) ||
(proxyDockerVisible.value && !params.proxyDocker))
) {
if (isMasterProductPro.value && params.proxyDocker) {
let confirmParams = {
header: i18n.global.t('setting.confDockerProxy'),
operationInfo: i18n.global.t('setting.restartNowHelper'),
@ -224,10 +163,7 @@ const submitChangePassword = async (formEl: FormInstance | undefined) => {
.then(async () => {
loading.value = false;
emit('search');
passwordVisible.value = false;
if (isClose) {
await updateDaemonJson(`${form.proxyType}-proxy`, '');
}
proxyVisible.value = false;
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
})
.catch(() => {
@ -253,26 +189,10 @@ const onSubmit = async () => {
if (!isClose) {
params.proxyPasswdKeep = form.proxyPasswdKeepItem ? 'Enable' : 'Disable';
}
let proxyPort = params.proxyPort ? `:${params.proxyPort}` : '';
let proxyUser = params.proxyUser ? `${escapeProxyURL(params.proxyUser)}` : '';
let proxyPasswd = '';
if (params.proxyUser) {
proxyPasswd = params.proxyPasswd ? `:${escapeProxyURL(params.proxyPasswd)}@` : '@';
}
let proxyUrl = form.proxyType + '://' + proxyUser + proxyPasswd + form.proxyUrl + proxyPort;
if (form.proxyType === 'http' || form.proxyType === 'https') {
params.proxyUrl = form.proxyType + '://' + form.proxyUrl;
}
await updateProxy(params);
if (isClose || params.proxyDocker === false) {
proxyUrl = '';
}
let param = {
proxyDocker: proxyUrl,
proxyDockerSyncToNode: form.syncToNode,
proxyDockerSyncNodes: JSON.stringify(form.nodes),
};
await updateDockerProxySetting(param);
emit('search');
handleClose();
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
@ -281,15 +201,8 @@ const onSubmit = async () => {
}
};
const listNodes = async () => {
try {
const res = await listNodeOptions();
nodeList.value = res.data || [];
} catch (error) {}
};
const handleClose = () => {
passwordVisible.value = false;
proxyVisible.value = false;
};
defineExpose({