// WaitForEnviron waits for an valid environment to arrive from the given // watcher. It terminates with ErrWaitAborted if it receives a value on abort. // // In practice, it shouldn't wait at all: juju *should* never deliver invalid // environ configs. Regardless, it should be considered deprecated; clients // should prefer to access an Environ via a shared Tracker. // // It never takes responsibility for the supplied watcher; the client remains // responsible for detecting and handling any watcher errors that may occur, // whether this func succeeds or fails. func WaitForEnviron( // TODO(wallyworld) - pass in credential watcher w watcher.NotifyWatcher, getter environs.EnvironConfigGetter, newEnviron environs.NewEnvironFunc, abort <-chan struct{}, ) (environs.Environ, error) { for { select { case <-abort: return nil, ErrWaitAborted case _, ok := <-w.Changes(): if !ok { return nil, errors.New("environ config watch closed") } // First check the model config is valid as we want to exit with // an error if we have received a config but it is not valid. // This distinguishes from the case where environ construction fails // because no config has been received yet. if _, err := getter.ModelConfig(); err != nil { return nil, errors.Annotate(err, "cannot read environ config") } environ, err := environs.GetEnviron(getter, newEnviron) if err == nil { return environ, nil } logger.Errorf("loaded invalid environment configuration: %v", err) } } }
// watchStorageAttachment starts watching the storage attachment with // the specified storage tag, waits for its first event, and records // the information in the current snapshot. func (w *RemoteStateWatcher) watchStorageAttachment( tag names.StorageTag, life params.Life, saw watcher.NotifyWatcher, ) error { var storageSnapshot StorageSnapshot select { case <-w.catacomb.Dying(): return w.catacomb.ErrDying() case _, ok := <-saw.Changes(): if !ok { return errors.New("storage attachment watcher closed") } var err error storageSnapshot, err = getStorageSnapshot(w.st, tag, w.unit.Tag()) if params.IsCodeNotProvisioned(err) { // If the storage is unprovisioned, we still want to // record the attachment, but we'll mark it as // unattached. This allows the uniter to wait for // pending storage attachments to be provisioned. storageSnapshot = StorageSnapshot{Life: life} } else if err != nil { return errors.Annotatef(err, "processing initial storage attachment change") } } innerSAW, err := newStorageAttachmentWatcher( w.st, saw, w.unit.Tag(), tag, w.storageAttachmentChanges, ) if err != nil { return errors.Trace(err) } w.current.Storage[tag] = storageSnapshot w.storageAttachmentWatchers[tag] = innerSAW return nil }
// WaitForEnviron waits for an valid environment to arrive from the given // watcher. It terminates with ErrWaitAborted if it receives a value on abort. // // In practice, it shouldn't wait at all: juju *should* never deliver invalid // environ configs. Regardless, it should be considered deprecated; clients // should prefer to access an Environ via a shared Tracker. // // It never takes responsibility for the supplied watcher; the client remains // responsible for detecting and handling any watcher errors that may occur, // whether this func succeeds or fails. func WaitForEnviron( w watcher.NotifyWatcher, getter ConfigGetter, newEnviron NewEnvironFunc, abort <-chan struct{}, ) (environs.Environ, error) { for { select { case <-abort: return nil, ErrWaitAborted case _, ok := <-w.Changes(): if !ok { return nil, errors.New("environ config watch closed") } config, err := getter.ModelConfig() if err != nil { return nil, errors.Annotate(err, "cannot read environ config") } environ, err := newEnviron(config) if err == nil { return environ, nil } logger.Errorf("loaded invalid environment configuration: %v", err) } } }
func NewProvisionerTask( controllerUUID string, machineTag names.MachineTag, harvestMode config.HarvestMode, machineGetter MachineGetter, toolsFinder ToolsFinder, machineWatcher watcher.StringsWatcher, retryWatcher watcher.NotifyWatcher, broker environs.InstanceBroker, auth authentication.AuthenticationProvider, imageStream string, retryStartInstanceStrategy RetryStrategy, ) (ProvisionerTask, error) { machineChanges := machineWatcher.Changes() workers := []worker.Worker{machineWatcher} var retryChanges watcher.NotifyChannel if retryWatcher != nil { retryChanges = retryWatcher.Changes() workers = append(workers, retryWatcher) } task := &provisionerTask{ controllerUUID: controllerUUID, machineTag: machineTag, machineGetter: machineGetter, toolsFinder: toolsFinder, machineChanges: machineChanges, retryChanges: retryChanges, broker: broker, auth: auth, harvestMode: harvestMode, harvestModeChan: make(chan config.HarvestMode, 1), machines: make(map[string]*apiprovisioner.Machine), imageStream: imageStream, retryStartInstanceStrategy: retryStartInstanceStrategy, } err := catacomb.Invoke(catacomb.Plan{ Site: &task.catacomb, Work: task.loop, Init: workers, }) if err != nil { return nil, errors.Trace(err) } return task, nil }
// newStorageAttachmentsWatcher creates a new worker that wakes on input from // the supplied watcher's Changes chan, finds out more about them, and delivers // them on the supplied out chan. // // The caller releases responsibility for stopping the supplied watcher and // waiting for errors, *whether or not this method succeeds*. func newStorageAttachmentWatcher( st StorageAccessor, watcher watcher.NotifyWatcher, unitTag names.UnitTag, storageTag names.StorageTag, out chan<- storageAttachmentChange, ) (*storageAttachmentWatcher, error) { s := &storageAttachmentWatcher{ st: st, changes: watcher.Changes(), out: out, storageTag: storageTag, unitTag: unitTag, } err := catacomb.Invoke(catacomb.Plan{ Site: &s.catacomb, Work: s.loop, Init: []worker.Worker{watcher}, }) if err != nil { return nil, errors.Trace(err) } return s, nil }