github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/apiaddressupdater/apiaddressupdater.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package apiaddressupdater
     5  
     6  import (
     7  	"fmt"
     8  	"sync"
     9  
    10  	"github.com/juju/errors"
    11  	"github.com/juju/loggo"
    12  	"gopkg.in/juju/worker.v1"
    13  
    14  	"github.com/juju/juju/core/watcher"
    15  	"github.com/juju/juju/network"
    16  )
    17  
    18  var logger = loggo.GetLogger("juju.worker.apiaddressupdater")
    19  
    20  // APIAddressUpdater is responsible for propagating API addresses.
    21  //
    22  // In practice, APIAddressUpdater is used by a machine agent to watch
    23  // API addresses in state and write the changes to the agent's config file.
    24  type APIAddressUpdater struct {
    25  	addresser APIAddresser
    26  	setter    APIAddressSetter
    27  
    28  	mu      sync.Mutex
    29  	current [][]network.HostPort
    30  }
    31  
    32  // APIAddresser is an interface that is provided to NewAPIAddressUpdater
    33  // which can be used to watch for API address changes.
    34  type APIAddresser interface {
    35  	APIHostPorts() ([][]network.HostPort, error)
    36  	WatchAPIHostPorts() (watcher.NotifyWatcher, error)
    37  }
    38  
    39  // APIAddressSetter is an interface that is provided to NewAPIAddressUpdater
    40  // whose SetAPIHostPorts method will be invoked whenever address changes occur.
    41  type APIAddressSetter interface {
    42  	SetAPIHostPorts(servers [][]network.HostPort) error
    43  }
    44  
    45  // NewAPIAddressUpdater returns a worker.Worker that watches for changes to
    46  // API addresses and then sets them on the APIAddressSetter.
    47  // TODO(fwereade): this should have a config struct, and some validation.
    48  func NewAPIAddressUpdater(addresser APIAddresser, setter APIAddressSetter) (worker.Worker, error) {
    49  	handler := &APIAddressUpdater{
    50  		addresser: addresser,
    51  		setter:    setter,
    52  	}
    53  	w, err := watcher.NewNotifyWorker(watcher.NotifyConfig{
    54  		Handler: handler,
    55  	})
    56  	if err != nil {
    57  		return nil, errors.Trace(err)
    58  	}
    59  	return w, nil
    60  }
    61  
    62  // SetUp is part of the watcher.NotifyHandler interface.
    63  func (c *APIAddressUpdater) SetUp() (watcher.NotifyWatcher, error) {
    64  	return c.addresser.WatchAPIHostPorts()
    65  }
    66  
    67  // Handle is part of the watcher.NotifyHandler interface.
    68  func (c *APIAddressUpdater) Handle(_ <-chan struct{}) error {
    69  	hpsToSet, err := c.getAddresses()
    70  	if err != nil {
    71  		return err
    72  	}
    73  	logger.Debugf("updating API hostPorts to %+v", hpsToSet)
    74  	c.mu.Lock()
    75  	c.current = hpsToSet
    76  	c.mu.Unlock()
    77  	if err := c.setter.SetAPIHostPorts(hpsToSet); err != nil {
    78  		return fmt.Errorf("error setting addresses: %v", err)
    79  	}
    80  	return nil
    81  }
    82  
    83  func (c *APIAddressUpdater) getAddresses() ([][]network.HostPort, error) {
    84  	addresses, err := c.addresser.APIHostPorts()
    85  	if err != nil {
    86  		return nil, fmt.Errorf("error getting addresses: %v", err)
    87  	}
    88  
    89  	// Filter out any LXC or LXD bridge addresses. See LP bug #1416928. and
    90  	// bug #1567683
    91  	hpsToSet := make([][]network.HostPort, 0, len(addresses))
    92  	for _, hostPorts := range addresses {
    93  		// Strip ports, filter, then add ports again.
    94  		filtered := network.FilterBridgeAddresses(network.HostsWithoutPort(hostPorts))
    95  		hps := make([]network.HostPort, 0, len(filtered))
    96  		for _, hostPort := range hostPorts {
    97  			for _, addr := range filtered {
    98  				if addr.Value == hostPort.Address.Value {
    99  					hps = append(hps, hostPort)
   100  				}
   101  			}
   102  		}
   103  		if len(hps) > 0 {
   104  			hpsToSet = append(hpsToSet, hps)
   105  		}
   106  	}
   107  	return hpsToSet, nil
   108  }
   109  
   110  // TearDown is part of the watcher.NotifyHandler interface.
   111  func (c *APIAddressUpdater) TearDown() error {
   112  	return nil
   113  }
   114  
   115  // Report shows up in the dependency engine report.
   116  func (c *APIAddressUpdater) Report() map[string]interface{} {
   117  	report := make(map[string]interface{})
   118  	c.mu.Lock()
   119  	defer c.mu.Unlock()
   120  	var servers [][]string
   121  	for _, server := range c.current {
   122  		var addresses []string
   123  		for _, addr := range server {
   124  			addresses = append(addresses, addr.String())
   125  		}
   126  		servers = append(servers, addresses)
   127  	}
   128  	report["servers"] = servers
   129  	return report
   130  }