github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/worker/storageprovisioner/machines.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package storageprovisioner 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/names" 9 "launchpad.net/tomb" 10 11 "github.com/juju/juju/apiserver/params" 12 "github.com/juju/juju/instance" 13 "github.com/juju/juju/state/watcher" 14 ) 15 16 // watchMachine starts a machine watcher if there is not already one for the 17 // specified tag. The watcher will notify the worker when the machine changes, 18 // for example when it is provisioned. 19 func watchMachine(ctx *context, tag names.MachineTag) { 20 _, ok := ctx.machines[tag] 21 if ok { 22 return 23 } 24 w := newMachineWatcher(ctx.machineAccessor, tag, ctx.machineChanges) 25 ctx.machines[tag] = w 26 } 27 28 // refreshMachine refreshes the specified machine's instance ID. If it is set, 29 // then the machine watcher is stopped and pending entities' parameters are 30 // updated. If the machine is not provisioned yet, this method is a no-op. 31 func refreshMachine(ctx *context, tag names.MachineTag) error { 32 w, ok := ctx.machines[tag] 33 if !ok { 34 return errors.Errorf("machine %s is not being watched", tag.Id()) 35 } 36 stopAndRemove := func() error { 37 if err := w.stop(); err != nil { 38 return errors.Annotate(err, "stopping machine watcher") 39 } 40 delete(ctx.machines, tag) 41 return nil 42 } 43 results, err := ctx.machineAccessor.InstanceIds([]names.MachineTag{tag}) 44 if err != nil { 45 return errors.Annotate(err, "getting machine instance ID") 46 } 47 if err := results[0].Error; err != nil { 48 if params.IsCodeNotProvisioned(err) { 49 return nil 50 } else if params.IsCodeNotFound(err) { 51 // Machine is gone, so stop watching. 52 return stopAndRemove() 53 } 54 return errors.Annotate(err, "getting machine instance ID") 55 } 56 machineProvisioned(ctx, tag, instance.Id(results[0].Result)) 57 // machine provisioning is the only thing we care about; 58 // stop the watcher. 59 return stopAndRemove() 60 } 61 62 // machineProvisioned is called when a watched machine is provisioned. 63 func machineProvisioned(ctx *context, tag names.MachineTag, instanceId instance.Id) { 64 for _, params := range ctx.incompleteVolumeParams { 65 if params.Attachment.Machine != tag || params.Attachment.InstanceId != "" { 66 continue 67 } 68 params.Attachment.InstanceId = instanceId 69 updatePendingVolume(ctx, params) 70 } 71 for id, params := range ctx.incompleteVolumeAttachmentParams { 72 if params.Machine != tag || params.InstanceId != "" { 73 continue 74 } 75 params.InstanceId = instanceId 76 updatePendingVolumeAttachment(ctx, id, params) 77 } 78 for id, params := range ctx.pendingFilesystemAttachments { 79 if params.Machine != tag || params.InstanceId != "" { 80 continue 81 } 82 params.InstanceId = instanceId 83 ctx.pendingFilesystemAttachments[id] = params 84 } 85 } 86 87 type machineWatcher struct { 88 tomb tomb.Tomb 89 accessor MachineAccessor 90 tag names.MachineTag 91 instanceId instance.Id 92 out chan<- names.MachineTag 93 } 94 95 func newMachineWatcher( 96 accessor MachineAccessor, 97 tag names.MachineTag, 98 out chan<- names.MachineTag, 99 ) *machineWatcher { 100 w := &machineWatcher{ 101 accessor: accessor, 102 tag: tag, 103 out: out, 104 } 105 go func() { 106 defer w.tomb.Done() 107 w.tomb.Kill(w.loop()) 108 }() 109 return w 110 } 111 112 func (mw *machineWatcher) stop() error { 113 mw.tomb.Kill(nil) 114 return mw.tomb.Wait() 115 } 116 117 func (mw *machineWatcher) loop() error { 118 w, err := mw.accessor.WatchMachine(mw.tag) 119 if err != nil { 120 return errors.Annotate(err, "watching machine") 121 } 122 logger.Debugf("watching machine %s", mw.tag.Id()) 123 defer logger.Debugf("finished watching machine %s", mw.tag.Id()) 124 var out chan<- names.MachineTag 125 for { 126 select { 127 case <-mw.tomb.Dying(): 128 return tomb.ErrDying 129 case _, ok := <-w.Changes(): 130 if !ok { 131 return watcher.EnsureErr(w) 132 } 133 out = mw.out 134 case out <- mw.tag: 135 out = nil 136 } 137 } 138 }