github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/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 manager, err := kvm.NewContainerManager(managerConfig) 29 if err != nil { 30 return nil, err 31 } 32 return &kvmBroker{ 33 manager: manager, 34 api: api, 35 agentConfig: agentConfig, 36 enableNAT: enableNAT, 37 }, nil 38 } 39 40 type kvmBroker struct { 41 manager container.Manager 42 api APICalls 43 agentConfig agent.Config 44 enableNAT bool 45 } 46 47 // StartInstance is specified in the Broker interface. 48 func (broker *kvmBroker) StartInstance(args environs.StartInstanceParams) (*environs.StartInstanceResult, error) { 49 if args.InstanceConfig.HasNetworks() { 50 return nil, errors.New("starting kvm containers with networks is not supported yet") 51 } 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 = kvm.DefaultKvmBridge 62 } 63 if !environs.AddressAllocationEnabled() { 64 logger.Debugf( 65 "address allocation feature flag not enabled; using DHCP for container %q", 66 machineId, 67 ) 68 } else { 69 logger.Debugf("trying to allocate static IP for container %q", machineId) 70 71 allocatedInfo, err := configureContainerNetwork( 72 machineId, 73 bridgeDevice, 74 broker.api, 75 args.NetworkInfo, 76 true, // allocate a new address. 77 broker.enableNAT, 78 ) 79 if err != nil { 80 // It's fine, just ignore it. The effect will be that the 81 // container won't have a static address configured. 82 logger.Infof("not allocating static IP for container %q: %v", machineId, err) 83 } else { 84 args.NetworkInfo = allocatedInfo 85 } 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 series := args.Tools.OneSeries() 92 args.InstanceConfig.MachineContainerType = instance.KVM 93 args.InstanceConfig.Tools = args.Tools[0] 94 95 config, err := broker.api.ContainerConfig() 96 if err != nil { 97 kvmLogger.Errorf("failed to get container config: %v", err) 98 return nil, err 99 } 100 101 if err := instancecfg.PopulateInstanceConfig( 102 args.InstanceConfig, 103 config.ProviderType, 104 config.AuthorizedKeys, 105 config.SSLHostnameVerification, 106 config.Proxy, 107 config.AptProxy, 108 config.AptMirror, 109 config.PreferIPv6, 110 config.EnableOSRefreshUpdate, 111 config.EnableOSUpgrade, 112 ); err != nil { 113 kvmLogger.Errorf("failed to populate machine config: %v", err) 114 return nil, err 115 } 116 117 storageConfig := &container.StorageConfig{ 118 AllowMount: true, 119 } 120 inst, hardware, err := broker.manager.CreateContainer(args.InstanceConfig, series, network, storageConfig) 121 if err != nil { 122 kvmLogger.Errorf("failed to start container: %v", err) 123 return nil, err 124 } 125 kvmLogger.Infof("started kvm container for machineId: %s, %s, %s", machineId, inst.Id(), hardware.String()) 126 return &environs.StartInstanceResult{ 127 Instance: inst, 128 Hardware: hardware, 129 NetworkInfo: network.Interfaces, 130 }, nil 131 } 132 133 // StopInstances shuts down the given instances. 134 func (broker *kvmBroker) StopInstances(ids ...instance.Id) error { 135 // TODO: potentially parallelise. 136 for _, id := range ids { 137 kvmLogger.Infof("stopping kvm container for instance: %s", id) 138 if err := broker.manager.DestroyContainer(id); err != nil { 139 kvmLogger.Errorf("container did not stop: %v", err) 140 return err 141 } 142 } 143 return nil 144 } 145 146 // AllInstances only returns running containers. 147 func (broker *kvmBroker) AllInstances() (result []instance.Instance, err error) { 148 return broker.manager.ListContainers() 149 } 150 151 // MaintainInstance checks that the container's host has the required iptables and routing 152 // rules to make the container visible to both the host and other machines on the same subnet. 153 func (broker *kvmBroker) MaintainInstance(args environs.StartInstanceParams) error { 154 machineId := args.InstanceConfig.MachineId 155 if !environs.AddressAllocationEnabled() { 156 kvmLogger.Debugf("address allocation disabled: Not running maintenance for kvm with machineId: %s", 157 machineId) 158 return nil 159 } 160 161 kvmLogger.Debugf("running maintenance for kvm with machineId: %s", machineId) 162 163 // Default to using the host network until we can configure. 164 bridgeDevice := broker.agentConfig.Value(agent.LxcBridge) 165 if bridgeDevice == "" { 166 bridgeDevice = kvm.DefaultKvmBridge 167 } 168 _, err := configureContainerNetwork( 169 machineId, 170 bridgeDevice, 171 broker.api, 172 args.NetworkInfo, 173 false, // don't allocate a new address. 174 broker.enableNAT, 175 ) 176 return err 177 }