From eee850b1e6cc6023fe96ba474d66ce2d287f0956 Mon Sep 17 00:00:00 2001 From: Michael Schurter Date: Fri, 7 Jul 2017 14:42:31 -0700 Subject: [PATCH] Update consul-template --- .../consul-template/config/config.go | 52 --------- .../consul-template/config/template.go | 16 +++ .../hashicorp/consul-template/config/vault.go | 21 ++++ .../dependency/catalog_datacenters.go | 24 +++- .../consul-template/dependency/dependency.go | 15 +-- .../dependency/vault_common.go | 11 ++ .../consul-template/dependency/vault_read.go | 91 +++++++++------ .../consul-template/dependency/vault_token.go | 5 +- .../consul-template/dependency/vault_write.go | 104 +++++++++++------- .../consul-template/manager/runner.go | 10 +- .../consul-template/template/funcs.go | 17 ++- .../consul-template/template/template.go | 18 ++- .../hashicorp/consul-template/watch/view.go | 12 ++ .../consul-template/watch/watcher.go | 12 ++ vendor/vendor.json | 38 +++---- 15 files changed, 273 insertions(+), 173 deletions(-) diff --git a/vendor/github.com/hashicorp/consul-template/config/config.go b/vendor/github.com/hashicorp/consul-template/config/config.go index 5276dfde2..d8e91b40e 100644 --- a/vendor/github.com/hashicorp/consul-template/config/config.go +++ b/vendor/github.com/hashicorp/consul-template/config/config.go @@ -242,58 +242,6 @@ func Parse(s string) (*Config, error) { } } - // TODO: Deprecations - if vault, ok := parsed["vault"].(map[string]interface{}); ok { - if val, ok := vault["renew"]; ok { - log.Println(`[WARN] vault.renew has been renamed to vault.renew_token. ` + - `Update your configuration files and change "renew" to "renew_token".`) - vault["renew_token"] = val - delete(vault, "renew") - } - } - - if auth, ok := parsed["auth"].(map[string]interface{}); ok { - log.Println("[WARN] auth has been moved under the consul stanza. " + - "Update your configuration files and place auth inside consul { }.") - if _, ok := parsed["consul"]; !ok { - parsed["consul"] = make(map[string]interface{}) - } - parsed["consul"].(map[string]interface{})["auth"] = auth - delete(parsed, "auth") - } - - if retry, ok := parsed["retry"].(string); ok { - log.Println("[WARN] retry has been moved under the consul stanza. " + - "Update your configuration files and place retry inside consul { }.") - if _, ok := parsed["consul"]; !ok { - parsed["consul"] = make(map[string]interface{}) - } - parsed["consul"].(map[string]interface{})["retry"] = map[string]interface{}{ - "backoff": retry, - } - delete(parsed, "retry") - } - - if ssl, ok := parsed["ssl"].(map[string]interface{}); ok { - log.Println("[WARN] ssl has been moved under the consul stanza. " + - "Update your configuration files and place ssl inside consul { }.") - if _, ok := parsed["consul"]; !ok { - parsed["consul"] = make(map[string]interface{}) - } - parsed["consul"].(map[string]interface{})["ssl"] = ssl - delete(parsed, "ssl") - } - - if token, ok := parsed["token"].(string); ok { - log.Println("[WARN] token has been moved under the consul stanza. " + - "Update your configuration files and place token inside consul { }.") - if _, ok := parsed["consul"]; !ok { - parsed["consul"] = make(map[string]interface{}) - } - parsed["consul"].(map[string]interface{})["token"] = token - delete(parsed, "token") - } - // Create a new, empty config var c Config diff --git a/vendor/github.com/hashicorp/consul-template/config/template.go b/vendor/github.com/hashicorp/consul-template/config/template.go index 13ff1409c..982162d08 100644 --- a/vendor/github.com/hashicorp/consul-template/config/template.go +++ b/vendor/github.com/hashicorp/consul-template/config/template.go @@ -56,6 +56,10 @@ type TemplateConfig struct { // This is required unless running in debug/dry mode. Destination *string `mapstructure:"destination"` + // ErrMissingKey is used to control how the template behaves when attempting + // to index a struct or map key that does not exist. + ErrMissingKey *bool `mapstructure:"error_on_missing_key"` + // Exec is the configuration for the command to run when the template renders // successfully. Exec *ExecConfig `mapstructure:"exec"` @@ -105,6 +109,8 @@ func (c *TemplateConfig) Copy() *TemplateConfig { o.Destination = c.Destination + o.ErrMissingKey = c.ErrMissingKey + if c.Exec != nil { o.Exec = c.Exec.Copy() } @@ -161,6 +167,10 @@ func (c *TemplateConfig) Merge(o *TemplateConfig) *TemplateConfig { r.Destination = o.Destination } + if o.ErrMissingKey != nil { + r.ErrMissingKey = o.ErrMissingKey + } + if o.Exec != nil { r.Exec = r.Exec.Merge(o.Exec) } @@ -211,6 +221,10 @@ func (c *TemplateConfig) Finalize() { c.Destination = String("") } + if c.ErrMissingKey == nil { + c.ErrMissingKey = Bool(false) + } + if c.Exec == nil { c.Exec = DefaultExecConfig() } @@ -258,6 +272,7 @@ func (c *TemplateConfig) GoString() string { "CommandTimeout:%s, "+ "Contents:%s, "+ "Destination:%s, "+ + "ErrMissingKey:%s, "+ "Exec:%#v, "+ "Perms:%s, "+ "Source:%s, "+ @@ -270,6 +285,7 @@ func (c *TemplateConfig) GoString() string { TimeDurationGoString(c.CommandTimeout), StringGoString(c.Contents), StringGoString(c.Destination), + BoolGoString(c.ErrMissingKey), c.Exec, FileModeGoString(c.Perms), StringGoString(c.Source), diff --git a/vendor/github.com/hashicorp/consul-template/config/vault.go b/vendor/github.com/hashicorp/consul-template/config/vault.go index 762c31867..9a0cb7c11 100644 --- a/vendor/github.com/hashicorp/consul-template/config/vault.go +++ b/vendor/github.com/hashicorp/consul-template/config/vault.go @@ -8,6 +8,11 @@ import ( ) const ( + // DefaultVaultGrace is the default grace period before which to read a new + // secret from Vault. If a lease is due to expire in 5 minutes, 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 @@ -33,6 +38,10 @@ 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"` + // RenewToken renews the Vault token. RenewToken *bool `mapstructure:"renew_token"` @@ -80,6 +89,8 @@ func (c *VaultConfig) Copy() *VaultConfig { o.Enabled = c.Enabled + o.Grace = c.Grace + o.RenewToken = c.RenewToken if c.Retry != nil { @@ -127,6 +138,10 @@ func (c *VaultConfig) Merge(o *VaultConfig) *VaultConfig { r.Enabled = o.Enabled } + if o.Grace != nil { + r.Grace = o.Grace + } + if o.RenewToken != nil { r.RenewToken = o.RenewToken } @@ -162,6 +177,10 @@ func (c *VaultConfig) Finalize() { }, "") } + if c.Grace == nil { + c.Grace = TimeDuration(DefaultVaultGrace) + } + if c.RenewToken == nil { c.RenewToken = boolFromEnv([]string{ "VAULT_RENEW_TOKEN", @@ -239,6 +258,7 @@ func (c *VaultConfig) GoString() string { return fmt.Sprintf("&VaultConfig{"+ "Address:%s, "+ "Enabled:%s, "+ + "Grace:%s, "+ "RenewToken:%s, "+ "Retry:%#v, "+ "SSL:%#v, "+ @@ -247,6 +267,7 @@ func (c *VaultConfig) GoString() string { "UnwrapToken:%s"+ "}", StringGoString(c.Address), + TimeDurationGoString(c.Grace), BoolGoString(c.Enabled), BoolGoString(c.RenewToken), c.Retry, diff --git a/vendor/github.com/hashicorp/consul-template/dependency/catalog_datacenters.go b/vendor/github.com/hashicorp/consul-template/dependency/catalog_datacenters.go index 398fbc50e..a78d33cf2 100644 --- a/vendor/github.com/hashicorp/consul-template/dependency/catalog_datacenters.go +++ b/vendor/github.com/hashicorp/consul-template/dependency/catalog_datacenters.go @@ -6,6 +6,7 @@ import ( "sort" "time" + "github.com/hashicorp/consul/api" "github.com/pkg/errors" ) @@ -20,13 +21,16 @@ var ( // CatalogDatacentersQuery is the dependency to query all datacenters type CatalogDatacentersQuery struct { + ignoreFailing bool + stopCh chan struct{} } // NewCatalogDatacentersQuery creates a new datacenter dependency. -func NewCatalogDatacentersQuery() (*CatalogDatacentersQuery, error) { +func NewCatalogDatacentersQuery(ignoreFailing bool) (*CatalogDatacentersQuery, error) { return &CatalogDatacentersQuery{ - stopCh: make(chan struct{}, 1), + ignoreFailing: ignoreFailing, + stopCh: make(chan struct{}, 1), }, nil } @@ -64,6 +68,22 @@ func (d *CatalogDatacentersQuery) Fetch(clients *ClientSet, opts *QueryOptions) return nil, nil, errors.Wrapf(err, d.String()) } + // If the user opted in for skipping "down" datacenters, figure out which + // datacenters are down. + if d.ignoreFailing { + dcs := make([]string, 0, len(result)) + for _, dc := range result { + if _, _, err := clients.Consul().Catalog().Services(&api.QueryOptions{ + Datacenter: dc, + AllowStale: false, + RequireConsistent: true, + }); err == nil { + dcs = append(dcs, dc) + } + } + result = dcs + } + log.Printf("[TRACE] %s: returned %d results", d, len(result)) sort.Strings(result) diff --git a/vendor/github.com/hashicorp/consul-template/dependency/dependency.go b/vendor/github.com/hashicorp/consul-template/dependency/dependency.go index 1285d818c..9cac1f26f 100644 --- a/vendor/github.com/hashicorp/consul-template/dependency/dependency.go +++ b/vendor/github.com/hashicorp/consul-template/dependency/dependency.go @@ -1,7 +1,6 @@ package dependency import ( - "log" "net/url" "regexp" "sort" @@ -42,19 +41,6 @@ type Dependency interface { // ServiceTags is a slice of tags assigned to a Service type ServiceTags []string -// Contains returns true if the tags exists in the ServiceTags slice. -// This is deprecated and should not be used. -func (t ServiceTags) Contains(s string) bool { - log.Printf("[WARN] .Tags.Contains is deprecated. Use the built-in\n" + - "functions 'in' or 'contains' with a pipe instead.") - for _, v := range t { - if v == s { - return true - } - } - return false -} - // QueryOptions is a list of options to send with the query. These options are // client-agnostic, and the dependency determines which, if any, of the options // to use. @@ -63,6 +49,7 @@ type QueryOptions struct { Datacenter string Near string RequireConsistent bool + VaultGrace time.Duration WaitIndex uint64 WaitTime time.Duration } diff --git a/vendor/github.com/hashicorp/consul-template/dependency/vault_common.go b/vendor/github.com/hashicorp/consul-template/dependency/vault_common.go index 17c2413b2..5f3055613 100644 --- a/vendor/github.com/hashicorp/consul-template/dependency/vault_common.go +++ b/vendor/github.com/hashicorp/consul-template/dependency/vault_common.go @@ -26,3 +26,14 @@ func leaseDurationOrDefault(d int) int { } return d } + +// vaultRenewDuration accepts a given renew duration (lease duration) and +// returns the cooresponding time.Duration. If the duration is 0 (not provided), +// this falls back to the VaultDefaultLeaseDuration. +func vaultRenewDuration(d int) time.Duration { + dur := time.Duration(d/2.0) * time.Second + if dur == 0 { + dur = VaultDefaultLeaseDuration + } + return dur +} diff --git a/vendor/github.com/hashicorp/consul-template/dependency/vault_read.go b/vendor/github.com/hashicorp/consul-template/dependency/vault_read.go index f33524c62..a903bac51 100644 --- a/vendor/github.com/hashicorp/consul-template/dependency/vault_read.go +++ b/vendor/github.com/hashicorp/consul-template/dependency/vault_read.go @@ -50,10 +50,7 @@ func (d *VaultReadQuery) Fetch(clients *ClientSet, opts *QueryOptions) (interfac // If this is not the first query and we have a lease duration, sleep until we // try to renew. if opts.WaitIndex != 0 && d.secret != nil && d.secret.LeaseDuration != 0 { - dur := time.Duration(d.secret.LeaseDuration/2.0) * time.Second - if dur == 0 { - dur = VaultDefaultLeaseDuration - } + dur := vaultRenewDuration(d.secret.LeaseDuration) log.Printf("[TRACE] %s: long polling for %s", d, dur) @@ -76,6 +73,9 @@ func (d *VaultReadQuery) Fetch(clients *ClientSet, opts *QueryOptions) (interfac if err == nil { log.Printf("[TRACE] %s: successfully renewed %s", d, d.secret.LeaseID) + // Print any warnings + d.printWarnings(renewal.Warnings) + secret := &Secret{ RequestID: renewal.RequestID, LeaseID: renewal.LeaseID, @@ -83,8 +83,25 @@ func (d *VaultReadQuery) Fetch(clients *ClientSet, opts *QueryOptions) (interfac Renewable: renewal.Renewable, Data: d.secret.Data, } + // For some older versions of Vault, the renewal did not include the + // remaining lease duration, so just use the original lease duration, + // because it's the best we can do. + if renewal.LeaseDuration != 0 { + secret.LeaseDuration = renewal.LeaseDuration + } d.secret = secret + // If the remaining time on the lease is less than or equal to our + // configured grace period, generate a new credential now. This will help + // minimize downtime, since Vault will revoke credentials immediately + // when their maximum TTL expires. + remaining := time.Duration(d.secret.LeaseDuration) * time.Second + if remaining <= opts.VaultGrace { + log.Printf("[DEBUG] %s: remaining lease (%s) < grace (%s), acquiring new", + d, remaining, opts.VaultGrace) + return d.readSecret(clients, opts) + } + return respWithMetadata(secret) } @@ -94,35 +111,7 @@ func (d *VaultReadQuery) Fetch(clients *ClientSet, opts *QueryOptions) (interfac // If we got this far, we either didn't have a secret to renew, the secret was // not renewable, or the renewal failed, so attempt a fresh read. - log.Printf("[TRACE] %s: GET %s", d, &url.URL{ - Path: "/v1/" + d.path, - RawQuery: opts.String(), - }) - vaultSecret, err := clients.Vault().Logical().Read(d.path) - if err != nil { - return nil, nil, errors.Wrap(err, d.String()) - } - - // The secret could be nil if it does not exist. - if vaultSecret == nil { - return nil, nil, fmt.Errorf("%s: no secret exists at %s", d, d.path) - } - - // Print any warnings. - for _, w := range vaultSecret.Warnings { - log.Printf("[WARN] %s: %s", d, w) - } - - // Create our cloned secret. - secret := &Secret{ - LeaseID: vaultSecret.LeaseID, - LeaseDuration: leaseDurationOrDefault(vaultSecret.LeaseDuration), - Renewable: vaultSecret.Renewable, - Data: vaultSecret.Data, - } - d.secret = secret - - return respWithMetadata(secret) + return d.readSecret(clients, opts) } // CanShare returns if this dependency is shareable. @@ -144,3 +133,39 @@ func (d *VaultReadQuery) String() string { func (d *VaultReadQuery) Type() Type { return TypeVault } + +func (d *VaultReadQuery) printWarnings(warnings []string) { + for _, w := range warnings { + log.Printf("[WARN] %s: %s", d, w) + } +} + +func (d *VaultReadQuery) readSecret(clients *ClientSet, opts *QueryOptions) (interface{}, *ResponseMetadata, error) { + log.Printf("[TRACE] %s: GET %s", d, &url.URL{ + Path: "/v1/" + d.path, + RawQuery: opts.String(), + }) + vaultSecret, err := clients.Vault().Logical().Read(d.path) + if err != nil { + return nil, nil, errors.Wrap(err, d.String()) + } + + // The secret could be nil if it does not exist. + if vaultSecret == nil { + return nil, nil, fmt.Errorf("%s: no secret exists at %s", d, d.path) + } + + // Print any warnings. + d.printWarnings(vaultSecret.Warnings) + + // Create our cloned secret. + secret := &Secret{ + LeaseID: vaultSecret.LeaseID, + LeaseDuration: leaseDurationOrDefault(vaultSecret.LeaseDuration), + Renewable: vaultSecret.Renewable, + Data: vaultSecret.Data, + } + d.secret = secret + + return respWithMetadata(secret) +} diff --git a/vendor/github.com/hashicorp/consul-template/dependency/vault_token.go b/vendor/github.com/hashicorp/consul-template/dependency/vault_token.go index e930b0b01..30e198a69 100644 --- a/vendor/github.com/hashicorp/consul-template/dependency/vault_token.go +++ b/vendor/github.com/hashicorp/consul-template/dependency/vault_token.go @@ -46,10 +46,7 @@ func (d *VaultTokenQuery) Fetch(clients *ClientSet, opts *QueryOptions) (interfa // If this is not the first query and we have a lease duration, sleep until we // try to renew. if opts.WaitIndex != 0 && d.leaseDuration != 0 { - dur := time.Duration(d.leaseDuration/2.0) * time.Second - if dur == 0 { - dur = VaultDefaultLeaseDuration - } + dur := vaultRenewDuration(d.leaseDuration) log.Printf("[TRACE] %s: long polling for %s", d, dur) diff --git a/vendor/github.com/hashicorp/consul-template/dependency/vault_write.go b/vendor/github.com/hashicorp/consul-template/dependency/vault_write.go index 1bbd80b32..f0e825a19 100644 --- a/vendor/github.com/hashicorp/consul-template/dependency/vault_write.go +++ b/vendor/github.com/hashicorp/consul-template/dependency/vault_write.go @@ -57,10 +57,7 @@ func (d *VaultWriteQuery) Fetch(clients *ClientSet, opts *QueryOptions) (interfa // If this is not the first query and we have a lease duration, sleep until we // try to renew. if opts.WaitIndex != 0 && d.secret != nil && d.secret.LeaseDuration != 0 { - dur := time.Duration(d.secret.LeaseDuration/2.0) * time.Second - if dur == 0 { - dur = VaultDefaultLeaseDuration - } + dur := vaultRenewDuration(d.secret.LeaseDuration) log.Printf("[TRACE] %s: long polling for %s", d, dur) @@ -83,15 +80,34 @@ func (d *VaultWriteQuery) Fetch(clients *ClientSet, opts *QueryOptions) (interfa if err == nil { log.Printf("[TRACE] %s: successfully renewed %s", d, d.secret.LeaseID) + // Print any warnings + d.printWarnings(renewal.Warnings) + secret := &Secret{ - RequestID: renewal.RequestID, - LeaseID: renewal.LeaseID, - LeaseDuration: d.secret.LeaseDuration, - Renewable: renewal.Renewable, - Data: d.secret.Data, + RequestID: renewal.RequestID, + LeaseID: renewal.LeaseID, + Renewable: renewal.Renewable, + Data: d.secret.Data, + } + // For some older versions of Vault, the renewal did not include the + // remaining lease duration, so just use the original lease duration, + // because it's the best we can do. + if renewal.LeaseDuration != 0 { + secret.LeaseDuration = renewal.LeaseDuration } d.secret = secret + // If the remaining time on the lease is less than or equal to our + // configured grace period, generate a new credential now. This will help + // minimize downtime, since Vault will revoke credentials immediately + // when their maximum TTL expires. + remaining := time.Duration(d.secret.LeaseDuration) * time.Second + if remaining <= opts.VaultGrace { + log.Printf("[DEBUG] %s: remaining lease (%s) < grace (%s), acquiring new", + d, remaining, opts.VaultGrace) + return d.writeSecret(clients, opts) + } + return respWithMetadata(secret) } @@ -101,36 +117,7 @@ func (d *VaultWriteQuery) Fetch(clients *ClientSet, opts *QueryOptions) (interfa // If we got this far, we either didn't have a secret to renew, the secret was // not renewable, or the renewal failed, so attempt a fresh write. - log.Printf("[TRACE] %s: PUT %s", d, &url.URL{ - Path: "/v1/" + d.path, - RawQuery: opts.String(), - }) - - vaultSecret, err := clients.Vault().Logical().Write(d.path, d.data) - if err != nil { - return nil, nil, errors.Wrap(err, d.String()) - } - - // The secret could be nil if it does not exist. - if vaultSecret == nil { - return nil, nil, fmt.Errorf("%s: no secret exists at %s", d, d.path) - } - - // Print any warnings. - for _, w := range vaultSecret.Warnings { - log.Printf("[WARN] %s: %s", d, w) - } - - // Create our cloned secret. - secret := &Secret{ - LeaseID: vaultSecret.LeaseID, - LeaseDuration: leaseDurationOrDefault(vaultSecret.LeaseDuration), - Renewable: vaultSecret.Renewable, - Data: vaultSecret.Data, - } - d.secret = secret - - return respWithMetadata(secret) + return d.writeSecret(clients, opts) } // CanShare returns if this dependency is shareable. @@ -170,3 +157,42 @@ func sha1Map(m map[string]interface{}) string { return fmt.Sprintf("%.4x", h.Sum(nil)) } + +func (d *VaultWriteQuery) printWarnings(warnings []string) { + for _, w := range warnings { + log.Printf("[WARN] %s: %s", d, w) + } +} + +func (d *VaultWriteQuery) writeSecret(clients *ClientSet, opts *QueryOptions) (interface{}, *ResponseMetadata, error) { + log.Printf("[TRACE] %s: PUT %s", d, &url.URL{ + Path: "/v1/" + d.path, + RawQuery: opts.String(), + }) + + vaultSecret, err := clients.Vault().Logical().Write(d.path, d.data) + if err != nil { + return nil, nil, errors.Wrap(err, d.String()) + } + + // The secret could be nil if it does not exist. + if vaultSecret == nil { + return nil, nil, fmt.Errorf("%s: no secret exists at %s", d, d.path) + } + + // Print any warnings. + for _, w := range vaultSecret.Warnings { + log.Printf("[WARN] %s: %s", d, w) + } + + // Create our cloned secret. + secret := &Secret{ + LeaseID: vaultSecret.LeaseID, + LeaseDuration: leaseDurationOrDefault(vaultSecret.LeaseDuration), + Renewable: vaultSecret.Renewable, + Data: vaultSecret.Data, + } + d.secret = secret + + return respWithMetadata(secret) +} diff --git a/vendor/github.com/hashicorp/consul-template/manager/runner.go b/vendor/github.com/hashicorp/consul-template/manager/runner.go index 15575995e..8a6da94b3 100644 --- a/vendor/github.com/hashicorp/consul-template/manager/runner.go +++ b/vendor/github.com/hashicorp/consul-template/manager/runner.go @@ -776,10 +776,11 @@ func (r *Runner) init() error { // destinations. for _, ctmpl := range *r.config.Templates { tmpl, err := template.NewTemplate(&template.NewTemplateInput{ - Source: config.StringVal(ctmpl.Source), - Contents: config.StringVal(ctmpl.Contents), - LeftDelim: config.StringVal(ctmpl.LeftDelim), - RightDelim: config.StringVal(ctmpl.RightDelim), + Source: config.StringVal(ctmpl.Source), + Contents: config.StringVal(ctmpl.Contents), + ErrMissingKey: config.BoolVal(ctmpl.ErrMissingKey), + LeftDelim: config.StringVal(ctmpl.LeftDelim), + RightDelim: config.StringVal(ctmpl.RightDelim), }) if err != nil { return err @@ -1173,6 +1174,7 @@ 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), }) if err != nil { return nil, errors.Wrap(err, "runner") diff --git a/vendor/github.com/hashicorp/consul-template/template/funcs.go b/vendor/github.com/hashicorp/consul-template/template/funcs.go index a0e7a6c57..3a73682ec 100644 --- a/vendor/github.com/hashicorp/consul-template/template/funcs.go +++ b/vendor/github.com/hashicorp/consul-template/template/funcs.go @@ -26,11 +26,22 @@ import ( var now = func() time.Time { return time.Now().UTC() } // datacentersFunc returns or accumulates datacenter dependencies. -func datacentersFunc(b *Brain, used, missing *dep.Set) func() ([]string, error) { - return func() ([]string, error) { +func datacentersFunc(b *Brain, used, missing *dep.Set) func(ignore ...bool) ([]string, error) { + return func(i ...bool) ([]string, error) { result := []string{} - d, err := dep.NewCatalogDatacentersQuery() + var ignore bool + switch len(i) { + case 0: + ignore = false + case 1: + ignore = i[0] + default: + return result, fmt.Errorf("datacenters: wrong number of arguments, expected 0 or 1"+ + ", but got %d", len(i)) + } + + d, err := dep.NewCatalogDatacentersQuery(ignore) if err != nil { return result, err } diff --git a/vendor/github.com/hashicorp/consul-template/template/template.go b/vendor/github.com/hashicorp/consul-template/template/template.go index d6be7802d..6f9e50a2c 100644 --- a/vendor/github.com/hashicorp/consul-template/template/template.go +++ b/vendor/github.com/hashicorp/consul-template/template/template.go @@ -41,6 +41,10 @@ type Template struct { // hexMD5 stores the hex version of the MD5 hexMD5 string + + // errMissingKey causes the template processing to exit immediately if a map + // is indexed with a key that does not exist. + errMissingKey bool } // NewTemplateInput is used as input when creating the template. @@ -51,6 +55,10 @@ type NewTemplateInput struct { // Contents are the raw template contents. Contents string + // ErrMissingKey causes the template parser to exit immediately with an error + // when a map is indexed with a key that does not exist. + ErrMissingKey bool + // LeftDelim and RightDelim are the template delimiters. LeftDelim string RightDelim string @@ -77,6 +85,7 @@ func NewTemplate(i *NewTemplateInput) (*Template, error) { t.contents = i.Contents t.leftDelim = i.LeftDelim t.rightDelim = i.RightDelim + t.errMissingKey = i.ErrMissingKey if i.Source != "" { contents, err := ioutil.ReadFile(i.Source) @@ -152,6 +161,12 @@ func (t *Template) Execute(i *ExecuteInput) (*ExecuteResult, error) { missing: &missing, })) + if t.errMissingKey { + tmpl.Option("missingkey=error") + } else { + tmpl.Option("missingkey=zero") + } + tmpl, err := tmpl.Parse(t.contents) if err != nil { return nil, errors.Wrap(err, "parse") @@ -246,8 +261,5 @@ func funcMap(i *funcMapInput) template.FuncMap { "multiply": multiply, "divide": divide, "modulo": modulo, - - // Deprecated functions - "key_or_default": keyWithDefaultFunc(i.brain, i.used, i.missing), } } diff --git a/vendor/github.com/hashicorp/consul-template/watch/view.go b/vendor/github.com/hashicorp/consul-template/watch/view.go index b73b1ed72..b495ac4c7 100644 --- a/vendor/github.com/hashicorp/consul-template/watch/view.go +++ b/vendor/github.com/hashicorp/consul-template/watch/view.go @@ -44,6 +44,11 @@ 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. @@ -65,6 +70,11 @@ 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. @@ -76,6 +86,7 @@ func NewView(i *NewViewInput) (*View, error) { once: i.Once, retryFunc: i.RetryFunc, stopCh: make(chan struct{}, 1), + vaultGrace: i.VaultGrace, }, nil } @@ -200,6 +211,7 @@ 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 { diff --git a/vendor/github.com/hashicorp/consul-template/watch/watcher.go b/vendor/github.com/hashicorp/consul-template/watch/watcher.go index b95ca55ef..a4ee4938c 100644 --- a/vendor/github.com/hashicorp/consul-template/watch/watcher.go +++ b/vendor/github.com/hashicorp/consul-template/watch/watcher.go @@ -42,6 +42,11 @@ 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 { @@ -61,6 +66,11 @@ 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. @@ -75,6 +85,7 @@ 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 @@ -138,6 +149,7 @@ 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") diff --git a/vendor/vendor.json b/vendor/vendor.json index 974466edf..80f366e06 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -593,44 +593,44 @@ { "checksumSHA1": "Nu2j1GusM7ZH0uYrGzqr1K7yH7I=", "path": "github.com/hashicorp/consul-template/child", - "revision": "92746fc5cf86dbb113558bacec43459a65c8df14", - "revisionTime": "2017-05-26T18:30:17Z" + "revision": "ecbc27c1922fed2f562e7fb63e1ad24e818fa60e", + "revisionTime": "2017-07-05T14:04:00Z" }, { - "checksumSHA1": "7TBPXChZZS84qZbzP7qFYeQding=", + "checksumSHA1": "QWcGW3wELSp/YsOVzCW02oEYR7c=", "path": "github.com/hashicorp/consul-template/config", - "revision": "92746fc5cf86dbb113558bacec43459a65c8df14", - "revisionTime": "2017-05-26T18:30:17Z" + "revision": "ecbc27c1922fed2f562e7fb63e1ad24e818fa60e", + "revisionTime": "2017-07-05T14:04:00Z" }, { - "checksumSHA1": "7rKifM082rlbHN9EcsVyu7VXLoo=", + "checksumSHA1": "mV7yjHpIfO4yRAdQaBlAqdGDKO8=", "path": "github.com/hashicorp/consul-template/dependency", - "revision": "92746fc5cf86dbb113558bacec43459a65c8df14", - "revisionTime": "2017-05-26T18:30:17Z" + "revision": "ecbc27c1922fed2f562e7fb63e1ad24e818fa60e", + "revisionTime": "2017-07-05T14:04:00Z" }, { - "checksumSHA1": "Ci5EmLs/h7ke9bUg7a34UfTbB5U=", + "checksumSHA1": "ZTlPhrxNzME75A4ydXM88TFt3Qs=", "path": "github.com/hashicorp/consul-template/manager", - "revision": "92746fc5cf86dbb113558bacec43459a65c8df14", - "revisionTime": "2017-05-26T18:30:17Z" + "revision": "ecbc27c1922fed2f562e7fb63e1ad24e818fa60e", + "revisionTime": "2017-07-05T14:04:00Z" }, { "checksumSHA1": "oskgb0WteBKOItG8NNDduM7E/D0=", "path": "github.com/hashicorp/consul-template/signals", - "revision": "92746fc5cf86dbb113558bacec43459a65c8df14", - "revisionTime": "2017-05-26T18:30:17Z" + "revision": "ecbc27c1922fed2f562e7fb63e1ad24e818fa60e", + "revisionTime": "2017-07-05T14:04:00Z" }, { - "checksumSHA1": "804hk7BQd6V2xjBwz+cE0hdzSlI=", + "checksumSHA1": "zSvJlNfZS3fCRlFaZ7r9Q+N17T8=", "path": "github.com/hashicorp/consul-template/template", - "revision": "92746fc5cf86dbb113558bacec43459a65c8df14", - "revisionTime": "2017-05-26T18:30:17Z" + "revision": "ecbc27c1922fed2f562e7fb63e1ad24e818fa60e", + "revisionTime": "2017-07-05T14:04:00Z" }, { - "checksumSHA1": "KjcelGP7qPh0ObKouBJuHmXUjqk=", + "checksumSHA1": "85W96Fo50FmrMaba7Dk12aDfwWs=", "path": "github.com/hashicorp/consul-template/watch", - "revision": "92746fc5cf86dbb113558bacec43459a65c8df14", - "revisionTime": "2017-05-26T18:30:17Z" + "revision": "ecbc27c1922fed2f562e7fb63e1ad24e818fa60e", + "revisionTime": "2017-07-05T14:04:00Z" }, { "checksumSHA1": "jfELEMRhiTcppZmRH+ZwtkVS5Uw=",