github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/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  // boilerplateConfig will be shown in help output, so please keep it up to
    28  // date when you change environment configuration below.
    29  var boilerplateConfig = `
    30  vmware:
    31    type: vsphere
    32  
    33    # IP address or DNS name of vsphere API host.
    34    host:
    35  
    36    # Vsphere API user credentials.
    37    user:
    38    password:
    39  
    40    # Name of vsphere datacenter.
    41    datacenter:
    42  
    43    # Name of the network, that all created vms will use ot obtain public ip address. 
    44    # This network should have ip pool configured or DHCP server connected to it.
    45    # This parameter is optional. 
    46    extenal-network:
    47  `[1:]
    48  
    49  // configFields is the spec for each vmware config value's type.
    50  var configFields = schema.Fields{
    51  	cfgHost:            schema.String(),
    52  	cfgUser:            schema.String(),
    53  	cfgPassword:        schema.String(),
    54  	cfgDatacenter:      schema.String(),
    55  	cfgExternalNetwork: schema.String(),
    56  }
    57  
    58  var requiredFields = []string{
    59  	cfgHost,
    60  	cfgUser,
    61  	cfgPassword,
    62  	cfgDatacenter,
    63  }
    64  
    65  var configDefaults = schema.Defaults{
    66  	cfgExternalNetwork: "",
    67  }
    68  
    69  var configSecretFields = []string{
    70  	cfgPassword,
    71  }
    72  
    73  var configImmutableFields = []string{
    74  	cfgHost,
    75  	cfgDatacenter,
    76  }
    77  
    78  type environConfig struct {
    79  	*config.Config
    80  	attrs map[string]interface{}
    81  }
    82  
    83  // newConfig builds a new environConfig from the provided Config and
    84  // returns it.
    85  func newConfig(cfg *config.Config) *environConfig {
    86  	return &environConfig{
    87  		Config: cfg,
    88  		attrs:  cfg.UnknownAttrs(),
    89  	}
    90  }
    91  
    92  // newValidConfig builds a new environConfig from the provided Config
    93  // and returns it. The resulting config values are validated.
    94  func newValidConfig(cfg *config.Config, defaults map[string]interface{}) (*environConfig, error) {
    95  	// Ensure that the provided config is valid.
    96  	if err := config.Validate(cfg, nil); err != nil {
    97  		return nil, errors.Trace(err)
    98  	}
    99  
   100  	// Apply the defaults and coerce/validate the custom config attrs.
   101  	validated, err := cfg.ValidateUnknownAttrs(configFields, defaults)
   102  	if err != nil {
   103  		return nil, errors.Trace(err)
   104  	}
   105  	validCfg, err := cfg.Apply(validated)
   106  	if err != nil {
   107  		return nil, errors.Trace(err)
   108  	}
   109  
   110  	// Build the config.
   111  	ecfg := newConfig(validCfg)
   112  
   113  	// Do final validation.
   114  	if err := ecfg.validate(); err != nil {
   115  		return nil, errors.Trace(err)
   116  	}
   117  
   118  	return ecfg, nil
   119  }
   120  
   121  func (c *environConfig) datacenter() string {
   122  	return c.attrs[cfgDatacenter].(string)
   123  }
   124  
   125  func (c *environConfig) host() string {
   126  	return c.attrs[cfgHost].(string)
   127  }
   128  
   129  func (c *environConfig) user() string {
   130  	return c.attrs[cfgUser].(string)
   131  }
   132  
   133  func (c *environConfig) password() string {
   134  	return c.attrs[cfgPassword].(string)
   135  }
   136  
   137  func (c *environConfig) externalNetwork() string {
   138  	return c.attrs[cfgExternalNetwork].(string)
   139  }
   140  
   141  func (c *environConfig) url() (*url.URL, error) {
   142  	return url.Parse(fmt.Sprintf("https://%s:%s@%s/sdk", c.user(), c.password(), c.host()))
   143  }
   144  
   145  // secret gathers the "secret" config values and returns them.
   146  func (c *environConfig) secret() map[string]string {
   147  	secretAttrs := make(map[string]string, len(configSecretFields))
   148  	for _, key := range configSecretFields {
   149  		secretAttrs[key] = c.attrs[key].(string)
   150  	}
   151  	return secretAttrs
   152  }
   153  
   154  // validate checks vmware-specific config values.
   155  func (c environConfig) validate() error {
   156  	// All fields must be populated, even with just the default.
   157  	for _, field := range requiredFields {
   158  		if c.attrs[field].(string) == "" {
   159  			return errors.Errorf("%s: must not be empty", field)
   160  		}
   161  	}
   162  	if _, err := c.url(); err != nil {
   163  		return errors.Trace(err)
   164  	}
   165  
   166  	return nil
   167  }
   168  
   169  // update applies changes from the provided config to the env config.
   170  // Changes to any immutable attributes result in an error.
   171  func (c *environConfig) update(cfg *config.Config) error {
   172  	// Validate the updates. newValidConfig does not modify the "known"
   173  	// config attributes so it is safe to call Validate here first.
   174  	if err := config.Validate(cfg, c.Config); err != nil {
   175  		return errors.Trace(err)
   176  	}
   177  
   178  	updates, err := newValidConfig(cfg, configDefaults)
   179  	if err != nil {
   180  		return errors.Trace(err)
   181  	}
   182  
   183  	// Check that no immutable fields have changed.
   184  	attrs := updates.UnknownAttrs()
   185  	for _, field := range configImmutableFields {
   186  		if attrs[field] != c.attrs[field] {
   187  			return errors.Errorf("%s: cannot change from %v to %v", field, c.attrs[field], attrs[field])
   188  		}
   189  	}
   190  
   191  	// Apply the updates.
   192  	c.Config = cfg
   193  	c.attrs = cfg.UnknownAttrs()
   194  	return nil
   195  }