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  }