Skip to content

Non-deterministic failures due to file-loading behavior and nil inputs in once mode #2070

@zarenner

Description

@zarenner

Assume a template such as:

 {{ $a := file "fileA.json" | parseJSON }}
 {{ $b := file "fileB.json" | parseJSON }}

 {{ if $a.enabled }}
 {{ if $b.foo | regexMatch "test*" }}
 {{ end }}
 {{ end }}

w/ fileA.json containing { "enabled": true } and fileB.json containing { "foo": "test" }

When repeatedly run with consul-template -once ..., this will non-deterministically succeed or fail:

  • Over thousands of runs it appears to succeed ~83% of the time on my machine.
  • If the two file-loading lines are reversed, the success rate drops to 36%.

My guess is that there are two things happening:

  1. regexMatch (and other functions) do not support nil inputs. This is clearly reproduced w/ e.g. {{ if ("{}" | parseJSON).foo | regexMatch "test*" }}{{ end }}. This failure does NOT occur with eq or other operators that tolerate nil inputs.
  2. Even in Once mode, multiple rendering passes are occurring. That is, is isn't waiting for both fileA and fileB to load. The failures occur when a rendering pass occurs where fileA was loaded but fileB was not yet loaded.

I do see the following note at https://github.com/hashicorp/consul-template/blob/main/docs/templating-language.md#parsejson:

Note: Consul Template evaluates the template multiple times, and on the first evaluation the value of the key will be empty (because no data has been loaded yet). This means that templates must guard against empty responses.

That would explain the behavior here... but at https://github.com/hashicorp/consul-template/blob/main/docs/modes.md#once-mode it also says:

In Once mode, Consul Template will wait for all dependencies to be rendered.

...although perhaps a file isn't a dependency for this context.

In any case, this behavior feels extremely surprising at least for Once mode and IMO if not a bug still probably deserves a bit more than a small comment in parseJSON.

Possible suggestions:

  1. Change regexMatch and other functions to tolerance nil inputs.
  2. Make file-loading behavior deterministic in once mode.
  3. If existing behavior is correct, consider further describing the behavior in parseJSON and also functions that may be impacted by it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions