2016-03-30 13:43:40 +00:00
|
|
|
/*
|
|
|
|
Copyright 2016 GitHub Inc.
|
2016-05-16 09:09:17 +00:00
|
|
|
See https://github.com/github/gh-ost/blob/master/LICENSE
|
2016-03-30 13:43:40 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
package mysql
|
|
|
|
|
2016-04-04 13:29:02 +00:00
|
|
|
import (
|
2019-01-31 16:03:48 +00:00
|
|
|
"crypto/tls"
|
|
|
|
"crypto/x509"
|
|
|
|
"errors"
|
2016-04-04 13:29:02 +00:00
|
|
|
"fmt"
|
2019-01-31 16:03:48 +00:00
|
|
|
"io/ioutil"
|
2016-08-05 23:50:09 +00:00
|
|
|
"net"
|
2019-01-31 16:03:48 +00:00
|
|
|
|
|
|
|
"github.com/go-sql-driver/mysql"
|
2016-04-04 13:29:02 +00:00
|
|
|
)
|
|
|
|
|
2019-02-22 18:33:19 +00:00
|
|
|
const (
|
|
|
|
TLS_CONFIG_KEY = "ghost"
|
|
|
|
)
|
|
|
|
|
2016-03-30 13:43:40 +00:00
|
|
|
// ConnectionConfig is the minimal configuration required to connect to a MySQL server
|
|
|
|
type ConnectionConfig struct {
|
2016-06-19 15:55:37 +00:00
|
|
|
Key InstanceKey
|
|
|
|
User string
|
|
|
|
Password string
|
|
|
|
ImpliedKey *InstanceKey
|
2019-01-31 16:03:48 +00:00
|
|
|
tlsConfig *tls.Config
|
2020-02-16 10:48:23 +00:00
|
|
|
Timeout float64
|
2016-03-30 13:43:40 +00:00
|
|
|
}
|
2016-04-04 13:29:02 +00:00
|
|
|
|
|
|
|
func NewConnectionConfig() *ConnectionConfig {
|
|
|
|
config := &ConnectionConfig{
|
|
|
|
Key: InstanceKey{},
|
|
|
|
}
|
2016-06-19 15:55:37 +00:00
|
|
|
config.ImpliedKey = &config.Key
|
2016-04-04 13:29:02 +00:00
|
|
|
return config
|
|
|
|
}
|
|
|
|
|
2016-10-11 14:42:19 +00:00
|
|
|
// DuplicateCredentials creates a new connection config with given key and with same credentials as this config
|
|
|
|
func (this *ConnectionConfig) DuplicateCredentials(key InstanceKey) *ConnectionConfig {
|
2016-04-04 13:29:02 +00:00
|
|
|
config := &ConnectionConfig{
|
2019-01-31 16:03:48 +00:00
|
|
|
Key: key,
|
|
|
|
User: this.User,
|
|
|
|
Password: this.Password,
|
|
|
|
tlsConfig: this.tlsConfig,
|
2020-02-16 10:48:23 +00:00
|
|
|
Timeout: this.Timeout,
|
2016-04-04 13:29:02 +00:00
|
|
|
}
|
2016-06-19 15:55:37 +00:00
|
|
|
config.ImpliedKey = &config.Key
|
2016-04-04 13:29:02 +00:00
|
|
|
return config
|
|
|
|
}
|
|
|
|
|
2016-10-11 14:42:19 +00:00
|
|
|
func (this *ConnectionConfig) Duplicate() *ConnectionConfig {
|
|
|
|
return this.DuplicateCredentials(this.Key)
|
|
|
|
}
|
|
|
|
|
2016-04-04 13:29:02 +00:00
|
|
|
func (this *ConnectionConfig) String() string {
|
2019-01-31 16:03:48 +00:00
|
|
|
return fmt.Sprintf("%s, user=%s, usingTLS=%t", this.Key.DisplayString(), this.User, this.tlsConfig != nil)
|
2016-04-04 13:29:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (this *ConnectionConfig) Equals(other *ConnectionConfig) bool {
|
2016-06-19 15:55:37 +00:00
|
|
|
return this.Key.Equals(&other.Key) || this.ImpliedKey.Equals(other.ImpliedKey)
|
2016-04-04 13:29:02 +00:00
|
|
|
}
|
|
|
|
|
2019-02-22 18:33:19 +00:00
|
|
|
func (this *ConnectionConfig) UseTLS(caCertificatePath, clientCertificate, clientKey string, allowInsecure bool) error {
|
2019-01-31 16:03:48 +00:00
|
|
|
var rootCertPool *x509.CertPool
|
2019-02-22 18:33:19 +00:00
|
|
|
var certs []tls.Certificate
|
2019-02-04 20:46:08 +00:00
|
|
|
var err error
|
|
|
|
|
2019-02-22 18:33:19 +00:00
|
|
|
if caCertificatePath == "" {
|
|
|
|
rootCertPool, err = x509.SystemCertPool()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rootCertPool = x509.NewCertPool()
|
|
|
|
pem, err := ioutil.ReadFile(caCertificatePath)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
|
|
|
|
return errors.New("could not add ca certificate to cert pool")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if clientCertificate != "" || clientKey != "" {
|
|
|
|
cert, err := tls.LoadX509KeyPair(clientCertificate, clientKey)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2019-01-31 16:03:48 +00:00
|
|
|
}
|
2019-02-22 18:33:19 +00:00
|
|
|
certs = []tls.Certificate{cert}
|
2019-01-31 16:03:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this.tlsConfig = &tls.Config{
|
2019-02-22 18:33:19 +00:00
|
|
|
Certificates: certs,
|
2019-01-31 16:03:48 +00:00
|
|
|
RootCAs: rootCertPool,
|
2019-02-04 22:21:25 +00:00
|
|
|
InsecureSkipVerify: allowInsecure,
|
2019-01-31 16:03:48 +00:00
|
|
|
}
|
|
|
|
|
2019-02-22 18:33:19 +00:00
|
|
|
return mysql.RegisterTLSConfig(TLS_CONFIG_KEY, this.tlsConfig)
|
2019-01-31 16:03:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (this *ConnectionConfig) TLSConfig() *tls.Config {
|
|
|
|
return this.tlsConfig
|
|
|
|
}
|
|
|
|
|
2018-03-12 14:17:53 +00:00
|
|
|
func (this *ConnectionConfig) GetDBUri(databaseName string) string {
|
2016-09-07 12:24:11 +00:00
|
|
|
hostname := this.Key.Hostname
|
|
|
|
var ip = net.ParseIP(hostname)
|
2016-08-05 23:50:09 +00:00
|
|
|
if (ip != nil) && (ip.To4() == nil) {
|
|
|
|
// Wrap IPv6 literals in square brackets
|
2016-09-07 12:24:11 +00:00
|
|
|
hostname = fmt.Sprintf("[%s]", hostname)
|
2016-08-05 23:50:09 +00:00
|
|
|
}
|
2018-03-07 14:30:02 +00:00
|
|
|
interpolateParams := true
|
2019-01-31 23:23:19 +00:00
|
|
|
// go-mysql-driver defaults to false if tls param is not provided; explicitly setting here to
|
|
|
|
// simplify construction of the DSN below.
|
2019-01-31 16:03:48 +00:00
|
|
|
tlsOption := "false"
|
|
|
|
if this.tlsConfig != nil {
|
2019-02-22 18:33:19 +00:00
|
|
|
tlsOption = TLS_CONFIG_KEY
|
2019-01-31 16:03:48 +00:00
|
|
|
}
|
2020-02-16 10:48:23 +00:00
|
|
|
return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?timeout=%fs&readTimeout=%fs&writeTimeout=%fs&interpolateParams=%t&autocommit=true&charset=utf8mb4,utf8,latin1&tls=%s", this.User, this.Password, hostname, this.Key.Port, databaseName, this.Timeout, this.Timeout, this.Timeout, interpolateParams, tlsOption)
|
2016-04-04 13:29:02 +00:00
|
|
|
}
|