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  }