github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/provider/ec2/provider.go (about)

     1  // Copyright 2011-2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package ec2
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/loggo"
    11  	"github.com/juju/utils"
    12  	"github.com/juju/utils/arch"
    13  	"gopkg.in/amz.v3/ec2"
    14  
    15  	"github.com/juju/juju/environs"
    16  	"github.com/juju/juju/environs/config"
    17  	"github.com/juju/juju/environs/simplestreams"
    18  )
    19  
    20  var logger = loggo.GetLogger("juju.provider.ec2")
    21  
    22  type environProvider struct{}
    23  
    24  var providerInstance environProvider
    25  
    26  func (environProvider) BoilerplateConfig() string {
    27  	return boilerplateConfig[1:]
    28  }
    29  
    30  // RestrictedConfigAttributes is specified in the EnvironProvider interface.
    31  func (p environProvider) RestrictedConfigAttributes() []string {
    32  	return []string{"region"}
    33  }
    34  
    35  // PrepareForCreateEnvironment is specified in the EnvironProvider interface.
    36  func (p environProvider) PrepareForCreateEnvironment(cfg *config.Config) (*config.Config, error) {
    37  	attrs := cfg.UnknownAttrs()
    38  	if _, ok := attrs["control-bucket"]; !ok {
    39  		uuid, err := utils.NewUUID()
    40  		if err != nil {
    41  			return nil, errors.Trace(err)
    42  		}
    43  		attrs["control-bucket"] = fmt.Sprintf("%x", uuid.Raw())
    44  	}
    45  	return cfg.Apply(attrs)
    46  }
    47  
    48  func (p environProvider) Open(cfg *config.Config) (environs.Environ, error) {
    49  	logger.Infof("opening environment %q", cfg.Name())
    50  	e := new(environ)
    51  	e.name = cfg.Name()
    52  	err := e.SetConfig(cfg)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  	return e, nil
    57  }
    58  
    59  func (p environProvider) PrepareForBootstrap(ctx environs.BootstrapContext, cfg *config.Config) (environs.Environ, error) {
    60  	cfg, err := p.PrepareForCreateEnvironment(cfg)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  	e, err := p.Open(cfg)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  	if ctx.ShouldVerifyCredentials() {
    69  		if err := verifyCredentials(e.(*environ)); err != nil {
    70  			return nil, err
    71  		}
    72  	}
    73  	return e, nil
    74  }
    75  
    76  func (environProvider) Validate(cfg, old *config.Config) (valid *config.Config, err error) {
    77  	newEcfg, err := validateConfig(cfg, old)
    78  	if err != nil {
    79  		return nil, fmt.Errorf("invalid EC2 provider config: %v", err)
    80  	}
    81  	return newEcfg.Apply(newEcfg.attrs)
    82  }
    83  
    84  // MetadataLookupParams returns parameters which are used to query image metadata to
    85  // find matching image information.
    86  func (p environProvider) MetadataLookupParams(region string) (*simplestreams.MetadataLookupParams, error) {
    87  	if region == "" {
    88  		return nil, fmt.Errorf("region must be specified")
    89  	}
    90  	ec2Region, ok := allRegions[region]
    91  	if !ok {
    92  		return nil, fmt.Errorf("unknown region %q", region)
    93  	}
    94  	return &simplestreams.MetadataLookupParams{
    95  		Region:        region,
    96  		Endpoint:      ec2Region.EC2Endpoint,
    97  		Architectures: arch.AllSupportedArches,
    98  	}, nil
    99  }
   100  
   101  func (environProvider) SecretAttrs(cfg *config.Config) (map[string]string, error) {
   102  	m := make(map[string]string)
   103  	ecfg, err := providerInstance.newConfig(cfg)
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	m["access-key"] = ecfg.accessKey()
   108  	m["secret-key"] = ecfg.secretKey()
   109  	return m, nil
   110  }
   111  
   112  const badAccessKey = `
   113  Please ensure the Access Key ID you have specified is correct.
   114  You can obtain the Access Key ID via the "Security Credentials"
   115  page in the AWS console.`
   116  
   117  const badSecretKey = `
   118  Please ensure the Secret Access Key you have specified is correct.
   119  You can obtain the Secret Access Key via the "Security Credentials"
   120  page in the AWS console.`
   121  
   122  // verifyCredentials issues a cheap, non-modifying/idempotent request to EC2 to
   123  // verify the configured credentials. If verification fails, a user-friendly
   124  // error will be returned, and the original error will be logged at debug
   125  // level.
   126  var verifyCredentials = func(e *environ) error {
   127  	_, err := e.ec2().AccountAttributes()
   128  	if err != nil {
   129  		logger.Debugf("ec2 request failed: %v", err)
   130  		if err, ok := err.(*ec2.Error); ok {
   131  			switch err.Code {
   132  			case "AuthFailure":
   133  				return errors.New("authentication failed.\n" + badAccessKey)
   134  			case "SignatureDoesNotMatch":
   135  				return errors.New("authentication failed.\n" + badSecretKey)
   136  			default:
   137  				return err
   138  			}
   139  		}
   140  		return err
   141  	}
   142  	return nil
   143  }