Merge pull request #7170 from fredrikhgrelland/consul_template_upgrade

Update consul-template to v0.24.1 and remove deprecated vault grace
This commit is contained in:
Michael Schurter
2020-03-10 14:15:47 -07:00
committed by GitHub
31 changed files with 438 additions and 192 deletions

View File

@@ -4,6 +4,7 @@ IMPROVEMENTS:
* build: Updated to Go 1.14 [[GH-7247](https://github.com/hashicorp/nomad/issues/7247)]
* consul: Added support for configuring `enable_tag_override` on service stanzas. [[GH-2057](https://github.com/hashicorp/nomad/issues/2057)]
* client: Updated consul-template library to v0.24.1 - added support for working with consul connect. [Deprecated vault_grace](https://nomadproject.io/guides/upgrade/upgrade-specific/#nomad-0110) [[GH-7170](https://github.com/hashicorp/nomad/pull/7170)]
BUG FIXES:

View File

@@ -402,7 +402,6 @@ func TestJobs_Canonicalize(t *testing.T) {
EmbeddedTmpl: stringToPtr("FOO=bar\n"),
DestPath: stringToPtr("local/file.env"),
Envvars: boolToPtr(true),
VaultGrace: timeToPtr(3 * time.Second),
},
},
},
@@ -532,7 +531,6 @@ func TestJobs_Canonicalize(t *testing.T) {
LeftDelim: stringToPtr("{{"),
RightDelim: stringToPtr("}}"),
Envvars: boolToPtr(false),
VaultGrace: timeToPtr(15 * time.Second),
},
{
SourcePath: stringToPtr(""),
@@ -545,7 +543,6 @@ func TestJobs_Canonicalize(t *testing.T) {
LeftDelim: stringToPtr("{{"),
RightDelim: stringToPtr("}}"),
Envvars: boolToPtr(true),
VaultGrace: timeToPtr(3 * time.Second),
},
},
},

View File

@@ -750,9 +750,6 @@ func (tmpl *Template) Canonicalize() {
if tmpl.Envvars == nil {
tmpl.Envvars = boolToPtr(false)
}
if tmpl.VaultGrace == nil {
tmpl.VaultGrace = timeToPtr(15 * time.Second)
}
}
type Vault struct {

View File

@@ -611,17 +611,6 @@ func newRunnerConfig(config *TaskTemplateManagerConfig,
}
conf.Templates = &flat
// Go through the templates and determine the minimum Vault grace
vaultGrace := time.Duration(-1)
for _, tmpl := range templateMapping {
// Initial condition
if vaultGrace < 0 {
vaultGrace = tmpl.VaultGrace
} else if tmpl.VaultGrace < vaultGrace {
vaultGrace = tmpl.VaultGrace
}
}
// Force faster retries
if config.retryRate != 0 {
rate := config.retryRate
@@ -666,7 +655,6 @@ func newRunnerConfig(config *TaskTemplateManagerConfig,
if cc.VaultConfig != nil && cc.VaultConfig.IsEnabled() {
conf.Vault.Address = &cc.VaultConfig.Addr
conf.Vault.Token = &config.VaultToken
conf.Vault.Grace = helper.TimeToPtr(vaultGrace)
if config.ClientConfig.VaultConfig.Namespace != "" {
conf.Vault.Namespace = &config.ClientConfig.VaultConfig.Namespace
}

View File

@@ -1340,51 +1340,6 @@ func TestTaskTemplateManager_Config_ServerName(t *testing.T) {
}
}
// TestTaskTemplateManager_Config_VaultGrace asserts the vault_grace setting is
// propagated to consul-template's configuration.
func TestTaskTemplateManager_Config_VaultGrace(t *testing.T) {
t.Parallel()
assert := assert.New(t)
c := config.DefaultConfig()
c.Node = mock.Node()
c.VaultConfig = &sconfig.VaultConfig{
Enabled: helper.BoolToPtr(true),
Addr: "https://localhost/",
TLSServerName: "notlocalhost",
}
alloc := mock.Alloc()
config := &TaskTemplateManagerConfig{
ClientConfig: c,
VaultToken: "token",
// Make a template that will render immediately
Templates: []*structs.Template{
{
EmbeddedTmpl: "bar",
DestPath: "foo",
ChangeMode: structs.TemplateChangeModeNoop,
VaultGrace: 10 * time.Second,
},
{
EmbeddedTmpl: "baz",
DestPath: "bam",
ChangeMode: structs.TemplateChangeModeNoop,
VaultGrace: 100 * time.Second,
},
},
EnvBuilder: taskenv.NewBuilder(c.Node, alloc, alloc.Job.TaskGroups[0].Tasks[0], c.Region),
}
ctmplMapping, err := parseTemplateConfigs(config)
assert.Nil(err, "Parsing Templates")
ctconf, err := newRunnerConfig(config, ctmplMapping)
assert.Nil(err, "Building Runner Config")
assert.NotNil(ctconf.Vault.Grace, "Vault Grace Pointer")
assert.Equal(10*time.Second, *ctconf.Vault.Grace, "Vault Grace Value")
}
// TestTaskTemplateManager_Config_VaultNamespace asserts the Vault namespace setting is
// propagated to consul-template's configuration.
func TestTaskTemplateManager_Config_VaultNamespace(t *testing.T) {
@@ -1413,7 +1368,6 @@ func TestTaskTemplateManager_Config_VaultNamespace(t *testing.T) {
ctconf, err := newRunnerConfig(config, ctmplMapping)
assert.Nil(err, "Building Runner Config")
assert.NotNil(ctconf.Vault.Grace, "Vault Grace Pointer")
assert.Equal(testNS, *ctconf.Vault.Namespace, "Vault Namespace Value")
}

View File

@@ -1706,7 +1706,6 @@ func TestJobs_ApiJobToStructsJob(t *testing.T) {
LeftDelim: helper.StringToPtr("abc"),
RightDelim: helper.StringToPtr("def"),
Envvars: helper.BoolToPtr(true),
VaultGrace: helper.TimeToPtr(3 * time.Second),
},
},
DispatchPayload: &api.DispatchPayloadConfig{
@@ -2054,7 +2053,6 @@ func TestJobs_ApiJobToStructsJob(t *testing.T) {
LeftDelim: "abc",
RightDelim: "def",
Envvars: true,
VaultGrace: 3 * time.Second,
},
},
DispatchPayload: &structs.DispatchPayloadConfig{

View File

@@ -359,7 +359,7 @@ func parseTemplates(result *[]*api.Template, list *ast.ObjectList) error {
"source",
"splay",
"env",
"vault_grace",
"vault_grace", //COMPAT(0.12) not used; emits warning in 0.11.
}
if err := helper.CheckHCLKeys(o.Val, valid); err != nil {
return err
@@ -374,6 +374,7 @@ func parseTemplates(result *[]*api.Template, list *ast.ObjectList) error {
ChangeMode: helper.StringToPtr("restart"),
Splay: helper.TimeToPtr(5 * time.Second),
Perms: helper.StringToPtr("0644"),
VaultGrace: helper.TimeToPtr(0),
}
dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{

View File

@@ -320,7 +320,6 @@ func TestParse(t *testing.T) {
Splay: helper.TimeToPtr(10 * time.Second),
Perms: helper.StringToPtr("0644"),
Envvars: helper.BoolToPtr(true),
VaultGrace: helper.TimeToPtr(33 * time.Second),
},
{
SourcePath: helper.StringToPtr("bar"),

View File

@@ -1,9 +1,10 @@
job "service_eto" {
type = "service"
group "group" {
task "task" {
service {
name = "example"
name = "example"
enable_tag_override = true
}
}

View File

@@ -1,7 +1,7 @@
job "group_service_eto" {
group "group" {
service {
name = "example"
name = "example"
enable_tag_override = true
}
}

View File

@@ -5666,7 +5666,6 @@ func TestTaskDiff(t *testing.T) {
ChangeSignal: "SIGHUP",
Splay: 1,
Perms: "0644",
VaultGrace: 3 * time.Second,
},
{
SourcePath: "foo2",
@@ -5677,7 +5676,6 @@ func TestTaskDiff(t *testing.T) {
Splay: 2,
Perms: "0666",
Envvars: true,
VaultGrace: 5 * time.Second,
},
},
},
@@ -5691,7 +5689,6 @@ func TestTaskDiff(t *testing.T) {
ChangeSignal: "SIGHUP",
Splay: 1,
Perms: "0644",
VaultGrace: 3 * time.Second,
},
{
SourcePath: "foo3",
@@ -5701,7 +5698,6 @@ func TestTaskDiff(t *testing.T) {
ChangeSignal: "SIGHUP3",
Splay: 3,
Perms: "0776",
VaultGrace: 10 * time.Second,
},
},
},
@@ -5760,12 +5756,6 @@ func TestTaskDiff(t *testing.T) {
Old: "",
New: "3",
},
{
Type: DiffTypeAdded,
Name: "VaultGrace",
Old: "",
New: "10000000000",
},
},
},
{
@@ -5820,12 +5810,6 @@ func TestTaskDiff(t *testing.T) {
Old: "2",
New: "",
},
{
Type: DiffTypeDeleted,
Name: "VaultGrace",
Old: "5000000000",
New: "",
},
},
},
},

View File

@@ -5829,6 +5829,24 @@ func (t *Task) Warnings() error {
mErr.Errors = append(mErr.Errors, fmt.Errorf("IOPS has been deprecated as of Nomad 0.9.0. Please remove IOPS from resource stanza."))
}
for idx, tmpl := range t.Templates {
if err := tmpl.Warnings(); err != nil {
err = multierror.Prefix(err, fmt.Sprintf("Template[%d]", idx))
mErr.Errors = append(mErr.Errors, err)
}
}
return mErr.ErrorOrNil()
}
func (t *Template) Warnings() error {
var mErr multierror.Error
// Deprecation notice for vault_grace
if t.VaultGrace > 0 {
mErr.Errors = append(mErr.Errors, fmt.Errorf("VaultGrace has been deprecated as of Nomad 0.11 and ignored since Vault 0.5. Please remove VaultGrace / vault_grace from template stanza."))
}
return mErr.ErrorOrNil()
}
@@ -5964,6 +5982,7 @@ type Template struct {
// VaultGrace is the grace duration between lease renewal and reacquiring a
// secret. If the lease of a secret is less than the grace, a new secret is
// acquired.
// COMPAT(0.12) VaultGrace has been ignored by Vault since Vault v0.5.
VaultGrace time.Duration
}
@@ -6038,10 +6057,6 @@ func (t *Template) Validate() error {
}
}
if t.VaultGrace.Nanoseconds() < 0 {
multierror.Append(&mErr, fmt.Errorf("Vault grace must be greater than zero: %v < 0", t.VaultGrace))
}
return mErr.ErrorOrNil()
}

View File

@@ -1,9 +1,40 @@
## v0.24.1 (Jan 24, 2020)
BUG FIXES:
* Make user non-numeric to satisfy PSP [GH-1332](https://github.com/hashicorp/consul-template/pull/1332)
* fatal error: PowerRegisterSuspendResumeNotification failure on windows [GH-1335](https://github.com/hashicorp/consul-template/issues/1335)
## v0.24.0 (Jan 08, 2020)
BREAKING CHANGES:
* Alpine Docker image no longer runs as root and so doesn't change ownership of the /consul-template/data and /consul-template/config directories to the consul-template user. See the [Docker Image Use](https://github.com/hashicorp/consul-template#docker-image-use) topic in the documentation for more.
BUG FIXES:
* arm builds are linked against wrong library [[GH-1317](https://github.com/hashicorp/consul-template/issues/1317), [GH-1326](https://github.com/hashicorp/consul-template/pull/1326)]
* consul-template container runs as root - breaks CISO compliance [[GH-1321](https://github.com/hashicorp/consul-template/issues/1321), [GH-1324](https://github.com/hashicorp/consul-template/pull/1324)]
* 'sockaddr' function returning whitespace after address [[GH-1314](https://github.com/hashicorp/consul-template/issues/1314), [GH-1315](https://github.com/hashicorp/consul-template/pull/1315)]
* runTemplate - DEBUG logging is needed to identify missing dependencies [[GH-1308](https://github.com/hashicorp/consul-template/issues/1308), [GH-1309](https://github.com/hashicorp/consul-template/pull/1309)]
* Remove code/logic for working with (long deprecated) Vault grace [[GH-1284](https://github.com/hashicorp/consul-template/pull/1284)]
## v0.23.0 (Nov 13, 2019)
IMPROVEMENTS:
* Support Configuring Consul Connect Clients [[GH-1262](https://github.com/hashicorp/consul-template/issues/1262), [GH-1304](https://github.com/hashicorp/consul-template/pull/1304), [GH-1306](https://github.com/hashicorp/consul-template/pull/1306)]
## v0.22.1 (Nov 08, 2019)
SECURITY:
* curl is vulnerable in the latest alpine docker image [[GH-1302](https://github.com/hashicorp/consul-template/issues/1302)]
BUG FIXES:
* fix breaking change for loop [[GH-1285](https://github.com/hashicorp/consul-template/issues/1285)]
## v0.22.0 (September 10, 2019)
IMPROVEMENTS:

View File

@@ -29,7 +29,7 @@ GOARCH ?= $(shell go env GOARCH)
XC_OS ?= darwin freebsd linux netbsd openbsd solaris windows
XC_ARCH ?= 386 amd64 arm arm64
# XC_EXCLUDE "arm64" entries excludes both arm and arm64
XC_EXCLUDE ?= darwin/arm64 freebsd/arm64 netbsd/arm64 openbsd/arm64 solaris/386 solaris/arm64 windows/arm64
XC_EXCLUDE ?= darwin/arm64 freebsd/arm64 netbsd/arm64 openbsd/arm64 solaris/arm64 windows/arm64 solaris/386
# GPG Signing key (blank by default, means no GPG signing)
GPG_KEY ?=
@@ -55,8 +55,8 @@ define make-xc-target
@printf "%s%20s %s\n" "-->" "${1}/${2}:" "${PROJECT}"
case "$2" in \
arm) export CGO_ENABLED="1" ; \
export GOARM=5 \
export CC="arm-linux-gnueabi-gcc" ;; \
export GOARM=6 \
export CC="arm-linux-gnueabihf-gcc" ;; \
arm64) export CGO_ENABLED="1" ; \
export CC="aarch64-linux-gnu-gcc" ;; \
*) export CGO_ENABLED="0" ;; \

View File

@@ -30,6 +30,9 @@ this functionality might prove useful.
- [Configuration File Format](#configuration-file-format)
- [Templating Language](#templating-language)
- [API Functions](#api-functions)
- [caLeaf](#caleaf)
- [caRoot](#caroot)
- [connect](#connect)
- [datacenters](#datacenters)
- [file](#file)
- [key](#key)
@@ -511,7 +514,7 @@ exec {
# This defines the signal sent to the child process when Consul Template is
# gracefully shutting down. The application should begin a graceful cleanup.
# If the application does not terminate before the `kill_timeout`, it will
# be terminated (effectively "kill -9"). The default value is "SIGTERM".
# be terminated (effectively "kill -9"). The default value is "SIGINT".
kill_signal = "SIGINT"
# This defines the amount of time to wait for the child process to gracefully
@@ -639,6 +642,87 @@ provides the following functions:
API functions interact with remote API calls, communicating with external
services like [Consul][consul] and [Vault][vault].
##### `caLeaf`
Query [Consul][consul] for the leaf certificate representing a single service.
```liquid
{{ caLeaf "<NAME>" }}
```
For example:
```liquid
{{ with caLeaf "proxy" }}{{ .CertPEM }}{{ end }}
```
renders
```text
-----BEGIN CERTIFICATE-----
MIICizCCAjGgAwIBAgIBCDAKBggqhkjOPQQDAjAWMRQwEgYDVQQDEwtDb25zdWwg
...
lXcQzfKlIYeFWvcAv4cA4W258gTtqaFRDRJ2i720eQ==
-----END CERTIFICATE-----
```
The two most useful fields are `.CertPEM` and `.PrivateKeyPEM`. For a complete
list of available fields, see consul's documentation on
[LeafCert](https://godoc.org/github.com/hashicorp/consul/api#LeafCert).
##### `caRoot`
Query [Consul][consul] for all [connect][connect] trusted certificate authority
(CA) root certificates.
```liquid
{{ caRoots }}
```
For example:
```liquid
{{ range caRoots }}{{ .RootCertPEM }}{{ end }}
```
renders
```text
-----BEGIN CERTIFICATE-----
MIICWDCCAf+gAwIBAgIBBzAKBggqhkjOPQQDAjAWMRQwEgYDVQQDEwtDb25zdWwg
...
bcA+Su3r8qSRppTlc6D0UOYOWc1ykQKQOK7mIg==
-----END CERTIFICATE-----
```
The most useful field is `.RootCertPEM`. For a complete list of available
fields, see consul's documentation on
[CARootList](https://godoc.org/github.com/hashicorp/consul/api#CARootList).
##### `connect`
Query [Consul][consul] for [connect][connect]-capable services based on their
health.
```liquid
{{ connect "<TAG>.<NAME>@<DATACENTER>~<NEAR>|<FILTER>" }}
```
Syntax is exactly the same as for the [service](#service) function below.
```liquid
{{ range connect "web" }}
server {{ .Name }} {{ .Address }}:{{ .Port }}{{ end }}
```
renders the IP addresses of all _healthy_ nodes with a logical
[connect][connect]-capable service named "web":
```text
server web01 10.5.2.45:21000
server web02 10.2.6.61:21000
```
##### `datacenters`
Query [Consul][consul] for all datacenters in its catalog.
@@ -2090,6 +2174,26 @@ func main() {
## Caveats
### Docker Image Use
The Alpine Docker image is configured to support an external volume to render
shared templates to. If mounted you will need to make sure that the
consul-template user in the docker image has write permissions to the
directory. Also if you build your own image using these you need to be sure you
have the permissions correct.
**The consul-template user in docker has a UID of 100 and a GID of 1000.**
This effects the in image directories /consul-template/config, used to add
configuration when using this as a parent image, and /consul-template/data,
exported as a VOLUME as a location to render shared results.
Previously the image initially ran as root in order to ensure the permissions
allowed it. But this ran against docker best practices and security policies.
If you build your own image based on ours you can override these values with
`--build-arg` parameters.
### Dots in Service Names
Using dots `.` in service names will conflict with the use of dots for [TAG
@@ -2422,7 +2526,7 @@ A: Configuration management tools are designed to be used in unison with Consul
## Contributing
To build and install Envconsul locally, you will need to [install Go][go].
To build and install Consul-Template locally, you will need to [install Go][go].
Clone the repository:
@@ -2459,6 +2563,7 @@ go test ./... -run SomeTestFunction_name
```
[consul]: https://www.consul.io "Consul by HashiCorp"
[connect]: https://www.consul.io/docs/connect/ "Connect"
[examples]: (https://github.com/hashicorp/consul-template/tree/master/examples) "Consul Template Examples"
[hcl]: https://github.com/hashicorp/hcl "HashiCorp Configuration Language (hcl)"
[releases]: https://releases.hashicorp.com/consul-template "Consul Template Releases"

View File

@@ -423,11 +423,6 @@ func (cli *CLI) ParseFlags(args []string) (
return nil
}), "vault-addr", "")
flags.Var((funcDurationVar)(func(t time.Duration) error {
c.Vault.Grace = config.TimeDuration(t)
return nil
}), "vault-grace", "")
flags.Var((funcBoolVar)(func(b bool) error {
c.Vault.RenewToken = config.Bool(b)
return nil

View File

@@ -40,8 +40,7 @@ type ExecConfig struct {
// EnvConfig is the environmental customizations.
Env *EnvConfig `mapstructure:"env"`
// KillSignal is the signal to send to the command to kill it gracefully. The
// default value is "SIGTERM".
// KillSignal is the signal to send to the command to kill it gracefully.
KillSignal *os.Signal `mapstructure:"kill_signal"`
// KillTimeout is the amount of time to give the process to cleanup before

View File

@@ -12,11 +12,6 @@ const (
// vault to version 1.1.0 or newer.
EnvVaultSkipVerify = "VAULT_SKIP_VERIFY"
// DefaultVaultGrace is the default grace period before which to read a new
// secret from Vault. If a lease is due to expire in 15 seconds, Consul
// Template will read a new secret at that time minus this value.
DefaultVaultGrace = 15 * time.Second
// DefaultVaultRenewToken is the default value for if the Vault token should
// be renewed.
DefaultVaultRenewToken = true
@@ -42,10 +37,6 @@ type VaultConfig struct {
// Enabled controls whether the Vault integration is active.
Enabled *bool `mapstructure:"enabled"`
// Grace is the amount of time before a lease is about to expire to force a
// new secret to be read.
Grace *time.Duration `mapstructure:"grace"`
// Namespace is the Vault namespace to use for reading/writing secrets. This can
// also be set via the VAULT_NAMESPACE environment variable.
Namespace *string `mapstructure:"namespace"`
@@ -104,8 +95,6 @@ func (c *VaultConfig) Copy() *VaultConfig {
o.Enabled = c.Enabled
o.Grace = c.Grace
o.Namespace = c.Namespace
o.RenewToken = c.RenewToken
@@ -157,10 +146,6 @@ func (c *VaultConfig) Merge(o *VaultConfig) *VaultConfig {
r.Enabled = o.Enabled
}
if o.Grace != nil {
r.Grace = o.Grace
}
if o.Namespace != nil {
r.Namespace = o.Namespace
}
@@ -204,10 +189,6 @@ func (c *VaultConfig) Finalize() {
}, "")
}
if c.Grace == nil {
c.Grace = TimeDuration(DefaultVaultGrace)
}
if c.Namespace == nil {
c.Namespace = stringFromEnv([]string{"VAULT_NAMESPACE"}, "")
}
@@ -302,7 +283,6 @@ func (c *VaultConfig) GoString() string {
return fmt.Sprintf("&VaultConfig{"+
"Address:%s, "+
"Enabled:%s, "+
"Grace:%s, "+
"Namespace:%s,"+
"RenewToken:%s, "+
"Retry:%#v, "+
@@ -314,7 +294,6 @@ func (c *VaultConfig) GoString() string {
"}",
StringGoString(c.Address),
BoolGoString(c.Enabled),
TimeDurationGoString(c.Grace),
StringGoString(c.Namespace),
BoolGoString(c.RenewToken),
c.Retry,

View File

@@ -0,0 +1,72 @@
package dependency
import (
"log"
"net/url"
"github.com/pkg/errors"
)
var (
// Ensure implements
_ Dependency = (*ConnectCAQuery)(nil)
)
type ConnectCAQuery struct {
stopCh chan struct{}
}
func NewConnectCAQuery() *ConnectCAQuery {
return &ConnectCAQuery{
stopCh: make(chan struct{}, 1),
}
}
func (d *ConnectCAQuery) Fetch(clients *ClientSet, opts *QueryOptions) (
interface{}, *ResponseMetadata, error,
) {
select {
case <-d.stopCh:
return nil, nil, ErrStopped
default:
}
opts = opts.Merge(nil)
log.Printf("[TRACE] %s: GET %s", d, &url.URL{
Path: "/v1/agent/connect/ca/roots",
RawQuery: opts.String(),
})
certs, md, err := clients.Consul().Agent().ConnectCARoots(
opts.ToConsulOpts())
if err != nil {
return nil, nil, errors.Wrap(err, d.String())
}
log.Printf("[TRACE] %s: returned %d results", d, len(certs.Roots))
log.Printf("[TRACE] %s: %#v ", d, md)
rm := &ResponseMetadata{
LastIndex: md.LastIndex,
LastContact: md.LastContact,
Block: true,
}
return certs.Roots, rm, nil
}
func (d *ConnectCAQuery) Stop() {
close(d.stopCh)
}
func (d *ConnectCAQuery) CanShare() bool {
return false
}
func (d *ConnectCAQuery) Type() Type {
return TypeConsul
}
func (d *ConnectCAQuery) String() string {
return "connect.caroots"
}

View File

@@ -0,0 +1,77 @@
package dependency
import (
"fmt"
"log"
"net/url"
"github.com/pkg/errors"
)
var (
// Ensure implements
_ Dependency = (*ConnectLeafQuery)(nil)
)
type ConnectLeafQuery struct {
stopCh chan struct{}
service string
}
func NewConnectLeafQuery(service string) *ConnectLeafQuery {
return &ConnectLeafQuery{
stopCh: make(chan struct{}, 1),
service: service,
}
}
func (d *ConnectLeafQuery) Fetch(clients *ClientSet, opts *QueryOptions) (
interface{}, *ResponseMetadata, error,
) {
select {
case <-d.stopCh:
return nil, nil, ErrStopped
default:
}
opts = opts.Merge(nil)
log.Printf("[TRACE] %s: GET %s", d, &url.URL{
Path: "/v1/agent/connect/ca/leaf/" + d.service,
RawQuery: opts.String(),
})
cert, md, err := clients.Consul().Agent().ConnectCALeaf(d.service,
opts.ToConsulOpts())
if err != nil {
return nil, nil, errors.Wrap(err, d.String())
}
log.Printf("[TRACE] %s: returned response", d)
rm := &ResponseMetadata{
LastIndex: md.LastIndex,
LastContact: md.LastContact,
Block: true,
}
return cert, rm, nil
}
func (d *ConnectLeafQuery) Stop() {
close(d.stopCh)
}
func (d *ConnectLeafQuery) CanShare() bool {
return false
}
func (d *ConnectLeafQuery) Type() Type {
return TypeConsul
}
func (d *ConnectLeafQuery) String() string {
if d.service != "" {
return fmt.Sprintf("connect.caleaf(%s)", d.service)
}
return "connect.caleaf"
}

View File

@@ -62,10 +62,20 @@ type HealthServiceQuery struct {
name string
near string
tag string
connect bool
}
// NewHealthServiceQuery processes the strings to build a service dependency.
func NewHealthServiceQuery(s string) (*HealthServiceQuery, error) {
return healthServiceQuery(s, false)
}
// NewHealthConnect Query processes the strings to build a connect dependency.
func NewHealthConnectQuery(s string) (*HealthServiceQuery, error) {
return healthServiceQuery(s, true)
}
func healthServiceQuery(s string, connect bool) (*HealthServiceQuery, error) {
if !HealthServiceQueryRe.MatchString(s) {
return nil, fmt.Errorf("health.service: invalid format: %q", s)
}
@@ -86,7 +96,8 @@ func NewHealthServiceQuery(s string) (*HealthServiceQuery, error) {
filters = append(filters, f)
case "":
default:
return nil, fmt.Errorf("health.service: invalid filter: %q in %q", f, s)
return nil, fmt.Errorf(
"health.service: invalid filter: %q in %q", f, s)
}
}
sort.Strings(filters)
@@ -101,6 +112,7 @@ func NewHealthServiceQuery(s string) (*HealthServiceQuery, error) {
name: m["name"],
near: m["near"],
tag: m["tag"],
connect: connect,
}, nil
}
@@ -130,10 +142,15 @@ func (d *HealthServiceQuery) Fetch(clients *ClientSet, opts *QueryOptions) (inte
log.Printf("[TRACE] %s: GET %s", d, u)
// Check if a user-supplied filter was given. If so, we may be querying for
// more than healthy services, so we need to implement client-side filtering.
// more than healthy services, so we need to implement client-side
// filtering.
passingOnly := len(d.filters) == 1 && d.filters[0] == HealthPassing
entries, qm, err := clients.Consul().Health().Service(d.name, d.tag, passingOnly, opts.ToConsulOpts())
nodes := clients.Consul().Health().Service
if d.connect {
nodes = clients.Consul().Health().Connect
}
entries, qm, err := nodes(d.name, d.tag, passingOnly, opts.ToConsulOpts())
if err != nil {
return nil, nil, errors.Wrap(err, d.String())
}
@@ -145,13 +162,14 @@ func (d *HealthServiceQuery) Fetch(clients *ClientSet, opts *QueryOptions) (inte
// Get the status of this service from its checks.
status := entry.Checks.AggregatedStatus()
// If we are not checking only healthy services, filter out services that do
// not match the given filter.
// If we are not checking only healthy services, filter out services
// that do not match the given filter.
if !acceptStatus(d.filters, status) {
continue
}
// Get the address of the service, falling back to the address of the node.
// Get the address of the service, falling back to the address of the
// node.
address := entry.Service.Address
if address == "" {
address = entry.Node.Address
@@ -167,10 +185,11 @@ func (d *HealthServiceQuery) Fetch(clients *ClientSet, opts *QueryOptions) (inte
Address: address,
ID: entry.Service.ID,
Name: entry.Service.Service,
Tags: ServiceTags(deepCopyAndSortTags(entry.Service.Tags)),
Status: status,
Checks: entry.Checks,
Port: entry.Service.Port,
Tags: ServiceTags(
deepCopyAndSortTags(entry.Service.Tags)),
Status: status,
Checks: entry.Checks,
Port: entry.Service.Port,
})
}

View File

@@ -691,12 +691,20 @@ func (r *Runner) runTemplate(tmpl *template.Template, runCtx *templateRunCtx) (*
// Grab the list of used and missing dependencies.
missing, used := result.Missing, result.Used
if l := missing.Len(); l > 0 {
log.Printf("[DEBUG] (runner) missing data for %d dependencies", l)
for _, missingDependency := range missing.List() {
log.Printf("[DEBUG] (runner) missing dependency: %s", missingDependency)
}
}
// Add the dependency to the list of dependencies for this runner.
for _, d := range used.List() {
// If we've taken over leadership for a template, we may have data
// that is cached, but not have the watcher. We must treat this as
// missing so that we create the watcher and re-run the template.
if isLeader && !r.watcher.Watching(d) {
log.Printf("[DEBUG] (runner) add used dependency %s to missing since isLeader but do not have a watcher", d)
missing.Add(d)
}
if _, ok := runCtx.depsMap[d.String()]; !ok {
@@ -1295,7 +1303,6 @@ func newWatcher(c *config.Config, clients *dep.ClientSet, once bool) (*watch.Wat
// dependencies like reading a file from disk.
RetryFuncDefault: nil,
RetryFuncVault: watch.RetryFunc(c.Vault.Retry.RetryFunc()),
VaultGrace: config.TimeDurationVal(c.Vault.Grace),
VaultToken: clients.Vault().Token(),
})
if err != nil {

View File

@@ -19,6 +19,7 @@ import (
"github.com/BurntSushi/toml"
dep "github.com/hashicorp/consul-template/dependency"
"github.com/hashicorp/consul/api"
socktmpl "github.com/hashicorp/go-sockaddr/template"
"github.com/pkg/errors"
yaml "gopkg.in/yaml.v2"
@@ -472,6 +473,62 @@ func servicesFunc(b *Brain, used, missing *dep.Set) func(...string) ([]*dep.Cata
}
}
// connectFunc returns or accumulates health connect dependencies.
func connectFunc(b *Brain, used, missing *dep.Set) func(...string) ([]*dep.HealthService, error) {
return func(s ...string) ([]*dep.HealthService, error) {
result := []*dep.HealthService{}
if len(s) == 0 || s[0] == "" {
return result, nil
}
d, err := dep.NewHealthConnectQuery(strings.Join(s, "|"))
if err != nil {
return nil, err
}
used.Add(d)
if value, ok := b.Recall(d); ok {
return value.([]*dep.HealthService), nil
}
missing.Add(d)
return result, nil
}
}
func connectCARootsFunc(b *Brain, used, missing *dep.Set,
) func(...string) ([]*api.CARoot, error) {
return func(...string) ([]*api.CARoot, error) {
d := dep.NewConnectCAQuery()
used.Add(d)
if value, ok := b.Recall(d); ok {
return value.([]*api.CARoot), nil
}
missing.Add(d)
return nil, nil
}
}
func connectLeafFunc(b *Brain, used, missing *dep.Set,
) func(...string) (*api.LeafCert, error) {
return func(s ...string) (*api.LeafCert, error) {
if len(s) == 0 || s[0] == "" {
return nil, nil
}
d := dep.NewConnectLeafQuery(s[0])
used.Add(d)
if value, ok := b.Recall(d); ok {
return value.(*api.LeafCert), nil
}
missing.Add(d)
return nil, nil
}
}
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)
@@ -1315,7 +1372,7 @@ func pathInSandbox(sandbox, path string) error {
// sockaddr wraps go-sockaddr templating
func sockaddr(args ...string) (string, error) {
t := fmt.Sprintf("{{ %s }} ", strings.Join(args, " "))
t := fmt.Sprintf("{{ %s }}", strings.Join(args, " "))
k, err := socktmpl.Parse(t)
if err != nil {
return "", err

View File

@@ -237,9 +237,12 @@ func funcMap(i *funcMapInput) template.FuncMap {
"secret": secretFunc(i.brain, i.used, i.missing),
"secrets": secretsFunc(i.brain, i.used, i.missing),
"service": serviceFunc(i.brain, i.used, i.missing),
"connect": connectFunc(i.brain, i.used, i.missing),
"services": servicesFunc(i.brain, i.used, i.missing),
"tree": treeFunc(i.brain, i.used, i.missing, true),
"safeTree": safeTreeFunc(i.brain, i.used, i.missing),
"caRoots": connectCARootsFunc(i.brain, i.used, i.missing),
"caLeaf": connectLeafFunc(i.brain, i.used, i.missing),
// Scratch
"scratch": func() *Scratch { return &scratch },

View File

@@ -2,7 +2,7 @@ package version
import "fmt"
const Version = "0.22.1"
const Version = "0.24.1"
var (
Name string

View File

@@ -45,11 +45,6 @@ type View struct {
// stopCh is used to stop polling on this View
stopCh chan struct{}
// vaultGrace is the grace period between a lease and the max TTL for which
// Consul Template will generate a new secret instead of renewing an existing
// one.
vaultGrace time.Duration
}
// NewViewInput is used as input to the NewView function.
@@ -71,11 +66,6 @@ type NewViewInput struct {
// RetryFunc is a function which dictates how this view should retry on
// upstream errors.
RetryFunc RetryFunc
// VaultGrace is the grace period between a lease and the max TTL for which
// Consul Template will generate a new secret instead of renewing an existing
// one.
VaultGrace time.Duration
}
// NewView constructs a new view with the given inputs.
@@ -87,7 +77,6 @@ func NewView(i *NewViewInput) (*View, error) {
once: i.Once,
retryFunc: i.RetryFunc,
stopCh: make(chan struct{}, 1),
vaultGrace: i.VaultGrace,
}, nil
}
@@ -214,7 +203,6 @@ func (v *View) fetch(doneCh, successCh chan<- struct{}, errCh chan<- error) {
AllowStale: allowStale,
WaitTime: defaultWaitTime,
WaitIndex: v.lastIndex,
VaultGrace: v.vaultGrace,
})
if err != nil {
if err == dep.ErrStopped {

View File

@@ -42,11 +42,6 @@ type Watcher struct {
retryFuncConsul RetryFunc
retryFuncDefault RetryFunc
retryFuncVault RetryFunc
// vaultGrace is the grace period between a lease and the max TTL for which
// Consul Template will generate a new secret instead of renewing an existing
// one.
vaultGrace time.Duration
}
type NewWatcherInput struct {
@@ -72,11 +67,6 @@ type NewWatcherInput struct {
RetryFuncConsul RetryFunc
RetryFuncDefault RetryFunc
RetryFuncVault RetryFunc
// VaultGrace is the grace period between a lease and the max TTL for which
// Consul Template will generate a new secret instead of renewing an existing
// one.
VaultGrace time.Duration
}
// NewWatcher creates a new watcher using the given API client.
@@ -91,7 +81,6 @@ func NewWatcher(i *NewWatcherInput) (*Watcher, error) {
retryFuncConsul: i.RetryFuncConsul,
retryFuncDefault: i.RetryFuncDefault,
retryFuncVault: i.RetryFuncVault,
vaultGrace: i.VaultGrace,
}
// Start a watcher for the Vault renew if that config was specified
@@ -165,7 +154,6 @@ func (w *Watcher) Add(d dep.Dependency) (bool, error) {
MaxStale: w.maxStale,
Once: w.once,
RetryFunc: retryFunc,
VaultGrace: w.vaultGrace,
})
if err != nil {
return false, errors.Wrap(err, "watcher")

23
vendor/vendor.json vendored
View File

@@ -193,18 +193,17 @@
{"path":"github.com/gorilla/context","checksumSHA1":"g/V4qrXjUGG9B+e3hB+4NAYJ5Gs=","revision":"08b5f424b9271eedf6f9f0ce86cb9396ed337a42","revisionTime":"2016-08-17T18:46:32Z"},
{"path":"github.com/gorilla/mux","checksumSHA1":"STQSdSj2FcpCf0NLfdsKhNutQT0=","revision":"e48e440e4c92e3251d812f8ce7858944dfa3331c","revisionTime":"2018-08-07T07:52:56Z"},
{"path":"github.com/gorilla/websocket","checksumSHA1":"gr0edNJuVv4+olNNZl5ZmwLgscA=","revision":"0ec3d1bd7fe50c503d6df98ee649d81f4857c564","revisionTime":"2019-03-06T00:42:57Z"},
{"path":"github.com/hashicorp/consul-template","checksumSHA1":"fmltp5DcXXO4cec5ZX19GcerHDw=","revision":"f04989c64e9bd4c49a7217ac4635732dd8e0bb26","revisionTime":"2019-11-08T20:12:44Z","version":"v0.22.1","versionExact":"v0.22.1"},
{"path":"github.com/hashicorp/consul-template/child","checksumSHA1":"yQfiSUOpV5BvGeztDd4fcA7qsbw=","revision":"f04989c64e9bd4c49a7217ac4635732dd8e0bb26","revisionTime":"2019-11-08T20:12:44Z","version":"v0.22.1","versionExact":"v0.22.1"},
{"path":"github.com/hashicorp/consul-template/config","checksumSHA1":"hjsBe5Qnn0DCttJkSNjy9mreW5Q=","revision":"f04989c64e9bd4c49a7217ac4635732dd8e0bb26","revisionTime":"2019-11-08T20:12:44Z","version":"v0.22.1","versionExact":"v0.22.1"},
{"path":"github.com/hashicorp/consul-template/conrfig","revision":"v0.22.1","version":"v0.22.1","versionExact":"v0.22.1"},
{"path":"github.com/hashicorp/consul-template/dependency","checksumSHA1":"6Tni+iVTu73EHriUDFaFJXyZzvM=","revision":"f04989c64e9bd4c49a7217ac4635732dd8e0bb26","revisionTime":"2019-11-08T20:12:44Z","version":"v0.22.1","versionExact":"v0.22.1"},
{"path":"github.com/hashicorp/consul-template/logging","checksumSHA1":"o5N7SV389Ej+3b1iRNmz1dx5e1M=","revision":"f04989c64e9bd4c49a7217ac4635732dd8e0bb26","revisionTime":"2019-11-08T20:12:44Z","version":"v0.22.1","versionExact":"v0.22.1"},
{"path":"github.com/hashicorp/consul-template/manager","checksumSHA1":"BFPu1t60WuMR7HyUSR0nI6IvbA0=","revision":"f04989c64e9bd4c49a7217ac4635732dd8e0bb26","revisionTime":"2019-11-08T20:12:44Z","version":"v0.22.1","versionExact":"v0.22.1"},
{"path":"github.com/hashicorp/consul-template/renderer","checksumSHA1":"zgTxCql4T0tvDUIMM+EQD6R/tEg=","revision":"f04989c64e9bd4c49a7217ac4635732dd8e0bb26","revisionTime":"2019-11-08T20:12:44Z","version":"v0.22.1","versionExact":"v0.22.1"},
{"path":"github.com/hashicorp/consul-template/signals","checksumSHA1":"YSEUV/9/k85XciRKu0cngxdjZLE=","revision":"f04989c64e9bd4c49a7217ac4635732dd8e0bb26","revisionTime":"2019-11-08T20:12:44Z","version":"v0.22.1","versionExact":"v0.22.1"},
{"path":"github.com/hashicorp/consul-template/template","checksumSHA1":"/AjvyyxEZXksXgxm1gmdJdJoXkw=","revision":"f04989c64e9bd4c49a7217ac4635732dd8e0bb26","revisionTime":"2019-11-08T20:12:44Z","version":"v0.22.1","versionExact":"v0.22.1"},
{"path":"github.com/hashicorp/consul-template/version","checksumSHA1":"CqEejkuDiTgPVrLg0xrMmAWvNwY=","revision":"f04989c64e9bd4c49a7217ac4635732dd8e0bb26","revisionTime":"2019-11-08T20:12:44Z","version":"v0.22.1","versionExact":"v0.22.1"},
{"path":"github.com/hashicorp/consul-template/watch","checksumSHA1":"cBIJewG416sFREUenIUK9v3zrUk=","revision":"f04989c64e9bd4c49a7217ac4635732dd8e0bb26","revisionTime":"2019-11-08T20:12:44Z","version":"v0.22.1","versionExact":"v0.22.1"},
{"path":"github.com/hashicorp/consul-template","checksumSHA1":"R4eLvAFtqPg22sjAUysBhFfdUPs=","revision":"58aa6c608af3387d0c2bf5d028be4960be1dbe56","revisionTime":"2020-01-25T00:24:05Z","version":"v0.24.1","versionExact":"v0.24.1"},
{"path":"github.com/hashicorp/consul-template/child","checksumSHA1":"yQfiSUOpV5BvGeztDd4fcA7qsbw=","revision":"58aa6c608af3387d0c2bf5d028be4960be1dbe56","revisionTime":"2020-01-25T00:24:05Z","version":"v0.24.1","versionExact":"v0.24.1"},
{"path":"github.com/hashicorp/consul-template/config","checksumSHA1":"ldDPZxD2PEPY4F9MFSOG4D8FWo8=","revision":"58aa6c608af3387d0c2bf5d028be4960be1dbe56","revisionTime":"2020-01-25T00:24:05Z","version":"v0.24.1","versionExact":"v0.24.1"},
{"path":"github.com/hashicorp/consul-template/dependency","checksumSHA1":"nr5sxKesvUIvgfLerh3itYdy35o=","revision":"58aa6c608af3387d0c2bf5d028be4960be1dbe56","revisionTime":"2020-01-25T00:24:05Z","version":"v0.24.1","versionExact":"v0.24.1"},
{"path":"github.com/hashicorp/consul-template/logging","checksumSHA1":"o5N7SV389Ej+3b1iRNmz1dx5e1M=","revision":"58aa6c608af3387d0c2bf5d028be4960be1dbe56","revisionTime":"2020-01-25T00:24:05Z","version":"v0.24.1","versionExact":"v0.24.1"},
{"path":"github.com/hashicorp/consul-template/manager","checksumSHA1":"ruoKjffTXwMv4NWk6emZQ6UAu5Y=","revision":"58aa6c608af3387d0c2bf5d028be4960be1dbe56","revisionTime":"2020-01-25T00:24:05Z","version":"v0.24.1","versionExact":"v0.24.1"},
{"path":"github.com/hashicorp/consul-template/renderer","checksumSHA1":"zgTxCql4T0tvDUIMM+EQD6R/tEg=","revision":"58aa6c608af3387d0c2bf5d028be4960be1dbe56","revisionTime":"2020-01-25T00:24:05Z","version":"v0.24.1","versionExact":"v0.24.1"},
{"path":"github.com/hashicorp/consul-template/signals","checksumSHA1":"YSEUV/9/k85XciRKu0cngxdjZLE=","revision":"58aa6c608af3387d0c2bf5d028be4960be1dbe56","revisionTime":"2020-01-25T00:24:05Z","version":"v0.24.1","versionExact":"v0.24.1"},
{"path":"github.com/hashicorp/consul-template/template","checksumSHA1":"8SvvLvFN6Xo1OIWAf7f7D8co1VQ=","revision":"58aa6c608af3387d0c2bf5d028be4960be1dbe56","revisionTime":"2020-01-25T00:24:05Z","version":"v0.24.1","versionExact":"v0.24.1"},
{"path":"github.com/hashicorp/consul-template/version","checksumSHA1":"jp7uP07VhT4HXN3Qt9Sadg39oGs=","revision":"58aa6c608af3387d0c2bf5d028be4960be1dbe56","revisionTime":"2020-01-25T00:24:05Z","version":"v0.24.1","versionExact":"v0.24.1"},
{"path":"github.com/hashicorp/consul-template/watch","checksumSHA1":"JEl5zNIf+Lp6iABBfsDG7xVhwrc=","revision":"58aa6c608af3387d0c2bf5d028be4960be1dbe56","revisionTime":"2020-01-25T00:24:05Z","version":"v0.24.1","versionExact":"v0.24.1"},
{"path":"github.com/hashicorp/consul/agent/consul/autopilot","checksumSHA1":"lu2pzUDqU0jwul48T6IkTZK9Gxc=","revision":"b137060630b463d7ad5360f0d8f32f9347ae3b7d","revisionTime":"2020-02-13T19:55:27Z"},
{"path":"github.com/hashicorp/consul/api","checksumSHA1":"N8Br+KaZ4HRAmTYIpAKOzuk+hHo=","revision":"b137060630b463d7ad5360f0d8f32f9347ae3b7d","revisionTime":"2020-02-13T19:55:27Z"},
{"path":"github.com/hashicorp/consul/command/flags","checksumSHA1":"wC8+MhTwWmFDdSOHv1anqBo06GA=","revision":"b137060630b463d7ad5360f0d8f32f9347ae3b7d","revisionTime":"2020-02-13T19:55:27Z"},

View File

@@ -990,14 +990,7 @@ README][ct].
splay value before invoking the change mode. Should be specified in
nanoseconds.
- `VaultGrace` - Specifies the grace period between lease renewal and secret
re-acquisition. When renewing a secret, if the remaining lease is less than or
equal to the configured grace, the template will request a new credential.
This prevents Vault from revoking the secret at its expiration and the task
having a stale secret. If the grace is set to a value that is higher than your
default TTL or max TTL, the template will always read a new secret. If the
task defines several templates, the `vault_grace` will be set to the lowest
value across all the templates.
- `VaultGrace` - [Deprecated](https://github.com/hashicorp/consul-template/issues/1268)
```json
{

View File

@@ -87,18 +87,7 @@ README][ct]. Since Nomad v0.6.0, templates can be read as environment variables.
prevent a thundering herd problem where all task instances restart at the same
time.
- `vault_grace` `(string: "15s")` - Specifies the grace period between lease
renewal and secret re-acquisition. When renewing a secret, if the remaining
lease is less than or equal to the configured grace, the template will request
a new credential. This prevents Vault from revoking the secret at its
expiration and the task having a stale secret.
If the grace is set to a value that is higher than your default TTL or max
TTL, the template will always read a new secret. **If secrets are being
renewed constantly, decrease the `vault_grace`.**
If the task defines several templates, the `vault_grace` will be set to the
lowest value across all the templates.
- `vault_grace` `(string: "15s")` - [Deprecated](https://github.com/hashicorp/consul-template/issues/1268)
## `template` Examples

View File

@@ -15,6 +15,16 @@ details provided for their upgrades as a result of new features or changed
behavior. This page is used to document those details separately from the
standard upgrade flow.
## Nomad 0.11.0
### client.template: `vault_grace` deprecation
Nomad 0.11.0 includes an update to [consul-template](https://github.com/hashicorp/consul-template) v0.24.1.
This library deprecates the `vault_grace` option for templating included in nomad.
The feature has been ignored since vault 0.5 and as long as you are running
a more recent version of vault, you can safely remove vault_grace from your
nomad jobs.
## Nomad 0.10.4
### Same-Node Scheduling Penalty Removed