-
Notifications
You must be signed in to change notification settings - Fork 2
/
config.go
128 lines (104 loc) · 3.91 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package radv
import (
"encoding/json"
"errors"
"io"
"os"
"github.com/creasty/defaults"
"github.com/go-playground/validator/v10"
"gopkg.in/yaml.v3"
)
// Config represents the configuration of the daemon
type Config struct {
// Interface-specific configuration parameters. The Name field must be
// unique within the slice. The slice itself and elements must not be
// nil.
Interfaces []*InterfaceConfig `yaml:"interfaces" json:"interfaces" validate:"required,non_nil_and_unique_name,dive,required"`
}
// InterfaceConfig represents the interface-specific configuration parameters
type InterfaceConfig struct {
// Required: Network interface name. Must be unique within the configuration.
Name string `yaml:"name" json:"name" validate:"required"`
// Interval between sending unsolicited RA. Must be >= 70 and <= 1800000. Default is 600000.
// The upper bound is chosen to be compliant with RFC4861. The lower bound is intentionally
// chosen to be lower than RFC4861 for faster convergence. If you don't wish to overwhelm the
// network, and wish to be compliant with RFC4861, set to higher than 3000 as RFC4861 suggests.
RAIntervalMilliseconds int `yaml:"raIntervalMilliseconds" json:"raIntervalMilliseconds" validate:"required,gte=70,lte=1800000" default:"600000"`
}
// ValidationErrors is a type alias for the validator.ValidationErrors
type ValidationErrors = validator.ValidationErrors
func (c *Config) defaultAndValidate() error {
if err := defaults.Set(c); err != nil {
panic("BUG (Please report 🙏): Defaulting failed: " + err.Error())
}
validate := validator.New(validator.WithRequiredStructEnabled())
// Adhoc custom validator which validates the slice elements are not
// nil AND the Name field is unique. As far as I know, there is no way
// to validate the uniqueness of struct fields in the nil-able slice of
// struct pointerrs with validator's built-in constraints.
validate.RegisterValidation("non_nil_and_unique_name", func(fl validator.FieldLevel) bool {
names := make(map[string]struct{})
ifaceSlice := fl.Field()
for i := 0; i < fl.Field().Len(); i++ {
ifacep := ifaceSlice.Index(i)
if ifacep.IsNil() {
return false
}
if ifacep.IsNil() {
return false
}
iface := ifacep.Elem()
name := iface.FieldByName("Name")
if _, ok := names[name.String()]; ok {
return false
} else {
names[name.String()] = struct{}{}
}
}
return true
})
if err := validate.Struct(c); err != nil {
if _, ok := err.(*validator.InvalidValidationError); ok {
panic("BUG (Please report 🙏): Invalid validation: " + err.Error())
}
var verrs ValidationErrors
if errors.As(err, &verrs) {
return verrs
}
// This is impossible, according to the validator's documentation
// https://pkg.go.dev/github.com/go-playground/validator/v10#hdr-Validation_Functions_Return_Type_error
return err
}
return nil
}
// ParseConfigJSON parses the JSON-encoded configuration from the reader. This
// function doesn't validate the configuration. The configuration is validated
// when you pass it to the Daemon.
func ParseConfigJSON(r io.Reader) (*Config, error) {
var c Config
if err := json.NewDecoder(r).Decode(&c); err != nil {
return nil, err
}
return &c, nil
}
// ParseConfigYAML parses the YAML-encoded configuration from the reader. This
// function doesn't validate the configuration. The configuration is validated
// when you pass it to the Daemon.
func ParseConfigYAML(r io.Reader) (*Config, error) {
var c Config
if err := yaml.NewDecoder(r).Decode(&c); err != nil {
return nil, err
}
return &c, nil
}
// ParseConfigYAMLFile parses the YAML-encoded configuration from the file at
// the given path. This function doesn't validate the configuration. The
// configuration is validated when you pass it to the Daemon.
func ParseConfigYAMLFile(path string) (*Config, error) {
f, err := os.Open(path)
if err != nil {
return nil, err
}
defer f.Close()
return ParseConfigYAML(f)
}