rebase: update vault/api to v1.1.1

Signed-off-by: Niels de Vos <ndevos@redhat.com>
This commit is contained in:
Niels de Vos
2021-09-28 17:05:57 +02:00
committed by mergify[bot]
parent b85076365c
commit bb68cc9bee
32 changed files with 1399 additions and 350 deletions

6
vendor/github.com/hashicorp/vault/api/README.md generated vendored Normal file
View File

@ -0,0 +1,6 @@
Vault API
=================
This provides the `github.com/hashicorp/vault/api` package which contains code useful for interacting with a Vault server.
[![GoDoc](https://godoc.org/github.com/hashicorp/vault/api?status.png)](https://godoc.org/github.com/hashicorp/vault/api)

View File

@ -25,26 +25,30 @@ import (
"golang.org/x/time/rate"
)
const EnvVaultAddress = "VAULT_ADDR"
const EnvVaultAgentAddr = "VAULT_AGENT_ADDR"
const EnvVaultCACert = "VAULT_CACERT"
const EnvVaultCAPath = "VAULT_CAPATH"
const EnvVaultClientCert = "VAULT_CLIENT_CERT"
const EnvVaultClientKey = "VAULT_CLIENT_KEY"
const EnvVaultClientTimeout = "VAULT_CLIENT_TIMEOUT"
const EnvVaultSRVLookup = "VAULT_SRV_LOOKUP"
const EnvVaultSkipVerify = "VAULT_SKIP_VERIFY"
const EnvVaultNamespace = "VAULT_NAMESPACE"
const EnvVaultTLSServerName = "VAULT_TLS_SERVER_NAME"
const EnvVaultWrapTTL = "VAULT_WRAP_TTL"
const EnvVaultMaxRetries = "VAULT_MAX_RETRIES"
const EnvVaultToken = "VAULT_TOKEN"
const EnvVaultMFA = "VAULT_MFA"
const EnvRateLimit = "VAULT_RATE_LIMIT"
const (
EnvVaultAddress = "VAULT_ADDR"
EnvVaultAgentAddr = "VAULT_AGENT_ADDR"
EnvVaultCACert = "VAULT_CACERT"
EnvVaultCAPath = "VAULT_CAPATH"
EnvVaultClientCert = "VAULT_CLIENT_CERT"
EnvVaultClientKey = "VAULT_CLIENT_KEY"
EnvVaultClientTimeout = "VAULT_CLIENT_TIMEOUT"
EnvVaultSRVLookup = "VAULT_SRV_LOOKUP"
EnvVaultSkipVerify = "VAULT_SKIP_VERIFY"
EnvVaultNamespace = "VAULT_NAMESPACE"
EnvVaultTLSServerName = "VAULT_TLS_SERVER_NAME"
EnvVaultWrapTTL = "VAULT_WRAP_TTL"
EnvVaultMaxRetries = "VAULT_MAX_RETRIES"
EnvVaultToken = "VAULT_TOKEN"
EnvVaultMFA = "VAULT_MFA"
EnvRateLimit = "VAULT_RATE_LIMIT"
)
// Deprecated values
const EnvVaultAgentAddress = "VAULT_AGENT_ADDR"
const EnvVaultInsecure = "VAULT_SKIP_VERIFY"
const (
EnvVaultAgentAddress = "VAULT_AGENT_ADDR"
EnvVaultInsecure = "VAULT_SKIP_VERIFY"
)
// WrappingLookupFunc is a function that, given an HTTP verb and a path,
// returns an optional string duration to be used for response wrapping (e.g.
@ -75,6 +79,14 @@ type Config struct {
// (or http.DefaultClient).
HttpClient *http.Client
// MinRetryWait controls the minimum time to wait before retrying when a 5xx
// error occurs. Defaults to 1000 milliseconds.
MinRetryWait time.Duration
// MaxRetryWait controls the maximum time to wait before retrying when a 5xx
// error occurs. Defaults to 1500 milliseconds.
MaxRetryWait time.Duration
// MaxRetries controls the maximum number of times to retry when a 5xx
// error occurs. Set to 0 to disable retrying. Defaults to 2 (for a total
// of three tries).
@ -93,6 +105,9 @@ type Config struct {
// The CheckRetry function to use; a default is used if not provided
CheckRetry retryablehttp.CheckRetry
// Logger is the leveled logger to provide to the retryable HTTP client.
Logger retryablehttp.LeveledLogger
// Limiter is the rate limiter used by the client.
// If this pointer is nil, then there will be no limit set.
// In contrast, if this pointer is set, even to an empty struct,
@ -146,9 +161,13 @@ type TLSConfig struct {
// If an error is encountered, this will return nil.
func DefaultConfig() *Config {
config := &Config{
Address: "https://127.0.0.1:8200",
HttpClient: cleanhttp.DefaultPooledClient(),
Timeout: time.Second * 60,
Address: "https://127.0.0.1:8200",
HttpClient: cleanhttp.DefaultPooledClient(),
Timeout: time.Second * 60,
MinRetryWait: time.Millisecond * 1000,
MaxRetryWait: time.Millisecond * 1500,
MaxRetries: 2,
Backoff: retryablehttp.LinearJitterBackoff,
}
transport := config.HttpClient.Transport.(*http.Transport)
@ -178,9 +197,6 @@ func DefaultConfig() *Config {
return http.ErrUseLastResponse
}
config.Backoff = retryablehttp.LinearJitterBackoff
config.MaxRetries = 2
return config
}
@ -360,7 +376,6 @@ func (c *Config) ReadEnvironment() error {
}
func parseRateLimit(val string) (rate float64, burst int, err error) {
_, err = fmt.Sscanf(val, "%f:%d", &rate, &burst)
if err != nil {
rate, err = strconv.ParseFloat(val, 64)
@ -371,7 +386,6 @@ func parseRateLimit(val string) (rate float64, burst int, err error) {
}
return rate, burst, err
}
// Client is the client to the Vault API. Create a client with NewClient.
@ -384,6 +398,8 @@ type Client struct {
wrappingLookupFunc WrappingLookupFunc
mfaCreds []string
policyOverride bool
requestCallbacks []RequestCallback
responseCallbacks []ResponseCallback
}
// NewClient returns a new client for the given configuration.
@ -410,6 +426,14 @@ func NewClient(c *Config) (*Client, error) {
c.modifyLock.Lock()
defer c.modifyLock.Unlock()
if c.MinRetryWait == 0 {
c.MinRetryWait = def.MinRetryWait
}
if c.MaxRetryWait == 0 {
c.MaxRetryWait = def.MaxRetryWait
}
if c.HttpClient == nil {
c.HttpClient = def.HttpClient
}
@ -463,6 +487,31 @@ func NewClient(c *Config) (*Client, error) {
return client, nil
}
func (c *Client) CloneConfig() *Config {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
newConfig := DefaultConfig()
newConfig.Address = c.config.Address
newConfig.AgentAddress = c.config.AgentAddress
newConfig.MinRetryWait = c.config.MinRetryWait
newConfig.MaxRetryWait = c.config.MaxRetryWait
newConfig.MaxRetries = c.config.MaxRetries
newConfig.Timeout = c.config.Timeout
newConfig.Backoff = c.config.Backoff
newConfig.CheckRetry = c.config.CheckRetry
newConfig.Logger = c.config.Logger
newConfig.Limiter = c.config.Limiter
newConfig.OutputCurlString = c.config.OutputCurlString
newConfig.SRVLookup = c.config.SRVLookup
// we specifically want a _copy_ of the client here, not a pointer to the original one
newClient := *c.config.HttpClient
newConfig.HttpClient = &newClient
return newConfig
}
// Sets the address of Vault in the client. The format of address should be
// "<Scheme>://<Host>:<Port>". Setting this on a client will override the
// value of VAULT_ADDR environment variable.
@ -475,6 +524,9 @@ func (c *Client) SetAddress(addr string) error {
return errwrap.Wrapf("failed to set address: {{err}}", err)
}
c.config.modifyLock.Lock()
c.config.Address = addr
c.config.modifyLock.Unlock()
c.addr = parsedAddr
return nil
}
@ -492,57 +544,149 @@ func (c *Client) Address() string {
// rateLimit and burst are specified according to https://godoc.org/golang.org/x/time/rate#NewLimiter
func (c *Client) SetLimiter(rateLimit float64, burst int) {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.Lock()
defer c.config.modifyLock.Unlock()
c.modifyLock.RUnlock()
c.config.Limiter = rate.NewLimiter(rate.Limit(rateLimit), burst)
}
func (c *Client) Limiter() *rate.Limiter {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.RLock()
defer c.config.modifyLock.RUnlock()
return c.config.Limiter
}
// SetMinRetryWait sets the minimum time to wait before retrying in the case of certain errors.
func (c *Client) SetMinRetryWait(retryWait time.Duration) {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.Lock()
defer c.config.modifyLock.Unlock()
c.config.MinRetryWait = retryWait
}
func (c *Client) MinRetryWait() time.Duration {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.RLock()
defer c.config.modifyLock.RUnlock()
return c.config.MinRetryWait
}
// SetMaxRetryWait sets the maximum time to wait before retrying in the case of certain errors.
func (c *Client) SetMaxRetryWait(retryWait time.Duration) {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.Lock()
defer c.config.modifyLock.Unlock()
c.config.MaxRetryWait = retryWait
}
func (c *Client) MaxRetryWait() time.Duration {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.RLock()
defer c.config.modifyLock.RUnlock()
return c.config.MaxRetryWait
}
// SetMaxRetries sets the number of retries that will be used in the case of certain errors
func (c *Client) SetMaxRetries(retries int) {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.Lock()
defer c.config.modifyLock.Unlock()
c.modifyLock.RUnlock()
c.config.MaxRetries = retries
}
func (c *Client) MaxRetries() int {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.RLock()
defer c.config.modifyLock.RUnlock()
return c.config.MaxRetries
}
func (c *Client) SetSRVLookup(srv bool) {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.Lock()
defer c.config.modifyLock.Unlock()
c.config.SRVLookup = srv
}
func (c *Client) SRVLookup() bool {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.RLock()
defer c.config.modifyLock.RUnlock()
return c.config.SRVLookup
}
// SetCheckRetry sets the CheckRetry function to be used for future requests.
func (c *Client) SetCheckRetry(checkRetry retryablehttp.CheckRetry) {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.Lock()
defer c.config.modifyLock.Unlock()
c.modifyLock.RUnlock()
c.config.CheckRetry = checkRetry
}
func (c *Client) CheckRetry() retryablehttp.CheckRetry {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.RLock()
defer c.config.modifyLock.RUnlock()
return c.config.CheckRetry
}
// SetClientTimeout sets the client request timeout
func (c *Client) SetClientTimeout(timeout time.Duration) {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.Lock()
defer c.config.modifyLock.Unlock()
c.modifyLock.RUnlock()
c.config.Timeout = timeout
}
func (c *Client) OutputCurlString() bool {
func (c *Client) ClientTimeout() time.Duration {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.RLock()
defer c.config.modifyLock.RUnlock()
return c.config.Timeout
}
func (c *Client) OutputCurlString() bool {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.RLock()
defer c.config.modifyLock.RUnlock()
c.modifyLock.RUnlock()
return c.config.OutputCurlString
}
func (c *Client) SetOutputCurlString(curl bool) {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.Lock()
defer c.config.modifyLock.Unlock()
c.modifyLock.RUnlock()
c.config.OutputCurlString = curl
}
@ -552,7 +696,6 @@ func (c *Client) SetOutputCurlString(curl bool) {
func (c *Client) CurrentWrappingLookupFunc() WrappingLookupFunc {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
return c.wrappingLookupFunc
}
@ -561,7 +704,6 @@ func (c *Client) CurrentWrappingLookupFunc() WrappingLookupFunc {
func (c *Client) SetWrappingLookupFunc(lookupFunc WrappingLookupFunc) {
c.modifyLock.Lock()
defer c.modifyLock.Unlock()
c.wrappingLookupFunc = lookupFunc
}
@ -570,7 +712,6 @@ func (c *Client) SetWrappingLookupFunc(lookupFunc WrappingLookupFunc) {
func (c *Client) SetMFACreds(creds []string) {
c.modifyLock.Lock()
defer c.modifyLock.Unlock()
c.mfaCreds = creds
}
@ -595,7 +736,6 @@ func (c *Client) setNamespace(namespace string) {
func (c *Client) Token() string {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
return c.token
}
@ -604,7 +744,6 @@ func (c *Client) Token() string {
func (c *Client) SetToken(v string) {
c.modifyLock.Lock()
defer c.modifyLock.Unlock()
c.token = v
}
@ -612,7 +751,6 @@ func (c *Client) SetToken(v string) {
func (c *Client) ClearToken() {
c.modifyLock.Lock()
defer c.modifyLock.Unlock()
c.token = ""
}
@ -655,13 +793,22 @@ func (c *Client) SetHeaders(headers http.Header) {
// SetBackoff sets the backoff function to be used for future requests.
func (c *Client) SetBackoff(backoff retryablehttp.Backoff) {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.Lock()
defer c.config.modifyLock.Unlock()
c.modifyLock.RUnlock()
c.config.Backoff = backoff
}
func (c *Client) SetLogger(logger retryablehttp.LeveledLogger) {
c.modifyLock.RLock()
defer c.modifyLock.RUnlock()
c.config.modifyLock.Lock()
defer c.config.modifyLock.Unlock()
c.config.Logger = logger
}
// Clone creates a new client with the same configuration. Note that the same
// underlying http.Client is used; modifying the client from more than one
// goroutine at once may not be safe, so modify the client as needed and then
@ -672,22 +819,33 @@ func (c *Client) SetBackoff(backoff retryablehttp.Backoff) {
// behavior, must currently then be set as desired on the new client.
func (c *Client) Clone() (*Client, error) {
c.modifyLock.RLock()
c.config.modifyLock.RLock()
defer c.modifyLock.RUnlock()
config := c.config
c.modifyLock.RUnlock()
config.modifyLock.RLock()
defer config.modifyLock.RUnlock()
newConfig := &Config{
Address: config.Address,
HttpClient: config.HttpClient,
MaxRetries: config.MaxRetries,
Timeout: config.Timeout,
Backoff: config.Backoff,
CheckRetry: config.CheckRetry,
Limiter: config.Limiter,
Address: config.Address,
HttpClient: config.HttpClient,
MinRetryWait: config.MinRetryWait,
MaxRetryWait: config.MaxRetryWait,
MaxRetries: config.MaxRetries,
Timeout: config.Timeout,
Backoff: config.Backoff,
CheckRetry: config.CheckRetry,
Logger: config.Logger,
Limiter: config.Limiter,
OutputCurlString: config.OutputCurlString,
AgentAddress: config.AgentAddress,
SRVLookup: config.SRVLookup,
}
client, err := NewClient(newConfig)
if err != nil {
return nil, err
}
config.modifyLock.RUnlock()
return NewClient(newConfig)
return client, nil
}
// SetPolicyOverride sets whether requests should be sent with the policy
@ -696,7 +854,6 @@ func (c *Client) Clone() (*Client, error) {
func (c *Client) SetPolicyOverride(override bool) {
c.modifyLock.Lock()
defer c.modifyLock.Unlock()
c.policyOverride = override
}
@ -712,7 +869,7 @@ func (c *Client) NewRequest(method, requestPath string) *Request {
policyOverride := c.policyOverride
c.modifyLock.RUnlock()
var host = addr.Host
host := addr.Host
// if SRV records exist (see https://tools.ietf.org/html/draft-andrews-http-srv-02), lookup the SRV
// record and take the highest match; this is not designed for high-availability, just discovery
// Internet Draft specifies that the SRV record is ignored if a port is given
@ -776,16 +933,23 @@ func (c *Client) RawRequestWithContext(ctx context.Context, r *Request) (*Respon
c.config.modifyLock.RLock()
limiter := c.config.Limiter
minRetryWait := c.config.MinRetryWait
maxRetryWait := c.config.MaxRetryWait
maxRetries := c.config.MaxRetries
checkRetry := c.config.CheckRetry
backoff := c.config.Backoff
httpClient := c.config.HttpClient
timeout := c.config.Timeout
outputCurlString := c.config.OutputCurlString
logger := c.config.Logger
c.config.modifyLock.RUnlock()
c.modifyLock.RUnlock()
for _, cb := range c.requestCallbacks {
cb(r)
}
if limiter != nil {
limiter.Wait(ctx)
}
@ -809,7 +973,10 @@ START:
}
if outputCurlString {
LastOutputStringError = &OutputStringError{Request: req}
LastOutputStringError = &OutputStringError{
Request: req,
TLSSkipVerify: c.config.HttpClient.Transport.(*http.Transport).TLSClientConfig.InsecureSkipVerify,
}
return nil, LastOutputStringError
}
@ -827,16 +994,17 @@ START:
}
if checkRetry == nil {
checkRetry = retryablehttp.DefaultRetryPolicy
checkRetry = DefaultRetryPolicy
}
client := &retryablehttp.Client{
HTTPClient: httpClient,
RetryWaitMin: 1000 * time.Millisecond,
RetryWaitMax: 1500 * time.Millisecond,
RetryWaitMin: minRetryWait,
RetryWaitMax: maxRetryWait,
RetryMax: maxRetries,
Backoff: backoff,
CheckRetry: checkRetry,
Logger: logger,
ErrorHandler: retryablehttp.PassthroughErrorHandler,
}
@ -888,9 +1056,96 @@ START:
goto START
}
if result != nil {
for _, cb := range c.responseCallbacks {
cb(result)
}
}
if err := result.Error(); err != nil {
return result, err
}
return result, nil
}
type (
RequestCallback func(*Request)
ResponseCallback func(*Response)
)
// WithRequestCallbacks makes a shallow clone of Client, modifies it to use
// the given callbacks, and returns it. Each of the callbacks will be invoked
// on every outgoing request. A client may be used to issue requests
// concurrently; any locking needed by callbacks invoked concurrently is the
// callback's responsibility.
func (c *Client) WithRequestCallbacks(callbacks ...RequestCallback) *Client {
c2 := *c
c2.modifyLock = sync.RWMutex{}
c2.requestCallbacks = callbacks
return &c2
}
// WithResponseCallbacks makes a shallow clone of Client, modifies it to use
// the given callbacks, and returns it. Each of the callbacks will be invoked
// on every received response. A client may be used to issue requests
// concurrently; any locking needed by callbacks invoked concurrently is the
// callback's responsibility.
func (c *Client) WithResponseCallbacks(callbacks ...ResponseCallback) *Client {
c2 := *c
c2.modifyLock = sync.RWMutex{}
c2.responseCallbacks = callbacks
return &c2
}
// RecordState returns a response callback that will record the state returned
// by Vault in a response header.
func RecordState(state *string) ResponseCallback {
return func(resp *Response) {
*state = resp.Header.Get("X-Vault-Index")
}
}
// RequireState returns a request callback that will add a request header to
// specify the state we require of Vault. This state was obtained from a
// response header seen previous, probably captured with RecordState.
func RequireState(states ...string) RequestCallback {
return func(req *Request) {
for _, s := range states {
req.Headers.Add("X-Vault-Index", s)
}
}
}
// ForwardInconsistent returns a request callback that will add a request
// header which says: if the state required isn't present on the node receiving
// this request, forward it to the active node. This should be used in
// conjunction with RequireState.
func ForwardInconsistent() RequestCallback {
return func(req *Request) {
req.Headers.Set("X-Vault-Inconsistent", "forward-active-node")
}
}
// ForwardAlways returns a request callback which adds a header telling any
// performance standbys handling the request to forward it to the active node.
// This feature must be enabled in Vault's configuration.
func ForwardAlways() RequestCallback {
return func(req *Request) {
req.Headers.Set("X-Vault-Forward", "active-node")
}
}
// DefaultRetryPolicy is the default retry policy used by new Client objects.
// It is the same as retryablehttp.DefaultRetryPolicy except that it also retries
// 412 requests, which are returned by Vault when a X-Vault-Index header isn't
// satisfied.
func DefaultRetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) {
retry, err := retryablehttp.DefaultRetryPolicy(ctx, resp, err)
if err != nil || retry {
return retry, err
}
if resp != nil && resp.StatusCode == 412 {
return true, nil
}
return false, nil
}

View File

@ -5,14 +5,16 @@ go 1.13
replace github.com/hashicorp/vault/sdk => ../sdk
require (
github.com/cenkalti/backoff/v3 v3.0.0
github.com/go-test/deep v1.0.2
github.com/hashicorp/errwrap v1.0.0
github.com/hashicorp/go-cleanhttp v0.5.1
github.com/hashicorp/go-hclog v0.16.1
github.com/hashicorp/go-multierror v1.1.0
github.com/hashicorp/go-retryablehttp v0.6.6
github.com/hashicorp/go-rootcerts v1.0.2
github.com/hashicorp/hcl v1.0.0
github.com/hashicorp/vault/sdk v0.1.14-0.20200519221838-e0cfd64bc267
github.com/hashicorp/vault/sdk v0.2.1
github.com/mitchellh/mapstructure v1.3.2
golang.org/x/net v0.0.0-20200602114024-627f9648deb9
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1

View File

@ -10,15 +10,15 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/go-metrics v0.3.3/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 h1:BUAU3CGlLvorLI26FmByPp2eC2qla6E1Tw+scpcg/to=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aws/aws-sdk-go v1.30.27/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c=
github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
@ -63,7 +63,6 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31 h1:28FVBuwkwowZMjbA7M0wXsI6t3PYulRTMio3SO+eKCM=
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw=
github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
@ -89,8 +88,9 @@ github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
@ -99,24 +99,21 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v0.14.1 h1:nQcJDQwIAGnmoUWp8ubocEX40cCml/17YkF6csQLReU=
github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-hclog v0.16.1 h1:IVQwpTGNRRIHafnTs2dQLIk4ENtneRIEEJWOVDqz99o=
github.com/hashicorp/go-hclog v0.16.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-kms-wrapping/entropy v0.1.0/go.mod h1:d1g9WGtAunDNpek8jUIEJnBlbgKS1N2Q61QkHiZyR1g=
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-retryablehttp v0.6.2 h1:bHM2aVXwBtBJWxHtkSrWuI4umABCUczs52eiUS9nSiw=
github.com/hashicorp/go-retryablehttp v0.6.2/go.mod h1:gEx6HMUGxYYhJScX7W1Il64m6cc2C1mDaW3NQ9sY1FY=
github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM=
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-rootcerts v1.0.1 h1:DMo4fmknnz0E0evoNYnV48RjWndOsmd6OW+09R3cEP8=
github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
@ -151,18 +148,15 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/cli v1.0.0 h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
@ -200,7 +194,6 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
@ -227,9 +220,7 @@ github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bd
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
@ -237,9 +228,9 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9 h1:vEg9joUBmeBcK9iSJftGNf3coIG4HqZElCPehJsfAYM=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@ -247,6 +238,7 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -256,7 +248,7 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -282,7 +274,6 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -290,11 +281,9 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980 h1:OjiUf46hAmXblsZdnoSXsEUSKU8r1UEzcL5RVZ4gO9Y=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI=
golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -306,6 +295,8 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
@ -331,7 +322,7 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -340,7 +331,6 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogR
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w=
gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=

View File

@ -5,6 +5,8 @@ import (
"math/rand"
"sync"
"time"
"github.com/cenkalti/backoff/v3"
)
var (
@ -229,28 +231,25 @@ func (r *LifetimeWatcher) Renew() {
r.Start()
}
// renewAuth is a helper for renewing authentication.
func (r *LifetimeWatcher) doRenew() error {
var nonRenewable bool
var tokenMode bool
var initLeaseDuration int
var credString string
var renewFunc func(string, int) (*Secret, error)
type renewFunc func(string, int) (*Secret, error)
// doRenew is a helper for renewing authentication.
func (r *LifetimeWatcher) doRenew() error {
defaultInitialRetryInterval := 10 * time.Second
switch {
case r.secret.Auth != nil:
tokenMode = true
nonRenewable = !r.secret.Auth.Renewable
initLeaseDuration = r.secret.Auth.LeaseDuration
credString = r.secret.Auth.ClientToken
renewFunc = r.client.Auth().Token().RenewTokenAsSelf
return r.doRenewWithOptions(true, !r.secret.Auth.Renewable,
r.secret.Auth.LeaseDuration, r.secret.Auth.ClientToken,
r.client.Auth().Token().RenewTokenAsSelf, defaultInitialRetryInterval)
default:
nonRenewable = !r.secret.Renewable
initLeaseDuration = r.secret.LeaseDuration
credString = r.secret.LeaseID
renewFunc = r.client.Sys().Renew
return r.doRenewWithOptions(false, !r.secret.Renewable,
r.secret.LeaseDuration, r.secret.LeaseID,
r.client.Sys().Renew, defaultInitialRetryInterval)
}
}
func (r *LifetimeWatcher) doRenewWithOptions(tokenMode bool, nonRenewable bool, initLeaseDuration int, credString string,
renew renewFunc, initialRetryInterval time.Duration) error {
if credString == "" ||
(nonRenewable && r.renewBehavior == RenewBehaviorErrorOnErrors) {
return r.errLifetimeWatcherNotRenewable
@ -259,6 +258,7 @@ func (r *LifetimeWatcher) doRenew() error {
initialTime := time.Now()
priorDuration := time.Duration(initLeaseDuration) * time.Second
r.calculateGrace(priorDuration)
var errorBackoff backoff.BackOff
for {
// Check if we are stopped.
@ -268,18 +268,20 @@ func (r *LifetimeWatcher) doRenew() error {
default:
}
var leaseDuration time.Duration
var remainingLeaseDuration time.Duration
fallbackLeaseDuration := initialTime.Add(priorDuration).Sub(time.Now())
var renewal *Secret
var err error
switch {
case nonRenewable || r.renewBehavior == RenewBehaviorRenewDisabled:
// Can't or won't renew, just keep the same expiration so we exit
// when it's reauthentication time
leaseDuration = fallbackLeaseDuration
remainingLeaseDuration = fallbackLeaseDuration
default:
// Renew the token
renewal, err := renewFunc(credString, r.increment)
renewal, err = renew(credString, r.increment)
if err != nil || renewal == nil || (tokenMode && renewal.Auth == nil) {
if r.renewBehavior == RenewBehaviorErrorOnErrors {
if err != nil {
@ -290,9 +292,22 @@ func (r *LifetimeWatcher) doRenew() error {
}
}
leaseDuration = fallbackLeaseDuration
// Calculate remaining duration until initial token lease expires
remainingLeaseDuration = initialTime.Add(time.Duration(initLeaseDuration) * time.Second).Sub(time.Now())
if errorBackoff == nil {
errorBackoff = &backoff.ExponentialBackOff{
MaxElapsedTime: remainingLeaseDuration,
RandomizationFactor: backoff.DefaultRandomizationFactor,
InitialInterval: initialRetryInterval,
MaxInterval: 5 * time.Minute,
Multiplier: 2,
Clock: backoff.SystemClock,
}
errorBackoff.Reset()
}
break
}
errorBackoff = nil
// Push a message that a renewal took place.
select {
@ -306,26 +321,38 @@ func (r *LifetimeWatcher) doRenew() error {
return r.errLifetimeWatcherNotRenewable
}
// Reset initial time
initialTime = time.Now()
// Grab the lease duration
newDuration := renewal.LeaseDuration
initLeaseDuration = renewal.LeaseDuration
if tokenMode {
newDuration = renewal.Auth.LeaseDuration
initLeaseDuration = renewal.Auth.LeaseDuration
}
leaseDuration = time.Duration(newDuration) * time.Second
remainingLeaseDuration = time.Duration(initLeaseDuration) * time.Second
}
// We keep evaluating a new grace period so long as the lease is
// extending. Once it stops extending, we've hit the max and need to
// rely on the grace duration.
if leaseDuration > priorDuration {
r.calculateGrace(leaseDuration)
}
priorDuration = leaseDuration
var sleepDuration time.Duration
// The sleep duration is set to 2/3 of the current lease duration plus
// 1/3 of the current grace period, which adds jitter.
sleepDuration := time.Duration(float64(leaseDuration.Nanoseconds())*2/3 + float64(r.grace.Nanoseconds())/3)
if errorBackoff != nil {
sleepDuration = errorBackoff.NextBackOff()
if sleepDuration == backoff.Stop {
return err
}
} else {
// We keep evaluating a new grace period so long as the lease is
// extending. Once it stops extending, we've hit the max and need to
// rely on the grace duration.
if remainingLeaseDuration > priorDuration {
r.calculateGrace(remainingLeaseDuration)
}
priorDuration = remainingLeaseDuration
// The sleep duration is set to 2/3 of the current lease duration plus
// 1/3 of the current grace period, which adds jitter.
sleepDuration = time.Duration(float64(remainingLeaseDuration.Nanoseconds())*2/3 + float64(r.grace.Nanoseconds())/3)
}
// If we are within grace, return now; or, if the amount of time we
// would sleep would land us in the grace period. This helps with short
@ -333,7 +360,7 @@ func (r *LifetimeWatcher) doRenew() error {
// seconds, a grace period of 3 seconds, and end up sleeping for more
// than three of those seconds and having a very small budget of time
// to renew.
if leaseDuration <= r.grace || leaseDuration-sleepDuration <= r.grace {
if remainingLeaseDuration <= r.grace || remainingLeaseDuration-sleepDuration <= r.grace {
return nil
}
@ -346,23 +373,6 @@ func (r *LifetimeWatcher) doRenew() error {
}
}
// sleepDuration calculates the time to sleep given the base lease duration. The
// base is the resulting lease duration. It will be reduced to 1/3 and
// multiplied by a random float between 0.0 and 1.0. This extra randomness
// prevents multiple clients from all trying to renew simultaneously.
func (r *LifetimeWatcher) sleepDuration(base time.Duration) time.Duration {
sleep := float64(base)
// Renew at 1/3 the remaining lease. This will give us an opportunity to retry
// at least one more time should the first renewal fail.
sleep = sleep / 3.0
// Use a randomness so many clients do not hit Vault simultaneously.
sleep = sleep * (r.random.Float64() + 1) / 2.0
return time.Duration(sleep)
}
// calculateGrace calculates the grace period based on a reasonable set of
// assumptions given the total lease time; it also adds some jitter to not have
// clients be in sync.
@ -380,5 +390,7 @@ func (r *LifetimeWatcher) calculateGrace(leaseDuration time.Duration) {
r.grace = time.Duration(jitterMax) + time.Duration(uint64(r.random.Int63())%uint64(jitterMax))
}
type Renewer = LifetimeWatcher
type RenewerInput = LifetimeWatcherInput
type (
Renewer = LifetimeWatcher
RenewerInput = LifetimeWatcherInput
)

View File

@ -11,12 +11,11 @@ const (
ErrOutputStringRequest = "output a string, please"
)
var (
LastOutputStringError *OutputStringError
)
var LastOutputStringError *OutputStringError
type OutputStringError struct {
*retryablehttp.Request
TLSSkipVerify bool
parsingError error
parsedCurlString string
}
@ -41,6 +40,9 @@ func (d *OutputStringError) parseRequest() {
// Build cURL string
d.parsedCurlString = "curl "
if d.TLSSkipVerify {
d.parsedCurlString += "--insecure "
}
if d.Request.Method != "GET" {
d.parsedCurlString = fmt.Sprintf("%s-X %s ", d.parsedCurlString, d.Request.Method)
}

View File

@ -82,7 +82,7 @@ func VaultPluginTLSProvider(apiTLSConfig *TLSConfig) func() (*tls.Config, error)
return nil, errwrap.Wrapf("error parsing wrapping token: {{err}}", err)
}
var allClaims = make(map[string]interface{})
allClaims := make(map[string]interface{})
if err = parsedJWT.UnsafeClaimsWithoutVerification(&allClaims); err != nil {
return nil, errwrap.Wrapf("error parsing claims from wrapping token: {{err}}", err)
}

View File

@ -52,7 +52,6 @@ func (c *Sys) ListAudit() (map[string]*Audit, error) {
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
resp, err := c.c.RawRequestWithContext(ctx, r)
if err != nil {
return nil, err
}
@ -94,7 +93,6 @@ func (c *Sys) EnableAuditWithOptions(path string, options *EnableAuditOptions) e
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
resp, err := c.c.RawRequestWithContext(ctx, r)
if err != nil {
return err
}

View File

@ -74,7 +74,9 @@ func (c *Sys) DisableAuth(path string) error {
}
// Rather than duplicate, we can use modern Go's type aliasing
type EnableAuthOptions = MountInput
type AuthConfigInput = MountConfigInput
type AuthMount = MountOutput
type AuthConfigOutput = MountConfigOutput
type (
EnableAuthOptions = MountInput
AuthConfigInput = MountConfigInput
AuthMount = MountOutput
AuthConfigOutput = MountConfigOutput
)

View File

@ -35,71 +35,41 @@ func (c *Sys) CORSStatus() (*CORSResponse, error) {
return &result, err
}
func (c *Sys) ConfigureCORS(req *CORSRequest) (*CORSResponse, error) {
func (c *Sys) ConfigureCORS(req *CORSRequest) error {
r := c.c.NewRequest("PUT", "/v1/sys/config/cors")
if err := r.SetJSONBody(req); err != nil {
return nil, err
return err
}
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
resp, err := c.c.RawRequestWithContext(ctx, r)
if err != nil {
return nil, err
if err == nil {
defer resp.Body.Close()
}
defer resp.Body.Close()
secret, err := ParseSecret(resp.Body)
if err != nil {
return nil, err
}
if secret == nil || secret.Data == nil {
return nil, errors.New("data from server response is empty")
}
var result CORSResponse
err = mapstructure.Decode(secret.Data, &result)
if err != nil {
return nil, err
}
return &result, err
return err
}
func (c *Sys) DisableCORS() (*CORSResponse, error) {
func (c *Sys) DisableCORS() error {
r := c.c.NewRequest("DELETE", "/v1/sys/config/cors")
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
resp, err := c.c.RawRequestWithContext(ctx, r)
if err != nil {
return nil, err
if err == nil {
defer resp.Body.Close()
}
defer resp.Body.Close()
secret, err := ParseSecret(resp.Body)
if err != nil {
return nil, err
}
if secret == nil || secret.Data == nil {
return nil, errors.New("data from server response is empty")
}
var result CORSResponse
err = mapstructure.Decode(secret.Data, &result)
if err != nil {
return nil, err
}
return &result, err
return err
}
type CORSRequest struct {
AllowedOrigins string `json:"allowed_origins" mapstructure:"allowed_origins"`
Enabled bool `json:"enabled" mapstructure:"enabled"`
AllowedOrigins []string `json:"allowed_origins" mapstructure:"allowed_origins"`
AllowedHeaders []string `json:"allowed_headers" mapstructure:"allowed_headers"`
Enabled bool `json:"enabled" mapstructure:"enabled"`
}
type CORSResponse struct {
AllowedOrigins string `json:"allowed_origins" mapstructure:"allowed_origins"`
Enabled bool `json:"enabled" mapstructure:"enabled"`
AllowedOrigins []string `json:"allowed_origins" mapstructure:"allowed_origins"`
AllowedHeaders []string `json:"allowed_headers" mapstructure:"allowed_headers"`
Enabled bool `json:"enabled" mapstructure:"enabled"`
}

View File

@ -1,6 +1,9 @@
package api
import "context"
import (
"context"
"time"
)
func (c *Sys) Leader() (*LeaderResponse, error) {
r := c.c.NewRequest("GET", "/v1/sys/leader")
@ -19,13 +22,14 @@ func (c *Sys) Leader() (*LeaderResponse, error) {
}
type LeaderResponse struct {
HAEnabled bool `json:"ha_enabled"`
IsSelf bool `json:"is_self"`
LeaderAddress string `json:"leader_address"`
LeaderClusterAddress string `json:"leader_cluster_address"`
PerfStandby bool `json:"performance_standby"`
PerfStandbyLastRemoteWAL uint64 `json:"performance_standby_last_remote_wal"`
LastWAL uint64 `json:"last_wal"`
RaftCommittedIndex uint64 `json:"raft_committed_index,omitempty"`
RaftAppliedIndex uint64 `json:"raft_applied_index,omitempty"`
HAEnabled bool `json:"ha_enabled"`
IsSelf bool `json:"is_self"`
ActiveTime time.Time `json:"active_time"`
LeaderAddress string `json:"leader_address"`
LeaderClusterAddress string `json:"leader_cluster_address"`
PerfStandby bool `json:"performance_standby"`
PerfStandbyLastRemoteWAL uint64 `json:"performance_standby_last_remote_wal"`
LastWAL uint64 `json:"last_wal"`
RaftCommittedIndex uint64 `json:"raft_committed_index,omitempty"`
RaftAppliedIndex uint64 `json:"raft_applied_index,omitempty"`
}

View File

@ -27,6 +27,27 @@ func (c *Sys) Renew(id string, increment int) (*Secret, error) {
return ParseSecret(resp.Body)
}
func (c *Sys) Lookup(id string) (*Secret, error) {
r := c.c.NewRequest("PUT", "/v1/sys/leases/lookup")
body := map[string]interface{}{
"lease_id": id,
}
if err := r.SetJSONBody(body); err != nil {
return nil, err
}
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
resp, err := c.c.RawRequestWithContext(ctx, r)
if err != nil {
return nil, err
}
defer resp.Body.Close()
return ParseSecret(resp.Body)
}
func (c *Sys) Revoke(id string) error {
r := c.c.NewRequest("PUT", "/v1/sys/leases/revoke")
body := map[string]interface{}{

View File

@ -109,7 +109,6 @@ func (c *Sys) ListPlugins(i *ListPluginsInput) (*ListPluginsResponse, error) {
for i, nameIfc := range pluginsIfc {
name, ok := nameIfc.(string)
if !ok {
}
plugins[i] = name
}
@ -323,7 +322,6 @@ func (c *Sys) ReloadPluginStatus(reloadStatusInput *ReloadPluginStatusInput) (*R
return &r, nil
}
return nil, nil
}
// catalogPathByType is a helper to construct the proper API path by plugin type

View File

@ -2,9 +2,16 @@ package api
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"time"
"github.com/hashicorp/vault/sdk/helper/parseutil"
"github.com/mitchellh/mapstructure"
"github.com/hashicorp/vault/sdk/helper/consts"
)
@ -16,6 +23,9 @@ type RaftJoinResponse struct {
// RaftJoinRequest represents the parameters consumed by the raft join API
type RaftJoinRequest struct {
AutoJoin string `json:"auto_join"`
AutoJoinScheme string `json:"auto_join_scheme"`
AutoJoinPort uint `json:"auto_join_port"`
LeaderAPIAddr string `json:"leader_api_addr"`
LeaderCACert string `json:"leader_ca_cert"`
LeaderClientCert string `json:"leader_client_cert"`
@ -24,6 +34,78 @@ type RaftJoinRequest struct {
NonVoter bool `json:"non_voter"`
}
// AutopilotConfig is used for querying/setting the Autopilot configuration.
type AutopilotConfig struct {
CleanupDeadServers bool `json:"cleanup_dead_servers" mapstructure:"cleanup_dead_servers"`
LastContactThreshold time.Duration `json:"last_contact_threshold" mapstructure:"-"`
DeadServerLastContactThreshold time.Duration `json:"dead_server_last_contact_threshold" mapstructure:"-"`
MaxTrailingLogs uint64 `json:"max_trailing_logs" mapstructure:"max_trailing_logs"`
MinQuorum uint `json:"min_quorum" mapstructure:"min_quorum"`
ServerStabilizationTime time.Duration `json:"server_stabilization_time" mapstructure:"-"`
}
// MarshalJSON makes the autopilot config fields JSON compatible
func (ac *AutopilotConfig) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]interface{}{
"cleanup_dead_servers": ac.CleanupDeadServers,
"last_contact_threshold": ac.LastContactThreshold.String(),
"dead_server_last_contact_threshold": ac.DeadServerLastContactThreshold.String(),
"max_trailing_logs": ac.MaxTrailingLogs,
"min_quorum": ac.MinQuorum,
"server_stabilization_time": ac.ServerStabilizationTime.String(),
})
}
// UnmarshalJSON parses the autopilot config JSON blob
func (ac *AutopilotConfig) UnmarshalJSON(b []byte) error {
var data interface{}
err := json.Unmarshal(b, &data)
if err != nil {
return err
}
conf := data.(map[string]interface{})
if err = mapstructure.WeakDecode(conf, ac); err != nil {
return err
}
if ac.LastContactThreshold, err = parseutil.ParseDurationSecond(conf["last_contact_threshold"]); err != nil {
return err
}
if ac.DeadServerLastContactThreshold, err = parseutil.ParseDurationSecond(conf["dead_server_last_contact_threshold"]); err != nil {
return err
}
if ac.ServerStabilizationTime, err = parseutil.ParseDurationSecond(conf["server_stabilization_time"]); err != nil {
return err
}
return nil
}
// AutopilotState represents the response of the raft autopilot state API
type AutopilotState struct {
Healthy bool `mapstructure:"healthy"`
FailureTolerance int `mapstructure:"failure_tolerance"`
Servers map[string]*AutopilotServer `mapstructure:"servers"`
Leader string `mapstructure:"leader"`
Voters []string `mapstructure:"voters"`
NonVoters []string `mapstructure:"non_voters"`
}
// AutopilotServer represents the server blocks in the response of the raft
// autopilot state API.
type AutopilotServer struct {
ID string `mapstructure:"id"`
Name string `mapstructure:"name"`
Address string `mapstructure:"address"`
NodeStatus string `mapstructure:"node_status"`
LastContact string `mapstructure:"last_contact"`
LastTerm uint64 `mapstructure:"last_term"`
LastIndex uint64 `mapstructure:"last_index"`
Healthy bool `mapstructure:"healthy"`
StableSince string `mapstructure:"stable_since"`
Status string `mapstructure:"status"`
Meta map[string]string `mapstructure:"meta"`
}
// RaftJoin adds the node from which this call is invoked from to the raft
// cluster represented by the leader address in the parameter.
func (c *Sys) RaftJoin(opts *RaftJoinRequest) (*RaftJoinResponse, error) {
@ -157,3 +239,79 @@ func (c *Sys) RaftSnapshotRestore(snapReader io.Reader, force bool) error {
return nil
}
// RaftAutopilotState returns the state of the raft cluster as seen by autopilot.
func (c *Sys) RaftAutopilotState() (*AutopilotState, error) {
r := c.c.NewRequest("GET", "/v1/sys/storage/raft/autopilot/state")
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
resp, err := c.c.RawRequestWithContext(ctx, r)
if resp != nil {
defer resp.Body.Close()
if resp.StatusCode == 404 {
return nil, nil
}
}
if err != nil {
return nil, err
}
secret, err := ParseSecret(resp.Body)
if err != nil {
return nil, err
}
if secret == nil || secret.Data == nil {
return nil, errors.New("data from server response is empty")
}
var result AutopilotState
err = mapstructure.Decode(secret.Data, &result)
if err != nil {
return nil, err
}
return &result, err
}
// RaftAutopilotConfiguration fetches the autopilot config.
func (c *Sys) RaftAutopilotConfiguration() (*AutopilotConfig, error) {
r := c.c.NewRequest("GET", "/v1/sys/storage/raft/autopilot/configuration")
ctx, cancelFunc := context.WithCancel(context.Background())
defer cancelFunc()
resp, err := c.c.RawRequestWithContext(ctx, r)
if resp != nil {
defer resp.Body.Close()
if resp.StatusCode == 404 {
return nil, nil
}
}
if err != nil {
return nil, err
}
secret, err := ParseSecret(resp.Body)
if err != nil {
return nil, err
}
if secret == nil {
return nil, errors.New("data from server response is empty")
}
var result AutopilotConfig
if err = mapstructure.Decode(secret.Data, &result); err != nil {
return nil, err
}
if result.LastContactThreshold, err = parseutil.ParseDurationSecond(secret.Data["last_contact_threshold"]); err != nil {
return nil, err
}
if result.DeadServerLastContactThreshold, err = parseutil.ParseDurationSecond(secret.Data["dead_server_last_contact_threshold"]); err != nil {
return nil, err
}
if result.ServerStabilizationTime, err = parseutil.ParseDurationSecond(secret.Data["server_stabilization_time"]); err != nil {
return nil, err
}
return &result, err
}

View File

@ -68,10 +68,24 @@ func (c *Sys) KeyStatus() (*KeyStatus, error) {
}
result.InstallTime = installTime
encryptionsRaw, ok := secret.Data["encryptions"]
if ok {
encryptions, ok := encryptionsRaw.(json.Number)
if !ok {
return nil, errors.New("could not convert encryptions to a number")
}
encryptions64, err := encryptions.Int64()
if err != nil {
return nil, err
}
result.Encryptions = int(encryptions64)
}
return &result, err
}
type KeyStatus struct {
Term int `json:"term"`
InstallTime time.Time `json:"install_time"`
Encryptions int `json:"encryptions"`
}