Skip to content

Commit

Permalink
Introducing safels and safetree commands to the consul-template.
Browse files Browse the repository at this point in the history
safels and safetree behave exactly like the native ls and tree with one exception. They will *refuse* to render template, if KV prefix query return blank/empty data.

This is especially usefull for rendering mission critical files that do not tolerate ls/tree KV queries to return blank data.

safels and safetree work in stale mode just as their ancestors but we get extra safety on top.

safels and safetree commands were born as an attempt to mitigate issues described here:

  hashicorp#1131
  hashicorp/consul#3975
  hashicorp/consul-replicate#82
  • Loading branch information
vaLski committed Aug 15, 2018
1 parent a739afb commit a296ac7
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 10 deletions.
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,23 @@ maxconns:15
minconns:5
```
##### `safels`
Same as [ls](#ls), but refuse to render template, if the KV prefix query return blank/empty data.
This is especially useful, for rendering mission critical files, that are being populated by consul-template.
For example:
```text
/root/.ssh/authorized_keys
/etc/sysconfig/iptables
```
Using `safels` on empty prefixes will result in template output not being rendered at all.
To learn how `safels` was born see [CT-1131](https://github.com/hashicorp/consul-template/issues/1131) [C-3975](https://github.com/hashicorp/consul/issues/3975) and [CR-82](https://github.com/hashicorp/consul-replicate/issues/82).
##### `node`
Query [Consul][consul] for a node in the catalog.
Expand Down Expand Up @@ -999,6 +1016,23 @@ nested/config/value "value"
Unlike `ls`, `tree` returns **all** keys under the prefix, just like the Unix
`tree` command.
##### `safetree`
Same as [tree](#tree), but refuse to render template, if the KV prefix query return blank/empty data.
This is especially useful, for rendering mission critical files, that are being populated by consul-template.
For example:
```text
/root/.ssh/authorized_keys
/etc/sysconfig/iptables
```
Using `safetree` on empty prefixes will result in template output not being rendered at all.
To learn how `safetree` was born see [CT-1131](https://github.com/hashicorp/consul-template/issues/1131) [C-3975](https://github.com/hashicorp/consul/issues/3975) and [CR-82](https://github.com/hashicorp/consul-replicate/issues/82).
---
#### Scratch
Expand Down
51 changes: 43 additions & 8 deletions template/funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,13 @@ func keyWithDefaultFunc(b *Brain, used, missing *dep.Set) func(string, string) (
}
}

func safelsFunc(b *Brain, used, missing *dep.Set) func(string) ([]*dep.KeyPair, error) {
// call lsFunc but explicitly mark that empty data set returned on monitored KV prefix is NOT safe
return lsFunc(b, used, missing, false)
}

// lsFunc returns or accumulates keyPrefix dependencies.
func lsFunc(b *Brain, used, missing *dep.Set) func(string) ([]*dep.KeyPair, error) {
func lsFunc(b *Brain, used, missing *dep.Set, emptyIsSafe bool) func(string) ([]*dep.KeyPair, error) {
return func(s string) ([]*dep.KeyPair, error) {
result := []*dep.KeyPair{}

Expand All @@ -227,9 +232,23 @@ func lsFunc(b *Brain, used, missing *dep.Set) func(string) ([]*dep.KeyPair, erro
result = append(result, pair)
}
}
return result, nil

if len(result) == 0 {
if emptyIsSafe {
// Operator used potentially unsafe ls function in the template instead of the safels
return result, nil
}
} else {
// non empty result is good so we just return the data
return result, nil
}

// If we reach this part of the code result is completely empty as value returned no KV pairs
// Operator selected to use safels on the specific KV prefix so we will refuse to render template
// by marking d as missing
}

// b.Recall either returned an error or safels entered unsafe case
missing.Add(d)

return result, nil
Expand Down Expand Up @@ -402,8 +421,13 @@ func servicesFunc(b *Brain, used, missing *dep.Set) func(...string) ([]*dep.Cata
}
}

func safetreeFunc(b *Brain, used, missing *dep.Set) func(string) ([]*dep.KeyPair, error) {
// call treeFunc but explicitly mark that empty data set returned on monitored KV prefix is NOT safe
return treeFunc(b, used, missing, false)
}

// treeFunc returns or accumulates keyPrefix dependencies.
func treeFunc(b *Brain, used, missing *dep.Set) func(string) ([]*dep.KeyPair, error) {
func treeFunc(b *Brain, used, missing *dep.Set, emptyIsSafe bool) func(string) ([]*dep.KeyPair, error) {
return func(s string) ([]*dep.KeyPair, error) {
result := []*dep.KeyPair{}

Expand All @@ -426,9 +450,23 @@ func treeFunc(b *Brain, used, missing *dep.Set) func(string) ([]*dep.KeyPair, er
result = append(result, pair)
}
}
return result, nil

if len(result) == 0 {
if emptyIsSafe {
// Operator used potentially unsafe tree function in the template instead of the safetree
return result, nil
}
} else {
// non empty result is good so we just return the data
return result, nil
}

// If we reach this part of the code result is completely empty as value returned no KV pairs
// Operator selected to use safetree on the specific KV prefix so we will refuse to render template
// by marking d as missing
}

// b.Recall either returned an error or safetree entered unsafe case
missing.Add(d)

return result, nil
Expand Down Expand Up @@ -657,9 +695,6 @@ func in(l, v interface{}) (bool, error) {

// Indent prefixes each line of a string with the specified number of spaces
func indent(spaces int, s string) (string, error) {
if spaces < 0 {
return "", fmt.Errorf("indent value must be a positive integer")
}
var output, prefix []byte
var sp bool
var size int
Expand All @@ -672,7 +707,7 @@ func indent(spaces int, s string) (string, error) {
}
output = append(output, c)
sp = c == '\n'
size++
size += 1
}
return string(output[:size]), nil
}
Expand Down
6 changes: 4 additions & 2 deletions template/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,14 +205,16 @@ func funcMap(i *funcMapInput) template.FuncMap {
"key": keyFunc(i.brain, i.used, i.missing),
"keyExists": keyExistsFunc(i.brain, i.used, i.missing),
"keyOrDefault": keyWithDefaultFunc(i.brain, i.used, i.missing),
"ls": lsFunc(i.brain, i.used, i.missing),
"ls": lsFunc(i.brain, i.used, i.missing, true),
"safels": safelsFunc(i.brain, i.used, i.missing),
"node": nodeFunc(i.brain, i.used, i.missing),
"nodes": nodesFunc(i.brain, i.used, i.missing),
"secret": secretFunc(i.brain, i.used, i.missing),
"secrets": secretsFunc(i.brain, i.used, i.missing),
"service": serviceFunc(i.brain, i.used, i.missing),
"services": servicesFunc(i.brain, i.used, i.missing),
"tree": treeFunc(i.brain, i.used, i.missing),
"tree": treeFunc(i.brain, i.used, i.missing, true),
"safetree": safetreeFunc(i.brain, i.used, i.missing),

// Scratch
"scratch": func() *Scratch { return &scratch },
Expand Down

0 comments on commit a296ac7

Please sign in to comment.