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