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 }