From 950c6b9d0811c0b6c93acc5a9c0b60a68bb1143c Mon Sep 17 00:00:00 2001 From: ssongliu <73214554+ssongliu@users.noreply.github.com> Date: Thu, 18 May 2023 18:38:19 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=B9=E5=99=A8=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E5=88=87=E5=89=B2=20(#1077)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/dto/docker.go | 3 + backend/app/service/docker.go | 71 ++++++++++++-- frontend/src/api/interface/container.ts | 2 + frontend/src/lang/modules/en.ts | 3 + frontend/src/lang/modules/zh.ts | 3 + .../src/views/container/container/index.vue | 2 +- .../src/views/container/setting/index.vue | 97 +++++++++++++++++-- 7 files changed, 164 insertions(+), 17 deletions(-) diff --git a/backend/app/dto/docker.go b/backend/app/dto/docker.go index ce1c9b62e..240d502be 100644 --- a/backend/app/dto/docker.go +++ b/backend/app/dto/docker.go @@ -13,6 +13,9 @@ type DaemonJsonConf struct { LiveRestore bool `json:"liveRestore"` IPTables bool `json:"iptables"` CgroupDriver string `json:"cgroupDriver"` + + LogMaxSize string `json:"logMaxSize"` + LogMaxFile string `json:"logMaxFile"` } type DockerOperation struct { diff --git a/backend/app/service/docker.go b/backend/app/service/docker.go index d9b2daae9..7916c3216 100644 --- a/backend/app/service/docker.go +++ b/backend/app/service/docker.go @@ -30,12 +30,17 @@ func NewIDockerService() IDockerService { } type daemonJsonItem struct { - Status string `json:"status"` - Mirrors []string `json:"registry-mirrors"` - Registries []string `json:"insecure-registries"` - LiveRestore bool `json:"live-restore"` - IPTables bool `json:"iptables"` - ExecOpts []string `json:"exec-opts"` + Status string `json:"status"` + Mirrors []string `json:"registry-mirrors"` + Registries []string `json:"insecure-registries"` + LiveRestore bool `json:"live-restore"` + IPTables bool `json:"iptables"` + ExecOpts []string `json:"exec-opts"` + LogOption logOption `json:"log-opts"` +} +type logOption struct { + LogMaxSize string `json:"max-size"` + LogMaxFile string `json:"max-file"` } func (u *DockerService) LoadDockerStatus() string { @@ -102,6 +107,8 @@ func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf { break } } + data.LogMaxSize = conf.LogOption.LogMaxSize + data.LogMaxFile = conf.LogOption.LogMaxFile data.Mirrors = conf.Mirrors data.Registries = conf.Registries data.IPTables = conf.IPTables @@ -134,6 +141,9 @@ func (u *DockerService) UpdateConf(req dto.DaemonJsonConf) error { } else { deamonMap["registry-mirrors"] = req.Mirrors } + + changeLogOption(deamonMap, req.LogMaxFile, req.LogMaxSize) + if !req.LiveRestore { delete(deamonMap, "live-restore") } else { @@ -217,3 +227,52 @@ func (u *DockerService) OperateDocker(req dto.DockerOperation) error { } return nil } + +func changeLogOption(deamonMap map[string]interface{}, logMaxFile, logMaxSize string) { + if opts, ok := deamonMap["log-opts"]; ok { + if len(logMaxFile) != 0 || len(logMaxSize) != 0 { + deamonMap["log-driver"] = "json-file" + } + optsMap, isMap := opts.(map[string]interface{}) + if isMap { + if len(logMaxFile) != 0 { + optsMap["max-file"] = logMaxFile + } else { + delete(optsMap, "max-file") + } + if len(logMaxSize) != 0 { + optsMap["max-size"] = logMaxSize + } else { + delete(optsMap, "max-size") + } + if len(optsMap) == 0 { + delete(deamonMap, "log-opts") + } + } else { + optsMap := make(map[string]interface{}) + if len(logMaxFile) != 0 { + optsMap["max-file"] = logMaxFile + } + if len(logMaxSize) != 0 { + optsMap["max-size"] = logMaxSize + } + if len(optsMap) != 0 { + deamonMap["log-opts"] = optsMap + } + } + } else { + if len(logMaxFile) != 0 || len(logMaxSize) != 0 { + deamonMap["log-driver"] = "json-file" + } + optsMap := make(map[string]interface{}) + if len(logMaxFile) != 0 { + optsMap["max-file"] = logMaxFile + } + if len(logMaxSize) != 0 { + optsMap["max-size"] = logMaxSize + } + if len(optsMap) != 0 { + deamonMap["log-opts"] = optsMap + } + } +} diff --git a/frontend/src/api/interface/container.ts b/frontend/src/api/interface/container.ts index b085ff7c3..8dd31935a 100644 --- a/frontend/src/api/interface/container.ts +++ b/frontend/src/api/interface/container.ts @@ -256,5 +256,7 @@ export namespace Container { liveRestore: boolean; iptables: boolean; cgroupDriver: string; + logMaxSize: string; + logMaxFile: string; } } diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 8a89ac911..a7e877d3d 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -575,6 +575,9 @@ const message = { 'The acceleration URL is preferred to perform operations. If this parameter is set to empty, mirror acceleration is disabled.', mirrorsHelper2: 'For details, see the official documents, ', registries: 'Insecure registries', + cutLog: 'Log option', + maxSize: 'Max-Size', + maxFile: 'Max-File', liveHelper: 'Allows the running container state to be preserved in case of unexpected shutdown or crash of the Docker daemon', liveWithSwarmHelper: 'live-restore daemon configuration is incompatible with swarm mode.', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 1c8267597..02b3d600c 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -589,6 +589,9 @@ const message = { mirrorsHelper: '优先使用加速 URL 执行操作,设置为空则取消镜像加速。', mirrorsHelper2: '具体操作配置请参照官方文档,', registries: '私有仓库', + cutLog: '日志切割', + maxSize: '文件大小', + maxFile: '保留份数', liveHelper: '允许在 Docker 守护进程发生意外停机或崩溃时保留正在运行的容器状态', liveWithSwarmHelper: 'live-restore 守护进程配置与 Swarm 模式不兼容', iptablesDisable: '关闭 iptables', diff --git a/frontend/src/views/container/container/index.vue b/frontend/src/views/container/container/index.vue index 7ee66822a..a8f92d1a3 100644 --- a/frontend/src/views/container/container/index.vue +++ b/frontend/src/views/container/container/index.vue @@ -78,7 +78,7 @@ diff --git a/frontend/src/views/container/setting/index.vue b/frontend/src/views/container/setting/index.vue index e9a461b14..5d7431125 100644 --- a/frontend/src/views/container/setting/index.vue +++ b/frontend/src/views/container/setting/index.vue @@ -44,7 +44,7 @@
- + + + + + +
+ + + + + + + + + + + +
+ @@ -163,6 +189,7 @@ import { updateDaemonJsonByfile, } from '@/api/modules/container'; import { MsgSuccess } from '@/utils/message'; +import { checkNumberRange } from '@/global/form-rules'; const loading = ref(false); const showDaemonJsonAlert = ref(false); @@ -178,6 +205,14 @@ const form = reactive({ liveRestore: false, iptables: true, cgroupDriver: '', + logOptionShow: false, + logMaxSize: 10, + sizeUnit: 'm', + logMaxFile: 3, +}); +const rules = reactive({ + logMaxSize: [checkNumberRange(1, 1024000)], + logMaxFile: [checkNumberRange(1, 100)], }); const formRef = ref(); @@ -276,7 +311,14 @@ const onSubmitSave = async () => { liveRestore: form.liveRestore, iptables: form.iptables, cgroupDriver: form.cgroupDriver, + logMaxSize: form.logMaxSize + form.sizeUnit, + logMaxFile: form.logMaxFile + '', }; + if (!form.logOptionShow) { + param.logMaxFile = ''; + param.logMaxSize = ''; + } + loading.value = true; await updateDaemonJson(param) .then(() => { @@ -308,15 +350,50 @@ const changeMode = async () => { }; const search = async () => { - const res = await loadDaemonJson(); - form.isSwarm = res.data.isSwarm; - form.status = res.data.status; - form.version = res.data.version; - form.cgroupDriver = res.data.cgroupDriver; - form.liveRestore = res.data.liveRestore; - form.iptables = res.data.iptables; - form.mirrors = res.data.registryMirrors ? res.data.registryMirrors.join('\n') : ''; - form.registries = res.data.insecureRegistries ? res.data.insecureRegistries.join('\n') : ''; + loading.value = true; + await loadDaemonJson() + .then((res) => { + loading.value = false; + form.isSwarm = res.data.isSwarm; + form.status = res.data.status; + form.version = res.data.version; + form.cgroupDriver = res.data.cgroupDriver; + form.liveRestore = res.data.liveRestore; + form.iptables = res.data.iptables; + form.mirrors = res.data.registryMirrors ? res.data.registryMirrors.join('\n') : ''; + form.registries = res.data.insecureRegistries ? res.data.insecureRegistries.join('\n') : ''; + if (res.data.logMaxFile || res.data.logMaxSize) { + form.logOptionShow = true; + } + form.logMaxFile = Number(res.data.logMaxFile); + form.logMaxSize = loadSize(res.data.logMaxSize); + }) + .catch(() => { + loading.value = false; + }); +}; + +const loadSize = (value: string) => { + if (value.indexOf('b') !== -1 || value.indexOf('B') !== -1) { + form.sizeUnit = 'b'; + return Number(value.replaceAll('b', '').replaceAll('B', '')); + } + if (value.indexOf('k') !== -1 || value.indexOf('K') !== -1) { + form.sizeUnit = 'k'; + return Number(value.replaceAll('k', '').replaceAll('K', '')); + } + if (value.indexOf('m') !== -1 || value.indexOf('M') !== -1) { + form.sizeUnit = 'm'; + return Number(value.replaceAll('m', '').replaceAll('M', '')); + } + if (value.indexOf('g') !== -1 || value.indexOf('G') !== -1) { + form.sizeUnit = 'g'; + return Number(value.replaceAll('g', '').replaceAll('G', '')); + } + if (value.indexOf('t') !== -1 || value.indexOf('T') !== -1) { + form.sizeUnit = 't'; + return Number(value.replaceAll('t', '').replaceAll('T', '')); + } }; onMounted(() => {