github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/provisioner/host_preparer.go (about)

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package provisioner
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/loggo"
     9  	"gopkg.in/juju/names.v2"
    10  
    11  	"github.com/juju/juju/apiserver/params"
    12  	"github.com/juju/juju/network"
    13  )
    14  
    15  // PrepareAPI is the functional interface that we need to be able to ask what
    16  // changes are necessary, and to then report back what changes have been done
    17  // to the host machine.
    18  type PrepareAPI interface {
    19  	// HostChangesForContainer returns the list of bridges to be created on the
    20  	// host machine, and the time to sleep after creating the bridges before
    21  	// bringing them up.
    22  	HostChangesForContainer(names.MachineTag) ([]network.DeviceToBridge, int, error)
    23  	// SetHostMachineNetworkConfig allows us to report back the host machine's
    24  	// current networking config. This is called after we've created new
    25  	// bridges to inform the Controller what the current networking interfaces
    26  	// are.
    27  	SetHostMachineNetworkConfig(names.MachineTag, []params.NetworkConfig) error
    28  }
    29  
    30  // HostPreparerParams is the configuration for HostPreparer
    31  type HostPreparerParams struct {
    32  	API                PrepareAPI
    33  	ObserveNetworkFunc func() ([]params.NetworkConfig, error)
    34  	AcquireLockFunc    func(string, <-chan struct{}) (func(), error)
    35  	CreateBridger      func() (network.Bridger, error)
    36  	AbortChan          <-chan struct{}
    37  	MachineTag         names.MachineTag
    38  	Logger             loggo.Logger
    39  }
    40  
    41  // HostPreparer calls out to the PrepareAPI to find out what changes need to be
    42  // done on this host to allow a new container to be started.
    43  type HostPreparer struct {
    44  	api                PrepareAPI
    45  	observeNetworkFunc func() ([]params.NetworkConfig, error)
    46  	acquireLockFunc    func(string, <-chan struct{}) (func(), error)
    47  	createBridger      func() (network.Bridger, error)
    48  	abortChan          <-chan struct{}
    49  	machineTag         names.MachineTag
    50  	logger             loggo.Logger
    51  }
    52  
    53  // NewHostPreparer creates a HostPreparer using the supplied parameters
    54  func NewHostPreparer(params HostPreparerParams) *HostPreparer {
    55  	return &HostPreparer{
    56  		api:                params.API,
    57  		observeNetworkFunc: params.ObserveNetworkFunc,
    58  		acquireLockFunc:    params.AcquireLockFunc,
    59  		createBridger:      params.CreateBridger,
    60  		abortChan:          params.AbortChan,
    61  		machineTag:         params.MachineTag,
    62  		logger:             params.Logger,
    63  	}
    64  }
    65  
    66  // Prepare applies changes to the host machine that are necessary to create
    67  // the requested container.
    68  func (hp *HostPreparer) Prepare(containerTag names.MachineTag) error {
    69  	devicesToBridge, reconfigureDelay, err := hp.api.HostChangesForContainer(containerTag)
    70  	if err != nil {
    71  		return errors.Annotate(err, "unable to setup network")
    72  	}
    73  
    74  	if len(devicesToBridge) == 0 {
    75  		hp.logger.Debugf("container %q requires no additional bridges", containerTag)
    76  		return nil
    77  	}
    78  
    79  	bridger, err := hp.createBridger()
    80  	if err != nil {
    81  		return errors.Trace(err)
    82  	}
    83  
    84  	hp.logger.Debugf("bridging %+v devices on host %q for container %q with delay=%v",
    85  		devicesToBridge, hp.machineTag.String(), containerTag.String(), reconfigureDelay)
    86  	releaser, err := hp.acquireLockFunc("bridging devices", hp.abortChan)
    87  	if err != nil {
    88  		return errors.Annotatef(err, "failed to acquire machine lock for bridging")
    89  	}
    90  	defer releaser()
    91  	// TODO(jam): 2017-02-15 bridger.Bridge should probably also take AbortChan
    92  	// if it is going to have reconfigureDelay
    93  	err = bridger.Bridge(devicesToBridge, reconfigureDelay)
    94  	if err != nil {
    95  		return errors.Annotate(err, "failed to bridge devices")
    96  	}
    97  
    98  	// We just changed the hosts' network setup so discover new
    99  	// interfaces/devices and propagate to state.
   100  	observedConfig, err := hp.observeNetworkFunc()
   101  	if err != nil {
   102  		return errors.Annotate(err, "cannot discover observed network config")
   103  	}
   104  
   105  	if len(observedConfig) > 0 {
   106  		hp.logger.Debugf("updating observed network config for %q to %#v", hp.machineTag.String(), observedConfig)
   107  		err := hp.api.SetHostMachineNetworkConfig(hp.machineTag, observedConfig)
   108  		if err != nil {
   109  			return errors.Trace(err)
   110  		}
   111  	}
   112  
   113  	return nil
   114  }