github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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/names" 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 41 // Validate validates the Azure provider configuration. 42 func (cfg ProviderConfig) Validate() error { 43 if cfg.NewStorageClient == nil { 44 return errors.NotValidf("nil NewStorageClient") 45 } 46 if cfg.StorageAccountNameGenerator == nil { 47 return errors.NotValidf("nil StorageAccountNameGenerator") 48 } 49 return nil 50 } 51 52 type azureEnvironProvider struct { 53 environProviderCredentials 54 55 config ProviderConfig 56 } 57 58 // NewEnvironProvider returns a new EnvironProvider for Azure. 59 func NewEnvironProvider(config ProviderConfig) (*azureEnvironProvider, error) { 60 if err := config.Validate(); err != nil { 61 return nil, errors.Annotate(err, "validating environ provider configuration") 62 } 63 return &azureEnvironProvider{config: config}, nil 64 } 65 66 // Open is specified in the EnvironProvider interface. 67 func (prov *azureEnvironProvider) Open(cfg *config.Config) (environs.Environ, error) { 68 logger.Debugf("opening model %q", cfg.Name()) 69 environ, err := newEnviron(prov, cfg) 70 if err != nil { 71 return nil, errors.Annotate(err, "opening model") 72 } 73 return environ, nil 74 } 75 76 // RestrictedConfigAttributes is specified in the EnvironProvider interface. 77 // 78 // The result of RestrictedConfigAttributes is the names of attributes that 79 // will be copied across to a hosted environment's initial configuration. 80 func (prov *azureEnvironProvider) RestrictedConfigAttributes() []string { 81 return []string{ 82 configAttrLocation, 83 configAttrEndpoint, 84 configAttrControllerResourceGroup, 85 configAttrStorageEndpoint, 86 } 87 } 88 89 // PrepareForCreateEnvironment is specified in the EnvironProvider interface. 90 func (prov *azureEnvironProvider) PrepareForCreateEnvironment(cfg *config.Config) (*config.Config, error) { 91 env, err := newEnviron(prov, cfg) 92 if err != nil { 93 return nil, errors.Annotate(err, "opening model") 94 } 95 return env.initResourceGroup() 96 } 97 98 // BootstrapConfig is specified in the EnvironProvider interface. 99 func (prov *azureEnvironProvider) BootstrapConfig(args environs.BootstrapConfigParams) (*config.Config, error) { 100 // Ensure that internal configuration is not specified, and then set 101 // what we can now. We only need to do this during bootstrap. Validate 102 // will check for changes later. 103 unknownAttrs := args.Config.UnknownAttrs() 104 for _, key := range internalConfigAttributes { 105 if _, ok := unknownAttrs[key]; ok { 106 return nil, errors.Errorf(`internal config %q must not be specified`, key) 107 } 108 } 109 110 attrs := map[string]interface{}{ 111 configAttrLocation: args.CloudRegion, 112 configAttrEndpoint: args.CloudEndpoint, 113 configAttrStorageEndpoint: args.CloudStorageEndpoint, 114 115 // Record the UUID that will be used for the controller 116 // model, which contains shared resources. 117 configAttrControllerResourceGroup: resourceGroupName( 118 names.NewModelTag(args.Config.UUID()), 119 args.Config.Name(), 120 ), 121 } 122 switch authType := args.Credentials.AuthType(); authType { 123 case cloud.UserPassAuthType: 124 for k, v := range args.Credentials.Attributes() { 125 attrs[k] = v 126 } 127 default: 128 return nil, errors.NotSupportedf("%q auth-type", authType) 129 } 130 cfg, err := args.Config.Apply(attrs) 131 if err != nil { 132 return nil, errors.Annotate(err, "updating config") 133 } 134 return cfg, nil 135 } 136 137 // PrepareForBootstrap is specified in the EnvironProvider interface. 138 func (prov *azureEnvironProvider) PrepareForBootstrap(ctx environs.BootstrapContext, cfg *config.Config) (environs.Environ, error) { 139 env, err := prov.Open(cfg) 140 if err != nil { 141 return nil, errors.Trace(err) 142 } 143 if ctx.ShouldVerifyCredentials() { 144 if err := verifyCredentials(env.(*azureEnviron)); err != nil { 145 return nil, errors.Trace(err) 146 } 147 } 148 return env, nil 149 } 150 151 // SecretAttrs is specified in the EnvironProvider interface. 152 func (prov *azureEnvironProvider) SecretAttrs(cfg *config.Config) (map[string]string, error) { 153 unknownAttrs := cfg.UnknownAttrs() 154 secretAttrs := map[string]string{ 155 configAttrAppPassword: unknownAttrs[configAttrAppPassword].(string), 156 } 157 if storageAccountKey, ok := unknownAttrs[configAttrStorageAccountKey].(string); ok { 158 secretAttrs[configAttrStorageAccountKey] = storageAccountKey 159 } 160 return secretAttrs, nil 161 } 162 163 // verifyCredentials issues a cheap, non-modifying request to Azure to 164 // verify the configured credentials. If verification fails, a user-friendly 165 // error will be returned, and the original error will be logged at debug 166 // level. 167 var verifyCredentials = func(e *azureEnviron) error { 168 e.mu.Lock() 169 defer e.mu.Unlock() 170 // TODO(axw) user-friendly error message 171 return e.config.token.EnsureFresh() 172 }