github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/provider/joyent/environ.go (about)

     1  // Copyright 2013 Joyent Inc.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package joyent
     5  
     6  import (
     7  	"fmt"
     8  	"sync"
     9  
    10  	"github.com/juju/errors"
    11  
    12  	"github.com/juju/juju/constraints"
    13  	"github.com/juju/juju/environs"
    14  	"github.com/juju/juju/environs/config"
    15  	"github.com/juju/juju/environs/imagemetadata"
    16  	"github.com/juju/juju/environs/simplestreams"
    17  	"github.com/juju/juju/environs/storage"
    18  	"github.com/juju/juju/instance"
    19  	"github.com/juju/juju/provider/common"
    20  	"github.com/juju/juju/state"
    21  )
    22  
    23  // This file contains the core of the Joyent Environ implementation.
    24  
    25  type joyentEnviron struct {
    26  	common.SupportsUnitPlacementPolicy
    27  
    28  	name string
    29  
    30  	// supportedArchitectures caches the architectures
    31  	// for which images can be instantiated.
    32  	archLock               sync.Mutex
    33  	supportedArchitectures []string
    34  
    35  	// All mutating operations should lock the mutex. Non-mutating operations
    36  	// should read all fields (other than name, which is immutable) from a
    37  	// shallow copy taken with getSnapshot().
    38  	// This advice is predicated on the goroutine-safety of the values of the
    39  	// affected fields.
    40  	lock    sync.Mutex
    41  	ecfg    *environConfig
    42  	storage storage.Storage
    43  	compute *joyentCompute
    44  }
    45  
    46  var _ environs.Environ = (*joyentEnviron)(nil)
    47  var _ state.Prechecker = (*joyentEnviron)(nil)
    48  
    49  // newEnviron create a new Joyent environ instance from config.
    50  func newEnviron(cfg *config.Config) (*joyentEnviron, error) {
    51  	env := new(joyentEnviron)
    52  	if err := env.SetConfig(cfg); err != nil {
    53  		return nil, err
    54  	}
    55  	env.name = cfg.Name()
    56  	var err error
    57  	env.storage, err = newStorage(env.ecfg, "")
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	env.compute, err = newCompute(env.ecfg)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	return env, nil
    66  }
    67  
    68  func (env *joyentEnviron) SetName(envName string) {
    69  	env.name = envName
    70  }
    71  
    72  func (*joyentEnviron) Provider() environs.EnvironProvider {
    73  	return providerInstance
    74  }
    75  
    76  // PrecheckInstance is defined on the state.Prechecker interface.
    77  func (env *joyentEnviron) PrecheckInstance(series string, cons constraints.Value, placement string) error {
    78  	if placement != "" {
    79  		return fmt.Errorf("unknown placement directive: %s", placement)
    80  	}
    81  	if !cons.HasInstanceType() {
    82  		return nil
    83  	}
    84  	// Constraint has an instance-type constraint so let's see if it is valid.
    85  	instanceTypes, err := env.listInstanceTypes()
    86  	if err != nil {
    87  		return err
    88  	}
    89  	for _, instanceType := range instanceTypes {
    90  		if instanceType.Name == *cons.InstanceType {
    91  			return nil
    92  		}
    93  	}
    94  	return fmt.Errorf("invalid Joyent instance %q specified", *cons.InstanceType)
    95  }
    96  
    97  // SupportedArchitectures is specified on the EnvironCapability interface.
    98  func (env *joyentEnviron) SupportedArchitectures() ([]string, error) {
    99  	env.archLock.Lock()
   100  	defer env.archLock.Unlock()
   101  	if env.supportedArchitectures != nil {
   102  		return env.supportedArchitectures, nil
   103  	}
   104  	cfg := env.Ecfg()
   105  	// Create a filter to get all images from our region and for the correct stream.
   106  	cloudSpec := simplestreams.CloudSpec{
   107  		Region:   cfg.Region(),
   108  		Endpoint: cfg.SdcUrl(),
   109  	}
   110  	imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{
   111  		CloudSpec: cloudSpec,
   112  		Stream:    cfg.ImageStream(),
   113  	})
   114  	var err error
   115  	env.supportedArchitectures, err = common.SupportedArchitectures(env, imageConstraint)
   116  	return env.supportedArchitectures, err
   117  }
   118  
   119  func (env *joyentEnviron) SetConfig(cfg *config.Config) error {
   120  	env.lock.Lock()
   121  	defer env.lock.Unlock()
   122  	ecfg, err := providerInstance.newConfig(cfg)
   123  	if err != nil {
   124  		return err
   125  	}
   126  	env.ecfg = ecfg
   127  	return nil
   128  }
   129  
   130  func (env *joyentEnviron) getSnapshot() *joyentEnviron {
   131  	env.lock.Lock()
   132  	clone := *env
   133  	env.lock.Unlock()
   134  	clone.lock = sync.Mutex{}
   135  	return &clone
   136  }
   137  
   138  func (env *joyentEnviron) Config() *config.Config {
   139  	return env.getSnapshot().ecfg.Config
   140  }
   141  
   142  func (env *joyentEnviron) Storage() storage.Storage {
   143  	return env.getSnapshot().storage
   144  }
   145  
   146  func (env *joyentEnviron) Bootstrap(ctx environs.BootstrapContext, args environs.BootstrapParams) (arch, series string, _ environs.BootstrapFinalizer, _ error) {
   147  	return common.Bootstrap(ctx, env, args)
   148  }
   149  
   150  func (env *joyentEnviron) StateServerInstances() ([]instance.Id, error) {
   151  	return common.ProviderStateInstances(env, env.Storage())
   152  }
   153  
   154  func (env *joyentEnviron) Destroy() error {
   155  	if err := common.Destroy(env); err != nil {
   156  		return errors.Trace(err)
   157  	}
   158  	return env.Storage().RemoveAll()
   159  }
   160  
   161  func (env *joyentEnviron) Ecfg() *environConfig {
   162  	return env.getSnapshot().ecfg
   163  }
   164  
   165  // MetadataLookupParams returns parameters which are used to query simplestreams metadata.
   166  func (env *joyentEnviron) MetadataLookupParams(region string) (*simplestreams.MetadataLookupParams, error) {
   167  	if region == "" {
   168  		region = env.Ecfg().Region()
   169  	}
   170  	return &simplestreams.MetadataLookupParams{
   171  		Series:        config.PreferredSeries(env.Ecfg()),
   172  		Region:        region,
   173  		Endpoint:      env.Ecfg().sdcUrl(),
   174  		Architectures: []string{"amd64", "armhf"},
   175  	}, nil
   176  }
   177  
   178  // Region is specified in the HasRegion interface.
   179  func (env *joyentEnviron) Region() (simplestreams.CloudSpec, error) {
   180  	return simplestreams.CloudSpec{
   181  		Region:   env.Ecfg().Region(),
   182  		Endpoint: env.Ecfg().sdcUrl(),
   183  	}, nil
   184  }