github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/fanconfigurer/fanconfigurer.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package fanconfigurer 5 6 import ( 7 "fmt" 8 "os" 9 "sync" 10 "time" 11 12 "github.com/juju/clock" 13 "github.com/juju/errors" 14 "github.com/juju/loggo" 15 "gopkg.in/juju/worker.v1/catacomb" 16 17 "github.com/juju/juju/core/watcher" 18 "github.com/juju/juju/network" 19 "github.com/juju/juju/utils/scriptrunner" 20 ) 21 22 var logger = loggo.GetLogger("juju.worker.fanconfigurer") 23 24 type FanConfigurer struct { 25 catacomb catacomb.Catacomb 26 config FanConfigurerConfig 27 clock clock.Clock 28 mu sync.Mutex 29 enabled bool 30 } 31 32 type FanConfigurerFacade interface { 33 FanConfig() (network.FanConfig, error) 34 WatchForFanConfigChanges() (watcher.NotifyWatcher, error) 35 } 36 37 type FanConfigurerConfig struct { 38 Facade FanConfigurerFacade 39 } 40 41 // processNewConfig acts on a new fan config. 42 func (fc *FanConfigurer) processNewConfig() error { 43 logger.Debugf("Processing new fan config") 44 fc.mu.Lock() 45 defer fc.mu.Unlock() 46 47 fanConfig, err := fc.config.Facade.FanConfig() 48 if err != nil { 49 return err 50 } 51 if len(fanConfig) == 0 { 52 logger.Debugf("Fan not enabled") 53 // TODO(wpk) 2017-08-05 We have to clean this up! 54 return nil 55 } 56 57 for i, fan := range fanConfig { 58 logger.Debugf("Adding config for %d: %s %s", i, fan.Underlay, fan.Overlay) 59 line := fmt.Sprintf("fanatic enable-fan -u %s -o %s", fan.Underlay, fan.Overlay) 60 result, err := scriptrunner.RunCommand(line, os.Environ(), fc.clock, 5000*time.Millisecond) 61 logger.Debugf("Launched %s - result %v %v %d", line, string(result.Stdout), string(result.Stderr), result.Code) 62 if err != nil { 63 return err 64 } 65 } 66 // TODO(wpk) 2017-09-28 Although officially not needed we do fanctl up -a just to be sure - 67 // fanatic sometimes fails to bring up interface because of some weird interactions with iptables. 68 result, err := scriptrunner.RunCommand("fanctl up -a", os.Environ(), fc.clock, 5000*time.Millisecond) 69 logger.Debugf("Launched fanctl up -a - result %v %v %d", string(result.Stdout), string(result.Stderr), result.Code) 70 71 return err 72 } 73 74 func NewFanConfigurer(config FanConfigurerConfig, clock clock.Clock) (*FanConfigurer, error) { 75 fc := &FanConfigurer{ 76 config: config, 77 clock: clock, 78 } 79 // We need to launch it once here to make sure that it's configured right away, 80 // so that machiner will have a proper fan device address to report back 81 // to controller. 82 err := fc.processNewConfig() 83 if err != nil { 84 return nil, errors.Trace(err) 85 } 86 err = catacomb.Invoke(catacomb.Plan{ 87 Site: &fc.catacomb, 88 Work: fc.loop, 89 }) 90 if err != nil { 91 return nil, errors.Trace(err) 92 } 93 return fc, nil 94 } 95 96 func (fc *FanConfigurer) loop() error { 97 configWatcher, err := fc.config.Facade.WatchForFanConfigChanges() 98 if err != nil { 99 return errors.Trace(err) 100 } 101 if err := fc.catacomb.Add(configWatcher); err != nil { 102 return errors.Trace(err) 103 } 104 105 for { 106 select { 107 case <-fc.catacomb.Dying(): 108 return fc.catacomb.ErrDying() 109 case _, ok := <-configWatcher.Changes(): 110 if !ok { 111 return errors.New("FAN configuration watcher closed") 112 } 113 if err = fc.processNewConfig(); err != nil { 114 return errors.Trace(err) 115 } 116 } 117 } 118 } 119 120 // Kill implements Worker.Kill() 121 func (fc *FanConfigurer) Kill() { 122 fc.catacomb.Kill(nil) 123 } 124 125 // Wait implements Worker.Wait() 126 func (fc *FanConfigurer) Wait() error { 127 return fc.catacomb.Wait() 128 }