From a5a707b92393c398fe7c0087c95737f1740936d2 Mon Sep 17 00:00:00 2001 From: ssongliu <73214554+ssongliu@users.noreply.github.com> Date: Tue, 21 Nov 2023 22:14:07 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=B9=E5=99=A8=E9=80=82=E9=85=8D=20?= =?UTF-8?q?IPv6=20(#3016)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs #2990 #2971 --- backend/app/api/v1/docker.go | 25 ++- backend/app/dto/container.go | 22 ++- backend/app/dto/docker.go | 11 ++ backend/app/service/container_network.go | 62 ++++-- backend/app/service/docker.go | 72 ++++++- backend/router/ro_container.go | 1 + cmd/server/docs/docs.go | 134 ++++++++++++- cmd/server/docs/swagger.json | 134 ++++++++++++- cmd/server/docs/swagger.yaml | 92 ++++++++- frontend/src/api/interface/container.ts | 6 + frontend/src/api/modules/container.ts | 7 + frontend/src/lang/modules/en.ts | 8 + frontend/src/lang/modules/tw.ts | 6 + frontend/src/lang/modules/zh.ts | 6 + frontend/src/utils/util.ts | 27 +++ .../views/container/network/create/index.vue | 178 ++++++++++++++++-- .../src/views/container/setting/index.vue | 51 +++++ .../views/container/setting/ipv6/index.vue | 157 +++++++++++++++ 18 files changed, 938 insertions(+), 61 deletions(-) create mode 100644 frontend/src/views/container/setting/ipv6/index.vue diff --git a/backend/app/api/v1/docker.go b/backend/app/api/v1/docker.go index 9ae5b9e2d..1d493aab3 100644 --- a/backend/app/api/v1/docker.go +++ b/backend/app/api/v1/docker.go @@ -83,7 +83,7 @@ func (b *BaseApi) UpdateDaemonJson(c *gin.Context) { // @Param request body dto.LogOption true "request" // @Success 200 // @Security ApiKeyAuth -// @Router /containers/daemonjson/update [post] +// @Router /containers/logoption/update [post] // @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 docker daemon.json 日志配置","formatEN":"Updated the docker daemon.json log option"} func (b *BaseApi) UpdateLogOption(c *gin.Context) { var req dto.LogOption @@ -99,6 +99,29 @@ func (b *BaseApi) UpdateLogOption(c *gin.Context) { helper.SuccessWithData(c, nil) } +// @Tags Container Docker +// @Summary Update docker daemon.json ipv6 option +// @Description 修改 docker ipv6 配置 +// @Accept json +// @Param request body dto.LogOption true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /containers/ipv6option/update [post] +// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFunctions":[],"formatZH":"更新 docker daemon.json ipv6 配置","formatEN":"Updated the docker daemon.json ipv6 option"} +func (b *BaseApi) UpdateIpv6Option(c *gin.Context) { + var req dto.Ipv6Option + if err := helper.CheckBind(&req, c); err != nil { + return + } + + if err := dockerService.UpdateIpv6Option(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + + helper.SuccessWithData(c, nil) +} + // @Tags Container Docker // @Summary Update docker daemon.json by upload file // @Description 上传替换 docker 配置文件 diff --git a/backend/app/dto/container.go b/backend/app/dto/container.go index 0648e90c0..767edfc62 100644 --- a/backend/app/dto/container.go +++ b/backend/app/dto/container.go @@ -135,13 +135,21 @@ type Network struct { Attachable bool `json:"attachable"` } type NetworkCreate struct { - Name string `json:"name" validate:"required"` - Driver string `json:"driver" validate:"required"` - Options []string `json:"options"` - Subnet string `json:"subnet"` - Gateway string `json:"gateway"` - IPRange string `json:"ipRange"` - Labels []string `json:"labels"` + Name string `json:"name" validate:"required"` + Driver string `json:"driver" validate:"required"` + Options []string `json:"options"` + Ipv4 bool `json:"ipv4"` + Subnet string `json:"subnet"` + Gateway string `json:"gateway"` + IPRange string `json:"ipRange"` + AuxAddress []SettingUpdate `json:"auxAddress"` + + Ipv6 bool `json:"ipv6"` + SubnetV6 string `json:"subnetV6"` + GatewayV6 string `json:"gatewayV6"` + IPRangeV6 string `json:"ipRangeV6"` + AuxAddressV6 []SettingUpdate `json:"auxAddressV6"` + Labels []string `json:"labels"` } type Volume struct { diff --git a/backend/app/dto/docker.go b/backend/app/dto/docker.go index 2f4299e74..bfabacc41 100644 --- a/backend/app/dto/docker.go +++ b/backend/app/dto/docker.go @@ -14,6 +14,11 @@ type DaemonJsonConf struct { IPTables bool `json:"iptables"` CgroupDriver string `json:"cgroupDriver"` + Ipv6 bool `json:"ipv6"` + FixedCidrV6 string `json:"fixedCidrV6"` + Ip6Tables bool `json:"ip6Tables"` + Experimental bool `json:"experimental"` + LogMaxSize string `json:"logMaxSize"` LogMaxFile string `json:"logMaxFile"` } @@ -23,6 +28,12 @@ type LogOption struct { LogMaxFile string `json:"logMaxFile"` } +type Ipv6Option struct { + FixedCidrV6 string `json:"fixedCidrV6"` + Ip6Tables bool `json:"ip6Tables" validate:"required"` + Experimental bool `json:"experimental"` +} + type DockerOperation struct { Operation string `json:"operation" validate:"required,oneof=start restart stop"` } diff --git a/backend/app/service/container_network.go b/backend/app/service/container_network.go index 08f567447..a3a890772 100644 --- a/backend/app/service/container_network.go +++ b/backend/app/service/container_network.go @@ -116,29 +116,57 @@ func (u *ContainerService) CreateNetwork(req dto.NetworkCreate) error { return err } var ( - ipam network.IPAMConfig - hasConf bool + ipams []network.IPAMConfig + enableV6 bool ) - if len(req.Subnet) != 0 { - ipam.Subnet = req.Subnet - hasConf = true + if req.Ipv4 { + var itemIpam network.IPAMConfig + if len(req.AuxAddress) != 0 { + itemIpam.AuxAddress = make(map[string]string) + } + if len(req.Subnet) != 0 { + itemIpam.Subnet = req.Subnet + } + if len(req.Gateway) != 0 { + itemIpam.Gateway = req.Gateway + } + if len(req.IPRange) != 0 { + itemIpam.IPRange = req.IPRange + } + for _, addr := range req.AuxAddress { + itemIpam.AuxAddress[addr.Key] = addr.Value + } + ipams = append(ipams, itemIpam) } - if len(req.Gateway) != 0 { - ipam.Gateway = req.Gateway - hasConf = true - } - if len(req.IPRange) != 0 { - ipam.IPRange = req.IPRange - hasConf = true + if req.Ipv6 { + enableV6 = true + var itemIpam network.IPAMConfig + if len(req.AuxAddress) != 0 { + itemIpam.AuxAddress = make(map[string]string) + } + if len(req.SubnetV6) != 0 { + itemIpam.Subnet = req.SubnetV6 + } + if len(req.GatewayV6) != 0 { + itemIpam.Gateway = req.GatewayV6 + } + if len(req.IPRangeV6) != 0 { + itemIpam.IPRange = req.IPRangeV6 + } + for _, addr := range req.AuxAddressV6 { + itemIpam.AuxAddress[addr.Key] = addr.Value + } + ipams = append(ipams, itemIpam) } options := types.NetworkCreate{ - Driver: req.Driver, - Options: stringsToMap(req.Options), - Labels: stringsToMap(req.Labels), + EnableIPv6: enableV6, + Driver: req.Driver, + Options: stringsToMap(req.Options), + Labels: stringsToMap(req.Labels), } - if hasConf { - options.IPAM = &network.IPAM{Config: []network.IPAMConfig{ipam}} + if len(ipams) != 0 { + options.IPAM = &network.IPAM{Config: ipams} } if _, err := client.NetworkCreate(context.TODO(), req.Name, options); err != nil { return err diff --git a/backend/app/service/docker.go b/backend/app/service/docker.go index a73337705..9e6f555bf 100644 --- a/backend/app/service/docker.go +++ b/backend/app/service/docker.go @@ -21,6 +21,7 @@ type DockerService struct{} type IDockerService interface { UpdateConf(req dto.SettingUpdate) error UpdateLogOption(req dto.LogOption) error + UpdateIpv6Option(req dto.Ipv6Option) error UpdateConfByFile(info dto.DaemonJsonUpdateByFile) error LoadDockerStatus() string LoadDockerConf() *dto.DaemonJsonConf @@ -32,13 +33,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"` - LogOption logOption `json:"log-opts"` + Status string `json:"status"` + Mirrors []string `json:"registry-mirrors"` + Registries []string `json:"insecure-registries"` + LiveRestore bool `json:"live-restore"` + Ipv6 bool `json:"ipv6"` + FixedCidrV6 string `json:"fixed-cidr-v6"` + Ip6Tables bool `json:"ip6tables"` + Experimental bool `json:"experimental"` + IPTables bool `json:"iptables"` + ExecOpts []string `json:"exec-opts"` + LogOption logOption `json:"log-opts"` } type logOption struct { LogMaxSize string `json:"max-size"` @@ -110,6 +115,10 @@ func (u *DockerService) LoadDockerConf() *dto.DaemonJsonConf { break } } + data.Ipv6 = conf.Ipv6 + data.FixedCidrV6 = conf.FixedCidrV6 + data.Ip6Tables = conf.Ip6Tables + data.Experimental = conf.Experimental data.LogMaxSize = conf.LogOption.LogMaxSize data.LogMaxFile = conf.LogOption.LogMaxFile data.Mirrors = conf.Mirrors @@ -149,6 +158,13 @@ func (u *DockerService) UpdateConf(req dto.SettingUpdate) error { } else { daemonMap["registry-mirrors"] = strings.Split(req.Value, ",") } + case "Ipv6": + if req.Value == "disable" { + delete(daemonMap, "ipv6") + delete(daemonMap, "fixed-cidr-v6") + delete(daemonMap, "ip6tables") + delete(daemonMap, "experimental") + } case "LogOption": if req.Value == "disable" { delete(daemonMap, "log-opts") @@ -237,6 +253,48 @@ func (u *DockerService) UpdateLogOption(req dto.LogOption) error { return nil } +func (u *DockerService) UpdateIpv6Option(req dto.Ipv6Option) error { + if _, err := os.Stat(constant.DaemonJsonPath); err != nil && os.IsNotExist(err) { + if err = os.MkdirAll(path.Dir(constant.DaemonJsonPath), os.ModePerm); err != nil { + return err + } + _, _ = os.Create(constant.DaemonJsonPath) + } + + file, err := os.ReadFile(constant.DaemonJsonPath) + if err != nil { + return err + } + daemonMap := make(map[string]interface{}) + _ = json.Unmarshal(file, &daemonMap) + + daemonMap["ipv6"] = true + daemonMap["fixed-cidr-v6"] = req.FixedCidrV6 + if req.Ip6Tables { + daemonMap["ip6tables"] = req.Ip6Tables + } + if req.Experimental { + daemonMap["experimental"] = req.Experimental + } + if len(daemonMap) == 0 { + _ = os.Remove(constant.DaemonJsonPath) + return nil + } + newJson, err := json.MarshalIndent(daemonMap, "", "\t") + if err != nil { + return err + } + if err := os.WriteFile(constant.DaemonJsonPath, newJson, 0640); err != nil { + return err + } + + stdout, err := cmd.Exec("systemctl restart docker") + if err != nil { + return errors.New(string(stdout)) + } + return nil +} + func (u *DockerService) UpdateConfByFile(req dto.DaemonJsonUpdateByFile) error { if len(req.File) == 0 { _ = os.Remove(constant.DaemonJsonPath) diff --git a/backend/router/ro_container.go b/backend/router/ro_container.go index cf89deae2..a065861ea 100644 --- a/backend/router/ro_container.go +++ b/backend/router/ro_container.go @@ -79,6 +79,7 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) { baRouter.POST("/docker/operate", baseApi.OperateDocker) baRouter.POST("/daemonjson/update", baseApi.UpdateDaemonJson) baRouter.POST("/logoption/update", baseApi.UpdateLogOption) + baRouter.POST("/ipv6option/update", baseApi.UpdateIpv6Option) baRouter.POST("/daemonjson/update/byfile", baseApi.UpdateDaemonJsonByFile) } } diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index ebee5efb1..bb209bdb4 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -1414,14 +1414,14 @@ const docTemplate = `{ "ApiKeyAuth": [] } ], - "description": "修改 docker 日志配置", + "description": "修改 docker 配置信息", "consumes": [ "application/json" ], "tags": [ "Container Docker" ], - "summary": "Update docker daemon.json log option", + "summary": "Update docker daemon.json", "parameters": [ { "description": "request", @@ -1429,7 +1429,7 @@ const docTemplate = `{ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/dto.LogOption" + "$ref": "#/definitions/dto.SettingUpdate" } } ], @@ -1440,9 +1440,12 @@ const docTemplate = `{ }, "x-panel-log": { "BeforeFunctions": [], - "bodyKeys": [], - "formatEN": "Updated the docker daemon.json log option", - "formatZH": "更新 docker daemon.json 日志配置", + "bodyKeys": [ + "key", + "value" + ], + "formatEN": "Updated the docker daemon.json configuration [key]=\u003e[value]", + "formatZH": "更新 docker daemon.json 配置 [key]=\u003e[value]", "paramKeys": [] } } @@ -2029,6 +2032,46 @@ const docTemplate = `{ } } }, + "/containers/ipv6option/update": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "修改 docker ipv6 配置", + "consumes": [ + "application/json" + ], + "tags": [ + "Container Docker" + ], + "summary": "Update docker daemon.json ipv6 option", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.LogOption" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFunctions": [], + "bodyKeys": [], + "formatEN": "Updated the docker daemon.json ipv6 option", + "formatZH": "更新 docker daemon.json ipv6 配置", + "paramKeys": [] + } + } + }, "/containers/limit": { "get": { "security": [ @@ -2128,6 +2171,46 @@ const docTemplate = `{ } } }, + "/containers/logoption/update": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "修改 docker 日志配置", + "consumes": [ + "application/json" + ], + "tags": [ + "Container Docker" + ], + "summary": "Update docker daemon.json log option", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.LogOption" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFunctions": [], + "bodyKeys": [], + "formatEN": "Updated the docker daemon.json log option", + "formatZH": "更新 docker daemon.json 日志配置", + "paramKeys": [] + } + } + }, "/containers/network": { "get": { "security": [ @@ -14023,15 +14106,27 @@ const docTemplate = `{ "cgroupDriver": { "type": "string" }, + "experimental": { + "type": "boolean" + }, + "fixedCidrV6": { + "type": "string" + }, "insecureRegistries": { "type": "array", "items": { "type": "string" } }, + "ip6Tables": { + "type": "boolean" + }, "iptables": { "type": "boolean" }, + "ipv6": { + "type": "boolean" + }, "isSwarm": { "type": "boolean" }, @@ -15530,15 +15625,39 @@ const docTemplate = `{ "name" ], "properties": { + "auxAddress": { + "type": "array", + "items": { + "$ref": "#/definitions/dto.SettingUpdate" + } + }, + "auxAddressV6": { + "type": "array", + "items": { + "$ref": "#/definitions/dto.SettingUpdate" + } + }, "driver": { "type": "string" }, "gateway": { "type": "string" }, + "gatewayV6": { + "type": "string" + }, "ipRange": { "type": "string" }, + "ipRangeV6": { + "type": "string" + }, + "ipv4": { + "type": "boolean" + }, + "ipv6": { + "type": "boolean" + }, "labels": { "type": "array", "items": { @@ -15556,6 +15675,9 @@ const docTemplate = `{ }, "subnet": { "type": "string" + }, + "subnetV6": { + "type": "string" } } }, diff --git a/cmd/server/docs/swagger.json b/cmd/server/docs/swagger.json index c67779cf5..b338e63b3 100644 --- a/cmd/server/docs/swagger.json +++ b/cmd/server/docs/swagger.json @@ -1407,14 +1407,14 @@ "ApiKeyAuth": [] } ], - "description": "修改 docker 日志配置", + "description": "修改 docker 配置信息", "consumes": [ "application/json" ], "tags": [ "Container Docker" ], - "summary": "Update docker daemon.json log option", + "summary": "Update docker daemon.json", "parameters": [ { "description": "request", @@ -1422,7 +1422,7 @@ "in": "body", "required": true, "schema": { - "$ref": "#/definitions/dto.LogOption" + "$ref": "#/definitions/dto.SettingUpdate" } } ], @@ -1433,9 +1433,12 @@ }, "x-panel-log": { "BeforeFunctions": [], - "bodyKeys": [], - "formatEN": "Updated the docker daemon.json log option", - "formatZH": "更新 docker daemon.json 日志配置", + "bodyKeys": [ + "key", + "value" + ], + "formatEN": "Updated the docker daemon.json configuration [key]=\u003e[value]", + "formatZH": "更新 docker daemon.json 配置 [key]=\u003e[value]", "paramKeys": [] } } @@ -2022,6 +2025,46 @@ } } }, + "/containers/ipv6option/update": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "修改 docker ipv6 配置", + "consumes": [ + "application/json" + ], + "tags": [ + "Container Docker" + ], + "summary": "Update docker daemon.json ipv6 option", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.LogOption" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFunctions": [], + "bodyKeys": [], + "formatEN": "Updated the docker daemon.json ipv6 option", + "formatZH": "更新 docker daemon.json ipv6 配置", + "paramKeys": [] + } + } + }, "/containers/limit": { "get": { "security": [ @@ -2121,6 +2164,46 @@ } } }, + "/containers/logoption/update": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "修改 docker 日志配置", + "consumes": [ + "application/json" + ], + "tags": [ + "Container Docker" + ], + "summary": "Update docker daemon.json log option", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.LogOption" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFunctions": [], + "bodyKeys": [], + "formatEN": "Updated the docker daemon.json log option", + "formatZH": "更新 docker daemon.json 日志配置", + "paramKeys": [] + } + } + }, "/containers/network": { "get": { "security": [ @@ -14016,15 +14099,27 @@ "cgroupDriver": { "type": "string" }, + "experimental": { + "type": "boolean" + }, + "fixedCidrV6": { + "type": "string" + }, "insecureRegistries": { "type": "array", "items": { "type": "string" } }, + "ip6Tables": { + "type": "boolean" + }, "iptables": { "type": "boolean" }, + "ipv6": { + "type": "boolean" + }, "isSwarm": { "type": "boolean" }, @@ -15523,15 +15618,39 @@ "name" ], "properties": { + "auxAddress": { + "type": "array", + "items": { + "$ref": "#/definitions/dto.SettingUpdate" + } + }, + "auxAddressV6": { + "type": "array", + "items": { + "$ref": "#/definitions/dto.SettingUpdate" + } + }, "driver": { "type": "string" }, "gateway": { "type": "string" }, + "gatewayV6": { + "type": "string" + }, "ipRange": { "type": "string" }, + "ipRangeV6": { + "type": "string" + }, + "ipv4": { + "type": "boolean" + }, + "ipv6": { + "type": "boolean" + }, "labels": { "type": "array", "items": { @@ -15549,6 +15668,9 @@ }, "subnet": { "type": "string" + }, + "subnetV6": { + "type": "string" } } }, diff --git a/cmd/server/docs/swagger.yaml b/cmd/server/docs/swagger.yaml index 9499a6997..d91f58d85 100644 --- a/cmd/server/docs/swagger.yaml +++ b/cmd/server/docs/swagger.yaml @@ -678,12 +678,20 @@ definitions: properties: cgroupDriver: type: string + experimental: + type: boolean + fixedCidrV6: + type: string insecureRegistries: items: type: string type: array + ip6Tables: + type: boolean iptables: type: boolean + ipv6: + type: boolean isSwarm: type: boolean liveRestore: @@ -1694,12 +1702,28 @@ definitions: type: object dto.NetworkCreate: properties: + auxAddress: + items: + $ref: '#/definitions/dto.SettingUpdate' + type: array + auxAddressV6: + items: + $ref: '#/definitions/dto.SettingUpdate' + type: array driver: type: string gateway: type: string + gatewayV6: + type: string ipRange: type: string + ipRangeV6: + type: string + ipv4: + type: boolean + ipv6: + type: boolean labels: items: type: string @@ -1712,6 +1736,8 @@ definitions: type: array subnet: type: string + subnetV6: + type: string required: - driver - name @@ -5426,27 +5452,29 @@ paths: post: consumes: - application/json - description: 修改 docker 日志配置 + description: 修改 docker 配置信息 parameters: - description: request in: body name: request required: true schema: - $ref: '#/definitions/dto.LogOption' + $ref: '#/definitions/dto.SettingUpdate' responses: "200": description: OK security: - ApiKeyAuth: [] - summary: Update docker daemon.json log option + summary: Update docker daemon.json tags: - Container Docker x-panel-log: BeforeFunctions: [] - bodyKeys: [] - formatEN: Updated the docker daemon.json log option - formatZH: 更新 docker daemon.json 日志配置 + bodyKeys: + - key + - value + formatEN: Updated the docker daemon.json configuration [key]=>[value] + formatZH: 更新 docker daemon.json 配置 [key]=>[value] paramKeys: [] /containers/daemonjson/update/byfile: post: @@ -5820,6 +5848,32 @@ paths: summary: Container inspect tags: - Container + /containers/ipv6option/update: + post: + consumes: + - application/json + description: 修改 docker ipv6 配置 + parameters: + - description: request + in: body + name: request + required: true + schema: + $ref: '#/definitions/dto.LogOption' + responses: + "200": + description: OK + security: + - ApiKeyAuth: [] + summary: Update docker daemon.json ipv6 option + tags: + - Container Docker + x-panel-log: + BeforeFunctions: [] + bodyKeys: [] + formatEN: Updated the docker daemon.json ipv6 option + formatZH: 更新 docker daemon.json ipv6 配置 + paramKeys: [] /containers/limit: get: description: 获取容器限制 @@ -5879,6 +5933,32 @@ paths: summary: Load container log tags: - Container + /containers/logoption/update: + post: + consumes: + - application/json + description: 修改 docker 日志配置 + parameters: + - description: request + in: body + name: request + required: true + schema: + $ref: '#/definitions/dto.LogOption' + responses: + "200": + description: OK + security: + - ApiKeyAuth: [] + summary: Update docker daemon.json log option + tags: + - Container Docker + x-panel-log: + BeforeFunctions: [] + bodyKeys: [] + formatEN: Updated the docker daemon.json log option + formatZH: 更新 docker daemon.json 日志配置 + paramKeys: [] /containers/network: get: consumes: diff --git a/frontend/src/api/interface/container.ts b/frontend/src/api/interface/container.ts index 22eb12048..4b8d7d003 100644 --- a/frontend/src/api/interface/container.ts +++ b/frontend/src/api/interface/container.ts @@ -297,6 +297,12 @@ export namespace Container { liveRestore: boolean; iptables: boolean; cgroupDriver: string; + + ipv6: boolean; + fixedCidrV6: string; + ip6Tables: boolean; + experimental: boolean; + logMaxSize: string; logMaxFile: string; } diff --git a/frontend/src/api/modules/container.ts b/frontend/src/api/modules/container.ts index a02277ffd..f69d89938 100644 --- a/frontend/src/api/modules/container.ts +++ b/frontend/src/api/modules/container.ts @@ -179,6 +179,13 @@ export const updateDaemonJson = (key: string, value: string) => { export const updateLogOption = (maxSize: string, maxFile: string) => { return http.post(`/containers/logoption/update`, { logMaxSize: maxSize, logMaxFile: maxFile }, TimeoutEnum.T_60S); }; +export const updateIpv6Option = (fixedCidrV6: string, ip6Tables: boolean, experimental: boolean) => { + return http.post( + `/containers/ipv6option/update`, + { fixedCidrV6: fixedCidrV6, ip6Tables: ip6Tables, experimental: experimental }, + TimeoutEnum.T_60S, + ); +}; export const updateDaemonJsonByfile = (params: Container.DaemonJsonUpdateByFile) => { return http.post(`/containers/daemonjson/update/byfile`, params); }; diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 9244cf870..35270652d 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -190,6 +190,7 @@ const message = { leechExts: 'Only support letters, numbers and,', paramSimple: 'Support lowercase letters and numbers, length 1-128', filePermission: 'File Permission Error', + formatErr: 'Format error, please check and retry', }, res: { paramError: 'The request failed, please try again later!', @@ -658,6 +659,7 @@ const message = { subnet: 'Subnet', scope: 'IP Scope', gateway: 'Gateway', + auxAddress: 'Exclude IP', volume: 'Volume', volumeDir: 'Volume dir', @@ -716,6 +718,12 @@ 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', + ipv6Helper: + 'When enabling IPv6, you need to add an IPv6 container network. Refer to the official documentation for specific configuration steps.', + ipv6CidrHelper: 'IPv6 address pool range for containers', + ipv6TablesHelper: 'Automatic configuration of Docker IPv6 for iptables rules', + experimentalHelper: + 'Enabling ip6tables requires this configuration to be turned on; otherwise, ip6tables will be ignored', cutLog: 'Log option', cutLogHelper1: 'The current configuration will only affect newly created containers.', cutLogHelper2: 'Existing containers need to be recreated for the configuration to take effect.', diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts index a7aa7fa6e..aa1010042 100644 --- a/frontend/src/lang/modules/tw.ts +++ b/frontend/src/lang/modules/tw.ts @@ -189,6 +189,7 @@ const message = { leechExts: '僅支持字母數字和,', paramSimple: '支持小寫字母和數字,長度 1-128', filePermission: '權限錯誤', + formatErr: '格式錯誤,檢查後重試', }, res: { paramError: '請求失敗,請稍後重試!', @@ -642,6 +643,7 @@ const message = { subnet: '子網', scope: 'IP 範圍', gateway: '網關', + auxAddress: '排除 IP', volume: '存儲卷', volumeDir: '存儲卷目錄', @@ -692,6 +694,10 @@ const message = { mirrorsHelper: '優先使用加速 URL 執行操作,設置為空則取消鏡像加速。', mirrorsHelper2: '具體操作配置請參照官方文檔', registries: '私有倉庫', + ipv6Helper: '開啟 IPv6 後,需要增加 IPv6 的容器網路,具體操作配置請參照官方文檔', + ipv6CidrHelper: '容器的 IPv6 地址池範圍', + ipv6TablesHelper: 'Docker IPv6 對 iptables 規則的自動配置', + experimentalHelper: '開啟 ip6tables 必須開啟此配置,否則 ip6tables 會被忽略', cutLog: '日誌切割', cutLogHelper1: '當前配置只會影響新創建的容器;', cutLogHelper2: '已經創建的容器需要重新創建使配置生效;', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index e7de53f5c..774e812fb 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -189,6 +189,7 @@ const message = { leechExts: '仅支持字母数字和,', paramSimple: '支持小写字母和数字,长度1-128', filePermission: '权限错误', + formatErr: '格式错误,检查后重试', }, res: { paramError: '请求失败,请稍后重试!', @@ -643,6 +644,7 @@ const message = { subnet: '子网', scope: 'IP 范围', gateway: '网关', + auxAddress: '排除 IP', volume: '存储卷', volumeDir: '存储卷目录', @@ -693,6 +695,10 @@ const message = { mirrorsHelper: '优先使用加速 URL 执行操作,设置为空则取消镜像加速。', mirrorsHelper2: '具体操作配置请参照官方文档', registries: '私有仓库', + ipv6Helper: '开启 IPv6 后,需要增加 IPv6 的容器网络,具体操作配置请参照官方文档', + ipv6CidrHelper: '容器的 IPv6 地址池范围', + ipv6TablesHelper: 'Docker IPv6 对 iptables 规则的自动配置', + experimentalHelper: '开启 ip6tables 必须开启此配置,否则 ip6tables 会被忽略', cutLog: '日志切割', cutLogHelper1: '当前配置只会影响新创建的容器;', cutLogHelper2: '已经创建的容器需要重新创建使配置生效;', diff --git a/frontend/src/utils/util.ts b/frontend/src/utils/util.ts index 3823590d4..5053d3cac 100644 --- a/frontend/src/utils/util.ts +++ b/frontend/src/utils/util.ts @@ -247,6 +247,33 @@ export function checkIpV4V6(value: string): boolean { } } +export function checkIpV6(value: string): boolean { + if (value === '' || typeof value === 'undefined' || value == null) { + return true; + } else { + const IPv4SegmentFormat = '(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'; + const IPv4AddressFormat = `(${IPv4SegmentFormat}[.]){3}${IPv4SegmentFormat}`; + const IPv6SegmentFormat = '(?:[0-9a-fA-F]{1,4})'; + const IPv6AddressRegExp = new RegExp( + '^(' + + `(?:${IPv6SegmentFormat}:){7}(?:${IPv6SegmentFormat}|:)|` + + `(?:${IPv6SegmentFormat}:){6}(?:${IPv4AddressFormat}|:${IPv6SegmentFormat}|:)|` + + `(?:${IPv6SegmentFormat}:){5}(?::${IPv4AddressFormat}|(:${IPv6SegmentFormat}){1,2}|:)|` + + `(?:${IPv6SegmentFormat}:){4}(?:(:${IPv6SegmentFormat}){0,1}:${IPv4AddressFormat}|(:${IPv6SegmentFormat}){1,3}|:)|` + + `(?:${IPv6SegmentFormat}:){3}(?:(:${IPv6SegmentFormat}){0,2}:${IPv4AddressFormat}|(:${IPv6SegmentFormat}){1,4}|:)|` + + `(?:${IPv6SegmentFormat}:){2}(?:(:${IPv6SegmentFormat}){0,3}:${IPv4AddressFormat}|(:${IPv6SegmentFormat}){1,5}|:)|` + + `(?:${IPv6SegmentFormat}:){1}(?:(:${IPv6SegmentFormat}){0,4}:${IPv4AddressFormat}|(:${IPv6SegmentFormat}){1,6}|:)|` + + `(?::((?::${IPv6SegmentFormat}){0,5}:${IPv4AddressFormat}|(?::${IPv6SegmentFormat}){1,7}|:))` + + ')(%[0-9a-zA-Z-.:]{1,})?$', + ); + if (!IPv6AddressRegExp.test(value) && value !== '') { + return true; + } else { + return false; + } + } +} + export function checkCidr(value: string): boolean { if (value === '') { return true; diff --git a/frontend/src/views/container/network/create/index.vue b/frontend/src/views/container/network/create/index.vue index 709b097c7..e096aab9c 100644 --- a/frontend/src/views/container/network/create/index.vue +++ b/frontend/src/views/container/network/create/index.vue @@ -1,5 +1,5 @@