hashicorp / hashicorp/consul-template

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

Open
#2,070 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
4.8k
Forks
801
Avg merge
4h 5m
Merged PRs (30d)
6

Description

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.

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the once-mode template with the file-loading and nil-input cases described in the issue, then read docs/templating-language.md#parsejson and docs/modes.md#once-mode. Determine whether the intended fix is deterministic dependency handling, nil tolerance, or documentation; the issue does not define a single acceptance criterion.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.