launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/provider/joyent/config.go (about) 1 // Copyright 2013 Joyent Inc. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package joyent 5 6 import ( 7 "fmt" 8 "os" 9 10 "launchpad.net/juju-core/environs/config" 11 "launchpad.net/juju-core/schema" 12 "launchpad.net/juju-core/utils" 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 const boilerplateConfig = `joyent: 18 type: joyent 19 20 # SDC config 21 # Can be set via env variables, or specified here 22 # sdc-user: <secret> 23 # Can be set via env variables, or specified here 24 # sdc-key-id: <secret> 25 # region defaults to us-west-1, override if required 26 # sdc-region: us-west-1 27 28 # Manta config 29 # Can be set via env variables, or specified here 30 # manta-user: <secret> 31 # Can be set via env variables, or specified here 32 # manta-key-id: <secret> 33 # region defaults to us-east, override if required 34 # manta-region: us-east 35 ` 36 37 const ( 38 SdcAccount = "SDC_ACCOUNT" 39 SdcKeyId = "SDC_KEY_ID" 40 SdcUrl = "SDC_URL" 41 MantaUser = "MANTA_USER" 42 MantaKeyId = "MANTA_KEY_ID" 43 MantaUrl = "MANTA_URL" 44 ) 45 46 var environmentVariables = map[string]string{ 47 "sdc-user": SdcAccount, 48 "sdc-key-id": SdcKeyId, 49 "manta-user": MantaUser, 50 "manta-key-id": MantaKeyId, 51 } 52 53 var configFields = schema.Fields{ 54 "sdc-user": schema.String(), 55 "sdc-key-id": schema.String(), 56 "sdc-region": schema.String(), 57 "manta-user": schema.String(), 58 "manta-key-id": schema.String(), 59 "manta-region": schema.String(), 60 "control-dir": schema.String(), 61 } 62 63 var configDefaultFields = schema.Defaults{ 64 "sdc-region": "us-west-1", 65 "manta-region": "us-east", 66 } 67 68 var configSecretFields = []string{ 69 "sdc-user", 70 "sdc-key-id", 71 "manta-user", 72 "manta-key-id", 73 } 74 75 var configImmutableFields = []string{ 76 "sdc-region", 77 "manta-region", 78 } 79 80 func prepareConfig(cfg *config.Config) (*config.Config, error) { 81 // Turn an incomplete config into a valid one, if possible. 82 attrs := cfg.UnknownAttrs() 83 84 if _, ok := attrs["control-dir"]; !ok { 85 uuid, err := utils.NewUUID() 86 if err != nil { 87 return nil, err 88 } 89 attrs["control-bucket"] = fmt.Sprintf("%x", uuid.Raw()) 90 } 91 92 // Read env variables 93 for _, field := range configSecretFields { 94 // If field is not set, get it from env variables 95 if attrs[field] == "" { 96 localEnvVariable := os.Getenv(environmentVariables[field]) 97 if localEnvVariable != "" { 98 attrs[field] = localEnvVariable 99 } else { 100 return nil, fmt.Errorf("cannot get %s value from environment variables %s", field, environmentVariables[field]) 101 } 102 } 103 } 104 105 return cfg.Apply(attrs) 106 } 107 108 func validateConfig(cfg *config.Config, old *environConfig) (*environConfig, error) { 109 // Check sanity of juju-level fields. 110 var oldCfg *config.Config 111 if old != nil { 112 oldCfg = old.Config 113 } 114 if err := config.Validate(cfg, oldCfg); err != nil { 115 return nil, err 116 } 117 118 // Extract validated provider-specific fields. All of configFields will be 119 // present in validated, and defaults will be inserted if necessary. If the 120 // schema you passed in doesn't quite express what you need, you can make 121 // whatever checks you need here, before continuing. 122 // In particular, if you want to extract (say) credentials from the user's 123 // shell environment variables, you'll need to allow missing values to pass 124 // through the schema by setting a value of schema.Omit in the configFields 125 // map, and then to set and check them at this point. These values *must* be 126 // stored in newAttrs: a Config will be generated on the user's machine only 127 // to begin with, and will subsequently be used on a different machine that 128 // will probably not have those variables set. 129 newAttrs, err := cfg.ValidateUnknownAttrs(configFields, configDefaultFields) 130 if err != nil { 131 return nil, err 132 } 133 for field := range configFields { 134 if newAttrs[field] == "" { 135 return nil, fmt.Errorf("%s: must not be empty", field) 136 } 137 } 138 139 // If an old config was supplied, check any immutable fields have not changed. 140 if old != nil { 141 for _, field := range configImmutableFields { 142 if old.attrs[field] != newAttrs[field] { 143 return nil, fmt.Errorf( 144 "%s: cannot change from %v to %v", 145 field, old.attrs[field], newAttrs[field], 146 ) 147 } 148 } 149 } 150 151 // Merge the validated provider-specific fields into the original config, 152 // to ensure the object we return is internally consistent. 153 newCfg, err := cfg.Apply(newAttrs) 154 if err != nil { 155 return nil, err 156 } 157 return &environConfig{ 158 Config: newCfg, 159 attrs: newAttrs, 160 }, nil 161 } 162 163 type environConfig struct { 164 *config.Config 165 attrs map[string]interface{} 166 } 167 168 func (ecfg *environConfig) sdcRegion() string { 169 return ecfg.attrs["sdc-region"].(string) 170 } 171 172 func (ecfg *environConfig) sdcUser() string { 173 return ecfg.attrs["sdc-user"].(string) 174 } 175 176 func (ecfg *environConfig) sdcKeyId() string { 177 return ecfg.attrs["sdc-key-id"].(string) 178 } 179 180 func (ecfg *environConfig) mantaRegion() string { 181 return ecfg.attrs["manta-region"].(string) 182 } 183 184 func (ecfg *environConfig) mantaUser() string { 185 return ecfg.attrs["manta-user"].(string) 186 } 187 188 func (ecfg *environConfig) mantaKeyId() string { 189 return ecfg.attrs["manta-key-id"].(string) 190 } 191 192 func (c *environConfig) controlDir() string { 193 return c.attrs["control-dir"].(string) 194 }