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 }