github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/lorry/engines/mysql/config.go (about) 1 /* 2 Copyright (C) 2022-2023 ApeCloud Co., Ltd 3 4 This file is part of KubeBlocks project 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU Affero General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU Affero General Public License for more details. 15 16 You should have received a copy of the GNU Affero General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 package mysql 21 22 import ( 23 "crypto/tls" 24 "crypto/x509" 25 "database/sql" 26 "fmt" 27 "net" 28 "os" 29 "strconv" 30 "time" 31 32 "github.com/go-sql-driver/mysql" 33 "github.com/pkg/errors" 34 "github.com/spf13/viper" 35 36 "github.com/1aal/kubeblocks/pkg/constant" 37 ) 38 39 const ( 40 // configurations to connect to MySQL, either a data source name represent by URL. 41 connectionURLKey = "url" 42 43 // To connect to MySQL running over SSL you have to download a 44 // SSL certificate. If this is provided the driver will connect using 45 // SSL. If you have disabled SSL you can leave this empty. 46 // When the user provides a pem path their connection string must end with 47 // &tls=custom 48 // The connection string should be in the following format 49 // "%s:%s@tcp(%s:3306)/%s?allowNativePasswords=true&tls=custom",'myadmin@mydemoserver', 'yourpassword', 'mydemoserver.mysql.database.azure.com', 'targetdb'. 50 pemPathKey = "pemPath" 51 52 // other general settings for DB connections. 53 maxIdleConnsKey = "maxIdleConns" 54 maxOpenConnsKey = "maxOpenConns" 55 connMaxLifetimeKey = "connMaxLifetime" 56 connMaxIdleTimeKey = "connMaxIdleTime" 57 ) 58 59 const ( 60 databaseName = "databaseName" 61 adminDatabase = "mysql" 62 defaultDBPort = 3306 63 ) 64 65 type Config struct { 66 url string 67 username string 68 password string 69 pemPath string 70 maxIdleConns int 71 maxOpenConns int 72 connMaxLifetime time.Duration 73 connMaxIdletime time.Duration 74 } 75 76 var config *Config 77 78 func NewConfig(properties map[string]string) (*Config, error) { 79 config = &Config{} 80 81 if val, ok := properties[connectionURLKey]; ok && val != "" { 82 config.url = val 83 } else { 84 config.url = "root:@tcp(127.0.0.1:3306)/mysql?multiStatements=true" 85 } 86 87 if viper.IsSet(constant.KBEnvServiceUser) { 88 config.username = viper.GetString(constant.KBEnvServiceUser) 89 } 90 91 if viper.IsSet(constant.KBEnvServicePassword) { 92 config.password = viper.GetString(constant.KBEnvServicePassword) 93 } 94 95 if val, ok := properties[pemPathKey]; ok { 96 config.pemPath = val 97 } 98 99 if val, ok := properties[maxIdleConnsKey]; ok { 100 if i, err := strconv.Atoi(val); err == nil { 101 config.maxIdleConns = i 102 } 103 } 104 105 if val, ok := properties[maxOpenConnsKey]; ok { 106 if i, err := strconv.Atoi(val); err == nil { 107 config.maxOpenConns = i 108 } 109 } 110 111 if val, ok := properties[connMaxLifetimeKey]; ok { 112 if d, err := time.ParseDuration(val); err == nil { 113 config.connMaxLifetime = d 114 } 115 } 116 117 if val, ok := properties[connMaxIdleTimeKey]; ok { 118 if d, err := time.ParseDuration(val); err == nil { 119 config.connMaxIdletime = d 120 } 121 } 122 123 if config.pemPath != "" { 124 rootCertPool := x509.NewCertPool() 125 pem, err := os.ReadFile(config.pemPath) 126 if err != nil { 127 return nil, errors.Wrapf(err, "Error reading PEM file from %s", config.pemPath) 128 } 129 130 ok := rootCertPool.AppendCertsFromPEM(pem) 131 if !ok { 132 return nil, fmt.Errorf("failed to append PEM") 133 } 134 135 err = mysql.RegisterTLSConfig("custom", &tls.Config{RootCAs: rootCertPool, MinVersion: tls.VersionTLS12}) 136 if err != nil { 137 return nil, errors.Wrap(err, "Error register TLS config") 138 } 139 } 140 return config, nil 141 } 142 143 func (config *Config) GetLocalDBConn() (*sql.DB, error) { 144 mysqlConfig, err := mysql.ParseDSN(config.url) 145 if err != nil { 146 return nil, errors.Wrapf(err, "illegal Data Source Name (DNS) specified by %s", connectionURLKey) 147 } 148 mysqlConfig.User = config.username 149 mysqlConfig.Passwd = config.password 150 db, err := sql.Open("mysql", mysqlConfig.FormatDSN()) 151 if err != nil { 152 return nil, errors.Wrap(err, "error opening DB connection") 153 } 154 155 return db, nil 156 } 157 158 func (config *Config) GetDBConnWithAddr(addr string) (*sql.DB, error) { 159 mysqlConfig, err := mysql.ParseDSN(config.url) 160 if err != nil { 161 return nil, errors.Wrapf(err, "illegal Data Source Name (DNS) specified by %s", connectionURLKey) 162 } 163 mysqlConfig.User = config.username 164 mysqlConfig.Passwd = config.password 165 mysqlConfig.Addr = addr 166 db, err := sql.Open("mysql", mysqlConfig.FormatDSN()) 167 if err != nil { 168 return nil, errors.Wrap(err, "error opening DB connection") 169 } 170 171 return db, nil 172 } 173 174 func (config *Config) GetDBPort() int { 175 mysqlConfig, err := mysql.ParseDSN(config.url) 176 if err != nil { 177 return defaultDBPort 178 } 179 180 _, portStr, err := net.SplitHostPort(mysqlConfig.Addr) 181 if err != nil { 182 return defaultDBPort 183 } 184 185 port, err := strconv.Atoi(portStr) 186 if err != nil { 187 return defaultDBPort 188 } 189 190 return port 191 } 192 193 func GetConfig() *Config { 194 return config 195 }