@@ -3,13 +3,14 @@ package postgres
33import (
44 "database/sql"
55 "encoding/json"
6- "errors "
6+ "time "
77
88 "github.com/Masterminds/squirrel"
99 "github.com/go-kit/kit/log/level"
1010 _ "github.com/lib/pq" // Import the postgres sql driver
1111 _ "github.com/mattes/migrate/driver/postgres" // Import the postgres migrations driver
1212 "github.com/mattes/migrate/migrate"
13+ "github.com/pkg/errors"
1314 "github.com/weaveworks/cortex/pkg/configs"
1415 "github.com/weaveworks/cortex/pkg/util"
1516)
@@ -19,11 +20,12 @@ const (
1920 // schema so this isn't needed.
2021 entityType = "org"
2122 subsystem = "cortex"
23+ // timeout waiting for database connection to be established
24+ dbTimeout = 5 * time .Minute
2225)
2326
2427var (
25- activeConfig = squirrel.Eq {
26- "deleted_at" : nil ,
28+ allConfigs = squirrel.Eq {
2729 "owner_type" : entityType ,
2830 "subsystem" : subsystem ,
2931 }
@@ -42,8 +44,32 @@ type dbProxy interface {
4244 Prepare (query string ) (* sql.Stmt , error )
4345}
4446
47+ // dbWait waits for database connection to be established
48+ func dbWait (db * sql.DB ) error {
49+ deadline := time .Now ().Add (dbTimeout )
50+ var err error
51+ for tries := 0 ; time .Now ().Before (deadline ); tries ++ {
52+ err = db .Ping ()
53+ if err == nil {
54+ return nil
55+ }
56+ level .Warn (util .Logger ).Log ("msg" , "db connection not established, retrying..." , "error" , err )
57+ time .Sleep (time .Second << uint (tries ))
58+ }
59+ return errors .Wrapf (err , "db connection not established after %s" , dbTimeout )
60+ }
61+
4562// New creates a new postgres DB
4663func New (uri , migrationsDir string ) (DB , error ) {
64+ db , err := sql .Open ("postgres" , uri )
65+ if err != nil {
66+ return DB {}, errors .Wrap (err , "cannot open postgres db" )
67+ }
68+
69+ if err := dbWait (db ); err != nil {
70+ return DB {}, errors .Wrap (err , "cannot establish db connection" )
71+ }
72+
4773 if migrationsDir != "" {
4874 level .Info (util .Logger ).Log ("msg" , "running database migrations..." )
4975 if errs , ok := migrate .UpSync (uri , migrationsDir ); ! ok {
@@ -53,7 +79,7 @@ func New(uri, migrationsDir string) (DB, error) {
5379 return DB {}, errors .New ("database migrations failed" )
5480 }
5581 }
56- db , err := sql . Open ( "postgres" , uri )
82+
5783 return DB {
5884 dbProxy : db ,
5985 StatementBuilderType : statementBuilder (db ),
@@ -97,7 +123,7 @@ func (d DB) GetConfig(userID string) (configs.View, error) {
97123 var cfgBytes []byte
98124 err := d .Select ("id" , "config" ).
99125 From ("configs" ).
100- Where (squirrel.And {activeConfig , squirrel.Eq {"owner_id" : userID }}).
126+ Where (squirrel.And {allConfigs , squirrel.Eq {"owner_id" : userID }}).
101127 OrderBy ("id DESC" ).
102128 Limit (1 ).
103129 QueryRow ().Scan (& cfgView .ID , & cfgBytes )
@@ -123,13 +149,13 @@ func (d DB) SetConfig(userID string, cfg configs.Config) error {
123149
124150// GetAllConfigs gets all of the configs.
125151func (d DB ) GetAllConfigs () (map [string ]configs.View , error ) {
126- return d .findConfigs (activeConfig )
152+ return d .findConfigs (allConfigs )
127153}
128154
129155// GetConfigs gets all of the configs that have changed recently.
130156func (d DB ) GetConfigs (since configs.ID ) (map [string ]configs.View , error ) {
131157 return d .findConfigs (squirrel.And {
132- activeConfig ,
158+ allConfigs ,
133159 squirrel.Gt {"id" : since },
134160 })
135161}
@@ -214,17 +240,50 @@ func (d DB) findRulesConfigs(filter squirrel.Sqlizer) (map[string]configs.Versio
214240
215241// GetAllRulesConfigs gets all alertmanager configs for all users.
216242func (d DB ) GetAllRulesConfigs () (map [string ]configs.VersionedRulesConfig , error ) {
217- return d .findRulesConfigs (activeConfig )
243+ return d .findRulesConfigs (allConfigs )
218244}
219245
220246// GetRulesConfigs gets all the alertmanager configs that have changed since a given config.
221247func (d DB ) GetRulesConfigs (since configs.ID ) (map [string ]configs.VersionedRulesConfig , error ) {
222248 return d .findRulesConfigs (squirrel.And {
223- activeConfig ,
249+ allConfigs ,
224250 squirrel.Gt {"id" : since },
225251 })
226252}
227253
254+ // SetDeletedAtConfig sets a deletedAt for configuration
255+ // by adding a single new row with deleted_at set
256+ // the same as SetConfig is actually insert
257+ func (d DB ) SetDeletedAtConfig (userID string , deletedAt time.Time , cfg configs.Config ) error {
258+ cfgBytes , err := json .Marshal (cfg )
259+ if err != nil {
260+ return err
261+ }
262+ _ , err = d .Insert ("configs" ).
263+ Columns ("owner_id" , "owner_type" , "subsystem" , "deleted_at" , "config" ).
264+ Values (userID , entityType , subsystem , deletedAt , cfgBytes ).
265+ Exec ()
266+ return err
267+ }
268+
269+ // DeactivateConfig deactivates a configuration.
270+ func (d DB ) DeactivateConfig (userID string ) error {
271+ cfg , err := d .GetConfig (userID )
272+ if err != nil {
273+ return err
274+ }
275+ return d .SetDeletedAtConfig (userID , time .Now (), cfg .Config )
276+ }
277+
278+ // RestoreConfig restores configuration.
279+ func (d DB ) RestoreConfig (userID string ) error {
280+ cfg , err := d .GetConfig (userID )
281+ if err != nil {
282+ return err
283+ }
284+ return d .SetDeletedAtConfig (userID , time.Time {}, cfg .Config )
285+ }
286+
228287// Transaction runs the given function in a postgres transaction. If fn returns
229288// an error the txn will be rolled back.
230289func (d DB ) Transaction (f func (DB ) error ) error {
0 commit comments