github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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/arch" 12 "gopkg.in/amz.v3/ec2" 13 14 "github.com/juju/juju/cloud" 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 environProviderCredentials 24 } 25 26 var providerInstance environProvider 27 28 // RestrictedConfigAttributes is specified in the EnvironProvider interface. 29 func (p environProvider) RestrictedConfigAttributes() []string { 30 return []string{"region"} 31 } 32 33 // PrepareForCreateEnvironment is specified in the EnvironProvider interface. 34 func (p environProvider) PrepareForCreateEnvironment(cfg *config.Config) (*config.Config, error) { 35 return cfg, nil 36 } 37 38 // Open is specified in the EnvironProvider interface. 39 func (p environProvider) Open(cfg *config.Config) (environs.Environ, error) { 40 logger.Infof("opening model %q", cfg.Name()) 41 e := new(environ) 42 e.name = cfg.Name() 43 err := e.SetConfig(cfg) 44 if err != nil { 45 return nil, err 46 } 47 return e, nil 48 } 49 50 // BootstrapConfig is specified in the EnvironProvider interface. 51 func (p environProvider) BootstrapConfig(args environs.BootstrapConfigParams) (*config.Config, error) { 52 // Add credentials to the configuration. 53 attrs := map[string]interface{}{ 54 "region": args.CloudRegion, 55 // TODO(axw) stop relying on hard-coded 56 // region endpoint information 57 // in the provider, and use 58 // args.CloudEndpoint here. 59 } 60 switch authType := args.Credentials.AuthType(); authType { 61 case cloud.AccessKeyAuthType: 62 credentialAttrs := args.Credentials.Attributes() 63 attrs["access-key"] = credentialAttrs["access-key"] 64 attrs["secret-key"] = credentialAttrs["secret-key"] 65 default: 66 return nil, errors.NotSupportedf("%q auth-type", authType) 67 } 68 69 // Set the default block-storage source. 70 if _, ok := args.Config.StorageDefaultBlockSource(); !ok { 71 attrs[config.StorageDefaultBlockSourceKey] = EBS_ProviderType 72 } 73 74 cfg, err := args.Config.Apply(attrs) 75 if err != nil { 76 return nil, errors.Trace(err) 77 } 78 return p.PrepareForCreateEnvironment(cfg) 79 } 80 81 // PrepareForBootstrap is specified in the EnvironProvider interface. 82 func (p environProvider) PrepareForBootstrap( 83 ctx environs.BootstrapContext, 84 cfg *config.Config, 85 ) (environs.Environ, error) { 86 e, err := p.Open(cfg) 87 if err != nil { 88 return nil, err 89 } 90 if ctx.ShouldVerifyCredentials() { 91 if err := verifyCredentials(e.(*environ)); err != nil { 92 return nil, err 93 } 94 } 95 return e, nil 96 } 97 98 // Validate is specified in the EnvironProvider interface. 99 func (environProvider) Validate(cfg, old *config.Config) (valid *config.Config, err error) { 100 newEcfg, err := validateConfig(cfg, old) 101 if err != nil { 102 return nil, fmt.Errorf("invalid EC2 provider config: %v", err) 103 } 104 return newEcfg.Apply(newEcfg.attrs) 105 } 106 107 // MetadataLookupParams returns parameters which are used to query image metadata to 108 // find matching image information. 109 func (p environProvider) MetadataLookupParams(region string) (*simplestreams.MetadataLookupParams, error) { 110 if region == "" { 111 return nil, fmt.Errorf("region must be specified") 112 } 113 ec2Region, ok := allRegions[region] 114 if !ok { 115 return nil, fmt.Errorf("unknown region %q", region) 116 } 117 return &simplestreams.MetadataLookupParams{ 118 Region: region, 119 Endpoint: ec2Region.EC2Endpoint, 120 Architectures: arch.AllSupportedArches, 121 }, nil 122 } 123 124 // SecretAttrs is specified in the EnvironProvider interface. 125 func (environProvider) SecretAttrs(cfg *config.Config) (map[string]string, error) { 126 m := make(map[string]string) 127 ecfg, err := providerInstance.newConfig(cfg) 128 if err != nil { 129 return nil, err 130 } 131 m["access-key"] = ecfg.accessKey() 132 m["secret-key"] = ecfg.secretKey() 133 return m, nil 134 } 135 136 const badAccessKey = ` 137 Please ensure the Access Key ID you have specified is correct. 138 You can obtain the Access Key ID via the "Security Credentials" 139 page in the AWS console.` 140 141 const badSecretKey = ` 142 Please ensure the Secret Access Key you have specified is correct. 143 You can obtain the Secret Access Key via the "Security Credentials" 144 page in the AWS console.` 145 146 // verifyCredentials issues a cheap, non-modifying/idempotent request to EC2 to 147 // verify the configured credentials. If verification fails, a user-friendly 148 // error will be returned, and the original error will be logged at debug 149 // level. 150 var verifyCredentials = func(e *environ) error { 151 _, err := e.ec2().AccountAttributes() 152 if err != nil { 153 logger.Debugf("ec2 request failed: %v", err) 154 if err, ok := err.(*ec2.Error); ok { 155 switch err.Code { 156 case "AuthFailure": 157 return errors.New("authentication failed.\n" + badAccessKey) 158 case "SignatureDoesNotMatch": 159 return errors.New("authentication failed.\n" + badSecretKey) 160 default: 161 return err 162 } 163 } 164 return err 165 } 166 return nil 167 }