-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MEDIUM: add code generator server_params_runtime and fix no-check-sen…
…d-proxy server param option
- Loading branch information
1 parent
6dc3242
commit 01c5e8d
Showing
18 changed files
with
588 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package main | ||
|
||
import ( | ||
_ "embed" | ||
"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 fmt.Errorf("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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package main | ||
|
||
import ( | ||
_ "embed" | ||
) | ||
|
||
//go:embed generate.tmpl | ||
var tmplResetEnumDisabledFields string |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 }} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
package main |
Oops, something went wrong.