github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/provider/azure/environprovider.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package azure 5 6 import ( 7 "github.com/Azure/azure-sdk-for-go/Godeps/_workspace/src/github.com/Azure/go-autorest/autorest" 8 "github.com/juju/errors" 9 "github.com/juju/loggo" 10 "github.com/juju/utils/clock" 11 12 "github.com/juju/juju/cloud" 13 "github.com/juju/juju/environs" 14 "github.com/juju/juju/environs/config" 15 "github.com/juju/juju/provider/azure/internal/azurestorage" 16 ) 17 18 // Logger for the Azure provider. 19 var logger = loggo.GetLogger("juju.provider.azure") 20 21 // ProviderConfig contains configuration for the Azure providers. 22 type ProviderConfig struct { 23 // Sender is the autorest.Sender that will be used by Azure 24 // clients. If sender is nil, the default HTTP client sender 25 // will be used. 26 Sender autorest.Sender 27 28 // RequestInspector will be used to inspect Azure requests 29 // if it is non-nil. 30 RequestInspector autorest.PrepareDecorator 31 32 // NewStorageClient will be used to construct new storage 33 // clients. 34 NewStorageClient azurestorage.NewClientFunc 35 36 // StorageAccountNameGenerator is a function returning storage 37 // account names. 38 StorageAccountNameGenerator func() string 39 40 // RetryClock is used when retrying API calls due to rate-limiting. 41 RetryClock clock.Clock 42 } 43 44 // Validate validates the Azure provider configuration. 45 func (cfg ProviderConfig) Validate() error { 46 if cfg.NewStorageClient == nil { 47 return errors.NotValidf("nil NewStorageClient") 48 } 49 if cfg.StorageAccountNameGenerator == nil { 50 return errors.NotValidf("nil StorageAccountNameGenerator") 51 } 52 if cfg.RetryClock == nil { 53 return errors.NotValidf("nil RetryClock") 54 } 55 return nil 56 } 57 58 type azureEnvironProvider struct { 59 environProviderCredentials 60 61 config ProviderConfig 62 } 63 64 // NewEnvironProvider returns a new EnvironProvider for Azure. 65 func NewEnvironProvider(config ProviderConfig) (*azureEnvironProvider, error) { 66 if err := config.Validate(); err != nil { 67 return nil, errors.Annotate(err, "validating environ provider configuration") 68 } 69 return &azureEnvironProvider{config: config}, nil 70 } 71 72 // Open is specified in the EnvironProvider interface. 73 func (prov *azureEnvironProvider) Open(cfg *config.Config) (environs.Environ, error) { 74 logger.Debugf("opening model %q", cfg.Name()) 75 environ, err := newEnviron(prov, cfg) 76 if err != nil { 77 return nil, errors.Annotate(err, "opening model") 78 } 79 return environ, nil 80 } 81 82 // RestrictedConfigAttributes is specified in the EnvironProvider interface. 83 // 84 // The result of RestrictedConfigAttributes is the names of attributes that 85 // will be copied across to a hosted environment's initial configuration. 86 func (prov *azureEnvironProvider) RestrictedConfigAttributes() []string { 87 // TODO(axw) there should be no restricted attributes. 88 return []string{ 89 configAttrLocation, 90 configAttrEndpoint, 91 configAttrStorageEndpoint, 92 } 93 } 94 95 // PrepareForCreateEnvironment is specified in the EnvironProvider interface. 96 func (prov *azureEnvironProvider) PrepareForCreateEnvironment(cfg *config.Config) (*config.Config, error) { 97 env, err := newEnviron(prov, cfg) 98 if err != nil { 99 return nil, errors.Annotate(err, "opening model") 100 } 101 return env.initResourceGroup() 102 } 103 104 // BootstrapConfig is specified in the EnvironProvider interface. 105 func (prov *azureEnvironProvider) BootstrapConfig(args environs.BootstrapConfigParams) (*config.Config, error) { 106 // Ensure that internal configuration is not specified, and then set 107 // what we can now. We only need to do this during bootstrap. Validate 108 // will check for changes later. 109 unknownAttrs := args.Config.UnknownAttrs() 110 for _, key := range internalConfigAttributes { 111 if _, ok := unknownAttrs[key]; ok { 112 return nil, errors.Errorf(`internal config %q must not be specified`, key) 113 } 114 } 115 116 attrs := map[string]interface{}{ 117 configAttrLocation: args.CloudRegion, 118 configAttrEndpoint: args.CloudEndpoint, 119 configAttrStorageEndpoint: args.CloudStorageEndpoint, 120 } 121 switch authType := args.Credentials.AuthType(); authType { 122 case cloud.UserPassAuthType: 123 for k, v := range args.Credentials.Attributes() { 124 attrs[k] = v 125 } 126 default: 127 return nil, errors.NotSupportedf("%q auth-type", authType) 128 } 129 cfg, err := args.Config.Apply(attrs) 130 if err != nil { 131 return nil, errors.Annotate(err, "updating config") 132 } 133 return cfg, nil 134 } 135 136 // PrepareForBootstrap is specified in the EnvironProvider interface. 137 func (prov *azureEnvironProvider) PrepareForBootstrap(ctx environs.BootstrapContext, cfg *config.Config) (environs.Environ, error) { 138 env, err := prov.Open(cfg) 139 if err != nil { 140 return nil, errors.Trace(err) 141 } 142 if ctx.ShouldVerifyCredentials() { 143 if err := verifyCredentials(env.(*azureEnviron)); err != nil { 144 return nil, errors.Trace(err) 145 } 146 } 147 return env, nil 148 } 149 150 // SecretAttrs is specified in the EnvironProvider interface. 151 func (prov *azureEnvironProvider) SecretAttrs(cfg *config.Config) (map[string]string, error) { 152 unknownAttrs := cfg.UnknownAttrs() 153 secretAttrs := map[string]string{ 154 configAttrAppPassword: unknownAttrs[configAttrAppPassword].(string), 155 } 156 if storageAccountKey, ok := unknownAttrs[configAttrStorageAccountKey].(string); ok { 157 secretAttrs[configAttrStorageAccountKey] = storageAccountKey 158 } 159 return secretAttrs, nil 160 } 161 162 // verifyCredentials issues a cheap, non-modifying request to Azure to 163 // verify the configured credentials. If verification fails, a user-friendly 164 // error will be returned, and the original error will be logged at debug 165 // level. 166 var verifyCredentials = func(e *azureEnviron) error { 167 e.mu.Lock() 168 defer e.mu.Unlock() 169 // TODO(axw) user-friendly error message 170 return e.config.token.EnsureFresh() 171 }