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