| OLD | NEW |
| 1 package mstate | 1 package mstate |
| 2 | 2 |
| 3 import ( | 3 import ( |
| 4 "errors" | 4 "errors" |
| 5 "fmt" | 5 "fmt" |
| 6 "labix.org/v2/mgo" | 6 "labix.org/v2/mgo" |
| 7 "labix.org/v2/mgo/txn" | 7 "labix.org/v2/mgo/txn" |
| 8 "launchpad.net/juju-core/mstate/presence" |
| 8 "launchpad.net/juju-core/trivial" | 9 "launchpad.net/juju-core/trivial" |
| 10 "time" |
| 9 ) | 11 ) |
| 10 | 12 |
| 11 // ResolvedMode describes the way state transition errors· | 13 // ResolvedMode describes the way state transition errors· |
| 12 // are resolved.· | 14 // are resolved.· |
| 13 type ResolvedMode int | 15 type ResolvedMode int |
| 14 | 16 |
| 15 const ( | 17 const ( |
| 16 ResolvedNone ResolvedMode = iota | 18 ResolvedNone ResolvedMode = iota |
| 17 ResolvedRetryHooks | 19 ResolvedRetryHooks |
| 18 ResolvedNoHooks | 20 ResolvedNoHooks |
| 19 nResolvedModes | 21 nResolvedModes |
| 20 ) | 22 ) |
| 21 | 23 |
| 22 // AssignmentPolicy controls what machine a unit will be assigned to. | 24 // AssignmentPolicy controls what machine a unit will be assigned to. |
| 23 type AssignmentPolicy string | 25 type AssignmentPolicy string |
| 24 | 26 |
| 25 const ( | 27 const ( |
| 26 // AssignLocal indicates that all service units should be assigned· | 28 // AssignLocal indicates that all service units should be assigned· |
| 27 // to machine 0. | 29 // to machine 0. |
| 28 AssignLocal AssignmentPolicy = "local" | 30 AssignLocal AssignmentPolicy = "local" |
| 29 // AssignUnused indicates that every service unit should be assigned | 31 // AssignUnused indicates that every service unit should be assigned |
| 30 // to a dedicated machine, and that new machines should be launched | 32 // to a dedicated machine, and that new machines should be launched |
| 31 // if required. | 33 // if required. |
| 32 AssignUnused AssignmentPolicy = "unused" | 34 AssignUnused AssignmentPolicy = "unused" |
| 33 ) | 35 ) |
| 34 | 36 |
| 37 // UnitStatus represents the status of the unit agent. |
| 38 type UnitStatus string |
| 39 |
| 40 const ( |
| 41 UnitPending UnitStatus = "pending" // Agent hasn't started |
| 42 UnitInstalled UnitStatus = "installed" // Agent has run the installed ho
ok |
| 43 UnitStarted UnitStatus = "started" // Agent is running properly |
| 44 UnitStopped UnitStatus = "stopped" // Agent has stopped running on r
equest |
| 45 UnitError UnitStatus = "error" // Agent is waiting in an error s
tate |
| 46 UnitDown UnitStatus = "down" // Agent is down or not communica
ting |
| 47 ) |
| 48 |
| 35 // NeedsUpgrade describes if a unit needs an | 49 // NeedsUpgrade describes if a unit needs an |
| 36 // upgrade and if this is forced. | 50 // upgrade and if this is forced. |
| 37 type NeedsUpgrade struct { | 51 type NeedsUpgrade struct { |
| 38 Upgrade bool | 52 Upgrade bool |
| 39 Force bool | 53 Force bool |
| 40 } | 54 } |
| 41 | 55 |
| 42 // Port identifies a network port number for a particular protocol. | 56 // Port identifies a network port number for a particular protocol. |
| 43 type Port struct { | 57 type Port struct { |
| 44 Protocol string `yaml:"proto"` | 58 Protocol string `yaml:"proto"` |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 // String returns the unit as string. | 100 // String returns the unit as string. |
| 87 func (u *Unit) String() string { | 101 func (u *Unit) String() string { |
| 88 return u.doc.Name | 102 return u.doc.Name |
| 89 } | 103 } |
| 90 | 104 |
| 91 // Name returns the unit name. | 105 // Name returns the unit name. |
| 92 func (u *Unit) Name() string { | 106 func (u *Unit) Name() string { |
| 93 return u.doc.Name | 107 return u.doc.Name |
| 94 } | 108 } |
| 95 | 109 |
| 110 // globalKey returns the global database key for the unit. |
| 111 func (u *Unit) globalKey() string { |
| 112 return "u#" + u.doc.Name |
| 113 } |
| 114 |
| 96 // Life returns whether the unit is Alive, Dying or Dead. | 115 // Life returns whether the unit is Alive, Dying or Dead. |
| 97 func (u *Unit) Life() Life { | 116 func (u *Unit) Life() Life { |
| 98 return u.doc.Life | 117 return u.doc.Life |
| 99 } | 118 } |
| 100 | 119 |
| 101 // Kill sets the unit lifecycle to Dying if it is Alive. | 120 // Kill sets the unit lifecycle to Dying if it is Alive. |
| 102 // It does nothing otherwise. | 121 // It does nothing otherwise. |
| 103 func (u *Unit) Kill() error { | 122 func (u *Unit) Kill() error { |
| 104 err := ensureLife(u.st, u.st.units, u.doc.Name, Dying, "unit") | 123 err := ensureLife(u.st, u.st.units, u.doc.Name, Dying, "unit") |
| 105 if err != nil { | 124 if err != nil { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 148 } | 167 } |
| 149 | 168 |
| 150 func (u *Unit) Refresh() error { | 169 func (u *Unit) Refresh() error { |
| 151 err := u.st.units.FindId(u.doc.Name).One(&u.doc) | 170 err := u.st.units.FindId(u.doc.Name).One(&u.doc) |
| 152 if err != nil { | 171 if err != nil { |
| 153 return fmt.Errorf("cannot refresh unit %q: %v", u, err) | 172 return fmt.Errorf("cannot refresh unit %q: %v", u, err) |
| 154 } | 173 } |
| 155 return nil | 174 return nil |
| 156 } | 175 } |
| 157 | 176 |
| 177 // Status returns the status of the unit's agent. |
| 178 func (u *Unit) Status() (s UnitStatus, info string, err error) { |
| 179 config, err := u.Config() |
| 180 if err != nil { |
| 181 return "", "", fmt.Errorf("cannot read status of unit %q: %v", u
, err) |
| 182 } |
| 183 raw, found := config.Get("status") |
| 184 if !found { |
| 185 return UnitPending, "", nil |
| 186 } |
| 187 s = UnitStatus(raw.(string)) |
| 188 switch s { |
| 189 case UnitError: |
| 190 // We always expect an info if status is 'error'. |
| 191 raw, found = config.Get("status-info") |
| 192 if !found { |
| 193 panic("no status-info found for unit error") |
| 194 } |
| 195 return s, raw.(string), nil |
| 196 case UnitStopped: |
| 197 return UnitStopped, "", nil |
| 198 } |
| 199 alive := u.AgentAlive() |
| 200 if !alive { |
| 201 s = UnitDown |
| 202 } |
| 203 return s, "", nil |
| 204 } |
| 205 |
| 206 // SetStatus sets the status of the unit. |
| 207 func (u *Unit) SetStatus(status UnitStatus, info string) error { |
| 208 if status == UnitPending { |
| 209 panic("unit status must not be set to pending") |
| 210 } |
| 211 config, err := u.Config() |
| 212 if err != nil { |
| 213 return err |
| 214 } |
| 215 config.Set("status", status) |
| 216 config.Set("status-info", info) |
| 217 _, err = config.Write() |
| 218 if err != nil { |
| 219 return fmt.Errorf("cannot set status of unit %q: %v", u, err) |
| 220 } |
| 221 return nil |
| 222 } |
| 223 |
| 224 // AgentAlive returns whether the respective remote agent is alive. |
| 225 func (u *Unit) AgentAlive() bool { |
| 226 return u.st.presencew.Alive(u.globalKey()) |
| 227 } |
| 228 |
| 229 // WaitAgentAlive blocks until the respective agent is alive. |
| 230 func (u *Unit) WaitAgentAlive(timeout time.Duration) error { |
| 231 ch := make(chan presence.Change) |
| 232 u.st.presencew.Add(u.globalKey(), ch) |
| 233 defer u.st.presencew.Remove(u.globalKey(), ch) |
| 234 // Initial check. |
| 235 select { |
| 236 case change := <-ch: |
| 237 if change.Alive { |
| 238 return nil |
| 239 } |
| 240 case <-time.After(timeout): |
| 241 return fmt.Errorf("waiting for agent of unit %q: still not alive
after timeout", u) |
| 242 } |
| 243 // Hasn't been alive, so now wait for change. |
| 244 select { |
| 245 case change := <-ch: |
| 246 if change.Alive { |
| 247 return nil |
| 248 } |
| 249 panic(fmt.Sprintf("presence reported dead status twice in a row
for unit %q", u)) |
| 250 case <-time.After(timeout): |
| 251 return fmt.Errorf("waiting for agent of unit %q: still not alive
after timeout", u) |
| 252 } |
| 253 panic("unreachable") |
| 254 } |
| 255 |
| 256 // SetAgentAlive signals that the agent for unit u is alive.· |
| 257 // It returns the started pinger. |
| 258 func (u *Unit) SetAgentAlive() (*presence.Pinger, error) { |
| 259 p := presence.NewPinger(u.st.presence, u.globalKey()) |
| 260 err := p.Start() |
| 261 if err != nil { |
| 262 return nil, err |
| 263 } |
| 264 return p, nil |
| 265 } |
| 266 |
| 158 // AssignedMachineId returns the id of the assigned machine. | 267 // AssignedMachineId returns the id of the assigned machine. |
| 159 func (u *Unit) AssignedMachineId() (id int, err error) { | 268 func (u *Unit) AssignedMachineId() (id int, err error) { |
| 160 defer trivial.ErrorContextf(&err, "cannot get machine id of unit %q", u) | 269 defer trivial.ErrorContextf(&err, "cannot get machine id of unit %q", u) |
| 161 if u.IsPrincipal() { | 270 if u.IsPrincipal() { |
| 162 if u.doc.MachineId == nil { | 271 if u.doc.MachineId == nil { |
| 163 return 0, errors.New("unit not assigned to machine") | 272 return 0, errors.New("unit not assigned to machine") |
| 164 } | 273 } |
| 165 return *u.doc.MachineId, nil | 274 return *u.doc.MachineId, nil |
| 166 } | 275 } |
| 167 pudoc := unitDoc{} | 276 pudoc := unitDoc{} |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 352 func (u *Unit) ClearNeedsUpgrade() error { | 461 func (u *Unit) ClearNeedsUpgrade() error { |
| 353 change := D{{"$set", D{{"needsupgrade", nil}}}} | 462 change := D{{"$set", D{{"needsupgrade", nil}}}} |
| 354 sel := D{{"_id", u.doc.Name}} | 463 sel := D{{"_id", u.doc.Name}} |
| 355 err := u.st.units.Update(sel, change) | 464 err := u.st.units.Update(sel, change) |
| 356 if err != nil { | 465 if err != nil { |
| 357 return fmt.Errorf("upgrade notification for unit %q cannot be re
set: %v", u, err) | 466 return fmt.Errorf("upgrade notification for unit %q cannot be re
set: %v", u, err) |
| 358 } | 467 } |
| 359 u.doc.NeedsUpgrade = nil | 468 u.doc.NeedsUpgrade = nil |
| 360 return nil | 469 return nil |
| 361 } | 470 } |
| 471 |
| 472 // Config returns the configuration node for the unit. |
| 473 func (u *Unit) Config() (config *ConfigNode, err error) { |
| 474 config, err = readConfigNode(u.st, u.globalKey()) |
| 475 if err != nil { |
| 476 return nil, fmt.Errorf("cannot get configuration of unit %q: %v"
, u, err) |
| 477 } |
| 478 return config, nil |
| 479 } |
| OLD | NEW |