mirror of https://github.com/1Panel-dev/1Panel
parent
055216604e
commit
a5a707b923
|
@ -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 配置文件
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"`
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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.',
|
||||
|
|
|
@ -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: '已經創建的容器需要重新創建使配置生效;',
|
||||
|
|
|
@ -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: '已经创建的容器需要重新创建使配置生效;',
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<el-drawer v-model="drawerVisible" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
|
||||
<el-drawer v-model="drawerVisible" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="$t('container.createNetwork')" :back="handleClose" />
|
||||
</template>
|
||||
|
@ -17,6 +17,99 @@
|
|||
<el-option label="overlay" value="overlay" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-checkbox v-model="form.ipv4">IPv4</el-checkbox>
|
||||
<div v-if="form.ipv4">
|
||||
<el-row type="flex" justify="center" :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('container.subnet')" prop="subnet">
|
||||
<el-input placeholder="172.16.10.0/24" clearable v-model.trim="form.subnet" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('container.gateway')" prop="gateway">
|
||||
<el-input placeholder="172.16.10.12" clearable v-model.trim="form.gateway" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('container.scope')" prop="scope">
|
||||
<el-input placeholder="172.16.10.0/16" clearable v-model.trim="form.scope" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12"></el-col>
|
||||
</el-row>
|
||||
<el-form-item :label="$t('container.auxAddress')" prop="scopeV6">
|
||||
<el-table :data="form.auxAddress" v-if="form.auxAddress.length !== 0">
|
||||
<el-table-column :label="$t('container.label')" min-width="100">
|
||||
<template #default="{ row }">
|
||||
<el-input placeholder="my-router" v-model="row.key" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="IP" min-width="150">
|
||||
<template #default="{ row }">
|
||||
<el-input placeholder="172.16.10.13" v-model="row.value" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="40">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" @click="handleV4Delete(scope.$index)">
|
||||
{{ $t('commons.button.delete') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-button class="mt-2" @click="handleV4Add()">
|
||||
{{ $t('commons.button.add') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<el-checkbox class="mb-4" v-model="form.ipv6">IPv6</el-checkbox>
|
||||
<div v-if="form.ipv6">
|
||||
<el-row type="flex" justify="center" :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('container.subnet')" prop="subnetV6">
|
||||
<el-input placeholder="2408:400e::/48" clearable v-model.trim="form.subnetV6" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('container.gateway')" prop="gatewayV6">
|
||||
<el-input placeholder="2408:400e::1" clearable v-model.trim="form.gatewayV6" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('container.scope')" prop="scopeV6">
|
||||
<el-input placeholder="2408:400e::/64" clearable v-model.trim="form.scopeV6" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12"></el-col>
|
||||
</el-row>
|
||||
<el-form-item :label="$t('container.auxAddress')" prop="scopeV6">
|
||||
<el-table :data="form.auxAddressV6" v-if="form.auxAddressV6.length !== 0">
|
||||
<el-table-column :label="$t('container.label')" min-width="100">
|
||||
<template #default="{ row }">
|
||||
<el-input placeholder="my-router" v-model="row.key" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="IP" min-width="150">
|
||||
<template #default="{ row }">
|
||||
<el-input placeholder="2408:400e::3" v-model="row.value" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="40">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" @click="handleV6Delete(scope.$index)">
|
||||
{{ $t('commons.button.delete') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-button class="mt-2" @click="handleV6Add()">
|
||||
{{ $t('commons.button.add') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
||||
<el-form-item :label="$t('container.option')" prop="optionStr">
|
||||
<el-input
|
||||
type="textarea"
|
||||
|
@ -25,15 +118,6 @@
|
|||
v-model="form.optionStr"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('container.subnet')" prop="subnet">
|
||||
<el-input clearable v-model.trim="form.subnet" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('container.gateway')" prop="gateway">
|
||||
<el-input clearable v-model.trim="form.gateway" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('container.scope')" prop="scope">
|
||||
<el-input clearable v-model.trim="form.scope" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('container.tag')" prop="labelStr">
|
||||
<el-input
|
||||
type="textarea"
|
||||
|
@ -66,6 +150,7 @@ import { ElForm } from 'element-plus';
|
|||
import { createNetwork } from '@/api/modules/container';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { checkIpV6 } from '@/utils/util';
|
||||
|
||||
const loading = ref(false);
|
||||
|
||||
|
@ -77,9 +162,16 @@ const form = reactive({
|
|||
optionStr: '',
|
||||
options: [] as Array<string>,
|
||||
driver: '',
|
||||
ipv4: true,
|
||||
subnet: '',
|
||||
gateway: '',
|
||||
scope: '',
|
||||
auxAddress: [],
|
||||
ipv6: false,
|
||||
subnetV6: '',
|
||||
gatewayV6: '',
|
||||
scopeV6: '',
|
||||
auxAddressV6: [],
|
||||
});
|
||||
|
||||
const acceptParams = (): void => {
|
||||
|
@ -88,10 +180,17 @@ const acceptParams = (): void => {
|
|||
form.labels = [];
|
||||
form.optionStr = '';
|
||||
form.options = [];
|
||||
form.driver = '';
|
||||
form.driver = 'bridge';
|
||||
form.ipv4 = true;
|
||||
form.subnet = '';
|
||||
form.gateway = '';
|
||||
form.scope = '';
|
||||
form.auxAddress = [];
|
||||
form.ipv6 = false;
|
||||
form.subnetV6 = '';
|
||||
form.gatewayV6 = '';
|
||||
form.scopeV6 = '';
|
||||
form.auxAddressV6 = [];
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||
|
@ -103,8 +202,65 @@ const handleClose = () => {
|
|||
const rules = reactive({
|
||||
name: [Rules.requiredInput],
|
||||
driver: [Rules.requiredSelect],
|
||||
subnet: [{ validator: checkCidr, trigger: 'blur' }],
|
||||
gateway: [Rules.ip],
|
||||
scope: [{ validator: checkCidr, trigger: 'blur' }],
|
||||
subnetV6: [{ validator: checkFixedCidrV6, trigger: 'blur' }],
|
||||
gatewayV6: [Rules.ipV6],
|
||||
scopeV6: [{ validator: checkFixedCidrV6, trigger: 'blur' }],
|
||||
});
|
||||
|
||||
function checkCidr(rule: any, value: any, callback: any) {
|
||||
if (value === '') {
|
||||
callback();
|
||||
}
|
||||
const reg =
|
||||
/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?:\/([0-9]|[1-2][0-9]|3[0-2]))?$/;
|
||||
if (!reg.test(value)) {
|
||||
return callback(new Error(i18n.global.t('commons.rule.formatErr')));
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
||||
function checkFixedCidrV6(rule: any, value: any, callback: any) {
|
||||
if (value === '') {
|
||||
callback();
|
||||
}
|
||||
if (!form.subnetV6 || form.subnetV6.indexOf('/') === -1) {
|
||||
return callback(new Error(i18n.global.t('commons.rule.formatErr')));
|
||||
}
|
||||
if (checkIpV6(form.subnetV6.split('/')[0])) {
|
||||
return callback(new Error(i18n.global.t('commons.rule.formatErr')));
|
||||
}
|
||||
const reg = /^(?:[1-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$/;
|
||||
if (!reg.test(form.subnetV6.split('/')[1])) {
|
||||
return callback(new Error(i18n.global.t('commons.rule.formatErr')));
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
||||
const handleV4Add = () => {
|
||||
let item = {
|
||||
key: '',
|
||||
value: '',
|
||||
};
|
||||
form.auxAddress.push(item);
|
||||
};
|
||||
const handleV4Delete = (index: number) => {
|
||||
form.auxAddress.splice(index, 1);
|
||||
};
|
||||
|
||||
const handleV6Add = () => {
|
||||
let item = {
|
||||
key: '',
|
||||
value: '',
|
||||
};
|
||||
form.auxAddressV6.push(item);
|
||||
};
|
||||
const handleV6Delete = (index: number) => {
|
||||
form.auxAddressV6.splice(index, 1);
|
||||
};
|
||||
|
||||
type FormInstance = InstanceType<typeof ElForm>;
|
||||
const formRef = ref<FormInstance>();
|
||||
const onSubmit = async (formEl: FormInstance | undefined) => {
|
||||
|
|
|
@ -100,6 +100,19 @@
|
|||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="ipv6" prop="ipv6">
|
||||
<el-switch v-model="form.ipv6" @change="handleIPv6"></el-switch>
|
||||
<span class="input-help"></span>
|
||||
<div v-if="ipv6OptionShow">
|
||||
<el-tag>{{ $t('container.subnet') }}: {{ form.fixedCidrV6 }}</el-tag>
|
||||
<div>
|
||||
<el-button @click="handleIPv6" type="primary" link>
|
||||
{{ $t('commons.button.view') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('container.cutLog')" prop="hasLogOption">
|
||||
<el-switch v-model="form.logOptionShow" @change="handleLogOption"></el-switch>
|
||||
<span class="input-help"></span>
|
||||
|
@ -206,6 +219,8 @@
|
|||
<Mirror ref="mirrorRef" @search="search" />
|
||||
<Registry ref="registriesRef" @search="search" />
|
||||
<LogOption ref="logOptionRef" @search="search" />
|
||||
<Ipv6Option ref="ipv6OptionRef" @search="search" />
|
||||
<ConfirmDialog ref="confirmDialogRefIpv6" @confirm="onSaveIPv6" @cancel="search" />
|
||||
<ConfirmDialog ref="confirmDialogRefIptable" @confirm="onSubmitOpenIPtable" @cancel="search" />
|
||||
<ConfirmDialog ref="confirmDialogRefLog" @confirm="onSubmitSaveLog" @cancel="search" />
|
||||
<ConfirmDialog ref="confirmDialogRefLive" @confirm="onSubmitSaveLive" @cancel="search" />
|
||||
|
@ -224,6 +239,7 @@ import { oneDark } from '@codemirror/theme-one-dark';
|
|||
import Mirror from '@/views/container/setting/mirror/index.vue';
|
||||
import Registry from '@/views/container/setting/registry/index.vue';
|
||||
import LogOption from '@/views/container/setting/log/index.vue';
|
||||
import Ipv6Option from '@/views/container/setting/ipv6/index.vue';
|
||||
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
|
||||
import i18n from '@/lang';
|
||||
import {
|
||||
|
@ -245,13 +261,16 @@ const extensions = [javascript(), oneDark];
|
|||
const confShowType = ref('base');
|
||||
|
||||
const logOptionRef = ref();
|
||||
const ipv6OptionRef = ref();
|
||||
const confirmDialogRefLog = ref();
|
||||
const mirrorRef = ref();
|
||||
const registriesRef = ref();
|
||||
const confirmDialogRefLive = ref();
|
||||
const confirmDialogRefCgroup = ref();
|
||||
const confirmDialogRefIptable = ref();
|
||||
const confirmDialogRefIpv6 = ref();
|
||||
const logOptionShow = ref();
|
||||
const ipv6OptionShow = ref();
|
||||
|
||||
const form = reactive({
|
||||
isSwarm: false,
|
||||
|
@ -262,6 +281,12 @@ const form = reactive({
|
|||
liveRestore: false,
|
||||
iptables: true,
|
||||
cgroupDriver: '',
|
||||
|
||||
ipv6: false,
|
||||
fixedCidrV6: '',
|
||||
ip6Tables: false,
|
||||
experimental: false,
|
||||
|
||||
logOptionShow: false,
|
||||
logMaxSize: '',
|
||||
logMaxFile: 3,
|
||||
|
@ -292,6 +317,27 @@ const onChangeMirrors = () => {
|
|||
const onChangeRegistries = () => {
|
||||
registriesRef.value.acceptParams({ registries: form.registries });
|
||||
};
|
||||
|
||||
const handleIPv6 = async () => {
|
||||
if (form.ipv6) {
|
||||
ipv6OptionRef.value.acceptParams({
|
||||
fixedCidrV6: form.fixedCidrV6,
|
||||
ip6Tables: form.ip6Tables,
|
||||
experimental: form.experimental,
|
||||
});
|
||||
return;
|
||||
}
|
||||
let params = {
|
||||
header: i18n.global.t('database.confChange'),
|
||||
operationInfo: i18n.global.t('database.restartNowHelper'),
|
||||
submitInputInfo: i18n.global.t('database.restartNow'),
|
||||
};
|
||||
confirmDialogRefIpv6.value!.acceptParams(params);
|
||||
};
|
||||
const onSaveIPv6 = () => {
|
||||
save('Ipv6', 'disable');
|
||||
};
|
||||
|
||||
const handleLogOption = async () => {
|
||||
if (form.logOptionShow) {
|
||||
logOptionRef.value.acceptParams({ logMaxSize: form.logMaxSize, logMaxFile: form.logMaxFile });
|
||||
|
@ -445,6 +491,11 @@ const search = async () => {
|
|||
form.logOptionShow = false;
|
||||
logOptionShow.value = false;
|
||||
}
|
||||
form.ipv6 = res.data.ipv6;
|
||||
ipv6OptionShow.value = form.ipv6;
|
||||
form.fixedCidrV6 = res.data.fixedCidrV6;
|
||||
form.ip6Tables = res.data.ip6Tables;
|
||||
form.experimental = res.data.experimental;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-drawer
|
||||
v-model="drawerVisible"
|
||||
:destroy-on-close="true"
|
||||
:close-on-click-modal="false"
|
||||
@close="handleClose"
|
||||
size="30%"
|
||||
>
|
||||
<template #header>
|
||||
<DrawerHeader header="IPv6" :back="handleClose" />
|
||||
</template>
|
||||
<el-alert class="common-prompt" :closable="false" type="warning">
|
||||
<template #default>
|
||||
<span class="input-help">
|
||||
{{ $t('container.ipv6Helper') }}
|
||||
<el-link
|
||||
style="font-size: 12px; margin-left: 5px"
|
||||
icon="Position"
|
||||
@click="toDoc()"
|
||||
type="primary"
|
||||
>
|
||||
{{ $t('firewall.quickJump') }}
|
||||
</el-link>
|
||||
</span>
|
||||
</template>
|
||||
</el-alert>
|
||||
|
||||
<el-form :model="form" ref="formRef" :rules="rules" v-loading="loading" label-position="top">
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="22">
|
||||
<el-form-item prop="fixedCidrV6" :label="$t('container.subnet')">
|
||||
<el-input v-model="form.fixedCidrV6" />
|
||||
<span class="input-help">{{ $t('container.ipv6CidrHelper') }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-checkbox v-model="showMore" :label="$t('app.advanced')" />
|
||||
</el-form-item>
|
||||
<div v-if="showMore">
|
||||
<el-form-item prop="ip6Tables" label="ip6tables">
|
||||
<el-switch v-model="form.ip6Tables"></el-switch>
|
||||
<span class="input-help">{{ $t('container.ipv6TablesHelper') }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item prop="experimental" label="experimental">
|
||||
<el-switch v-model="form.experimental"></el-switch>
|
||||
<span class="input-help">{{ $t('container.experimentalHelper') }}</span>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="handleClose">{{ $t('commons.button.cancel') }}</el-button>
|
||||
<el-button :disabled="loading" type="primary" @click="onSave(formRef)">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
|
||||
<ConfirmDialog ref="confirmDialogRef" @confirm="onSubmitSave"></ConfirmDialog>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref } from 'vue';
|
||||
import i18n from '@/lang';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { FormInstance } from 'element-plus';
|
||||
import { updateIpv6Option } from '@/api/modules/container';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { checkIpV6 } from '@/utils/util';
|
||||
|
||||
const loading = ref();
|
||||
const drawerVisible = ref();
|
||||
const confirmDialogRef = ref();
|
||||
const formRef = ref();
|
||||
const showMore = ref(false);
|
||||
|
||||
interface DialogProps {
|
||||
fixedCidrV6: string;
|
||||
ip6Tables: boolean;
|
||||
experimental: boolean;
|
||||
}
|
||||
|
||||
const form = reactive({
|
||||
fixedCidrV6: '',
|
||||
ip6Tables: false,
|
||||
experimental: false,
|
||||
});
|
||||
const rules = reactive({
|
||||
fixedCidrV6: [{ validator: checkFixedCidrV6, trigger: 'blur', required: true }],
|
||||
});
|
||||
|
||||
function checkFixedCidrV6(rule: any, value: any, callback: any) {
|
||||
if (!form.fixedCidrV6 || form.fixedCidrV6.indexOf('/') === -1) {
|
||||
return callback(new Error(i18n.global.t('commons.rule.formatErr')));
|
||||
}
|
||||
if (checkIpV6(form.fixedCidrV6.split('/')[0])) {
|
||||
return callback(new Error(i18n.global.t('commons.rule.formatErr')));
|
||||
}
|
||||
const reg = /^(?:[1-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$/;
|
||||
if (!reg.test(form.fixedCidrV6.split('/')[1])) {
|
||||
return callback(new Error(i18n.global.t('commons.rule.formatErr')));
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
||||
const toDoc = () => {
|
||||
window.open('https://1panel.cn/docs/user_manual/containers/setting/', '_blank', 'noopener,noreferrer');
|
||||
};
|
||||
|
||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
form.fixedCidrV6 = params.fixedCidrV6;
|
||||
form.ip6Tables = params.ip6Tables;
|
||||
form.experimental = params.experimental;
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
|
||||
const onSave = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
let params = {
|
||||
header: i18n.global.t('database.confChange'),
|
||||
operationInfo: i18n.global.t('database.restartNowHelper'),
|
||||
submitInputInfo: i18n.global.t('database.restartNow'),
|
||||
};
|
||||
confirmDialogRef.value!.acceptParams(params);
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmitSave = async () => {
|
||||
loading.value = true;
|
||||
await updateIpv6Option(form.fixedCidrV6, form.ip6Tables, form.experimental)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
drawerVisible.value = false;
|
||||
emit('search');
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
emit('search');
|
||||
drawerVisible.value = false;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
Loading…
Reference in New Issue