2015-04-25 19:05:26 +00:00
package mysql
import (
"database/sql"
"fmt"
2016-06-11 15:48:40 +00:00
"github.com/fatih/structs"
2015-04-25 19:05:26 +00:00
_ "github.com/go-sql-driver/mysql"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
)
func pathConfigConnection ( b * backend ) * framework . Path {
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-25 19:05:26 +00:00
Type : framework . TypeString ,
Description : "DB connection string" ,
} ,
2016-06-17 14:11:39 +00:00
"value" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : ` DB connection string . Use ' connection_url ' instead .
This name is deprecated . ` ,
} ,
2015-10-02 01:15:56 +00:00
"max_open_connections" : & framework . FieldSchema {
Type : framework . TypeInt ,
Description : "Maximum number of open connections to database" ,
} ,
2016-07-19 18:17:34 +00:00
"max_idle_connections" : & framework . FieldSchema {
2016-07-20 13:26:26 +00:00
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." ,
2016-07-19 18:17:34 +00:00
} ,
2016-02-19 21:44:52 +00:00
"verify_connection" : & framework . FieldSchema {
2016-02-18 22:02:59 +00:00
Type : framework . TypeBool ,
Default : true ,
Description : "If set, connection_url is verified by actually connecting to the database" ,
} ,
2015-04-25 19:05:26 +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-25 19:05:26 +00:00
} ,
HelpSynopsis : pathConfigConnectionHelpSyn ,
HelpDescription : pathConfigConnectionHelpDesc ,
}
}
2016-06-11 15:48:40 +00:00
// pathConnectionRead reads out the connection configuration
func ( b * backend ) pathConnectionRead ( req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
entry , err := req . Storage . Get ( "config/connection" )
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
}
2015-04-25 19:05:26 +00:00
func ( b * backend ) pathConnectionWrite (
req * logical . Request , data * framework . FieldData ) ( * logical . Response , error ) {
2016-06-17 14:11:39 +00:00
connValue := data . Get ( "value" ) . ( string )
2015-10-03 03:47:10 +00:00
connURL := data . Get ( "connection_url" ) . ( string )
2016-02-18 22:02:59 +00:00
if connURL == "" {
2016-06-17 14:11:39 +00:00
if connValue == "" {
return logical . ErrorResponse ( "the connection_url parameter must be supplied" ) , nil
} else {
connURL = connValue
}
2016-02-18 22:02:59 +00:00
}
2015-04-25 19:05:26 +00:00
2015-10-02 01:15:56 +00:00
maxOpenConns := data . Get ( "max_open_connections" ) . ( int )
if maxOpenConns == 0 {
maxOpenConns = 2
}
2016-07-20 13:26:26 +00:00
maxIdleConns := data . Get ( "max_idle_connections" ) . ( int )
if maxIdleConns == 0 {
maxIdleConns = maxOpenConns
}
if maxIdleConns > maxOpenConns {
maxIdleConns = maxOpenConns
}
2016-02-18 22:02:59 +00:00
// Don't check the connection_url if verification is disabled
2016-02-19 21:44:52 +00:00
verifyConnection := data . Get ( "verify_connection" ) . ( bool )
if verifyConnection {
2016-02-18 22:02:59 +00:00
// Verify the string
db , err := sql . Open ( "mysql" , connURL )
if err != nil {
return logical . ErrorResponse ( fmt . Sprintf (
2016-02-19 21:44:52 +00:00
"error validating connection info: %s" , err ) ) , nil
2016-02-18 22:02:59 +00:00
}
defer db . Close ( )
if err := db . Ping ( ) ; err != nil {
return logical . ErrorResponse ( fmt . Sprintf (
2016-02-19 21:44:52 +00:00
"error validating connection info: %s" , err ) ) , nil
2016-02-18 22:02:59 +00:00
}
2015-04-25 19:05:26 +00:00
}
// Store it
2015-10-02 01:15:56 +00:00
entry , err := logical . StorageEntryJSON ( "config/connection" , connectionConfig {
2015-10-03 03:47:10 +00:00
ConnectionURL : connURL ,
2015-10-02 01:15:56 +00:00
MaxOpenConnections : maxOpenConns ,
2016-07-20 13:26:26 +00:00
MaxIdleConnections : maxIdleConns ,
2015-10-02 01:15:56 +00:00
} )
2015-04-25 19:05:26 +00:00
if err != nil {
return nil , err
}
if err := req . Storage . Put ( entry ) ; err != nil {
return nil , err
}
// Reset the DB connection
b . ResetDB ( )
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 URL as it is, including passwords, if any." )
return resp , nil
2015-04-25 19:05:26 +00:00
}
2015-10-02 01:15:56 +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" `
2016-07-20 16:00:05 +00:00
MaxIdleConnections int ` json:"max_idle_connections" structs:"max_idle_connections" mapstructure:"max_idle_connections" `
2015-10-02 01:15:56 +00:00
}
2015-04-25 19:05:26 +00:00
const pathConfigConnectionHelpSyn = `
Configure the connection string to talk to MySQL .
`
const pathConfigConnectionHelpDesc = `
2016-02-19 21:44:52 +00:00
This path configures the connection string used to connect to MySQL . The value
of the string is a Data Source Name ( DSN ) . An example is using
"username:password@protocol(address)/dbname?param=value"
2015-04-25 19:05:26 +00:00
2016-02-19 21:44:52 +00:00
For example , RDS may look like :
"id:password@tcp(your-amazonaws-uri.com:3306)/dbname"
2015-04-25 19:05:26 +00:00
When configuring the connection string , the backend will verify its validity .
2016-02-19 21:44:52 +00:00
If the database is not available when setting the connection URL , set the
"verify_connection" option to false .
2015-04-25 19:05:26 +00:00
`