launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/environs/config/config_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package config_test 5 6 import ( 7 "fmt" 8 "regexp" 9 stdtesting "testing" 10 "time" 11 12 "github.com/loggo/loggo" 13 gc "launchpad.net/gocheck" 14 15 "launchpad.net/juju-core/cert" 16 "launchpad.net/juju-core/environs/config" 17 "launchpad.net/juju-core/juju/osenv" 18 "launchpad.net/juju-core/schema" 19 "launchpad.net/juju-core/testing" 20 jc "launchpad.net/juju-core/testing/checkers" 21 "launchpad.net/juju-core/testing/testbase" 22 "launchpad.net/juju-core/version" 23 ) 24 25 func Test(t *stdtesting.T) { 26 gc.TestingT(t) 27 } 28 29 type ConfigSuite struct { 30 testbase.LoggingSuite 31 home string 32 } 33 34 var _ = gc.Suite(&ConfigSuite{}) 35 36 func (s *ConfigSuite) SetUpTest(c *gc.C) { 37 s.LoggingSuite.SetUpTest(c) 38 // Make sure that the defaults are used, which 39 // is <root>=WARNING 40 loggo.ResetLoggers() 41 } 42 43 // sampleConfig holds a configuration with all required 44 // attributes set. 45 var sampleConfig = testing.Attrs{ 46 "type": "my-type", 47 "name": "my-name", 48 "authorized-keys": testing.FakeAuthKeys, 49 "firewall-mode": config.FwInstance, 50 "admin-secret": "foo", 51 "unknown": "my-unknown", 52 "ca-cert": caCert, 53 "ssl-hostname-verification": true, 54 "development": false, 55 "state-port": 1234, 56 "api-port": 4321, 57 "syslog-port": 2345, 58 "default-series": "precise", 59 } 60 61 type configTest struct { 62 about string 63 useDefaults config.Defaulting 64 attrs map[string]interface{} 65 err string 66 } 67 68 var configTests = []configTest{ 69 { 70 about: "The minimum good configuration", 71 useDefaults: config.UseDefaults, 72 attrs: testing.Attrs{ 73 "type": "my-type", 74 "name": "my-name", 75 }, 76 }, { 77 about: "Metadata URLs", 78 useDefaults: config.UseDefaults, 79 attrs: testing.Attrs{ 80 "type": "my-type", 81 "name": "my-name", 82 "image-metadata-url": "image-url", 83 "tools-metadata-url": "tools-metadata-url-value", 84 }, 85 }, { 86 about: "Deprecated tools metadata URL used", 87 useDefaults: config.UseDefaults, 88 attrs: testing.Attrs{ 89 "type": "my-type", 90 "name": "my-name", 91 "tools-url": "tools-metadata-url-value", 92 }, 93 }, { 94 about: "Deprecated tools metadata URL ignored", 95 useDefaults: config.UseDefaults, 96 attrs: testing.Attrs{ 97 "type": "my-type", 98 "name": "my-name", 99 "tools-metadata-url": "tools-metadata-url-value", 100 "tools-url": "ignore-me", 101 }, 102 }, { 103 about: "Explicit series", 104 useDefaults: config.UseDefaults, 105 attrs: testing.Attrs{ 106 "type": "my-type", 107 "name": "my-name", 108 "default-series": "my-series", 109 }, 110 }, { 111 about: "Implicit series with empty value", 112 useDefaults: config.UseDefaults, 113 attrs: testing.Attrs{ 114 "type": "my-type", 115 "name": "my-name", 116 "default-series": "", 117 }, 118 }, { 119 about: "Explicit logging", 120 useDefaults: config.UseDefaults, 121 attrs: testing.Attrs{ 122 "type": "my-type", 123 "name": "my-name", 124 "logging-config": "juju=INFO", 125 }, 126 }, { 127 about: "Explicit authorized-keys", 128 useDefaults: config.UseDefaults, 129 attrs: testing.Attrs{ 130 "type": "my-type", 131 "name": "my-name", 132 "authorized-keys": testing.FakeAuthKeys, 133 }, 134 }, { 135 about: "Load authorized-keys from path", 136 useDefaults: config.UseDefaults, 137 attrs: testing.Attrs{ 138 "type": "my-type", 139 "name": "my-name", 140 "authorized-keys-path": "~/.ssh/authorized_keys2", 141 }, 142 }, { 143 about: "CA cert & key from path", 144 useDefaults: config.UseDefaults, 145 attrs: testing.Attrs{ 146 "type": "my-type", 147 "name": "my-name", 148 "ca-cert-path": "cacert2.pem", 149 "ca-private-key-path": "cakey2.pem", 150 }, 151 }, { 152 about: "CA cert & key from path; cert attribute set too", 153 useDefaults: config.UseDefaults, 154 attrs: testing.Attrs{ 155 "type": "my-type", 156 "name": "my-name", 157 "ca-cert-path": "cacert2.pem", 158 "ca-cert": "ignored", 159 "ca-private-key-path": "cakey2.pem", 160 }, 161 }, { 162 about: "CA cert & key from ~ path", 163 useDefaults: config.UseDefaults, 164 attrs: testing.Attrs{ 165 "type": "my-type", 166 "name": "my-name", 167 "ca-cert-path": "~/othercert.pem", 168 "ca-private-key-path": "~/otherkey.pem", 169 }, 170 }, /* { 171 about: "CA cert only from ~ path", 172 useDefaults: config.UseDefaults, 173 attrs: testing.Attrs{ 174 "type": "my-type", 175 "name": "my-name", 176 "ca-cert-path": "~/othercert.pem", 177 "ca-private-key": "", 178 }, 179 }, { 180 about: "CA cert only as attribute", 181 useDefaults: config.UseDefaults, 182 attrs: testing.Attrs{ 183 "type": "my-type", 184 "name": "my-name", 185 "ca-cert": caCert, 186 "ca-private-key": "", 187 }, 188 }, */{ 189 about: "CA cert and key as attributes", 190 useDefaults: config.UseDefaults, 191 attrs: testing.Attrs{ 192 "type": "my-type", 193 "name": "my-name", 194 "ca-cert": caCert, 195 "ca-private-key": caKey, 196 }, 197 }, { 198 about: "Mismatched CA cert and key", 199 useDefaults: config.UseDefaults, 200 attrs: testing.Attrs{ 201 "type": "my-type", 202 "name": "my-name", 203 "ca-cert": caCert, 204 "ca-private-key": caKey2, 205 }, 206 err: "bad CA certificate/key in configuration: crypto/tls: private key does not match public key", 207 }, { 208 about: "Invalid CA cert", 209 useDefaults: config.UseDefaults, 210 attrs: testing.Attrs{ 211 "type": "my-type", 212 "name": "my-name", 213 "ca-cert": invalidCACert, 214 }, 215 err: `bad CA certificate/key in configuration: (asn1:|ASN\.1) syntax error:.*`, 216 }, { 217 about: "Invalid CA key", 218 useDefaults: config.UseDefaults, 219 attrs: testing.Attrs{ 220 "type": "my-type", 221 "name": "my-name", 222 "ca-cert": caCert, 223 "ca-private-key": invalidCAKey, 224 }, 225 err: "bad CA certificate/key in configuration: crypto/tls:.*", 226 }, /* { 227 about: "No CA cert or key", 228 useDefaults: config.UseDefaults, 229 attrs: testing.Attrs{ 230 "type": "my-type", 231 "name": "my-name", 232 "ca-cert": "", 233 "ca-private-key": "", 234 }, 235 }, { 236 about: "CA key but no cert", 237 useDefaults: config.UseDefaults, 238 attrs: testing.Attrs{ 239 "type": "my-type", 240 "name": "my-name", 241 "ca-cert": "", 242 "ca-private-key": caKey, 243 }, 244 err: "bad CA certificate/key in configuration: crypto/tls:.*", 245 }, { 246 about: "No CA key", 247 useDefaults: config.UseDefaults, 248 attrs: testing.Attrs{ 249 "type": "my-type", 250 "name": "my-name", 251 "ca-cert": "foo", 252 "ca-private-key": "", 253 }, 254 err: "bad CA certificate/key in configuration: no certificates found", 255 }, */{ 256 about: "CA cert specified as non-existent file", 257 useDefaults: config.UseDefaults, 258 attrs: testing.Attrs{ 259 "type": "my-type", 260 "name": "my-name", 261 "ca-cert-path": "no-such-file", 262 }, 263 err: `open .*\.juju/no-such-file: .*`, 264 }, { 265 about: "CA key specified as non-existent file", 266 useDefaults: config.UseDefaults, 267 attrs: testing.Attrs{ 268 "type": "my-type", 269 "name": "my-name", 270 "ca-private-key-path": "no-such-file", 271 }, 272 err: `open .*\.juju/no-such-file: .*`, 273 }, { 274 about: "Specified agent version", 275 useDefaults: config.UseDefaults, 276 attrs: testing.Attrs{ 277 "type": "my-type", 278 "name": "my-name", 279 "authorized-keys": testing.FakeAuthKeys, 280 "agent-version": "1.2.3", 281 }, 282 }, { 283 about: "Specified development flag", 284 useDefaults: config.UseDefaults, 285 attrs: testing.Attrs{ 286 "type": "my-type", 287 "name": "my-name", 288 "authorized-keys": testing.FakeAuthKeys, 289 "development": true, 290 }, 291 }, { 292 about: "Specified admin secret", 293 useDefaults: config.UseDefaults, 294 attrs: testing.Attrs{ 295 "type": "my-type", 296 "name": "my-name", 297 "authorized-keys": testing.FakeAuthKeys, 298 "development": false, 299 "admin-secret": "pork", 300 }, 301 }, { 302 about: "Invalid development flag", 303 useDefaults: config.UseDefaults, 304 attrs: testing.Attrs{ 305 "type": "my-type", 306 "name": "my-name", 307 "authorized-keys": testing.FakeAuthKeys, 308 "development": "invalid", 309 }, 310 err: `development: expected bool, got string\("invalid"\)`, 311 }, { 312 about: "Invalid agent version", 313 useDefaults: config.UseDefaults, 314 attrs: testing.Attrs{ 315 "type": "my-type", 316 "name": "my-name", 317 "authorized-keys": testing.FakeAuthKeys, 318 "agent-version": "2", 319 }, 320 err: `invalid agent version in environment configuration: "2"`, 321 }, { 322 about: "Missing type", 323 useDefaults: config.UseDefaults, 324 attrs: testing.Attrs{ 325 "name": "my-name", 326 }, 327 err: "type: expected string, got nothing", 328 }, { 329 about: "Empty type", 330 useDefaults: config.UseDefaults, 331 attrs: testing.Attrs{ 332 "name": "my-name", 333 "type": "", 334 }, 335 err: "empty type in environment configuration", 336 }, { 337 about: "Missing name", 338 useDefaults: config.UseDefaults, 339 attrs: testing.Attrs{ 340 "type": "my-type", 341 }, 342 err: "name: expected string, got nothing", 343 }, { 344 about: "Bad name, no slash", 345 useDefaults: config.UseDefaults, 346 attrs: testing.Attrs{ 347 "name": "foo/bar", 348 "type": "my-type", 349 }, 350 err: "environment name contains unsafe characters", 351 }, { 352 about: "Bad name, no backslash", 353 useDefaults: config.UseDefaults, 354 attrs: testing.Attrs{ 355 "name": "foo\\bar", 356 "type": "my-type", 357 }, 358 err: "environment name contains unsafe characters", 359 }, { 360 about: "Empty name", 361 useDefaults: config.UseDefaults, 362 attrs: testing.Attrs{ 363 "type": "my-type", 364 "name": "", 365 }, 366 err: "empty name in environment configuration", 367 }, { 368 about: "Default firewall mode", 369 useDefaults: config.UseDefaults, 370 attrs: testing.Attrs{ 371 "type": "my-type", 372 "name": "my-name", 373 }, 374 }, { 375 about: "Empty firewall mode", 376 useDefaults: config.UseDefaults, 377 attrs: testing.Attrs{ 378 "type": "my-type", 379 "name": "my-name", 380 "firewall-mode": "", 381 }, 382 }, { 383 about: "Instance firewall mode", 384 useDefaults: config.UseDefaults, 385 attrs: testing.Attrs{ 386 "type": "my-type", 387 "name": "my-name", 388 "firewall-mode": config.FwInstance, 389 }, 390 }, { 391 about: "Global firewall mode", 392 useDefaults: config.UseDefaults, 393 attrs: testing.Attrs{ 394 "type": "my-type", 395 "name": "my-name", 396 "firewall-mode": config.FwGlobal, 397 }, 398 }, { 399 about: "Illegal firewall mode", 400 useDefaults: config.UseDefaults, 401 attrs: testing.Attrs{ 402 "type": "my-type", 403 "name": "my-name", 404 "firewall-mode": "illegal", 405 }, 406 err: "invalid firewall mode in environment configuration: .*", 407 }, { 408 about: "ssl-hostname-verification off", 409 useDefaults: config.UseDefaults, 410 attrs: testing.Attrs{ 411 "type": "my-type", 412 "name": "my-name", 413 "ssl-hostname-verification": false, 414 }, 415 }, { 416 about: "ssl-hostname-verification incorrect", 417 useDefaults: config.UseDefaults, 418 attrs: testing.Attrs{ 419 "type": "my-type", 420 "name": "my-name", 421 "ssl-hostname-verification": "yes please", 422 }, 423 err: `ssl-hostname-verification: expected bool, got string\("yes please"\)`, 424 }, { 425 about: "provisioner-safe-mode off", 426 useDefaults: config.UseDefaults, 427 attrs: testing.Attrs{ 428 "type": "my-type", 429 "name": "my-name", 430 "provisioner-safe-mode": false, 431 }, 432 }, { 433 about: "provisioner-safe-mode on", 434 useDefaults: config.UseDefaults, 435 attrs: testing.Attrs{ 436 "type": "my-type", 437 "name": "my-name", 438 "provisioner-safe-mode": true, 439 }, 440 }, { 441 about: "provisioner-safe-mode incorrect", 442 useDefaults: config.UseDefaults, 443 attrs: testing.Attrs{ 444 "type": "my-type", 445 "name": "my-name", 446 "provisioner-safe-mode": "yes please", 447 }, 448 err: `provisioner-safe-mode: expected bool, got string\("yes please"\)`, 449 }, { 450 about: "default image stream", 451 useDefaults: config.UseDefaults, 452 attrs: testing.Attrs{ 453 "type": "my-type", 454 "name": "my-name", 455 }, 456 }, { 457 about: "explicit image stream", 458 useDefaults: config.UseDefaults, 459 attrs: testing.Attrs{ 460 "type": "my-type", 461 "name": "my-name", 462 "image-stream": "daily", 463 }, 464 }, { 465 about: "Explicit state port", 466 useDefaults: config.UseDefaults, 467 attrs: testing.Attrs{ 468 "type": "my-type", 469 "name": "my-name", 470 "state-port": 37042, 471 }, 472 }, { 473 about: "Invalid state port", 474 useDefaults: config.UseDefaults, 475 attrs: testing.Attrs{ 476 "type": "my-type", 477 "name": "my-name", 478 "state-port": "illegal", 479 }, 480 err: `state-port: expected number, got string\("illegal"\)`, 481 }, { 482 about: "Explicit API port", 483 useDefaults: config.UseDefaults, 484 attrs: testing.Attrs{ 485 "type": "my-type", 486 "name": "my-name", 487 "api-port": 77042, 488 }, 489 }, { 490 about: "Invalid API port", 491 useDefaults: config.UseDefaults, 492 attrs: testing.Attrs{ 493 "type": "my-type", 494 "name": "my-name", 495 "api-port": "illegal", 496 }, 497 err: `api-port: expected number, got string\("illegal"\)`, 498 }, { 499 about: "Explicit syslog port", 500 useDefaults: config.UseDefaults, 501 attrs: testing.Attrs{ 502 "type": "my-type", 503 "name": "my-name", 504 "syslog-port": 3456, 505 }, 506 }, { 507 about: "Invalid syslog port", 508 useDefaults: config.UseDefaults, 509 attrs: testing.Attrs{ 510 "type": "my-type", 511 "name": "my-name", 512 "syslog-port": "illegal", 513 }, 514 err: `syslog-port: expected number, got string\("illegal"\)`, 515 }, { 516 about: "Explicit bootstrap timeout", 517 useDefaults: config.UseDefaults, 518 attrs: testing.Attrs{ 519 "type": "my-type", 520 "name": "my-name", 521 "bootstrap-timeout": 300, 522 }, 523 }, { 524 about: "Invalid bootstrap timeout", 525 useDefaults: config.UseDefaults, 526 attrs: testing.Attrs{ 527 "type": "my-type", 528 "name": "my-name", 529 "bootstrap-timeout": "illegal", 530 }, 531 err: `bootstrap-timeout: expected number, got string\("illegal"\)`, 532 }, { 533 about: "Explicit bootstrap retry delay", 534 useDefaults: config.UseDefaults, 535 attrs: testing.Attrs{ 536 "type": "my-type", 537 "name": "my-name", 538 "bootstrap-retry-delay": 5, 539 }, 540 }, { 541 about: "Invalid bootstrap retry delay", 542 useDefaults: config.UseDefaults, 543 attrs: testing.Attrs{ 544 "type": "my-type", 545 "name": "my-name", 546 "bootstrap-retry-delay": "illegal", 547 }, 548 err: `bootstrap-retry-delay: expected number, got string\("illegal"\)`, 549 }, { 550 about: "Explicit bootstrap addresses delay", 551 useDefaults: config.UseDefaults, 552 attrs: testing.Attrs{ 553 "type": "my-type", 554 "name": "my-name", 555 "bootstrap-addresses-delay": 15, 556 }, 557 }, { 558 about: "Invalid bootstrap addresses delay", 559 useDefaults: config.UseDefaults, 560 attrs: testing.Attrs{ 561 "type": "my-type", 562 "name": "my-name", 563 "bootstrap-addresses-delay": "illegal", 564 }, 565 err: `bootstrap-addresses-delay: expected number, got string\("illegal"\)`, 566 }, { 567 about: "Invalid logging configuration", 568 useDefaults: config.UseDefaults, 569 attrs: testing.Attrs{ 570 "type": "my-type", 571 "name": "my-name", 572 "logging-config": "foo=bar", 573 }, 574 err: `unknown severity level "bar"`, 575 }, { 576 about: "Sample configuration", 577 useDefaults: config.UseDefaults, 578 attrs: sampleConfig, 579 }, { 580 about: "No defaults: sample configuration", 581 useDefaults: config.NoDefaults, 582 attrs: sampleConfig, 583 }, { 584 about: "No defaults: with ca-cert-path", 585 useDefaults: config.NoDefaults, 586 attrs: sampleConfig.Merge(testing.Attrs{"ca-cert-path": "arble"}), 587 err: `attribute "ca-cert-path" is not allowed in configuration`, 588 }, { 589 about: "No defaults: with ca-private-key-path", 590 useDefaults: config.NoDefaults, 591 attrs: sampleConfig.Merge(testing.Attrs{"ca-private-key-path": "arble"}), 592 err: `attribute "ca-private-key-path" is not allowed in configuration`, 593 }, { 594 about: "No defaults: with authorized-keys-path", 595 useDefaults: config.NoDefaults, 596 attrs: sampleConfig.Merge(testing.Attrs{"authorized-keys-path": "arble"}), 597 err: `attribute "authorized-keys-path" is not allowed in configuration`, 598 }, { 599 about: "No defaults: missing authorized-keys", 600 useDefaults: config.NoDefaults, 601 attrs: sampleConfig.Delete("authorized-keys"), 602 err: `authorized-keys missing from environment configuration`, 603 }, { 604 about: "Config settings from juju 1.13.3 actual installation", 605 useDefaults: config.NoDefaults, 606 attrs: map[string]interface{}{ 607 "name": "sample", 608 "development": false, 609 "admin-secret": "", 610 "ssl-hostname-verification": true, 611 "authorized-keys": "ssh-rsa mykeys rog@rog-x220\n", 612 "control-bucket": "rog-some-control-bucket", 613 "region": "us-east-1", 614 "image-metadata-url": "", 615 "ca-private-key": "", 616 "default-series": "precise", 617 "tools-metadata-url": "", 618 "secret-key": "a-secret-key", 619 "access-key": "an-access-key", 620 "agent-version": "1.13.2", 621 "ca-cert": caCert, 622 "firewall-mode": "instance", 623 "type": "ec2", 624 }, 625 }, { 626 about: "Provider type null is replaced with manual", 627 useDefaults: config.UseDefaults, 628 attrs: testing.Attrs{ 629 "type": "null", 630 "name": "my-name", 631 }, 632 }, 633 authTokenConfigTest("token=value, tokensecret=value", true), 634 authTokenConfigTest("token=value, ", true), 635 authTokenConfigTest("token=value, \ttokensecret=value", true), 636 authTokenConfigTest("", true), 637 authTokenConfigTest("token=value, tokensecret=value, \t", true), 638 authTokenConfigTest("=", false), 639 authTokenConfigTest("tokenvalue", false), 640 authTokenConfigTest("token=value, sometoken=", false), 641 authTokenConfigTest("token==value", false), 642 authTokenConfigTest(" token=value", false), 643 authTokenConfigTest("=value", false), 644 authTokenConfigTest("token=value, =z", false), 645 authTokenConfigTest("token=value =z", false), 646 authTokenConfigTest("\t", false), 647 missingAttributeNoDefault("default-series"), 648 missingAttributeNoDefault("firewall-mode"), 649 missingAttributeNoDefault("development"), 650 missingAttributeNoDefault("ssl-hostname-verification"), 651 // TODO(rog) reinstate these tests when we can lose 652 // backward compatibility with pre-1.13 config. 653 // missingAttributeNoDefault("state-port"), 654 // missingAttributeNoDefault("api-port"), 655 } 656 657 // authTokenConfigTest returns a config test that checks 658 // that a configuration with the given auth token 659 // will pass or fail, depending on the value of ok. 660 func authTokenConfigTest(token string, ok bool) configTest { 661 var testName string 662 var err string 663 664 if ok { 665 testName = fmt.Sprintf("Valid auth token test: %q", token) 666 } else { 667 testName = fmt.Sprintf("Invalid auth token test: %q", token) 668 err = fmt.Sprintf("charm store auth token needs to be a set of key-value pairs, not %q", token) 669 } 670 671 return configTest{ 672 about: testName, 673 useDefaults: config.UseDefaults, 674 attrs: sampleConfig.Merge(testing.Attrs{"charm-store-auth": token}), 675 err: regexp.QuoteMeta(err), 676 } 677 } 678 679 func missingAttributeNoDefault(attrName string) configTest { 680 return configTest{ 681 about: fmt.Sprintf("No default: missing %s", attrName), 682 useDefaults: config.NoDefaults, 683 attrs: sampleConfig.Delete(attrName), 684 err: fmt.Sprintf("%s: expected [a-z]+, got nothing", attrName), 685 } 686 } 687 688 type testFile struct { 689 name, data string 690 } 691 692 func (*ConfigSuite) TestConfig(c *gc.C) { 693 files := []testing.TestFile{ 694 {".ssh/id_dsa.pub", "dsa"}, 695 {".ssh/id_rsa.pub", "rsa\n"}, 696 {".ssh/identity.pub", "identity"}, 697 {".ssh/authorized_keys", "auth0\n# first\nauth1\n\n"}, 698 {".ssh/authorized_keys2", "auth2\nauth3\n"}, 699 700 {".juju/my-name-cert.pem", caCert}, 701 {".juju/my-name-private-key.pem", caKey}, 702 {".juju/cacert2.pem", caCert2}, 703 {".juju/cakey2.pem", caKey2}, 704 {"othercert.pem", caCert3}, 705 {"otherkey.pem", caKey3}, 706 } 707 h := testing.MakeFakeHomeWithFiles(c, files) 708 defer h.Restore() 709 for i, test := range configTests { 710 c.Logf("test %d. %s", i, test.about) 711 test.check(c, h) 712 } 713 } 714 715 var noCertFilesTests = []configTest{ 716 { 717 about: "Unspecified certificate and key", 718 useDefaults: config.UseDefaults, 719 attrs: testing.Attrs{ 720 "type": "my-type", 721 "name": "my-name", 722 "authorized-keys": testing.FakeAuthKeys, 723 }, 724 }, { 725 about: "Unspecified certificate, specified key", 726 useDefaults: config.UseDefaults, 727 attrs: testing.Attrs{ 728 "type": "my-type", 729 "name": "my-name", 730 "authorized-keys": testing.FakeAuthKeys, 731 "ca-private-key": caKey, 732 }, 733 err: "bad CA certificate/key in configuration: crypto/tls:.*", 734 }, 735 } 736 737 func (*ConfigSuite) TestConfigNoCertFiles(c *gc.C) { 738 h := testing.MakeEmptyFakeHome(c) 739 defer h.Restore() 740 for i, test := range noCertFilesTests { 741 c.Logf("test %d. %s", i, test.about) 742 test.check(c, h) 743 } 744 } 745 746 var emptyCertFilesTests = []configTest{ 747 { 748 about: "Cert unspecified; key specified", 749 useDefaults: config.UseDefaults, 750 attrs: testing.Attrs{ 751 "type": "my-type", 752 "name": "my-name", 753 "authorized-keys": testing.FakeAuthKeys, 754 "ca-private-key": caKey, 755 }, 756 err: `file ".*/my-name-cert.pem" is empty`, 757 }, { 758 about: "Cert and key unspecified", 759 useDefaults: config.UseDefaults, 760 attrs: testing.Attrs{ 761 "type": "my-type", 762 "name": "my-name", 763 "authorized-keys": testing.FakeAuthKeys, 764 }, 765 err: `file ".*/my-name-cert.pem" is empty`, 766 }, { 767 about: "Cert specified, key unspecified", 768 useDefaults: config.UseDefaults, 769 attrs: testing.Attrs{ 770 "type": "my-type", 771 "name": "my-name", 772 "authorized-keys": testing.FakeAuthKeys, 773 "ca-cert": caCert, 774 }, 775 err: `file ".*/my-name-private-key.pem" is empty`, 776 }, /* { 777 about: "Cert and key specified as absent", 778 useDefaults: config.UseDefaults, 779 attrs: testing.Attrs{ 780 "type": "my-type", 781 "name": "my-name", 782 "authorized-keys": testing.FakeAuthKeys, 783 "ca-cert": "", 784 "ca-private-key": "", 785 }, 786 }, { 787 about: "Cert specified as absent", 788 useDefaults: config.UseDefaults, 789 attrs: testing.Attrs{ 790 "type": "my-type", 791 "name": "my-name", 792 "authorized-keys": testing.FakeAuthKeys, 793 "ca-cert": "", 794 }, 795 err: "bad CA certificate/key in configuration: crypto/tls: .*", 796 }, */ 797 } 798 799 func (*ConfigSuite) TestConfigEmptyCertFiles(c *gc.C) { 800 files := []testing.TestFile{ 801 {".juju/my-name-cert.pem", ""}, 802 {".juju/my-name-private-key.pem", ""}, 803 } 804 h := testing.MakeFakeHomeWithFiles(c, files) 805 defer h.Restore() 806 807 for i, test := range emptyCertFilesTests { 808 c.Logf("test %d. %s", i, test.about) 809 test.check(c, h) 810 } 811 } 812 813 func (test configTest) check(c *gc.C, home *testing.FakeHome) { 814 cfg, err := config.New(test.useDefaults, test.attrs) 815 if test.err != "" { 816 c.Check(cfg, gc.IsNil) 817 c.Assert(err, gc.ErrorMatches, test.err) 818 return 819 } 820 c.Assert(err, gc.IsNil) 821 822 typ, _ := test.attrs["type"].(string) 823 // "null" has been deprecated in favour of "manual", 824 // and is automatically switched. 825 if typ == "null" { 826 typ = "manual" 827 } 828 name, _ := test.attrs["name"].(string) 829 c.Assert(cfg.Type(), gc.Equals, typ) 830 c.Assert(cfg.Name(), gc.Equals, name) 831 agentVersion, ok := cfg.AgentVersion() 832 if s := test.attrs["agent-version"]; s != nil { 833 c.Assert(ok, jc.IsTrue) 834 c.Assert(agentVersion, gc.Equals, version.MustParse(s.(string))) 835 } else { 836 c.Assert(ok, jc.IsFalse) 837 c.Assert(agentVersion, gc.Equals, version.Zero) 838 } 839 840 if statePort, ok := test.attrs["state-port"]; ok { 841 c.Assert(cfg.StatePort(), gc.Equals, statePort) 842 } 843 if apiPort, ok := test.attrs["api-port"]; ok { 844 c.Assert(cfg.APIPort(), gc.Equals, apiPort) 845 } 846 if syslogPort, ok := test.attrs["syslog-port"]; ok { 847 c.Assert(cfg.SyslogPort(), gc.Equals, syslogPort) 848 } 849 850 dev, _ := test.attrs["development"].(bool) 851 c.Assert(cfg.Development(), gc.Equals, dev) 852 853 if series, _ := test.attrs["default-series"].(string); series != "" { 854 c.Assert(cfg.DefaultSeries(), gc.Equals, series) 855 } else { 856 c.Assert(cfg.DefaultSeries(), gc.Equals, config.DefaultSeries) 857 } 858 if m, _ := test.attrs["firewall-mode"].(string); m != "" { 859 c.Assert(cfg.FirewallMode(), gc.Equals, m) 860 } 861 if secret, _ := test.attrs["admin-secret"].(string); secret != "" { 862 c.Assert(cfg.AdminSecret(), gc.Equals, secret) 863 } 864 865 if path, _ := test.attrs["authorized-keys-path"].(string); path != "" { 866 c.Assert(cfg.AuthorizedKeys(), gc.Equals, home.FileContents(c, path)) 867 c.Assert(cfg.AllAttrs()["authorized-keys-path"], gc.IsNil) 868 } else if keys, _ := test.attrs["authorized-keys"].(string); keys != "" { 869 c.Assert(cfg.AuthorizedKeys(), gc.Equals, keys) 870 } else { 871 // Content of all the files that are read by default. 872 c.Assert(cfg.AuthorizedKeys(), gc.Equals, "dsa\nrsa\nidentity\n") 873 } 874 875 cert, certPresent := cfg.CACert() 876 if path, _ := test.attrs["ca-cert-path"].(string); path != "" { 877 c.Assert(certPresent, jc.IsTrue) 878 c.Assert(string(cert), gc.Equals, home.FileContents(c, path)) 879 } else if v, ok := test.attrs["ca-cert"].(string); v != "" { 880 c.Assert(certPresent, jc.IsTrue) 881 c.Assert(string(cert), gc.Equals, v) 882 } else if ok { 883 c.Check(cert, gc.HasLen, 0) 884 c.Assert(certPresent, jc.IsFalse) 885 } else if bool(test.useDefaults) && home.FileExists(".juju/my-name-cert.pem") { 886 c.Assert(certPresent, jc.IsTrue) 887 c.Assert(string(cert), gc.Equals, home.FileContents(c, "my-name-cert.pem")) 888 } else { 889 c.Check(cert, gc.HasLen, 0) 890 c.Assert(certPresent, jc.IsFalse) 891 } 892 893 key, keyPresent := cfg.CAPrivateKey() 894 if path, _ := test.attrs["ca-private-key-path"].(string); path != "" { 895 c.Assert(keyPresent, jc.IsTrue) 896 c.Assert(string(key), gc.Equals, home.FileContents(c, path)) 897 } else if v, ok := test.attrs["ca-private-key"].(string); v != "" { 898 c.Assert(keyPresent, jc.IsTrue) 899 c.Assert(string(key), gc.Equals, v) 900 } else if ok { 901 c.Check(key, gc.HasLen, 0) 902 c.Assert(keyPresent, jc.IsFalse) 903 } else if bool(test.useDefaults) && home.FileExists(".juju/my-name-private-key.pem") { 904 c.Assert(keyPresent, jc.IsTrue) 905 c.Assert(string(key), gc.Equals, home.FileContents(c, "my-name-private-key.pem")) 906 } else { 907 c.Check(key, gc.HasLen, 0) 908 c.Assert(keyPresent, jc.IsFalse) 909 } 910 911 if v, ok := test.attrs["ssl-hostname-verification"]; ok { 912 c.Assert(cfg.SSLHostnameVerification(), gc.Equals, v) 913 } 914 915 if v, ok := test.attrs["provisioner-safe-mode"]; ok { 916 c.Assert(cfg.ProvisionerSafeMode(), gc.Equals, v) 917 } else { 918 c.Assert(cfg.ProvisionerSafeMode(), gc.Equals, false) 919 } 920 sshOpts := cfg.BootstrapSSHOpts() 921 test.assertDuration( 922 c, 923 "bootstrap-timeout", 924 sshOpts.Timeout, 925 config.DefaultBootstrapSSHTimeout, 926 ) 927 test.assertDuration( 928 c, 929 "bootstrap-retry-delay", 930 sshOpts.RetryDelay, 931 config.DefaultBootstrapSSHRetryDelay, 932 ) 933 test.assertDuration( 934 c, 935 "bootstrap-addresses-delay", 936 sshOpts.AddressesDelay, 937 config.DefaultBootstrapSSHAddressesDelay, 938 ) 939 940 if v, ok := test.attrs["image-stream"]; ok { 941 c.Assert(cfg.ImageStream(), gc.Equals, v) 942 } else { 943 c.Assert(cfg.ImageStream(), gc.Equals, "released") 944 } 945 946 url, urlPresent := cfg.ImageMetadataURL() 947 if v, _ := test.attrs["image-metadata-url"].(string); v != "" { 948 c.Assert(url, gc.Equals, v) 949 c.Assert(urlPresent, jc.IsTrue) 950 } else { 951 c.Assert(urlPresent, jc.IsFalse) 952 } 953 toolsURL, urlPresent := cfg.ToolsURL() 954 oldToolsURL, oldURLPresent := cfg.AllAttrs()["tools-url"] 955 oldToolsURLAttrValue, oldURLAttrPresent := test.attrs["tools-url"] 956 expectedToolsURLValue := test.attrs["tools-metadata-url"] 957 if expectedToolsURLValue == nil { 958 expectedToolsURLValue = oldToolsURLAttrValue 959 } 960 if expectedToolsURLValue != nil && expectedToolsURLValue != "" { 961 c.Assert(expectedToolsURLValue, gc.Equals, "tools-metadata-url-value") 962 c.Assert(toolsURL, gc.Equals, expectedToolsURLValue) 963 c.Assert(urlPresent, jc.IsTrue) 964 c.Assert(oldToolsURL, gc.Equals, expectedToolsURLValue) 965 c.Assert(oldURLPresent, jc.IsTrue) 966 } else { 967 c.Assert(urlPresent, jc.IsFalse) 968 c.Assert(oldURLAttrPresent, jc.IsFalse) 969 c.Assert(oldToolsURL, gc.Equals, "") 970 } 971 } 972 973 func (test configTest) assertDuration(c *gc.C, name string, actual time.Duration, defaultInSeconds int) { 974 value, ok := test.attrs[name].(int) 975 if !ok || value == 0 { 976 c.Assert(actual, gc.Equals, time.Duration(defaultInSeconds)*time.Second) 977 } else { 978 c.Assert(actual, gc.Equals, time.Duration(value)*time.Second) 979 } 980 } 981 982 func (s *ConfigSuite) TestConfigAttrs(c *gc.C) { 983 // Normally this is handled by testing.FakeHome 984 s.PatchEnvironment(osenv.JujuLoggingConfigEnvKey, "") 985 attrs := map[string]interface{}{ 986 "type": "my-type", 987 "name": "my-name", 988 "authorized-keys": testing.FakeAuthKeys, 989 "firewall-mode": config.FwInstance, 990 "admin-secret": "foo", 991 "unknown": "my-unknown", 992 "ca-cert": caCert, 993 "ssl-hostname-verification": true, 994 "development": false, 995 "provisioner-safe-mode": false, 996 "state-port": 1234, 997 "api-port": 4321, 998 "syslog-port": 2345, 999 "bootstrap-timeout": 3600, 1000 "bootstrap-retry-delay": 30, 1001 "bootstrap-addresses-delay": 10, 1002 "default-series": "precise", 1003 "charm-store-auth": "token=auth", 1004 } 1005 cfg, err := config.New(config.NoDefaults, attrs) 1006 c.Assert(err, gc.IsNil) 1007 1008 // These attributes are added if not set. 1009 attrs["development"] = false 1010 attrs["default-series"] = config.DefaultSeries 1011 attrs["logging-config"] = "<root>=WARNING;unit=DEBUG" 1012 attrs["ca-private-key"] = "" 1013 attrs["image-metadata-url"] = "" 1014 attrs["tools-metadata-url"] = "" 1015 attrs["tools-url"] = "" 1016 attrs["image-stream"] = "" 1017 // Default firewall mode is instance 1018 attrs["firewall-mode"] = string(config.FwInstance) 1019 c.Assert(cfg.AllAttrs(), jc.DeepEquals, attrs) 1020 c.Assert(cfg.UnknownAttrs(), jc.DeepEquals, map[string]interface{}{"unknown": "my-unknown"}) 1021 1022 newcfg, err := cfg.Apply(map[string]interface{}{ 1023 "name": "new-name", 1024 "new-unknown": "my-new-unknown", 1025 }) 1026 c.Assert(err, gc.IsNil) 1027 1028 attrs["name"] = "new-name" 1029 attrs["new-unknown"] = "my-new-unknown" 1030 c.Assert(newcfg.AllAttrs(), jc.DeepEquals, attrs) 1031 } 1032 1033 type validationTest struct { 1034 about string 1035 new testing.Attrs 1036 old testing.Attrs 1037 err string 1038 } 1039 1040 var validationTests = []validationTest{{ 1041 about: "Can't change the type", 1042 new: testing.Attrs{"type": "new-type"}, 1043 err: `cannot change type from "my-type" to "new-type"`, 1044 }, { 1045 about: "Can't change the name", 1046 new: testing.Attrs{"name": "new-name"}, 1047 err: `cannot change name from "my-name" to "new-name"`, 1048 }, { 1049 about: "Can set agent version", 1050 new: testing.Attrs{"agent-version": "1.9.13"}, 1051 }, { 1052 about: "Can change agent version", 1053 old: testing.Attrs{"agent-version": "1.9.13"}, 1054 new: testing.Attrs{"agent-version": "1.9.27"}, 1055 }, { 1056 about: "Can't clear agent version", 1057 old: testing.Attrs{"agent-version": "1.9.27"}, 1058 err: `cannot clear agent-version`, 1059 }, { 1060 about: "Can't change the firewall-mode", 1061 old: testing.Attrs{"firewall-mode": config.FwGlobal}, 1062 new: testing.Attrs{"firewall-mode": config.FwInstance}, 1063 err: `cannot change firewall-mode from "global" to "instance"`, 1064 }, { 1065 about: "Cannot change the state-port", 1066 old: testing.Attrs{"state-port": config.DefaultStatePort}, 1067 new: testing.Attrs{"state-port": 42}, 1068 err: `cannot change state-port from 37017 to 42`, 1069 }, { 1070 about: "Cannot change the api-port", 1071 old: testing.Attrs{"api-port": config.DefaultAPIPort}, 1072 new: testing.Attrs{"api-port": 42}, 1073 err: `cannot change api-port from 17070 to 42`, 1074 }, { 1075 about: "Cannot change the syslog-port", 1076 old: testing.Attrs{"syslog-port": 345}, 1077 new: testing.Attrs{"syslog-port": 42}, 1078 err: `cannot change syslog-port from 345 to 42`, 1079 }, { 1080 about: "Can change the state-port from explicit-default to implicit-default", 1081 old: testing.Attrs{"state-port": config.DefaultStatePort}, 1082 }, { 1083 about: "Can change the api-port from explicit-default to implicit-default", 1084 old: testing.Attrs{"api-port": config.DefaultAPIPort}, 1085 }, { 1086 about: "Can change the state-port from implicit-default to explicit-default", 1087 new: testing.Attrs{"state-port": config.DefaultStatePort}, 1088 }, { 1089 about: "Can change the api-port from implicit-default to explicit-default", 1090 new: testing.Attrs{"api-port": config.DefaultAPIPort}, 1091 }, { 1092 about: "Cannot change the state-port from implicit-default to different value", 1093 new: testing.Attrs{"state-port": 42}, 1094 err: `cannot change state-port from 37017 to 42`, 1095 }, { 1096 about: "Cannot change the api-port from implicit-default to different value", 1097 new: testing.Attrs{"api-port": 42}, 1098 err: `cannot change api-port from 17070 to 42`, 1099 }, { 1100 about: "Cannot change the syslog-port from implicit-default to different value", 1101 new: testing.Attrs{"syslog-port": 42}, 1102 err: `cannot change syslog-port from 514 to 42`, 1103 }} 1104 1105 func (*ConfigSuite) TestValidateChange(c *gc.C) { 1106 files := []testing.TestFile{ 1107 {".ssh/identity.pub", "identity"}, 1108 } 1109 h := testing.MakeFakeHomeWithFiles(c, files) 1110 defer h.Restore() 1111 1112 for i, test := range validationTests { 1113 c.Logf("test %d: %s", i, test.about) 1114 newConfig := newTestConfig(c, test.new) 1115 oldConfig := newTestConfig(c, test.old) 1116 err := config.Validate(newConfig, oldConfig) 1117 if test.err == "" { 1118 c.Assert(err, gc.IsNil) 1119 } else { 1120 c.Assert(err, gc.ErrorMatches, test.err) 1121 } 1122 } 1123 } 1124 1125 func makeFakeHome(c *gc.C) *testing.FakeHome { 1126 return testing.MakeFakeHomeWithFiles(c, []testing.TestFile{ 1127 {".ssh/id_rsa.pub", "rsa\n"}, 1128 {".juju/myenv-cert.pem", caCert}, 1129 {".juju/myenv-private-key.pem", caKey}, 1130 }) 1131 } 1132 1133 func (*ConfigSuite) TestValidateUnknownAttrs(c *gc.C) { 1134 defer makeFakeHome(c).Restore() 1135 cfg, err := config.New(config.UseDefaults, map[string]interface{}{ 1136 "name": "myenv", 1137 "type": "other", 1138 "known": "this", 1139 "unknown": "that", 1140 }) 1141 1142 // No fields: all attrs passed through. 1143 attrs, err := cfg.ValidateUnknownAttrs(nil, nil) 1144 c.Assert(err, gc.IsNil) 1145 c.Assert(attrs, gc.DeepEquals, map[string]interface{}{ 1146 "known": "this", 1147 "unknown": "that", 1148 }) 1149 1150 // Valid field: that and other attrs passed through. 1151 fields := schema.Fields{"known": schema.String()} 1152 attrs, err = cfg.ValidateUnknownAttrs(fields, nil) 1153 c.Assert(err, gc.IsNil) 1154 c.Assert(attrs, gc.DeepEquals, map[string]interface{}{ 1155 "known": "this", 1156 "unknown": "that", 1157 }) 1158 1159 // Default field: inserted. 1160 fields["default"] = schema.String() 1161 defaults := schema.Defaults{"default": "the other"} 1162 attrs, err = cfg.ValidateUnknownAttrs(fields, defaults) 1163 c.Assert(err, gc.IsNil) 1164 c.Assert(attrs, gc.DeepEquals, map[string]interface{}{ 1165 "known": "this", 1166 "unknown": "that", 1167 "default": "the other", 1168 }) 1169 1170 // Invalid field: failure. 1171 fields["known"] = schema.Int() 1172 _, err = cfg.ValidateUnknownAttrs(fields, defaults) 1173 c.Assert(err, gc.ErrorMatches, `known: expected int, got string\("this"\)`) 1174 } 1175 1176 func newTestConfig(c *gc.C, explicit testing.Attrs) *config.Config { 1177 final := testing.Attrs{"type": "my-type", "name": "my-name"} 1178 for key, value := range explicit { 1179 final[key] = value 1180 } 1181 result, err := config.New(config.UseDefaults, final) 1182 c.Assert(err, gc.IsNil) 1183 return result 1184 } 1185 1186 func (*ConfigSuite) TestLoggingConfig(c *gc.C) { 1187 defer makeFakeHome(c).Restore() 1188 1189 config := newTestConfig(c, testing.Attrs{ 1190 "logging-config": "<root>=WARNING;juju=DEBUG"}) 1191 c.Assert(config.LoggingConfig(), gc.Equals, "<root>=WARNING;juju=DEBUG;unit=DEBUG") 1192 } 1193 1194 func (*ConfigSuite) TestLoggingConfigWithUnit(c *gc.C) { 1195 defer makeFakeHome(c).Restore() 1196 1197 config := newTestConfig(c, testing.Attrs{ 1198 "logging-config": "<root>=WARNING;unit=INFO"}) 1199 c.Assert(config.LoggingConfig(), gc.Equals, "<root>=WARNING;unit=INFO") 1200 } 1201 1202 func (s *ConfigSuite) TestLoggingConfigFromEnvironment(c *gc.C) { 1203 defer makeFakeHome(c).Restore() 1204 s.PatchEnvironment(osenv.JujuLoggingConfigEnvKey, "<root>=INFO") 1205 1206 config := newTestConfig(c, nil) 1207 c.Assert(config.LoggingConfig(), gc.Equals, "<root>=INFO;unit=DEBUG") 1208 } 1209 1210 func (*ConfigSuite) TestProxyValuesWithFallback(c *gc.C) { 1211 defer makeFakeHome(c).Restore() 1212 1213 config := newTestConfig(c, testing.Attrs{ 1214 "http-proxy": "http://user@10.0.0.1", 1215 "https-proxy": "https://user@10.0.0.1", 1216 "ftp-proxy": "ftp://user@10.0.0.1", 1217 }) 1218 c.Assert(config.HttpProxy(), gc.Equals, "http://user@10.0.0.1") 1219 c.Assert(config.AptHttpProxy(), gc.Equals, "http://user@10.0.0.1") 1220 c.Assert(config.HttpsProxy(), gc.Equals, "https://user@10.0.0.1") 1221 c.Assert(config.AptHttpsProxy(), gc.Equals, "https://user@10.0.0.1") 1222 c.Assert(config.FtpProxy(), gc.Equals, "ftp://user@10.0.0.1") 1223 c.Assert(config.AptFtpProxy(), gc.Equals, "ftp://user@10.0.0.1") 1224 } 1225 1226 func (*ConfigSuite) TestProxyValues(c *gc.C) { 1227 defer makeFakeHome(c).Restore() 1228 1229 config := newTestConfig(c, testing.Attrs{ 1230 "http-proxy": "http://user@10.0.0.1", 1231 "https-proxy": "https://user@10.0.0.1", 1232 "ftp-proxy": "ftp://user@10.0.0.1", 1233 "apt-http-proxy": "http://user@10.0.0.2", 1234 "apt-https-proxy": "https://user@10.0.0.2", 1235 "apt-ftp-proxy": "ftp://user@10.0.0.2", 1236 }) 1237 c.Assert(config.HttpProxy(), gc.Equals, "http://user@10.0.0.1") 1238 c.Assert(config.AptHttpProxy(), gc.Equals, "http://user@10.0.0.2") 1239 c.Assert(config.HttpsProxy(), gc.Equals, "https://user@10.0.0.1") 1240 c.Assert(config.AptHttpsProxy(), gc.Equals, "https://user@10.0.0.2") 1241 c.Assert(config.FtpProxy(), gc.Equals, "ftp://user@10.0.0.1") 1242 c.Assert(config.AptFtpProxy(), gc.Equals, "ftp://user@10.0.0.2") 1243 } 1244 1245 func (*ConfigSuite) TestProxyValuesNotSet(c *gc.C) { 1246 defer makeFakeHome(c).Restore() 1247 1248 config := newTestConfig(c, testing.Attrs{}) 1249 c.Assert(config.HttpProxy(), gc.Equals, "") 1250 c.Assert(config.AptHttpProxy(), gc.Equals, "") 1251 c.Assert(config.HttpsProxy(), gc.Equals, "") 1252 c.Assert(config.AptHttpsProxy(), gc.Equals, "") 1253 c.Assert(config.FtpProxy(), gc.Equals, "") 1254 c.Assert(config.AptFtpProxy(), gc.Equals, "") 1255 } 1256 1257 func (*ConfigSuite) TestProxyConfigMap(c *gc.C) { 1258 defer makeFakeHome(c).Restore() 1259 1260 cfg := newTestConfig(c, testing.Attrs{}) 1261 proxy := osenv.ProxySettings{ 1262 Http: "http proxy", 1263 Https: "https proxy", 1264 Ftp: "ftp proxy", 1265 } 1266 cfg, err := cfg.Apply(config.ProxyConfigMap(proxy)) 1267 c.Assert(err, gc.IsNil) 1268 c.Assert(cfg.ProxySettings(), gc.DeepEquals, proxy) 1269 c.Assert(cfg.AptProxySettings(), gc.DeepEquals, proxy) 1270 } 1271 1272 func (*ConfigSuite) TestAptProxyConfigMap(c *gc.C) { 1273 defer makeFakeHome(c).Restore() 1274 1275 cfg := newTestConfig(c, testing.Attrs{}) 1276 proxy := osenv.ProxySettings{ 1277 Http: "http proxy", 1278 Https: "https proxy", 1279 Ftp: "ftp proxy", 1280 } 1281 cfg, err := cfg.Apply(config.AptProxyConfigMap(proxy)) 1282 c.Assert(err, gc.IsNil) 1283 // The default proxy settings should still be empty. 1284 c.Assert(cfg.ProxySettings(), gc.DeepEquals, osenv.ProxySettings{}) 1285 c.Assert(cfg.AptProxySettings(), gc.DeepEquals, proxy) 1286 } 1287 1288 func (*ConfigSuite) TestGenerateStateServerCertAndKey(c *gc.C) { 1289 // In order to test missing certs, it checks the JUJU_HOME dir, so we need 1290 // a fake home. 1291 defer testing.MakeFakeHomeWithFiles(c, []testing.TestFile{ 1292 {".ssh/id_rsa.pub", "rsa\n"}, 1293 }).Restore() 1294 1295 for _, test := range []struct { 1296 configValues map[string]interface{} 1297 errMatch string 1298 }{{ 1299 configValues: map[string]interface{}{ 1300 "name": "test-no-certs", 1301 "type": "dummy", 1302 }, 1303 errMatch: "environment configuration has no ca-cert", 1304 }, { 1305 configValues: map[string]interface{}{ 1306 "name": "test-no-certs", 1307 "type": "dummy", 1308 "ca-cert": testing.CACert, 1309 }, 1310 errMatch: "environment configuration has no ca-private-key", 1311 }, { 1312 configValues: map[string]interface{}{ 1313 "name": "test-no-certs", 1314 "type": "dummy", 1315 "ca-cert": testing.CACert, 1316 "ca-private-key": testing.CAKey, 1317 }, 1318 }} { 1319 cfg, err := config.New(config.UseDefaults, test.configValues) 1320 c.Assert(err, gc.IsNil) 1321 certPEM, keyPEM, err := cfg.GenerateStateServerCertAndKey() 1322 if test.errMatch == "" { 1323 c.Assert(err, gc.IsNil) 1324 1325 _, _, err = cert.ParseCertAndKey(certPEM, keyPEM) 1326 c.Check(err, gc.IsNil) 1327 1328 err = cert.Verify(certPEM, []byte(testing.CACert), time.Now()) 1329 c.Assert(err, gc.IsNil) 1330 err = cert.Verify(certPEM, []byte(testing.CACert), time.Now().AddDate(9, 0, 0)) 1331 c.Assert(err, gc.IsNil) 1332 err = cert.Verify(certPEM, []byte(testing.CACert), time.Now().AddDate(10, 0, 1)) 1333 c.Assert(err, gc.NotNil) 1334 } else { 1335 c.Assert(err, gc.ErrorMatches, test.errMatch) 1336 c.Assert(certPEM, gc.IsNil) 1337 c.Assert(keyPEM, gc.IsNil) 1338 } 1339 } 1340 } 1341 1342 var caCert = ` 1343 -----BEGIN CERTIFICATE----- 1344 MIIBjDCCATigAwIBAgIBADALBgkqhkiG9w0BAQUwHjENMAsGA1UEChMEanVqdTEN 1345 MAsGA1UEAxMEcm9vdDAeFw0xMjExMDkxNjQwMjhaFw0yMjExMDkxNjQ1MjhaMB4x 1346 DTALBgNVBAoTBGp1anUxDTALBgNVBAMTBHJvb3QwWTALBgkqhkiG9w0BAQEDSgAw 1347 RwJAduA1Gnb2VJLxNGfG4St0Qy48Y3q5Z5HheGtTGmti/FjlvQvScCFGCnJG7fKA 1348 Knd7ia3vWg7lxYkIvMPVP88LAQIDAQABo2YwZDAOBgNVHQ8BAf8EBAMCAKQwEgYD 1349 VR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQUlvKX8vwp0o+VdhdhoA9O6KlOm00w 1350 HwYDVR0jBBgwFoAUlvKX8vwp0o+VdhdhoA9O6KlOm00wCwYJKoZIhvcNAQEFA0EA 1351 LlNpevtFr8gngjAFFAO/FXc7KiZcCrA5rBfb/rEy297lIqmKt5++aVbLEPyxCIFC 1352 r71Sj63TUTFWtRZAxvn9qQ== 1353 -----END CERTIFICATE----- 1354 `[1:] 1355 1356 var caKey = ` 1357 -----BEGIN RSA PRIVATE KEY----- 1358 MIIBOQIBAAJAduA1Gnb2VJLxNGfG4St0Qy48Y3q5Z5HheGtTGmti/FjlvQvScCFG 1359 CnJG7fKAKnd7ia3vWg7lxYkIvMPVP88LAQIDAQABAkEAsFOdMSYn+AcF1M/iBfjo 1360 uQWJ+Zz+CgwuvumjGNsUtmwxjA+hh0fCn0Ah2nAt4Ma81vKOKOdQ8W6bapvsVDH0 1361 6QIhAJOkLmEKm4H5POQV7qunRbRsLbft/n/SHlOBz165WFvPAiEAzh9fMf70std1 1362 sVCHJRQWKK+vw3oaEvPKvkPiV5ui0C8CIGNsvybuo8ald5IKCw5huRlFeIxSo36k 1363 m3OVCXc6zfwVAiBnTUe7WcivPNZqOC6TAZ8dYvdWo4Ifz3jjpEfymjid1wIgBIJv 1364 ERPyv2NQqIFQZIyzUP7LVRIWfpFFOo9/Ww/7s5Y= 1365 -----END RSA PRIVATE KEY----- 1366 `[1:] 1367 1368 var caCert2 = ` 1369 -----BEGIN CERTIFICATE----- 1370 MIIBjTCCATmgAwIBAgIBADALBgkqhkiG9w0BAQUwHjENMAsGA1UEChMEanVqdTEN 1371 MAsGA1UEAxMEcm9vdDAeFw0xMjExMDkxNjQxMDhaFw0yMjExMDkxNjQ2MDhaMB4x 1372 DTALBgNVBAoTBGp1anUxDTALBgNVBAMTBHJvb3QwWjALBgkqhkiG9w0BAQEDSwAw 1373 SAJBAJkSWRrr81y8pY4dbNgt+8miSKg4z6glp2KO2NnxxAhyyNtQHKvC+fJALJj+ 1374 C2NhuvOv9xImxOl3Hg8fFPCXCtcCAwEAAaNmMGQwDgYDVR0PAQH/BAQDAgCkMBIG 1375 A1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFOsX/ZCqKzWCAaTTVcWsWKT5Msow 1376 MB8GA1UdIwQYMBaAFOsX/ZCqKzWCAaTTVcWsWKT5MsowMAsGCSqGSIb3DQEBBQNB 1377 AAVV57jetEzJQnjgBzhvx/UwauFn78jGhXfV5BrQmxIb4SF4DgSCFstPwUQOAr8h 1378 XXzJqBQH92KYmp+y3YXDoMQ= 1379 -----END CERTIFICATE----- 1380 `[1:] 1381 1382 var caKey2 = ` 1383 -----BEGIN RSA PRIVATE KEY----- 1384 MIIBOQIBAAJBAJkSWRrr81y8pY4dbNgt+8miSKg4z6glp2KO2NnxxAhyyNtQHKvC 1385 +fJALJj+C2NhuvOv9xImxOl3Hg8fFPCXCtcCAwEAAQJATQNzO11NQvJS5U6eraFt 1386 FgSFQ8XZjILtVWQDbJv8AjdbEgKMHEy33icsAKIUAx8jL9kjq6K9kTdAKXZi9grF 1387 UQIhAPD7jccIDUVm785E5eR9eisq0+xpgUIa24Jkn8cAlst5AiEAopxVFl1auer3 1388 GP2In3pjdL4ydzU/gcRcYisoJqwHpM8CIHtqmaXBPeq5WT9ukb5/dL3+5SJCtmxA 1389 jQMuvZWRe6khAiBvMztYtPSDKXRbCZ4xeQ+kWSDHtok8Y5zNoTeu4nvDrwIgb3Al 1390 fikzPveC5g6S6OvEQmyDz59tYBubm2XHgvxqww0= 1391 -----END RSA PRIVATE KEY----- 1392 `[1:] 1393 1394 var caCert3 = ` 1395 -----BEGIN CERTIFICATE----- 1396 MIIBjTCCATmgAwIBAgIBADALBgkqhkiG9w0BAQUwHjENMAsGA1UEChMEanVqdTEN 1397 MAsGA1UEAxMEcm9vdDAeFw0xMjExMDkxNjQxMjlaFw0yMjExMDkxNjQ2MjlaMB4x 1398 DTALBgNVBAoTBGp1anUxDTALBgNVBAMTBHJvb3QwWjALBgkqhkiG9w0BAQEDSwAw 1399 SAJBAIW7CbHFJivvV9V6mO8AGzJS9lqjUf6MdEPsdF6wx2Cpzr/lSFIggCwRA138 1400 9MuFxflxb/3U8Nq+rd8rVtTgFMECAwEAAaNmMGQwDgYDVR0PAQH/BAQDAgCkMBIG 1401 A1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFJafrxqByMN9BwGfcmuF0Lw/1QII 1402 MB8GA1UdIwQYMBaAFJafrxqByMN9BwGfcmuF0Lw/1QIIMAsGCSqGSIb3DQEBBQNB 1403 AHq3vqNhxya3s33DlQfSj9whsnqM0Nm+u8mBX/T76TF5rV7+B33XmYzSyfA3yBi/ 1404 zHaUR/dbHuiNTO+KXs3/+Y4= 1405 -----END CERTIFICATE----- 1406 `[1:] 1407 1408 var caKey3 = ` 1409 -----BEGIN RSA PRIVATE KEY----- 1410 MIIBOgIBAAJBAIW7CbHFJivvV9V6mO8AGzJS9lqjUf6MdEPsdF6wx2Cpzr/lSFIg 1411 gCwRA1389MuFxflxb/3U8Nq+rd8rVtTgFMECAwEAAQJAaivPi4qJPrJb2onl50H/ 1412 VZnWKqmljGF4YQDWduMEt7GTPk+76x9SpO7W4gfY490Ivd9DEXfbr/KZqhwWikNw 1413 LQIhALlLfRXLF2ZfToMfB1v1v+jith5onAu24O68mkdRc5PLAiEAuMJ/6U07hggr 1414 Ckf9OT93wh84DK66h780HJ/FUHKcoCMCIDsPZaJBpoa50BOZG0ZjcTTwti3BGCPf 1415 uZg+w0oCGz27AiEAsUCYKqEXy/ymHhT2kSecozYENdajyXvcaOG3EPkD3nUCICOP 1416 zatzs7c/4mx4a0JBG6Za0oEPUcm2I34is50KSohz 1417 -----END RSA PRIVATE KEY----- 1418 `[1:] 1419 1420 var invalidCAKey = ` 1421 -----BEGIN RSA PRIVATE KEY----- 1422 MIIBOgIBAAJAZabKgKInuOxj5vDWLwHHQtK3/45KB+32D15w94Nt83BmuGxo90lw 1423 -----END RSA PRIVATE KEY----- 1424 `[1:] 1425 1426 var invalidCACert = ` 1427 -----BEGIN CERTIFICATE----- 1428 MIIBOgIBAAJAZabKgKInuOxj5vDWLwHHQtK3/45KB+32D15w94Nt83BmuGxo90lw 1429 -----END CERTIFICATE----- 1430 `[1:]