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  }