github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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/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/environs" 13 "github.com/juju/juju/environs/config" 14 "github.com/juju/juju/provider/azure/internal/azureauth" 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 // RetryClock is used when retrying API calls due to rate-limiting. 37 RetryClock clock.Clock 38 39 // RandomWindowsAdminPassword is a function used to generate 40 // a random password for the Windows admin user. 41 RandomWindowsAdminPassword func() string 42 43 // InteractiveCreateServicePrincipal is a function used to 44 // interactively create/update service principals with 45 // password credentials. 46 InteractiveCreateServicePrincipal azureauth.InteractiveCreateServicePrincipalFunc 47 } 48 49 // Validate validates the Azure provider configuration. 50 func (cfg ProviderConfig) Validate() error { 51 if cfg.NewStorageClient == nil { 52 return errors.NotValidf("nil NewStorageClient") 53 } 54 if cfg.RetryClock == nil { 55 return errors.NotValidf("nil RetryClock") 56 } 57 if cfg.RandomWindowsAdminPassword == nil { 58 return errors.NotValidf("nil RandomWindowsAdminPassword") 59 } 60 if cfg.InteractiveCreateServicePrincipal == nil { 61 return errors.NotValidf("nil InteractiveCreateServicePrincipal") 62 } 63 return nil 64 } 65 66 type azureEnvironProvider struct { 67 environProviderCredentials 68 69 config ProviderConfig 70 } 71 72 // NewEnvironProvider returns a new EnvironProvider for Azure. 73 func NewEnvironProvider(config ProviderConfig) (*azureEnvironProvider, error) { 74 if err := config.Validate(); err != nil { 75 return nil, errors.Annotate(err, "validating environ provider configuration") 76 } 77 return &azureEnvironProvider{ 78 environProviderCredentials: environProviderCredentials{ 79 sender: config.Sender, 80 requestInspector: config.RequestInspector, 81 interactiveCreateServicePrincipal: config.InteractiveCreateServicePrincipal, 82 }, 83 config: config, 84 }, nil 85 } 86 87 // Open is part of the EnvironProvider interface. 88 func (prov *azureEnvironProvider) Open(args environs.OpenParams) (environs.Environ, error) { 89 logger.Debugf("opening model %q", args.Config.Name()) 90 if err := validateCloudSpec(args.Cloud); err != nil { 91 return nil, errors.Annotate(err, "validating cloud spec") 92 } 93 environ, err := newEnviron(prov, args.Cloud, args.Config) 94 if err != nil { 95 return nil, errors.Annotate(err, "opening model") 96 } 97 return environ, nil 98 } 99 100 // PrepareConfig is part of the EnvironProvider interface. 101 func (prov *azureEnvironProvider) PrepareConfig(args environs.PrepareConfigParams) (*config.Config, error) { 102 if err := validateCloudSpec(args.Cloud); err != nil { 103 return nil, errors.Annotate(err, "validating cloud spec") 104 } 105 return args.Config, nil 106 } 107 108 func validateCloudSpec(spec environs.CloudSpec) error { 109 if err := spec.Validate(); err != nil { 110 return errors.Trace(err) 111 } 112 if spec.Credential == nil { 113 return errors.NotValidf("missing credential") 114 } 115 if authType := spec.Credential.AuthType(); authType != clientCredentialsAuthType { 116 return errors.NotSupportedf("%q auth-type", authType) 117 } 118 return nil 119 } 120 121 // verifyCredentials issues a cheap, non-modifying request to Azure to 122 // verify the configured credentials. If verification fails, a user-friendly 123 // error will be returned, and the original error will be logged at debug 124 // level. 125 var verifyCredentials = func(e *azureEnviron) error { 126 // TODO(axw) user-friendly error message 127 return e.authorizer.refresh() 128 }