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  }