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