Documentation ¶
Overview ¶
Overrider provides an API for overriding and reading redacted values for a configuration object.
The configuration object provided is expected to have two levels of nested structs. The top level struct should have fields called "sections". These fields may either be a struct or a slice of structs. As such a section consists of a list of elements. In the case where the field is a struct and not a slice, the section list always contains one element. Further nested levels may exist but Overrider will not interact with them directly. If a nested field is a struct, then github.com/mitchellh/mapstructure will be used to decode the map into the struct.
In order for a section to be overridden an `override` struct tag must be present. The `override` tag defines a name for the section and option. Struct tags can be used to mark options as redacted by adding a `<name>,redact` to the end of the `override` tag value.
Example:
type SectionAConfig struct { Option string `override:"option"` Password string `override:"password,redact"` } type SectionBConfig struct { ID string `override:"id"` Option string `override:"option"` } type Config struct { SectionA SectionAConfig `override:"section-a"` SectionB []SectionBConfig `override:"section-b,element-key=id"` IgnoredSection IgnoredConfig IgnoredField string } type IgnoredConfig struct { // contains anything ... } // Setup c := Config{ SectionA: SectionAConfig{ Option: "option value", Password: "secret", }, SectionB: []SectionBConfig{ { ID: "id0", Option: "option value 0", }, { ID: "id1", Option: "option value 1", }, }, IgnoredSection: IgnoredConfig{}, IgnoredField: "this value is ignored", } o := override.New(c) // Read redacted section values redacted, err := o.Sections() // Override options for a section newElement, err := o.Override(Override{ Section: "section-b", Element: "id1", // Element may be empty when overriding a section which is not a list. Options: map[string]interface{}{"option": "overridden option value"}, })
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ElementKeys ¶
ElementKeys returns a map of section name to element key for each section.
func OverrideConfig ¶
OverrideConfig applies all given overrides and returns a map of all configuration sections, even if they were not overridden. The overrides are all applied to the same object and the original configuration object remains unmodified.
Values must be of the same type as the named option field, or have another means of converting the value.
Numeric types will be converted to the absolute type using Go's default conversion mechanisms. Strings and Stringer types will be parsed for numeric values if possible. TextUnmarshaler types will attempt to unmarshal string values.
Mismatched types or failure to convert the value will result in an error.
An element value that is a Validator will be validated and any encounted error returned.
When a new element is being created if the element type is a Initer, then the zero value of the element will first have defaults set before the overrides are applied.
The underlying configuration object is not modified, but rather a copy is returned via the Element type.
Example ¶
package main import ( "fmt" "github.com/influxdata/kapacitor/services/config/override" ) type SectionA struct { Option1 string `override:"option1"` Option2 string `override:"option2"` } type SectionB struct { Option3 string `override:"option3"` } type SectionC struct { Option4 int64 `override:"option4"` Password string `override:"password,redact"` } type SectionD struct { ID string `override:"id"` Option5 string `override:"option5"` Option6 map[string]map[string]int `override:"option6"` Option7 [][]int `override:"option7"` } func (d *SectionD) Init() { d.Option5 = "o5" } func (d SectionD) Validate() error { if d.ID == "" { return fmt.Errorf("ID cannot be empty") } return nil } type SectionIgnored struct { String string } type SectionNums struct { Int int Int8 int8 Int16 int16 Int32 int32 Int64 int64 Uint uint Uint8 uint8 Uint16 uint16 Uint32 uint32 Uint64 uint64 Float32 float32 Float64 float64 } type TestConfig struct { SectionA SectionA `override:"section-a"` SectionB SectionB `override:"section-b"` SectionC *SectionC `override:"section-c"` SectionNums SectionNums `override:"section-nums"` SectionDs []SectionD `override:"section-d,element-key=id"` SectionIgnored SectionIgnored IgnoredInt int IgnoredString string } func main() { config := &TestConfig{ SectionA: SectionA{ Option1: "o1", }, SectionB: SectionB{ Option3: "o2", }, SectionC: &SectionC{ Option4: -1, }, SectionDs: []SectionD{ { ID: "x", Option5: "x-5", }, { ID: "y", Option5: "y-5", }, { ID: "z", Option5: "z-5", }, }, } // Override options in section-a if newConfig, err := override.OverrideConfig(config, []override.Override{ { Section: "section-a", Options: map[string]interface{}{ "option1": "new option1 value", "option2": "initial option2 value", }, }, { Section: "section-b", Options: map[string]interface{}{ "option3": "initial option3 value", }, }, { Section: "section-c", Options: map[string]interface{}{ "option4": 586, }, }, { Section: "section-d", Element: "x", Options: map[string]interface{}{ "option5": "x-new-5", }, }, { Section: "section-d", Element: "y", Options: map[string]interface{}{ "option5": "y-new-5", }, }, { Section: "section-d", Create: true, Options: map[string]interface{}{ "id": "w", "option5": "w-new-5", }, }, }); err != nil { fmt.Println("ERROR:", err) } else { a := newConfig["section-a"][0].Value().(SectionA) fmt.Println("New SectionA.Option1:", a.Option1) fmt.Println("New SectionA.Option2:", a.Option2) b := newConfig["section-b"][0].Value().(SectionB) fmt.Println("New SectionB.Option3:", b.Option3) c := newConfig["section-c"][0].Value().(*SectionC) fmt.Println("New SectionC.Option4:", c.Option4) // NOTE: Section elements are sorted by element key d := newConfig["section-d"] d0 := d[0].Value().(SectionD) d1 := d[1].Value().(SectionD) d2 := d[2].Value().(SectionD) d3 := d[3].Value().(SectionD) fmt.Println("New SectionD[0].Option5:", d0.Option5) fmt.Println("New SectionD[1].Option5:", d1.Option5) fmt.Println("New SectionD[2].Option5:", d2.Option5) fmt.Println("Old SectionD[3].Option5:", d3.Option5) } }
Output: New SectionA.Option1: new option1 value New SectionA.Option2: initial option2 value New SectionB.Option3: initial option3 value New SectionC.Option4: 586 New SectionD[0].Option5: w-new-5 New SectionD[1].Option5: x-new-5 New SectionD[2].Option5: y-new-5 Old SectionD[3].Option5: z-5
Types ¶
type Element ¶
type Element struct {
// contains filtered or unexported fields
}
Element provides access to the underlying value or a map of redacted values.
func (Element) ElementID ¶
ElementID returns the value of the field specified by the element key. It is unique for all elements within a Section.
type Initer ¶
type Initer interface {
Init()
}
Initer set defaults on the receiving object. If a type is a Initer and a new value needs to be created of that type, then Init() is called on a new instance of that type.
type Override ¶
type Override struct { // Section is the name of the section to override. Section string // Element is the name of the element within a section to override. // If the section is not a slice of structs then this can remain empty. Element string // Options is a set of option name to value to override existing values. Options map[string]interface{} // Delete indicates whether the specified element should be deleted. Delete bool // Create indicates whether to create a new element in the specified section. // To create a new element leave the element name empty in this Override object // and provide the value in the Options map under the element key. Create bool }
Override specifies what configuration values should be overridden and how. Configuration options can be overridden as well as elements of a section can be deleted or created.
type Section ¶
type Section []Element
Section is a list of Elements. Elements are sorted by their element ID.