From 45bb11e020b4b7124e3255976c2b7688d4872095 Mon Sep 17 00:00:00 2001 From: poornas Date: Tue, 27 Nov 2018 14:42:32 -0800 Subject: [PATCH] Set namespace on vault client if VAULT_NAMESPACE env is set (#6867) --- cmd/crypto/vault.go | 5 + docs/kms/README.md | 6 + .../hashicorp/vault/api/auth_token.go | 1 + .../github.com/hashicorp/vault/api/client.go | 42 +++++- .../github.com/hashicorp/vault/api/logical.go | 19 +++ .../github.com/hashicorp/vault/api/request.go | 4 +- .../hashicorp/vault/api/sys_audit.go | 65 +++++---- .../hashicorp/vault/api/sys_auth.go | 74 ++-------- .../hashicorp/vault/api/sys_capabilities.go | 34 +++-- .../hashicorp/vault/api/sys_config_cors.go | 58 ++++++-- .../hashicorp/vault/api/sys_generate_root.go | 2 + .../hashicorp/vault/api/sys_health.go | 2 + .../hashicorp/vault/api/sys_leader.go | 11 +- .../hashicorp/vault/api/sys_mounts.go | 53 +++---- .../hashicorp/vault/api/sys_plugins.go | 129 +++++++++++++++--- .../hashicorp/vault/api/sys_policy.go | 44 +++--- .../hashicorp/vault/api/sys_rekey.go | 41 +++++- .../hashicorp/vault/api/sys_rotate.go | 44 +++++- .../hashicorp/vault/api/sys_seal.go | 17 +++ .../hashicorp/vault/api/sys_stepdown.go | 4 +- .../hashicorp/vault/helper/consts/consts.go | 14 ++ .../hashicorp/vault/helper/consts/error.go | 16 +++ .../vault/helper/consts/plugin_types.go | 59 ++++++++ .../vault/helper/consts/replication.go | 87 ++++++++++++ vendor/vendor.json | 12 +- 25 files changed, 644 insertions(+), 199 deletions(-) create mode 100644 vendor/github.com/hashicorp/vault/helper/consts/consts.go create mode 100644 vendor/github.com/hashicorp/vault/helper/consts/error.go create mode 100644 vendor/github.com/hashicorp/vault/helper/consts/plugin_types.go create mode 100644 vendor/github.com/hashicorp/vault/helper/consts/replication.go diff --git a/cmd/crypto/vault.go b/cmd/crypto/vault.go index cf0be6967..150064648 100644 --- a/cmd/crypto/vault.go +++ b/cmd/crypto/vault.go @@ -192,6 +192,11 @@ func NewVault(kmsConf KMSConfig) (KMS, error) { if err != nil { return nil, err } + + if ns, ok := os.LookupEnv("VAULT_NAMESPACE"); ok { + c.SetNamespace(ns) + } + accessToken, leaseDuration, err := getVaultAccessToken(c, config.Auth.AppRole.ID, config.Auth.AppRole.Secret) if err != nil { return nil, err diff --git a/docs/kms/README.md b/docs/kms/README.md index 74edb045f..51a0619d3 100644 --- a/docs/kms/README.md +++ b/docs/kms/README.md @@ -50,6 +50,8 @@ vault write -f auth/approle/role/my-role/secret-id The AppRole ID, AppRole Secret Id, Vault endpoint and Vault key name can now be used to start minio server with Vault as KMS. +Note: If [Vault Namespaces](https://learn.hashicorp.com/vault/operations/namespaces) are in use, VAULT_NAMESPACE variable needs to be set before setting approle and transit secrets engine. + ### 3. Environment variables You'll need the Vault endpoint, AppRole ID, AppRole SecretID and encryption key-ring name defined in step 2.2 @@ -67,6 +69,10 @@ Optionally set `MINIO_SSE_VAULT_CAPATH` as the path to a directory of PEM-encode export MINIO_SSE_VAULT_CAPATH=/home/user/custom-pems ``` +Optionally set `VAULT_NAMESPACE` if AppRole and Transit Secrets engine have been scoped to Vault Namespace +``` +export VAULT_NAMESPACE=ns1 +``` ### 4. Test your setup To test this setup, start minio server with environment variables set in Step 3, and server is ready to handle SSE-S3 requests. diff --git a/vendor/github.com/hashicorp/vault/api/auth_token.go b/vendor/github.com/hashicorp/vault/api/auth_token.go index c66fba348..ed594eee8 100644 --- a/vendor/github.com/hashicorp/vault/api/auth_token.go +++ b/vendor/github.com/hashicorp/vault/api/auth_token.go @@ -271,4 +271,5 @@ type TokenCreateRequest struct { DisplayName string `json:"display_name"` NumUses int `json:"num_uses"` Renewable *bool `json:"renewable,omitempty"` + Type string `json:"type"` } diff --git a/vendor/github.com/hashicorp/vault/api/client.go b/vendor/github.com/hashicorp/vault/api/client.go index 7ebde5942..d3acaea9d 100644 --- a/vendor/github.com/hashicorp/vault/api/client.go +++ b/vendor/github.com/hashicorp/vault/api/client.go @@ -17,8 +17,9 @@ import ( "github.com/hashicorp/errwrap" "github.com/hashicorp/go-cleanhttp" - retryablehttp "github.com/hashicorp/go-retryablehttp" + "github.com/hashicorp/go-retryablehttp" "github.com/hashicorp/go-rootcerts" + "github.com/hashicorp/vault/helper/consts" "github.com/hashicorp/vault/helper/parseutil" "golang.org/x/net/http2" "golang.org/x/time/rate" @@ -120,7 +121,7 @@ type TLSConfig struct { func DefaultConfig() *Config { config := &Config{ Address: "https://127.0.0.1:8200", - HttpClient: cleanhttp.DefaultClient(), + HttpClient: cleanhttp.DefaultPooledClient(), } config.HttpClient.Timeout = time.Second * 60 @@ -464,6 +465,19 @@ func (c *Client) SetMFACreds(creds []string) { c.mfaCreds = creds } +// SetNamespace sets the namespace supplied either via the environment +// variable or via the command line. +func (c *Client) SetNamespace(namespace string) { + c.modifyLock.Lock() + defer c.modifyLock.Unlock() + + if c.headers == nil { + c.headers = make(http.Header) + } + + c.headers.Set(consts.NamespaceHeaderName, namespace) +} + // Token returns the access token being used by this client. It will // return the empty string if there is no token set. func (c *Client) Token() string { @@ -490,6 +504,26 @@ func (c *Client) ClearToken() { c.token = "" } +// Headers gets the current set of headers used for requests. This returns a +// copy; to modify it make modifications locally and use SetHeaders. +func (c *Client) Headers() http.Header { + c.modifyLock.RLock() + defer c.modifyLock.RUnlock() + + if c.headers == nil { + return nil + } + + ret := make(http.Header) + for k, v := range c.headers { + for _, val := range v { + ret[k] = append(ret[k], val) + } + } + + return ret +} + // SetHeaders sets the headers to be used for future requests. func (c *Client) SetHeaders(headers http.Header) { c.modifyLock.Lock() @@ -512,6 +546,10 @@ func (c *Client) SetBackoff(backoff retryablehttp.Backoff) { // 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 // clone. +// +// Also, only the client's config is currently copied; this means items not in +// the api.Config struct, such as policy override and wrapping function +// 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() diff --git a/vendor/github.com/hashicorp/vault/api/logical.go b/vendor/github.com/hashicorp/vault/api/logical.go index 5add065ff..d13daac6e 100644 --- a/vendor/github.com/hashicorp/vault/api/logical.go +++ b/vendor/github.com/hashicorp/vault/api/logical.go @@ -5,6 +5,7 @@ import ( "context" "fmt" "io" + "net/url" "os" "github.com/hashicorp/errwrap" @@ -46,8 +47,26 @@ func (c *Client) Logical() *Logical { } func (c *Logical) Read(path string) (*Secret, error) { + return c.ReadWithData(path, nil) +} + +func (c *Logical) ReadWithData(path string, data map[string][]string) (*Secret, error) { r := c.c.NewRequest("GET", "/v1/"+path) + var values url.Values + for k, v := range data { + if values == nil { + values = make(url.Values) + } + for _, val := range v { + values.Add(k, val) + } + } + + if values != nil { + r.Params = values + } + ctx, cancelFunc := context.WithCancel(context.Background()) defer cancelFunc() resp, err := c.c.RawRequestWithContext(ctx, r) diff --git a/vendor/github.com/hashicorp/vault/api/request.go b/vendor/github.com/hashicorp/vault/api/request.go index 5bcff8c6c..4efa2aa84 100644 --- a/vendor/github.com/hashicorp/vault/api/request.go +++ b/vendor/github.com/hashicorp/vault/api/request.go @@ -8,6 +8,8 @@ import ( "net/http" "net/url" + "github.com/hashicorp/vault/helper/consts" + retryablehttp "github.com/hashicorp/go-retryablehttp" ) @@ -124,7 +126,7 @@ func (r *Request) toRetryableHTTP() (*retryablehttp.Request, error) { } if len(r.ClientToken) != 0 { - req.Header.Set("X-Vault-Token", r.ClientToken) + req.Header.Set(consts.AuthHeaderName, r.ClientToken) } if len(r.WrapTTL) != 0 { diff --git a/vendor/github.com/hashicorp/vault/api/sys_audit.go b/vendor/github.com/hashicorp/vault/api/sys_audit.go index 3c195ad25..2448c0367 100644 --- a/vendor/github.com/hashicorp/vault/api/sys_audit.go +++ b/vendor/github.com/hashicorp/vault/api/sys_audit.go @@ -2,6 +2,7 @@ package api import ( "context" + "errors" "fmt" "github.com/mitchellh/mapstructure" @@ -25,17 +26,24 @@ func (c *Sys) AuditHash(path string, input string) (string, error) { } defer resp.Body.Close() - type d struct { - Hash string `json:"hash"` - } - - var result d - err = resp.DecodeJSON(&result) + secret, err := ParseSecret(resp.Body) if err != nil { return "", err } + if secret == nil || secret.Data == nil { + return "", errors.New("data from server response is empty") + } - return result.Hash, err + hash, ok := secret.Data["hash"] + if !ok { + return "", errors.New("hash not found in response data") + } + hashStr, ok := hash.(string) + if !ok { + return "", errors.New("could not parse hash in response data") + } + + return hashStr, nil } func (c *Sys) ListAudit() (map[string]*Audit, error) { @@ -50,29 +58,18 @@ func (c *Sys) ListAudit() (map[string]*Audit, error) { } defer resp.Body.Close() - var result map[string]interface{} - err = resp.DecodeJSON(&result) + 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") + } mounts := map[string]*Audit{} - for k, v := range result { - switch v.(type) { - case map[string]interface{}: - default: - continue - } - var res Audit - err = mapstructure.Decode(v, &res) - if err != nil { - return nil, err - } - // Not a mount, some other api.Secret data - if res.Type == "" { - continue - } - mounts[k] = &res + err = mapstructure.Decode(secret.Data, &mounts) + if err != nil { + return nil, err } return mounts, nil @@ -124,16 +121,16 @@ func (c *Sys) DisableAudit(path string) error { // documentation. Please refer to that documentation for more details. type EnableAuditOptions struct { - Type string `json:"type"` - Description string `json:"description"` - Options map[string]string `json:"options"` - Local bool `json:"local"` + Type string `json:"type" mapstructure:"type"` + Description string `json:"description" mapstructure:"description"` + Options map[string]string `json:"options" mapstructure:"options"` + Local bool `json:"local" mapstructure:"local"` } type Audit struct { - Path string - Type string - Description string - Options map[string]string - Local bool + Type string `json:"type" mapstructure:"type"` + Description string `json:"description" mapstructure:"description"` + Options map[string]string `json:"options" mapstructure:"options"` + Local bool `json:"local" mapstructure:"local"` + Path string `json:"path" mapstructure:"path"` } diff --git a/vendor/github.com/hashicorp/vault/api/sys_auth.go b/vendor/github.com/hashicorp/vault/api/sys_auth.go index 7d3a3f8c9..e7a9c222d 100644 --- a/vendor/github.com/hashicorp/vault/api/sys_auth.go +++ b/vendor/github.com/hashicorp/vault/api/sys_auth.go @@ -2,6 +2,7 @@ package api import ( "context" + "errors" "fmt" "github.com/mitchellh/mapstructure" @@ -18,29 +19,18 @@ func (c *Sys) ListAuth() (map[string]*AuthMount, error) { } defer resp.Body.Close() - var result map[string]interface{} - err = resp.DecodeJSON(&result) + 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") + } mounts := map[string]*AuthMount{} - for k, v := range result { - switch v.(type) { - case map[string]interface{}: - default: - continue - } - var res AuthMount - err = mapstructure.Decode(v, &res) - if err != nil { - return nil, err - } - // Not a mount, some other api.Secret data - if res.Type == "" { - continue - } - mounts[k] = &res + err = mapstructure.Decode(secret.Data, &mounts) + if err != nil { + return nil, err } return mounts, nil @@ -83,46 +73,8 @@ func (c *Sys) DisableAuth(path string) error { return err } -// Structures for the requests/resposne are all down here. They aren't -// individually documented because the map almost directly to the raw HTTP API -// documentation. Please refer to that documentation for more details. - -type EnableAuthOptions struct { - Type string `json:"type"` - Description string `json:"description"` - Config AuthConfigInput `json:"config"` - Local bool `json:"local"` - PluginName string `json:"plugin_name,omitempty"` - SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"` - Options map[string]string `json:"options" mapstructure:"options"` -} - -type AuthConfigInput struct { - DefaultLeaseTTL string `json:"default_lease_ttl" mapstructure:"default_lease_ttl"` - MaxLeaseTTL string `json:"max_lease_ttl" mapstructure:"max_lease_ttl"` - PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"` - AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" mapstructure:"audit_non_hmac_request_keys"` - AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" mapstructure:"audit_non_hmac_response_keys"` - ListingVisibility string `json:"listing_visibility,omitempty" mapstructure:"listing_visibility"` - PassthroughRequestHeaders []string `json:"passthrough_request_headers,omitempty" mapstructure:"passthrough_request_headers"` -} - -type AuthMount struct { - Type string `json:"type" mapstructure:"type"` - Description string `json:"description" mapstructure:"description"` - Accessor string `json:"accessor" mapstructure:"accessor"` - Config AuthConfigOutput `json:"config" mapstructure:"config"` - Local bool `json:"local" mapstructure:"local"` - SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"` - Options map[string]string `json:"options" mapstructure:"options"` -} - -type AuthConfigOutput struct { - DefaultLeaseTTL int `json:"default_lease_ttl" mapstructure:"default_lease_ttl"` - MaxLeaseTTL int `json:"max_lease_ttl" mapstructure:"max_lease_ttl"` - PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"` - AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" mapstructure:"audit_non_hmac_request_keys"` - AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" mapstructure:"audit_non_hmac_response_keys"` - ListingVisibility string `json:"listing_visibility,omitempty" mapstructure:"listing_visibility"` - PassthroughRequestHeaders []string `json:"passthrough_request_headers,omitempty" mapstructure:"passthrough_request_headers"` -} +// Rather than duplicate, we can use modern Go's type aliasing +type EnableAuthOptions = MountInput +type AuthConfigInput = MountConfigInput +type AuthMount = MountOutput +type AuthConfigOutput = MountConfigOutput diff --git a/vendor/github.com/hashicorp/vault/api/sys_capabilities.go b/vendor/github.com/hashicorp/vault/api/sys_capabilities.go index d4242a2aa..64b3951dd 100644 --- a/vendor/github.com/hashicorp/vault/api/sys_capabilities.go +++ b/vendor/github.com/hashicorp/vault/api/sys_capabilities.go @@ -2,7 +2,10 @@ package api import ( "context" + "errors" "fmt" + + "github.com/mitchellh/mapstructure" ) func (c *Sys) CapabilitiesSelf(path string) ([]string, error) { @@ -33,22 +36,29 @@ func (c *Sys) Capabilities(token, path string) ([]string, error) { } defer resp.Body.Close() - var result map[string]interface{} - err = resp.DecodeJSON(&result) + secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } - - if result["capabilities"] == nil { - return nil, nil + if secret == nil || secret.Data == nil { + return nil, errors.New("data from server response is empty") } - var capabilities []string - capabilitiesRaw, ok := result["capabilities"].([]interface{}) - if !ok { - return nil, fmt.Errorf("error interpreting returned capabilities") + + var res []string + err = mapstructure.Decode(secret.Data[path], &res) + if err != nil { + return nil, err } - for _, capability := range capabilitiesRaw { - capabilities = append(capabilities, capability.(string)) + + if len(res) == 0 { + _, ok := secret.Data["capabilities"] + if ok { + err = mapstructure.Decode(secret.Data["capabilities"], &res) + if err != nil { + return nil, err + } + } } - return capabilities, nil + + return res, nil } diff --git a/vendor/github.com/hashicorp/vault/api/sys_config_cors.go b/vendor/github.com/hashicorp/vault/api/sys_config_cors.go index 94ccbd72f..d153a47c3 100644 --- a/vendor/github.com/hashicorp/vault/api/sys_config_cors.go +++ b/vendor/github.com/hashicorp/vault/api/sys_config_cors.go @@ -1,6 +1,11 @@ package api -import "context" +import ( + "context" + "errors" + + "github.com/mitchellh/mapstructure" +) func (c *Sys) CORSStatus() (*CORSResponse, error) { r := c.c.NewRequest("GET", "/v1/sys/config/cors") @@ -13,8 +18,20 @@ func (c *Sys) CORSStatus() (*CORSResponse, error) { } 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 = resp.DecodeJSON(&result) + err = mapstructure.Decode(secret.Data, &result) + if err != nil { + return nil, err + } + return &result, err } @@ -32,8 +49,20 @@ func (c *Sys) ConfigureCORS(req *CORSRequest) (*CORSResponse, error) { } 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 = resp.DecodeJSON(&result) + err = mapstructure.Decode(secret.Data, &result) + if err != nil { + return nil, err + } + return &result, err } @@ -48,18 +77,29 @@ func (c *Sys) DisableCORS() (*CORSResponse, error) { } 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 = resp.DecodeJSON(&result) - return &result, err + err = mapstructure.Decode(secret.Data, &result) + if err != nil { + return nil, err + } + return &result, err } type CORSRequest struct { - AllowedOrigins string `json:"allowed_origins"` - Enabled bool `json:"enabled"` + AllowedOrigins string `json:"allowed_origins" mapstructure:"allowed_origins"` + Enabled bool `json:"enabled" mapstructure:"enabled"` } type CORSResponse struct { - AllowedOrigins string `json:"allowed_origins"` - Enabled bool `json:"enabled"` + AllowedOrigins string `json:"allowed_origins" mapstructure:"allowed_origins"` + Enabled bool `json:"enabled" mapstructure:"enabled"` } diff --git a/vendor/github.com/hashicorp/vault/api/sys_generate_root.go b/vendor/github.com/hashicorp/vault/api/sys_generate_root.go index ec7314da1..66f72dff6 100644 --- a/vendor/github.com/hashicorp/vault/api/sys_generate_root.go +++ b/vendor/github.com/hashicorp/vault/api/sys_generate_root.go @@ -119,4 +119,6 @@ type GenerateRootStatusResponse struct { EncodedToken string `json:"encoded_token"` EncodedRootToken string `json:"encoded_root_token"` PGPFingerprint string `json:"pgp_fingerprint"` + OTP string `json:"otp"` + OTPLength int `json:"otp_length"` } diff --git a/vendor/github.com/hashicorp/vault/api/sys_health.go b/vendor/github.com/hashicorp/vault/api/sys_health.go index f49d05b67..e4c60d446 100644 --- a/vendor/github.com/hashicorp/vault/api/sys_health.go +++ b/vendor/github.com/hashicorp/vault/api/sys_health.go @@ -11,6 +11,7 @@ func (c *Sys) Health() (*HealthResponse, error) { r.Params.Add("sealedcode", "299") r.Params.Add("standbycode", "299") r.Params.Add("drsecondarycode", "299") + r.Params.Add("performancestandbycode", "299") ctx, cancelFunc := context.WithCancel(context.Background()) defer cancelFunc() @@ -35,4 +36,5 @@ type HealthResponse struct { Version string `json:"version"` ClusterName string `json:"cluster_name,omitempty"` ClusterID string `json:"cluster_id,omitempty"` + LastWAL uint64 `json:"last_wal,omitempty"` } diff --git a/vendor/github.com/hashicorp/vault/api/sys_leader.go b/vendor/github.com/hashicorp/vault/api/sys_leader.go index 170a55ffb..8846dcdfa 100644 --- a/vendor/github.com/hashicorp/vault/api/sys_leader.go +++ b/vendor/github.com/hashicorp/vault/api/sys_leader.go @@ -19,8 +19,11 @@ 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"` + 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"` } diff --git a/vendor/github.com/hashicorp/vault/api/sys_mounts.go b/vendor/github.com/hashicorp/vault/api/sys_mounts.go index 29a469f37..f5993c708 100644 --- a/vendor/github.com/hashicorp/vault/api/sys_mounts.go +++ b/vendor/github.com/hashicorp/vault/api/sys_mounts.go @@ -2,6 +2,7 @@ package api import ( "context" + "errors" "fmt" "github.com/mitchellh/mapstructure" @@ -18,29 +19,18 @@ func (c *Sys) ListMounts() (map[string]*MountOutput, error) { } defer resp.Body.Close() - var result map[string]interface{} - err = resp.DecodeJSON(&result) + 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") + } mounts := map[string]*MountOutput{} - for k, v := range result { - switch v.(type) { - case map[string]interface{}: - default: - continue - } - var res MountOutput - err = mapstructure.Decode(v, &res) - if err != nil { - return nil, err - } - // Not a mount, some other api.Secret data - if res.Type == "" { - continue - } - mounts[k] = &res + err = mapstructure.Decode(secret.Data, &mounts) + if err != nil { + return nil, err } return mounts, nil @@ -121,8 +111,16 @@ func (c *Sys) MountConfig(path string) (*MountConfigOutput, error) { } 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 MountConfigOutput - err = resp.DecodeJSON(&result) + err = mapstructure.Decode(secret.Data, &result) if err != nil { return nil, err } @@ -134,10 +132,13 @@ type MountInput struct { Type string `json:"type"` Description string `json:"description"` Config MountConfigInput `json:"config"` - Options map[string]string `json:"options"` Local bool `json:"local"` - PluginName string `json:"plugin_name,omitempty"` SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"` + Options map[string]string `json:"options"` + + // Deprecated: Newer server responses should be returning this information in the + // Type field (json: "type") instead. + PluginName string `json:"plugin_name,omitempty"` } type MountConfigInput struct { @@ -146,11 +147,14 @@ type MountConfigInput struct { Description *string `json:"description,omitempty" mapstructure:"description"` MaxLeaseTTL string `json:"max_lease_ttl" mapstructure:"max_lease_ttl"` ForceNoCache bool `json:"force_no_cache" mapstructure:"force_no_cache"` - PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"` AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" mapstructure:"audit_non_hmac_request_keys"` AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" mapstructure:"audit_non_hmac_response_keys"` ListingVisibility string `json:"listing_visibility,omitempty" mapstructure:"listing_visibility"` PassthroughRequestHeaders []string `json:"passthrough_request_headers,omitempty" mapstructure:"passthrough_request_headers"` + TokenType string `json:"token_type,omitempty" mapstructure:"token_type"` + + // Deprecated: This field will always be blank for newer server responses. + PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"` } type MountOutput struct { @@ -167,9 +171,12 @@ type MountConfigOutput struct { DefaultLeaseTTL int `json:"default_lease_ttl" mapstructure:"default_lease_ttl"` MaxLeaseTTL int `json:"max_lease_ttl" mapstructure:"max_lease_ttl"` ForceNoCache bool `json:"force_no_cache" mapstructure:"force_no_cache"` - PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"` AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" mapstructure:"audit_non_hmac_request_keys"` AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" mapstructure:"audit_non_hmac_response_keys"` ListingVisibility string `json:"listing_visibility,omitempty" mapstructure:"listing_visibility"` PassthroughRequestHeaders []string `json:"passthrough_request_headers,omitempty" mapstructure:"passthrough_request_headers"` + TokenType string `json:"token_type,omitempty" mapstructure:"token_type"` + + // Deprecated: This field will always be blank for newer server responses. + PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"` } diff --git a/vendor/github.com/hashicorp/vault/api/sys_plugins.go b/vendor/github.com/hashicorp/vault/api/sys_plugins.go index 218f8e938..d15165ee9 100644 --- a/vendor/github.com/hashicorp/vault/api/sys_plugins.go +++ b/vendor/github.com/hashicorp/vault/api/sys_plugins.go @@ -2,24 +2,46 @@ package api import ( "context" + "errors" "fmt" "net/http" + + "github.com/hashicorp/vault/helper/consts" + "github.com/mitchellh/mapstructure" ) // ListPluginsInput is used as input to the ListPlugins function. -type ListPluginsInput struct{} +type ListPluginsInput struct { + // Type of the plugin. Required. + Type consts.PluginType `json:"type"` +} // ListPluginsResponse is the response from the ListPlugins call. type ListPluginsResponse struct { + // PluginsByType is the list of plugins by type. + PluginsByType map[consts.PluginType][]string `json:"types"` + // Names is the list of names of the plugins. - Names []string + // + // Deprecated: Newer server responses should be returning PluginsByType (json: + // "types") instead. + Names []string `json:"names"` } // ListPlugins lists all plugins in the catalog and returns their names as a // list of strings. func (c *Sys) ListPlugins(i *ListPluginsInput) (*ListPluginsResponse, error) { - path := "/v1/sys/plugins/catalog" - req := c.c.NewRequest("LIST", path) + path := "" + method := "" + if i.Type == consts.PluginTypeUnknown { + path = "/v1/sys/plugins/catalog" + method = "GET" + } else { + path = fmt.Sprintf("/v1/sys/plugins/catalog/%s", i.Type) + method = "LIST" + } + + req := c.c.NewRequest(method, path) ctx, cancelFunc := context.WithCancel(context.Background()) defer cancelFunc() @@ -29,21 +51,76 @@ func (c *Sys) ListPlugins(i *ListPluginsInput) (*ListPluginsResponse, error) { } defer resp.Body.Close() - var result struct { - Data struct { - Keys []string `json:"keys"` - } `json:"data"` - } - if err := resp.DecodeJSON(&result); err != nil { + 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") + } + + if resp.StatusCode == 405 && req.Method == "GET" { + // We received an Unsupported Operation response from Vault, indicating + // Vault of an older version that doesn't support the READ method yet. + req.Method = "LIST" + resp, err := c.c.RawRequestWithContext(ctx, req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + var result struct { + Data struct { + Keys []string `json:"keys"` + } `json:"data"` + } + if err := resp.DecodeJSON(&result); err != nil { + return nil, err + } + return &ListPluginsResponse{Names: result.Data.Keys}, nil + } - return &ListPluginsResponse{Names: result.Data.Keys}, nil + result := &ListPluginsResponse{ + PluginsByType: make(map[consts.PluginType][]string), + } + if i.Type == consts.PluginTypeUnknown { + for pluginTypeStr, pluginsRaw := range secret.Data { + pluginType, err := consts.ParsePluginType(pluginTypeStr) + if err != nil { + return nil, err + } + + pluginsIfc, ok := pluginsRaw.([]interface{}) + if !ok { + return nil, fmt.Errorf("unable to parse plugins for %q type", pluginTypeStr) + } + + plugins := make([]string, len(pluginsIfc)) + for i, nameIfc := range pluginsIfc { + name, ok := nameIfc.(string) + if !ok { + + } + plugins[i] = name + } + result.PluginsByType[pluginType] = plugins + } + } else { + var respKeys []string + if err := mapstructure.Decode(secret.Data["keys"], &respKeys); err != nil { + return nil, err + } + result.PluginsByType[i.Type] = respKeys + } + + return result, nil } // GetPluginInput is used as input to the GetPlugin function. type GetPluginInput struct { Name string `json:"-"` + + // Type of the plugin. Required. + Type consts.PluginType `json:"type"` } // GetPluginResponse is the response from the GetPlugin call. @@ -55,8 +132,9 @@ type GetPluginResponse struct { SHA256 string `json:"sha256"` } +// GetPlugin retrieves information about the plugin. func (c *Sys) GetPlugin(i *GetPluginInput) (*GetPluginResponse, error) { - path := fmt.Sprintf("/v1/sys/plugins/catalog/%s", i.Name) + path := catalogPathByType(i.Type, i.Name) req := c.c.NewRequest(http.MethodGet, path) ctx, cancelFunc := context.WithCancel(context.Background()) @@ -68,13 +146,13 @@ func (c *Sys) GetPlugin(i *GetPluginInput) (*GetPluginResponse, error) { defer resp.Body.Close() var result struct { - Data GetPluginResponse + Data *GetPluginResponse } err = resp.DecodeJSON(&result) if err != nil { return nil, err } - return &result.Data, err + return result.Data, err } // RegisterPluginInput is used as input to the RegisterPlugin function. @@ -82,6 +160,9 @@ type RegisterPluginInput struct { // Name is the name of the plugin. Required. Name string `json:"-"` + // Type of the plugin. Required. + Type consts.PluginType `json:"type"` + // Args is the list of args to spawn the process with. Args []string `json:"args,omitempty"` @@ -94,8 +175,9 @@ type RegisterPluginInput struct { // RegisterPlugin registers the plugin with the given information. func (c *Sys) RegisterPlugin(i *RegisterPluginInput) error { - path := fmt.Sprintf("/v1/sys/plugins/catalog/%s", i.Name) + path := catalogPathByType(i.Type, i.Name) req := c.c.NewRequest(http.MethodPut, path) + if err := req.SetJSONBody(i); err != nil { return err } @@ -113,12 +195,15 @@ func (c *Sys) RegisterPlugin(i *RegisterPluginInput) error { type DeregisterPluginInput struct { // Name is the name of the plugin. Required. Name string `json:"-"` + + // Type of the plugin. Required. + Type consts.PluginType `json:"type"` } // DeregisterPlugin removes the plugin with the given name from the plugin // catalog. func (c *Sys) DeregisterPlugin(i *DeregisterPluginInput) error { - path := fmt.Sprintf("/v1/sys/plugins/catalog/%s", i.Name) + path := catalogPathByType(i.Type, i.Name) req := c.c.NewRequest(http.MethodDelete, path) ctx, cancelFunc := context.WithCancel(context.Background()) @@ -129,3 +214,15 @@ func (c *Sys) DeregisterPlugin(i *DeregisterPluginInput) error { } return err } + +// catalogPathByType is a helper to construct the proper API path by plugin type +func catalogPathByType(pluginType consts.PluginType, name string) string { + path := fmt.Sprintf("/v1/sys/plugins/catalog/%s/%s", pluginType, name) + + // Backwards compat, if type is not provided then use old path + if pluginType == consts.PluginTypeUnknown { + path = fmt.Sprintf("/v1/sys/plugins/catalog/%s", name) + } + + return path +} diff --git a/vendor/github.com/hashicorp/vault/api/sys_policy.go b/vendor/github.com/hashicorp/vault/api/sys_policy.go index 4b535fb39..cdbb3f75a 100644 --- a/vendor/github.com/hashicorp/vault/api/sys_policy.go +++ b/vendor/github.com/hashicorp/vault/api/sys_policy.go @@ -2,11 +2,14 @@ package api import ( "context" + "errors" "fmt" + + "github.com/mitchellh/mapstructure" ) func (c *Sys) ListPolicies() ([]string, error) { - r := c.c.NewRequest("GET", "/v1/sys/policy") + r := c.c.NewRequest("LIST", "/v1/sys/policies/acl") ctx, cancelFunc := context.WithCancel(context.Background()) defer cancelFunc() @@ -16,29 +19,25 @@ func (c *Sys) ListPolicies() ([]string, error) { } defer resp.Body.Close() - var result map[string]interface{} - err = resp.DecodeJSON(&result) + secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } - - var ok bool - if _, ok = result["policies"]; !ok { - return nil, fmt.Errorf("policies not found in response") + if secret == nil || secret.Data == nil { + return nil, errors.New("data from server response is empty") } - listRaw := result["policies"].([]interface{}) - var policies []string - - for _, val := range listRaw { - policies = append(policies, val.(string)) + var result []string + err = mapstructure.Decode(secret.Data["keys"], &result) + if err != nil { + return nil, err } - return policies, err + return result, err } func (c *Sys) GetPolicy(name string) (string, error) { - r := c.c.NewRequest("GET", fmt.Sprintf("/v1/sys/policy/%s", name)) + r := c.c.NewRequest("GET", fmt.Sprintf("/v1/sys/policies/acl/%s", name)) ctx, cancelFunc := context.WithCancel(context.Background()) defer cancelFunc() @@ -53,16 +52,15 @@ func (c *Sys) GetPolicy(name string) (string, error) { return "", err } - var result map[string]interface{} - err = resp.DecodeJSON(&result) + secret, err := ParseSecret(resp.Body) if err != nil { return "", err } - - if rulesRaw, ok := result["rules"]; ok { - return rulesRaw.(string), nil + if secret == nil || secret.Data == nil { + return "", errors.New("data from server response is empty") } - if policyRaw, ok := result["policy"]; ok { + + if policyRaw, ok := secret.Data["policy"]; ok { return policyRaw.(string), nil } @@ -71,10 +69,10 @@ func (c *Sys) GetPolicy(name string) (string, error) { func (c *Sys) PutPolicy(name, rules string) error { body := map[string]string{ - "rules": rules, + "policy": rules, } - r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/sys/policy/%s", name)) + r := c.c.NewRequest("PUT", fmt.Sprintf("/v1/sys/policies/acl/%s", name)) if err := r.SetJSONBody(body); err != nil { return err } @@ -91,7 +89,7 @@ func (c *Sys) PutPolicy(name, rules string) error { } func (c *Sys) DeletePolicy(name string) error { - r := c.c.NewRequest("DELETE", fmt.Sprintf("/v1/sys/policy/%s", name)) + r := c.c.NewRequest("DELETE", fmt.Sprintf("/v1/sys/policies/acl/%s", name)) ctx, cancelFunc := context.WithCancel(context.Background()) defer cancelFunc() diff --git a/vendor/github.com/hashicorp/vault/api/sys_rekey.go b/vendor/github.com/hashicorp/vault/api/sys_rekey.go index 89ad11d5a..55f1a703d 100644 --- a/vendor/github.com/hashicorp/vault/api/sys_rekey.go +++ b/vendor/github.com/hashicorp/vault/api/sys_rekey.go @@ -1,6 +1,11 @@ package api -import "context" +import ( + "context" + "errors" + + "github.com/mitchellh/mapstructure" +) func (c *Sys) RekeyStatus() (*RekeyStatusResponse, error) { r := c.c.NewRequest("GET", "/v1/sys/rekey/init") @@ -211,8 +216,20 @@ func (c *Sys) RekeyRetrieveBackup() (*RekeyRetrieveResponse, error) { } 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 RekeyRetrieveResponse - err = resp.DecodeJSON(&result) + err = mapstructure.Decode(secret.Data, &result) + if err != nil { + return nil, err + } + return &result, err } @@ -227,8 +244,20 @@ func (c *Sys) RekeyRetrieveRecoveryBackup() (*RekeyRetrieveResponse, error) { } 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 RekeyRetrieveResponse - err = resp.DecodeJSON(&result) + err = mapstructure.Decode(secret.Data, &result) + if err != nil { + return nil, err + } + return &result, err } @@ -340,9 +369,9 @@ type RekeyUpdateResponse struct { } type RekeyRetrieveResponse struct { - Nonce string `json:"nonce"` - Keys map[string][]string `json:"keys"` - KeysB64 map[string][]string `json:"keys_base64"` + Nonce string `json:"nonce" mapstructure:"nonce"` + Keys map[string][]string `json:"keys" mapstructure:"keys"` + KeysB64 map[string][]string `json:"keys_base64" mapstructure:"keys_base64"` } type RekeyVerificationStatusResponse struct { diff --git a/vendor/github.com/hashicorp/vault/api/sys_rotate.go b/vendor/github.com/hashicorp/vault/api/sys_rotate.go index c7f97ce3b..c525feb00 100644 --- a/vendor/github.com/hashicorp/vault/api/sys_rotate.go +++ b/vendor/github.com/hashicorp/vault/api/sys_rotate.go @@ -2,6 +2,8 @@ package api import ( "context" + "encoding/json" + "errors" "time" ) @@ -28,9 +30,45 @@ func (c *Sys) KeyStatus() (*KeyStatus, error) { } defer resp.Body.Close() - result := new(KeyStatus) - err = resp.DecodeJSON(result) - return result, 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 KeyStatus + + termRaw, ok := secret.Data["term"] + if !ok { + return nil, errors.New("term not found in response") + } + term, ok := termRaw.(json.Number) + if !ok { + return nil, errors.New("could not convert term to a number") + } + term64, err := term.Int64() + if err != nil { + return nil, err + } + result.Term = int(term64) + + installTimeRaw, ok := secret.Data["install_time"] + if !ok { + return nil, errors.New("install_time not found in response") + } + installTimeStr, ok := installTimeRaw.(string) + if !ok { + return nil, errors.New("could not convert install_time to a string") + } + installTime, err := time.Parse(time.RFC3339Nano, installTimeStr) + if err != nil { + return nil, err + } + result.InstallTime = installTime + + return &result, err } type KeyStatus struct { diff --git a/vendor/github.com/hashicorp/vault/api/sys_seal.go b/vendor/github.com/hashicorp/vault/api/sys_seal.go index 7cc32ac33..301d3f26a 100644 --- a/vendor/github.com/hashicorp/vault/api/sys_seal.go +++ b/vendor/github.com/hashicorp/vault/api/sys_seal.go @@ -41,6 +41,15 @@ func (c *Sys) Unseal(shard string) (*SealStatusResponse, error) { return sealStatusRequest(c, r) } +func (c *Sys) UnsealWithOptions(opts *UnsealOpts) (*SealStatusResponse, error) { + r := c.c.NewRequest("PUT", "/v1/sys/unseal") + if err := r.SetJSONBody(opts); err != nil { + return nil, err + } + + return sealStatusRequest(c, r) +} + func sealStatusRequest(c *Sys, r *Request) (*SealStatusResponse, error) { ctx, cancelFunc := context.WithCancel(context.Background()) defer cancelFunc() @@ -57,13 +66,21 @@ func sealStatusRequest(c *Sys, r *Request) (*SealStatusResponse, error) { type SealStatusResponse struct { Type string `json:"type"` + Initialized bool `json:"initialized"` Sealed bool `json:"sealed"` T int `json:"t"` N int `json:"n"` Progress int `json:"progress"` Nonce string `json:"nonce"` Version string `json:"version"` + Migration bool `json:"migration"` ClusterName string `json:"cluster_name,omitempty"` ClusterID string `json:"cluster_id,omitempty"` RecoverySeal bool `json:"recovery_seal"` } + +type UnsealOpts struct { + Key string `json:"key"` + Reset bool `json:"reset"` + Migrate bool `json:"migrate"` +} diff --git a/vendor/github.com/hashicorp/vault/api/sys_stepdown.go b/vendor/github.com/hashicorp/vault/api/sys_stepdown.go index 21db3d8e5..55dc6fbcb 100644 --- a/vendor/github.com/hashicorp/vault/api/sys_stepdown.go +++ b/vendor/github.com/hashicorp/vault/api/sys_stepdown.go @@ -8,8 +8,8 @@ func (c *Sys) StepDown() error { ctx, cancelFunc := context.WithCancel(context.Background()) defer cancelFunc() resp, err := c.c.RawRequestWithContext(ctx, r) - if err == nil { - defer resp.Body.Close() + if resp != nil && resp.Body != nil { + resp.Body.Close() } return err } diff --git a/vendor/github.com/hashicorp/vault/helper/consts/consts.go b/vendor/github.com/hashicorp/vault/helper/consts/consts.go new file mode 100644 index 000000000..972a69f47 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/consts/consts.go @@ -0,0 +1,14 @@ +package consts + +const ( + // ExpirationRestoreWorkerCount specifies the number of workers to use while + // restoring leases into the expiration manager + ExpirationRestoreWorkerCount = 64 + + // NamespaceHeaderName is the header set to specify which namespace the + // request is indented for. + NamespaceHeaderName = "X-Vault-Namespace" + + // AuthHeaderName is the name of the header containing the token. + AuthHeaderName = "X-Vault-Token" +) diff --git a/vendor/github.com/hashicorp/vault/helper/consts/error.go b/vendor/github.com/hashicorp/vault/helper/consts/error.go new file mode 100644 index 000000000..06977d5d5 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/consts/error.go @@ -0,0 +1,16 @@ +package consts + +import "errors" + +var ( + // ErrSealed is returned if an operation is performed on a sealed barrier. + // No operation is expected to succeed before unsealing + ErrSealed = errors.New("Vault is sealed") + + // ErrStandby is returned if an operation is performed on a standby Vault. + // No operation is expected to succeed until active. + ErrStandby = errors.New("Vault is in standby mode") + + // Used when .. is used in a path + ErrPathContainsParentReferences = errors.New("path cannot contain parent references") +) diff --git a/vendor/github.com/hashicorp/vault/helper/consts/plugin_types.go b/vendor/github.com/hashicorp/vault/helper/consts/plugin_types.go new file mode 100644 index 000000000..e0a00e486 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/consts/plugin_types.go @@ -0,0 +1,59 @@ +package consts + +import "fmt" + +var PluginTypes = []PluginType{ + PluginTypeUnknown, + PluginTypeCredential, + PluginTypeDatabase, + PluginTypeSecrets, +} + +type PluginType uint32 + +// This is a list of PluginTypes used by Vault. +// If we need to add any in the future, it would +// be best to add them to the _end_ of the list below +// because they resolve to incrementing numbers, +// which may be saved in state somewhere. Thus if +// the name for one of those numbers changed because +// a value were added to the middle, that could cause +// the wrong plugin types to be read from storage +// for a given underlying number. Example of the problem +// here: https://play.golang.org/p/YAaPw5ww3er +const ( + PluginTypeUnknown PluginType = iota + PluginTypeCredential + PluginTypeDatabase + PluginTypeSecrets +) + +func (p PluginType) String() string { + switch p { + case PluginTypeUnknown: + return "unknown" + case PluginTypeCredential: + return "auth" + case PluginTypeDatabase: + return "database" + case PluginTypeSecrets: + return "secret" + default: + return "unsupported" + } +} + +func ParsePluginType(pluginType string) (PluginType, error) { + switch pluginType { + case "unknown": + return PluginTypeUnknown, nil + case "auth": + return PluginTypeCredential, nil + case "database": + return PluginTypeDatabase, nil + case "secret": + return PluginTypeSecrets, nil + default: + return PluginTypeUnknown, fmt.Errorf("%q is not a supported plugin type", pluginType) + } +} diff --git a/vendor/github.com/hashicorp/vault/helper/consts/replication.go b/vendor/github.com/hashicorp/vault/helper/consts/replication.go new file mode 100644 index 000000000..bdad15522 --- /dev/null +++ b/vendor/github.com/hashicorp/vault/helper/consts/replication.go @@ -0,0 +1,87 @@ +package consts + +import "time" + +type ReplicationState uint32 + +var ReplicationStaleReadTimeout = 2 * time.Second + +const ( + _ ReplicationState = iota + OldReplicationPrimary + OldReplicationSecondary + OldReplicationBootstrapping + // Don't add anything here. Adding anything to this Old block would cause + // the rest of the values to change below. This was done originally to + // ensure no overlap between old and new values. + + ReplicationUnknown ReplicationState = 0 + ReplicationPerformancePrimary ReplicationState = 1 << iota + ReplicationPerformanceSecondary + OldSplitReplicationBootstrapping + ReplicationDRPrimary + ReplicationDRSecondary + ReplicationPerformanceBootstrapping + ReplicationDRBootstrapping + ReplicationPerformanceDisabled + ReplicationDRDisabled + ReplicationPerformanceStandby +) + +func (r ReplicationState) string() string { + switch r { + case ReplicationPerformanceSecondary: + return "secondary" + case ReplicationPerformancePrimary: + return "primary" + case ReplicationPerformanceBootstrapping: + return "bootstrapping" + case ReplicationPerformanceDisabled: + return "disabled" + case ReplicationDRPrimary: + return "primary" + case ReplicationDRSecondary: + return "secondary" + case ReplicationDRBootstrapping: + return "bootstrapping" + case ReplicationDRDisabled: + return "disabled" + } + + return "unknown" +} + +func (r ReplicationState) GetDRString() string { + switch { + case r.HasState(ReplicationDRBootstrapping): + return ReplicationDRBootstrapping.string() + case r.HasState(ReplicationDRPrimary): + return ReplicationDRPrimary.string() + case r.HasState(ReplicationDRSecondary): + return ReplicationDRSecondary.string() + case r.HasState(ReplicationDRDisabled): + return ReplicationDRDisabled.string() + default: + return "unknown" + } +} + +func (r ReplicationState) GetPerformanceString() string { + switch { + case r.HasState(ReplicationPerformanceBootstrapping): + return ReplicationPerformanceBootstrapping.string() + case r.HasState(ReplicationPerformancePrimary): + return ReplicationPerformancePrimary.string() + case r.HasState(ReplicationPerformanceSecondary): + return ReplicationPerformanceSecondary.string() + case r.HasState(ReplicationPerformanceDisabled): + return ReplicationPerformanceDisabled.string() + default: + return "unknown" + } +} + +func (r ReplicationState) HasState(flag ReplicationState) bool { return r&flag != 0 } +func (r *ReplicationState) AddState(flag ReplicationState) { *r |= flag } +func (r *ReplicationState) ClearState(flag ReplicationState) { *r &= ^flag } +func (r *ReplicationState) ToggleState(flag ReplicationState) { *r ^= flag } diff --git a/vendor/vendor.json b/vendor/vendor.json index cbd1c7ec0..ae5920ab2 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -438,10 +438,10 @@ "revisionTime": "2016-01-19T13:13:26-08:00" }, { - "checksumSHA1": "nBmnbC438E5CNF1kRCnivCnqsEM=", + "checksumSHA1": "fmBqxy85Q0iaiJ144S8+nYUn0rs=", "path": "github.com/hashicorp/vault/api", - "revision": "f348177b5d55dbd38d039b814bf34cbc9cfc093b", - "revisionTime": "2018-07-27T12:33:20Z" + "revision": "d4367e581fe117356c4d4ac9a8c8c4e514457449", + "revisionTime": "2018-11-21T18:10:53Z" }, { "checksumSHA1": "bSdPFOHaTwEvM4PIvn0PZfn75jM=", @@ -449,6 +449,12 @@ "revision": "f348177b5d55dbd38d039b814bf34cbc9cfc093b", "revisionTime": "2018-07-27T12:33:20Z" }, + { + "checksumSHA1": "MQKcgExxbVHltqyTjVbDuHlkfLw=", + "path": "github.com/hashicorp/vault/helper/consts", + "revision": "d4367e581fe117356c4d4ac9a8c8c4e514457449", + "revisionTime": "2018-11-21T18:10:53Z" + }, { "checksumSHA1": "RlqPBLOexQ0jj6jomhiompWKaUg=", "path": "github.com/hashicorp/vault/helper/hclutil",