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