github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/provider/vsphere/config.go (about)

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