github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/container/broker/host_preparer.go (about)

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package broker
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/loggo"
     9  	"github.com/juju/names/v5"
    10  
    11  	"github.com/juju/juju/network"
    12  	"github.com/juju/juju/rpc/params"
    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  	releaser, err := hp.acquireLockFunc("bridging devices", hp.abortChan)
    70  	if err != nil {
    71  		return errors.Annotatef(err, "failed to acquire machine lock for bridging")
    72  	}
    73  	defer releaser()
    74  
    75  	devicesToBridge, reconfigureDelay, err := hp.api.HostChangesForContainer(containerTag)
    76  	if err != nil {
    77  		return errors.Annotate(err, "unable to setup network")
    78  	}
    79  
    80  	if len(devicesToBridge) == 0 {
    81  		hp.logger.Debugf("container %q requires no additional bridges", containerTag)
    82  		return nil
    83  	}
    84  
    85  	bridger, err := hp.createBridger()
    86  	if err != nil {
    87  		return errors.Trace(err)
    88  	}
    89  
    90  	hp.logger.Debugf("bridging %+v devices on host %q for container %q with delay=%v",
    91  		devicesToBridge, hp.machineTag.String(), containerTag.String(), reconfigureDelay)
    92  
    93  	// TODO(jam): 2017-02-15 bridger.Bridge should probably also take AbortChan
    94  	// if it is going to have reconfigureDelay
    95  	err = bridger.Bridge(devicesToBridge, reconfigureDelay)
    96  	if err != nil {
    97  		return errors.Annotate(err, "failed to bridge devices")
    98  	}
    99  
   100  	// We just changed the hosts' network setup so discover new
   101  	// interfaces/devices and propagate to state.
   102  	observedConfig, err := hp.observeNetworkFunc()
   103  	if err != nil {
   104  		return errors.Annotate(err, "cannot discover observed network config")
   105  	}
   106  
   107  	if len(observedConfig) > 0 {
   108  		hp.logger.Debugf("updating observed network config for %q to %#v", hp.machineTag.String(), observedConfig)
   109  		err := hp.api.SetHostMachineNetworkConfig(hp.machineTag, observedConfig)
   110  		if err != nil {
   111  			return errors.Trace(err)
   112  		}
   113  	}
   114  
   115  	return nil
   116  }