github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/state/restore.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state 5 6 import ( 7 "github.com/juju/errors" 8 "gopkg.in/mgo.v2" 9 "gopkg.in/mgo.v2/bson" 10 "gopkg.in/mgo.v2/txn" 11 ) 12 13 // RestoreStatus is the type of the statuses 14 type RestoreStatus string 15 16 const ( 17 currentRestoreId = "current" 18 19 // UnknownRestoreStatus is the initial status for restoreInfoDoc. 20 UnknownRestoreStatus RestoreStatus = "UNKNOWN" 21 // RestorePending is a status to signal that a restore is about to start 22 // any change done in this status will be lost. 23 RestorePending RestoreStatus = "PENDING" 24 // RestoreInProgress indicates that a Restore is in progress. 25 RestoreInProgress RestoreStatus = "RESTORING" 26 // RestoreFinished it is set by restore upon a succesful run. 27 RestoreFinished RestoreStatus = "RESTORED" 28 // RestoreChecked is set when the server comes up after a succesful restore. 29 RestoreChecked RestoreStatus = "CHECKED" 30 // RestoreFailed indicates that the process failed in a recoverable step. 31 RestoreFailed RestoreStatus = "FAILED" 32 ) 33 34 type restoreInfoDoc struct { 35 Id string `bson:"_id"` 36 Status RestoreStatus `bson:"status"` 37 } 38 39 // RestoreInfo its used to syncronize Restore and machine agent 40 type RestoreInfo struct { 41 st *State 42 doc restoreInfoDoc 43 } 44 45 // Status returns the current Restore doc status 46 func (info *RestoreInfo) Status() RestoreStatus { 47 return info.doc.Status 48 } 49 50 // SetStatus sets the status of the current restore. Checks are made 51 // to ensure that status changes are performed in the correct order. 52 func (info *RestoreInfo) SetStatus(status RestoreStatus) error { 53 var assertSane bson.D 54 55 if status == RestoreInProgress { 56 assertSane = bson.D{{"status", RestorePending}} 57 } 58 if status == RestoreChecked { 59 assertSane = bson.D{{"status", RestoreFinished}} 60 } 61 62 ops := []txn.Op{{ 63 C: restoreInfoC, 64 Id: currentRestoreId, 65 Assert: assertSane, 66 Update: bson.D{{"$set", bson.D{{"status", status}}}}, 67 }} 68 err := info.st.runTransaction(ops) 69 if err == txn.ErrAborted { 70 return errors.Errorf("cannot set restore status to %q: Another "+ 71 "status change occurred concurrently", status) 72 } 73 return errors.Annotatef(err, "cannot set restore status to %q", status) 74 } 75 76 // RestoreInfoSetter returns the current info doc, if it does not exists 77 // it creates it with UnknownRestoreStatus status 78 func (st *State) RestoreInfoSetter() (*RestoreInfo, error) { 79 doc := restoreInfoDoc{} 80 restoreInfo, closer := st.getCollection(restoreInfoC) 81 defer closer() 82 err := restoreInfo.Find(bson.M{"_id": currentRestoreId}).One(&doc) 83 switch errors.Cause(err) { 84 case nil: 85 case mgo.ErrNotFound: 86 doc = restoreInfoDoc{ 87 Id: currentRestoreId, 88 Status: UnknownRestoreStatus, 89 } 90 default: 91 return nil, errors.Annotate(err, "cannot read restore info") 92 } 93 return &RestoreInfo{st: st, doc: doc}, nil 94 }