github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/provider/cloudsigma/provider.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // Juju provider for CloudSigma
     5  
     6  package cloudsigma
     7  
     8  import (
     9  	"fmt"
    10  
    11  	"github.com/juju/errors"
    12  	"github.com/juju/loggo"
    13  	"github.com/juju/utils"
    14  
    15  	"github.com/juju/juju/environs"
    16  	"github.com/juju/juju/environs/config"
    17  	"github.com/juju/juju/environs/simplestreams"
    18  	"github.com/juju/juju/storage/provider/registry"
    19  )
    20  
    21  var logger = loggo.GetLogger("juju.provider.cloudsigma")
    22  
    23  const (
    24  	providerType = "cloudsigma"
    25  )
    26  
    27  func getImageSource(env environs.Environ) (simplestreams.DataSource, error) {
    28  	e, ok := env.(*environ)
    29  	if !ok {
    30  		return nil, errors.NotSupportedf("non-cloudsigma environment")
    31  	}
    32  	return simplestreams.NewURLDataSource("cloud images", fmt.Sprintf(CloudsigmaCloudImagesURLTemplate, e.ecfg.region()), utils.VerifySSLHostnames), nil
    33  }
    34  
    35  type environProvider struct{}
    36  
    37  var providerInstance = environProvider{}
    38  
    39  // check the provider implements environs.EnvironProvider interface
    40  var _ environs.EnvironProvider = (*environProvider)(nil)
    41  
    42  func init() {
    43  	// This will only happen in binaries that actually import this provider
    44  	// somewhere. To enable a provider, import it in the "providers/all"
    45  	// package; please do *not* import individual providers anywhere else,
    46  	// except in direct tests for that provider.
    47  	environs.RegisterProvider("cloudsigma", providerInstance)
    48  	environs.RegisterImageDataSourceFunc("cloud sigma image source", getImageSource)
    49  	registry.RegisterEnvironStorageProviders(providerType)
    50  }
    51  
    52  // Boilerplate returns a default configuration for the environment in yaml format.
    53  // The text should be a key followed by some number of attributes:
    54  //    `environName:
    55  //        type: environTypeName
    56  //        attr1: val1
    57  //    `
    58  // The text is used as a template (see the template package) with one extra template
    59  // function available, rand, which expands to a random hexadecimal string when invoked.
    60  func (environProvider) BoilerplateConfig() string {
    61  	return boilerplateConfig
    62  }
    63  
    64  // Open opens the environment and returns it.
    65  // The configuration must have come from a previously
    66  // prepared environment.
    67  func (environProvider) Open(cfg *config.Config) (environs.Environ, error) {
    68  	logger.Infof("opening environment %q", cfg.Name())
    69  
    70  	cfg, err := prepareConfig(cfg)
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  
    75  	env := &environ{name: cfg.Name()}
    76  	if err := env.SetConfig(cfg); err != nil {
    77  		return nil, err
    78  	}
    79  
    80  	return env, nil
    81  }
    82  
    83  // RestrictedConfigAttributes are provider specific attributes stored in
    84  // the config that really cannot or should not be changed across
    85  // environments running inside a single juju server.
    86  func (environProvider) RestrictedConfigAttributes() []string {
    87  	return []string{"region"}
    88  }
    89  
    90  // PrepareForCreateEnvironment prepares an environment for creation. Any
    91  // additional configuration attributes are added to the config passed in
    92  // and returned.  This allows providers to add additional required config
    93  // for new environments that may be created in an existing juju server.
    94  func (environProvider) PrepareForCreateEnvironment(cfg *config.Config) (*config.Config, error) {
    95  	// Not even sure if this will ever make sense.
    96  	return nil, errors.NotImplementedf("PrepareForCreateEnvironment")
    97  }
    98  
    99  // Prepare prepares an environment for use. Any additional
   100  // configuration attributes in the returned environment should
   101  // be saved to be used later. If the environment is already
   102  // prepared, this call is equivalent to Open.
   103  func (environProvider) PrepareForBootstrap(ctx environs.BootstrapContext, cfg *config.Config) (environs.Environ, error) {
   104  	logger.Infof("preparing environment %q", cfg.Name())
   105  	return providerInstance.Open(cfg)
   106  }
   107  
   108  // Validate ensures that config is a valid configuration for this
   109  // provider, applying changes to it if necessary, and returns the
   110  // validated configuration.
   111  // If old is not nil, it holds the previous environment configuration
   112  // for consideration when validating changes.
   113  func (environProvider) Validate(cfg, old *config.Config) (*config.Config, error) {
   114  	logger.Infof("validating environment %q", cfg.Name())
   115  
   116  	// You should almost certainly not change this method; if you need to change
   117  	// how configs are validated, you should edit validateConfig itself, to ensure
   118  	// that your checks are always applied.
   119  	newEcfg, err := validateConfig(cfg, nil)
   120  	if err != nil {
   121  		return nil, errors.Errorf("invalid config: %v", err)
   122  	}
   123  	if old != nil {
   124  		oldEcfg, err := validateConfig(old, nil)
   125  		if err != nil {
   126  			return nil, errors.Errorf("invalid base config: %v", err)
   127  		}
   128  		if newEcfg, err = validateConfig(cfg, oldEcfg); err != nil {
   129  			return nil, errors.Errorf("invalid config change: %v", err)
   130  		}
   131  	}
   132  
   133  	return newEcfg.Config, nil
   134  }
   135  
   136  // SecretAttrs filters the supplied configuration returning only values
   137  // which are considered sensitive. All of the values of these secret
   138  // attributes need to be strings.
   139  func (environProvider) SecretAttrs(cfg *config.Config) (map[string]string, error) {
   140  	logger.Infof("filtering secret attributes for environment %q", cfg.Name())
   141  
   142  	// If you keep configSecretFields up to date, this method should Just Work.
   143  	ecfg, err := validateConfig(cfg, nil)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  	secretAttrs := map[string]string{}
   148  	for _, field := range configSecretFields {
   149  		if value, ok := ecfg.attrs[field]; ok {
   150  			if stringValue, ok := value.(string); ok {
   151  				secretAttrs[field] = stringValue
   152  			} else {
   153  				// All your secret attributes must be strings at the moment. Sorry.
   154  				// It's an expedient and hopefully temporary measure that helps us
   155  				// plug a security hole in the API.
   156  				return nil, errors.Errorf(
   157  					"secret %q field must have a string value; got %v",
   158  					field, value,
   159  				)
   160  			}
   161  		}
   162  	}
   163  
   164  	return secretAttrs, nil
   165  }