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  }