@@ -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,6 +20,8 @@ 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 (
@@ -42,8 +45,32 @@ type dbProxy interface {
4245 Prepare (query string ) (* sql.Stmt , error )
4346}
4447
48+ // dbWait waits for database connection to be established
49+ func dbWait (db * sql.DB ) error {
50+ deadline := time .Now ().Add (dbTimeout )
51+ var err error
52+ for tries := 0 ; time .Now ().Before (deadline ); tries ++ {
53+ err = db .Ping ()
54+ if err == nil {
55+ return nil
56+ }
57+ level .Warn (util .Logger ).Log ("msg" , "db connection not established, retrying..." , "error" , err )
58+ time .Sleep (time .Second << uint (tries ))
59+ }
60+ return errors .Wrapf (err , "db connection not established after %s" , dbTimeout )
61+ }
62+
4563// New creates a new postgres DB
4664func New (uri , migrationsDir string ) (DB , error ) {
65+ db , err := sql .Open ("postgres" , uri )
66+ if err != nil {
67+ return DB {}, errors .Wrap (err , "cannot open postgres db" )
68+ }
69+
70+ if err := dbWait (db ); err != nil {
71+ return DB {}, errors .Wrap (err , "cannot establish db connection" )
72+ }
73+
4774 if migrationsDir != "" {
4875 level .Info (util .Logger ).Log ("msg" , "running database migrations..." )
4976 if errs , ok := migrate .UpSync (uri , migrationsDir ); ! ok {
@@ -53,7 +80,7 @@ func New(uri, migrationsDir string) (DB, error) {
5380 return DB {}, errors .New ("database migrations failed" )
5481 }
5582 }
56- db , err := sql . Open ( "postgres" , uri )
83+
5784 return DB {
5885 dbProxy : db ,
5986 StatementBuilderType : statementBuilder (db ),
@@ -225,6 +252,57 @@ func (d DB) GetRulesConfigs(since configs.ID) (map[string]configs.VersionedRules
225252 })
226253}
227254
255+ // GetLastConfig gets a last configuration (active or deleted).
256+ func (d DB ) GetLastConfig (userID string ) (configs.View , error ) {
257+ var cfgView configs.View
258+ var cfgBytes []byte
259+ err := d .Select ("id" , "config" ).
260+ From ("configs" ).
261+ Where (squirrel.Eq {"owner_id" : userID }).
262+ OrderBy ("id DESC" ).
263+ Limit (1 ).
264+ QueryRow ().Scan (& cfgView .ID , & cfgBytes )
265+ if err != nil {
266+ return cfgView , err
267+ }
268+ err = json .Unmarshal (cfgBytes , & cfgView .Config )
269+ log .Infof ("get last config bytes: %s" , cfgBytes )
270+ return cfgView , err
271+ }
272+
273+ // SetDeletedAtConfig sets a deletedAt for configuration.
274+ func (d DB ) SetDeletedAtConfig (userID string , deletedAt time.Time , cfg configs.Config ) error {
275+ cfgBytes , err := json .Marshal (cfg )
276+ if err != nil {
277+ return err
278+ }
279+
280+ log .Infof ("set deletedA to %s for %s" , deletedAt , cfgBytes )
281+ _ , err = d .Insert ("configs" ).
282+ Columns ("owner_id" , "owner_type" , "subsystem" , "deleted_at" , "config" ).
283+ Values (userID , entityType , subsystem , deletedAt , cfgBytes ).
284+ Exec ()
285+ return err
286+ }
287+
288+ // DeactivateConfig deactivates a configuration.
289+ func (d DB ) DeactivateConfig (userID string ) error {
290+ cfg , err := d .GetLastConfig (userID )
291+ if err != nil {
292+ return err
293+ }
294+ return d .SetDeletedAtConfig (userID , time .Now (), cfg .Config )
295+ }
296+
297+ // RestoreConfig restores deactivated configuration.
298+ func (d DB ) RestoreConfig (userID string ) error {
299+ cfg , err := d .GetLastConfig (userID )
300+ if err != nil {
301+ return err
302+ }
303+ return d .SetDeletedAtConfig (userID , time.Time {}, cfg .Config )
304+ }
305+
228306// Transaction runs the given function in a postgres transaction. If fn returns
229307// an error the txn will be rolled back.
230308func (d DB ) Transaction (f func (DB ) error ) error {
0 commit comments