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  }