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 }