github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/provider/vsphere/environ_broker.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 // +build !gccgo 5 6 package vsphere 7 8 import ( 9 "github.com/juju/errors" 10 "github.com/juju/govmomi/vim25/mo" 11 12 "github.com/juju/juju/cloudconfig/cloudinit" 13 "github.com/juju/juju/cloudconfig/instancecfg" 14 "github.com/juju/juju/cloudconfig/providerinit" 15 "github.com/juju/juju/environs" 16 "github.com/juju/juju/instance" 17 "github.com/juju/juju/provider/common" 18 "github.com/juju/juju/state/multiwatcher" 19 "github.com/juju/juju/tools" 20 ) 21 22 const ( 23 DefaultCpuCores = uint64(2) 24 DefaultCpuPower = uint64(2000) 25 DefaultMemMb = uint64(2000) 26 ) 27 28 func isStateServer(mcfg *instancecfg.InstanceConfig) bool { 29 return multiwatcher.AnyJobNeedsState(mcfg.Jobs...) 30 } 31 32 // MaintainInstance is specified in the InstanceBroker interface. 33 func (*environ) MaintainInstance(args environs.StartInstanceParams) error { 34 return nil 35 } 36 37 // StartInstance implements environs.InstanceBroker. 38 func (env *environ) StartInstance(args environs.StartInstanceParams) (*environs.StartInstanceResult, error) { 39 env = env.getSnapshot() 40 41 if args.InstanceConfig.HasNetworks() { 42 return nil, errors.New("starting instances with networks is not supported yet") 43 } 44 45 img, err := findImageMetadata(env, args) 46 if err != nil { 47 return nil, errors.Trace(err) 48 } 49 if err := env.finishMachineConfig(args, img); err != nil { 50 return nil, errors.Trace(err) 51 } 52 53 raw, hwc, err := env.newRawInstance(args, img) 54 if err != nil { 55 return nil, errors.Trace(err) 56 } 57 58 logger.Infof("started instance %q", raw.Name) 59 inst := newInstance(raw, env) 60 61 result := environs.StartInstanceResult{ 62 Instance: inst, 63 Hardware: hwc, 64 } 65 return &result, nil 66 } 67 68 //this variable is exported, because it has to be rewritten in external unit tests 69 var FinishInstanceConfig = instancecfg.FinishInstanceConfig 70 71 // finishMachineConfig updates args.MachineConfig in place. Setting up 72 // the API, StateServing, and SSHkeys information. 73 func (env *environ) finishMachineConfig(args environs.StartInstanceParams, img *OvaFileMetadata) error { 74 envTools, err := args.Tools.Match(tools.Filter{Arch: img.Arch}) 75 if err != nil { 76 return err 77 } 78 79 args.InstanceConfig.Tools = envTools[0] 80 return FinishInstanceConfig(args.InstanceConfig, env.Config()) 81 } 82 83 // newRawInstance is where the new physical instance is actually 84 // provisioned, relative to the provided args and spec. Info for that 85 // low-level instance is returned. 86 func (env *environ) newRawInstance(args environs.StartInstanceParams, img *OvaFileMetadata) (*mo.VirtualMachine, *instance.HardwareCharacteristics, error) { 87 machineID := common.MachineFullName(env, args.InstanceConfig.MachineId) 88 89 cloudcfg, err := cloudinit.New(args.Tools.OneSeries()) 90 if err != nil { 91 return nil, nil, errors.Trace(err) 92 } 93 cloudcfg.AddPackage("open-vm-tools") 94 cloudcfg.AddPackage("iptables-persistent") 95 userData, err := providerinit.ComposeUserData(args.InstanceConfig, cloudcfg, VsphereRenderer{}) 96 if err != nil { 97 return nil, nil, errors.Annotate(err, "cannot make user data") 98 } 99 logger.Debugf("Vmware user data; %d bytes", len(userData)) 100 101 rootDisk := common.MinRootDiskSizeGiB * 1024 102 if args.Constraints.RootDisk != nil && *args.Constraints.RootDisk > rootDisk { 103 rootDisk = *args.Constraints.RootDisk 104 } 105 cpuCores := DefaultCpuCores 106 if args.Constraints.CpuCores != nil { 107 cpuCores = *args.Constraints.CpuCores 108 } 109 cpuPower := DefaultCpuPower 110 if args.Constraints.CpuPower != nil { 111 cpuPower = *args.Constraints.CpuPower 112 } 113 mem := DefaultMemMb 114 if args.Constraints.Mem != nil { 115 mem = *args.Constraints.Mem 116 } 117 118 hwc := &instance.HardwareCharacteristics{ 119 Arch: &img.Arch, 120 Mem: &mem, 121 CpuCores: &cpuCores, 122 CpuPower: &cpuPower, 123 RootDisk: &rootDisk, 124 } 125 zones, err := env.parseAvailabilityZones(args) 126 if err != nil { 127 return nil, nil, errors.Trace(err) 128 } 129 var inst *mo.VirtualMachine 130 for _, zone := range zones { 131 var availZone *vmwareAvailZone 132 availZone, err = env.availZone(zone) 133 if err != nil { 134 logger.Warningf("Error while getting availability zone %s: %s", zone, err) 135 continue 136 } 137 apiPort := 0 138 if isStateServer(args.InstanceConfig) { 139 apiPort = args.InstanceConfig.StateServingInfo.APIPort 140 } 141 spec := &instanceSpec{ 142 machineID: machineID, 143 zone: availZone, 144 hwc: hwc, 145 img: img, 146 userData: userData, 147 sshKey: args.InstanceConfig.AuthorizedKeys, 148 isState: isStateServer(args.InstanceConfig), 149 apiPort: apiPort, 150 } 151 inst, err = env.client.CreateInstance(env.ecfg, spec) 152 if err != nil { 153 logger.Warningf("Error while trying to create instance in %s availability zone: %s", zone, err) 154 continue 155 } 156 break 157 } 158 if err != nil { 159 return nil, nil, errors.Annotate(err, "Can't create instance in any of availability zones, last error") 160 } 161 return inst, hwc, err 162 } 163 164 // AllInstances implements environs.InstanceBroker. 165 func (env *environ) AllInstances() ([]instance.Instance, error) { 166 instances, err := env.instances() 167 return instances, errors.Trace(err) 168 } 169 170 // StopInstances implements environs.InstanceBroker. 171 func (env *environ) StopInstances(instances ...instance.Id) error { 172 env = env.getSnapshot() 173 174 var ids []string 175 for _, id := range instances { 176 ids = append(ids, string(id)) 177 } 178 179 err := env.client.RemoveInstances(ids...) 180 return errors.Trace(err) 181 }