2015-04-19 00:34:36 +00:00
package postgresql
import (
2018-01-08 18:31:38 +00:00
"context"
2015-04-19 00:34:36 +00:00
"database/sql"
"fmt"
2016-06-11 15:48:40 +00:00
"github.com/fatih/structs"
2015-04-19 00:34:36 +00:00
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
_ "github.com/lib/pq"
)
2015-04-19 01:09:33 +00:00
func pathConfigConnection ( b * backend ) * framework . Path {
2015-04-19 00:34:36 +00:00
return & framework . Path {
Pattern : "config/connection" ,
Fields : map [ string ] * framework . FieldSchema {
2015-10-03 03:47:10 +00:00
"connection_url" : & framework . FieldSchema {
2015-04-19 00:34:36 +00:00
Type : framework . TypeString ,
Description : "DB connection string" ,
} ,
2016-06-30 17:46:39 +00:00
2015-10-03 03:47:10 +00:00
"value" : & framework . FieldSchema {
Type : framework . TypeString ,
2016-01-21 20:38:10 +00:00
Description : ` DB connection string . Use ' connection_url ' instead .
This will be deprecated . ` ,
2015-10-03 03:47:10 +00:00
} ,
2016-06-30 17:46:39 +00:00
2016-02-19 02:03:47 +00:00
"verify_connection" : & framework . FieldSchema {
Type : framework . TypeBool ,
Default : true ,
Description : ` If set, connection_url is verified by actually connecting to the database ` ,
} ,
2016-06-30 17:46:39 +00:00
2015-10-02 00:11:24 +00:00
"max_open_connections" : & framework . FieldSchema {
2016-01-21 20:38:10 +00:00
Type : framework . TypeInt ,
Description : ` Maximum number of open connections to the database ;
a zero uses the default value of two and a
negative value means unlimited ` ,
} ,
"max_idle_connections" : & framework . FieldSchema {
Type : framework . TypeInt ,
Description : ` Maximum number of idle connections to the database ;
a zero uses the value of max_open_connections
and a negative value disables idle connections .
If larger than max_open_connections it will be
reduced to the same size . ` ,
2015-10-02 00:11:24 +00:00
} ,
2015-04-19 00:34:36 +00:00
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
2016-01-07 15:30:47 +00:00
logical . UpdateOperation : b . pathConnectionWrite ,
2016-06-11 15:48:40 +00:00
logical . ReadOperation : b . pathConnectionRead ,
2015-04-19 00:34:36 +00:00
} ,
HelpSynopsis : pathConfigConnectionHelpSyn ,
HelpDescription : pathConfigConnectionHelpDesc ,
}
}
2016-06-11 15:48:40 +00:00
// pathConnectionRead reads out the connection configuration
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathConnectionRead ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2018-01-19 06:44:44 +00:00
entry , err := req . Storage . Get ( ctx , "config/connection" )
2016-06-11 15:48:40 +00:00
if err != nil {
return nil , fmt . Errorf ( "failed to read connection configuration" )
}
if entry == nil {
return nil , nil
}
var config connectionConfig
if err := entry . DecodeJSON ( & config ) ; err != nil {
return nil , err
}
return & logical . Response {
Data : structs . New ( config ) . Map ( ) ,
} , nil
}
2018-01-08 18:31:38 +00:00
func ( b * backend ) pathConnectionWrite ( ctx context . Context , req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-02-19 02:03:47 +00:00
connValue := data . Get ( "value" ) . ( string )
2015-10-03 03:47:10 +00:00
connURL := data . Get ( "connection_url" ) . ( string )
2016-02-19 02:03:47 +00:00
if connURL == "" {
if connValue == "" {
return logical . ErrorResponse ( "connection_url parameter must be supplied" ) , nil
} else {
connURL = connValue
}
}
2015-04-19 00:34:36 +00:00
2015-10-02 00:11:24 +00:00
maxOpenConns := data . Get ( "max_open_connections" ) . ( int )
if maxOpenConns == 0 {
maxOpenConns = 2
}
2016-01-21 20:38:10 +00:00
maxIdleConns := data . Get ( "max_idle_connections" ) . ( int )
if maxIdleConns == 0 {
maxIdleConns = maxOpenConns
}
if maxIdleConns > maxOpenConns {
maxIdleConns = maxOpenConns
}
2016-02-19 02:03:47 +00:00
// Don't check the connection_url if verification is disabled
verifyConnection := data . Get ( "verify_connection" ) . ( bool )
if verifyConnection {
// Verify the string
db , err := sql . Open ( "postgres" , connURL )
if err != nil {
return logical . ErrorResponse ( fmt . Sprintf (
"Error validating connection info: %s" , err ) ) , nil
}
defer db . Close ( )
if err := db . Ping ( ) ; err != nil {
return logical . ErrorResponse ( fmt . Sprintf (
"Error validating connection info: %s" , err ) ) , nil
}
2015-04-19 00:34:36 +00:00
}
// Store it
2015-10-02 00:11:24 +00:00
entry , err := logical . StorageEntryJSON ( "config/connection" , connectionConfig {
2016-06-17 14:11:39 +00:00
ConnectionString : connValue ,
2015-10-03 03:47:10 +00:00
ConnectionURL : connURL ,
2015-10-02 00:11:24 +00:00
MaxOpenConnections : maxOpenConns ,
2016-01-21 20:38:10 +00:00
MaxIdleConnections : maxIdleConns ,
2015-10-02 00:11:24 +00:00
} )
2015-04-19 00:34:36 +00:00
if err != nil {
return nil , err
}
2018-01-19 06:44:44 +00:00
if err := req . Storage . Put ( ctx , entry ) ; err != nil {
2015-04-19 00:34:36 +00:00
return nil , err
}
2015-04-19 01:09:33 +00:00
// Reset the DB connection
2018-01-19 06:44:44 +00:00
b . ResetDB ( ctx )
2015-04-19 01:09:33 +00:00
2016-06-21 13:58:57 +00:00
resp := & logical . Response { }
resp . AddWarning ( "Read access to this endpoint should be controlled via ACLs as it will return the connection string or URL as it is, including passwords, if any." )
return resp , nil
2015-04-19 00:34:36 +00:00
}
2015-10-02 00:11:24 +00:00
type connectionConfig struct {
2016-06-17 14:11:39 +00:00
ConnectionURL string ` json:"connection_url" structs:"connection_url" mapstructure:"connection_url" `
// Deprecate "value" in coming releases
ConnectionString string ` json:"value" structs:"value" mapstructure:"value" `
2016-06-11 15:48:40 +00:00
MaxOpenConnections int ` json:"max_open_connections" structs:"max_open_connections" mapstructure:"max_open_connections" `
MaxIdleConnections int ` json:"max_idle_connections" structs:"max_idle_connections" mapstructure:"max_idle_connections" `
2015-10-02 00:11:24 +00:00
}
2015-04-19 00:34:36 +00:00
const pathConfigConnectionHelpSyn = `
Configure the connection string to talk to PostgreSQL .
`
const pathConfigConnectionHelpDesc = `
This path configures the connection string used to connect to PostgreSQL .
The value of the string can be a URL , or a PG style string in the
format of "user=foo host=bar" etc .
2015-04-27 19:00:07 +00:00
The URL looks like :
"postgresql://user:pass@host:port/dbname"
2015-04-19 00:34:36 +00:00
When configuring the connection string , the backend will verify its validity .
`