github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/worker/provisioner/broker.go (about) 1 // Copyright 2013 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 "github.com/juju/utils/arch" 10 "github.com/juju/version" 11 "gopkg.in/juju/names.v2" 12 13 "github.com/juju/juju/apiserver/params" 14 "github.com/juju/juju/container" 15 "github.com/juju/juju/instance" 16 "github.com/juju/juju/network" 17 "github.com/juju/juju/tools" 18 ) 19 20 type APICalls interface { 21 ContainerConfig() (params.ContainerConfig, error) 22 PrepareContainerInterfaceInfo(names.MachineTag) ([]network.InterfaceInfo, error) 23 GetContainerInterfaceInfo(names.MachineTag) ([]network.InterfaceInfo, error) 24 ReleaseContainerAddresses(names.MachineTag) error 25 } 26 27 type hostArchToolsFinder struct { 28 f ToolsFinder 29 } 30 31 // FindTools is defined on the ToolsFinder interface. 32 func (h hostArchToolsFinder) FindTools(v version.Number, series, _ string) (tools.List, error) { 33 // Override the arch constraint with the arch of the host. 34 return h.f.FindTools(v, series, arch.HostArch()) 35 } 36 37 // resolvConf is the full path to the resolv.conf file on the local 38 // system. Defined here so it can be overriden for testing. 39 var resolvConf = "/etc/resolv.conf" 40 41 func prepareOrGetContainerInterfaceInfo( 42 api APICalls, 43 machineID string, 44 bridgeDevice string, 45 allocateOrMaintain bool, 46 startingNetworkInfo []network.InterfaceInfo, 47 log loggo.Logger, 48 ) ([]network.InterfaceInfo, error) { 49 maintain := !allocateOrMaintain 50 51 if maintain { 52 log.Debugf("not running maintenance for machine %q", machineID) 53 return nil, nil 54 } 55 56 log.Debugf("using multi-bridge networking for container %q", machineID) 57 58 containerTag := names.NewMachineTag(machineID) 59 preparedInfo, err := api.PrepareContainerInterfaceInfo(containerTag) 60 if err != nil { 61 return nil, errors.Trace(err) 62 } 63 log.Tracef("PrepareContainerInterfaceInfo returned %+v", preparedInfo) 64 65 return preparedInfo, nil 66 } 67 68 // finishNetworkConfig populates the ParentInterfaceName, DNSServers, and 69 // DNSSearchDomains fields on each element, when they are not set. The given 70 // bridgeDevice is used for ParentInterfaceName, while the DNS config is 71 // discovered using network.ParseResolvConf(). If interfaces has zero length, 72 // container.FallbackInterfaceInfo() is used as fallback. 73 func finishNetworkConfig(bridgeDevice string, interfaces []network.InterfaceInfo) ([]network.InterfaceInfo, error) { 74 haveNameservers, haveSearchDomains := false, false 75 if len(interfaces) == 0 { 76 // Use the fallback network config as a last resort. 77 interfaces = container.FallbackInterfaceInfo() 78 } 79 80 results := make([]network.InterfaceInfo, len(interfaces)) 81 for i, info := range interfaces { 82 if info.ParentInterfaceName == "" { 83 info.ParentInterfaceName = bridgeDevice 84 } 85 86 if len(info.DNSServers) > 0 { 87 haveNameservers = true 88 } 89 90 if len(info.DNSSearchDomains) > 0 { 91 haveSearchDomains = true 92 } 93 results[i] = info 94 } 95 96 if !haveNameservers || !haveSearchDomains { 97 logger.Warningf("incomplete DNS config found, discovering host's DNS config") 98 dnsConfig, err := network.ParseResolvConf(resolvConf) 99 if err != nil { 100 return nil, errors.Trace(err) 101 } 102 103 // Since the result is sorted, the first entry is the primary NIC. Also, 104 // results always contains at least one element. 105 results[0].DNSServers = dnsConfig.Nameservers 106 results[0].DNSSearchDomains = dnsConfig.SearchDomains 107 logger.Debugf( 108 "setting DNS servers %+v and domains %+v on container interface %q", 109 results[0].DNSServers, results[0].DNSSearchDomains, results[0].InterfaceName, 110 ) 111 } 112 113 return results, nil 114 } 115 116 func releaseContainerAddresses( 117 api APICalls, 118 instanceID instance.Id, 119 namespace instance.Namespace, 120 log loggo.Logger, 121 ) { 122 containerTag, err := namespace.MachineTag(string(instanceID)) 123 if err != nil { 124 // Not a reason to cause StopInstances to fail though.. 125 log.Warningf("unexpected container tag %q: %v", instanceID, err) 126 return 127 } 128 err = api.ReleaseContainerAddresses(containerTag) 129 switch { 130 case err == nil: 131 log.Infof("released all addresses for container %q", containerTag.Id()) 132 case errors.IsNotSupported(err): 133 log.Warningf("not releasing all addresses for container %q: %v", containerTag.Id(), err) 134 default: 135 log.Warningf( 136 "unexpected error trying to release container %q addreses: %v", 137 containerTag.Id(), err, 138 ) 139 } 140 } 141 142 // matchHostArchTools filters the given list of tools to the host architecture. 143 func matchHostArchTools(allTools tools.List) (tools.List, error) { 144 arch := arch.HostArch() 145 archTools, err := allTools.Match(tools.Filter{Arch: arch}) 146 if err == tools.ErrNoMatches { 147 return nil, errors.Errorf( 148 "need tools for arch %s, only found %s", 149 arch, allTools.Arches(), 150 ) 151 } else if err != nil { 152 return nil, errors.Trace(err) 153 } 154 return archTools, nil 155 }