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  }