launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/state/environ.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state 5 6 import ( 7 "labix.org/v2/mgo" 8 "labix.org/v2/mgo/txn" 9 10 errgo "launchpad.net/errgo/errors" 11 "launchpad.net/juju-core/errors" 12 "launchpad.net/juju-core/names" 13 ) 14 15 // environGlobalKey is the key for the environment, its 16 // settings and constraints. 17 const environGlobalKey = "e" 18 19 // Environment represents the state of an environment. 20 type Environment struct { 21 st *State 22 doc environmentDoc 23 annotator 24 } 25 26 // environmentDoc represents the internal state of the environment in MongoDB. 27 type environmentDoc struct { 28 UUID string `bson:"_id"` 29 Name string 30 Life Life 31 } 32 33 // Environment returns the environment entity. 34 func (st *State) Environment() (*Environment, error) { 35 env := &Environment{st: st} 36 if err := env.refresh(st.environments.Find(nil)); err != nil { 37 return nil, mask(err, errors.IsNotFoundError) 38 } 39 env.annotator = annotator{ 40 globalKey: env.globalKey(), 41 tag: env.Tag(), 42 st: st, 43 } 44 return env, nil 45 } 46 47 // Tag returns a name identifying the environment. 48 // The returned name will be different from other Tag values returned 49 // by any other entities from the same state. 50 func (e *Environment) Tag() string { 51 return names.EnvironTag(e.doc.UUID) 52 } 53 54 // UUID returns the universally unique identifier of the environment. 55 func (e *Environment) UUID() string { 56 return e.doc.UUID 57 } 58 59 // Name returns the human friendly name of the environment. 60 func (e *Environment) Name() string { 61 return e.doc.Name 62 } 63 64 // Life returns whether the environment is Alive, Dying or Dead. 65 func (e *Environment) Life() Life { 66 return e.doc.Life 67 } 68 69 // globalKey returns the global database key for the environment. 70 func (e *Environment) globalKey() string { 71 return environGlobalKey 72 } 73 74 func (e *Environment) Refresh() error { 75 return e.refresh(e.st.environments.FindId(e.UUID())) 76 } 77 78 func (e *Environment) refresh(query *mgo.Query) error { 79 err := query.One(&e.doc) 80 if errgo.Cause(err) == mgo.ErrNotFound { 81 return errors.NotFoundf("environment") 82 } 83 return err 84 } 85 86 // Destroy sets the environment's lifecycle to Dying, preventing 87 // addition of services or machines to state. 88 func (e *Environment) Destroy() error { 89 if e.Life() != Alive { 90 return nil 91 } 92 // TODO(axw) 2013-12-11 #1218688 93 // Resolve the race between checking for manual machines and 94 // destroying the environment. We can set Environment to Dying 95 // to resolve the race, but that puts the environment into an 96 // unusable state. 97 // 98 // We add a cleanup for services, but not for machines; 99 // machines are destroyed via the provider interface. The 100 // exception to this rule is manual machines; the API prevents 101 // destroy-environment from succeeding if any non-manager 102 // manual machines exist. 103 ops := []txn.Op{{ 104 C: e.st.environments.Name, 105 Id: e.doc.UUID, 106 Update: D{{"$set", D{{"life", Dying}}}}, 107 Assert: isEnvAliveDoc, 108 }, e.st.newCleanupOp("services", "")} 109 err := e.st.runTransaction(ops) 110 switch err { 111 case nil, txn.ErrAborted: 112 // If the transaction aborted, the environment is either 113 // Dying or Dead; neither case is an error. If it's Dead, 114 // reporting it as Dying is not incorrect; the user thought 115 // it was Alive, so we've progressed towards Dead. If the 116 // user then calls Refresh they'll get the true value. 117 e.doc.Life = Dying 118 } 119 return err 120 } 121 122 // createEnvironmentOp returns the operation needed to create 123 // an environment document with the given name and UUID. 124 func createEnvironmentOp(st *State, name, uuid string) txn.Op { 125 doc := &environmentDoc{uuid, name, Alive} 126 return txn.Op{ 127 C: st.environments.Name, 128 Id: uuid, 129 Assert: txn.DocMissing, 130 Insert: doc, 131 } 132 } 133 134 // assertAliveOp returns a txn.Op that asserts the environment is alive. 135 func (e *Environment) assertAliveOp() txn.Op { 136 return txn.Op{ 137 C: e.st.environments.Name, 138 Id: e.UUID(), 139 Assert: isEnvAliveDoc, 140 } 141 } 142 143 // isEnvAlive is an Environment-specific versio nof isAliveDoc. 144 // 145 // Environment documents from versions of Juju prior to 1.17 146 // do not have the life field; if it does not exist, it should 147 // be considered to have the value Alive. 148 var isEnvAliveDoc = D{ 149 {"life", D{{"$in", []interface{}{Alive, nil}}}}, 150 }