// Watching determines if the given dependency is being watched. func (w *Watcher) Watching(d dep.Dependency) bool { w.Lock() defer w.Unlock() _, ok := w.depViewMap[d.String()] return ok }
// Forget accepts a dependency and removes all associated data with this // dependency. It also resets the "receivedData" internal map. func (b *Brain) Forget(d dep.Dependency) { b.Lock() defer b.Unlock() delete(b.data, d.String()) delete(b.receivedData, d.String()) }
// Remember accepts a dependency and the data to store associated with that // dep. This function converts the given data to a proper type and stores // it interally. func (b *Brain) Remember(d dep.Dependency, data interface{}) { b.Lock() defer b.Unlock() b.data[d.String()] = data b.receivedData[d.String()] = struct{}{} }
// ForceWatching is used to force setting the internal state of watching // a depedency. This is only used for unit testing purposes. func (w *Watcher) ForceWatching(d dep.Dependency, enabled bool) { w.Lock() defer w.Unlock() if enabled { w.depViewMap[d.String()] = nil } else { delete(w.depViewMap, d.String()) } }
// Recall gets the current value for the given dependency in the Brain. func (b *Brain) Recall(d dep.Dependency) (interface{}, bool) { b.RLock() defer b.RUnlock() // If we have not received data for this dependency, return now. if _, ok := b.receivedData[d.String()]; !ok { return nil, false } return b.data[d.String()], true }
// Remove removes the given dependency from the list and stops the // associated View. If a View for the given dependency does not exist, this // function will return false. If the View does exist, this function will return // true upon successful deletion. func (w *Watcher) Remove(d dep.Dependency) bool { w.Lock() defer w.Unlock() log.Printf("[DEBUG] (watcher) removing %s", d) if view, ok := w.depViewMap[d.String()]; ok { log.Printf("[TRACE] (watcher) actually removing %s", d) view.stop() delete(w.depViewMap, d.String()) return true } log.Printf("[TRACE] (watcher) %s did not exist, skipping", d) return false }
// Add adds the given dependency to the list of monitored depedencies // and start the associated view. If the dependency already exists, no action is // taken. // // If the Dependency already existed, it this function will return false. If the // view was successfully created, it will return true. If an error occurs while // creating the view, it will be returned here (but future errors returned by // the view will happen on the channel). func (w *Watcher) Add(d dep.Dependency) (bool, error) { w.Lock() defer w.Unlock() log.Printf("[DEBUG] (watcher) adding %s", d) if _, ok := w.depViewMap[d.String()]; ok { log.Printf("[TRACE] (watcher) %s already exists, skipping", d) return false, nil } // Choose the correct retry function based off of the dependency's type. var retryFunc RetryFunc switch d.Type() { case dep.TypeConsul: retryFunc = w.retryFuncConsul case dep.TypeVault: retryFunc = w.retryFuncVault default: retryFunc = w.retryFuncDefault } v, err := NewView(&NewViewInput{ Dependency: d, Clients: w.clients, MaxStale: w.maxStale, Once: w.once, RetryFunc: retryFunc, }) if err != nil { return false, errors.Wrap(err, "watcher") } log.Printf("[TRACE] (watcher) %s starting", d) w.depViewMap[d.String()] = v go v.poll(w.dataCh, w.errCh) return true, nil }
// Receive accepts a Dependency and data for that dep. This data is // cached on the Runner. This data is then used to determine if a Template // is "renderable" (i.e. all its Dependencies have been downloaded at least // once). func (r *Runner) Receive(d dep.Dependency, data interface{}) { r.dependenciesLock.Lock() defer r.dependenciesLock.Unlock() // Just because we received data, it does not mean that we are actually // watching for that data. How is that possible you may ask? Well, this // Runner's data channel is pooled, meaning it accepts multiple data views // before actually blocking. Whilest this runner is performing a Run() and // executing diffs, it may be possible that more data was pushed onto the // data channel pool for a dependency that we no longer care about. // // Accepting this dependency would introduce stale data into the brain, and // that is simply unacceptable. In fact, it is a fun little bug: // // https://github.com/hashicorp/consul-template/issues/198 // // and by "little" bug, I mean really big bug. if _, ok := r.dependencies[d.String()]; ok { log.Printf("[DEBUG] (runner) receiving dependency %s", d) r.brain.Remember(d, data) } }