Merge branch 'master-oss' into postgres-pl-lock

This commit is contained in:
Jeff Mitchell 2016-06-28 11:00:14 -04:00
commit f7a6515889
7 changed files with 62 additions and 74 deletions

View file

@ -26,6 +26,10 @@ IMPROVEMENTS:
different paths using the command options [GH-1532]
* cli: `vault auth -methods` will now display the config settings of the mount
[GH-1531]
* cli: `vault read/write/unwrap -field` now allows selecting token response
fields [GH-1567]
* cli: `vault write -field` now allows selecting wrapped response fields
[GH-1567]
* credential/aws-ec2: Added a new constraint, 'bound_account_id' to the role
[GH-1523]
* secret/aws: Listing of roles is supported now [GH-1546]
@ -38,6 +42,8 @@ BUG FIXES:
during renewal [GH-1542]
* core: Fix regression causing status codes to be `400` in most non-5xx error
cases [GH-1553]
* physical/postgres: Remove use of prepared statements as this causes
connection multiplexing software to break [GH-1548]
## 0.6.0 (June 14th, 2016)

View file

@ -230,7 +230,7 @@ func TestServer_ReloadListener(t *testing.T) {
}
checkFinished()
time.Sleep(2 * time.Second)
time.Sleep(5 * time.Second)
checkFinished()
if err := testCertificateName("foo.example.com"); err != nil {

View file

@ -31,27 +31,44 @@ func DefaultTokenHelper() (token.TokenHelper, error) {
func PrintRawField(ui cli.Ui, secret *api.Secret, field string) int {
var val interface{}
switch field {
case "wrapping_token":
if secret.WrapInfo != nil {
switch {
case secret.Auth != nil:
switch field {
case "token":
val = secret.Auth.ClientToken
case "token_accessor":
val = secret.Auth.Accessor
case "token_duration":
val = secret.Auth.LeaseDuration
case "token_renewable":
val = secret.Auth.Renewable
case "token_policies":
val = secret.Auth.Policies
default:
val = secret.Data[field]
}
case secret.WrapInfo != nil:
switch field {
case "wrapping_token":
val = secret.WrapInfo.Token
}
case "wrapping_token_ttl":
if secret.WrapInfo != nil {
case "wrapping_token_ttl":
val = secret.WrapInfo.TTL
}
case "wrapping_token_creation_time":
if secret.WrapInfo != nil {
case "wrapping_token_creation_time":
val = secret.WrapInfo.CreationTime.String()
}
case "wrapped_accessor":
if secret.WrapInfo != nil {
case "wrapped_accessor":
val = secret.WrapInfo.WrappedAccessor
default:
val = secret.Data[field]
}
case "refresh_interval":
val = secret.LeaseDuration
default:
val = secret.Data[field]
switch field {
case "refresh_interval":
val = secret.LeaseDuration
default:
val = secret.Data[field]
}
}
if val != nil {

View file

@ -4,7 +4,6 @@ import (
"fmt"
"io"
"os"
"reflect"
"strings"
"github.com/hashicorp/vault/helper/kv-builder"
@ -75,23 +74,7 @@ func (c *WriteCommand) Run(args []string) int {
// Handle single field output
if field != "" {
if val, ok := secret.Data[field]; ok {
// c.Ui.Output() prints a CR character which in this case is
// not desired. Since Vault CLI currently only uses BasicUi,
// which writes to standard output, os.Stdout is used here to
// directly print the message. If mitchellh/cli exposes method
// to print without CR, this check needs to be removed.
if reflect.TypeOf(c.Ui).String() == "*cli.BasicUi" {
fmt.Fprintf(os.Stdout, fmt.Sprintf("%v", val))
} else {
c.Ui.Output(fmt.Sprintf("%v", val))
}
return 0
} else {
c.Ui.Error(fmt.Sprintf(
"Field %s not present in secret", field))
return 1
}
return PrintRawField(c.Ui, secret, field)
}
return OutputSecret(c.Ui, format, secret)

View file

@ -14,9 +14,12 @@ import (
// PostgreSQL Backend is a physical backend that stores data
// within a PostgreSQL database.
type PostgreSQLBackend struct {
table string
client *sql.DB
statements map[string]*sql.Stmt
table string
client *sql.DB
put_query string
get_query string
delete_query string
list_query string
logger *log.Logger
}
@ -50,49 +53,30 @@ func newPostgreSQLBackend(conf map[string]string, logger *log.Logger) (Backend,
// Setup our put strategy based on the presence or absence of a native
// upsert.
var put_statement string
var put_query string
if upsert_required {
put_statement = "SELECT vault_kv_put($1, $2, $3, $4)"
put_query = "SELECT vault_kv_put($1, $2, $3, $4)"
} else {
put_statement = "INSERT INTO " + quoted_table + " VALUES($1, $2, $3, $4)" +
put_query = "INSERT INTO " + quoted_table + " VALUES($1, $2, $3, $4)" +
" ON CONFLICT (path, key) DO " +
" UPDATE SET (parent_path, path, key, value) = ($1, $2, $3, $4)"
}
// Setup the backend.
m := &PostgreSQLBackend{
table: quoted_table,
client: db,
statements: make(map[string]*sql.Stmt),
table: quoted_table,
client: db,
put_query: put_query,
get_query: "SELECT value FROM " + quoted_table + " WHERE path = $1 AND key = $2",
delete_query: "DELETE FROM " + quoted_table + " WHERE path = $1 AND key = $2",
list_query: "SELECT key FROM " + quoted_table + " WHERE path = $1" +
"UNION SELECT substr(path, length($1)+1) FROM " + quoted_table + "WHERE parent_path = $1",
logger: logger,
}
// Prepare all the statements required
statements := map[string]string{
"put": put_statement,
"get": "SELECT value FROM " + quoted_table + " WHERE path = $1 AND key = $2",
"delete": "DELETE FROM " + quoted_table + " WHERE path = $1 AND key = $2",
"list": "SELECT key FROM " + quoted_table + " WHERE path = $1" +
"UNION SELECT substr(path, length($1)+1) FROM " + quoted_table + "WHERE parent_path = $1",
}
for name, query := range statements {
if err := m.prepare(name, query); err != nil {
return nil, err
}
}
return m, nil
}
// prepare is a helper to prepare a query for future execution
func (m *PostgreSQLBackend) prepare(name, query string) error {
stmt, err := m.client.Prepare(query)
if err != nil {
return fmt.Errorf("failed to prepare '%s': %v", name, err)
}
m.statements[name] = stmt
return nil
}
// splitKey is a helper to split a full path key into individual
// parts: parentPath, path, key
func (m *PostgreSQLBackend) splitKey(fullPath string) (string, string, string) {
@ -123,7 +107,7 @@ func (m *PostgreSQLBackend) Put(entry *Entry) error {
parentPath, path, key := m.splitKey(entry.Key)
_, err := m.statements["put"].Exec(parentPath, path, key, entry.Value)
_, err := m.client.Exec(m.put_query, parentPath, path, key, entry.Value)
if err != nil {
return err
}
@ -137,7 +121,7 @@ func (m *PostgreSQLBackend) Get(fullPath string) (*Entry, error) {
_, path, key := m.splitKey(fullPath)
var result []byte
err := m.statements["get"].QueryRow(path, key).Scan(&result)
err := m.client.QueryRow(m.get_query, path, key).Scan(&result)
if err == sql.ErrNoRows {
return nil, nil
}
@ -158,7 +142,7 @@ func (m *PostgreSQLBackend) Delete(fullPath string) error {
_, path, key := m.splitKey(fullPath)
_, err := m.statements["delete"].Exec(path, key)
_, err := m.client.Exec(m.delete_query, path, key)
if err != nil {
return err
}
@ -170,7 +154,7 @@ func (m *PostgreSQLBackend) Delete(fullPath string) error {
func (m *PostgreSQLBackend) List(prefix string) ([]string, error) {
defer metrics.MeasureSince([]string{"postgres", "list"}, time.Now())
rows, err := m.statements["list"].Query("/" + prefix)
rows, err := m.client.Query(m.list_query, "/" + prefix)
if err != nil {
return nil, err
}

View file

@ -32,7 +32,7 @@ func TestPostgreSQLBackend(t *testing.T) {
defer func() {
pg := b.(*PostgreSQLBackend)
_, err := pg.client.Exec("DROP TABLE " + pg.table)
_, err := pg.client.Exec("TRUNCATE TABLE " + pg.table)
if err != nil {
t.Fatalf("Failed to drop table: %v", err)
}

View file

@ -4,7 +4,6 @@ import (
"encoding/json"
"fmt"
"regexp"
"strconv"
"strings"
"sync"
"time"
@ -92,8 +91,7 @@ func NewTokenStore(c *Core, config *logical.BackendConfig) (*TokenStore, error)
t.tokenLocks = map[string]*sync.RWMutex{}
for i := int64(0); i < 256; i++ {
t.tokenLocks[fmt.Sprintf("%2x",
strconv.FormatInt(i, 16))] = &sync.RWMutex{}
t.tokenLocks[fmt.Sprintf("%02x", i)] = &sync.RWMutex{}
}
t.tokenLocks["custom"] = &sync.RWMutex{}