docker-archive / deploykit

A toolkit for creating and managing declarative, self-healing infrastructure.
Apache License 2.0
2.25k stars 262 forks source link

Enrollment controller template indexing rendering "<no value>" #821

Closed kaufers closed 6 years ago

kaufers commented 6 years ago

When the enrollment controller parses the instance.Description values from the group memebers (using the SourceKeySelector) 1 of 3 things can happen:

  1. The template correctly parses the property value from the instance.Description
  2. The SourceKeySelector does not match any property value from the instance.Description
  3. The SourceKeySelector cannot even execute

For example, look at test https://github.com/docker/infrakit/blob/master/pkg/controller/enrollment/enroller_test.go#L154

Here, the SourceKeySelector is (modified to remove the int cast):

options:
  SourceKeySelector: \{\{ $x := .Properties | jsonDecode \}\}\{\{ $x.backend_id \}\}

Now, let's apply the different input instance.Description values to show the 3 different options.

  1. Input: {ID: instance.ID("id1"), Properties: types.AnyString("{\"backend_id\":\"1\"} ") Template output: 1

  2. Input: {ID: instance.ID("id2), Properties: types.AnyString("{}")} Template output: <no value>

  3. Input: {ID: instance.ID("id3")} Template errors out because the input is missing the Properties value: error calling jsonDecode: unexpected end of JSON input

Option 2 is what seems incorrect. If the source template does not match shouldn't we be detecting an error vs. using the <no value> template rendering?

kaufers commented 6 years ago

I'm having trouble accurately determining how to detect when <no value> is returned. Is there a template option that we can toggle to have an error raised?

Something like this seems to work but it feels like a bit of a hack:

diff --git a/pkg/controller/enrollment/sync.go b/pkg/controller/enrollment/sync.go
index 830d652f..33a1e0a8 100644
--- a/pkg/controller/enrollment/sync.go
+++ b/pkg/controller/enrollment/sync.go
@@ -128,6 +128,9 @@ func (l *enroller) sync() error {
                        if err != nil {
                                return "", err
                        }
+                       if view == "<no value>" {
+                               return "", fmt.Errorf("Template does not match any property: %v", string([]byte(l.options.SourceKeySelector)))
+                       }
                        return view, nil
                }

Running the updated UT shows an error like this:

EROR[01-04|08:52:42] cannot index entry                       module=controller/enrollment instance.Description="{ID:instance-5 LogicalID:<nil> Tags:map[] Properties:{}}" err="Template does not match any property: \\{\\{ $x := .Properties | jsonDecode \\}\\}\\{\\{ $x.backend_id \\}\\}" stack="[infrakit/pkg/controller/enrollment/_test/_obj_test/set.go:21 infrakit/pkg/controller/enrollment/_test/_obj_test/set.go:59 infrakit/pkg/controller/enrollment/_test/_obj_test/sync.go:213 github.com/docker/infrakit/pkg/controller/enrollment/enroller_test.go:355]"
kaufers commented 6 years ago

Looks like there is an option for this in the base templating package: https://golang.org/pkg/text/template/#Template.Option