diff --git a/backend/app/api/v1/container.go b/backend/app/api/v1/container.go index 542abbd25..2b1f73307 100644 --- a/backend/app/api/v1/container.go +++ b/backend/app/api/v1/container.go @@ -179,6 +179,32 @@ func (b *BaseApi) ContainerCreate(c *gin.Context) { helper.SuccessWithData(c, nil) } +// @Tags Container +// @Summary Clean container log +// @Description 清理容器日志 +// @Accept json +// @Param request body dto.OperationWithName true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /containers/clean/log [post] +// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"清理容器 [name] 日志","formatEN":"clean container [name] logs"} +func (b *BaseApi) CleanContainerLog(c *gin.Context) { + var req dto.OperationWithName + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := global.VALID.Struct(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := containerService.ContainerLogClean(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, nil) +} + // @Tags Container // @Summary Operate Container // @Description 容器操作 diff --git a/backend/app/api/v1/setting.go b/backend/app/api/v1/setting.go index ece5e1921..97a3dea5e 100644 --- a/backend/app/api/v1/setting.go +++ b/backend/app/api/v1/setting.go @@ -189,7 +189,7 @@ func (b *BaseApi) HandlePasswordExpired(c *gin.Context) { // @Tags System Setting // @Summary Load time zone options // @Description 加载系统可用时区 -// @Success 200 {string} +// @Success 200 // @Security ApiKeyAuth // @Router /settings/time/option [get] func (b *BaseApi) LoadTimeZone(c *gin.Context) { diff --git a/backend/app/service/container.go b/backend/app/service/container.go index 4ee02b92f..edcb72f79 100644 --- a/backend/app/service/container.go +++ b/backend/app/service/container.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "io" + "os" "os/exec" "sort" "strconv" @@ -39,6 +40,7 @@ type IContainerService interface { CreateCompose(req dto.ComposeCreate) (string, error) ComposeOperation(req dto.ComposeOperation) error ContainerCreate(req dto.ContainerCreate) error + ContainerLogClean(req dto.OperationWithName) error ContainerOperation(req dto.ContainerOperation) error ContainerLogs(param dto.ContainerLog) (string, error) ContainerStats(id string) (*dto.ContainterStats, error) @@ -263,6 +265,27 @@ func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error return err } +func (u *ContainerService) ContainerLogClean(req dto.OperationWithName) error { + client, err := docker.NewDockerClient() + if err != nil { + return err + } + container, err := client.ContainerInspect(context.Background(), req.Name) + if err != nil { + return err + } + file, err := os.OpenFile(container.LogPath, os.O_RDWR|os.O_CREATE, 0666) + if err != nil { + return err + } + defer file.Close() + if err = file.Truncate(0); err != nil { + return err + } + _, _ = file.Seek(0, 0) + return nil +} + func (u *ContainerService) ContainerLogs(req dto.ContainerLog) (string, error) { cmd := exec.Command("docker", "logs", req.ContainerID) if req.Mode != "all" { diff --git a/backend/router/ro_container.go b/backend/router/ro_container.go index 213264780..d1612e9fa 100644 --- a/backend/router/ro_container.go +++ b/backend/router/ro_container.go @@ -21,6 +21,7 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) { baRouter.POST("", baseApi.ContainerCreate) baRouter.POST("/search", baseApi.SearchContainer) baRouter.POST("/search/log", baseApi.ContainerLogs) + baRouter.POST("/clean/log", baseApi.CleanContainerLog) baRouter.POST("/inspect", baseApi.Inspect) baRouter.POST("/operate", baseApi.ContainerOperation) diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index 28427fb44..61918a005 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -937,6 +937,48 @@ var doc = `{ } } }, + "/containers/clean/log": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "清理容器日志", + "consumes": [ + "application/json" + ], + "tags": [ + "Container" + ], + "summary": "Clean container log", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.OperationWithName" + } + } + ], + "responses": { + "200": { + "description": "" + } + }, + "x-panel-log": { + "BeforeFuntions": [], + "bodyKeys": [ + "name" + ], + "formatEN": "clean container [name] logs", + "formatZH": "清理容器 [name] 日志", + "paramKeys": [] + } + } + }, "/containers/compose": { "post": { "security": [ @@ -7750,6 +7792,25 @@ var doc = `{ } } }, + "/settings/time/option": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "加载系统可用时区", + "tags": [ + "System Setting" + ], + "summary": "Load time zone options", + "responses": { + "200": { + "description": "" + } + } + } + }, "/settings/time/sync": { "post": { "security": [ @@ -7758,10 +7819,24 @@ var doc = `{ } ], "description": "系统时间同步", + "consumes": [ + "application/json" + ], "tags": [ "System Setting" ], "summary": "Sync system time", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SyncTimeZone" + } + } + ], "responses": { "200": { "description": "OK", @@ -7772,9 +7847,12 @@ var doc = `{ }, "x-panel-log": { "BeforeFuntions": [], - "bodyKeys": [], - "formatEN": "sync system time", - "formatZH": "系统时间同步", + "bodyKeys": [ + "ntpSite", + "timeZone" + ], + "formatEN": "sync system time [ntpSite]-[timeZone]", + "formatZH": "系统时间同步[ntpSite]-[timeZone]", "paramKeys": [] } } @@ -10689,6 +10767,12 @@ var doc = `{ "liveRestore": { "type": "boolean" }, + "logMaxFile": { + "type": "string" + }, + "logMaxSize": { + "type": "string" + }, "registryMirrors": { "type": "array", "items": { @@ -10898,12 +10982,6 @@ var doc = `{ "restart", "stop" ] - }, - "stopService": { - "type": "boolean" - }, - "stopSocket": { - "type": "boolean" } } }, @@ -11728,6 +11806,17 @@ var doc = `{ } } }, + "dto.OperationWithName": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + } + } + }, "dto.PageContainer": { "type": "object", "required": [ @@ -12292,12 +12381,18 @@ var doc = `{ "dto.SettingInfo": { "type": "object", "properties": { + "allowIPs": { + "type": "string" + }, "appStoreLastModified": { "type": "string" }, "appStoreVersion": { "type": "string" }, + "bindDomain": { + "type": "string" + }, "complexityVerification": { "type": "string" }, @@ -12337,6 +12432,9 @@ var doc = `{ "monitorStoreDays": { "type": "string" }, + "ntpSite": { + "type": "string" + }, "panelName": { "type": "string" }, @@ -12364,6 +12462,9 @@ var doc = `{ "theme": { "type": "string" }, + "timeZone": { + "type": "string" + }, "userName": { "type": "string" }, @@ -12444,6 +12545,17 @@ var doc = `{ } } }, + "dto.SyncTimeZone": { + "type": "object", + "properties": { + "ntpSite": { + "type": "string" + }, + "timeZone": { + "type": "string" + } + } + }, "dto.UpdateDescription": { "type": "object", "required": [ @@ -12968,6 +13080,12 @@ var doc = `{ "cpuQuota": { "type": "number" }, + "dockerCompose": { + "type": "string" + }, + "editCompose": { + "type": "boolean" + }, "memoryLimit": { "type": "number" }, @@ -13071,6 +13189,12 @@ var doc = `{ "cpuQuota": { "type": "number" }, + "dockerCompose": { + "type": "string" + }, + "editCompose": { + "type": "boolean" + }, "installId": { "type": "integer" }, @@ -13417,6 +13541,12 @@ var doc = `{ "cpuQuota": { "type": "number" }, + "dockerCompose": { + "type": "string" + }, + "editCompose": { + "type": "boolean" + }, "memoryLimit": { "type": "number" }, @@ -14323,6 +14453,9 @@ var doc = `{ "id": { "type": "integer" }, + "installed": { + "type": "boolean" + }, "key": { "type": "string" }, @@ -14388,6 +14521,9 @@ var doc = `{ "createdAt": { "type": "string" }, + "dockerCompose": { + "type": "string" + }, "downloadCallBackUrl": { "type": "string" }, diff --git a/cmd/server/docs/swagger.json b/cmd/server/docs/swagger.json index 75a8c000c..69c7f6597 100644 --- a/cmd/server/docs/swagger.json +++ b/cmd/server/docs/swagger.json @@ -923,6 +923,48 @@ } } }, + "/containers/clean/log": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "清理容器日志", + "consumes": [ + "application/json" + ], + "tags": [ + "Container" + ], + "summary": "Clean container log", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.OperationWithName" + } + } + ], + "responses": { + "200": { + "description": "" + } + }, + "x-panel-log": { + "BeforeFuntions": [], + "bodyKeys": [ + "name" + ], + "formatEN": "clean container [name] logs", + "formatZH": "清理容器 [name] 日志", + "paramKeys": [] + } + } + }, "/containers/compose": { "post": { "security": [ @@ -7736,6 +7778,25 @@ } } }, + "/settings/time/option": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "加载系统可用时区", + "tags": [ + "System Setting" + ], + "summary": "Load time zone options", + "responses": { + "200": { + "description": "" + } + } + } + }, "/settings/time/sync": { "post": { "security": [ @@ -7744,10 +7805,24 @@ } ], "description": "系统时间同步", + "consumes": [ + "application/json" + ], "tags": [ "System Setting" ], "summary": "Sync system time", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.SyncTimeZone" + } + } + ], "responses": { "200": { "description": "OK", @@ -7758,9 +7833,12 @@ }, "x-panel-log": { "BeforeFuntions": [], - "bodyKeys": [], - "formatEN": "sync system time", - "formatZH": "系统时间同步", + "bodyKeys": [ + "ntpSite", + "timeZone" + ], + "formatEN": "sync system time [ntpSite]-[timeZone]", + "formatZH": "系统时间同步[ntpSite]-[timeZone]", "paramKeys": [] } } @@ -10675,6 +10753,12 @@ "liveRestore": { "type": "boolean" }, + "logMaxFile": { + "type": "string" + }, + "logMaxSize": { + "type": "string" + }, "registryMirrors": { "type": "array", "items": { @@ -10884,12 +10968,6 @@ "restart", "stop" ] - }, - "stopService": { - "type": "boolean" - }, - "stopSocket": { - "type": "boolean" } } }, @@ -11714,6 +11792,17 @@ } } }, + "dto.OperationWithName": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + } + } + }, "dto.PageContainer": { "type": "object", "required": [ @@ -12278,12 +12367,18 @@ "dto.SettingInfo": { "type": "object", "properties": { + "allowIPs": { + "type": "string" + }, "appStoreLastModified": { "type": "string" }, "appStoreVersion": { "type": "string" }, + "bindDomain": { + "type": "string" + }, "complexityVerification": { "type": "string" }, @@ -12323,6 +12418,9 @@ "monitorStoreDays": { "type": "string" }, + "ntpSite": { + "type": "string" + }, "panelName": { "type": "string" }, @@ -12350,6 +12448,9 @@ "theme": { "type": "string" }, + "timeZone": { + "type": "string" + }, "userName": { "type": "string" }, @@ -12430,6 +12531,17 @@ } } }, + "dto.SyncTimeZone": { + "type": "object", + "properties": { + "ntpSite": { + "type": "string" + }, + "timeZone": { + "type": "string" + } + } + }, "dto.UpdateDescription": { "type": "object", "required": [ @@ -12954,6 +13066,12 @@ "cpuQuota": { "type": "number" }, + "dockerCompose": { + "type": "string" + }, + "editCompose": { + "type": "boolean" + }, "memoryLimit": { "type": "number" }, @@ -13057,6 +13175,12 @@ "cpuQuota": { "type": "number" }, + "dockerCompose": { + "type": "string" + }, + "editCompose": { + "type": "boolean" + }, "installId": { "type": "integer" }, @@ -13403,6 +13527,12 @@ "cpuQuota": { "type": "number" }, + "dockerCompose": { + "type": "string" + }, + "editCompose": { + "type": "boolean" + }, "memoryLimit": { "type": "number" }, @@ -14309,6 +14439,9 @@ "id": { "type": "integer" }, + "installed": { + "type": "boolean" + }, "key": { "type": "string" }, @@ -14374,6 +14507,9 @@ "createdAt": { "type": "string" }, + "dockerCompose": { + "type": "string" + }, "downloadCallBackUrl": { "type": "string" }, diff --git a/cmd/server/docs/swagger.yaml b/cmd/server/docs/swagger.yaml index 98309556d..90e45d82e 100644 --- a/cmd/server/docs/swagger.yaml +++ b/cmd/server/docs/swagger.yaml @@ -485,6 +485,10 @@ definitions: type: boolean liveRestore: type: boolean + logMaxFile: + type: string + logMaxSize: + type: string registryMirrors: items: type: string @@ -622,10 +626,6 @@ definitions: - restart - stop type: string - stopService: - type: boolean - stopSocket: - type: boolean required: - operation type: object @@ -1180,6 +1180,13 @@ definitions: required: - id type: object + dto.OperationWithName: + properties: + name: + type: string + required: + - name + type: object dto.PageContainer: properties: filters: @@ -1556,10 +1563,14 @@ definitions: type: object dto.SettingInfo: properties: + allowIPs: + type: string appStoreLastModified: type: string appStoreVersion: type: string + bindDomain: + type: string complexityVerification: type: string dingVars: @@ -1586,6 +1597,8 @@ definitions: type: string monitorStoreDays: type: string + ntpSite: + type: string panelName: type: string port: @@ -1604,6 +1617,8 @@ definitions: type: string theme: type: string + timeZone: + type: string userName: type: string weChatVars: @@ -1658,6 +1673,13 @@ definitions: required: - id type: object + dto.SyncTimeZone: + properties: + ntpSite: + type: string + timeZone: + type: string + type: object dto.UpdateDescription: properties: description: @@ -2000,6 +2022,10 @@ definitions: type: string cpuQuota: type: number + dockerCompose: + type: string + editCompose: + type: boolean memoryLimit: type: number memoryUnit: @@ -2069,6 +2095,10 @@ definitions: type: string cpuQuota: type: number + dockerCompose: + type: string + editCompose: + type: boolean installId: type: integer memoryLimit: @@ -2304,6 +2334,10 @@ definitions: type: string cpuQuota: type: number + dockerCompose: + type: string + editCompose: + type: boolean memoryLimit: type: number memoryUnit: @@ -2915,6 +2949,8 @@ definitions: type: string id: type: integer + installed: + type: boolean key: type: string lastModified: @@ -2958,6 +2994,8 @@ definitions: type: integer createdAt: type: string + dockerCompose: + type: string downloadCallBackUrl: type: string downloadUrl: @@ -3809,6 +3847,33 @@ paths: formatEN: create container [name][image] formatZH: 创建容器 [name][image] paramKeys: [] + /containers/clean/log: + post: + consumes: + - application/json + description: 清理容器日志 + parameters: + - description: request + in: body + name: request + required: true + schema: + $ref: '#/definitions/dto.OperationWithName' + responses: + "200": + description: "" + security: + - ApiKeyAuth: [] + summary: Clean container log + tags: + - Container + x-panel-log: + BeforeFuntions: [] + bodyKeys: + - name + formatEN: clean container [name] logs + formatZH: 清理容器 [name] 日志 + paramKeys: [] /containers/compose: post: consumes: @@ -8139,9 +8204,29 @@ paths: formatEN: update system ssl => [ssl] formatZH: 修改系统 ssl => [ssl] paramKeys: [] + /settings/time/option: + get: + description: 加载系统可用时区 + responses: + "200": + description: "" + security: + - ApiKeyAuth: [] + summary: Load time zone options + tags: + - System Setting /settings/time/sync: post: + consumes: + - application/json description: 系统时间同步 + parameters: + - description: request + in: body + name: request + required: true + schema: + $ref: '#/definitions/dto.SyncTimeZone' responses: "200": description: OK @@ -8154,9 +8239,11 @@ paths: - System Setting x-panel-log: BeforeFuntions: [] - bodyKeys: [] - formatEN: sync system time - formatZH: 系统时间同步 + bodyKeys: + - ntpSite + - timeZone + formatEN: sync system time [ntpSite]-[timeZone] + formatZH: 系统时间同步[ntpSite]-[timeZone] paramKeys: [] /settings/update: post: diff --git a/frontend/src/api/modules/container.ts b/frontend/src/api/modules/container.ts index af10bf8fa..ec15b00cc 100644 --- a/frontend/src/api/modules/container.ts +++ b/frontend/src/api/modules/container.ts @@ -11,6 +11,9 @@ export const createContainer = (params: Container.ContainerCreate) => { export const logContainer = (params: Container.ContainerLogSearch) => { return http.post(`/containers/search/log`, params, 400000); }; +export const cleanContainerLog = (containerName: string) => { + return http.post(`/containers/clean/log`, { name: containerName }); +}; export const ContainerStats = (id: string) => { return http.get(`/containers/stats/${id}`); }; diff --git a/frontend/src/components/container-log/index.vue b/frontend/src/components/container-log/index.vue index 7eb5c3289..bd53c1d02 100644 --- a/frontend/src/components/container-log/index.vue +++ b/frontend/src/components/container-log/index.vue @@ -4,12 +4,15 @@ -
+
{{ $t('commons.button.watch') }}
- + {{ $t('file.download') }} + + {{ $t('commons.button.clean') }} +
+ + diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index ccae3d04f..8aa362771 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -444,6 +444,7 @@ const message = { last4Hour: 'Last 4 Hours', lastHour: 'Last Hour', last10Min: 'Last 10 Minutes', + cleanLog: 'Clean log', newName: 'New name', source: 'Resource rate', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index f8ad70d1f..27c46b8b1 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -463,6 +463,7 @@ const message = { last4Hour: '最近 4 小时', lastHour: '最近 1 小时', last10Min: '最近 10 分钟', + cleanLog: '清空日志', newName: '新名称', source: '资源使用率', diff --git a/frontend/src/views/container/container/log/index.vue b/frontend/src/views/container/container/log/index.vue index 05545ddc4..717f9c040 100644 --- a/frontend/src/views/container/container/log/index.vue +++ b/frontend/src/views/container/container/log/index.vue @@ -8,12 +8,15 @@ -
+
{{ $t('commons.button.watch') }}
- + {{ $t('file.download') }} + + {{ $t('commons.button.clean') }} +
+ +