override

package
v1.3.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 8, 2017 License: MIT Imports: 10 Imported by: 0

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

func ElementKeys(config interface{}) (map[string]string, error)

ElementKeys returns a map of section name to element key for each section.

func OverrideConfig

func OverrideConfig(config interface{}, os []Override) (map[string]Section, error)

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

func (e Element) ElementID() string

ElementID returns the value of the field specified by the element key. It is unique for all elements within a Section.

func (Element) Redacted

func (e Element) Redacted() (map[string]interface{}, []string, error)

Redacted returns the options for the element in a map. Any fields with the `override:",redact"` tag set will be replaced with a boolean value indicating whether a non-zero value was set.

func (Element) Value

func (e Element) Value() interface{}

Value returns the underlying value of the configuration element.

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.

func (Override) Validate

func (o Override) Validate() error

Validate that the values set on this Override are self-consistent.

type Section

type Section []Element

Section is a list of Elements. Elements are sorted by their element ID.

func (Section) Len

func (s Section) Len() int

func (Section) Less

func (s Section) Less(i, j int) bool

func (Section) Swap

func (s Section) Swap(i, j int)

type Stringer

type Stringer interface {
	String() string
}

Stringer is a type that can provide a string value of itself. If a value is a Stringer and needs to be copied into a numeric value, then String() is called and parsed as a numeric value if possible.

type Validator

type Validator interface {
	Validate() error
}

Validator is a type that can validate itself. If an element is a Validator, then Validate() is called whenever it is modified.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL