github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/mongo/mongo_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package mongo_test 5 6 import ( 7 "encoding/base64" 8 "fmt" 9 "io/ioutil" 10 "os" 11 "os/exec" 12 "path" 13 "path/filepath" 14 "regexp" 15 "strconv" 16 "strings" 17 18 "github.com/juju/errors" 19 "github.com/juju/loggo" 20 "github.com/juju/testing" 21 jc "github.com/juju/testing/checkers" 22 "github.com/juju/utils/packaging/manager" 23 "github.com/juju/utils/series" 24 gc "gopkg.in/check.v1" 25 26 environs "github.com/juju/juju/environs/config" 27 "github.com/juju/juju/mongo" 28 "github.com/juju/juju/network" 29 "github.com/juju/juju/service/common" 30 svctesting "github.com/juju/juju/service/common/testing" 31 coretesting "github.com/juju/juju/testing" 32 ) 33 34 type MongoSuite struct { 35 coretesting.BaseSuite 36 mongodConfigPath string 37 mongodPath string 38 39 data *svctesting.FakeServiceData 40 } 41 42 var _ = gc.Suite(&MongoSuite{}) 43 44 var testInfo = struct { 45 StatePort int 46 Cert string 47 PrivateKey string 48 SharedSecret string 49 }{ 50 StatePort: 25252, 51 Cert: "foobar-cert", 52 PrivateKey: "foobar-privkey", 53 SharedSecret: "foobar-sharedsecret", 54 } 55 56 var expectedArgs = struct { 57 MongoInstall []jc.SimpleMessage 58 YumBase []string 59 AptGetBase []string 60 Semanage []string 61 Chcon []string 62 }{ 63 MongoInstall: []jc.SimpleMessage{ 64 {loggo.INFO, "Ensuring mongo server is running; data directory.*"}, 65 {loggo.INFO, "Running: yum --assumeyes --debuglevel=1 install epel-release"}, 66 {loggo.INFO, "installing mongodb-server"}, 67 {loggo.INFO, "Running: yum --assumeyes --debuglevel=1 install mongodb-server"}, 68 }, 69 YumBase: []string{ 70 "--assumeyes", 71 "--debuglevel=1", 72 "install", 73 }, 74 AptGetBase: []string{ 75 "--option=Dpkg::Options::=--force-confold", 76 "--option=Dpkg::options::=--force-unsafe-io", 77 "--assume-yes", 78 "--quiet", 79 "install", 80 }, 81 Semanage: []string{ 82 "port", 83 "-a", 84 "-t", 85 "mongod_port_t", 86 "-p", 87 "tcp", 88 strconv.Itoa(environs.DefaultStatePort), 89 }, 90 Chcon: []string{ 91 "-R", 92 "-v", 93 "-t", 94 "mongod_var_lib_t", 95 "/var/lib/juju/", 96 }, 97 } 98 99 func makeEnsureServerParams(dataDir, namespace string) mongo.EnsureServerParams { 100 return mongo.EnsureServerParams{ 101 StatePort: testInfo.StatePort, 102 Cert: testInfo.Cert, 103 PrivateKey: testInfo.PrivateKey, 104 SharedSecret: testInfo.SharedSecret, 105 106 DataDir: dataDir, 107 Namespace: namespace, 108 } 109 } 110 111 func (s *MongoSuite) SetUpTest(c *gc.C) { 112 s.BaseSuite.SetUpTest(c) 113 114 testing.PatchExecutable(c, s, "mongod", "#!/bin/bash\n\nprintf %s 'db version v2.4.9'\n") 115 jujuMongodPath, err := exec.LookPath("mongod") 116 c.Assert(err, jc.ErrorIsNil) 117 118 s.PatchValue(&mongo.JujuMongodPath, jujuMongodPath) 119 s.mongodPath = jujuMongodPath 120 121 // Patch "df" such that it always reports there's 1MB free. 122 s.PatchValue(mongo.AvailSpace, func(dir string) (float64, error) { 123 info, err := os.Stat(dir) 124 if err != nil { 125 return 0, err 126 } 127 if info.IsDir() { 128 return 1, nil 129 130 } 131 return 0, fmt.Errorf("not a directory") 132 }) 133 s.PatchValue(mongo.MinOplogSizeMB, 1) 134 135 testPath := c.MkDir() 136 s.mongodConfigPath = filepath.Join(testPath, "mongodConfig") 137 s.PatchValue(mongo.MongoConfigPath, s.mongodConfigPath) 138 139 s.data = svctesting.NewFakeServiceData() 140 mongo.PatchService(s.PatchValue, s.data) 141 } 142 143 func (s *MongoSuite) patchSeries(ser string) { 144 s.PatchValue(&series.HostSeries, func() string { return ser }) 145 } 146 147 func (s *MongoSuite) TestJujuMongodPath(c *gc.C) { 148 obtained, err := mongo.Path() 149 c.Check(err, jc.ErrorIsNil) 150 c.Check(obtained, gc.Matches, s.mongodPath) 151 } 152 153 func (s *MongoSuite) TestDefaultMongodPath(c *gc.C) { 154 s.PatchValue(&mongo.JujuMongodPath, "/not/going/to/exist/mongod") 155 s.PatchEnvPathPrepend(filepath.Dir(s.mongodPath)) 156 157 obtained, err := mongo.Path() 158 c.Check(err, jc.ErrorIsNil) 159 c.Check(obtained, gc.Matches, s.mongodPath) 160 } 161 162 func (s *MongoSuite) TestMakeJournalDirs(c *gc.C) { 163 dir := c.MkDir() 164 err := mongo.MakeJournalDirs(dir) 165 c.Assert(err, jc.ErrorIsNil) 166 167 testJournalDirs(dir, c) 168 } 169 170 func testJournalDirs(dir string, c *gc.C) { 171 journalDir := path.Join(dir, "journal") 172 173 c.Assert(journalDir, jc.IsDirectory) 174 info, err := os.Stat(filepath.Join(journalDir, "prealloc.0")) 175 c.Assert(err, jc.ErrorIsNil) 176 177 size := int64(1024 * 1024) 178 179 c.Assert(info.Size(), gc.Equals, size) 180 info, err = os.Stat(filepath.Join(journalDir, "prealloc.1")) 181 c.Assert(err, jc.ErrorIsNil) 182 c.Assert(info.Size(), gc.Equals, size) 183 info, err = os.Stat(filepath.Join(journalDir, "prealloc.2")) 184 c.Assert(err, jc.ErrorIsNil) 185 c.Assert(info.Size(), gc.Equals, size) 186 } 187 188 func (s *MongoSuite) assertSSLKeyFile(c *gc.C, dataDir string) { 189 contents, err := ioutil.ReadFile(mongo.SSLKeyPath(dataDir)) 190 c.Assert(err, jc.ErrorIsNil) 191 c.Assert(string(contents), gc.Equals, testInfo.Cert+"\n"+testInfo.PrivateKey) 192 } 193 194 func (s *MongoSuite) assertSharedSecretFile(c *gc.C, dataDir string) { 195 contents, err := ioutil.ReadFile(mongo.SharedSecretPath(dataDir)) 196 c.Assert(err, jc.ErrorIsNil) 197 c.Assert(string(contents), gc.Equals, testInfo.SharedSecret) 198 } 199 200 func (s *MongoSuite) assertMongoConfigFile(c *gc.C) { 201 contents, err := ioutil.ReadFile(s.mongodConfigPath) 202 c.Assert(err, jc.ErrorIsNil) 203 c.Assert(contents, jc.DeepEquals, []byte("ENABLE_MONGODB=no")) 204 } 205 206 func (s *MongoSuite) TestEnsureServer(c *gc.C) { 207 dataDir := s.testEnsureServerNumaCtl(c, false) 208 209 s.assertSSLKeyFile(c, dataDir) 210 s.assertSharedSecretFile(c, dataDir) 211 s.assertMongoConfigFile(c) 212 213 // make sure that we log the version of mongodb as we get ready to 214 // start it 215 tlog := c.GetTestLog() 216 any := `(.|\n)*` 217 start := "^" + any 218 tail := any + "$" 219 c.Assert(tlog, gc.Matches, start+`using mongod: .*/mongod --version: "db version v2\.4\.9`+tail) 220 } 221 222 func (s *MongoSuite) TestEnsureServerServerExistsAndRunning(c *gc.C) { 223 dataDir := c.MkDir() 224 namespace := "namespace" 225 226 pm, err := coretesting.GetPackageManager() 227 c.Assert(err, jc.ErrorIsNil) 228 229 testing.PatchExecutableAsEchoArgs(c, s, pm.PackageManager) 230 231 s.data.SetStatus(mongo.ServiceName(namespace), "running") 232 s.data.SetErrors(nil, nil, nil, errors.New("shouldn't be called")) 233 234 err = mongo.EnsureServer(makeEnsureServerParams(dataDir, namespace)) 235 c.Assert(err, jc.ErrorIsNil) 236 237 // These should still be written out even if the service was installed. 238 s.assertSSLKeyFile(c, dataDir) 239 s.assertSharedSecretFile(c, dataDir) 240 s.assertMongoConfigFile(c) 241 242 c.Check(s.data.Installed(), gc.HasLen, 0) 243 s.data.CheckCallNames(c, "Installed", "Exists", "Running") 244 } 245 246 func (s *MongoSuite) TestEnsureServerServerExistsNotRunningIsStarted(c *gc.C) { 247 dataDir := c.MkDir() 248 namespace := "namespace" 249 250 pm, err := coretesting.GetPackageManager() 251 c.Assert(err, jc.ErrorIsNil) 252 testing.PatchExecutableAsEchoArgs(c, s, pm.PackageManager) 253 254 s.data.SetStatus(mongo.ServiceName(namespace), "installed") 255 256 err = mongo.EnsureServer(makeEnsureServerParams(dataDir, namespace)) 257 c.Assert(err, jc.ErrorIsNil) 258 259 // These should still be written out even if the service was installed. 260 s.assertSSLKeyFile(c, dataDir) 261 s.assertSharedSecretFile(c, dataDir) 262 s.assertMongoConfigFile(c) 263 264 c.Check(s.data.Installed(), gc.HasLen, 0) 265 s.data.CheckCallNames(c, "Installed", "Exists", "Running", "Start") 266 } 267 268 func (s *MongoSuite) TestEnsureServerServerExistsNotRunningStartError(c *gc.C) { 269 dataDir := c.MkDir() 270 namespace := "namespace" 271 272 pm, err := coretesting.GetPackageManager() 273 c.Assert(err, jc.ErrorIsNil) 274 testing.PatchExecutableAsEchoArgs(c, s, pm.PackageManager) 275 276 s.data.SetStatus(mongo.ServiceName(namespace), "installed") 277 failure := errors.New("won't start") 278 s.data.SetErrors(nil, nil, nil, failure) // Installed, Exists, Running, Running, Start 279 280 err = mongo.EnsureServer(makeEnsureServerParams(dataDir, namespace)) 281 282 c.Check(errors.Cause(err), gc.Equals, failure) 283 c.Check(s.data.Installed(), gc.HasLen, 0) 284 s.data.CheckCallNames(c, "Installed", "Exists", "Running", "Start") 285 } 286 287 func (s *MongoSuite) TestEnsureServerNumaCtl(c *gc.C) { 288 s.testEnsureServerNumaCtl(c, true) 289 } 290 291 func (s *MongoSuite) testEnsureServerNumaCtl(c *gc.C, setNumaPolicy bool) string { 292 dataDir := c.MkDir() 293 dbDir := filepath.Join(dataDir, "db") 294 namespace := "namespace" 295 296 pm, err := coretesting.GetPackageManager() 297 c.Assert(err, jc.ErrorIsNil) 298 testing.PatchExecutableAsEchoArgs(c, s, pm.PackageManager) 299 300 testParams := makeEnsureServerParams(dataDir, namespace) 301 testParams.SetNumaControlPolicy = setNumaPolicy 302 err = mongo.EnsureServer(testParams) 303 c.Assert(err, jc.ErrorIsNil) 304 305 testJournalDirs(dbDir, c) 306 307 assertInstalled := func() { 308 installed := s.data.Installed() 309 c.Assert(installed, gc.HasLen, 1) 310 service := installed[0] 311 c.Assert(service.Name(), gc.Equals, "juju-db-namespace") 312 c.Assert(service.Conf().Desc, gc.Equals, "juju state database") 313 if setNumaPolicy { 314 stripped := strings.Replace(service.Conf().ExtraScript, "\n", "", -1) 315 c.Assert(stripped, gc.Matches, `.* sysctl .*`) 316 } else { 317 c.Assert(service.Conf().ExtraScript, gc.Equals, "") 318 } 319 c.Assert(service.Conf().ExecStart, gc.Matches, `.*/check-.*/mongod.*`) 320 c.Assert(service.Conf().Logfile, gc.Equals, "") 321 } 322 assertInstalled() 323 return dataDir 324 } 325 326 func (s *MongoSuite) TestInstallMongod(c *gc.C) { 327 type installs struct { 328 series string 329 cmd [][]string 330 } 331 332 tests := []installs{ 333 {"precise", [][]string{{"--target-release", "precise-updates/cloud-tools", "mongodb-server"}}}, 334 {"quantal", [][]string{{"python-software-properties"}, {"--target-release", "mongodb-server"}}}, 335 {"raring", [][]string{{"--target-release", "mongodb-server"}}}, 336 {"saucy", [][]string{{"--target-release", "mongodb-server"}}}, 337 {"trusty", [][]string{{"juju-mongodb"}}}, 338 {"u-series", [][]string{{"juju-mongodb"}}}, 339 } 340 341 testing.PatchExecutableAsEchoArgs(c, s, "add-apt-repository") 342 testing.PatchExecutableAsEchoArgs(c, s, "apt-get") 343 for _, test := range tests { 344 dataDir := c.MkDir() 345 namespace := "namespace" + test.series 346 s.patchSeries(test.series) 347 err := mongo.EnsureServer(makeEnsureServerParams(dataDir, namespace)) 348 c.Assert(err, jc.ErrorIsNil) 349 350 for _, cmd := range test.cmd { 351 match := append(expectedArgs.AptGetBase, cmd...) 352 testing.AssertEchoArgs(c, "apt-get", match...) 353 } 354 } 355 } 356 357 func (s *MongoSuite) TestInstallFailChconMongodCentOS(c *gc.C) { 358 returnCode := 1 359 execNameFail := "chcon" 360 361 exec := []string{"yum", "chcon"} 362 363 expectedResult := append(expectedArgs.MongoInstall, []jc.SimpleMessage{ 364 {loggo.INFO, "running " + execNameFail + " .*"}, 365 {loggo.ERROR, execNameFail + " failed to change file security context error exit status " + strconv.Itoa(returnCode)}, 366 {loggo.ERROR, regexp.QuoteMeta("cannot install/upgrade mongod (will proceed anyway): exit status " + strconv.Itoa(returnCode))}, 367 }...) 368 s.assertSuccessWithInstallStepFailCentOS(c, exec, execNameFail, returnCode, expectedResult) 369 } 370 371 func (s *MongoSuite) TestSemanageRuleExistsDoesNotFail(c *gc.C) { 372 // if the return code is 1 then the rule already exists and we do not fail 373 returnCode := 1 374 execNameFail := "semanage" 375 376 exec := []string{"yum", "chcon"} 377 378 expectedResult := append(expectedArgs.MongoInstall, []jc.SimpleMessage{ 379 {loggo.INFO, "running chcon .*"}, 380 {loggo.INFO, "running " + execNameFail + " .*"}, 381 }...) 382 383 s.assertSuccessWithInstallStepFailCentOS(c, exec, execNameFail, returnCode, expectedResult) 384 } 385 386 func (s *MongoSuite) TestInstallFailSemanageMongodCentOS(c *gc.C) { 387 returnCode := 2 388 execNameFail := "semanage" 389 390 exec := []string{"yum", "chcon"} 391 392 expectedResult := append(expectedArgs.MongoInstall, []jc.SimpleMessage{ 393 {loggo.INFO, "running chcon .*"}, 394 {loggo.INFO, "running " + execNameFail + " .*"}, 395 {loggo.ERROR, execNameFail + " failed to provide access on port " + strconv.Itoa(environs.DefaultStatePort) + " error exit status " + strconv.Itoa(returnCode)}, 396 {loggo.ERROR, regexp.QuoteMeta("cannot install/upgrade mongod (will proceed anyway): exit status " + strconv.Itoa(returnCode))}, 397 }...) 398 s.assertSuccessWithInstallStepFailCentOS(c, exec, execNameFail, returnCode, expectedResult) 399 } 400 401 func (s *MongoSuite) assertSuccessWithInstallStepFailCentOS(c *gc.C, exec []string, execNameFail string, returnCode int, expectedResult []jc.SimpleMessage) { 402 type installs struct { 403 series string 404 pkg string 405 } 406 test := installs{ 407 "centos7", "mongodb*", 408 } 409 410 for _, e := range exec { 411 testing.PatchExecutableAsEchoArgs(c, s, e) 412 } 413 414 testing.PatchExecutableThrowError(c, s, execNameFail, returnCode) 415 416 dataDir := c.MkDir() 417 namespace := "namespace" + test.series 418 s.patchSeries(test.series) 419 420 var tw loggo.TestWriter 421 c.Assert(loggo.RegisterWriter("mongosuite", &tw, loggo.INFO), jc.ErrorIsNil) 422 defer loggo.RemoveWriter("mongosuite") 423 424 err := mongo.EnsureServer(makeEnsureServerParams(dataDir, namespace)) 425 c.Assert(err, jc.ErrorIsNil) 426 c.Assert(tw.Log(), jc.LogMatches, expectedResult) 427 } 428 429 func (s *MongoSuite) TestInstallSuccessMongodCentOS(c *gc.C) { 430 type installs struct { 431 series string 432 pkg string 433 } 434 test := installs{ 435 "centos7", "mongodb*", 436 } 437 438 testing.PatchExecutableAsEchoArgs(c, s, "yum") 439 testing.PatchExecutableAsEchoArgs(c, s, "chcon") 440 testing.PatchExecutableAsEchoArgs(c, s, "semanage") 441 442 dataDir := c.MkDir() 443 namespace := "namespace" + test.series 444 s.patchSeries(test.series) 445 446 err := mongo.EnsureServer(makeEnsureServerParams(dataDir, namespace)) 447 c.Assert(err, jc.ErrorIsNil) 448 449 expected := append(expectedArgs.YumBase, "epel-release") 450 451 testing.AssertEchoArgs(c, "yum", expected...) 452 453 testing.AssertEchoArgs(c, "chcon", expectedArgs.Chcon...) 454 455 testing.AssertEchoArgs(c, "semanage", expectedArgs.Semanage...) 456 } 457 458 func (s *MongoSuite) TestMongoAptGetFails(c *gc.C) { 459 s.assertTestMongoGetFails(c, "trusty", "apt-get") 460 } 461 462 func (s *MongoSuite) TestMongoYumFails(c *gc.C) { 463 s.assertTestMongoGetFails(c, "centos7", "yum") 464 } 465 466 func (s *MongoSuite) assertTestMongoGetFails(c *gc.C, series string, packageManager string) { 467 s.patchSeries(series) 468 469 // Any exit code from apt-get that isn't 0 or 100 will be treated 470 // as unexpected, skipping the normal retry loop. failCmd causes 471 // the command to exit with 1. 472 binDir := c.MkDir() 473 s.PatchEnvPathPrepend(binDir) 474 failCmd(filepath.Join(binDir, packageManager)) 475 476 // Set the mongodb service as installed but not running. 477 namespace := "namespace" 478 s.data.SetStatus(mongo.ServiceName(namespace), "installed") 479 480 var tw loggo.TestWriter 481 c.Assert(loggo.RegisterWriter("test-writer", &tw, loggo.ERROR), jc.ErrorIsNil) 482 defer loggo.RemoveWriter("test-writer") 483 484 dataDir := c.MkDir() 485 err := mongo.EnsureServer(makeEnsureServerParams(dataDir, namespace)) 486 487 // Even though apt-get failed, EnsureServer should continue and 488 // not return the error - even though apt-get failed, the Juju 489 // mongodb package is most likely already installed. 490 // The error should be logged however. 491 c.Assert(err, jc.ErrorIsNil) 492 493 c.Check(tw.Log(), jc.LogMatches, []jc.SimpleMessage{ 494 {loggo.ERROR, `packaging command failed: .+`}, 495 {loggo.ERROR, `cannot install/upgrade mongod \(will proceed anyway\): packaging command failed`}, 496 }) 497 498 // Verify that EnsureServer continued and started the mongodb service. 499 c.Check(s.data.Installed(), gc.HasLen, 0) 500 s.data.CheckCallNames(c, "Installed", "Exists", "Running", "Start") 501 } 502 503 func (s *MongoSuite) TestInstallMongodServiceExists(c *gc.C) { 504 pm, err := coretesting.GetPackageManager() 505 c.Assert(err, jc.ErrorIsNil) 506 testing.PatchExecutableAsEchoArgs(c, s, pm.PackageManager) 507 if pm.PackageManager == "yum" { 508 testing.PatchExecutableAsEchoArgs(c, s, "chcon") 509 testing.PatchExecutableAsEchoArgs(c, s, "semanage") 510 } 511 512 dataDir := c.MkDir() 513 namespace := "namespace" 514 515 s.data.SetStatus(mongo.ServiceName(namespace), "running") 516 s.data.SetErrors(nil, nil, nil, errors.New("shouldn't be called")) 517 518 err = mongo.EnsureServer(makeEnsureServerParams(dataDir, namespace)) 519 c.Assert(err, jc.ErrorIsNil) 520 521 c.Check(s.data.Installed(), gc.HasLen, 0) 522 s.data.CheckCallNames(c, "Installed", "Exists", "Running") 523 } 524 525 func (s *MongoSuite) TestNewServiceWithReplSet(c *gc.C) { 526 dataDir := c.MkDir() 527 528 conf := mongo.NewConf(dataDir, dataDir, mongo.JujuMongodPath, 1234, 1024, false) 529 c.Assert(strings.Contains(conf.ExecStart, "--replSet"), jc.IsTrue) 530 } 531 532 func (s *MongoSuite) TestNewServiceWithNumCtl(c *gc.C) { 533 dataDir := c.MkDir() 534 535 conf := mongo.NewConf(dataDir, dataDir, mongo.JujuMongodPath, 1234, 1024, true) 536 c.Assert(conf.ExtraScript, gc.Not(gc.Matches), "") 537 } 538 539 func (s *MongoSuite) TestNewServiceIPv6(c *gc.C) { 540 dataDir := c.MkDir() 541 542 conf := mongo.NewConf(dataDir, dataDir, mongo.JujuMongodPath, 1234, 1024, false) 543 c.Assert(strings.Contains(conf.ExecStart, "--ipv6"), jc.IsTrue) 544 } 545 546 func (s *MongoSuite) TestNewServiceWithJournal(c *gc.C) { 547 dataDir := c.MkDir() 548 549 conf := mongo.NewConf(dataDir, dataDir, mongo.JujuMongodPath, 1234, 1024, false) 550 c.Assert(conf.ExecStart, gc.Matches, `.* --journal.*`) 551 } 552 553 func (s *MongoSuite) TestNoAuthCommandWithJournal(c *gc.C) { 554 dataDir := c.MkDir() 555 556 cmd, err := mongo.NoauthCommand(dataDir, 1234) 557 c.Assert(err, jc.ErrorIsNil) 558 var isJournalPresent bool 559 for _, value := range cmd.Args { 560 if value == "--journal" { 561 isJournalPresent = true 562 } 563 } 564 c.Assert(isJournalPresent, jc.IsTrue) 565 } 566 567 func (s *MongoSuite) TestRemoveService(c *gc.C) { 568 namespace := "namespace" 569 s.data.SetStatus(mongo.ServiceName(namespace), "running") 570 571 err := mongo.RemoveService(namespace) 572 c.Assert(err, jc.ErrorIsNil) 573 574 removed := s.data.Removed() 575 if !c.Check(removed, gc.HasLen, 1) { 576 c.Check(removed[0].Name(), gc.Equals, "juju-db-namespace") 577 c.Check(removed[0].Conf(), jc.DeepEquals, common.Conf{}) 578 } 579 s.data.CheckCallNames(c, "Stop", "Remove") 580 } 581 582 func (s *MongoSuite) TestQuantalAptAddRepo(c *gc.C) { 583 dir := c.MkDir() 584 // patch manager.RunCommandWithRetry for repository addition: 585 s.PatchValue(&manager.RunCommandWithRetry, func(string) (string, int, error) { 586 return "", 1, fmt.Errorf("packaging command failed: exit status 1") 587 }) 588 s.PatchEnvPathPrepend(dir) 589 590 pm, err := coretesting.GetPackageManager() 591 c.Assert(err, jc.ErrorIsNil) 592 failCmd(filepath.Join(dir, pm.RepositoryManager)) 593 testing.PatchExecutableAsEchoArgs(c, s, pm.PackageManager) 594 595 var tw loggo.TestWriter 596 c.Assert(loggo.RegisterWriter("test-writer", &tw, loggo.ERROR), jc.ErrorIsNil) 597 defer loggo.RemoveWriter("test-writer") 598 599 // test that we call add-apt-repository only for quantal 600 // (and that if it fails, we log the error) 601 s.patchSeries("quantal") 602 err = mongo.EnsureServer(makeEnsureServerParams(dir, "")) 603 c.Assert(err, jc.ErrorIsNil) 604 605 c.Assert(tw.Log(), jc.LogMatches, []jc.SimpleMessage{ 606 {loggo.ERROR, `cannot install/upgrade mongod \(will proceed anyway\): packaging command failed`}, 607 }) 608 609 s.PatchValue(&manager.RunCommandWithRetry, func(string) (string, int, error) { 610 return "", 0, nil 611 }) 612 s.patchSeries("trusty") 613 failCmd(filepath.Join(dir, "mongod")) 614 err = mongo.EnsureServer(makeEnsureServerParams(dir, "")) 615 c.Assert(err, jc.ErrorIsNil) 616 } 617 618 func (s *MongoSuite) TestNoMongoDir(c *gc.C) { 619 // Make a non-existent directory that can nonetheless be 620 // created. 621 pm, err := coretesting.GetPackageManager() 622 c.Assert(err, jc.ErrorIsNil) 623 testing.PatchExecutableAsEchoArgs(c, s, pm.PackageManager) 624 625 dataDir := filepath.Join(c.MkDir(), "dir", "data") 626 err = mongo.EnsureServer(makeEnsureServerParams(dataDir, "")) 627 c.Check(err, jc.ErrorIsNil) 628 629 _, err = os.Stat(filepath.Join(dataDir, "db")) 630 c.Assert(err, jc.ErrorIsNil) 631 } 632 633 func (s *MongoSuite) TestServiceName(c *gc.C) { 634 name := mongo.ServiceName("foo") 635 c.Assert(name, gc.Equals, "juju-db-foo") 636 name = mongo.ServiceName("") 637 c.Assert(name, gc.Equals, "juju-db") 638 } 639 640 func (s *MongoSuite) TestSelectPeerAddress(c *gc.C) { 641 addresses := []network.Address{{ 642 Value: "10.0.0.1", 643 Type: network.IPv4Address, 644 NetworkName: "cloud", 645 Scope: network.ScopeCloudLocal}, { 646 Value: "8.8.8.8", 647 Type: network.IPv4Address, 648 NetworkName: "public", 649 Scope: network.ScopePublic}} 650 651 address := mongo.SelectPeerAddress(addresses) 652 c.Assert(address, gc.Equals, "10.0.0.1") 653 } 654 655 func (s *MongoSuite) TestSelectPeerHostPort(c *gc.C) { 656 657 hostPorts := []network.HostPort{{ 658 Address: network.Address{ 659 Value: "10.0.0.1", 660 Type: network.IPv4Address, 661 NetworkName: "cloud", 662 Scope: network.ScopeCloudLocal, 663 }, 664 Port: environs.DefaultStatePort}, { 665 Address: network.Address{ 666 Value: "8.8.8.8", 667 Type: network.IPv4Address, 668 NetworkName: "public", 669 Scope: network.ScopePublic, 670 }, 671 Port: environs.DefaultStatePort}} 672 673 address := mongo.SelectPeerHostPort(hostPorts) 674 c.Assert(address, gc.Equals, "10.0.0.1:"+strconv.Itoa(environs.DefaultStatePort)) 675 } 676 677 func (s *MongoSuite) TestGenerateSharedSecret(c *gc.C) { 678 secret, err := mongo.GenerateSharedSecret() 679 c.Assert(err, jc.ErrorIsNil) 680 c.Assert(secret, gc.HasLen, 1024) 681 _, err = base64.StdEncoding.DecodeString(secret) 682 c.Assert(err, jc.ErrorIsNil) 683 } 684 685 func (s *MongoSuite) TestAddPPAInQuantal(c *gc.C) { 686 testing.PatchExecutableAsEchoArgs(c, s, "apt-get") 687 688 testing.PatchExecutableAsEchoArgs(c, s, "add-apt-repository") 689 s.patchSeries("quantal") 690 691 dataDir := c.MkDir() 692 err := mongo.EnsureServer(makeEnsureServerParams(dataDir, "")) 693 c.Assert(err, jc.ErrorIsNil) 694 695 pack := [][]string{ 696 { 697 "python-software-properties", 698 }, { 699 "--target-release", 700 "mongodb-server", 701 }, 702 } 703 cmd := append(expectedArgs.AptGetBase, pack[0]...) 704 testing.AssertEchoArgs(c, "apt-get", cmd...) 705 706 cmd = append(expectedArgs.AptGetBase, pack[1]...) 707 testing.AssertEchoArgs(c, "apt-get", cmd...) 708 709 match := []string{ 710 "--yes", 711 "\"ppa:juju/stable\"", 712 } 713 714 testing.AssertEchoArgs(c, "add-apt-repository", match...) 715 } 716 717 func (s *MongoSuite) TestAddEpelInCentOS(c *gc.C) { 718 testing.PatchExecutableAsEchoArgs(c, s, "yum") 719 720 s.patchSeries("centos7") 721 722 testing.PatchExecutableAsEchoArgs(c, s, "chcon") 723 testing.PatchExecutableAsEchoArgs(c, s, "semanage") 724 725 dataDir := c.MkDir() 726 err := mongo.EnsureServer(makeEnsureServerParams(dataDir, "")) 727 c.Assert(err, jc.ErrorIsNil) 728 729 expectedEpelRelease := append(expectedArgs.YumBase, "epel-release") 730 testing.AssertEchoArgs(c, "yum", expectedEpelRelease...) 731 732 expectedMongodbServer := append(expectedArgs.YumBase, "mongodb-server") 733 testing.AssertEchoArgs(c, "yum", expectedMongodbServer...) 734 735 testing.AssertEchoArgs(c, "chcon", expectedArgs.Chcon...) 736 737 testing.AssertEchoArgs(c, "semanage", expectedArgs.Semanage...) 738 } 739 740 // failCmd creates an executable file at the given location that will do nothing 741 // except return an error. 742 func failCmd(path string) { 743 err := ioutil.WriteFile(path, []byte("#!/bin/bash --norc\nexit 1"), 0755) 744 if err != nil { 745 panic(err) 746 } 747 }