func (u *UndertakerAPI) environResourceWatcher() params.NotifyWatchResult { var nothing params.NotifyWatchResult machines, err := u.st.AllMachines() if err != nil { nothing.Error = common.ServerError(err) return nothing } services, err := u.st.AllServices() if err != nil { nothing.Error = common.ServerError(err) return nothing } var watchers []state.NotifyWatcher for _, machine := range machines { watchers = append(watchers, machine.Watch()) } for _, service := range services { watchers = append(watchers, service.Watch()) } watch := common.NewMultiNotifyWatcher(watchers...) if _, ok := <-watch.Changes(); ok { return params.NotifyWatchResult{ NotifyWatcherId: u.resources.Register(watch), } } nothing.Error = common.ServerError(watcher.EnsureErr(watch)) return nothing }
// WatchStorageAttachment returns a state.NotifyWatcher that reacts to changes // to the VolumeAttachmentInfo or FilesystemAttachmentInfo corresponding to the tags // specified. func WatchStorageAttachment( st StorageInterface, storageTag names.StorageTag, machineTag names.MachineTag, unitTag names.UnitTag, ) (state.NotifyWatcher, error) { storageInstance, err := st.StorageInstance(storageTag) if err != nil { return nil, errors.Annotate(err, "getting storage instance") } var w state.NotifyWatcher switch storageInstance.Kind() { case state.StorageKindBlock: volume, err := st.StorageInstanceVolume(storageTag) if err != nil { return nil, errors.Annotate(err, "getting storage volume") } w = st.WatchVolumeAttachment(machineTag, volume.VolumeTag()) case state.StorageKindFilesystem: filesystem, err := st.StorageInstanceFilesystem(storageTag) if err != nil { return nil, errors.Annotate(err, "getting storage filesystem") } w = st.WatchFilesystemAttachment(machineTag, filesystem.FilesystemTag()) default: return nil, errors.Errorf("invalid storage kind %v", storageInstance.Kind()) } w2 := st.WatchStorageAttachment(storageTag, unitTag) return common.NewMultiNotifyWatcher(w, w2), nil }
func (*multiNotifyWatcherSuite) TestMultiNotifyWatcherStop(c *gc.C) { w0 := apiservertesting.NewFakeNotifyWatcher() w1 := apiservertesting.NewFakeNotifyWatcher() mw := common.NewMultiNotifyWatcher(w0, w1) wc := statetesting.NewNotifyWatcherC(c, nopSyncStarter{}, mw) wc.AssertOneChange() statetesting.AssertCanStopWhenSending(c, mw) wc.AssertClosed() }
func (*multiNotifyWatcherSuite) TestMultiNotifyWatcherStop(c *gc.C) { w0 := &fakeNotifyWatcher{changes: make(chan struct{}, 1)} w1 := &fakeNotifyWatcher{changes: make(chan struct{}, 1)} w0.changes <- struct{}{} w1.changes <- struct{}{} mw := common.NewMultiNotifyWatcher(w0, w1) wc := statetesting.NewNotifyWatcherC(c, nopSyncStarter{}, mw) wc.AssertOneChange() statetesting.AssertCanStopWhenSending(c, mw) wc.AssertClosed() }
func (api *ProxyUpdaterAPI) oneWatch() params.NotifyWatchResult { var result params.NotifyWatchResult watch := common.NewMultiNotifyWatcher( api.backend.WatchForModelConfigChanges(), api.backend.WatchAPIHostPorts()) if _, ok := <-watch.Changes(); ok { result = params.NotifyWatchResult{ NotifyWatcherId: api.resources.Register(watch), } } result.Error = common.ServerError(watcher.EnsureErr(watch)) return result }
// WatchStorageAttachment returns a state.NotifyWatcher that reacts to changes // to the VolumeAttachmentInfo or FilesystemAttachmentInfo corresponding to the // tags specified. func WatchStorageAttachment( st StorageInterface, storageTag names.StorageTag, machineTag names.MachineTag, unitTag names.UnitTag, ) (state.NotifyWatcher, error) { storageInstance, err := st.StorageInstance(storageTag) if err != nil { return nil, errors.Annotate(err, "getting storage instance") } var watchers []state.NotifyWatcher switch storageInstance.Kind() { case state.StorageKindBlock: volume, err := st.StorageInstanceVolume(storageTag) if err != nil { return nil, errors.Annotate(err, "getting storage volume") } // We need to watch both the volume attachment, and the // machine's block devices. A volume attachment's block // device could change (most likely, become present). watchers = []state.NotifyWatcher{ st.WatchVolumeAttachment(machineTag, volume.VolumeTag()), // TODO(axw) 2015-09-30 #1501203 // We should filter the events to only those relevant // to the volume attachment. This means we would need // to either start th block device watcher after we // have provisioned the volume attachment (cleaner?), // or have the filter ignore changes until the volume // attachment is provisioned. st.WatchBlockDevices(machineTag), } case state.StorageKindFilesystem: filesystem, err := st.StorageInstanceFilesystem(storageTag) if err != nil { return nil, errors.Annotate(err, "getting storage filesystem") } watchers = []state.NotifyWatcher{ st.WatchFilesystemAttachment(machineTag, filesystem.FilesystemTag()), } default: return nil, errors.Errorf("invalid storage kind %v", storageInstance.Kind()) } watchers = append(watchers, st.WatchStorageAttachment(storageTag, unitTag)) return common.NewMultiNotifyWatcher(watchers...), nil }
func (*multiNotifyWatcherSuite) TestMultiNotifyWatcher(c *gc.C) { w0 := apiservertesting.NewFakeNotifyWatcher() w1 := apiservertesting.NewFakeNotifyWatcher() mw := common.NewMultiNotifyWatcher(w0, w1) defer statetesting.AssertStop(c, mw) wc := statetesting.NewNotifyWatcherC(c, nopSyncStarter{}, mw) wc.AssertOneChange() w0.C <- struct{}{} wc.AssertOneChange() w1.C <- struct{}{} wc.AssertOneChange() w0.C <- struct{}{} w1.C <- struct{}{} wc.AssertOneChange() }