github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/worker/provisioner/lxd-broker.go (about)

     1  // Copyright 2016 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  
    10  	"github.com/juju/juju/agent"
    11  	"github.com/juju/juju/cloudconfig/instancecfg"
    12  	"github.com/juju/juju/container"
    13  	"github.com/juju/juju/environs"
    14  	"github.com/juju/juju/instance"
    15  	"github.com/juju/juju/tools/lxdclient"
    16  )
    17  
    18  var lxdLogger = loggo.GetLogger("juju.provisioner.lxd")
    19  
    20  var _ environs.InstanceBroker = (*lxdBroker)(nil)
    21  
    22  func NewLxdBroker(
    23  	api APICalls,
    24  	manager container.Manager,
    25  	agentConfig agent.Config,
    26  	namespace string,
    27  	enableNAT bool,
    28  ) (environs.InstanceBroker, error) {
    29  	return &lxdBroker{
    30  		manager:     manager,
    31  		namespace:   namespace,
    32  		api:         api,
    33  		agentConfig: agentConfig,
    34  		enableNAT:   enableNAT,
    35  	}, nil
    36  }
    37  
    38  type lxdBroker struct {
    39  	manager     container.Manager
    40  	namespace   string
    41  	api         APICalls
    42  	agentConfig agent.Config
    43  	enableNAT   bool
    44  }
    45  
    46  func (broker *lxdBroker) StartInstance(args environs.StartInstanceParams) (*environs.StartInstanceResult, error) {
    47  	machineId := args.InstanceConfig.MachineId
    48  	bridgeDevice := broker.agentConfig.Value(agent.LxdBridge)
    49  	if bridgeDevice == "" {
    50  		bridgeDevice = lxdclient.DefaultLXDBridge
    51  	}
    52  
    53  	config, err := broker.api.ContainerConfig()
    54  	if err != nil {
    55  		lxdLogger.Errorf("failed to get container config: %v", err)
    56  		return nil, err
    57  	}
    58  
    59  	preparedInfo, err := prepareOrGetContainerInterfaceInfo(
    60  		broker.api,
    61  		machineId,
    62  		bridgeDevice,
    63  		true, // allocate if possible, do not maintain existing.
    64  		broker.enableNAT,
    65  		args.NetworkInfo,
    66  		lxdLogger,
    67  		config.ProviderType,
    68  	)
    69  	if err != nil {
    70  		// It's not fatal (yet) if we couldn't pre-allocate addresses for the
    71  		// container.
    72  		logger.Warningf("failed to prepare container %q network config: %v", machineId, err)
    73  	} else {
    74  		args.NetworkInfo = preparedInfo
    75  	}
    76  
    77  	network := container.BridgeNetworkConfig(bridgeDevice, 0, args.NetworkInfo)
    78  
    79  	// The provisioner worker will provide all tools it knows about
    80  	// (after applying explicitly specified constraints), which may
    81  	// include tools for architectures other than the host's. We
    82  	// must constrain to the host's architecture for LXD.
    83  	archTools, err := matchHostArchTools(args.Tools)
    84  	if err != nil {
    85  		return nil, errors.Trace(err)
    86  	}
    87  
    88  	series := archTools.OneSeries()
    89  	args.InstanceConfig.MachineContainerType = instance.LXD
    90  	if err := args.InstanceConfig.SetTools(archTools); err != nil {
    91  		return nil, errors.Trace(err)
    92  	}
    93  
    94  	if err := instancecfg.PopulateInstanceConfig(
    95  		args.InstanceConfig,
    96  		config.ProviderType,
    97  		config.AuthorizedKeys,
    98  		config.SSLHostnameVerification,
    99  		config.Proxy,
   100  		config.AptProxy,
   101  		config.AptMirror,
   102  		config.PreferIPv6,
   103  		config.EnableOSRefreshUpdate,
   104  		config.EnableOSUpgrade,
   105  	); err != nil {
   106  		lxdLogger.Errorf("failed to populate machine config: %v", err)
   107  		return nil, err
   108  	}
   109  
   110  	storageConfig := &container.StorageConfig{}
   111  	inst, hardware, err := broker.manager.CreateContainer(args.InstanceConfig, series, network, storageConfig, args.StatusCallback)
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  
   116  	return &environs.StartInstanceResult{
   117  		Instance:    inst,
   118  		Hardware:    hardware,
   119  		NetworkInfo: network.Interfaces,
   120  	}, nil
   121  }
   122  
   123  func (broker *lxdBroker) StopInstances(ids ...instance.Id) error {
   124  	// TODO: potentially parallelise.
   125  	for _, id := range ids {
   126  		lxdLogger.Infof("stopping lxd container for instance: %s", id)
   127  		if err := broker.manager.DestroyContainer(id); err != nil {
   128  			lxdLogger.Errorf("container did not stop: %v", err)
   129  			return err
   130  		}
   131  		providerType := broker.agentConfig.Value(agent.ProviderType)
   132  		maybeReleaseContainerAddresses(broker.api, id, broker.namespace, lxdLogger, providerType)
   133  	}
   134  	return nil
   135  }
   136  
   137  // AllInstances only returns running containers.
   138  func (broker *lxdBroker) AllInstances() (result []instance.Instance, err error) {
   139  	return broker.manager.ListContainers()
   140  }
   141  
   142  // MaintainInstance ensures the container's host has the required iptables and
   143  // routing rules to make the container visible to both the host and other
   144  // machines on the same subnet. This is important mostly when address allocation
   145  // feature flag is enabled, as otherwise we don't create additional iptables
   146  // rules or routes.
   147  func (broker *lxdBroker) MaintainInstance(args environs.StartInstanceParams) error {
   148  	machineID := args.InstanceConfig.MachineId
   149  
   150  	// Default to using the host network until we can configure.
   151  	bridgeDevice := broker.agentConfig.Value(agent.LxdBridge)
   152  	if bridgeDevice == "" {
   153  		bridgeDevice = lxdclient.DefaultLXDBridge
   154  	}
   155  
   156  	// There's no InterfaceInfo we expect to get below.
   157  	_, err := prepareOrGetContainerInterfaceInfo(
   158  		broker.api,
   159  		machineID,
   160  		bridgeDevice,
   161  		false, // maintain, do not allocate.
   162  		broker.enableNAT,
   163  		args.NetworkInfo,
   164  		lxdLogger,
   165  		broker.agentConfig.Value(agent.ProviderType),
   166  	)
   167  	return err
   168  }