2019-08-22 05:12:46 +00:00
|
|
|
package mysql
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
cryptotls "crypto/tls"
|
|
|
|
"database/sql"
|
|
|
|
|
|
|
|
"github.com/go-sql-driver/mysql"
|
2020-11-30 23:45:22 +00:00
|
|
|
"github.com/k3s-io/kine/pkg/drivers/generic"
|
|
|
|
"github.com/k3s-io/kine/pkg/logstructured"
|
|
|
|
"github.com/k3s-io/kine/pkg/logstructured/sqllog"
|
|
|
|
"github.com/k3s-io/kine/pkg/server"
|
|
|
|
"github.com/k3s-io/kine/pkg/tls"
|
2020-10-28 07:38:43 +00:00
|
|
|
"github.com/sirupsen/logrus"
|
2019-08-22 05:12:46 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
defaultUnixDSN = "root@unix(/var/run/mysqld/mysqld.sock)/"
|
|
|
|
defaultHostDSN = "root@tcp(127.0.0.1)/"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
schema = []string{
|
2020-10-28 07:38:43 +00:00
|
|
|
`CREATE TABLE IF NOT EXISTS kine
|
2019-08-22 05:12:46 +00:00
|
|
|
(
|
|
|
|
id INTEGER AUTO_INCREMENT,
|
2019-11-13 06:05:20 +00:00
|
|
|
name VARCHAR(630),
|
2019-08-22 05:12:46 +00:00
|
|
|
created INTEGER,
|
|
|
|
deleted INTEGER,
|
|
|
|
create_revision INTEGER,
|
|
|
|
prev_revision INTEGER,
|
|
|
|
lease INTEGER,
|
2019-11-02 00:05:00 +00:00
|
|
|
value MEDIUMBLOB,
|
|
|
|
old_value MEDIUMBLOB,
|
2019-08-22 05:12:46 +00:00
|
|
|
PRIMARY KEY (id)
|
|
|
|
);`,
|
2020-10-28 07:38:43 +00:00
|
|
|
`CREATE INDEX kine_name_index ON kine (name)`,
|
|
|
|
`CREATE INDEX kine_name_id_index ON kine (name,id)`,
|
|
|
|
`CREATE INDEX kine_id_deleted_index ON kine (id,deleted)`,
|
|
|
|
`CREATE INDEX kine_prev_revision_index ON kine (prev_revision)`,
|
|
|
|
`CREATE UNIQUE INDEX kine_name_prev_revision_uindex ON kine (name, prev_revision)`,
|
2019-08-22 05:12:46 +00:00
|
|
|
}
|
2020-10-28 07:38:43 +00:00
|
|
|
createDB = "CREATE DATABASE IF NOT EXISTS "
|
2019-08-22 05:12:46 +00:00
|
|
|
)
|
|
|
|
|
2020-10-15 17:34:24 +00:00
|
|
|
func New(ctx context.Context, dataSourceName string, tlsInfo tls.Config, connPoolConfig generic.ConnectionPoolConfig) (server.Backend, error) {
|
2019-08-22 05:12:46 +00:00
|
|
|
tlsConfig, err := tlsInfo.ClientConfig()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if tlsConfig != nil {
|
|
|
|
tlsConfig.MinVersion = cryptotls.VersionTLS11
|
|
|
|
}
|
|
|
|
|
|
|
|
parsedDSN, err := prepareDSN(dataSourceName, tlsConfig)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := createDBIfNotExist(parsedDSN); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-10-15 17:34:24 +00:00
|
|
|
dialect, err := generic.Open(ctx, "mysql", parsedDSN, connPoolConfig, "?", false)
|
2019-08-22 05:12:46 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-10-28 07:38:43 +00:00
|
|
|
|
2019-08-22 05:12:46 +00:00
|
|
|
dialect.LastInsertID = true
|
2021-08-30 20:43:25 +00:00
|
|
|
dialect.GetSizeSQL = `
|
|
|
|
SELECT SUM(data_length + index_length)
|
|
|
|
FROM information_schema.TABLES
|
|
|
|
WHERE table_schema = DATABASE() AND table_name = 'kine'`
|
2020-10-28 07:38:43 +00:00
|
|
|
dialect.CompactSQL = `
|
|
|
|
DELETE kv FROM kine AS kv
|
|
|
|
INNER JOIN (
|
|
|
|
SELECT kp.prev_revision AS id
|
|
|
|
FROM kine AS kp
|
|
|
|
WHERE
|
2020-11-13 03:14:07 +00:00
|
|
|
kp.name != 'compact_rev_key' AND
|
2020-10-28 07:38:43 +00:00
|
|
|
kp.prev_revision != 0 AND
|
|
|
|
kp.id <= ?
|
|
|
|
UNION
|
|
|
|
SELECT kd.id AS id
|
|
|
|
FROM kine AS kd
|
|
|
|
WHERE
|
|
|
|
kd.deleted != 0 AND
|
|
|
|
kd.id <= ?
|
|
|
|
) AS ks
|
2020-11-13 03:14:07 +00:00
|
|
|
ON kv.id = ks.id`
|
2019-11-13 06:05:20 +00:00
|
|
|
dialect.TranslateErr = func(err error) error {
|
|
|
|
if err, ok := err.(*mysql.MySQLError); ok && err.Number == 1062 {
|
|
|
|
return server.ErrKeyExists
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
2019-08-22 05:12:46 +00:00
|
|
|
if err := setup(dialect.DB); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
dialect.Migrate(context.Background())
|
|
|
|
return logstructured.New(sqllog.New(dialect)), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func setup(db *sql.DB) error {
|
2020-10-28 07:38:43 +00:00
|
|
|
logrus.Infof("Configuring database table schema and indexes, this may take a moment...")
|
|
|
|
|
2019-08-22 05:12:46 +00:00
|
|
|
for _, stmt := range schema {
|
2020-10-28 07:38:43 +00:00
|
|
|
logrus.Tracef("SETUP EXEC : %v", generic.Stripped(stmt))
|
2019-08-22 05:12:46 +00:00
|
|
|
_, err := db.Exec(stmt)
|
|
|
|
if err != nil {
|
2020-10-28 07:38:43 +00:00
|
|
|
if mysqlError, ok := err.(*mysql.MySQLError); !ok || mysqlError.Number != 1061 {
|
|
|
|
return err
|
|
|
|
}
|
2019-08-22 05:12:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-28 07:38:43 +00:00
|
|
|
logrus.Infof("Database tables and indexes are up to date")
|
2019-08-22 05:12:46 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func createDBIfNotExist(dataSourceName string) error {
|
|
|
|
config, err := mysql.ParseDSN(dataSourceName)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
dbName := config.DBName
|
|
|
|
|
|
|
|
db, err := sql.Open("mysql", dataSourceName)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = db.Exec(createDB + dbName)
|
|
|
|
if err != nil {
|
|
|
|
if mysqlError, ok := err.(*mysql.MySQLError); !ok || mysqlError.Number != 1049 {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
config.DBName = ""
|
|
|
|
db, err = sql.Open("mysql", config.FormatDSN())
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = db.Exec(createDB + dbName)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func prepareDSN(dataSourceName string, tlsConfig *cryptotls.Config) (string, error) {
|
|
|
|
if len(dataSourceName) == 0 {
|
|
|
|
dataSourceName = defaultUnixDSN
|
|
|
|
if tlsConfig != nil {
|
|
|
|
dataSourceName = defaultHostDSN
|
|
|
|
}
|
|
|
|
}
|
|
|
|
config, err := mysql.ParseDSN(dataSourceName)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
// setting up tlsConfig
|
|
|
|
if tlsConfig != nil {
|
|
|
|
if err := mysql.RegisterTLSConfig("kine", tlsConfig); err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
config.TLSConfig = "kine"
|
|
|
|
}
|
|
|
|
dbName := "kubernetes"
|
|
|
|
if len(config.DBName) > 0 {
|
|
|
|
dbName = config.DBName
|
|
|
|
}
|
|
|
|
config.DBName = dbName
|
|
|
|
parsedDSN := config.FormatDSN()
|
|
|
|
|
|
|
|
return parsedDSN, nil
|
|
|
|
}
|