| OLD | NEW |
| 1 package buildbot | 1 package buildbot |
| 2 | 2 |
| 3 /* | 3 /* |
| 4 Store/Retrieve buildbot data in a database. | 4 Store/Retrieve buildbot data in a database. |
| 5 */ | 5 */ |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "fmt" | 8 "fmt" |
| 9 | 9 |
| 10 "github.com/golang/glog" | 10 "github.com/golang/glog" |
| 11 "github.com/jmoiron/sqlx" | 11 "github.com/jmoiron/sqlx" |
| 12 "skia.googlesource.com/buildbot.git/go/database" | 12 "skia.googlesource.com/buildbot.git/go/database" |
| 13 "skia.googlesource.com/buildbot.git/go/metadata" | 13 "skia.googlesource.com/buildbot.git/go/metadata" |
| 14 ) | 14 ) |
| 15 | 15 |
| 16 const ( | 16 const ( |
| 17 // Key of the password for the readwrite user. | 17 // Key of the password for the readwrite user. |
| 18 METADATA_KEY = "readwrite" | 18 METADATA_KEY = "readwrite" |
| 19 | 19 |
| 20 » // Path where the SQLite database is stored when running locally. | 20 » // Production database. |
| 21 » SQLITE_DB_PATH = "./testing.db" | 21 » PROD_DATABASE = "buildbot" |
| 22 | 22 » PROD_DB_HOST = "tcp(173.194.253.125:3306)" |
| 23 » DATABASE = "buildbot" | 23 » PROD_USER = "readwrite" |
| 24 | |
| 25 » // Template to generate the database connection string in production. | |
| 26 » // The IP address of the database is found here: | |
| 27 » // https://console.developers.google.com/project/31977622648/sql/inst
ances/skia-master-db/overview | |
| 28 » // And 3306 is the default port for MySQL. | |
| 29 » DB_CONN_TMPL = "%s:%s@tcp(173.194.253.125:3306)/%s?parseTime=true" | |
| 30 | |
| 31 » // Username of the read/write user. | |
| 32 » RW_USER = "readwrite" | |
| 33 | 24 |
| 34 TABLE_BUILDS = "builds" | 25 TABLE_BUILDS = "builds" |
| 35 TABLE_BUILD_REVISIONS = "buildRevisions" | 26 TABLE_BUILD_REVISIONS = "buildRevisions" |
| 36 TABLE_BUILD_STEPS = "buildSteps" | 27 TABLE_BUILD_STEPS = "buildSteps" |
| 37 ) | 28 ) |
| 38 | 29 |
| 39 var ( | 30 var ( |
| 40 DB *sqlx.DB = nil | 31 DB *sqlx.DB = nil |
| 41 ) | 32 ) |
| 42 | 33 |
| 43 // Setup the database to be shared across the app. | 34 // Setup the database to be shared across the app. |
| 44 func InitDB(conf *database.DatabaseConfig) error { | 35 func InitDB(local bool) error { |
| 36 » conf := databaseConfig(local) |
| 45 vdb := database.NewVersionedDB(conf) | 37 vdb := database.NewVersionedDB(conf) |
| 46 dbVersion, err := vdb.DBVersion() | 38 dbVersion, err := vdb.DBVersion() |
| 47 if err != nil { | 39 if err != nil { |
| 48 return fmt.Errorf("Could not determine database version: %v", er
r) | 40 return fmt.Errorf("Could not determine database version: %v", er
r) |
| 49 } | 41 } |
| 50 maxDBVersion := vdb.MaxDBVersion() | 42 maxDBVersion := vdb.MaxDBVersion() |
| 51 if dbVersion < maxDBVersion { | 43 if dbVersion < maxDBVersion { |
| 52 glog.Infof("Migrating DB to version: %d", maxDBVersion) | 44 glog.Infof("Migrating DB to version: %d", maxDBVersion) |
| 53 if err = vdb.Migrate(maxDBVersion); err != nil { | 45 if err = vdb.Migrate(maxDBVersion); err != nil { |
| 54 return fmt.Errorf("Could not migrate DB: %v", err) | 46 return fmt.Errorf("Could not migrate DB: %v", err) |
| 55 } | 47 } |
| 56 } | 48 } |
| 57 if err = vdb.Close(); err != nil { | 49 if err = vdb.Close(); err != nil { |
| 58 return fmt.Errorf("Could not close database: %v", err) | 50 return fmt.Errorf("Could not close database: %v", err) |
| 59 } | 51 } |
| 60 » if conf.MySQLString != "" { | 52 » DB, err = sqlx.Open("mysql", conf.MySQLString) |
| 61 » » DB, err = sqlx.Open("mysql", conf.MySQLString) | |
| 62 » } else { | |
| 63 » » DB, err = sqlx.Open("sqlite3", conf.SQLiteFilePath) | |
| 64 » } | |
| 65 if err != nil { | 53 if err != nil { |
| 66 return fmt.Errorf("Failed to open database: %v", err) | 54 return fmt.Errorf("Failed to open database: %v", err) |
| 67 } | 55 } |
| 68 return nil | 56 return nil |
| 69 } | 57 } |
| 70 | 58 |
| 71 // Returns the DB connection string for running in production where a | 59 // databaseConfig returns the DB connection config. If 'local' is true it |
| 72 // metadata server is available. If 'local' is true it will always return | 60 // returns a config suitable for local testing. Otherwise it assumes that it's |
| 73 // "" (empty string). When used with Init() this will cause it to use a | 61 // running in production and a metadata server is available. |
| 74 // local SQLite database. If it's not local and the meta data server is | 62 func databaseConfig(local bool) *database.DatabaseConfig { |
| 75 // unreachable it will terminate. | 63 » if local { |
| 76 func ProdDatabaseConfig(local bool) *database.DatabaseConfig { | 64 » » return database.LocalTestDatabaseConfig(migrationSteps) |
| 77 » mysqlStr := "" | 65 » } else { |
| 78 » sqlitePath := SQLITE_DB_PATH | 66 » » // We are in the production environment, so we look up the param
eters. |
| 79 | 67 |
| 80 » // We are in the production environment, so we look up the parameters. | 68 » » // First, get the password from the metadata server. |
| 81 » if !local { | |
| 82 » » // First, get the password from the metadata server. | |
| 83 // See https://developers.google.com/compute/docs/metadata#custo
m. | 69 // See https://developers.google.com/compute/docs/metadata#custo
m. |
| 84 password, err := metadata.Get(METADATA_KEY) | 70 password, err := metadata.Get(METADATA_KEY) |
| 85 if err != nil { | 71 if err != nil { |
| 86 glog.Fatalf("Failed to find metadata. Use 'local' flag w
hen running locally.") | 72 glog.Fatalf("Failed to find metadata. Use 'local' flag w
hen running locally.") |
| 87 } | 73 } |
| 88 » » mysqlStr, sqlitePath = fmt.Sprintf(DB_CONN_TMPL, RW_USER, passwo
rd, DATABASE), "" | 74 » » return database.NewDatabaseConfig(PROD_USER, password, PROD_DB_H
OST, PROD_DATABASE, migrationSteps) |
| 89 » } | |
| 90 | |
| 91 » return &database.DatabaseConfig{ | |
| 92 » » MySQLString: mysqlStr, | |
| 93 » » SQLiteFilePath: sqlitePath, | |
| 94 » » MigrationSteps: migrationSteps, | |
| 95 } | 75 } |
| 96 } | 76 } |
| 97 | 77 |
| 98 // Returns a DB connection string for running a local testing MySQL instance. | |
| 99 func LocalMySQLTestDatabaseConfig(user, password string) *database.DatabaseConfi
g { | |
| 100 mysqlStr := fmt.Sprintf("%s:%s@/sk_testing", user, password) | |
| 101 return &database.DatabaseConfig{ | |
| 102 MySQLString: mysqlStr, | |
| 103 SQLiteFilePath: "", | |
| 104 MigrationSteps: migrationSteps, | |
| 105 } | |
| 106 } | |
| 107 | |
| 108 var v1_up = []string{ | 78 var v1_up = []string{ |
| 109 `CREATE TABLE IF NOT EXISTS builds ( | 79 `CREATE TABLE IF NOT EXISTS builds ( |
| 110 builder VARCHAR(100) NOT NULL, | 80 builder VARCHAR(100) NOT NULL, |
| 111 master VARCHAR(100) NOT NULL, | 81 master VARCHAR(100) NOT NULL, |
| 112 number INT NOT NULL, | 82 number INT NOT NULL, |
| 113 gotRevision VARCHAR(40), | 83 gotRevision VARCHAR(40), |
| 114 branch VARCHAR(100) NOT NULL, | 84 branch VARCHAR(100) NOT NULL, |
| 115 results INT, | 85 results INT, |
| 116 buildslave VARCHAR(100) NOT NULL, | 86 buildslave VARCHAR(100) NOT NULL, |
| 117 started DOUBLE, | 87 started DOUBLE, |
| (...skipping 27 matching lines...) Expand all Loading... |
| 145 `DROP TABLE IF EXISTS buildRevisions`, | 115 `DROP TABLE IF EXISTS buildRevisions`, |
| 146 `DROP TABLE IF EXISTS builds`, | 116 `DROP TABLE IF EXISTS builds`, |
| 147 } | 117 } |
| 148 | 118 |
| 149 // Define the migration steps. | 119 // Define the migration steps. |
| 150 // Note: Only add to this list, once a step has landed in version control it | 120 // Note: Only add to this list, once a step has landed in version control it |
| 151 // must not be changed. | 121 // must not be changed. |
| 152 var migrationSteps = []database.MigrationStep{ | 122 var migrationSteps = []database.MigrationStep{ |
| 153 // version 1 | 123 // version 1 |
| 154 { | 124 { |
| 155 » » MySQLUp: v1_up, | 125 » » MySQLUp: v1_up, |
| 156 » » MySQLDown: v1_down, | 126 » » MySQLDown: v1_down, |
| 157 » » SQLiteUp: v1_up, | |
| 158 » » SQLiteDown: v1_down, | |
| 159 }, | 127 }, |
| 160 } | 128 } |
| OLD | NEW |