[MM-42167] Add configuration tables to migration system (#19671)
* add configuration tables to migration system * config: move config migrations into new system completely * add mysql specific bits * use helper db instance instead * fix typo Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
4da27d8e30
Коммит
e49cc0313a
@@ -5,8 +5,11 @@ package config
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
@@ -17,8 +20,15 @@ import (
|
||||
// Load the Postgres driver
|
||||
_ "github.com/lib/pq"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/config/migrations"
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||
"github.com/mattermost/morph"
|
||||
|
||||
"github.com/mattermost/morph/drivers"
|
||||
ms "github.com/mattermost/morph/drivers/mysql"
|
||||
ps "github.com/mattermost/morph/drivers/postgres"
|
||||
mbindata "github.com/mattermost/morph/sources/go_bindata"
|
||||
)
|
||||
|
||||
// MaxWriteLength defines the maximum length accepted for write to the Configurations or
|
||||
@@ -27,6 +37,12 @@ import (
|
||||
// It is imposed by MySQL's default max_allowed_packet value of 4Mb.
|
||||
const MaxWriteLength = 4 * 1024 * 1024
|
||||
|
||||
// We use the something different from the default migration table name of morph
|
||||
const migrationsTableName = "db_config_migrations"
|
||||
|
||||
// The timeout value for each migration file to run.
|
||||
const migrationsTimeoutInSeconds = 100000
|
||||
|
||||
// DatabaseStore is a config store backed by a database.
|
||||
// Not to be used directly. Only to be used as a backing store for config.Store
|
||||
type DatabaseStore struct {
|
||||
@@ -63,7 +79,7 @@ func NewDatabaseStore(dsn string) (ds *DatabaseStore, err error) {
|
||||
dataSourceName: dataSourceName,
|
||||
db: db,
|
||||
}
|
||||
if err = initializeConfigurationsTable(ds.db); err != nil {
|
||||
if err = ds.initializeConfigurationsTable(); err != nil {
|
||||
err = errors.Wrap(err, "failed to initialize")
|
||||
return nil, err
|
||||
}
|
||||
@@ -74,61 +90,75 @@ func NewDatabaseStore(dsn string) (ds *DatabaseStore, err error) {
|
||||
// initializeConfigurationsTable ensures the requisite tables in place to form the backing store.
|
||||
//
|
||||
// Uses MEDIUMTEXT on MySQL, and TEXT on sane databases.
|
||||
func initializeConfigurationsTable(db *sqlx.DB) error {
|
||||
mysqlCharset := ""
|
||||
if db.DriverName() == "mysql" {
|
||||
mysqlCharset = "DEFAULT CHARACTER SET utf8mb4"
|
||||
func (ds *DatabaseStore) initializeConfigurationsTable() error {
|
||||
var assetNamesForDriver []string
|
||||
for _, assetName := range migrations.AssetNames() {
|
||||
if strings.HasPrefix(assetName, ds.driverName) {
|
||||
assetNamesForDriver = append(assetNamesForDriver, filepath.Base(assetName))
|
||||
}
|
||||
}
|
||||
|
||||
_, err := db.Exec(`
|
||||
CREATE TABLE IF NOT EXISTS Configurations (
|
||||
Id VARCHAR(26) PRIMARY KEY,
|
||||
Value TEXT NOT NULL,
|
||||
CreateAt BIGINT NOT NULL,
|
||||
Active BOOLEAN NULL UNIQUE
|
||||
)
|
||||
` + mysqlCharset)
|
||||
|
||||
src, err := mbindata.WithInstance(&mbindata.AssetSource{
|
||||
Names: assetNamesForDriver,
|
||||
AssetFunc: func(name string) ([]byte, error) {
|
||||
return migrations.Asset(filepath.Join(ds.driverName, name))
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create Configurations table")
|
||||
return err
|
||||
}
|
||||
defer src.Close()
|
||||
|
||||
cfg := drivers.Config{
|
||||
MigrationsTable: migrationsTableName,
|
||||
StatementTimeoutInSecs: migrationsTimeoutInSeconds,
|
||||
}
|
||||
|
||||
_, err = db.Exec(`
|
||||
CREATE TABLE IF NOT EXISTS ConfigurationFiles (
|
||||
Name VARCHAR(64) PRIMARY KEY,
|
||||
Data TEXT NOT NULL,
|
||||
CreateAt BIGINT NOT NULL,
|
||||
UpdateAt BIGINT NOT NULL
|
||||
)
|
||||
` + mysqlCharset)
|
||||
var driver drivers.Driver
|
||||
switch ds.driverName {
|
||||
case model.DatabaseDriverMysql:
|
||||
dataSource, rErr := resetReadTimeout(ds.dataSourceName)
|
||||
if rErr != nil {
|
||||
return fmt.Errorf("failed to reset read timeout from datasource: %w", rErr)
|
||||
}
|
||||
|
||||
dataSource, err = appendMultipleStatementsFlag(dataSource)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var db *sqlx.DB
|
||||
db, err = sqlx.Open(ds.driverName, dataSource)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to connect to %s database", ds.driverName)
|
||||
}
|
||||
|
||||
driver, err = ms.WithInstance(db.DB, &ms.Config{
|
||||
Config: cfg,
|
||||
})
|
||||
|
||||
defer db.Close()
|
||||
case model.DatabaseDriverPostgres:
|
||||
driver, err = ps.WithInstance(ds.db.DB, &ps.Config{
|
||||
Config: cfg,
|
||||
})
|
||||
default:
|
||||
err = fmt.Errorf("unsupported database type %s for migration", ds.driverName)
|
||||
}
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create ConfigurationFiles table")
|
||||
return err
|
||||
}
|
||||
|
||||
// Change from TEXT (65535 limit) to MEDIUM TEXT (16777215) on MySQL. This is a
|
||||
// backwards-compatible migration for any existing schema.
|
||||
// Also fix using the wrong encoding initially
|
||||
if db.DriverName() == "mysql" {
|
||||
_, err = db.Exec(`ALTER TABLE Configurations MODIFY Value MEDIUMTEXT`)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to alter Configurations table")
|
||||
}
|
||||
_, err = db.Exec(`ALTER TABLE Configurations CONVERT TO CHARACTER SET utf8mb4`)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to alter Configurations table character set")
|
||||
}
|
||||
|
||||
_, err = db.Exec(`ALTER TABLE ConfigurationFiles MODIFY Data MEDIUMTEXT`)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to alter ConfigurationFiles table")
|
||||
}
|
||||
_, err = db.Exec(`ALTER TABLE ConfigurationFiles CONVERT TO CHARACTER SET utf8mb4`)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to alter ConfigurationFiles table character set")
|
||||
}
|
||||
opts := []morph.EngineOption{
|
||||
morph.WithLock("mm-config-lock-key"),
|
||||
}
|
||||
engine, err := morph.New(context.Background(), driver, src, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer engine.Close()
|
||||
|
||||
return nil
|
||||
return engine.ApplyAll()
|
||||
}
|
||||
|
||||
// parseDSN splits up a connection string into a driver name and data source name.
|
||||
|
||||
Ссылка в новой задаче
Block a user