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