Add the ability for warnings to be added to responses. These are

marshalled into JSON or displayed from the CLI depending on the output
mode. This allows conferring information such as "no such policy exists"
when creating a token -- not an error, but something the user should be
aware of.

Fixes #676
This commit is contained in:
Jeff Mitchell
2015-10-07 15:30:54 -04:00
parent 89ee5d8d3b
commit fd2c0f033e
5 changed files with 64 additions and 1 deletions

View File

@@ -15,6 +15,11 @@ type Secret struct {
// is arbitrary and up to the secret backend.
Data map[string]interface{} `json:"data"`
// Warnings contains any warnings related to the operation. These
// are not issues that caused the command to fail, but that the
// client should be aware of.
Warnings []string `json:"warnings"`
// Auth, if non-nil, means that there was authentication information
// attached to this response.
Auth *SecretAuth `json:"auth,omitempty"`

View File

@@ -43,6 +43,7 @@ func outputFormatTable(ui cli.Ui, s *api.Secret, whitespace bool) int {
config.Prefix = ""
input := make([]string, 0, 5)
input = append(input, fmt.Sprintf("Key %s Value", config.Delim))
if s.LeaseDuration > 0 {
@@ -71,6 +72,14 @@ func outputFormatTable(ui cli.Ui, s *api.Secret, whitespace bool) int {
input = append(input, fmt.Sprintf("%s %s %v", k, config.Delim, v))
}
if len(s.Warnings) != 0 {
input = append(input, "")
input = append(input, "The following warnings were generated:")
for _, warning := range s.Warnings {
input = append(input, fmt.Sprintf("* %s", warning))
}
}
ui.Output(columnize.Format(input, config))
return 0
}

View File

@@ -96,7 +96,10 @@ func respondLogical(w http.ResponseWriter, r *http.Request, path string, dataOnl
return
}
logicalResp := &LogicalResponse{Data: resp.Data}
logicalResp := &LogicalResponse{
Data: resp.Data,
Warnings: resp.GetWarnings(),
}
if resp.Secret != nil {
logicalResp.LeaseID = resp.Secret.LeaseID
logicalResp.Renewable = resp.Secret.Renewable
@@ -196,6 +199,7 @@ type LogicalResponse struct {
Renewable bool `json:"renewable"`
LeaseDuration int `json:"lease_duration"`
Data map[string]interface{} `json:"data"`
Warnings []string `json:"warnings"`
Auth *Auth `json:"auth"`
}

View File

@@ -40,6 +40,28 @@ type Response struct {
// This is only valid for credential backends. This will be blanked
// for any logical backend and ignored.
Redirect string
// Warnings allow operations or backends to return warnings in response
// to user actions without failing the action outright.
// Making it private helps ensure that it is easy for various parts of
// Vault (backend, core, etc.) to add warnings without accidentally
// replacing what exists.
warnings []string
}
func (r *Response) AddWarning(warning string) {
if r.warnings == nil {
r.warnings = make([]string, 0, 1)
}
r.warnings = append(r.warnings, warning)
}
func (r *Response) GetWarnings() []string {
return r.warnings
}
func (r *Response) ClearWarnings() {
r.warnings = make([]string, 0, 1)
}
// IsError returns true if this response seems to indicate an error.

View File

@@ -46,6 +46,8 @@ type TokenStore struct {
expiration *ExpirationManager
cubbyholeBackend *CubbyholeBackend
policyLookupFunc func() ([]string, error)
}
// NewTokenStore is used to construct a token store that is
@@ -59,6 +61,10 @@ func NewTokenStore(c *Core, config *logical.BackendConfig) (*TokenStore, error)
view: view,
}
if c.policy != nil {
t.policyLookupFunc = c.policy.ListPolicies
}
// Setup the salt
salt, err := salt.NewSalt(view, &salt.Config{
HashFunc: salt.SHA1Hash,
@@ -636,6 +642,23 @@ func (ts *TokenStore) handleCreate(
},
}
if ts.policyLookupFunc != nil {
availPolicies, err := ts.policyLookupFunc()
if err == nil {
policies := map[string]bool{}
if availPolicies != nil && len(availPolicies) > 0 {
for _, p := range availPolicies {
policies[p] = true
}
}
for _, p := range te.Policies {
if !policies[p] {
resp.AddWarning(fmt.Sprintf("policy \"%s\" does not exist", p))
}
}
}
}
return resp, nil
}