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