Skip to content

Commit

Permalink
Add support for variables in outputs and default provider.
Browse files Browse the repository at this point in the history
  • Loading branch information
blakerouse committed Jan 24, 2025
1 parent 4199196 commit 2c31f82
Show file tree
Hide file tree
Showing 18 changed files with 421 additions and 58 deletions.
32 changes: 26 additions & 6 deletions internal/pkg/agent/application/coordinator/coordinator.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ type ConfigManager interface {
type VarsManager interface {
Runner

// DefaultProvider returns the default provider that the variable manager is configured to use.
DefaultProvider() string

// Observe instructs the variables to observe.
Observe([]string)

Expand Down Expand Up @@ -1337,14 +1340,15 @@ func (c *Coordinator) observeASTVars() {
c.varsMgr.Observe(nil)
return
}
var vars []string
inputs, ok := transpiler.Lookup(c.ast, "inputs")
if !ok {
// No inputs; no vars
c.varsMgr.Observe(nil)
return
if ok {
vars = inputs.Vars(vars, c.varsMgr.DefaultProvider())
}
outputs, ok := transpiler.Lookup(c.ast, "outputs")
if ok {
vars = outputs.Vars(vars, c.varsMgr.DefaultProvider())
}
var vars []string
vars = inputs.Vars(vars)
c.varsMgr.Observe(vars)
}

Expand Down Expand Up @@ -1421,6 +1425,8 @@ func (c *Coordinator) generateComponentModel() (err error) {
}()

ast := c.ast.ShallowClone()

// perform variable substitution for inputs
inputs, ok := transpiler.Lookup(ast, "inputs")
if ok {
renderedInputs, err := transpiler.RenderInputs(inputs, c.vars)
Expand All @@ -1433,6 +1439,20 @@ func (c *Coordinator) generateComponentModel() (err error) {
}
}

// perform variable substitution for outputs
// outputs only support the context variables (dynamic provides are not provide to the outputs)
outputs, ok := transpiler.Lookup(ast, "outputs")
if ok {
renderedOutputs, err := transpiler.RenderOutputs(outputs, c.vars)
if err != nil {
return fmt.Errorf("rendering outputs failed: %w", err)
}
err = transpiler.Insert(ast, renderedOutputs, "outputs")
if err != nil {
return fmt.Errorf("inserting rendered outputs failed: %w", err)
}
}

cfg, err := ast.Map()
if err != nil {
return fmt.Errorf("failed to convert ast to map[string]interface{}: %w", err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -928,7 +928,7 @@ func BenchmarkCoordinator_generateComponentModel(b *testing.B) {
require.NoError(b, err)
vars := make([]*transpiler.Vars, len(varsMaps))
for i, vm := range varsMaps {
vars[i], err = transpiler.NewVars(fmt.Sprintf("%d", i), vm, mapstr.M{})
vars[i], err = transpiler.NewVars(fmt.Sprintf("%d", i), vm, mapstr.M{}, "")
require.NoError(b, err)
}

Expand Down Expand Up @@ -1235,6 +1235,10 @@ func (f *fakeVarsManager) Vars(ctx context.Context, vars []*transpiler.Vars) {
}
}

func (f *fakeVarsManager) DefaultProvider() string {
return ""
}

type fakeOTelManager struct {
updateCallback func(*confmap.Conf) error
result error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1104,7 +1104,7 @@ inputs:
components = nil
vars, err := transpiler.NewVars("", map[string]interface{}{
"TEST_VAR": "input-id",
}, nil)
}, nil, "")
require.NoError(t, err, "Vars creation must succeed")
varsChan <- []*transpiler.Vars{vars}
coord.runLoopIteration(ctx)
Expand All @@ -1121,7 +1121,7 @@ inputs:
components = nil
vars, err = transpiler.NewVars("", map[string]interface{}{
"TEST_VAR": "changed-input-id",
}, nil)
}, nil, "")
require.NoError(t, err, "Vars creation must succeed")
varsChan <- []*transpiler.Vars{vars}
coord.runLoopIteration(ctx)
Expand Down Expand Up @@ -1239,7 +1239,7 @@ func TestCoordinatorInitiatesUpgrade(t *testing.T) {
// (Coordinator will only regenerate its component model when it has non-nil
// vars).
func emptyVars(t *testing.T) []*transpiler.Vars {
vars, err := transpiler.NewVars("", map[string]interface{}{}, nil)
vars, err := transpiler.NewVars("", map[string]interface{}{}, nil, "")
require.NoError(t, err, "Vars creation must succeed")
return []*transpiler.Vars{vars}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ func TestDiagnosticVariables(t *testing.T) {
map[string]interface{}{
"testvar": "testvalue",
},
nil)
nil, "")
require.NoError(t, err)

expected := `
Expand Down
26 changes: 13 additions & 13 deletions internal/pkg/agent/transpiler/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ type Node interface {

// Vars adds to the array with the variables identified in the node. Returns the array in-case
// the capacity of the array had to be changed.
Vars([]string) []string
Vars([]string, string) []string

// Apply apply the current vars, returning the new value for the node. This does not modify the original Node.
Apply(*Vars) (Node, error)
Expand Down Expand Up @@ -182,10 +182,10 @@ func (d *Dict) Hash64With(h *xxhash.Digest) error {
}

// Vars returns a list of all variables referenced in the dictionary.
func (d *Dict) Vars(vars []string) []string {
func (d *Dict) Vars(vars []string, defaultProvider string) []string {
for _, v := range d.value {
k := v.(*Key)
vars = k.Vars(vars)
vars = k.Vars(vars, defaultProvider)
}
return vars
}
Expand Down Expand Up @@ -318,11 +318,11 @@ func (k *Key) Hash64With(h *xxhash.Digest) error {
}

// Vars returns a list of all variables referenced in the value.
func (k *Key) Vars(vars []string) []string {
func (k *Key) Vars(vars []string, defaultProvider string) []string {
if k.value == nil {
return vars
}
return k.value.Vars(vars)
return k.value.Vars(vars, defaultProvider)
}

// Apply applies the vars to the value. This does not modify the original node.
Expand Down Expand Up @@ -463,9 +463,9 @@ func (l *List) ShallowClone() Node {
}

// Vars returns a list of all variables referenced in the list.
func (l *List) Vars(vars []string) []string {
func (l *List) Vars(vars []string, defaultProvider string) []string {
for _, v := range l.value {
vars = v.Vars(vars)
vars = v.Vars(vars, defaultProvider)
}
return vars
}
Expand Down Expand Up @@ -552,12 +552,12 @@ func (s *StrVal) Hash64With(h *xxhash.Digest) error {
}

// Vars returns a list of all variables referenced in the string.
func (s *StrVal) Vars(vars []string) []string {
func (s *StrVal) Vars(vars []string, defaultProvider string) []string {
// errors are ignored (if there is an error determine the vars it will also error computing the policy)
_, _ = replaceVars(s.value, func(variable string) (Node, Processors, bool) {
vars = append(vars, variable)
return nil, nil, false
}, false)
}, false, defaultProvider)
return vars
}

Expand Down Expand Up @@ -613,7 +613,7 @@ func (s *IntVal) ShallowClone() Node {
}

// Vars does nothing. Cannot have variable in an IntVal.
func (s *IntVal) Vars(vars []string) []string {
func (s *IntVal) Vars(vars []string, defaultProvider string) []string {
return vars
}

Expand Down Expand Up @@ -691,7 +691,7 @@ func (s *UIntVal) Hash64With(h *xxhash.Digest) error {
}

// Vars does nothing. Cannot have variable in an UIntVal.
func (s *UIntVal) Vars(vars []string) []string {
func (s *UIntVal) Vars(vars []string, defaultProvider string) []string {
return vars
}

Expand Down Expand Up @@ -764,7 +764,7 @@ func (s *FloatVal) hashString() string {
}

// Vars does nothing. Cannot have variable in an FloatVal.
func (s *FloatVal) Vars(vars []string) []string {
func (s *FloatVal) Vars(vars []string, defaultProvider string) []string {
return vars
}

Expand Down Expand Up @@ -843,7 +843,7 @@ func (s *BoolVal) Hash64With(h *xxhash.Digest) error {
}

// Vars does nothing. Cannot have variable in an BoolVal.
func (s *BoolVal) Vars(vars []string) []string {
func (s *BoolVal) Vars(vars []string, defaultProvider string) []string {
return vars
}

Expand Down
79 changes: 74 additions & 5 deletions internal/pkg/agent/transpiler/ast_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -882,7 +882,7 @@ func TestApplyDoesNotMutate(t *testing.T) {

for name, test := range tests {
t.Run(name, func(t *testing.T) {
vars, err := NewVars("", map[string]any{"var": "value"}, mapstr.M{})
vars, err := NewVars("", map[string]any{"var": "value"}, mapstr.M{}, "")
require.NoError(t, err)
applied, err := test.input.Apply(vars)
require.NoError(t, err)
Expand Down Expand Up @@ -961,8 +961,9 @@ func TestShallowClone(t *testing.T) {

func TestVars(t *testing.T) {
tests := map[string]struct {
input map[string]interface{}
result []string
input map[string]interface{}
result []string
defaultProvider string
}{
"empty": {
input: map[string]interface{}{},
Expand Down Expand Up @@ -1045,14 +1046,74 @@ func TestVars(t *testing.T) {
},
result: []string{"var1", "var2", "var3", "var1", "var5", "var6", "var1"},
},
"nested with default": {
input: map[string]interface{}{
"novars": map[string]interface{}{
"list1": []interface{}{
map[string]interface{}{
"int": 1,
"float": 1.1234,
"bool": true,
"str": "value1",
},
},
"list2": []interface{}{
map[string]interface{}{
"int": 2,
"float": 2.3456,
"bool": false,
"str": "value2",
},
},
},
"vars1": map[string]interface{}{
"list1": []interface{}{
map[string]interface{}{
"int": 1,
"float": 1.1234,
"bool": true,
"str": "${custom.var1|host.var2|'constant'}",
},
},
"list2": []interface{}{
map[string]interface{}{
"int": 2,
"float": 2.3456,
"bool": false,
"str": "${var3|custom.var1|'constant'}",
},
},
},
"vars2": map[string]interface{}{
"list1": []interface{}{
map[string]interface{}{
"int": 1,
"float": 1.1234,
"bool": true,
"str": "${host.var5|host.var6|'constant'}",
},
},
"list2": []interface{}{
map[string]interface{}{
"int": 2,
"float": 2.3456,
"bool": false,
"str": "${var1}",
},
},
},
},
result: []string{"custom.var1", "host.var2", "custom.var3", "custom.var1", "host.var5", "host.var6", "custom.var1"},
defaultProvider: "custom",
},
}

for name, test := range tests {
t.Run(name, func(t *testing.T) {
ast, err := NewAST(test.input)
require.NoError(t, err)
var vars []string
vars = ast.root.Vars(vars)
vars = ast.root.Vars(vars, test.defaultProvider)
assert.Equal(t, test.result, vars)
})
}
Expand Down Expand Up @@ -1146,7 +1207,15 @@ func TestCondition(t *testing.T) {
}

func mustMakeVars(mapping map[string]interface{}) *Vars {
v, err := NewVars("", mapping, nil)
v, err := NewVars("", mapping, nil, "")
if err != nil {
panic(err)
}
return v
}

func mustMakeVarsWithDefault(mapping map[string]interface{}, defaultProvider string) *Vars {
v, err := NewVars("", mapping, nil, defaultProvider)
if err != nil {
panic(err)
}
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,25 @@ func TestRenderInputs(t *testing.T) {
}),
},
},
"basic single var with default": {
input: NewKey("inputs", NewList([]Node{
NewDict([]Node{
NewKey("key", NewStrVal("${name}")),
}),
})),
expected: NewList([]Node{
NewDict([]Node{
NewKey("key", NewStrVal("value1")),
}),
}),
varsArray: []*Vars{
mustMakeVarsWithDefault(map[string]interface{}{
"var1": map[string]interface{}{
"name": "value1",
},
}, "var1"),
},
},
"duplicate result is removed": {
input: NewKey("inputs", NewList([]Node{
NewDict([]Node{
Expand Down Expand Up @@ -785,7 +804,7 @@ func TestRenderInputs(t *testing.T) {
}

func mustMakeVarsP(id string, mapping map[string]interface{}, processorKey string, processors Processors) *Vars {
v, err := NewVarsWithProcessors(id, mapping, processorKey, processors, nil)
v, err := NewVarsWithProcessors(id, mapping, processorKey, processors, nil, "")
if err != nil {
panic(err)
}
Expand Down
Loading

0 comments on commit 2c31f82

Please sign in to comment.