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