github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/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.pendingVolumes {
    65  		if params.Attachment.Machine != tag || params.Attachment.InstanceId != "" {
    66  			continue
    67  		}
    68  		params.Attachment.InstanceId = instanceId
    69  	}
    70  	for id, params := range ctx.pendingVolumeAttachments {
    71  		if params.Machine != tag || params.InstanceId != "" {
    72  			continue
    73  		}
    74  		params.InstanceId = instanceId
    75  		ctx.pendingVolumeAttachments[id] = params
    76  	}
    77  	for id, params := range ctx.pendingFilesystemAttachments {
    78  		if params.Machine != tag || params.InstanceId != "" {
    79  			continue
    80  		}
    81  		params.InstanceId = instanceId
    82  		ctx.pendingFilesystemAttachments[id] = params
    83  	}
    84  }
    85  
    86  type machineWatcher struct {
    87  	tomb       tomb.Tomb
    88  	accessor   MachineAccessor
    89  	tag        names.MachineTag
    90  	instanceId instance.Id
    91  	out        chan<- names.MachineTag
    92  }
    93  
    94  func newMachineWatcher(
    95  	accessor MachineAccessor,
    96  	tag names.MachineTag,
    97  	out chan<- names.MachineTag,
    98  ) *machineWatcher {
    99  	w := &machineWatcher{
   100  		accessor: accessor,
   101  		tag:      tag,
   102  		out:      out,
   103  	}
   104  	go func() {
   105  		defer w.tomb.Done()
   106  		w.tomb.Kill(w.loop())
   107  	}()
   108  	return w
   109  }
   110  
   111  func (mw *machineWatcher) stop() error {
   112  	mw.tomb.Kill(nil)
   113  	return mw.tomb.Wait()
   114  }
   115  
   116  func (mw *machineWatcher) loop() error {
   117  	w, err := mw.accessor.WatchMachine(mw.tag)
   118  	if err != nil {
   119  		return errors.Annotate(err, "watching machine")
   120  	}
   121  	logger.Debugf("watching machine %s", mw.tag.Id())
   122  	defer logger.Debugf("finished watching machine %s", mw.tag.Id())
   123  	var out chan<- names.MachineTag
   124  	for {
   125  		select {
   126  		case <-mw.tomb.Dying():
   127  			return tomb.ErrDying
   128  		case _, ok := <-w.Changes():
   129  			if !ok {
   130  				return watcher.EnsureErr(w)
   131  			}
   132  			out = mw.out
   133  		case out <- mw.tag:
   134  			out = nil
   135  		}
   136  	}
   137  }