forked from smartcontractkit/chainlink
/
migrate.go
128 lines (110 loc) · 3.29 KB
/
migrate.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package migrate
import (
"context"
"database/sql"
"embed"
"fmt"
"os"
"strconv"
"strings"
"github.com/pkg/errors"
"github.com/pressly/goose/v3"
"github.com/smartcontractkit/sqlx"
null "gopkg.in/guregu/null.v4"
"github.com/DCMMC/chainlink/core/services/postgres"
"github.com/DCMMC/chainlink/core/store/migrate/migrations" // Invoke init() functions within migrations pkg.
)
//go:embed migrations/*.sql
var embedMigrations embed.FS
const MIGRATIONS_DIR string = "migrations"
func init() {
goose.SetBaseFS(embedMigrations)
goose.SetSequential(true)
goose.SetTableName("goose_migrations")
verbose, _ := strconv.ParseBool(os.Getenv("LOG_SQL_MIGRATIONS"))
goose.SetVerbose(verbose)
}
// Ensure we migrated from v1 migrations to goose_migrations
func ensureMigrated(db *sql.DB) {
sqlxDB := postgres.WrapDbWithSqlx(db)
var names []string
err := sqlxDB.Select(&names, `SELECT id FROM migrations`)
if err != nil {
// already migrated
return
}
err = postgres.SqlTransaction(context.Background(), db, func(tx *sqlx.Tx) error {
// ensure that no legacy job specs are present: we _must_ bail out early if
// so because otherwise we run the risk of dropping working jobs if the
// user has not read the release notes
return migrations.CheckNoLegacyJobs(tx.Tx)
})
if err != nil {
panic(err)
}
// Look for the squashed migration. If not present, the db needs to be migrated on an earlier release first
found := false
for _, name := range names {
if name == "1611847145" {
found = true
}
}
if !found {
panic("Database state is too old. Need to migrate to chainlink version 0.9.10 first before upgrading to this version. This upgrade is NOT REVERSIBLE, so it is STRONGLY RECOMMENDED that you take a database backup before continuing.")
}
// ensure a goose migrations table exists with it's initial v0
if _, err = goose.GetDBVersion(db); err != nil {
panic(err)
}
// insert records for existing migrations
sql := fmt.Sprintf(`INSERT INTO %s (version_id, is_applied) VALUES ($1, true);`, goose.TableName())
err = postgres.SqlTransaction(context.Background(), db, func(tx *sqlx.Tx) error {
for _, name := range names {
var id int64
// the first migration doesn't follow the naming convention
if name == "1611847145" {
id = 1
} else {
idx := strings.Index(name, "_")
if idx < 0 {
// old migration we don't care about
continue
}
id, err = strconv.ParseInt(name[:idx], 10, 64)
if err == nil && id <= 0 {
return errors.New("migration IDs must be greater than zero")
}
}
if _, err = db.Exec(sql, id); err != nil {
return err
}
}
_, err = db.Exec("DROP TABLE migrations;")
return err
})
if err != nil {
panic(err)
}
}
func Migrate(db *sql.DB) error {
ensureMigrated(db)
return goose.Up(db, MIGRATIONS_DIR)
}
func Rollback(db *sql.DB, version null.Int) error {
ensureMigrated(db)
if version.Valid {
return goose.DownTo(db, MIGRATIONS_DIR, version.Int64)
}
return goose.Down(db, MIGRATIONS_DIR)
}
func Current(db *sql.DB) (int64, error) {
ensureMigrated(db)
return goose.EnsureDBVersion(db)
}
func Status(db *sql.DB) error {
ensureMigrated(db)
return goose.Status(db, MIGRATIONS_DIR)
}
func Create(db *sql.DB, name, migrationType string) error {
return goose.Create(db, "core/store/migrate/migrations", name, migrationType)
}