github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/worker/uniter/remotestate/watcher.go (about) 1 // Copyright 2012-2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package remotestate 5 6 import ( 7 "sync" 8 "time" 9 10 "github.com/juju/errors" 11 "github.com/juju/loggo" 12 "github.com/juju/names" 13 "launchpad.net/tomb" 14 15 apiwatcher "github.com/juju/juju/api/watcher" 16 "github.com/juju/juju/apiserver/params" 17 "github.com/juju/juju/state/watcher" 18 "github.com/juju/juju/worker" 19 "github.com/juju/juju/worker/leadership" 20 ) 21 22 var logger = loggo.GetLogger("juju.worker.uniter.remotestate") 23 24 // RemoteStateWatcher collects unit, service, and service config information 25 // from separate state watchers, and updates a Snapshot which is sent on a 26 // channel upon change. 27 type RemoteStateWatcher struct { 28 st State 29 unit Unit 30 service Service 31 relations map[names.RelationTag]*relationUnitsWatcher 32 relationUnitsChanges chan relationUnitsChange 33 storageAttachmentWatchers map[names.StorageTag]*storageAttachmentWatcher 34 storageAttachmentChanges chan storageAttachmentChange 35 leadershipTracker leadership.Tracker 36 updateStatusChannel func() <-chan time.Time 37 38 tomb tomb.Tomb 39 40 out chan struct{} 41 mu sync.Mutex 42 current Snapshot 43 } 44 45 // WatcherConfig holds configuration parameters for the 46 // remote state watcher. 47 type WatcherConfig struct { 48 State State 49 LeadershipTracker leadership.Tracker 50 UpdateStatusChannel func() <-chan time.Time 51 UnitTag names.UnitTag 52 } 53 54 // NewWatcher returns a RemoteStateWatcher that handles state changes pertaining to the 55 // supplied unit. 56 func NewWatcher(config WatcherConfig) (*RemoteStateWatcher, error) { 57 w := &RemoteStateWatcher{ 58 st: config.State, 59 relations: make(map[names.RelationTag]*relationUnitsWatcher), 60 relationUnitsChanges: make(chan relationUnitsChange), 61 storageAttachmentWatchers: make(map[names.StorageTag]*storageAttachmentWatcher), 62 storageAttachmentChanges: make(chan storageAttachmentChange), 63 leadershipTracker: config.LeadershipTracker, 64 updateStatusChannel: config.UpdateStatusChannel, 65 // Note: it is important that the out channel be buffered! 66 // The remote state watcher will perform a non-blocking send 67 // on the channel to wake up the observer. It is non-blocking 68 // so that we coalesce events while the observer is busy. 69 out: make(chan struct{}, 1), 70 current: Snapshot{ 71 Relations: make(map[int]RelationSnapshot), 72 Storage: make(map[names.StorageTag]StorageSnapshot), 73 }, 74 } 75 if err := w.init(config.UnitTag); err != nil { 76 return nil, errors.Trace(err) 77 } 78 go func() { 79 defer w.tomb.Done() 80 err := w.loop(config.UnitTag) 81 logger.Errorf("remote state watcher exited: %v", err) 82 w.tomb.Kill(errors.Cause(err)) 83 84 // Stop all remaining sub-watchers. 85 for _, w := range w.storageAttachmentWatchers { 86 watcher.Stop(w, &w.tomb) 87 } 88 for _, w := range w.relations { 89 watcher.Stop(w, &w.tomb) 90 } 91 }() 92 return w, nil 93 } 94 95 func (w *RemoteStateWatcher) Stop() error { 96 w.tomb.Kill(nil) 97 return w.tomb.Wait() 98 } 99 100 func (w *RemoteStateWatcher) Dead() <-chan struct{} { 101 return w.tomb.Dead() 102 } 103 104 func (w *RemoteStateWatcher) Wait() error { 105 return w.tomb.Wait() 106 } 107 108 func (w *RemoteStateWatcher) Kill() { 109 w.tomb.Kill(nil) 110 } 111 112 func (w *RemoteStateWatcher) RemoteStateChanged() <-chan struct{} { 113 return w.out 114 } 115 116 func (w *RemoteStateWatcher) Snapshot() Snapshot { 117 w.mu.Lock() 118 defer w.mu.Unlock() 119 snapshot := w.current 120 snapshot.Relations = make(map[int]RelationSnapshot) 121 for id, relationSnapshot := range w.current.Relations { 122 snapshot.Relations[id] = relationSnapshot 123 } 124 snapshot.Storage = make(map[names.StorageTag]StorageSnapshot) 125 for tag, storageSnapshot := range w.current.Storage { 126 snapshot.Storage[tag] = storageSnapshot 127 } 128 snapshot.Actions = make([]string, len(w.current.Actions)) 129 for i, action := range w.current.Actions { 130 snapshot.Actions[i] = action 131 } 132 return snapshot 133 } 134 135 func (w *RemoteStateWatcher) ClearResolvedMode() { 136 w.mu.Lock() 137 w.current.ResolvedMode = params.ResolvedNone 138 w.mu.Unlock() 139 } 140 141 func (w *RemoteStateWatcher) init(unitTag names.UnitTag) (err error) { 142 // TODO(dfc) named return value is a time bomb 143 // TODO(axw) move this logic. 144 defer func() { 145 if params.IsCodeNotFoundOrCodeUnauthorized(err) { 146 err = worker.ErrTerminateAgent 147 } 148 }() 149 if w.unit, err = w.st.Unit(unitTag); err != nil { 150 return err 151 } 152 w.service, err = w.unit.Service() 153 if err != nil { 154 return err 155 } 156 return nil 157 } 158 159 func (w *RemoteStateWatcher) loop(unitTag names.UnitTag) (err error) { 160 var requiredEvents int 161 162 var seenUnitChange bool 163 unitw, err := w.unit.Watch() 164 if err != nil { 165 return err 166 } 167 defer watcher.Stop(unitw, &w.tomb) 168 requiredEvents++ 169 170 var seenServiceChange bool 171 servicew, err := w.service.Watch() 172 if err != nil { 173 return err 174 } 175 defer watcher.Stop(servicew, &w.tomb) 176 requiredEvents++ 177 178 var seenConfigChange bool 179 configw, err := w.unit.WatchConfigSettings() 180 if err != nil { 181 return err 182 } 183 defer watcher.Stop(configw, &w.tomb) 184 requiredEvents++ 185 186 var seenRelationsChange bool 187 relationsw, err := w.service.WatchRelations() 188 if err != nil { 189 return err 190 } 191 defer watcher.Stop(relationsw, &w.tomb) 192 requiredEvents++ 193 194 var seenAddressesChange bool 195 addressesw, err := w.unit.WatchAddresses() 196 if err != nil { 197 return err 198 } 199 defer watcher.Stop(addressesw, &w.tomb) 200 requiredEvents++ 201 202 var seenStorageChange bool 203 storagew, err := w.unit.WatchStorage() 204 if err != nil { 205 return err 206 } 207 defer watcher.Stop(storagew, &w.tomb) 208 requiredEvents++ 209 210 var seenLeaderSettingsChange bool 211 leaderSettingsw, err := w.service.WatchLeadershipSettings() 212 if err != nil { 213 return err 214 } 215 defer watcher.Stop(leaderSettingsw, &w.tomb) 216 requiredEvents++ 217 218 var seenActionsChange bool 219 actionsw, err := w.unit.WatchActionNotifications() 220 if err != nil { 221 return err 222 } 223 defer watcher.Stop(actionsw, &w.tomb) 224 requiredEvents++ 225 226 var seenLeadershipChange bool 227 // There's no watcher for this per se; we wait on a channel 228 // returned by the leadership tracker. 229 requiredEvents++ 230 231 var eventsObserved int 232 observedEvent := func(flag *bool) { 233 if !*flag { 234 *flag = true 235 eventsObserved++ 236 } 237 } 238 239 // fire will, once the first event for each watcher has 240 // been observed, send a signal on the out channel. 241 fire := func() { 242 if eventsObserved != requiredEvents { 243 return 244 } 245 select { 246 case w.out <- struct{}{}: 247 default: 248 } 249 } 250 251 defer func() { 252 for _, ruw := range w.relations { 253 watcher.Stop(ruw, &w.tomb) 254 } 255 }() 256 257 // Check the initial leadership status, and then we can flip-flop 258 // waiting on leader or minion to trigger the changed event. 259 var waitLeader, waitMinion <-chan struct{} 260 claimLeader := w.leadershipTracker.ClaimLeader() 261 select { 262 case <-w.tomb.Dying(): 263 return tomb.ErrDying 264 case <-claimLeader.Ready(): 265 isLeader := claimLeader.Wait() 266 w.leadershipChanged(isLeader) 267 if isLeader { 268 waitMinion = w.leadershipTracker.WaitMinion().Ready() 269 } else { 270 waitLeader = w.leadershipTracker.WaitLeader().Ready() 271 } 272 observedEvent(&seenLeadershipChange) 273 } 274 275 for { 276 select { 277 case <-w.tomb.Dying(): 278 return tomb.ErrDying 279 280 case _, ok := <-unitw.Changes(): 281 logger.Debugf("got unit change") 282 if !ok { 283 return watcher.EnsureErr(unitw) 284 } 285 if err := w.unitChanged(); err != nil { 286 return err 287 } 288 observedEvent(&seenUnitChange) 289 290 case _, ok := <-servicew.Changes(): 291 logger.Debugf("got service change") 292 if !ok { 293 return watcher.EnsureErr(servicew) 294 } 295 if err := w.serviceChanged(); err != nil { 296 return err 297 } 298 observedEvent(&seenServiceChange) 299 300 case _, ok := <-configw.Changes(): 301 logger.Debugf("got config change: ok=%t", ok) 302 if !ok { 303 return watcher.EnsureErr(configw) 304 } 305 if err := w.configChanged(); err != nil { 306 return err 307 } 308 observedEvent(&seenConfigChange) 309 310 case _, ok := <-addressesw.Changes(): 311 logger.Debugf("got address change: ok=%t", ok) 312 if !ok { 313 return watcher.EnsureErr(addressesw) 314 } 315 if err := w.addressesChanged(); err != nil { 316 return err 317 } 318 observedEvent(&seenAddressesChange) 319 320 case _, ok := <-leaderSettingsw.Changes(): 321 logger.Debugf("got leader settings change: ok=%t", ok) 322 if !ok { 323 return watcher.EnsureErr(leaderSettingsw) 324 } 325 if err := w.leaderSettingsChanged(); err != nil { 326 return err 327 } 328 observedEvent(&seenLeaderSettingsChange) 329 330 case actions, ok := <-actionsw.Changes(): 331 logger.Debugf("got action change: %v ok=%t", actions, ok) 332 if !ok { 333 return watcher.EnsureErr(actionsw) 334 } 335 if err := w.actionsChanged(actions); err != nil { 336 return err 337 } 338 observedEvent(&seenActionsChange) 339 340 case keys, ok := <-relationsw.Changes(): 341 logger.Debugf("got relations change: ok=%t", ok) 342 if !ok { 343 return watcher.EnsureErr(relationsw) 344 } 345 if err := w.relationsChanged(keys); err != nil { 346 return err 347 } 348 observedEvent(&seenRelationsChange) 349 350 case keys, ok := <-storagew.Changes(): 351 logger.Debugf("got storage change: %v ok=%t", keys, ok) 352 if !ok { 353 return watcher.EnsureErr(storagew) 354 } 355 if err := w.storageChanged(keys); err != nil { 356 return err 357 } 358 observedEvent(&seenStorageChange) 359 360 case <-waitMinion: 361 logger.Debugf("got leadership change: minion") 362 if err := w.leadershipChanged(false); err != nil { 363 return err 364 } 365 waitMinion = nil 366 waitLeader = w.leadershipTracker.WaitLeader().Ready() 367 368 case <-waitLeader: 369 logger.Debugf("got leadership change: leader") 370 if err := w.leadershipChanged(true); err != nil { 371 return err 372 } 373 waitLeader = nil 374 waitMinion = w.leadershipTracker.WaitMinion().Ready() 375 376 case change := <-w.storageAttachmentChanges: 377 logger.Debugf("storage attachment change %v", change) 378 if err := w.storageAttachmentChanged(change); err != nil { 379 return err 380 } 381 382 case change := <-w.relationUnitsChanges: 383 logger.Debugf("got a relation units change: %v", change) 384 if err := w.relationUnitsChanged(change); err != nil { 385 return err 386 } 387 388 case <-w.updateStatusChannel(): 389 logger.Debugf("update status timer triggered") 390 if err := w.updateStatusChanged(); err != nil { 391 return err 392 } 393 } 394 395 // Something changed. 396 fire() 397 } 398 } 399 400 // updateStatusChanged is called when the update status timer expires. 401 func (w *RemoteStateWatcher) updateStatusChanged() error { 402 w.mu.Lock() 403 w.current.UpdateStatusVersion++ 404 w.mu.Unlock() 405 return nil 406 } 407 408 // unitChanged responds to changes in the unit. 409 func (w *RemoteStateWatcher) unitChanged() error { 410 if err := w.unit.Refresh(); err != nil { 411 return err 412 } 413 resolved, err := w.unit.Resolved() 414 if err != nil { 415 return err 416 } 417 w.mu.Lock() 418 defer w.mu.Unlock() 419 w.current.Life = w.unit.Life() 420 w.current.ResolvedMode = resolved 421 return nil 422 } 423 424 // serviceChanged responds to changes in the service. 425 func (w *RemoteStateWatcher) serviceChanged() error { 426 if err := w.service.Refresh(); err != nil { 427 return err 428 } 429 url, force, err := w.service.CharmURL() 430 if err != nil { 431 return err 432 } 433 w.mu.Lock() 434 w.current.CharmURL = url 435 w.current.ForceCharmUpgrade = force 436 w.mu.Unlock() 437 return nil 438 } 439 440 func (w *RemoteStateWatcher) configChanged() error { 441 w.mu.Lock() 442 w.current.ConfigVersion++ 443 w.mu.Unlock() 444 return nil 445 } 446 447 func (w *RemoteStateWatcher) addressesChanged() error { 448 w.mu.Lock() 449 w.current.ConfigVersion++ 450 w.mu.Unlock() 451 return nil 452 } 453 454 func (w *RemoteStateWatcher) leaderSettingsChanged() error { 455 w.mu.Lock() 456 w.current.LeaderSettingsVersion++ 457 w.mu.Unlock() 458 return nil 459 } 460 461 func (w *RemoteStateWatcher) leadershipChanged(isLeader bool) error { 462 w.mu.Lock() 463 w.current.Leader = isLeader 464 w.mu.Unlock() 465 return nil 466 } 467 468 // relationsChanged responds to service relation changes. 469 func (w *RemoteStateWatcher) relationsChanged(keys []string) error { 470 w.mu.Lock() 471 defer w.mu.Unlock() 472 for _, key := range keys { 473 relationTag := names.NewRelationTag(key) 474 rel, err := w.st.Relation(relationTag) 475 if params.IsCodeNotFoundOrCodeUnauthorized(err) { 476 // If it's actually gone, this unit cannot have entered 477 // scope, and therefore never needs to know about it. 478 if ruw, ok := w.relations[relationTag]; ok { 479 if err := ruw.Stop(); err != nil { 480 return errors.Trace(err) 481 } 482 delete(w.relations, relationTag) 483 delete(w.current.Relations, ruw.relationId) 484 } 485 } else if err != nil { 486 return err 487 } else { 488 if _, ok := w.relations[relationTag]; ok { 489 relationSnapshot := w.current.Relations[rel.Id()] 490 relationSnapshot.Life = rel.Life() 491 w.current.Relations[rel.Id()] = relationSnapshot 492 continue 493 } 494 in, err := w.st.WatchRelationUnits(relationTag, w.unit.Tag()) 495 if err != nil { 496 return errors.Trace(err) 497 } 498 if err := w.watchRelationUnits(rel, relationTag, in); err != nil { 499 watcher.Stop(in, &w.tomb) 500 return errors.Trace(err) 501 } 502 } 503 } 504 return nil 505 } 506 507 // watchRelationUnits starts watching the relation units for the given 508 // relation, waits for its first event, and records the information in 509 // the current snapshot. 510 func (w *RemoteStateWatcher) watchRelationUnits( 511 rel Relation, relationTag names.RelationTag, in apiwatcher.RelationUnitsWatcher, 512 ) error { 513 relationSnapshot := RelationSnapshot{ 514 Life: rel.Life(), 515 Members: make(map[string]int64), 516 } 517 select { 518 case <-w.tomb.Dying(): 519 return tomb.ErrDying 520 case change, ok := <-in.Changes(): 521 if !ok { 522 return watcher.EnsureErr(in) 523 } 524 for unit, settings := range change.Changed { 525 relationSnapshot.Members[unit] = settings.Version 526 } 527 } 528 w.current.Relations[rel.Id()] = relationSnapshot 529 w.relations[relationTag] = newRelationUnitsWatcher( 530 rel.Id(), in, w.relationUnitsChanges, 531 ) 532 return nil 533 } 534 535 // relationUnitsChanged responds to relation units changes. 536 func (w *RemoteStateWatcher) relationUnitsChanged(change relationUnitsChange) error { 537 w.mu.Lock() 538 defer w.mu.Unlock() 539 snapshot, ok := w.current.Relations[change.relationId] 540 if !ok { 541 return nil 542 } 543 for unit, settings := range change.Changed { 544 snapshot.Members[unit] = settings.Version 545 } 546 for _, unit := range change.Departed { 547 delete(snapshot.Members, unit) 548 } 549 return nil 550 } 551 552 // storageAttachmentChanged responds to storage attachment changes. 553 func (w *RemoteStateWatcher) storageAttachmentChanged(change storageAttachmentChange) error { 554 w.mu.Lock() 555 w.current.Storage[change.Tag] = change.Snapshot 556 w.mu.Unlock() 557 return nil 558 } 559 560 func (w *RemoteStateWatcher) actionsChanged(actions []string) error { 561 w.mu.Lock() 562 defer w.mu.Unlock() 563 w.current.Actions = append(w.current.Actions, actions...) 564 return nil 565 } 566 567 // storageChanged responds to unit storage changes. 568 func (w *RemoteStateWatcher) storageChanged(keys []string) error { 569 tags := make([]names.StorageTag, len(keys)) 570 for i, key := range keys { 571 tags[i] = names.NewStorageTag(key) 572 } 573 ids := make([]params.StorageAttachmentId, len(keys)) 574 for i, tag := range tags { 575 ids[i] = params.StorageAttachmentId{ 576 StorageTag: tag.String(), 577 UnitTag: w.unit.Tag().String(), 578 } 579 } 580 results, err := w.st.StorageAttachmentLife(ids) 581 if err != nil { 582 return errors.Trace(err) 583 } 584 585 w.mu.Lock() 586 defer w.mu.Unlock() 587 588 for i, result := range results { 589 tag := tags[i] 590 if result.Error == nil { 591 if storageSnapshot, ok := w.current.Storage[tag]; ok { 592 // We've previously started a watcher for this storage 593 // attachment, so all we needed to do was update the 594 // lifecycle state. 595 storageSnapshot.Life = result.Life 596 w.current.Storage[tag] = storageSnapshot 597 continue 598 } 599 // We haven't seen this storage attachment before, so start 600 // a watcher now and wait for the initial event. 601 in, err := w.st.WatchStorageAttachment(tag, w.unit.Tag()) 602 if err != nil { 603 return errors.Annotate(err, "watching storage attachment") 604 } 605 if err := w.watchStorageAttachment(tag, result.Life, in); err != nil { 606 watcher.Stop(in, &w.tomb) 607 return errors.Trace(err) 608 } 609 } else if params.IsCodeNotFound(result.Error) { 610 if watcher, ok := w.storageAttachmentWatchers[tag]; ok { 611 if err := watcher.Stop(); err != nil { 612 return errors.Annotatef( 613 err, "stopping watcher of %s attachment", 614 names.ReadableString(tag), 615 ) 616 } 617 delete(w.storageAttachmentWatchers, tag) 618 } 619 delete(w.current.Storage, tag) 620 } else { 621 return errors.Annotatef( 622 result.Error, "getting life of %s attachment", 623 names.ReadableString(tag), 624 ) 625 } 626 } 627 return nil 628 } 629 630 // watchStorageAttachment starts watching the storage attachment with 631 // the specified storage tag, waits for its first event, and records 632 // the information in the current snapshot. 633 func (w *RemoteStateWatcher) watchStorageAttachment( 634 tag names.StorageTag, 635 life params.Life, 636 in apiwatcher.NotifyWatcher, 637 ) error { 638 var storageSnapshot StorageSnapshot 639 select { 640 case <-w.tomb.Dying(): 641 return tomb.ErrDying 642 case _, ok := <-in.Changes(): 643 if !ok { 644 return watcher.EnsureErr(in) 645 } 646 var err error 647 storageSnapshot, err = getStorageSnapshot(w.st, tag, w.unit.Tag()) 648 if params.IsCodeNotProvisioned(err) { 649 // If the storage is unprovisioned, we still want to 650 // record the attachment, but we'll mark it as 651 // unattached. This allows the uniter to wait for 652 // pending storage attachments to be provisioned. 653 storageSnapshot = StorageSnapshot{Life: life} 654 } else if err != nil { 655 return errors.Annotatef(err, "processing initial storage attachment change") 656 } 657 } 658 w.current.Storage[tag] = storageSnapshot 659 w.storageAttachmentWatchers[tag] = newStorageAttachmentWatcher( 660 w.st, in, w.unit.Tag(), tag, w.storageAttachmentChanges, 661 ) 662 return nil 663 }