github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/provider/ec2/config_test.go (about) 1 // Copyright 2011, 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package ec2 5 6 // TODO: Clean this up so it matches environs/openstack/config_test.go. 7 8 import ( 9 "io/ioutil" 10 "os" 11 "path/filepath" 12 "strings" 13 14 jc "github.com/juju/testing/checkers" 15 "github.com/juju/utils" 16 "gopkg.in/amz.v3/aws" 17 gc "gopkg.in/check.v1" 18 19 "github.com/juju/juju/cloud" 20 "github.com/juju/juju/environs" 21 "github.com/juju/juju/environs/config" 22 "github.com/juju/juju/testing" 23 ) 24 25 // Use local suite since this file lives in the ec2 package 26 // for testing internals. 27 type ConfigSuite struct { 28 testing.BaseSuite 29 savedHome, savedAccessKey, savedSecretKey string 30 } 31 32 var _ = gc.Suite(&ConfigSuite{}) 33 34 var configTestRegion = aws.Region{ 35 Name: "configtest", 36 EC2Endpoint: "testregion.nowhere:1234", 37 } 38 39 var testAuth = aws.Auth{ 40 AccessKey: "gopher", 41 SecretKey: "long teeth", 42 } 43 44 // configTest specifies a config parsing test, checking that env when 45 // parsed as the ec2 section of a config file matches baseConfigResult 46 // when mutated by the mutate function, or that the parse matches the 47 // given error. 48 type configTest struct { 49 config map[string]interface{} 50 change map[string]interface{} 51 expect map[string]interface{} 52 region string 53 vpcID string 54 forceVPCID bool 55 accessKey string 56 secretKey string 57 firewallMode string 58 blockStorageSource string 59 err string 60 } 61 62 type attrs map[string]interface{} 63 64 func (t configTest) check(c *gc.C) { 65 attrs := testing.FakeConfig().Merge(testing.Attrs{ 66 "type": "ec2", 67 }).Merge(t.config) 68 cfg, err := config.New(config.NoDefaults, attrs) 69 c.Assert(err, jc.ErrorIsNil) 70 e, err := environs.New(cfg) 71 if t.change != nil { 72 c.Assert(err, jc.ErrorIsNil) 73 74 // Testing a change in configuration. 75 var old, changed, valid *config.Config 76 ec2env := e.(*environ) 77 old = ec2env.ecfg().Config 78 changed, err = old.Apply(t.change) 79 c.Assert(err, jc.ErrorIsNil) 80 81 // Keep err for validation below. 82 valid, err = providerInstance.Validate(changed, old) 83 if err == nil { 84 err = ec2env.SetConfig(valid) 85 } 86 } 87 if t.err != "" { 88 c.Check(err, gc.ErrorMatches, t.err) 89 return 90 } 91 c.Assert(err, jc.ErrorIsNil) 92 93 ecfg := e.(*environ).ecfg() 94 c.Assert(ecfg.Name(), gc.Equals, "testenv") 95 if t.region != "" { 96 c.Assert(ecfg.region(), gc.Equals, t.region) 97 } 98 99 c.Assert(ecfg.vpcID(), gc.Equals, t.vpcID) 100 c.Assert(ecfg.forceVPCID(), gc.Equals, t.forceVPCID) 101 102 if t.accessKey != "" { 103 c.Assert(ecfg.accessKey(), gc.Equals, t.accessKey) 104 c.Assert(ecfg.secretKey(), gc.Equals, t.secretKey) 105 expected := map[string]string{ 106 "access-key": t.accessKey, 107 "secret-key": t.secretKey, 108 } 109 c.Assert(err, jc.ErrorIsNil) 110 actual, err := e.Provider().SecretAttrs(ecfg.Config) 111 c.Assert(err, jc.ErrorIsNil) 112 c.Assert(expected, gc.DeepEquals, actual) 113 } else { 114 c.Assert(ecfg.accessKey(), gc.DeepEquals, testAuth.AccessKey) 115 c.Assert(ecfg.secretKey(), gc.DeepEquals, testAuth.SecretKey) 116 } 117 if t.firewallMode != "" { 118 c.Assert(ecfg.FirewallMode(), gc.Equals, t.firewallMode) 119 } 120 for name, expect := range t.expect { 121 actual, found := ecfg.UnknownAttrs()[name] 122 c.Check(found, jc.IsTrue) 123 c.Check(actual, gc.Equals, expect) 124 } 125 } 126 127 var configTests = []configTest{ 128 { 129 config: attrs{}, 130 }, { 131 // check that region defaults to us-east-1 132 config: attrs{}, 133 region: "us-east-1", 134 }, { 135 config: attrs{ 136 "region": "eu-west-1", 137 }, 138 region: "eu-west-1", 139 }, { 140 config: attrs{ 141 "region": "unknown", 142 }, 143 err: ".*invalid region name.*", 144 }, { 145 config: attrs{ 146 "region": "configtest", 147 }, 148 region: "configtest", 149 }, { 150 config: attrs{ 151 "region": "configtest", 152 }, 153 change: attrs{ 154 "region": "us-east-1", 155 }, 156 err: `.*cannot change region from "configtest" to "us-east-1"`, 157 }, { 158 config: attrs{ 159 "region": 666, 160 }, 161 err: `.*expected string, got int\(666\)`, 162 }, { 163 config: attrs{}, 164 vpcID: "", 165 forceVPCID: false, 166 }, { 167 config: attrs{ 168 "vpc-id": "invalid", 169 }, 170 err: `.*vpc-id: "invalid" is not a valid AWS VPC ID`, 171 vpcID: "", 172 forceVPCID: false, 173 }, { 174 config: attrs{ 175 "vpc-id": 42, 176 }, 177 err: `.*expected string, got int\(42\)`, 178 vpcID: "", 179 forceVPCID: false, 180 }, { 181 config: attrs{ 182 "vpc-id-force": "nonsense", 183 }, 184 err: `.*expected bool, got string\("nonsense"\)`, 185 vpcID: "", 186 forceVPCID: false, 187 }, { 188 config: attrs{ 189 "vpc-id": "vpc-anything", 190 "vpc-id-force": 999, 191 }, 192 err: `.*expected bool, got int\(999\)`, 193 vpcID: "", 194 forceVPCID: false, 195 }, { 196 config: attrs{ 197 "vpc-id": "", 198 "vpc-id-force": true, 199 }, 200 err: `.*cannot use vpc-id-force without specifying vpc-id as well`, 201 vpcID: "", 202 forceVPCID: true, 203 }, { 204 config: attrs{ 205 "vpc-id": "vpc-a1b2c3d4", 206 }, 207 vpcID: "vpc-a1b2c3d4", 208 forceVPCID: false, 209 }, { 210 config: attrs{ 211 "vpc-id": "vpc-some-id", 212 "vpc-id-force": true, 213 }, 214 vpcID: "vpc-some-id", 215 forceVPCID: true, 216 }, { 217 config: attrs{ 218 "vpc-id": "vpc-abcd", 219 "vpc-id-force": false, 220 }, 221 vpcID: "vpc-abcd", 222 forceVPCID: false, 223 }, { 224 config: attrs{ 225 "vpc-id": "vpc-unchanged", 226 "vpc-id-force": true, 227 }, 228 change: attrs{ 229 "vpc-id": "vpc-unchanged", 230 "vpc-id-force": false, 231 }, 232 err: `.*cannot change vpc-id-force from true to false`, 233 vpcID: "vpc-unchanged", 234 forceVPCID: true, 235 }, { 236 config: attrs{ 237 "vpc-id": "", 238 }, 239 change: attrs{ 240 "vpc-id": "vpc-changed", 241 }, 242 err: `.*cannot change vpc-id from "" to "vpc-changed"`, 243 vpcID: "", 244 forceVPCID: false, 245 }, { 246 config: attrs{ 247 "vpc-id": "vpc-initial", 248 }, 249 change: attrs{ 250 "vpc-id": "", 251 }, 252 err: `.*cannot change vpc-id from "vpc-initial" to ""`, 253 vpcID: "vpc-initial", 254 forceVPCID: false, 255 }, { 256 config: attrs{ 257 "vpc-id": "vpc-old", 258 }, 259 change: attrs{ 260 "vpc-id": "vpc-new", 261 }, 262 err: `.*cannot change vpc-id from "vpc-old" to "vpc-new"`, 263 vpcID: "vpc-old", 264 forceVPCID: false, 265 }, { 266 config: attrs{ 267 "vpc-id": "vpc-foo", 268 "vpc-id-force": true, 269 }, 270 change: attrs{}, 271 vpcID: "vpc-foo", 272 forceVPCID: true, 273 }, { 274 config: attrs{ 275 "access-key": 666, 276 }, 277 err: `.*expected string, got int\(666\)`, 278 }, { 279 config: attrs{ 280 "secret-key": 666, 281 }, 282 err: `.*expected string, got int\(666\)`, 283 }, { 284 config: attrs{ 285 "access-key": "jujuer", 286 "secret-key": "open sesame", 287 }, 288 accessKey: "jujuer", 289 secretKey: "open sesame", 290 }, { 291 config: attrs{ 292 "access-key": "jujuer", 293 }, 294 err: ".*model has no access-key or secret-key", 295 }, { 296 config: attrs{ 297 "secret-key": "badness", 298 }, 299 err: ".*model has no access-key or secret-key", 300 }, { 301 config: attrs{ 302 "admin-secret": "Futumpsh", 303 }, 304 }, { 305 config: attrs{}, 306 firewallMode: config.FwInstance, 307 }, { 308 config: attrs{}, 309 blockStorageSource: "ebs", 310 }, { 311 config: attrs{ 312 "storage-default-block-source": "ebs-fast", 313 }, 314 blockStorageSource: "ebs-fast", 315 }, { 316 config: attrs{ 317 "firewall-mode": "instance", 318 }, 319 firewallMode: config.FwInstance, 320 }, { 321 config: attrs{ 322 "firewall-mode": "global", 323 }, 324 firewallMode: config.FwGlobal, 325 }, { 326 config: attrs{ 327 "firewall-mode": "none", 328 }, 329 firewallMode: config.FwNone, 330 }, { 331 config: attrs{ 332 "ssl-hostname-verification": false, 333 }, 334 err: ".*disabling ssh-hostname-verification is not supported", 335 }, { 336 config: attrs{ 337 "future": "hammerstein", 338 }, 339 expect: attrs{ 340 "future": "hammerstein", 341 }, 342 }, { 343 change: attrs{ 344 "future": "hammerstein", 345 }, 346 expect: attrs{ 347 "future": "hammerstein", 348 }, 349 }, 350 } 351 352 func indent(s string, with string) string { 353 var r string 354 lines := strings.Split(s, "\n") 355 for _, l := range lines { 356 r += with + l + "\n" 357 } 358 return r 359 } 360 361 func (s *ConfigSuite) SetUpTest(c *gc.C) { 362 s.BaseSuite.SetUpTest(c) 363 s.savedHome = utils.Home() 364 s.savedAccessKey = os.Getenv("AWS_ACCESS_KEY_ID") 365 s.savedSecretKey = os.Getenv("AWS_SECRET_ACCESS_KEY") 366 367 home := c.MkDir() 368 sshDir := filepath.Join(home, ".ssh") 369 err := os.Mkdir(sshDir, 0777) 370 c.Assert(err, jc.ErrorIsNil) 371 err = ioutil.WriteFile(filepath.Join(sshDir, "id_rsa.pub"), []byte("sshkey\n"), 0666) 372 c.Assert(err, jc.ErrorIsNil) 373 374 err = utils.SetHome(home) 375 c.Assert(err, jc.ErrorIsNil) 376 os.Setenv("AWS_ACCESS_KEY_ID", testAuth.AccessKey) 377 os.Setenv("AWS_SECRET_ACCESS_KEY", testAuth.SecretKey) 378 aws.Regions["configtest"] = configTestRegion 379 } 380 381 func (s *ConfigSuite) TearDownTest(c *gc.C) { 382 err := utils.SetHome(s.savedHome) 383 c.Assert(err, jc.ErrorIsNil) 384 os.Setenv("AWS_ACCESS_KEY_ID", s.savedAccessKey) 385 os.Setenv("AWS_SECRET_ACCESS_KEY", s.savedSecretKey) 386 delete(aws.Regions, "configtest") 387 s.BaseSuite.TearDownTest(c) 388 } 389 390 func (s *ConfigSuite) TestConfig(c *gc.C) { 391 for i, t := range configTests { 392 c.Logf("test %d: %v", i, t.config) 393 t.check(c) 394 } 395 } 396 397 func (s *ConfigSuite) TestMissingAuth(c *gc.C) { 398 os.Setenv("AWS_ACCESS_KEY_ID", "") 399 os.Setenv("AWS_SECRET_ACCESS_KEY", "") 400 401 // Since PR #52 amz.v3 uses these AWS_ vars as fallbacks, if set. 402 os.Setenv("AWS_ACCESS_KEY", "") 403 os.Setenv("AWS_SECRET_KEY", "") 404 405 // Since LP r37 goamz uses also these EC2_ as fallbacks, so unset them too. 406 os.Setenv("EC2_ACCESS_KEY", "") 407 os.Setenv("EC2_SECRET_KEY", "") 408 test := configTests[0] 409 test.err = ".*model has no access-key or secret-key" 410 test.check(c) 411 } 412 413 func (s *ConfigSuite) TestBootstrapConfigSetsDefaultBlockSource(c *gc.C) { 414 s.PatchValue(&verifyCredentials, func(*environ) error { return nil }) 415 attrs := testing.FakeConfig().Merge(testing.Attrs{ 416 "type": "ec2", 417 }) 418 cfg, err := config.New(config.NoDefaults, attrs) 419 c.Assert(err, jc.ErrorIsNil) 420 421 cfg, err = providerInstance.BootstrapConfig(environs.BootstrapConfigParams{ 422 Config: cfg, 423 Credentials: cloud.NewCredential( 424 cloud.AccessKeyAuthType, 425 map[string]string{ 426 "access-key": "x", 427 "secret-key": "y", 428 }, 429 ), 430 CloudRegion: "test", 431 }) 432 c.Assert(err, jc.ErrorIsNil) 433 source, ok := cfg.StorageDefaultBlockSource() 434 c.Assert(ok, jc.IsTrue) 435 c.Assert(source, gc.Equals, "ebs") 436 } 437 438 func (s *ConfigSuite) TestPrepareSetsDefaultBlockSource(c *gc.C) { 439 s.PatchValue(&verifyCredentials, func(*environ) error { return nil }) 440 attrs := testing.FakeConfig().Merge(testing.Attrs{ 441 "type": "ec2", 442 }) 443 config, err := config.New(config.NoDefaults, attrs) 444 c.Assert(err, jc.ErrorIsNil) 445 446 cfg, err := providerInstance.BootstrapConfig(environs.BootstrapConfigParams{ 447 Config: config, 448 CloudRegion: "test", 449 Credentials: cloud.NewCredential( 450 cloud.AccessKeyAuthType, 451 map[string]string{ 452 "access-key": "x", 453 "secret-key": "y", 454 }, 455 ), 456 }) 457 c.Assert(err, jc.ErrorIsNil) 458 459 source, ok := cfg.StorageDefaultBlockSource() 460 c.Assert(ok, jc.IsTrue) 461 c.Assert(source, gc.Equals, "ebs") 462 } 463 464 func (*ConfigSuite) TestSchema(c *gc.C) { 465 fields := providerInstance.Schema() 466 // Check that all the fields defined in environs/config 467 // are in the returned schema. 468 globalFields, err := config.Schema(nil) 469 c.Assert(err, gc.IsNil) 470 for name, field := range globalFields { 471 c.Check(fields[name], jc.DeepEquals, field) 472 } 473 }