config: remove unknown variable elements from the config
This commit is contained in:
parent
e502bf6ba9
commit
1af5aee146
|
@ -0,0 +1,46 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
// UnknownVariableValue is a sentinel value that can be used
|
||||||
|
// to denote that the value of a variable is unknown at this time.
|
||||||
|
// RawConfig uses this information to build up data about
|
||||||
|
// unknown keys.
|
||||||
|
const UnknownVariableValue = "74D93920-ED26-11E3-AC10-0800200C9A66"
|
||||||
|
|
||||||
|
// RawConfig is a structure that holds a piece of configuration
|
||||||
|
// where te overall structure is unknown since it will be used
|
||||||
|
// to configure a plugin or some other similar external component.
|
||||||
|
//
|
||||||
|
// RawConfigs can be interpolated with variables that come from
|
||||||
|
// other resources, user variables, etc.
|
||||||
|
//
|
||||||
|
// RawConfig supports a query-like interface to request
|
||||||
|
// information from deep within the structure.
|
||||||
|
type RawConfig struct {
|
||||||
|
Raw map[string]interface{}
|
||||||
|
Variables map[string]InterpolatedVariable
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interpolate uses the given mapping of variable values and uses
|
||||||
|
// those as the values to replace any variables in this raw
|
||||||
|
// configuration.
|
||||||
|
//
|
||||||
|
// Any prior calls to Interpolate are replaced with this one.
|
||||||
|
//
|
||||||
|
// If a variable key is missing, this will panic.
|
||||||
|
func (r *RawConfig) Interpolate(map[string]string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config returns the entire configuration with the variables
|
||||||
|
// interpolated from any call to Interpolate.
|
||||||
|
//
|
||||||
|
// If any interpolated variables are unknown (value set to
|
||||||
|
// UnknownVariableValue), the first non-container (map, slice, etc.) element
|
||||||
|
// will be removed from the config. The keys of unknown variables
|
||||||
|
// can be found using the UnknownKeys function.
|
||||||
|
//
|
||||||
|
// By pruning out unknown keys from the configuration, the raw
|
||||||
|
// structure will always successfully decode into its ultimate
|
||||||
|
// structure using something like mapstructure.
|
||||||
|
func (r *RawConfig) Config() map[string]interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,8 @@ type variableReplaceWalker struct {
|
||||||
|
|
||||||
loc reflectwalk.Location
|
loc reflectwalk.Location
|
||||||
m, mk reflect.Value
|
m, mk reflect.Value
|
||||||
|
cs []reflect.Value
|
||||||
|
csData interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *variableReplaceWalker) Enter(loc reflectwalk.Location) error {
|
func (w *variableReplaceWalker) Enter(loc reflectwalk.Location) error {
|
||||||
|
@ -112,16 +114,24 @@ func (w *variableReplaceWalker) Enter(loc reflectwalk.Location) error {
|
||||||
|
|
||||||
func (w *variableReplaceWalker) Exit(loc reflectwalk.Location) error {
|
func (w *variableReplaceWalker) Exit(loc reflectwalk.Location) error {
|
||||||
w.loc = reflectwalk.None
|
w.loc = reflectwalk.None
|
||||||
|
|
||||||
|
switch loc {
|
||||||
|
case reflectwalk.Map:
|
||||||
|
w.cs = w.cs[:len(w.cs)-1]
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *variableReplaceWalker) Map(reflect.Value) error {
|
func (w *variableReplaceWalker) Map(m reflect.Value) error {
|
||||||
|
w.cs = append(w.cs, m)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *variableReplaceWalker) MapElem(m, k, v reflect.Value) error {
|
func (w *variableReplaceWalker) MapElem(m, k, v reflect.Value) error {
|
||||||
w.m = m
|
w.m = m
|
||||||
w.mk = k
|
w.mk = k
|
||||||
|
w.csData = k
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,6 +167,13 @@ func (w *variableReplaceWalker) Primitive(v reflect.Value) error {
|
||||||
panic("no value for variable key: " + key)
|
panic("no value for variable key: " + key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this is an unknown variable, then we remove it from
|
||||||
|
// the configuration.
|
||||||
|
if value == UnknownVariableValue {
|
||||||
|
w.removeCurrent()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Replace
|
// Replace
|
||||||
result = strings.Replace(result, match[0], value, -1)
|
result = strings.Replace(result, match[0], value, -1)
|
||||||
}
|
}
|
||||||
|
@ -173,3 +190,16 @@ func (w *variableReplaceWalker) Primitive(v reflect.Value) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *variableReplaceWalker) removeCurrent() {
|
||||||
|
c := w.cs[len(w.cs)-1]
|
||||||
|
switch c.Kind() {
|
||||||
|
case reflect.Map:
|
||||||
|
// Zero value so that we delete the map key
|
||||||
|
var val reflect.Value
|
||||||
|
|
||||||
|
// Get the key and delete it
|
||||||
|
k := w.csData.(reflect.Value)
|
||||||
|
c.SetMapIndex(k, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -107,6 +107,7 @@ func TestVariableReplaceWalker(t *testing.T) {
|
||||||
w := &variableReplaceWalker{
|
w := &variableReplaceWalker{
|
||||||
Values: map[string]string{
|
Values: map[string]string{
|
||||||
"var.bar": "bar",
|
"var.bar": "bar",
|
||||||
|
"var.unknown": UnknownVariableValue,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,6 +139,33 @@ func TestVariableReplaceWalker(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
map[string]interface{}{
|
||||||
|
"foo": map[string]interface{}{
|
||||||
|
"foo": []string{"${var.bar}"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"foo": map[string]interface{}{
|
||||||
|
"foo": []string{"bar"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
map[string]interface{}{
|
||||||
|
"foo": "bar",
|
||||||
|
"bar": "hello${var.unknown}world",
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
map[string]interface{}{
|
||||||
|
"foo": []string{"foo", "${var.unknown}", "bar"},
|
||||||
|
},
|
||||||
|
map[string]interface{}{},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range cases {
|
for i, tc := range cases {
|
||||||
|
|
Loading…
Reference in New Issue