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