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  }