1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
14 "git.arvados.org/arvados.git/lib/controller/dblock"
15 "git.arvados.org/arvados.git/lib/ctrlctx"
18 type railsDatabase struct{}
20 func (runner railsDatabase) String() string {
21 return "railsDatabase"
24 func (runner railsDatabase) Run(ctx context.Context, fail func(error), super *Supervisor) error {
25 err := super.wait(ctx, runPostgreSQL{}, installPassenger{src: "services/api"})
30 // determine path to installed rails app or source tree
32 if super.ClusterType == "production" {
33 appdir = "/var/lib/arvados/railsapi"
35 appdir = filepath.Join(super.SourcePath, "services/api")
38 // list versions in db/migrate/{version}_{name}.rb
39 todo := map[string]bool{}
40 fs.WalkDir(os.DirFS(appdir), "db/migrate", func(path string, d fs.DirEntry, err error) error {
41 if cut := strings.Index(d.Name(), "_"); cut > 0 && strings.HasSuffix(d.Name(), ".rb") {
42 todo[d.Name()[:cut]] = true
47 // read schema_migrations table (list of migrations already
48 // applied) and remove those entries from todo
49 dbconnector := ctrlctx.DBConnector{PostgreSQL: super.cluster.PostgreSQL}
50 defer dbconnector.Close()
51 db, err := dbconnector.GetDB(ctx)
55 rows, err := db.QueryContext(ctx, `SELECT version FROM schema_migrations`)
57 if super.ClusterType == "production" {
60 super.logger.WithError(err).Info("schema_migrations query failed, trying db:setup")
61 return super.RunProgram(ctx, "services/api", runOptions{env: railsEnv}, "bundle", "exec", "rake", "db:setup")
76 // if nothing remains in todo, all available migrations are
77 // done, so return without running any [relatively slow]
83 super.logger.Infof("%d migrations pending", len(todo))
84 if !dblock.RailsMigrations.Lock(ctx, dbconnector.GetDB) {
85 return context.Canceled
87 defer dblock.RailsMigrations.Unlock()
88 return super.RunProgram(ctx, appdir, runOptions{env: railsEnv}, "bundle", "exec", "rake", "db:migrate")