Merge branch v2.11 into v3.0
This commit is contained in:
commit
319517adef
15 changed files with 1263 additions and 701 deletions
|
@ -1,10 +1,13 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -16,9 +19,65 @@ import (
|
|||
"github.com/traefik/paerser/generator"
|
||||
"github.com/traefik/paerser/parser"
|
||||
"github.com/traefik/traefik/v3/cmd"
|
||||
"github.com/traefik/traefik/v3/pkg/collector/hydratation"
|
||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||
"github.com/traefik/traefik/v3/pkg/config/static"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var commentGenerated = `## CODE GENERATED AUTOMATICALLY
|
||||
## THIS FILE MUST NOT BE EDITED BY HAND
|
||||
`
|
||||
|
||||
func main() {
|
||||
logger := log.With().Logger()
|
||||
|
||||
dynConf := &dynamic.Configuration{}
|
||||
|
||||
err := hydratation.Hydrate(dynConf)
|
||||
if err != nil {
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
|
||||
dynConf.HTTP.Models = map[string]*dynamic.Model{}
|
||||
clean(dynConf.HTTP.Middlewares)
|
||||
clean(dynConf.TCP.Middlewares)
|
||||
clean(dynConf.HTTP.Services)
|
||||
clean(dynConf.TCP.Services)
|
||||
clean(dynConf.UDP.Services)
|
||||
|
||||
err = tomlWrite("./docs/content/reference/dynamic-configuration/file.toml", dynConf)
|
||||
if err != nil {
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
err = yamlWrite("./docs/content/reference/dynamic-configuration/file.yaml", dynConf)
|
||||
if err != nil {
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
|
||||
err = labelsWrite("./docs/content/reference/dynamic-configuration", dynConf)
|
||||
if err != nil {
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
|
||||
staticConf := &static.Configuration{}
|
||||
|
||||
err = hydratation.Hydrate(staticConf)
|
||||
if err != nil {
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
|
||||
delete(staticConf.EntryPoints, "EntryPoint1")
|
||||
|
||||
err = tomlWrite("./docs/content/reference/static-configuration/file.toml", staticConf)
|
||||
if err != nil {
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
err = yamlWrite("./docs/content/reference/static-configuration/file.yaml", staticConf)
|
||||
if err != nil {
|
||||
logger.Fatal().Err(err).Send()
|
||||
}
|
||||
|
||||
genStaticConfDoc("./docs/content/reference/static-configuration/env-ref.md", "", func(i interface{}) ([]parser.Flat, error) {
|
||||
return env.Encode(env.DefaultNamePrefix, i)
|
||||
})
|
||||
|
@ -26,6 +85,161 @@ func main() {
|
|||
genKVDynConfDoc("./docs/content/reference/dynamic-configuration/kv-ref.md")
|
||||
}
|
||||
|
||||
func labelsWrite(outputDir string, element *dynamic.Configuration) error {
|
||||
cleanServers(element)
|
||||
|
||||
etnOpts := parser.EncoderToNodeOpts{OmitEmpty: true, TagName: parser.TagLabel, AllowSliceAsStruct: true}
|
||||
node, err := parser.EncodeToNode(element, parser.DefaultRootName, etnOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
metaOpts := parser.MetadataOpts{TagName: parser.TagLabel, AllowSliceAsStruct: true}
|
||||
err = parser.AddMetadata(element, node, metaOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
labels := make(map[string]string)
|
||||
encodeNode(labels, node.Name, node)
|
||||
|
||||
var keys []string
|
||||
for k := range labels {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
dockerLabels, err := os.Create(filepath.Join(outputDir, "docker-labels.yml"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dockerLabels.Close()
|
||||
|
||||
// Write the comment at the beginning of the file
|
||||
if _, err := dockerLabels.WriteString(commentGenerated); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
marathonLabels, err := os.Create(filepath.Join(outputDir, "marathon-labels.json"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer marathonLabels.Close()
|
||||
|
||||
// Write the comment at the beginning of the file
|
||||
if _, err := marathonLabels.WriteString(strings.ReplaceAll(commentGenerated, "##", "//")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i, k := range keys {
|
||||
v := labels[k]
|
||||
if v != "" {
|
||||
if v == "42000000000" {
|
||||
v = "42s"
|
||||
}
|
||||
fmt.Fprintln(dockerLabels, `- "`+strings.ToLower(k)+`=`+v+`"`)
|
||||
|
||||
if i == len(keys)-1 {
|
||||
fmt.Fprintln(marathonLabels, `"`+strings.ToLower(k)+`": "`+v+`"`)
|
||||
} else {
|
||||
fmt.Fprintln(marathonLabels, `"`+strings.ToLower(k)+`": "`+v+`",`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func cleanServers(element *dynamic.Configuration) {
|
||||
for _, svc := range element.HTTP.Services {
|
||||
if svc.LoadBalancer != nil {
|
||||
server := svc.LoadBalancer.Servers[0]
|
||||
svc.LoadBalancer.Servers = nil
|
||||
svc.LoadBalancer.Servers = append(svc.LoadBalancer.Servers, server)
|
||||
}
|
||||
}
|
||||
|
||||
for _, svc := range element.TCP.Services {
|
||||
if svc.LoadBalancer != nil {
|
||||
server := svc.LoadBalancer.Servers[0]
|
||||
svc.LoadBalancer.Servers = nil
|
||||
svc.LoadBalancer.Servers = append(svc.LoadBalancer.Servers, server)
|
||||
}
|
||||
}
|
||||
|
||||
for _, svc := range element.UDP.Services {
|
||||
if svc.LoadBalancer != nil {
|
||||
server := svc.LoadBalancer.Servers[0]
|
||||
svc.LoadBalancer.Servers = nil
|
||||
svc.LoadBalancer.Servers = append(svc.LoadBalancer.Servers, server)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func yamlWrite(outputFile string, element any) error {
|
||||
file, err := os.OpenFile(outputFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// Write the comment at the beginning of the file
|
||||
if _, err := file.WriteString(commentGenerated); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
encoder := yaml.NewEncoder(buf)
|
||||
encoder.SetIndent(2)
|
||||
err = encoder.Encode(element)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = file.Write(buf.Bytes())
|
||||
return err
|
||||
}
|
||||
|
||||
func tomlWrite(outputFile string, element any) error {
|
||||
file, err := os.OpenFile(outputFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// Write the comment at the beginning of the file
|
||||
if _, err := file.WriteString(commentGenerated); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return toml.NewEncoder(file).Encode(element)
|
||||
}
|
||||
|
||||
func clean(element any) {
|
||||
valSvcs := reflect.ValueOf(element)
|
||||
|
||||
key := valSvcs.MapKeys()[0]
|
||||
valueSvcRoot := valSvcs.MapIndex(key).Elem()
|
||||
|
||||
var svcFieldNames []string
|
||||
for i := 0; i < valueSvcRoot.NumField(); i++ {
|
||||
svcFieldNames = append(svcFieldNames, valueSvcRoot.Type().Field(i).Name)
|
||||
}
|
||||
|
||||
sort.Strings(svcFieldNames)
|
||||
|
||||
for i, fieldName := range svcFieldNames {
|
||||
v := reflect.New(valueSvcRoot.Type())
|
||||
v.Elem().FieldByName(fieldName).Set(valueSvcRoot.FieldByName(fieldName))
|
||||
|
||||
valSvcs.SetMapIndex(reflect.ValueOf(fmt.Sprintf("%s%.2d", valueSvcRoot.Type().Name(), i+1)), v)
|
||||
}
|
||||
|
||||
valSvcs.SetMapIndex(reflect.ValueOf(fmt.Sprintf("%s0", valueSvcRoot.Type().Name())), reflect.Value{})
|
||||
valSvcs.SetMapIndex(reflect.ValueOf(fmt.Sprintf("%s1", valueSvcRoot.Type().Name())), reflect.Value{})
|
||||
}
|
||||
|
||||
func genStaticConfDoc(outputFile, prefix string, encodeFn func(interface{}) ([]parser.Flat, error)) {
|
||||
logger := log.With().Str("file", outputFile).Logger()
|
||||
|
||||
|
@ -117,6 +331,7 @@ func genKVDynConfDoc(outputFile string) {
|
|||
}
|
||||
|
||||
store := storeWriter{data: map[string]string{}}
|
||||
|
||||
c := client{store: store}
|
||||
err = c.load("traefik", conf)
|
||||
if err != nil {
|
||||
|
@ -130,6 +345,12 @@ func genKVDynConfDoc(outputFile string) {
|
|||
|
||||
sort.Strings(keys)
|
||||
|
||||
_, _ = fmt.Fprintf(file, `<!--
|
||||
CODE GENERATED AUTOMATICALLY
|
||||
THIS FILE MUST NOT BE EDITED BY HAND
|
||||
-->
|
||||
`)
|
||||
|
||||
for _, k := range keys {
|
||||
_, _ = fmt.Fprintf(file, "| `%s` | `%s` |\n", k, store.data[k])
|
||||
}
|
||||
|
|
66
internal/parser.go
Normal file
66
internal/parser.go
Normal file
|
@ -0,0 +1,66 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/traefik/paerser/parser"
|
||||
)
|
||||
|
||||
func encodeNode(labels map[string]string, root string, node *parser.Node) {
|
||||
for _, child := range node.Children {
|
||||
if child.Disabled {
|
||||
continue
|
||||
}
|
||||
|
||||
var sep string
|
||||
if child.Name[0] != '[' {
|
||||
sep = "."
|
||||
}
|
||||
|
||||
childName := root + sep + child.Name
|
||||
|
||||
if child.RawValue != nil {
|
||||
encodeRawValue(labels, childName, child.RawValue)
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.Contains(child.Tag.Get(parser.TagLabel), parser.TagLabelAllowEmpty) {
|
||||
labels[childName] = "true"
|
||||
}
|
||||
|
||||
if len(child.Children) > 0 {
|
||||
encodeNode(labels, childName, child)
|
||||
} else if len(child.Name) > 0 {
|
||||
labels[childName] = child.Value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func encodeRawValue(labels map[string]string, root string, rawValue interface{}) {
|
||||
if rawValue == nil {
|
||||
return
|
||||
}
|
||||
|
||||
tValue := reflect.TypeOf(rawValue)
|
||||
|
||||
if tValue.Kind() == reflect.Map && tValue.Elem().Kind() == reflect.Interface {
|
||||
r := reflect.ValueOf(rawValue).
|
||||
Convert(reflect.TypeOf((map[string]interface{})(nil))).
|
||||
Interface().(map[string]interface{})
|
||||
|
||||
for k, v := range r {
|
||||
switch tv := v.(type) {
|
||||
case string:
|
||||
labels[root+"."+k] = tv
|
||||
case []interface{}:
|
||||
for i, e := range tv {
|
||||
encodeRawValue(labels, fmt.Sprintf("%s.%s[%d]", root, k, i), e)
|
||||
}
|
||||
default:
|
||||
encodeRawValue(labels, root+"."+k, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue