// watchMachinesLoop watches for changes provided by the given // machinesWatcher and starts machine goroutines to deal with them, // using the provided newMachineContext function to create the // appropriate context for each new machine tag. func watchMachinesLoop(context updaterContext, machinesWatcher watcher.StringsWatcher) (err error) { p := &updater{ context: context, machines: make(map[names.MachineTag]chan struct{}), machineDead: make(chan machine), } defer func() { // TODO(fwereade): is this a home-grown sync.WaitGroup or something? // strongly suspect these machine goroutines could be managed rather // less opaquely if we made them all workers. for len(p.machines) > 0 { delete(p.machines, (<-p.machineDead).Tag()) } }() for { select { case <-p.context.dying(): return p.context.errDying() case ids, ok := <-machinesWatcher.Changes(): if !ok { return errors.New("machines watcher closed") } tags := make([]names.MachineTag, len(ids)) for i := range ids { tags[i] = names.NewMachineTag(ids[i]) } if err := p.startMachines(tags); err != nil { return err } case m := <-p.machineDead: delete(p.machines, m.Tag()) } } }
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 }
// watchLoop watches the machine for units added or removed. func (md *machineData) watchLoop(unitw watcher.StringsWatcher) error { if err := md.catacomb.Add(unitw); err != nil { return errors.Trace(err) } for { select { case <-md.catacomb.Dying(): return md.catacomb.ErrDying() case change, ok := <-unitw.Changes(): if !ok { return errors.New("machine units watcher closed") } select { case md.fw.unitsChange <- &unitsChange{md, change}: case <-md.catacomb.Dying(): return md.catacomb.ErrDying() } } } }