github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/provider/vmware/config.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package vmware
     5  
     6  import (
     7  	"fmt"
     8  	"net/url"
     9  
    10  	"github.com/juju/errors"
    11  	"github.com/juju/schema"
    12  
    13  	"github.com/juju/juju/environs/config"
    14  )
    15  
    16  // The vmware-specific config keys.
    17  const (
    18  	cfgDatastore    = "datastore"
    19  	cfgDatacenter   = "datacenter"
    20  	cfgResourcePool = "resource-pool"
    21  	cfgHost         = "host"
    22  	cfgUser         = "user"
    23  	cfgPassword     = "password"
    24  )
    25  
    26  // boilerplateConfig will be shown in help output, so please keep it up to
    27  // date when you change environment configuration below.
    28  var boilerplateConfig = `
    29  vmware:
    30  //  Some description
    31  `[1:]
    32  
    33  // configFields is the spec for each vmware config value's type.
    34  var configFields = schema.Fields{
    35  	cfgHost:         schema.String(),
    36  	cfgUser:         schema.String(),
    37  	cfgPassword:     schema.String(),
    38  	cfgDatastore:    schema.String(),
    39  	cfgDatacenter:   schema.String(),
    40  	cfgResourcePool: schema.String(),
    41  }
    42  
    43  var configDefaults = schema.Defaults{}
    44  
    45  var configSecretFields = []string{
    46  	cfgPassword,
    47  }
    48  
    49  var configImmutableFields = []string{
    50  	cfgHost,
    51  	cfgDatacenter,
    52  	cfgDatastore,
    53  	cfgResourcePool,
    54  }
    55  
    56  type environConfig struct {
    57  	*config.Config
    58  	attrs map[string]interface{}
    59  }
    60  
    61  // newConfig builds a new environConfig from the provided Config and
    62  // returns it.
    63  func newConfig(cfg *config.Config) *environConfig {
    64  	return &environConfig{
    65  		Config: cfg,
    66  		attrs:  cfg.UnknownAttrs(),
    67  	}
    68  }
    69  
    70  // prepareConfig builds a new environConfig from the provided Config and
    71  // returns it. The resulting config values are validated.
    72  func prepareConfig(cfg *config.Config) (*environConfig, error) {
    73  	// Finish the config.
    74  	ecfg, err := newValidConfig(cfg, configDefaults)
    75  	return ecfg, errors.Trace(err)
    76  }
    77  
    78  // newValidConfig builds a new environConfig from the provided Config
    79  // and returns it. The resulting config values are validated.
    80  func newValidConfig(cfg *config.Config, defaults map[string]interface{}) (*environConfig, error) {
    81  	// Ensure that the provided config is valid.
    82  	if err := config.Validate(cfg, nil); err != nil {
    83  		return nil, errors.Trace(err)
    84  	}
    85  
    86  	// Apply the defaults and coerce/validate the custom config attrs.
    87  	validated, err := cfg.ValidateUnknownAttrs(configFields, defaults)
    88  	if err != nil {
    89  		return nil, errors.Trace(err)
    90  	}
    91  	validCfg, err := cfg.Apply(validated)
    92  	if err != nil {
    93  		return nil, errors.Trace(err)
    94  	}
    95  
    96  	// Build the config.
    97  	ecfg := newConfig(validCfg)
    98  
    99  	// Do final validation.
   100  	if err := ecfg.validate(); err != nil {
   101  		return nil, errors.Trace(err)
   102  	}
   103  
   104  	return ecfg, nil
   105  }
   106  
   107  func (c *environConfig) datastore() string {
   108  	return c.attrs[cfgDatastore].(string)
   109  }
   110  
   111  func (c *environConfig) datacenter() string {
   112  	return c.attrs[cfgDatacenter].(string)
   113  }
   114  
   115  func (c *environConfig) resourcePool() string {
   116  	return c.attrs[cfgResourcePool].(string)
   117  }
   118  
   119  func (c *environConfig) host() string {
   120  	return c.attrs[cfgHost].(string)
   121  }
   122  
   123  func (c *environConfig) user() string {
   124  	return c.attrs[cfgUser].(string)
   125  }
   126  
   127  func (c *environConfig) password() string {
   128  	return c.attrs[cfgPassword].(string)
   129  }
   130  
   131  func (c *environConfig) url() (*url.URL, error) {
   132  	return url.Parse(fmt.Sprintf("https://%s:%s@%s/sdk", c.user(), c.password(), c.host()))
   133  }
   134  
   135  // secret gathers the "secret" config values and returns them.
   136  func (c *environConfig) secret() map[string]string {
   137  	secretAttrs := make(map[string]string, len(configSecretFields))
   138  	for _, key := range configSecretFields {
   139  		secretAttrs[key] = c.attrs[key].(string)
   140  	}
   141  	return secretAttrs
   142  }
   143  
   144  // validate checks vmware-specific config values.
   145  func (c environConfig) validate() error {
   146  	// All fields must be populated, even with just the default.
   147  	for field := range configFields {
   148  		if c.attrs[field].(string) == "" {
   149  			return errors.Errorf("%s: must not be empty", field)
   150  		}
   151  	}
   152  	if _, err := c.url(); err != nil {
   153  		return errors.Trace(err)
   154  	}
   155  
   156  	return nil
   157  }
   158  
   159  // update applies changes from the provided config to the env config.
   160  // Changes to any immutable attributes result in an error.
   161  func (c *environConfig) update(cfg *config.Config) error {
   162  	// Validate the updates. newValidConfig does not modify the "known"
   163  	// config attributes so it is safe to call Validate here first.
   164  	if err := config.Validate(cfg, c.Config); err != nil {
   165  		return errors.Trace(err)
   166  	}
   167  
   168  	updates, err := newValidConfig(cfg, configDefaults)
   169  	if err != nil {
   170  		return errors.Trace(err)
   171  	}
   172  
   173  	// Check that no immutable fields have changed.
   174  	attrs := updates.UnknownAttrs()
   175  	for _, field := range configImmutableFields {
   176  		if attrs[field] != c.attrs[field] {
   177  			return errors.Errorf("%s: cannot change from %v to %v", field, c.attrs[field], attrs[field])
   178  		}
   179  	}
   180  
   181  	// Apply the updates.
   182  	c.Config = cfg
   183  	c.attrs = cfg.UnknownAttrs()
   184  	return nil
   185  }