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 }