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