From 2633c20b3a317f1874d203eb7004f62fb01d5de8 Mon Sep 17 00:00:00 2001 From: Helene Durand Date: Wed, 27 Nov 2024 15:02:22 +0100 Subject: [PATCH] MEDIUM: add code generator server_params_runtime and fix no-check-send-proxy server param option --- Makefile | 2 + cmd/server_params_runtime/README.md | 60 ++ cmd/server_params_runtime/args.go | 97 ++ cmd/server_params_runtime/embed.go | 8 + cmd/server_params_runtime/formating.go | 33 + cmd/server_params_runtime/generate.tmpl | 36 + cmd/server_params_runtime/header.tmpl | 22 + cmd/server_params_runtime/main.go | 117 +++ cmd/server_params_runtime/params.go | 1 + .../server_params_prepare_for_runtime.go | 82 ++ config-parser/params/server-options.go | 1 + configuration/configuration.go | 2 +- configuration/server.go | 6 +- configuration/server2.txt | 918 ------------------ configuration/server_template.go | 2 +- models/server_params_prepare_for_runtime.go | 102 ++ runtime/interface.go | 2 + runtime/runtime_client.go | 13 + runtime/servers.go | 6 + 19 files changed, 588 insertions(+), 922 deletions(-) create mode 100644 cmd/server_params_runtime/README.md create mode 100644 cmd/server_params_runtime/args.go create mode 100644 cmd/server_params_runtime/embed.go create mode 100644 cmd/server_params_runtime/formating.go create mode 100644 cmd/server_params_runtime/generate.tmpl create mode 100644 cmd/server_params_runtime/header.tmpl create mode 100644 cmd/server_params_runtime/main.go create mode 100644 cmd/server_params_runtime/params.go create mode 100644 cmd/server_params_runtime/server_params_prepare_for_runtime.go delete mode 100644 configuration/server2.txt create mode 100644 models/server_params_prepare_for_runtime.go diff --git a/Makefile b/Makefile index ad051d47..f7e81a17 100644 --- a/Makefile +++ b/Makefile @@ -30,11 +30,13 @@ spec: .PHONY: models models: gentypes spec swagger-check ./bin/swagger generate model --additional-initialism=FCGI -f ${PROJECT_PATH}/specification/build/haproxy_spec.yaml -r ${PROJECT_PATH}/specification/copyright.txt -m models -t ${PROJECT_PATH} + rm -rf models/server_params_prepare_for_runtime.go rm -rf models/*_compare.go rm -rf models/*_compare_test.go go run cmd/struct_equal_generator/*.go -l ${PROJECT_PATH}/specification/copyright.txt ${PROJECT_PATH}/models go run cmd/struct_tags_checker/*.go ${PROJECT_PATH}/models go run cmd/kubebuilder_marker_generator/*.go ${PROJECT_PATH}/models + go run cmd/server_params_runtime/*.go ${PROJECT_PATH}/models .PHONY: swagger-check swagger-check: diff --git a/cmd/server_params_runtime/README.md b/cmd/server_params_runtime/README.md new file mode 100644 index 00000000..6be6a952 --- /dev/null +++ b/cmd/server_params_runtime/README.md @@ -0,0 +1,60 @@ +# ![HAProxy](../../assets/images/haproxy-weblogo-210x49.png "HAProxy") + +## Generator for: `models/server_params_prepare_for_runtime.go` + +This genetator generates a file that will contains the needed functions to prepare a ServerParams to use in combination with `add server` command on the runtime socket. + +This file will contain 3 functions: + +``` +func (p *ServerParams) prepareForRuntimeDoNotSendDisabledFields() +func (p *ServerParams) prepareForRuntimeDoNotSendEnabledFields() +func (p *ServerParams) PrepareFieldsForRuntimeAddServer() +``` + +They are used for example in Ingress Controller the following way: +``` +params.PrepareFieldsForRuntimeAddServer() +serverParams := configuration.SerializeServerParams(defaultServer.ServerParams) +res := cp_params.ServerOptionsString(serverParams) +``` + +### func (p *ServerParams) prepareForRuntimeDoNotSendDisabledFields() +For example for `Check` that has the values [enabled disabled]. + +- if the value is `enabled` we must send `add server check` +- if the value is `disabled` we must not send `add server no-check` as `no-check` is not allowed on a dynamic server + +`no-check` is the default value. + +The purpose is to set `Check` to "" when the value was `disabled` so the commands sent are: + - `add server check` if value is `enabled` + - `add server` if value is `disabled` + + +### func (p *ServerParams) prepareForRuntimeDoNotSendEnabledFields() +It's just the opposite. + +For example for `NoSslv3` + +- if `enabled` we must send `no-sslv3` +- if `disabled` we must not sent an option + + +### func (p *ServerParams) PrepareFieldsForRuntimeAddServer()` +is just calling both `PrepareForRuntimeDoNotSendDisabledFields` and `PrepareForRuntimeDoNotSendEnabledFields` + + +## WHAT TO DO + +Just fill in `server_params_prepare_for_runtime.go` the map: +- `ServerParamsPrepareForRuntimeMap` + +for each field that has an `// Enum: [enabled disabled]"` +with the correct function to use + +## Ensure that the map is always filled in a field is added into ServerParams: CI check + +The generator checks all fields in ServerParams that have `// Enum: [enabled disabled]"` have an entry in the `ServerParamsPrepareForRuntimeMap`. + +If a new field is added and not declared in `ServerParamsPrepareForRuntimeMap`, the generator fails with an error and this will make the CI fail. diff --git a/cmd/server_params_runtime/args.go b/cmd/server_params_runtime/args.go new file mode 100644 index 00000000..1b26f075 --- /dev/null +++ b/cmd/server_params_runtime/args.go @@ -0,0 +1,97 @@ +package main + +import ( + _ "embed" + "errors" + "fmt" + "io/fs" + "log" + "os" + "path" + "path/filepath" + "strings" +) + +type Args struct { + Licence string + LicencePath string + Directory string + Selector string + Files []string +} + +func (a *Args) Parse() error { //nolint:gocognit + selector, err := os.Getwd() + if err != nil { + log.Panic(err) + } + for i := 1; i < len(os.Args); i++ { + val := os.Args[i] + switch { + case val == "-l": + if i+1 >= len(os.Args) { + return errors.New("missing licence file after -l") + } + a.LicencePath = os.Args[i+1] + i++ + case strings.HasPrefix(val, "--licence="): + a.LicencePath = strings.TrimPrefix(val, "--licence=") + default: + selector = val + } + } + + if a.LicencePath != "" { + var licence []byte + licence, err = os.ReadFile(a.LicencePath) + if err != nil { + return err + } + lines := strings.Split(string(licence), "\n") + var s strings.Builder + for _, line := range lines { + s.WriteString("// ") + s.WriteString(line) + s.WriteString("\n") + } + a.Licence = s.String() + } + isDirectory := false + file, err := os.Open(selector) + if err == nil { + var fileInfo fs.FileInfo + fileInfo, err = file.Stat() + if err == nil { + isDirectory = fileInfo.IsDir() + } + } + if selector == "*" || selector == "." || isDirectory { + err = filepath.Walk(selector, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + + if strings.HasSuffix(path, serverParamFileName) { + fmt.Println(path) //nolint:forbidigo + a.Files = append(a.Files, path) + } + return nil + }) + if err != nil { + log.Panic(err) + } + } else { + a.Files = append(a.Files, selector) + } + a.Selector = selector + if isDirectory { + a.Directory = selector + } else { + a.Directory = path.Dir(selector) + } + + return nil +} diff --git a/cmd/server_params_runtime/embed.go b/cmd/server_params_runtime/embed.go new file mode 100644 index 00000000..a69564e8 --- /dev/null +++ b/cmd/server_params_runtime/embed.go @@ -0,0 +1,8 @@ +package main + +import ( + _ "embed" +) + +//go:embed generate.tmpl +var tmplResetEnumDisabledFields string diff --git a/cmd/server_params_runtime/formating.go b/cmd/server_params_runtime/formating.go new file mode 100644 index 00000000..febc1a90 --- /dev/null +++ b/cmd/server_params_runtime/formating.go @@ -0,0 +1,33 @@ +package main + +import ( + "bytes" + "fmt" + "go/format" + "go/parser" + "go/token" + "os" + + "golang.org/x/tools/imports" +) + +func fmtFile(fileName string) error { + fset := token.NewFileSet() + node, err := parser.ParseFile(fset, fileName, nil, parser.ParseComments) + if err != nil { + return err + } + + // gofmt the modified file + var buf bytes.Buffer + if err = format.Node(&buf, fset, node); err != nil { + return err + } + + formattedCode, err := imports.Process(fileName, buf.Bytes(), nil) + if err != nil { + return fmt.Errorf("failed to perform goimports: %w", err) + } + + return os.WriteFile(fileName, formattedCode, 0o600) +} diff --git a/cmd/server_params_runtime/generate.tmpl b/cmd/server_params_runtime/generate.tmpl new file mode 100644 index 00000000..aa501d4b --- /dev/null +++ b/cmd/server_params_runtime/generate.tmpl @@ -0,0 +1,36 @@ +// Code generated by server_params_runtime; DO NOT EDIT. + +{{ .Licence }} + +package {{ .Package }} + + +func (s ServerParams){{ .PrepareFieldsForRuntimeAddServer }}()* ServerParams { + serverParams := new(ServerParams) + // *defaultServer = p + a, _ := s.MarshalBinary() + _ = serverParams.UnmarshalBinary(a) + + serverParams.{{ .DoNotSendDisabledFieldsFunc }}() + serverParams.{{ .DoNotSendEnabledFieldsFunc }}() + + return serverParams +} + + +func (s *ServerParams){{ .DoNotSendDisabledFieldsFunc }}() { +{{- range .DoNotSendDisabledFields }} + if s.{{ . }} == "disabled" { + s.{{ . }} = "" + } +{{- end }} +} + + +func (s *ServerParams){{ .DoNotSendEnabledFieldsFunc }}() { +{{- range .DoNotSendEnabledFields }} + if s.{{ . }} == "enabled" { + s.{{ . }} = "" + } +{{- end }} +} diff --git a/cmd/server_params_runtime/header.tmpl b/cmd/server_params_runtime/header.tmpl new file mode 100644 index 00000000..804c9bc6 --- /dev/null +++ b/cmd/server_params_runtime/header.tmpl @@ -0,0 +1,22 @@ +// Code generated by server_params_runtime; DO NOT EDIT. + +{{ .Licence }} + +package {{ .Package }} + +import ( + cryptorand "crypto/rand" + "fmt" + "math" + "math/rand" + "strconv" + "testing" + "time" + "bytes" + "encoding/gob" + + "github.com/go-faker/faker/v4" + "github.com/go-openapi/strfmt" + + jsoniter "github.com/json-iterator/go" +) diff --git a/cmd/server_params_runtime/main.go b/cmd/server_params_runtime/main.go new file mode 100644 index 00000000..7df51603 --- /dev/null +++ b/cmd/server_params_runtime/main.go @@ -0,0 +1,117 @@ +package main + +import ( + _ "embed" + "go/token" + "log" + "os" + "strings" + "text/template" + + "github.com/sirkon/dst" + "github.com/sirkon/dst/decorator" +) + +const ( + serverParamFileName = "server_params.go" + commentEnumFieldsToReset = `// Enum: ["enabled","disabled"]` +) + +func main() { + var allEnumFields []string + var packageName string + args := Args{} + err := args.Parse() + if err != nil { + log.Panic(err) + } + for _, fileName := range args.Files { + packageName, allEnumFields = enumFieldsEnabledDisabled(fileName) + if err != nil { + log.Panic(err) + } + + // check that all enum + // Enum: [enabled disabled]" + // fields have an entry in the ServerParamsPrepareForRuntimeMap + missingFields, errMissingField := checkMissingEnumFields(allEnumFields) + if errMissingField != nil { + // Exit with error if any new enum field is found and its behavior is not defined in ServerParamsPrepareForRuntimeMap + log.Printf("There are some fields in models/server_params.go that are Enum[enabled disabled] but missing in `ServerParamsPrepareForRuntimeMap`") + log.Printf(" File location `cmd/server_params_runtime/server_parans_runtime_fields_behavior.go`") + log.Printf("ACTION: Please add them to `ServerParamsPrepareForRuntimeMap`") + log.Printf("Missing fields %v", missingFields) + log.Printf("\t For doc, read cmd/server_params_runtime/README.md") + + os.Exit(1) + } + + // Generate the reset function using the template + tmpl, errTmpl := template.New("generate.tmpl").Parse(tmplResetEnumDisabledFields) + // ParseFiles(path.Join(templatePath)) + if errTmpl != nil { + log.Panic(errTmpl) + } + + generatedFileName := strings.TrimSuffix(fileName, ".go") + "_prepare_for_runtime.go" + _ = os.Truncate(generatedFileName, 0) + file, errFile := os.OpenFile(generatedFileName, os.O_CREATE|os.O_WRONLY, 0o600) + if errFile != nil { + log.Panic(errFile) + } + defer file.Close() + + doNotSendDisabledFields := listEmptyDisabledFields(allEnumFields) + doNotSendEnabledFields := listEmtpyEnabledFields(allEnumFields) + + errTmpl = tmpl.Execute(file, map[string]interface{}{ + "PrepareFieldsForRuntimeAddServer": FuncPrepareFieldsForRuntimeAddServer, + "DoNotSendDisabledFields": doNotSendDisabledFields, + "DoNotSendDisabledFieldsFunc": FuncDoNotSendDisabledFields, + "DoNotSendEnabledFields": doNotSendEnabledFields, + "DoNotSendEnabledFieldsFunc": FuncDoNotSendEnabledFields, + "Package": packageName, + "Licence": args.Licence, + }) + if errTmpl != nil { + log.Panic(errTmpl) + } + + errFmt := fmtFile(generatedFileName) + if errFmt != nil { + log.Panic(errFmt) + } + } +} + +func enumFieldsEnabledDisabled(filename string) (string, []string) { //nolint:gocognit + var fieldsWithComment []string + f, err := decorator.ParseFile(token.NewFileSet(), filename, nil, 0) + if err != nil { + log.Fatal(err) + } + + for _, decl := range f.Decls { + if genDecl, ok := decl.(*dst.GenDecl); ok && genDecl.Tok == token.TYPE { + for _, spec := range genDecl.Specs { + if typeSpec, ok := spec.(*dst.TypeSpec); ok { + if structType, ok := typeSpec.Type.(*dst.StructType); ok { + for _, field := range structType.Fields.List { + comments := field.Decorations().Start.All() + + for _, comment := range comments { + if comment == commentEnumFieldsToReset { + // Add field name to the list + if len(field.Names) > 0 { + fieldsWithComment = append(fieldsWithComment, field.Names[0].Name) + } + } + } + } + } + } + } + } + } + return f.Name.Name, fieldsWithComment +} diff --git a/cmd/server_params_runtime/params.go b/cmd/server_params_runtime/params.go new file mode 100644 index 00000000..06ab7d0f --- /dev/null +++ b/cmd/server_params_runtime/params.go @@ -0,0 +1 @@ +package main diff --git a/cmd/server_params_runtime/server_params_prepare_for_runtime.go b/cmd/server_params_runtime/server_params_prepare_for_runtime.go new file mode 100644 index 00000000..977942af --- /dev/null +++ b/cmd/server_params_runtime/server_params_prepare_for_runtime.go @@ -0,0 +1,82 @@ +package main + +import ( + "errors" +) + +const ( + FuncDoNotSendDisabledFields = "prepareForRuntimeDoNotSendDisabledFields" + FuncDoNotSendEnabledFields = "prepareForRuntimeDoNotSendEnabledFields" + FuncPrepareFieldsForRuntimeAddServer = "PrepareFieldsForRuntimeAddServer" +) + +var ServerParamsPrepareForRuntimeMap = map[string]string{ //nolint:gochecknoglobals + "AgentCheck": FuncDoNotSendDisabledFields, + "Backup": FuncDoNotSendDisabledFields, + "Check": FuncDoNotSendDisabledFields, + "CheckSendProxy": FuncDoNotSendDisabledFields, + "CheckSsl": FuncDoNotSendDisabledFields, + "CheckViaSocks4": FuncDoNotSendDisabledFields, + "ForceSslv3": FuncDoNotSendDisabledFields, + "ForceTlsv10": FuncDoNotSendDisabledFields, + "ForceTlsv11": FuncDoNotSendDisabledFields, + "ForceTlsv12": FuncDoNotSendDisabledFields, + "ForceTlsv13": FuncDoNotSendDisabledFields, + "Maintenance": FuncDoNotSendDisabledFields, + "NoSslv3": FuncDoNotSendEnabledFields, + "NoTlsv10": FuncDoNotSendEnabledFields, + "NoTlsv11": FuncDoNotSendEnabledFields, + "NoTlsv12": FuncDoNotSendEnabledFields, + "NoTlsv13": FuncDoNotSendEnabledFields, + "NoVerifyhost": FuncDoNotSendEnabledFields, + "SendProxy": FuncDoNotSendDisabledFields, + "SendProxyV2": FuncDoNotSendDisabledFields, + "SendProxyV2Ssl": FuncDoNotSendDisabledFields, + "SendProxyV2SslCn": FuncDoNotSendDisabledFields, + "Ssl": FuncDoNotSendDisabledFields, + "SslReuse": FuncDoNotSendDisabledFields, + "Stick": FuncDoNotSendDisabledFields, + "Tfo": FuncDoNotSendDisabledFields, + "TLSTickets": FuncDoNotSendDisabledFields, +} + +func checkMissingEnumFields(allFields []string) ([]string, error) { + missingFields := []string{} + for _, field := range allFields { + // check that all enum + // Enum: [enabled disabled]" + // fields have an entry in the ServerParamsPrepareForRuntimeMap + f, ok := ServerParamsPrepareForRuntimeMap[field] + if !ok || (f != FuncDoNotSendEnabledFields && f != FuncDoNotSendDisabledFields) { + missingFields = append(missingFields, field) + } + } + if len(missingFields) > 0 { + return missingFields, errors.New("missing enum fields") + } + return missingFields, nil +} + +func listEmptyDisabledFields(allFields []string) []string { + var emptyDisabledFields []string + for _, field := range allFields { + if f, ok := ServerParamsPrepareForRuntimeMap[field]; ok { + if f == FuncDoNotSendDisabledFields { + emptyDisabledFields = append(emptyDisabledFields, field) + } + } + } + return emptyDisabledFields +} + +func listEmtpyEnabledFields(allFields []string) []string { + var emptyEnabledFields []string + for _, field := range allFields { + if f, ok := ServerParamsPrepareForRuntimeMap[field]; ok { + if f == FuncDoNotSendEnabledFields { + emptyEnabledFields = append(emptyEnabledFields, field) + } + } + } + return emptyEnabledFields +} diff --git a/config-parser/params/server-options.go b/config-parser/params/server-options.go index b1deb34c..b6f99e0c 100644 --- a/config-parser/params/server-options.go +++ b/config-parser/params/server-options.go @@ -175,6 +175,7 @@ var serverOptionFactoryMethods = map[string]func() ServerOption{ //nolint:gochec "no-agent-check": func() ServerOption { return &ServerOptionWord{Name: "no-agent-check"} }, "no-backup": func() ServerOption { return &ServerOptionWord{Name: "no-backup"} }, "no-check": func() ServerOption { return &ServerOptionWord{Name: "no-check"} }, + "no-check-send-proxy": func() ServerOption { return &ServerOptionWord{Name: "no-check-send-proxy"} }, "no-check-ssl": func() ServerOption { return &ServerOptionWord{Name: "no-check-ssl"} }, "no-send-proxy": func() ServerOption { return &ServerOptionWord{Name: "no-send-proxy"} }, "no-send-proxy-v2": func() ServerOption { return &ServerOptionWord{Name: "no-send-proxy-v2"} }, diff --git a/configuration/configuration.go b/configuration/configuration.go index 5e481a25..dc448d82 100644 --- a/configuration/configuration.go +++ b/configuration/configuration.go @@ -2137,7 +2137,7 @@ func (s *SectionObject) defaultServer(field reflect.Value) error { return misc.CreateTypeAssertError("default-server") } dServers := []types.DefaultServer{{}} - dServers[0].Params = serializeServerParams(ds.ServerParams, s.Options) + dServers[0].Params = SerializeServerParams(ds.ServerParams, s.Options) if err := s.set("default-server", dServers); err != nil { return err } diff --git a/configuration/server.go b/configuration/server.go index 2e05acac..5eb1bd46 100644 --- a/configuration/server.go +++ b/configuration/server.go @@ -277,6 +277,8 @@ func parseServerParams(serverOptions []params.ServerOption, serverParams *models serverParams.Check = "disabled" case "check-send-proxy": serverParams.CheckSendProxy = "enabled" + case "no-check-send-proxy": + serverParams.CheckSendProxy = "disabled" case "check-ssl": serverParams.CheckSsl = "enabled" case "no-check-ssl": @@ -555,7 +557,7 @@ func ParseServer(ondiskServer types.Server) *models.Server { return s } -func serializeServerParams(s models.ServerParams, opt *options.ConfigurationOptions) []params.ServerOption { //nolint:gocognit,gocyclo,cyclop,cyclop,maintidx +func SerializeServerParams(s models.ServerParams, opt *options.ConfigurationOptions) []params.ServerOption { //nolint:gocognit,gocyclo,cyclop,cyclop,maintidx var options []params.ServerOption // ServerOptionWord if s.AgentCheck == "enabled" { @@ -894,7 +896,7 @@ func SerializeServer(s models.Server, opt *options.ConfigurationOptions) types.S } comment, _ := serializeMetadata(s.Metadata) server.Comment = comment - server.Params = serializeServerParams(s.ServerParams, opt) + server.Params = SerializeServerParams(s.ServerParams, opt) if s.ID != nil { server.Params = append(server.Params, ¶ms.ServerOptionValue{Name: "id", Value: strconv.FormatInt(*s.ID, 10)}) } diff --git a/configuration/server2.txt b/configuration/server2.txt deleted file mode 100644 index bd6ac265..00000000 --- a/configuration/server2.txt +++ /dev/null @@ -1,918 +0,0 @@ -// Copyright 2019 HAProxy Technologies -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package configuration - -import ( - "errors" - "fmt" - "strconv" - "strings" - - "github.com/go-openapi/strfmt" - parser "github.com/haproxytech/client-native/v6/config-parser" - parser_errors "github.com/haproxytech/client-native/v6/config-parser/errors" - "github.com/haproxytech/client-native/v6/config-parser/params" - "github.com/haproxytech/client-native/v6/config-parser/types" - - "github.com/haproxytech/client-native/v6/configuration/options" - "github.com/haproxytech/client-native/v6/misc" - "github.com/haproxytech/client-native/v6/models" -) - -type Server interface { - GetServers(parentType string, parentName string, transactionID string) (int64, models.Servers, error) - GetServer(name string, parentType string, parentName string, transactionID string) (int64, *models.Server, error) - DeleteServer(name string, parentType string, parentName string, transactionID string, version int64) error - CreateServer(parentType string, parentName string, data *models.Server, transactionID string, version int64) error - EditServer(name string, parentType string, parentName string, data *models.Server, transactionID string, version int64) error - GetServerSwitchingRules(backend string, transactionID string) (int64, models.ServerSwitchingRules, error) - GetServerSwitchingRule(id int64, backend string, transactionID string) (int64, *models.ServerSwitchingRule, error) - DeleteServerSwitchingRule(id int64, backend string, transactionID string, version int64) error - CreateServerSwitchingRule(id int64, backend string, data *models.ServerSwitchingRule, transactionID string, version int64) error - EditServerSwitchingRule(id int64, backend string, data *models.ServerSwitchingRule, transactionID string, version int64) error - ReplaceServerSwitchingRules(backend string, data models.ServerSwitchingRules, transactionID string, version int64) error -} - -// GetServers returns configuration version and an array of -// configured servers in the specified backend. Returns error on fail. -func (c *client) GetServers(parentType string, parentName string, transactionID string) (int64, models.Servers, error) { - p, err := c.GetParser(transactionID) - if err != nil { - return 0, nil, err - } - - v, err := c.GetVersion(transactionID) - if err != nil { - return 0, nil, err - } - - servers, err := ParseServers(parentType, parentName, p) - if err != nil { - return v, nil, c.HandleError("", parentType, parentName, "", false, err) - } - - return v, servers, nil -} - -// GetServer returns configuration version and a requested server -// in the specified backend. Returns error on fail or if server does not exist. -func (c *client) GetServer(name string, parentType string, parentName string, transactionID string) (int64, *models.Server, error) { - p, err := c.GetParser(transactionID) - if err != nil { - return 0, nil, err - } - - v, err := c.GetVersion(transactionID) - if err != nil { - return 0, nil, err - } - - server, _ := GetServerByName(name, parentType, parentName, p) - if server == nil { - return v, nil, NewConfError(ErrObjectDoesNotExist, fmt.Sprintf("server %s does not exist in %s %s", name, parentName, parentType)) - } - - return v, server, nil -} - -// DeleteServer deletes a server in configuration. One of version or transactionID is -// mandatory. Returns error on fail, nil on success. -func (c *client) DeleteServer(name string, parentType string, parentName string, transactionID string, version int64) error { - p, t, err := c.loadDataForChange(transactionID, version) - if err != nil { - return err - } - - server, i := GetServerByName(name, parentType, parentName, p) - if server == nil { - e := NewConfError(ErrObjectDoesNotExist, fmt.Sprintf("server %s does not exist in %s %s", name, parentName, parentType)) - return c.HandleError(name, parentType, parentName, t, transactionID == "", e) - } - - if err := p.Delete(sectionType(parentType), parentName, "server", i); err != nil { - return c.HandleError(name, parentType, parentName, t, transactionID == "", err) - } - - return c.SaveData(p, t, transactionID == "") -} - -// CreateServer creates a server in configuration. One of version or transactionID is -// mandatory. Returns error on fail, nil on success. -func (c *client) CreateServer(parentType string, parentName string, data *models.Server, transactionID string, version int64) error { - if c.UseModelsValidation { - validationErr := data.Validate(strfmt.Default) - if validationErr != nil { - return NewConfError(ErrValidationError, validationErr.Error()) - } - } - p, t, err := c.loadDataForChange(transactionID, version) - if err != nil { - return err - } - - server, _ := GetServerByName(data.Name, parentType, parentName, p) - if server != nil { - e := NewConfError(ErrObjectAlreadyExists, fmt.Sprintf("server %s already exists in %s %s", data.Name, parentName, parentType)) - return c.HandleError(data.Name, parentType, parentName, t, transactionID == "", e) - } - - if err := p.Insert(sectionType(parentType), parentName, "server", SerializeServer(*data, &c.ConfigurationOptions), -1); err != nil { - return c.HandleError(data.Name, parentType, parentName, t, transactionID == "", err) - } - - return c.SaveData(p, t, transactionID == "") -} - -// EditServer edits a server in configuration. One of version or transactionID is -// mandatory. Returns error on fail, nil on success. -func (c *client) EditServer(name string, parentType string, parentName string, data *models.Server, transactionID string, version int64) error { - if c.UseModelsValidation { - validationErr := data.Validate(strfmt.Default) - if validationErr != nil { - return NewConfError(ErrValidationError, validationErr.Error()) - } - } - p, t, err := c.loadDataForChange(transactionID, version) - if err != nil { - return err - } - - server, i := GetServerByName(name, parentType, parentName, p) - if server == nil { - e := NewConfError(ErrObjectDoesNotExist, fmt.Sprintf("server %v does not exist in %s %s", name, parentName, parentType)) - return c.HandleError(data.Name, parentType, parentName, t, transactionID == "", e) - } - - if err := p.Set(sectionType(parentType), parentName, "server", SerializeServer(*data, &c.ConfigurationOptions), i); err != nil { - return c.HandleError(data.Name, parentType, parentName, t, transactionID == "", err) - } - - return c.SaveData(p, t, transactionID == "") -} - -func ParseServers(parentType string, parentName string, p parser.Parser) (models.Servers, error) { - var servers models.Servers - - data, err := p.Get(sectionType(parentType), parentName, "server", false) - if err != nil { - if errors.Is(err, parser_errors.ErrFetch) { - return servers, nil - } - return nil, err - } - - ondiskServers, ok := data.([]types.Server) - if !ok { - return nil, misc.CreateTypeAssertError("server") - } - for _, ondiskServer := range ondiskServers { - s := ParseServer(ondiskServer) - if s != nil { - servers = append(servers, s) - } - } - return servers, nil -} - -func ParseAddress(address string) (string, *int64) { - var port *int64 - if strings.HasPrefix(address, "[") && strings.ContainsRune(address, ']') { // IPv6 with port [2001:0DB8:0000:0000:0000:0000:1428:57ab]:80 - split := strings.Split(address, "]") - split[0] = strings.TrimPrefix(split[0], "[") - if len(split) == 2 { // has port - split[1] = strings.ReplaceAll(split[1], ":", "") - p, err := strconv.ParseInt(split[1], 10, 64) - if err == nil { - port = &p - } - } - return split[0], port - } - - switch c := strings.Count(address, ":"); { - case c == 1: // IPv4 with port 127.0.0.1:80 - split := strings.Split(address, ":") - p, err := strconv.ParseInt(split[1], 10, 64) - if err == nil { - port = &p - } - return split[0], port - case c > 1: // IPv6 2001:0DB8:0000:0000:0000:0000:1428:57ab - // Assume the last element is the port number. - // This is an imperfect solution, which is why dataplaneapi - // adds brackets to IPv6 when it can. - idx := strings.LastIndex(address, ":") - p, err := strconv.ParseInt(address[idx+1:], 10, 16) - if err != nil { - return address, nil - } - return address[:idx], &p - case c == 0: - return address, nil // IPv4 or socket address - default: - return "", nil - } -} - -func parseServerParams(serverOptions []params.ServerOption, serverParams *models.ServerParams) { //nolint:gocognit,gocyclo,cyclop,cyclop,maintidx - var sourceArgs []string - for _, p := range serverOptions { - switch v := p.(type) { - case *params.ServerOptionWord: - switch v.Name { - case "agent-check": - serverParams.AgentCheck = "enabled" - case "no-agent-check": - serverParams.AgentCheck = "disabled" - case "allow-0rtt": - serverParams.Allow0rtt = true - case "backup": - serverParams.Backup = "enabled" - case "no-backup": - serverParams.Backup = "disabled" - case "check": - serverParams.Check = "enabled" - case "no-check": - serverParams.Check = "disabled" - case "check-send-proxy": - serverParams.CheckSendProxy = "enabled" - case "check-ssl": - serverParams.CheckSsl = "enabled" - case "no-check-ssl": - serverParams.CheckSsl = "disabled" - case "check-via-socks4": - serverParams.CheckViaSocks4 = "enabled" - case "disabled": - serverParams.Maintenance = "enabled" - case "enabled": - serverParams.Maintenance = "disabled" - case "force-sslv3": - serverParams.ForceSslv3 = "enabled" - case "force-tlsv10": - serverParams.ForceTlsv10 = "enabled" - case "no-sslv3": - serverParams.NoSslv3 = "enabled" - case "no-tlsv10": - serverParams.ForceTlsv10 = "disabled" - case "force-tlsv11": - serverParams.ForceTlsv11 = "enabled" - case "no-tlsv11": - serverParams.ForceTlsv11 = "disabled" - case "force-tlsv12": - serverParams.ForceTlsv12 = "enabled" - case "no-tlsv12": - serverParams.ForceTlsv12 = "disabled" - case "force-tlsv13": - serverParams.ForceTlsv13 = "enabled" - case "no-tlsv13": - serverParams.ForceTlsv13 = "disabled" - case "send-proxy": - serverParams.SendProxy = "enabled" - case "no-send-proxy": - serverParams.SendProxy = "disabled" - case "send-proxy-v2": - serverParams.SendProxyV2 = "enabled" - case "no-send-proxy-v2": - serverParams.SendProxyV2 = "disabled" - case "send-proxy-v2-ssl": - serverParams.SendProxyV2Ssl = "enabled" - case "no-send-proxy-v2-ssl": - serverParams.SendProxyV2Ssl = "disabled" - case "send-proxy-v2-ssl-cn": - serverParams.SendProxyV2SslCn = "enabled" - case "no-send-proxy-v2-ssl-cn": - serverParams.SendProxyV2SslCn = "disabled" - case "ssl": - serverParams.Ssl = "enabled" - case "no-ssl": - serverParams.Ssl = "disabled" - case "ssl-reuse": - serverParams.SslReuse = "enabled" - case "no-ssl-reuse": - serverParams.SslReuse = "disabled" - case "tls-tickets": - serverParams.TLSTickets = "enabled" - case "no-tls-tickets": - serverParams.TLSTickets = "disabled" - case "tfo": - serverParams.Tfo = "enabled" - case "no-tfo": - serverParams.Tfo = "disabled" - case "stick": - serverParams.Stick = "enabled" - case "non-stick": - serverParams.Stick = "disabled" - } - case *params.ServerOptionValue: - switch v.Name { - case "agent-send": - serverParams.AgentSend = v.Value - case "agent-inter": - serverParams.AgentInter = misc.ParseTimeout(v.Value) - case "agent-addr": - serverParams.AgentAddr = v.Value - case "agent-port": - p, err := strconv.ParseInt(v.Value, 10, 64) - if err == nil && p != 0 { - serverParams.AgentPort = &p - } - case "alpn": - serverParams.Alpn = v.Value - case "ca-file": - serverParams.SslCafile = v.Value - case "check-alpn": - serverParams.CheckAlpn = v.Value - case "check-proto": - serverParams.CheckProto = v.Value - case "check-sni": - serverParams.CheckSni = v.Value - case "ciphers": - serverParams.Ciphers = v.Value - case "ciphersuites": - serverParams.Ciphersuites = v.Value - case "client-sigalgs": - serverParams.ClientSigalgs = v.Value - case "cookie": - serverParams.Cookie = v.Value - case "crl-file": - serverParams.CrlFile = v.Value - case "crt": - serverParams.SslCertificate = v.Value - case "curves": - serverParams.Curves = v.Value - case "error-limit": - c, err := strconv.ParseInt(v.Value, 10, 64) - if err == nil { - serverParams.ErrorLimit = c - } - case "fall": - serverParams.Fall = misc.ParseTimeout(v.Value) - case "guid": - serverParams.GUID = v.Value - case "init-addr": - serverParams.InitAddr = &v.Value - case "inter": - serverParams.Inter = misc.ParseTimeout(v.Value) - case "fastinter": - serverParams.Fastinter = misc.ParseTimeout(v.Value) - case "downinter": - serverParams.Downinter = misc.ParseTimeout(v.Value) - case "log-bufsize": - l, err := strconv.ParseInt(v.Value, 10, 64) - if err == nil { - serverParams.LogBufsize = &l - } - case "log-proto": - serverParams.LogProto = v.Value - case "maxconn": - m, err := strconv.ParseInt(v.Value, 10, 64) - if err == nil { - serverParams.Maxconn = &m - } - case "maxqueue": - m, err := strconv.ParseInt(v.Value, 10, 64) - if err == nil { - serverParams.Maxqueue = &m - } - case "max-reuse": - c, err := strconv.ParseInt(v.Value, 10, 64) - if err == nil { - serverParams.MaxReuse = &c - } - case "minconn": - m, err := strconv.ParseInt(v.Value, 10, 64) - if err == nil { - serverParams.Minconn = &m - } - case "namespace": - serverParams.Namespace = v.Value - case "npn": - serverParams.Npn = v.Value - case "observe": - serverParams.Observe = v.Value - case "on-error": - serverParams.OnError = v.Value - case "on-marked-down": - serverParams.OnMarkedDown = v.Value - case "on-marked-up": - serverParams.OnMarkedUp = v.Value - case "pool-low-conn": - m, err := strconv.ParseInt(v.Value, 10, 64) - if err == nil { - serverParams.PoolLowConn = &m - } - case "pool-max-conn": - m, err := strconv.ParseInt(v.Value, 10, 64) - if err == nil { - serverParams.PoolMaxConn = &m - } - case "pool-purge-delay": - serverParams.PoolPurgeDelay = misc.ParseTimeout(v.Value) - case "addr": - serverParams.HealthCheckAddress = v.Value - case "port": - p, err := strconv.ParseInt(v.Value, 10, 64) - if err == nil { - serverParams.HealthCheckPort = &p - } - case "proto": - serverParams.Proto = v.Value - case "redir": - serverParams.Redir = v.Value - case "rise": - serverParams.Rise = misc.ParseTimeout(v.Value) - case "resolve-opts": - serverParams.ResolveOpts = v.Value - case "resolve-prefer": - serverParams.ResolvePrefer = v.Value - case "resolve-net": - serverParams.ResolveNet = v.Value - case "resolvers": - serverParams.Resolvers = v.Value - case "proxy-v2-options": - serverParams.ProxyV2Options = strings.Split(v.Value, ",") - case "shard": - if v.Value != "" { - p, err := strconv.ParseInt(v.Value, 10, 64) - if err == nil { - serverParams.Shard = p - } - } - case "sigalgs": - serverParams.Sigalgs = v.Value - case "slowstart": - serverParams.Slowstart = misc.ParseTimeout(v.Value) - case "sni": - serverParams.Sni = v.Value - case "source": - serverParams.Source = v.Value - case "usesrc", "interface": - sourceArgs = append(sourceArgs, v.Name+" "+v.Value) - case "ssl-max-ver": - serverParams.SslMaxVer = v.Value - case "ssl-min-ver": - serverParams.SslMinVer = v.Value - case "socks4": - serverParams.Socks4 = v.Value - case "tcp-ut": - serverParams.TCPUt = misc.ParseTimeout(v.Value) - case "track": - serverParams.Track = v.Value - case "verify": - serverParams.Verify = v.Value - case "verifyhost": - serverParams.Verifyhost = v.Value - case "weight": - w, err := strconv.ParseInt(v.Value, 10, 64) - if err == nil { - serverParams.Weight = &w - } - case "ws": - serverParams.Ws = v.Value - case "pool-conn-name": - serverParams.PoolConnName = v.Value - case "hash-key": - serverParams.HashKey = v.Value - } - case *params.ServerOptionIDValue: - if v.Name == "set-proxy-v2-tlv-fmt" { - serverParams.SetProxyV2TlvFmt = &models.ServerParamsSetProxyV2TlvFmt{ - ID: &v.ID, - Value: &v.Value, - } - } - } - } - // Add corresponding arguments to the source option. - if serverParams.Source != "" && len(sourceArgs) > 0 { - serverParams.Source += " " + strings.Join(sourceArgs, " ") - } -} - -func ParseServer(ondiskServer types.Server) *models.Server { - s := &models.Server{ - Name: ondiskServer.Name, - } - address, port := ParseAddress(ondiskServer.Address) - if address == "" { - return nil - } - s.Address = address - s.Port = port - s.Metadata = parseMetadata(ondiskServer.Comment) - for _, p := range ondiskServer.Params { - if v, ok := p.(*params.ServerOptionValue); ok { - if v.Name == "id" { - p, err := strconv.ParseInt(v.Value, 10, 64) - if err == nil { - s.ID = &p - } - } - } - } - parseServerParams(ondiskServer.Params, &s.ServerParams) - return s -} - -func serializeServerParams(s models.ServerParams, opt *options.ConfigurationOptions) []params.ServerOption { //nolint:gocognit,gocyclo,cyclop,cyclop,maintidx - var options []params.ServerOption - // ServerOptionWord - if s.AgentCheck == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "agent-check"}) - } - if s.AgentCheck == "disabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "no-agent-check"}) - } - if s.Allow0rtt { - options = append(options, ¶ms.ServerOptionWord{Name: "allow-0rtt"}) - } - if s.Backup == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "backup"}) - } - if s.Backup == "disabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "no-backup"}) - } - if s.Check == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "check"}) - } - if s.Check == "disabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "no-check"}) - } - if s.CheckSendProxy == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "check-send-proxy"}) - } - if s.CheckSendProxy == "disabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "no-check-send-proxy"}) - } - if s.CheckSsl == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "check-ssl"}) - } - if s.CheckSsl == "disabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "no-check-ssl"}) - } - if s.CheckViaSocks4 == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "check-via-socks4"}) - } - if s.ForceSslv3 == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "force-sslv3"}) - } - if s.NoSslv3 == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "no-sslv3"}) - } - if s.ForceTlsv10 == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "force-tlsv10"}) - } - if s.ForceTlsv10 == "disabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "no-tlsv10"}) - } - if s.ForceTlsv11 == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "force-tlsv11"}) - } - if s.ForceTlsv11 == "disabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "no-tlsv11"}) - } - if s.ForceTlsv12 == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "force-tlsv12"}) - } - if s.ForceTlsv12 == "disabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "no-tlsv12"}) - } - if s.ForceTlsv13 == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "force-tlsv13"}) - } - if s.ForceTlsv13 == "disabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "no-tlsv13"}) - } - if s.Maintenance == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "disabled"}) - } - if s.Maintenance == "disabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "enabled"}) - } - if s.SendProxy == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "send-proxy"}) - } - if s.SendProxy == "disabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "no-send-proxy"}) - } - if s.SendProxyV2 == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "send-proxy-v2"}) - } - if s.SendProxyV2 == "disabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "no-send-proxy-v2"}) - } - if s.SendProxyV2Ssl == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "send-proxy-v2-ssl"}) - } - if s.SendProxyV2Ssl == "disabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "no-send-proxy-v2-ssl"}) - } - if s.SendProxyV2SslCn == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "send-proxy-v2-ssl-cn"}) - } - if s.SendProxyV2SslCn == "disabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "no-send-proxy-v2-ssl-cn"}) - } - if s.Ssl == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "ssl"}) - } - if s.Ssl == "disabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "no-ssl"}) - } - if s.SslReuse == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "ssl-reuse"}) - } - if s.SslReuse == "disabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "no-ssl-reuse"}) - } - if s.TLSTickets == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "tls-tickets"}) - } - if s.TLSTickets == "disabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "no-tls-tickets"}) - } - if s.Stick == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "stick"}) - } - if s.Stick == "disabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "non-stick"}) - } - if s.Tfo == "enabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "tfo"}) - } - if s.Tfo == "disabled" { - options = append(options, ¶ms.ServerOptionWord{Name: "no-tfo"}) - } - if s.AgentSend != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "agent-send", Value: s.AgentSend}) - } - if s.AgentInter != nil { - options = append(options, ¶ms.ServerOptionValue{Name: "agent-inter", Value: misc.SerializeTime(*s.AgentInter, opt.PreferredTimeSuffix)}) - } - if s.AgentAddr != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "agent-addr", Value: s.AgentAddr}) - } - if s.AgentPort != nil { - options = append(options, ¶ms.ServerOptionValue{Name: "agent-port", Value: strconv.FormatInt(*s.AgentPort, 10)}) - } - if s.Alpn != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "alpn", Value: s.Alpn}) - } - if s.SslCafile != "" { // ca-file - options = append(options, ¶ms.ServerOptionValue{Name: "ca-file", Value: s.SslCafile}) - } - if s.CheckAlpn != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "check-alpn", Value: s.CheckAlpn}) - } - if s.CheckProto != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "check-proto", Value: s.CheckProto}) - } - if s.CheckSni != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "check-sni", Value: s.CheckSni}) - } - if s.Ciphers != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "ciphers", Value: s.Ciphers}) - } - if s.Ciphersuites != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "ciphersuites", Value: s.Ciphersuites}) - } - if s.ClientSigalgs != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "client-sigalgs", Value: s.ClientSigalgs}) - } - if s.Cookie != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "cookie", Value: s.Cookie}) - } - if s.CrlFile != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "crl-file", Value: s.CrlFile}) - } - if s.Curves != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "curves", Value: s.Curves}) - } - if s.SslCertificate != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "crt", Value: s.SslCertificate}) - } - if s.ErrorLimit != 0 { - options = append(options, ¶ms.ServerOptionValue{Name: "error-limit", Value: strconv.FormatInt(s.ErrorLimit, 10)}) - } - if s.GUID != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "guid", Value: s.GUID}) - } - if s.Fall != nil { - options = append(options, ¶ms.ServerOptionValue{Name: "fall", Value: strconv.FormatInt(*s.Fall, 10)}) - } - if s.InitAddr != nil { - options = append(options, ¶ms.ServerOptionValue{Name: "init-addr", Value: *s.InitAddr}) - } - if s.Inter != nil { - options = append(options, ¶ms.ServerOptionValue{Name: "inter", Value: misc.SerializeTime(*s.Inter, opt.PreferredTimeSuffix)}) - } - if s.Fastinter != nil { - options = append(options, ¶ms.ServerOptionValue{Name: "fastinter", Value: misc.SerializeTime(*s.Fastinter, opt.PreferredTimeSuffix)}) - } - if s.Downinter != nil { - options = append(options, ¶ms.ServerOptionValue{Name: "downinter", Value: misc.SerializeTime(*s.Downinter, opt.PreferredTimeSuffix)}) - } - if s.LogBufsize != nil { - options = append(options, ¶ms.ServerOptionValue{Name: "log-bufsize", Value: strconv.FormatInt(*s.LogBufsize, 10)}) - } - if s.LogProto != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "log-proto", Value: s.LogProto}) - } - if s.Maxconn != nil { - options = append(options, ¶ms.ServerOptionValue{Name: "maxconn", Value: strconv.FormatInt(*s.Maxconn, 10)}) - } - if s.Maxqueue != nil { - options = append(options, ¶ms.ServerOptionValue{Name: "maxqueue", Value: strconv.FormatInt(*s.Maxqueue, 10)}) - } - if s.MaxReuse != nil { - options = append(options, ¶ms.ServerOptionValue{Name: "max-reuse", Value: strconv.FormatInt(*s.MaxReuse, 10)}) - } - if s.Minconn != nil { - options = append(options, ¶ms.ServerOptionValue{Name: "minconn", Value: strconv.FormatInt(*s.Minconn, 10)}) - } - if s.Namespace != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "namespace", Value: s.Namespace}) - } - if s.Npn != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "npn", Value: s.Npn}) - } - if s.Observe != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "observe", Value: s.Observe}) - } - if s.OnError != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "on-error", Value: s.OnError}) - } - if s.OnMarkedDown != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "on-marked-down", Value: s.OnMarkedDown}) - } - if s.OnMarkedUp != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "on-marked-up", Value: s.OnMarkedUp}) - } - if s.PoolLowConn != nil { - options = append(options, ¶ms.ServerOptionValue{Name: "pool-low-conn", Value: strconv.FormatInt(*s.PoolLowConn, 10)}) - } - if s.PoolMaxConn != nil { - options = append(options, ¶ms.ServerOptionValue{Name: "pool-max-conn", Value: strconv.FormatInt(*s.PoolMaxConn, 10)}) - } - if s.PoolPurgeDelay != nil { - options = append(options, ¶ms.ServerOptionValue{Name: "pool-purge-delay", Value: misc.SerializeTime(*s.PoolPurgeDelay, opt.PreferredTimeSuffix)}) - } - if s.HealthCheckAddress != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "addr", Value: s.HealthCheckAddress}) - } - if s.HealthCheckPort != nil { - options = append(options, ¶ms.ServerOptionValue{Name: "port", Value: strconv.FormatInt(*s.HealthCheckPort, 10)}) - } - if s.Proto != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "proto", Value: s.Proto}) - } - if s.Redir != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "redir", Value: s.Redir}) - } - if s.Rise != nil { - options = append(options, ¶ms.ServerOptionValue{Name: "rise", Value: strconv.FormatInt(*s.Rise, 10)}) - } - if s.ResolveOpts != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "resolve-opts", Value: s.ResolveOpts}) - } - if s.ResolvePrefer != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "resolve-prefer", Value: s.ResolvePrefer}) - } - if s.ResolveNet != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "resolve-net", Value: s.ResolveNet}) - } - if s.Resolvers != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "resolvers", Value: s.Resolvers}) - } - if len(s.ProxyV2Options) > 0 { - options = append(options, ¶ms.ServerOptionValue{Name: "proxy-v2-options", Value: strings.Join(s.ProxyV2Options, ",")}) - } - if s.Shard != 0 { - options = append(options, ¶ms.ServerOptionValue{Name: "shard", Value: strconv.FormatInt(s.Shard, 10)}) - } - if s.Sigalgs != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "sigalgs", Value: s.Sigalgs}) - } - if s.Slowstart != nil { - options = append(options, ¶ms.ServerOptionValue{Name: "slowstart", Value: misc.SerializeTime(*s.Slowstart, opt.PreferredTimeSuffix)}) - } - if s.Sni != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "sni", Value: s.Sni}) - } - if s.Source != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "source", Value: s.Source}) - } - if s.SslMaxVer != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "ssl-max-ver", Value: s.SslMaxVer}) - } - if s.SslMinVer != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "ssl-min-ver", Value: s.SslMinVer}) - } - if s.Socks4 != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "socks4", Value: s.Socks4}) - } - if s.SetProxyV2TlvFmt != nil && s.SetProxyV2TlvFmt.ID != nil && s.SetProxyV2TlvFmt.Value != nil { - options = append(options, ¶ms.ServerOptionIDValue{Name: "set-proxy-v2-tlv-fmt", ID: *s.SetProxyV2TlvFmt.ID, Value: *s.SetProxyV2TlvFmt.Value}) - } - if s.TCPUt != nil { - options = append(options, ¶ms.ServerOptionValue{Name: "tcp-ut", Value: misc.SerializeTime(*s.TCPUt, opt.PreferredTimeSuffix)}) - } - if s.Track != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "track", Value: s.Track}) - } - if s.Verify != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "verify", Value: s.Verify}) - } - if s.Verifyhost != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "verifyhost", Value: s.Verifyhost}) - } - if s.Weight != nil { - options = append(options, ¶ms.ServerOptionValue{Name: "weight", Value: strconv.FormatInt(*s.Weight, 10)}) - } - if s.Ws != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "ws", Value: s.Ws}) - } - if s.PoolConnName != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "pool-conn-name", Value: s.PoolConnName}) - } - if s.HashKey != "" { - options = append(options, ¶ms.ServerOptionValue{Name: "hash-key", Value: s.HashKey}) - } - return options -} - -func SerializeServer(s models.Server, opt *options.ConfigurationOptions) types.Server { - server := types.Server{ - Name: s.Name, - Params: []params.ServerOption{}, - } - if s.Port != nil { - server.Address = fmt.Sprintf("%s:%d", misc.SanitizeIPv6Address(s.Address), *s.Port) - } else { - server.Address = misc.SanitizeIPv6Address(s.Address) - } - comment, _ := serializeMetadata(s.Metadata) - server.Comment = comment - server.Params = serializeServerParams(s.ServerParams, opt) - if s.ID != nil { - server.Params = append(server.Params, ¶ms.ServerOptionValue{Name: "id", Value: strconv.FormatInt(*s.ID, 10)}) - } - return server -} - -func GetServerByName(name string, parentType string, parentName string, p parser.Parser) (*models.Server, int) { - server, i, err := FindServers(parentType, parentName, name, p) - if err != nil { - return nil, i - } - return server, i -} - -func sectionType(parentType string) parser.Section { - var sectionType parser.Section - switch parentType { - case BackendParentName: - sectionType = parser.Backends - case RingParentName: - sectionType = parser.Ring - case PeersParentName: - sectionType = parser.Peers - } - return sectionType -} - -func FindServers(parentType string, parentName string, serverName string, p parser.Parser) (*models.Server, int, error) { - data, err := p.Get(sectionType(parentType), parentName, "server", false) - if err != nil { - if errors.Is(err, parser_errors.ErrFetch) { - return nil, 0, nil - } - return nil, 0, err - } - - ondiskServers, ok := data.([]types.Server) - if !ok { - return nil, 0, misc.CreateTypeAssertError("server") - } - - for i, ondiskServer := range ondiskServers { - if ondiskServer.Name == serverName { - return ParseServer(ondiskServer), i, nil - } - } - - return nil, 0, nil -} diff --git a/configuration/server_template.go b/configuration/server_template.go index f0466ee8..076c9639 100644 --- a/configuration/server_template.go +++ b/configuration/server_template.go @@ -200,7 +200,7 @@ func SerializeServerTemplate(s models.ServerTemplate, opt *options.Configuration if s.Port != nil { template.Port = *s.Port } - template.Params = serializeServerParams(s.ServerParams, opt) + template.Params = SerializeServerParams(s.ServerParams, opt) return template } diff --git a/models/server_params_prepare_for_runtime.go b/models/server_params_prepare_for_runtime.go new file mode 100644 index 00000000..00916dac --- /dev/null +++ b/models/server_params_prepare_for_runtime.go @@ -0,0 +1,102 @@ +// Code generated by server_params_runtime; DO NOT EDIT. + +package models + +func (s ServerParams) PrepareFieldsForRuntimeAddServer() *ServerParams { + serverParams := new(ServerParams) + // *defaultServer = p + a, _ := s.MarshalBinary() + _ = serverParams.UnmarshalBinary(a) + + serverParams.prepareForRuntimeDoNotSendDisabledFields() + serverParams.prepareForRuntimeDoNotSendEnabledFields() + + return serverParams +} + +func (s *ServerParams) prepareForRuntimeDoNotSendDisabledFields() { + if s.AgentCheck == "disabled" { + s.AgentCheck = "" + } + if s.Backup == "disabled" { + s.Backup = "" + } + if s.Check == "disabled" { + s.Check = "" + } + if s.CheckSendProxy == "disabled" { + s.CheckSendProxy = "" + } + if s.CheckSsl == "disabled" { + s.CheckSsl = "" + } + if s.CheckViaSocks4 == "disabled" { + s.CheckViaSocks4 = "" + } + if s.ForceSslv3 == "disabled" { + s.ForceSslv3 = "" + } + if s.ForceTlsv10 == "disabled" { + s.ForceTlsv10 = "" + } + if s.ForceTlsv11 == "disabled" { + s.ForceTlsv11 = "" + } + if s.ForceTlsv12 == "disabled" { + s.ForceTlsv12 = "" + } + if s.ForceTlsv13 == "disabled" { + s.ForceTlsv13 = "" + } + if s.Maintenance == "disabled" { + s.Maintenance = "" + } + if s.SendProxy == "disabled" { + s.SendProxy = "" + } + if s.SendProxyV2 == "disabled" { + s.SendProxyV2 = "" + } + if s.SendProxyV2Ssl == "disabled" { + s.SendProxyV2Ssl = "" + } + if s.SendProxyV2SslCn == "disabled" { + s.SendProxyV2SslCn = "" + } + if s.Ssl == "disabled" { + s.Ssl = "" + } + if s.SslReuse == "disabled" { + s.SslReuse = "" + } + if s.Stick == "disabled" { + s.Stick = "" + } + if s.Tfo == "disabled" { + s.Tfo = "" + } + if s.TLSTickets == "disabled" { + s.TLSTickets = "" + } +} + +func (s *ServerParams) prepareForRuntimeDoNotSendEnabledFields() { + if s.NoSslv3 == "enabled" { + s.NoSslv3 = "" + } + if s.NoTlsv10 == "enabled" { + s.NoTlsv10 = "" + } + if s.NoTlsv11 == "enabled" { + s.NoTlsv11 = "" + } + if s.NoTlsv12 == "enabled" { + s.NoTlsv12 = "" + } + if s.NoTlsv13 == "enabled" { + s.NoTlsv13 = "" + } + if s.NoVerifyhost == "enabled" { + s.NoVerifyhost = "" + } +} diff --git a/runtime/interface.go b/runtime/interface.go index 49de7753..4c04d1b2 100644 --- a/runtime/interface.go +++ b/runtime/interface.go @@ -71,6 +71,8 @@ type Servers interface { SetServerWeight(backend, server string, weight string) error // SetServerHealth set health for server SetServerHealth(backend, server string, health string) error + // EnableServerHealth + EnableServerHealth(backend, server string) error // EnableAgentCheck enable agent check for server EnableAgentCheck(backend, server string) error // DisableAgentCheck disable agent check for server diff --git a/runtime/runtime_client.go b/runtime/runtime_client.go index 75db3523..4c3bbe40 100644 --- a/runtime/runtime_client.go +++ b/runtime/runtime_client.go @@ -299,6 +299,19 @@ func (c *client) SetServerHealth(backend, server string, health string) error { return nil } +// EnableServerHealth enable health check for server +func (c *client) EnableServerHealth(backend, server string) error { + if !c.runtime.IsValid() { + return errors.New("no valid runtime found") + } + err := c.runtime.EnableServerHealth(backend, server) + if err != nil { + return fmt.Errorf("%s %w", c.runtime.socketPath, err) + } + + return nil +} + // EnableAgentCheck enable agent check for server func (c *client) EnableAgentCheck(backend, server string) error { if !c.runtime.IsValid() { diff --git a/runtime/servers.go b/runtime/servers.go index fb2a7e6b..25917201 100644 --- a/runtime/servers.go +++ b/runtime/servers.go @@ -77,6 +77,12 @@ func (s *SingleRuntime) SetServerHealth(backend, server string, health string) e return s.Execute(cmd) } +// EnableServerHealth enable health check for server +func (s *SingleRuntime) EnableServerHealth(backend, server string) error { + cmd := fmt.Sprintf("enable health %s/%s", backend, server) + return s.Execute(cmd) +} + // SetServerCheckPort set health heck port for server func (s *SingleRuntime) SetServerCheckPort(backend, server string, port int) error { if !(port > 0 && port <= 65535) {