github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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  	"strings"
     9  	"sync"
    10  
    11  	"github.com/joyent/gosdc/cloudapi"
    12  	"github.com/juju/errors"
    13  
    14  	"github.com/juju/juju/constraints"
    15  	"github.com/juju/juju/environs"
    16  	"github.com/juju/juju/environs/config"
    17  	"github.com/juju/juju/environs/imagemetadata"
    18  	"github.com/juju/juju/environs/simplestreams"
    19  	"github.com/juju/juju/environs/tags"
    20  	"github.com/juju/juju/instance"
    21  	"github.com/juju/juju/provider/common"
    22  )
    23  
    24  // This file contains the core of the Joyent Environ implementation.
    25  
    26  type joyentEnviron struct {
    27  	common.SupportsUnitPlacementPolicy
    28  
    29  	name string
    30  
    31  	compute *joyentCompute
    32  
    33  	// supportedArchitectures caches the architectures
    34  	// for which images can be instantiated.
    35  	archLock               sync.Mutex
    36  	supportedArchitectures []string
    37  
    38  	lock sync.Mutex // protects ecfg
    39  	ecfg *environConfig
    40  }
    41  
    42  // newEnviron create a new Joyent environ instance from config.
    43  func newEnviron(cfg *config.Config) (*joyentEnviron, error) {
    44  	env := new(joyentEnviron)
    45  	if err := env.SetConfig(cfg); err != nil {
    46  		return nil, err
    47  	}
    48  	env.name = cfg.Name()
    49  	var err error
    50  	env.compute, err = newCompute(env.ecfg)
    51  	if err != nil {
    52  		return nil, err
    53  	}
    54  	return env, nil
    55  }
    56  
    57  func (env *joyentEnviron) SetName(envName string) {
    58  	env.name = envName
    59  }
    60  
    61  func (*joyentEnviron) Provider() environs.EnvironProvider {
    62  	return providerInstance
    63  }
    64  
    65  // PrecheckInstance is defined on the state.Prechecker interface.
    66  func (env *joyentEnviron) PrecheckInstance(series string, cons constraints.Value, placement string) error {
    67  	if placement != "" {
    68  		return fmt.Errorf("unknown placement directive: %s", placement)
    69  	}
    70  	if !cons.HasInstanceType() {
    71  		return nil
    72  	}
    73  	// Constraint has an instance-type constraint so let's see if it is valid.
    74  	instanceTypes, err := env.listInstanceTypes()
    75  	if err != nil {
    76  		return err
    77  	}
    78  	for _, instanceType := range instanceTypes {
    79  		if instanceType.Name == *cons.InstanceType {
    80  			return nil
    81  		}
    82  	}
    83  	return fmt.Errorf("invalid Joyent instance %q specified", *cons.InstanceType)
    84  }
    85  
    86  // SupportedArchitectures is specified on the EnvironCapability interface.
    87  func (env *joyentEnviron) SupportedArchitectures() ([]string, error) {
    88  	env.archLock.Lock()
    89  	defer env.archLock.Unlock()
    90  	if env.supportedArchitectures != nil {
    91  		return env.supportedArchitectures, nil
    92  	}
    93  	cfg := env.Ecfg()
    94  	// Create a filter to get all images from our region and for the correct stream.
    95  	cloudSpec := simplestreams.CloudSpec{
    96  		Region:   cfg.Region(),
    97  		Endpoint: cfg.SdcUrl(),
    98  	}
    99  	imageConstraint := imagemetadata.NewImageConstraint(simplestreams.LookupParams{
   100  		CloudSpec: cloudSpec,
   101  		Stream:    cfg.ImageStream(),
   102  	})
   103  	var err error
   104  	env.supportedArchitectures, err = common.SupportedArchitectures(env, imageConstraint)
   105  	return env.supportedArchitectures, err
   106  }
   107  
   108  func (env *joyentEnviron) SetConfig(cfg *config.Config) error {
   109  	env.lock.Lock()
   110  	defer env.lock.Unlock()
   111  	ecfg, err := providerInstance.newConfig(cfg)
   112  	if err != nil {
   113  		return err
   114  	}
   115  	env.ecfg = ecfg
   116  	return nil
   117  }
   118  
   119  func (env *joyentEnviron) Config() *config.Config {
   120  	return env.Ecfg().Config
   121  }
   122  
   123  func (env *joyentEnviron) Bootstrap(ctx environs.BootstrapContext, args environs.BootstrapParams) (*environs.BootstrapResult, error) {
   124  	return common.Bootstrap(ctx, env, args)
   125  }
   126  
   127  func (env *joyentEnviron) ControllerInstances() ([]instance.Id, error) {
   128  	instanceIds := []instance.Id{}
   129  
   130  	filter := cloudapi.NewFilter()
   131  	filter.Set(tagKey("group"), "juju")
   132  	filter.Set(tagKey("model"), env.Config().Name())
   133  	filter.Set(tagKey(tags.JujuModel), env.Config().UUID())
   134  	filter.Set(tagKey(tags.JujuIsController), "true")
   135  
   136  	machines, err := env.compute.cloudapi.ListMachines(filter)
   137  	if err != nil || len(machines) == 0 {
   138  		return nil, environs.ErrNotBootstrapped
   139  	}
   140  
   141  	for _, m := range machines {
   142  		if strings.EqualFold(m.State, "provisioning") || strings.EqualFold(m.State, "running") {
   143  			copy := m
   144  			ji := &joyentInstance{machine: &copy, env: env}
   145  			instanceIds = append(instanceIds, ji.Id())
   146  		}
   147  	}
   148  
   149  	return instanceIds, nil
   150  }
   151  
   152  func (env *joyentEnviron) Destroy() error {
   153  	return errors.Trace(common.Destroy(env))
   154  }
   155  
   156  func (env *joyentEnviron) Ecfg() *environConfig {
   157  	env.lock.Lock()
   158  	defer env.lock.Unlock()
   159  	return env.ecfg
   160  }
   161  
   162  // MetadataLookupParams returns parameters which are used to query simplestreams metadata.
   163  func (env *joyentEnviron) MetadataLookupParams(region string) (*simplestreams.MetadataLookupParams, error) {
   164  	if region == "" {
   165  		region = env.Ecfg().Region()
   166  	}
   167  	return &simplestreams.MetadataLookupParams{
   168  		Series:        config.PreferredSeries(env.Ecfg()),
   169  		Region:        region,
   170  		Endpoint:      env.Ecfg().sdcUrl(),
   171  		Architectures: []string{"amd64", "armhf"},
   172  	}, nil
   173  }
   174  
   175  // Region is specified in the HasRegion interface.
   176  func (env *joyentEnviron) Region() (simplestreams.CloudSpec, error) {
   177  	return simplestreams.CloudSpec{
   178  		Region:   env.Ecfg().Region(),
   179  		Endpoint: env.Ecfg().sdcUrl(),
   180  	}, nil
   181  }