Vendor update to consul template 0.19.4

This commit is contained in:
Preetha Appan 2017-11-13 14:58:36 -06:00
parent cb476f2f8c
commit c60b7d45ed
15 changed files with 184 additions and 70 deletions

View File

@ -114,14 +114,19 @@ func (c *RetryConfig) RetryFunc() RetryFunc {
return false, 0
}
base := math.Pow(2, float64(retry))
sleep := time.Duration(base) * TimeDurationVal(c.Backoff)
baseSleep := TimeDurationVal(c.Backoff)
maxSleep := TimeDurationVal(c.MaxBackoff)
if maxSleep > 0 && maxSleep < sleep {
return true, maxSleep
if maxSleep > 0 {
attemptsTillMaxBackoff := int(math.Log2(maxSleep.Seconds() / baseSleep.Seconds()))
if retry > attemptsTillMaxBackoff {
return true, maxSleep
}
}
base := math.Pow(2, float64(retry))
sleep := time.Duration(base) * baseSleep
return true, sleep
}
}

View File

@ -10,11 +10,6 @@ import (
)
const (
// DefaultTemplateFilePerms are the default file permissions for templates
// rendered onto disk when a specific file permission has not already been
// specified.
DefaultTemplateFilePerms = 0644
// DefaultTemplateCommandTimeout is the amount of time to wait for a command
// to return.
DefaultTemplateCommandTimeout = 30 * time.Second
@ -25,10 +20,6 @@ var (
// are empty.
ErrTemplateStringEmpty = errors.New("template: cannot be empty")
// ErrTemplateInvalidFormat is the error returned with the template is not
// a valid format.
ErrTemplateInvalidFormat = errors.New("template: invalid format")
// configTemplateRe is the pattern to split the config template syntax.
configTemplateRe = regexp.MustCompile("([a-zA-Z]:)?([^:]+)")
)
@ -52,6 +43,10 @@ type TemplateConfig struct {
// must be specified, but not both.
Contents *string `mapstructure:"contents"`
// CreateDestDirs tells Consul Template to create the parent directories of
// the destination path if they do not exist. The default value is true.
CreateDestDirs *bool `mapstructure:"create_dest_dirs"`
// Destination is the location on disk where the template should be rendered.
// This is required unless running in debug/dry mode.
Destination *string `mapstructure:"destination"`
@ -107,6 +102,8 @@ func (c *TemplateConfig) Copy() *TemplateConfig {
o.Contents = c.Contents
o.CreateDestDirs = c.CreateDestDirs
o.Destination = c.Destination
o.ErrMissingKey = c.ErrMissingKey
@ -163,6 +160,10 @@ func (c *TemplateConfig) Merge(o *TemplateConfig) *TemplateConfig {
r.Contents = o.Contents
}
if o.CreateDestDirs != nil {
r.CreateDestDirs = o.CreateDestDirs
}
if o.Destination != nil {
r.Destination = o.Destination
}
@ -217,6 +218,10 @@ func (c *TemplateConfig) Finalize() {
c.Contents = String("")
}
if c.CreateDestDirs == nil {
c.CreateDestDirs = Bool(true)
}
if c.Destination == nil {
c.Destination = String("")
}
@ -239,7 +244,7 @@ func (c *TemplateConfig) Finalize() {
c.Exec.Finalize()
if c.Perms == nil {
c.Perms = FileMode(DefaultTemplateFilePerms)
c.Perms = FileMode(0)
}
if c.Source == nil {
@ -271,6 +276,7 @@ func (c *TemplateConfig) GoString() string {
"Command:%s, "+
"CommandTimeout:%s, "+
"Contents:%s, "+
"CreateDestDirs:%s, "+
"Destination:%s, "+
"ErrMissingKey:%s, "+
"Exec:%#v, "+
@ -284,6 +290,7 @@ func (c *TemplateConfig) GoString() string {
StringGoString(c.Command),
TimeDurationGoString(c.CommandTimeout),
StringGoString(c.Contents),
BoolGoString(c.CreateDestDirs),
StringGoString(c.Destination),
BoolGoString(c.ErrMissingKey),
c.Exec,
@ -399,7 +406,8 @@ func ParseTemplateConfig(s string) (*TemplateConfig, error) {
case 3:
source, destination, command = parts[0], parts[1], parts[2]
default:
return nil, ErrTemplateInvalidFormat
source, destination = parts[0], parts[1]
command = strings.Join(parts[2:], ":")
}
var sourcePtr, destinationPtr, commandPtr *string

View File

@ -16,7 +16,7 @@ var (
_ Dependency = (*CatalogNodeQuery)(nil)
// CatalogNodeQueryRe is the regular expression to use.
CatalogNodeQueryRe = regexp.MustCompile(`\A` + nameRe + dcRe + `\z`)
CatalogNodeQueryRe = regexp.MustCompile(`\A` + nodeNameRe + dcRe + `\z`)
)
func init() {

View File

@ -92,7 +92,11 @@ func (d *CatalogNodesQuery) Fetch(clients *ClientSet, opts *QueryOptions) (inter
Meta: node.Meta,
})
}
sort.Stable(ByNode(nodes))
// Sort unless the user explicitly asked for nearness
if d.near == "" {
sort.Stable(ByNode(nodes))
}
rm := &ResponseMetadata{
LastIndex: qm.LastIndex,

View File

@ -15,7 +15,7 @@ var (
_ Dependency = (*CatalogServiceQuery)(nil)
// CatalogServiceQueryRe is the regular expression to use.
CatalogServiceQueryRe = regexp.MustCompile(`\A` + tagRe + nameRe + dcRe + nearRe + `\z`)
CatalogServiceQueryRe = regexp.MustCompile(`\A` + tagRe + serviceNameRe + dcRe + nearRe + `\z`)
)
func init() {

View File

@ -310,7 +310,7 @@ func (c *ClientSet) Consul() *consulapi.Client {
return c.consul.client
}
// Vault returns the Consul client for this set.
// Vault returns the Vault client for this set.
func (c *ClientSet) Vault() *vaultapi.Client {
c.RLock()
defer c.RUnlock()

View File

@ -11,13 +11,14 @@ import (
)
const (
dcRe = `(@(?P<dc>[[:word:]\.\-\_]+))?`
keyRe = `/?(?P<key>[^@]+)`
filterRe = `(\|(?P<filter>[[:word:]\,]+))?`
nameRe = `(?P<name>[[:word:]\-\_]+)`
nearRe = `(~(?P<near>[[:word:]\.\-\_]+))?`
prefixRe = `/?(?P<prefix>[^@]+)`
tagRe = `((?P<tag>[[:word:]\.\-\_]+)\.)?`
dcRe = `(@(?P<dc>[[:word:]\.\-\_]+))?`
keyRe = `/?(?P<key>[^@]+)`
filterRe = `(\|(?P<filter>[[:word:]\,]+))?`
serviceNameRe = `(?P<name>[[:word:]\-\_]+)`
nodeNameRe = `(?P<name>[[:word:]\.\-\_]+)`
nearRe = `(~(?P<near>[[:word:]\.\-\_]+))?`
prefixRe = `/?(?P<prefix>[^@]+)`
tagRe = `((?P<tag>[[:word:]\.\-\_]+)\.)?`
)
type Type int

View File

@ -29,7 +29,7 @@ var (
_ Dependency = (*HealthServiceQuery)(nil)
// HealthServiceQueryRe is the regular expression to use.
HealthServiceQueryRe = regexp.MustCompile(`\A` + tagRe + nameRe + dcRe + nearRe + filterRe + `\z`)
HealthServiceQueryRe = regexp.MustCompile(`\A` + tagRe + serviceNameRe + dcRe + nearRe + filterRe + `\z`)
)
func init() {
@ -174,7 +174,10 @@ func (d *HealthServiceQuery) Fetch(clients *ClientSet, opts *QueryOptions) (inte
log.Printf("[TRACE] %s: returned %d results after filtering", d, len(list))
sort.Stable(ByNodeThenID(list))
// Sort unless the user explicitly asked for nearness
if d.near == "" {
sort.Stable(ByNodeThenID(list))
}
rm := &ResponseMetadata{
LastIndex: qm.LastIndex,

View File

@ -14,6 +14,7 @@ import (
"github.com/hashicorp/consul-template/config"
dep "github.com/hashicorp/consul-template/dependency"
"github.com/hashicorp/consul-template/template"
"github.com/hashicorp/consul-template/version"
consulapi "github.com/hashicorp/consul/api"
)
@ -33,8 +34,14 @@ const (
templateDataFlag = 0x22b9a127a2c03520
)
// templateData is GOB encoded share the depdency values
// templateData is GOB encoded share the dependency values
type templateData struct {
// Version is the version of Consul Template which created this template data.
// This is important because users may be running multiple versions of CT
// with the same templates. This provides a nicer upgrade path.
Version string
// Data is the actual template data.
Data map[string]interface{}
}
@ -197,7 +204,8 @@ func (d *DedupManager) UpdateDeps(t *template.Template, deps []dep.Dependency) e
// Package up the dependency data
td := templateData{
Data: make(map[string]interface{}),
Version: version.Version,
Data: make(map[string]interface{}),
}
for _, dp := range deps {
// Skip any dependencies that can't be shared
@ -409,6 +417,11 @@ func (d *DedupManager) parseData(path string, raw []byte) {
path, err)
return
}
if td.Version != version.Version {
log.Printf("[WARN] (dedup) created with different version (%s vs %s)",
td.Version, version.Version)
return
}
log.Printf("[INFO] (dedup) loading %d dependencies from '%s'",
len(td.Data), path)

View File

@ -11,14 +11,30 @@ import (
"github.com/pkg/errors"
)
const (
// DefaultFilePerms are the default file permissions for files rendered onto
// disk when a specific file permission has not already been specified.
DefaultFilePerms = 0644
)
var (
// ErrNoParentDir is the error returned with the parent directory is missing
// and the user disabled it.
ErrNoParentDir = errors.New("parent directory is missing")
// ErrMissingDest is the error returned with the destination is empty.
ErrMissingDest = errors.New("missing destination")
)
// RenderInput is used as input to the render function.
type RenderInput struct {
Backup bool
Contents []byte
Dry bool
DryStream io.Writer
Path string
Perms os.FileMode
Backup bool
Contents []byte
CreateDestDirs bool
Dry bool
DryStream io.Writer
Path string
Perms os.FileMode
}
// RenderResult is returned and stored. It contains the status of the render
@ -58,7 +74,7 @@ func Render(i *RenderInput) (*RenderResult, error) {
if i.Dry {
fmt.Fprintf(i.DryStream, "> %s\n%s", i.Path, i.Contents)
} else {
if err := AtomicWrite(i.Path, i.Contents, i.Perms, i.Backup); err != nil {
if err := AtomicWrite(i.Path, i.CreateDestDirs, i.Contents, i.Perms, i.Backup); err != nil {
return nil, errors.Wrap(err, "failed writing file")
}
}
@ -85,15 +101,19 @@ func Render(i *RenderInput) (*RenderResult, error) {
//
// If no errors occur, the Tempfile is "renamed" (moved) to the destination
// path.
func AtomicWrite(path string, contents []byte, perms os.FileMode, backup bool) error {
func AtomicWrite(path string, createDestDirs bool, contents []byte, perms os.FileMode, backup bool) error {
if path == "" {
return fmt.Errorf("missing destination")
return ErrMissingDest
}
parent := filepath.Dir(path)
if _, err := os.Stat(parent); os.IsNotExist(err) {
if err := os.MkdirAll(parent, 0755); err != nil {
return err
if createDestDirs {
if err := os.MkdirAll(parent, 0755); err != nil {
return err
}
} else {
return ErrNoParentDir
}
}
@ -115,6 +135,22 @@ func AtomicWrite(path string, contents []byte, perms os.FileMode, backup bool) e
return err
}
// If the user did not explicitly set permissions, attempt to lookup the
// current permissions on the file. If the file does not exist, fall back to
// the default. Otherwise, inherit the current permissions.
if perms == 0 {
currentInfo, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
perms = DefaultFilePerms
} else {
return err
}
} else {
perms = currentInfo.Mode()
}
}
if err := os.Chmod(f.Name(), perms); err != nil {
return err
}
@ -158,5 +194,10 @@ func copyFile(src, dst string) error {
d.Close()
return err
}
return d.Close()
if err := d.Close(); err != nil {
return err
}
// io.Copy can restrict file permissions based on umask.
return os.Chmod(dst, stat.Mode())
}

View File

@ -43,7 +43,7 @@ type Runner struct {
// outStream and errStream are the io.Writer streams where the runner will
// write information. These can be modified by calling SetOutStream and
// SetErrStream accordingly.
// SetErrStream accordingly.
// inStream is the ioReader where the runner will read information.
outStream, errStream io.Writer
@ -740,12 +740,13 @@ func (r *Runner) runTemplate(tmpl *template.Template, runCtx *templateRunCtx) (*
// Render the template, taking dry mode into account
result, err := Render(&RenderInput{
Backup: config.BoolVal(templateConfig.Backup),
Contents: result.Output,
Dry: r.dry,
DryStream: r.outStream,
Path: config.StringVal(templateConfig.Destination),
Perms: config.FileModeVal(templateConfig.Perms),
Backup: config.BoolVal(templateConfig.Backup),
Contents: result.Output,
CreateDestDirs: config.BoolVal(templateConfig.CreateDestDirs),
Dry: r.dry,
DryStream: r.outStream,
Path: config.StringVal(templateConfig.Destination),
Perms: config.FileModeVal(templateConfig.Perms),
})
if err != nil {
return nil, errors.Wrap(err, "error rendering "+templateConfig.Display())
@ -1252,14 +1253,14 @@ func newWatcher(c *config.Config, clients *dep.ClientSet, once bool) (*watch.Wat
Clients: clients,
MaxStale: config.TimeDurationVal(c.MaxStale),
Once: once,
RenewVault: config.StringPresent(c.Vault.Token) && config.BoolVal(c.Vault.RenewToken),
RenewVault: clients.Vault().Token() != "" && config.BoolVal(c.Vault.RenewToken),
RetryFuncConsul: watch.RetryFunc(c.Consul.Retry.RetryFunc()),
// TODO: Add a sane default retry - right now this only affects "local"
// dependencies like reading a file from disk.
RetryFuncDefault: nil,
RetryFuncVault: watch.RetryFunc(c.Vault.Retry.RetryFunc()),
VaultGrace: config.TimeDurationVal(c.Vault.Grace),
VaultToken: config.StringVal(c.Vault.Token),
VaultToken: clients.Vault().Token(),
})
if err != nil {
return nil, errors.Wrap(err, "runner")

View File

@ -655,6 +655,25 @@ func in(l, v interface{}) (bool, error) {
return false, nil
}
// Indent prefixes each line of a string with the specified number of spaces
func indent(spaces int, s string) (string, error) {
var output, prefix []byte
var sp bool
var size int
prefix = []byte(strings.Repeat(" ", spaces))
sp = true
for _, c := range []byte(s) {
if sp && c != '\n' {
output = append(output, prefix...)
size += spaces
}
output = append(output, c)
sp = c == '\n'
size += 1
}
return string(output[:size]), nil
}
// loop accepts varying parameters and differs its behavior. If given one
// parameter, loop will return a goroutine that begins at 0 and loops until the
// given int, increasing the index by 1 each iteration. If given two parameters,

View File

@ -233,6 +233,7 @@ func funcMap(i *funcMapInput) template.FuncMap {
"executeTemplate": executeTemplateFunc(i.t),
"explode": explode,
"in": in,
"indent": indent,
"loop": loop,
"join": join,
"trimSpace": trimSpace,

View File

@ -0,0 +1,12 @@
package version
import "fmt"
const Version = "0.19.5.dev"
var (
Name string
GitCommit string
HumanVersion = fmt.Sprintf("%s v%s (%s)", Name, Version, GitCommit)
)

42
vendor/vendor.json vendored
View File

@ -709,44 +709,50 @@
{
"checksumSHA1": "Nu2j1GusM7ZH0uYrGzqr1K7yH7I=",
"path": "github.com/hashicorp/consul-template/child",
"revision": "16b6f8c417d88c88e9b88af6235da2582397c709",
"revisionTime": "2017-10-03T21:31:50Z"
"revision": "26d029ad37335b3827a9fde5569b2c5e10dcac8f",
"revisionTime": "2017-10-31T14:25:17Z"
},
{
"checksumSHA1": "nkbwT6jsnaXDiXrJFjCge9W5ULo=",
"checksumSHA1": "qKAxyhYnUpKzZ5KpA6aOiIHHqqg=",
"path": "github.com/hashicorp/consul-template/config",
"revision": "16b6f8c417d88c88e9b88af6235da2582397c709",
"revisionTime": "2017-10-03T21:31:50Z"
"revision": "26d029ad37335b3827a9fde5569b2c5e10dcac8f",
"revisionTime": "2017-10-31T14:25:17Z"
},
{
"checksumSHA1": "ki5mjKALz3JrAee3mYUNl8pFJnU=",
"checksumSHA1": "gZUb/+jEn+2hdO/lmQSKcYuOB/o=",
"path": "github.com/hashicorp/consul-template/dependency",
"revision": "16b6f8c417d88c88e9b88af6235da2582397c709",
"revisionTime": "2017-10-03T21:31:50Z"
"revision": "26d029ad37335b3827a9fde5569b2c5e10dcac8f",
"revisionTime": "2017-10-31T14:25:17Z"
},
{
"checksumSHA1": "yXXJXYYs/OPVJW2ErBiQVaLxSt0=",
"checksumSHA1": "JVwx9FW1/nxRvg1lEeydBhaf3No=",
"path": "github.com/hashicorp/consul-template/manager",
"revision": "16b6f8c417d88c88e9b88af6235da2582397c709",
"revisionTime": "2017-10-03T21:31:50Z"
"revision": "26d029ad37335b3827a9fde5569b2c5e10dcac8f",
"revisionTime": "2017-10-31T14:25:17Z"
},
{
"checksumSHA1": "YSEUV/9/k85XciRKu0cngxdjZLE=",
"path": "github.com/hashicorp/consul-template/signals",
"revision": "16b6f8c417d88c88e9b88af6235da2582397c709",
"revisionTime": "2017-10-03T21:31:50Z"
"revision": "26d029ad37335b3827a9fde5569b2c5e10dcac8f",
"revisionTime": "2017-10-31T14:25:17Z"
},
{
"checksumSHA1": "zSvJlNfZS3fCRlFaZ7r9Q+N17T8=",
"checksumSHA1": "N9qobVzScLbTEnGE7MgFnnTbGBw=",
"path": "github.com/hashicorp/consul-template/template",
"revision": "16b6f8c417d88c88e9b88af6235da2582397c709",
"revisionTime": "2017-10-03T21:31:50Z"
"revision": "26d029ad37335b3827a9fde5569b2c5e10dcac8f",
"revisionTime": "2017-10-31T14:25:17Z"
},
{
"checksumSHA1": "NB5+D4AuCNV9Bsqh3YFdPi4AJ6U=",
"path": "github.com/hashicorp/consul-template/version",
"revision": "26d029ad37335b3827a9fde5569b2c5e10dcac8f",
"revisionTime": "2017-10-31T14:25:17Z"
},
{
"checksumSHA1": "b4+Y+02pY2Y5620F9ALzKg8Zmdw=",
"path": "github.com/hashicorp/consul-template/watch",
"revision": "16b6f8c417d88c88e9b88af6235da2582397c709",
"revisionTime": "2017-10-03T21:31:50Z"
"revision": "26d029ad37335b3827a9fde5569b2c5e10dcac8f",
"revisionTime": "2017-10-31T14:25:17Z"
},
{
"checksumSHA1": "XLfcIX2qpRr0o26aFMjCOzvw6jo=",