github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/provider/cloudsigma/environinstance.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package cloudsigma
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/loggo"
     9  
    10  	"github.com/juju/juju/cloudconfig/instancecfg"
    11  	"github.com/juju/juju/cloudconfig/providerinit"
    12  	"github.com/juju/juju/environs"
    13  	"github.com/juju/juju/environs/imagemetadata"
    14  	"github.com/juju/juju/instance"
    15  	"github.com/juju/juju/tools"
    16  )
    17  
    18  //
    19  // Imlementation of InstanceBroker: methods for starting and stopping instances.
    20  //
    21  
    22  var findInstanceImage = func(
    23  	matchingImages []*imagemetadata.ImageMetadata,
    24  ) (*imagemetadata.ImageMetadata, error) {
    25  	if len(matchingImages) == 0 {
    26  		return nil, errors.New("no matching image meta data")
    27  	}
    28  	return matchingImages[0], nil
    29  }
    30  
    31  // MaintainInstance is specified in the InstanceBroker interface.
    32  func (*environ) MaintainInstance(args environs.StartInstanceParams) error {
    33  	return nil
    34  }
    35  
    36  // StartInstance asks for a new instance to be created, associated with
    37  // the provided config in machineConfig. The given config describes the juju
    38  // state for the new instance to connect to. The config MachineNonce, which must be
    39  // unique within an environment, is used by juju to protect against the
    40  // consequences of multiple instances being started with the same machine id.
    41  func (env *environ) StartInstance(args environs.StartInstanceParams) (*environs.StartInstanceResult, error) {
    42  	logger.Infof("sigmaEnviron.StartInstance...")
    43  
    44  	if args.InstanceConfig == nil {
    45  		return nil, errors.New("instance configuration is nil")
    46  	}
    47  
    48  	if len(args.Tools) == 0 {
    49  		return nil, errors.New("tools not found")
    50  	}
    51  
    52  	img, err := findInstanceImage(args.ImageMetadata)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	tools, err := args.Tools.Match(tools.Filter{Arch: img.Arch})
    58  	if err != nil {
    59  		return nil, errors.Errorf("chosen architecture %v not present in %v", img.Arch, args.Tools.Arches())
    60  	}
    61  
    62  	if err := args.InstanceConfig.SetTools(tools); err != nil {
    63  		return nil, errors.Trace(err)
    64  	}
    65  	if err := instancecfg.FinishInstanceConfig(args.InstanceConfig, env.Config()); err != nil {
    66  		return nil, err
    67  	}
    68  	userData, err := providerinit.ComposeUserData(args.InstanceConfig, nil, CloudSigmaRenderer{})
    69  	if err != nil {
    70  		return nil, errors.Annotate(err, "cannot make user data")
    71  	}
    72  
    73  	logger.Debugf("cloudsigma user data; %d bytes", len(userData))
    74  
    75  	client := env.client
    76  	server, rootdrive, arch, err := client.newInstance(args, img, userData)
    77  	if err != nil {
    78  		return nil, errors.Errorf("failed start instance: %v", err)
    79  	}
    80  
    81  	inst := &sigmaInstance{server: server}
    82  
    83  	// prepare hardware characteristics
    84  	hwch, err := inst.hardware(arch, rootdrive.Size())
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  
    89  	logger.Debugf("hardware: %v", hwch)
    90  	return &environs.StartInstanceResult{
    91  		Instance: inst,
    92  		Hardware: hwch,
    93  	}, nil
    94  }
    95  
    96  // AllInstances returns all instances currently known to the broker.
    97  func (env *environ) AllInstances() ([]instance.Instance, error) {
    98  	// Please note that this must *not* return instances that have not been
    99  	// allocated as part of this environment -- if it does, juju will see they
   100  	// are not tracked in state, assume they're stale/rogue, and shut them down.
   101  
   102  	logger.Tracef("environ.AllInstances...")
   103  
   104  	servers, err := env.client.instances()
   105  	if err != nil {
   106  		logger.Tracef("environ.AllInstances failed: %v", err)
   107  		return nil, err
   108  	}
   109  
   110  	instances := make([]instance.Instance, 0, len(servers))
   111  	for _, server := range servers {
   112  		instance := sigmaInstance{server: server}
   113  		instances = append(instances, instance)
   114  	}
   115  
   116  	if logger.LogLevel() <= loggo.TRACE {
   117  		logger.Tracef("All instances, len = %d:", len(instances))
   118  		for _, instance := range instances {
   119  			logger.Tracef("... id: %q, status: %q", instance.Id(), instance.Status())
   120  		}
   121  	}
   122  
   123  	return instances, nil
   124  }
   125  
   126  // Instances returns a slice of instances corresponding to the
   127  // given instance ids.  If no instances were found, but there
   128  // was no other error, it will return ErrNoInstances.  If
   129  // some but not all the instances were found, the returned slice
   130  // will have some nil slots, and an ErrPartialInstances error
   131  // will be returned.
   132  func (env *environ) Instances(ids []instance.Id) ([]instance.Instance, error) {
   133  	logger.Tracef("environ.Instances %#v", ids)
   134  	// Please note that this must *not* return instances that have not been
   135  	// allocated as part of this environment -- if it does, juju will see they
   136  	// are not tracked in state, assume they're stale/rogue, and shut them down.
   137  	// This advice applies even if an instance id passed in corresponds to a
   138  	// real instance that's not part of the environment -- the Environ should
   139  	// treat that no differently to a request for one that does not exist.
   140  
   141  	m, err := env.client.instanceMap()
   142  	if err != nil {
   143  		logger.Warningf("environ.Instances failed: %v", err)
   144  		return nil, err
   145  	}
   146  
   147  	var found int
   148  	r := make([]instance.Instance, len(ids))
   149  	for i, id := range ids {
   150  		if s, ok := m[string(id)]; ok {
   151  			r[i] = sigmaInstance{server: s}
   152  			found++
   153  		}
   154  	}
   155  
   156  	if found == 0 {
   157  		err = environs.ErrNoInstances
   158  	} else if found != len(ids) {
   159  		err = environs.ErrPartialInstances
   160  	}
   161  
   162  	return r, err
   163  }
   164  
   165  // StopInstances shuts down the given instances.
   166  func (env *environ) StopInstances(instances ...instance.Id) error {
   167  	logger.Debugf("stop instances %+v", instances)
   168  
   169  	var err error
   170  
   171  	for _, instance := range instances {
   172  		if e := env.client.stopInstance(instance); e != nil {
   173  			err = e
   174  		}
   175  	}
   176  
   177  	return err
   178  }