mirror of
https://github.com/grafana/grafana.git
synced 2025-02-12 08:35:43 -06:00
159 lines
2.8 KiB
Go
159 lines
2.8 KiB
Go
package migrator
|
|
|
|
import (
|
|
"time"
|
|
|
|
_ "github.com/go-sql-driver/mysql"
|
|
"github.com/go-xorm/xorm"
|
|
_ "github.com/lib/pq"
|
|
_ "github.com/mattn/go-sqlite3"
|
|
"github.com/torkelo/grafana-pro/pkg/log"
|
|
)
|
|
|
|
type Migrator struct {
|
|
LogLevel log.LogLevel
|
|
|
|
x *xorm.Engine
|
|
dialect Dialect
|
|
migrations []Migration
|
|
}
|
|
|
|
type MigrationLog struct {
|
|
Id int64
|
|
MigrationId string
|
|
Sql string
|
|
Success bool
|
|
Error string
|
|
Timestamp time.Time
|
|
}
|
|
|
|
func NewMigrator(engine *xorm.Engine) *Migrator {
|
|
mg := &Migrator{}
|
|
mg.x = engine
|
|
mg.LogLevel = log.WARN
|
|
mg.migrations = make([]Migration, 0)
|
|
mg.dialect = NewDialect(mg.x.DriverName())
|
|
return mg
|
|
}
|
|
|
|
func (mg *Migrator) AddMigration(id string, m Migration) {
|
|
m.SetId(id)
|
|
mg.migrations = append(mg.migrations, m)
|
|
}
|
|
|
|
func (mg *Migrator) GetMigrationLog() (map[string]MigrationLog, error) {
|
|
logMap := make(map[string]MigrationLog)
|
|
logItems := make([]MigrationLog, 0)
|
|
|
|
exists, err := mg.x.IsTableExist(new(MigrationLog))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if !exists {
|
|
return logMap, nil
|
|
}
|
|
|
|
if err = mg.x.Find(&logItems); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, logItem := range logItems {
|
|
if !logItem.Success {
|
|
continue
|
|
}
|
|
logMap[logItem.MigrationId] = logItem
|
|
}
|
|
|
|
return logMap, nil
|
|
}
|
|
|
|
func (mg *Migrator) Start() error {
|
|
if mg.LogLevel <= log.INFO {
|
|
log.Info("Migrator:: Starting DB migration")
|
|
}
|
|
|
|
logMap, err := mg.GetMigrationLog()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, m := range mg.migrations {
|
|
_, exists := logMap[m.Id()]
|
|
if exists {
|
|
if mg.LogLevel <= log.DEBUG {
|
|
log.Debug("Migrator:: Skipping migration: %v, Already executed", m.Id())
|
|
}
|
|
continue
|
|
}
|
|
|
|
sql := m.Sql(mg.dialect)
|
|
|
|
record := MigrationLog{
|
|
MigrationId: m.Id(),
|
|
Sql: sql,
|
|
Timestamp: time.Now(),
|
|
}
|
|
|
|
if mg.LogLevel <= log.DEBUG {
|
|
log.Debug("Migrator: Executing SQL: \n %v \n", sql)
|
|
}
|
|
|
|
if err := mg.exec(m); err != nil {
|
|
record.Error = err.Error()
|
|
mg.x.Insert(&record)
|
|
return err
|
|
} else {
|
|
record.Success = true
|
|
mg.x.Insert(&record)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (mg *Migrator) exec(m Migration) error {
|
|
if mg.LogLevel <= log.INFO {
|
|
log.Info("Migrator::exec migration id: %v", m.Id())
|
|
}
|
|
|
|
err := mg.inTransaction(func(sess *xorm.Session) error {
|
|
_, err := sess.Exec(m.Sql(mg.dialect))
|
|
if err != nil {
|
|
log.Error(3, "Migrator::exec FAILED migration id: %v, err: %v", m.Id(), err)
|
|
return err
|
|
}
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type dbTransactionFunc func(sess *xorm.Session) error
|
|
|
|
func (mg *Migrator) inTransaction(callback dbTransactionFunc) error {
|
|
var err error
|
|
|
|
sess := mg.x.NewSession()
|
|
defer sess.Close()
|
|
|
|
if err = sess.Begin(); err != nil {
|
|
return err
|
|
}
|
|
|
|
err = callback(sess)
|
|
|
|
if err != nil {
|
|
sess.Rollback()
|
|
return err
|
|
} else if err = sess.Commit(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|