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