This repository has been archived by the owner on Jul 4, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 83
/
schema_initializer.go
117 lines (90 loc) · 2.68 KB
/
schema_initializer.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
package database
import (
"fmt"
"io/ioutil"
"time"
dbr "github.com/gocraft/dbr/v2"
"github.com/lib/pq"
"github.com/pkg/errors"
_ "github.com/lib/pq"
log "github.com/sirupsen/logrus"
)
const (
schemaName = "public"
clusterTableName = "cluster"
)
// InitializeDatabaseConnection opens database connection
func InitializeDatabaseConnection(connectionString string, retryCount int) (*dbr.Connection, error) {
connection, err := waitForDatabaseAccess(connectionString, retryCount)
if err != nil {
return nil, err
}
return connection, nil
}
// SetupSchema initializes Provisioner database schema
func SetupSchema(connection *dbr.Connection, schemaFilePath string) error {
initialized, err := checkIfDatabaseInitialized(connection)
if err != nil {
closeDBConnection(connection)
return errors.Wrap(err, "Failed to check if database is initialized")
}
if initialized {
log.Info("Database already initialized")
return nil
}
log.Info("Database not initialized. Setting up schema...")
content, err := ioutil.ReadFile(schemaFilePath)
if err != nil {
closeDBConnection(connection)
return errors.Wrap(err, "Failed to read schema file")
}
_, err = connection.Exec(string(content))
if err != nil {
closeDBConnection(connection)
return errors.Wrap(err, "Failed to setup database schema")
}
log.Info("Database initialized successfully")
return nil
}
func closeDBConnection(db *dbr.Connection) {
err := db.Close()
if err != nil {
log.Warnf("Failed to close database connection: %s", err.Error())
}
}
const TableNotExistsError = "42P01"
func checkIfDatabaseInitialized(db *dbr.Connection) (bool, error) {
checkQuery := fmt.Sprintf(`SELECT '%s.%s'::regclass;`, schemaName, clusterTableName)
row := db.QueryRow(checkQuery)
var tableName string
err := row.Scan(&tableName)
if err != nil {
psqlErr, converted := err.(*pq.Error)
if converted && psqlErr.Code == TableNotExistsError {
return false, nil
}
return false, errors.Wrap(err, "Failed to check if schema initialized")
}
return tableName == clusterTableName, nil
}
func waitForDatabaseAccess(connString string, retryCount int) (*dbr.Connection, error) {
var connection *dbr.Connection
var err error
for ; retryCount > 0; retryCount-- {
connection, err = dbr.Open("postgres", connString, nil)
if err != nil {
return nil, errors.Wrap(err, "Invalid connection string")
}
err = connection.Ping()
if err == nil {
return connection, nil
}
err = connection.Close()
if err != nil {
log.Info("Failed to close database ...")
}
log.Info("Failed to access database, waiting 5 seconds to retry...")
time.Sleep(5 * time.Second)
}
return nil, errors.New("timeout waiting for database access")
}