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