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 }