github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/controllerport/worker.go (about) 1 // Copyright 2018 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package controllerport 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/pubsub" 9 "gopkg.in/juju/worker.v1" 10 "gopkg.in/juju/worker.v1/dependency" 11 "gopkg.in/tomb.v2" 12 13 "github.com/juju/juju/agent" 14 "github.com/juju/juju/pubsub/controller" 15 ) 16 17 // Config is the configuration required for running an API server worker. 18 type Config struct { 19 AgentConfig agent.Config 20 Hub *pubsub.StructuredHub 21 Logger Logger 22 ControllerAPIPort int 23 UpdateControllerAPIPort func(int) error 24 } 25 26 // Validate validates the API server configuration. 27 func (config Config) Validate() error { 28 if config.AgentConfig == nil { 29 return errors.NotValidf("nil AgentConfig") 30 } 31 if config.Hub == nil { 32 return errors.NotValidf("nil Hub") 33 } 34 if config.Logger == nil { 35 return errors.NotValidf("nil Logger") 36 } 37 if config.UpdateControllerAPIPort == nil { 38 return errors.NotValidf("nil UpdateControllerAPIPort") 39 } 40 return nil 41 } 42 43 // NewWorker returns a new API server worker, with the given configuration. 44 func NewWorker(config Config) (worker.Worker, error) { 45 if err := config.Validate(); err != nil { 46 return nil, errors.Trace(err) 47 } 48 49 w := &Worker{ 50 logger: config.Logger, 51 update: config.UpdateControllerAPIPort, 52 } 53 54 servingInfo, ok := config.AgentConfig.StateServingInfo() 55 if !ok { 56 return nil, errors.New("missing state serving info") 57 } 58 w.controllerAPIPort = servingInfo.ControllerAPIPort 59 // We need to make sure that update the agent config with 60 // the potentially new controller api port from the database 61 // before we start any other workers that need to connect 62 // to the controller over the controller port. 63 w.updateControllerPort(config.ControllerAPIPort) 64 65 unsub, err := config.Hub.Subscribe(controller.ConfigChanged, 66 func(topic string, data controller.ConfigChangedMessage, err error) { 67 if w.updateControllerPort(data.Config.ControllerAPIPort()) { 68 w.tomb.Kill(dependency.ErrBounce) 69 } 70 }) 71 if err != nil { 72 return nil, errors.Annotate(err, "unable to subscribe to details topic") 73 } 74 75 w.tomb.Go(func() error { 76 defer unsub() 77 <-w.tomb.Dying() 78 return nil 79 }) 80 return w, nil 81 } 82 83 // Worker is responsible for updating the agent config when the controller api 84 // port value changes, and then bouncing the worker to notify the other 85 // dependent workers, which should be the peer-grouper and http-server. 86 type Worker struct { 87 tomb tomb.Tomb 88 logger Logger 89 update func(int) error 90 91 controllerAPIPort int 92 } 93 94 // Kill implements Worker.Kill. 95 func (w *Worker) Kill() { 96 w.tomb.Kill(nil) 97 } 98 99 // Wait implements Worker.Wait. 100 func (w *Worker) Wait() error { 101 return w.tomb.Wait() 102 } 103 104 func (w *Worker) updateControllerPort(port int) bool { 105 if w.controllerAPIPort == port { 106 return false 107 } 108 // The local cache is out of date, update it. 109 w.logger.Infof("updating controller API port to %v", port) 110 err := w.update(port) 111 if err != nil { 112 w.logger.Errorf("unable to update agent.conf with new controller API port: %v", err) 113 } 114 w.controllerAPIPort = port 115 return true 116 }