github.com/rogpeppe/juju@v0.0.0-20140613142852-6337964b789e/provider/joyent/config_test.go (about) 1 // Copyright 2013 Joyent Inc. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package joyent_test 5 6 import ( 7 "fmt" 8 "io/ioutil" 9 "os" 10 11 "github.com/juju/testing" 12 "github.com/juju/utils" 13 gc "launchpad.net/gocheck" 14 15 "github.com/juju/juju/environs" 16 "github.com/juju/juju/environs/config" 17 jp "github.com/juju/juju/provider/joyent" 18 coretesting "github.com/juju/juju/testing" 19 "github.com/juju/juju/utils/ssh" 20 ) 21 22 func newConfig(c *gc.C, attrs coretesting.Attrs) *config.Config { 23 attrs = coretesting.FakeConfig().Merge(attrs) 24 cfg, err := config.New(config.UseDefaults, attrs) 25 c.Assert(err, gc.IsNil) 26 return cfg 27 } 28 29 func validAttrs() coretesting.Attrs { 30 return coretesting.FakeConfig().Merge(coretesting.Attrs{ 31 "type": "joyent", 32 "sdc-user": "juju-test", 33 "sdc-key-id": "00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff", 34 "sdc-url": "https://test.api.joyentcloud.com", 35 "manta-user": "juju-test", 36 "manta-key-id": "00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff", 37 "manta-url": "https://test.manta.joyent.com", 38 "private-key-path": "~/.ssh/provider_id_rsa", 39 "algorithm": "rsa-sha256", 40 "control-dir": "juju-test", 41 }) 42 } 43 44 type ConfigSuite struct { 45 coretesting.FakeJujuHomeSuite 46 originalValues map[string]testing.Restorer 47 privateKeyData string 48 } 49 50 var _ = gc.Suite(&ConfigSuite{}) 51 52 func (s *ConfigSuite) SetUpSuite(c *gc.C) { 53 s.FakeJujuHomeSuite.SetUpSuite(c) 54 restoreSdcAccount := testing.PatchEnvironment(jp.SdcAccount, "tester") 55 s.AddSuiteCleanup(func(*gc.C) { restoreSdcAccount() }) 56 restoreSdcKeyId := testing.PatchEnvironment(jp.SdcKeyId, "ff:ee:dd:cc:bb:aa:99:88:77:66:55:44:33:22:11:00") 57 s.AddSuiteCleanup(func(*gc.C) { restoreSdcKeyId() }) 58 restoreMantaUser := testing.PatchEnvironment(jp.MantaUser, "tester") 59 s.AddSuiteCleanup(func(*gc.C) { restoreMantaUser() }) 60 restoreMantaKeyId := testing.PatchEnvironment(jp.MantaKeyId, "ff:ee:dd:cc:bb:aa:99:88:77:66:55:44:33:22:11:00") 61 s.AddSuiteCleanup(func(*gc.C) { restoreMantaKeyId() }) 62 s.privateKeyData = generatePrivateKey(c) 63 } 64 65 func generatePrivateKey(c *gc.C) string { 66 oldBits := ssh.KeyBits 67 defer func() { 68 ssh.KeyBits = oldBits 69 }() 70 ssh.KeyBits = 32 71 private, _, err := ssh.GenerateKey("test-client") 72 c.Assert(err, gc.IsNil) 73 return private 74 } 75 76 func (s *ConfigSuite) SetUpTest(c *gc.C) { 77 s.FakeJujuHomeSuite.SetUpTest(c) 78 s.AddCleanup(CreateTestKey(c)) 79 for _, envVar := range jp.EnvironmentVariables { 80 s.PatchEnvironment(envVar, "") 81 } 82 } 83 84 var newConfigTests = []struct { 85 info string 86 insert coretesting.Attrs 87 remove []string 88 envVars map[string]string 89 expect coretesting.Attrs 90 err string 91 }{{ 92 info: "sdc-user is required", 93 remove: []string{"sdc-user"}, 94 err: ".* cannot get sdc-user value from environment variable .*", 95 }, { 96 info: "sdc-user cannot be empty", 97 insert: coretesting.Attrs{"sdc-user": ""}, 98 err: ".* cannot get sdc-user value from environment variable .*", 99 }, { 100 info: "can get sdc-user from env variable", 101 insert: coretesting.Attrs{"sdc-user": ""}, 102 expect: coretesting.Attrs{"sdc-user": "tester"}, 103 envVars: map[string]string{ 104 "SDC_ACCOUNT": "tester", 105 }, 106 }, { 107 info: "can get sdc-user from env variable, missing from config", 108 remove: []string{"sdc-user"}, 109 expect: coretesting.Attrs{"sdc-user": "tester"}, 110 envVars: map[string]string{ 111 "SDC_ACCOUNT": "tester", 112 }, 113 }, { 114 info: "sdc-key-id is required", 115 remove: []string{"sdc-key-id"}, 116 err: ".* cannot get sdc-key-id value from environment variable .*", 117 }, { 118 info: "sdc-key-id cannot be empty", 119 insert: coretesting.Attrs{"sdc-key-id": ""}, 120 err: ".* cannot get sdc-key-id value from environment variable .*", 121 }, { 122 info: "can get sdc-key-id from env variable", 123 insert: coretesting.Attrs{"sdc-key-id": ""}, 124 expect: coretesting.Attrs{"sdc-key-id": "key"}, 125 envVars: map[string]string{ 126 "SDC_KEY_ID": "key", 127 }, 128 }, { 129 info: "can get sdc-key-id from env variable, missing from config", 130 remove: []string{"sdc-key-id"}, 131 expect: coretesting.Attrs{"sdc-key-id": "key"}, 132 envVars: map[string]string{ 133 "SDC_KEY_ID": "key", 134 }, 135 }, { 136 info: "sdc-url is inserted if missing", 137 expect: coretesting.Attrs{"sdc-url": "https://test.api.joyentcloud.com"}, 138 }, { 139 info: "sdc-url cannot be empty", 140 insert: coretesting.Attrs{"sdc-url": ""}, 141 err: ".* cannot get sdc-url value from environment variable .*", 142 }, { 143 info: "sdc-url is untouched if present", 144 insert: coretesting.Attrs{"sdc-url": "https://test.api.joyentcloud.com"}, 145 expect: coretesting.Attrs{"sdc-url": "https://test.api.joyentcloud.com"}, 146 }, { 147 info: "manta-user is required", 148 remove: []string{"manta-user"}, 149 err: ".* cannot get manta-user value from environment variable .*", 150 }, { 151 info: "manta-user cannot be empty", 152 insert: coretesting.Attrs{"manta-user": ""}, 153 err: ".* cannot get manta-user value from environment variable .*", 154 }, { 155 info: "can get manta-user from env variable", 156 insert: coretesting.Attrs{"manta-user": ""}, 157 expect: coretesting.Attrs{"manta-user": "tester"}, 158 envVars: map[string]string{ 159 "MANTA_USER": "tester", 160 }, 161 }, { 162 info: "can get manta-user from env variable, missing from config", 163 remove: []string{"manta-user"}, 164 expect: coretesting.Attrs{"manta-user": "tester"}, 165 envVars: map[string]string{ 166 "MANTA_USER": "tester", 167 }, 168 }, { 169 info: "manta-key-id is required", 170 remove: []string{"manta-key-id"}, 171 err: ".* cannot get manta-key-id value from environment variable .*", 172 }, { 173 info: "manta-key-id cannot be empty", 174 insert: coretesting.Attrs{"manta-key-id": ""}, 175 err: ".* cannot get manta-key-id value from environment variable .*", 176 }, { 177 info: "can get manta-key-id from env variable", 178 insert: coretesting.Attrs{"manta-key-id": ""}, 179 expect: coretesting.Attrs{"manta-key-id": "key"}, 180 envVars: map[string]string{ 181 "MANTA_KEY_ID": "key", 182 }, 183 }, { 184 info: "can get manta-key-id from env variable, missing from config", 185 remove: []string{"manta-key-id"}, 186 expect: coretesting.Attrs{"manta-key-id": "key"}, 187 envVars: map[string]string{ 188 "MANTA_KEY_ID": "key", 189 }, 190 }, { 191 info: "manta-url is inserted if missing", 192 expect: coretesting.Attrs{"manta-url": "https://test.manta.joyent.com"}, 193 }, { 194 info: "manta-url cannot be empty", 195 insert: coretesting.Attrs{"manta-url": ""}, 196 err: ".* cannot get manta-url value from environment variable .*", 197 }, { 198 info: "manta-url is untouched if present", 199 insert: coretesting.Attrs{"manta-url": "https://test.manta.joyent.com"}, 200 expect: coretesting.Attrs{"manta-url": "https://test.manta.joyent.com"}, 201 }, { 202 info: "private-key-path is inserted if missing", 203 remove: []string{"private-key-path"}, 204 expect: coretesting.Attrs{"private-key-path": "~/.ssh/id_rsa"}, 205 }, { 206 info: "can get private-key-path from env variable", 207 insert: coretesting.Attrs{"private-key-path": ""}, 208 expect: coretesting.Attrs{"private-key-path": "some-file"}, 209 envVars: map[string]string{ 210 "MANTA_PRIVATE_KEY_FILE": "some-file", 211 }, 212 }, { 213 info: "can get private-key-path from env variable, missing from config", 214 remove: []string{"private-key-path"}, 215 expect: coretesting.Attrs{"private-key-path": "some-file"}, 216 envVars: map[string]string{ 217 "MANTA_PRIVATE_KEY_FILE": "some-file", 218 }, 219 }, { 220 info: "algorithm is inserted if missing", 221 expect: coretesting.Attrs{"algorithm": "rsa-sha256"}, 222 }, { 223 info: "algorithm cannot be empty", 224 insert: coretesting.Attrs{"algorithm": ""}, 225 err: ".* algorithm: must not be empty", 226 }, { 227 info: "unknown field is not touched", 228 insert: coretesting.Attrs{"unknown-field": 12345}, 229 expect: coretesting.Attrs{"unknown-field": 12345}, 230 }} 231 232 func (s *ConfigSuite) TestNewEnvironConfig(c *gc.C) { 233 for i, test := range newConfigTests { 234 c.Logf("test %d: %s", i, test.info) 235 for k, v := range test.envVars { 236 os.Setenv(k, v) 237 } 238 attrs := validAttrs().Merge(test.insert).Delete(test.remove...) 239 attrs["private-key"] = s.privateKeyData 240 testConfig := newConfig(c, attrs) 241 environ, err := environs.New(testConfig) 242 if test.err == "" { 243 c.Check(err, gc.IsNil) 244 if err != nil { 245 continue 246 } 247 attrs := environ.Config().AllAttrs() 248 for field, value := range test.expect { 249 c.Check(attrs[field], gc.Equals, value) 250 } 251 } else { 252 c.Check(environ, gc.IsNil) 253 c.Check(err, gc.ErrorMatches, test.err) 254 } 255 } 256 } 257 258 var changeConfigTests = []struct { 259 info string 260 insert coretesting.Attrs 261 remove []string 262 expect coretesting.Attrs 263 err string 264 }{{ 265 info: "no change, no error", 266 expect: validAttrs(), 267 }, { 268 info: "can change sdc-user", 269 insert: coretesting.Attrs{"sdc-user": "joyent_user"}, 270 expect: coretesting.Attrs{"sdc-user": "joyent_user"}, 271 }, { 272 info: "can change sdc-key-id", 273 insert: coretesting.Attrs{"sdc-key-id": "ff:ee:dd:cc:bb:aa:99:88:77:66:55:44:33:22:11:00"}, 274 expect: coretesting.Attrs{"sdc-key-id": "ff:ee:dd:cc:bb:aa:99:88:77:66:55:44:33:22:11:00"}, 275 }, { 276 info: "can change sdc-url", 277 insert: coretesting.Attrs{"sdc-url": "https://test.api.joyentcloud.com"}, 278 expect: coretesting.Attrs{"sdc-url": "https://test.api.joyentcloud.com"}, 279 }, { 280 info: "can change manta-user", 281 insert: coretesting.Attrs{"manta-user": "manta_user"}, 282 expect: coretesting.Attrs{"manta-user": "manta_user"}, 283 }, { 284 info: "can change manta-key-id", 285 insert: coretesting.Attrs{"manta-key-id": "ff:ee:dd:cc:bb:aa:99:88:77:66:55:44:33:22:11:00"}, 286 expect: coretesting.Attrs{"manta-key-id": "ff:ee:dd:cc:bb:aa:99:88:77:66:55:44:33:22:11:00"}, 287 }, { 288 info: "can change manta-url", 289 insert: coretesting.Attrs{"manta-url": "https://test.manta.joyent.com"}, 290 expect: coretesting.Attrs{"manta-url": "https://test.manta.joyent.com"}, 291 }, { 292 info: "can insert unknown field", 293 insert: coretesting.Attrs{"unknown": "ignoti"}, 294 expect: coretesting.Attrs{"unknown": "ignoti"}, 295 }} 296 297 func (s *ConfigSuite) TestValidateChange(c *gc.C) { 298 attrs := validAttrs() 299 attrs["private-key"] = s.privateKeyData 300 baseConfig := newConfig(c, attrs) 301 for i, test := range changeConfigTests { 302 c.Logf("test %d: %s", i, test.info) 303 attrs := validAttrs().Merge(test.insert).Delete(test.remove...) 304 attrs["private-key"] = s.privateKeyData 305 testConfig := newConfig(c, attrs) 306 validatedConfig, err := jp.Provider.Validate(testConfig, baseConfig) 307 if test.err == "" { 308 c.Check(err, gc.IsNil) 309 if err != nil { 310 continue 311 } 312 attrs := validatedConfig.AllAttrs() 313 for field, value := range test.expect { 314 c.Check(attrs[field], gc.Equals, value) 315 } 316 } else { 317 c.Check(validatedConfig, gc.IsNil) 318 c.Check(err, gc.ErrorMatches, "invalid config change: "+test.err) 319 } 320 } 321 } 322 323 func (s *ConfigSuite) TestSetConfig(c *gc.C) { 324 baseConfig := newConfig(c, validAttrs()) 325 for i, test := range changeConfigTests { 326 c.Logf("test %d: %s", i, test.info) 327 environ, err := environs.New(baseConfig) 328 c.Assert(err, gc.IsNil) 329 attrs := validAttrs().Merge(test.insert).Delete(test.remove...) 330 testConfig := newConfig(c, attrs) 331 err = environ.SetConfig(testConfig) 332 newAttrs := environ.Config().AllAttrs() 333 if test.err == "" { 334 c.Check(err, gc.IsNil) 335 for field, value := range test.expect { 336 c.Check(newAttrs[field], gc.Equals, value) 337 } 338 } else { 339 c.Check(err, gc.ErrorMatches, test.err) 340 for field, value := range baseConfig.UnknownAttrs() { 341 c.Check(newAttrs[field], gc.Equals, value) 342 } 343 } 344 } 345 } 346 347 func validPrepareAttrs() coretesting.Attrs { 348 return validAttrs().Delete("private-key") 349 } 350 351 var prepareConfigTests = []struct { 352 info string 353 insert coretesting.Attrs 354 remove []string 355 expect coretesting.Attrs 356 err string 357 }{{ 358 info: "All value provided, nothig to do", 359 expect: validPrepareAttrs(), 360 }, { 361 info: "private key is loaded from key file", 362 insert: coretesting.Attrs{"private-key-path": fmt.Sprintf("~/.ssh/%s", testKeyFileName)}, 363 expect: coretesting.Attrs{"private-key": testPrivateKey}, 364 }, { 365 info: "bad private-key-path errors, not panics", 366 insert: coretesting.Attrs{"private-key-path": "~/.ssh/no-such-file"}, 367 err: "invalid Joyent provider config: open .*: no such file or directory", 368 }} 369 370 func (s *ConfigSuite) TestPrepare(c *gc.C) { 371 ctx := coretesting.Context(c) 372 for i, test := range prepareConfigTests { 373 c.Logf("test %d: %s", i, test.info) 374 attrs := validPrepareAttrs().Merge(test.insert).Delete(test.remove...) 375 testConfig := newConfig(c, attrs) 376 preparedConfig, err := jp.Provider.Prepare(ctx, testConfig) 377 if test.err == "" { 378 c.Check(err, gc.IsNil) 379 attrs := preparedConfig.Config().AllAttrs() 380 for field, value := range test.expect { 381 c.Check(attrs[field], gc.Equals, value) 382 } 383 } else { 384 c.Check(preparedConfig, gc.IsNil) 385 c.Check(err, gc.ErrorMatches, test.err) 386 } 387 } 388 } 389 390 func (s *ConfigSuite) TestPrepareWithDefaultKeyFile(c *gc.C) { 391 ctx := coretesting.Context(c) 392 // By default "private-key-path isn't set until after validateConfig has been called. 393 attrs := validAttrs().Delete("private-key-path", "private-key") 394 keyFilePath, err := utils.NormalizePath(jp.DefaultPrivateKey) 395 c.Assert(err, gc.IsNil) 396 err = ioutil.WriteFile(keyFilePath, []byte(testPrivateKey), 400) 397 c.Assert(err, gc.IsNil) 398 defer os.Remove(keyFilePath) 399 testConfig := newConfig(c, attrs) 400 preparedConfig, err := jp.Provider.Prepare(ctx, testConfig) 401 c.Assert(err, gc.IsNil) 402 attrs = preparedConfig.Config().AllAttrs() 403 c.Check(attrs["private-key-path"], gc.Equals, jp.DefaultPrivateKey) 404 c.Check(attrs["private-key"], gc.Equals, testPrivateKey) 405 }