github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/provider/cloudsigma/config.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package cloudsigma 5 6 import ( 7 "github.com/altoros/gosigma" 8 "github.com/juju/errors" 9 "github.com/juju/schema" 10 "github.com/juju/utils" 11 12 "github.com/juju/juju/environs/config" 13 ) 14 15 // boilerplateConfig will be shown in help output, so please keep it up to 16 // date when you change environment configuration below. 17 var boilerplateConfig = `# https://juju.ubuntu.com/docs/config-cloudsigma.html 18 cloudsigma: 19 type: cloudsigma 20 21 # region holds the cloudsigma region (zrh, lvs, ...). 22 # 23 # region: <your region> 24 25 # credentials for CloudSigma account 26 # 27 # username: <your username> 28 # password: <secret> 29 ` 30 31 const ( 32 defaultStoragePort = 8040 33 ) 34 35 var configFields = schema.Fields{ 36 "username": schema.String(), 37 "password": schema.String(), 38 "region": schema.String(), 39 } 40 41 var configDefaultFields = schema.Defaults{ 42 "username": "", 43 "password": "", 44 "region": gosigma.DefaultRegion, 45 } 46 47 var configSecretFields = []string{ 48 "password", 49 } 50 51 var configImmutableFields = []string{ 52 "region", 53 } 54 55 func prepareConfig(cfg *config.Config) (*config.Config, error) { 56 // Turn an incomplete config into a valid one, if possible. 57 attrs := cfg.AllAttrs() 58 59 if _, ok := attrs["uuid"]; !ok { 60 uuid, err := utils.NewUUID() 61 if err != nil { 62 return nil, errors.Trace(err) 63 } 64 attrs["uuid"] = uuid.String() 65 } 66 67 return cfg.Apply(attrs) 68 } 69 70 func validateConfig(cfg *config.Config, old *environConfig) (*environConfig, error) { 71 // Check sanity of juju-level fields. 72 var oldCfg *config.Config 73 if old != nil { 74 oldCfg = old.Config 75 } 76 if err := config.Validate(cfg, oldCfg); err != nil { 77 return nil, errors.Trace(err) 78 } 79 80 // Extract validated provider-specific fields. All of configFields will be 81 // present in validated, and defaults will be inserted if necessary. If the 82 // schema you passed in doesn't quite express what you need, you can make 83 // whatever checks you need here, before continuing. 84 // In particular, if you want to extract (say) credentials from the user's 85 // shell environment variables, you'll need to allow missing values to pass 86 // through the schema by setting a value of schema.Omit in the configFields 87 // map, and then to set and check them at this point. These values *must* be 88 // stored in newAttrs: a Config will be generated on the user's machine only 89 // to begin with, and will subsequently be used on a different machine that 90 // will probably not have those variables set. 91 newAttrs, err := cfg.ValidateUnknownAttrs(configFields, configDefaultFields) 92 if err != nil { 93 return nil, errors.Trace(err) 94 } 95 for field := range configFields { 96 if newAttrs[field] == "" { 97 return nil, errors.Errorf("%s: must not be empty", field) 98 } 99 } 100 101 // If an old config was supplied, check any immutable fields have not changed. 102 if old != nil { 103 for _, field := range configImmutableFields { 104 if old.attrs[field] != newAttrs[field] { 105 return nil, errors.Errorf( 106 "%s: cannot change from %v to %v", 107 field, old.attrs[field], newAttrs[field], 108 ) 109 } 110 } 111 } 112 113 // Merge the validated provider-specific fields into the original config, 114 // to ensure the object we return is internally consistent. 115 newCfg, err := cfg.Apply(newAttrs) 116 if err != nil { 117 return nil, errors.Trace(err) 118 } 119 ecfg := &environConfig{ 120 Config: newCfg, 121 attrs: newAttrs, 122 } 123 124 return ecfg, nil 125 } 126 127 // configChanged checks if CloudSigma client environment configuration is changed 128 func (c environConfig) clientConfigChanged(newConfig *environConfig) bool { 129 // compare 130 if newConfig.region() != c.region() || newConfig.username() != c.username() || 131 newConfig.password() != c.password() { 132 return true 133 } 134 135 return false 136 } 137 138 type environConfig struct { 139 *config.Config 140 attrs map[string]interface{} 141 } 142 143 func (c environConfig) region() string { 144 return c.attrs["region"].(string) 145 } 146 147 func (c environConfig) username() string { 148 return c.attrs["username"].(string) 149 } 150 151 func (c environConfig) password() string { 152 return c.attrs["password"].(string) 153 }