mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
	
	
		
			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
							 | 
						||
| 
								 | 
							
								}
							 |