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  }