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