1
// Copyright 2016 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
4
package apiconfigwatcher
9
"github.com/juju/errors"
10
"github.com/juju/loggo"
11
"github.com/juju/utils/voyeur"
14
"github.com/juju/juju/agent"
15
"github.com/juju/juju/worker"
16
"github.com/juju/juju/worker/dependency"
19
var logger = loggo.GetLogger("juju.worker.apiconfigwatcher")
21
type ManifoldConfig struct {
23
AgentConfigChanged *voyeur.Value
26
// Manifold returns a dependency.Manifold which wraps an agent's
27
// voyeur.Value which is set whenever the agent config is
28
// changed. When the API server addresses in the config change the
29
// manifold will bounce itself.
31
// The manifold is intended to be a dependency for the api-caller
32
// manifold and is required to support model migrations.
33
func Manifold(config ManifoldConfig) dependency.Manifold {
34
return dependency.Manifold{
35
Inputs: []string{config.AgentName},
36
Start: func(context dependency.Context) (worker.Worker, error) {
37
if config.AgentConfigChanged == nil {
38
return nil, errors.NotValidf("nil AgentConfigChanged")
42
if err := context.Get(config.AgentName, &a); err != nil {
46
w := &apiconfigwatcher{
48
agentConfigChanged: config.AgentConfigChanged,
49
addrs: getAPIAddresses(a),
60
type apiconfigwatcher struct {
63
agentConfigChanged *voyeur.Value
67
func (w *apiconfigwatcher) loop() error {
68
watch := w.agentConfigChanged.Watch()
71
// TODO(mjs) - this is pretty awful. There should be a
72
// NotifyWatcher for voyeur.Value. Note also that this code is
73
// repeated elsewhere.
74
watchCh := make(chan bool)
79
case <-w.tomb.Dying():
84
// watcher or voyeur.Value closed.
92
// Always unconditionally check for a change in API addresses
93
// first, in case there was a change between the start func
94
// and the call to Watch.
95
if !stringSliceEq(w.addrs, getAPIAddresses(w.agent)) {
96
logger.Debugf("API addresses changed in agent config")
97
return dependency.ErrBounce
101
case <-w.tomb.Dying():
103
case _, ok := <-watchCh:
105
return errors.New("config changed value closed")
111
// Kill implements worker.Worker.
112
func (w *apiconfigwatcher) Kill() {
116
// Wait implements worker.Worker.
117
func (w *apiconfigwatcher) Wait() error {
121
func getAPIAddresses(a agent.Agent) []string {
122
config := a.CurrentConfig()
123
addrs, err := config.APIAddresses()
125
logger.Errorf("retrieving API addresses: %s", err)
132
func stringSliceEq(a, b []string) bool {
133
if a == nil && b == nil {
137
if a == nil || b == nil {
141
if len(a) != len(b) {