Skip to content

Commit

Permalink
Use new dependency abstraction to install mongo server
Browse files Browse the repository at this point in the history
  • Loading branch information
achilleasa committed Aug 28, 2019
1 parent cd44181 commit bbdd5b5
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 204 deletions.
90 changes: 4 additions & 86 deletions mongo/mongo.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ import (
"github.com/juju/errors"
"github.com/juju/loggo"
"github.com/juju/os/series"
"github.com/juju/packaging/config"
"github.com/juju/packaging/manager"
"github.com/juju/replicaset"
"github.com/juju/utils"
"github.com/juju/utils/featureflag"
Expand All @@ -30,6 +28,8 @@ import (
"github.com/juju/juju/controller"
"github.com/juju/juju/core/network"
"github.com/juju/juju/feature"
"github.com/juju/juju/packaging"
"github.com/juju/juju/packaging/dependency"
"github.com/juju/juju/service"
"github.com/juju/juju/service/common"
"github.com/juju/juju/service/snap"
Expand All @@ -49,9 +49,6 @@ var (
// MongodSystemPath is actually just the system path
MongodSystemPath = "/usr/bin/mongod"

// This is NUMACTL package name for apt-get
numaCtlPkg = "numactl"

// mininmumSystemMongoVersion is the minimum version we would allow to be used from /usr/bin/mongod.
minimumSystemMongoVersion = Version{Major: 3, Minor: 4}
)
Expand All @@ -60,21 +57,13 @@ var (
type StorageEngine string

const (
// JujuMongoPackage is the mongo package Juju uses when
// installing mongo.
JujuMongoPackage = "juju-mongodb3.2"

// JujuDbSnap is the snap of MongoDB that Juju uses.
JujuDbSnap = "juju-db"

// JujuDbSnapMongodPath is the path that the juju-db snap
// makes mongod available at
JujuDbSnapMongodPath = "/snap/bin/juju-db.mongod"

// JujuMongoToolsPackage is the mongo package Juju uses when
// installing mongo tools to get mongodump etc.
JujuMongoToolsPackage = "juju-mongo-tools3.2"

// MMAPV1 is the default storage engine in mongo db up to 3.x
MMAPV1 StorageEngine = "mmapv1"

Expand Down Expand Up @@ -685,15 +674,6 @@ func logVersion(mongoPath string) {
logger.Debugf("using mongod: %s --version: %q", mongoPath, output)
}

func installPackage(pkg string, pacconfer config.PackagingConfigurer, pacman manager.PackageManager) error {
// apply release targeting if needed.
if pacconfer.IsCloudArchivePackage(pkg) {
pkg = strings.Join(pacconfer.ApplyCloudArchiveTarget(pkg), " ")
}

return pacman.Install(pkg)
}

func getSnapChannel() string {
return fmt.Sprintf("%s/%s", SnapTrack, SnapRisk)
}
Expand Down Expand Up @@ -725,59 +705,15 @@ func installMongod(operatingsystem string, numaCtl bool, dataDir string) error {
return service.Install()
}

// fetch the packaging configuration manager for the current operating system.
pacconfer, err := config.NewPackagingConfigurer(operatingsystem)
if err != nil {
if err := packaging.InstallDependency(dependency.Mongo(numaCtl), operatingsystem); err != nil {
return err
}

// fetch the package manager implementation for the current operating system.
pacman, err := manager.NewPackageManager(operatingsystem)
if err != nil {
return err
}

// CentOS requires "epel-release" for the epel repo mongodb-server is in.
if operatingsystem == "centos7" {
// install epel-release
if err := pacman.Install("epel-release"); err != nil {
return err
}
}
mongoPkgs, fallbackPkgs := packagesForSeries(operatingsystem)

if numaCtl {
logger.Infof("installing %v and %s", mongoPkgs, numaCtlPkg)
if err = installPackage(numaCtlPkg, pacconfer, pacman); err != nil {
return errors.Trace(err)
}
} else {
logger.Infof("installing %v", mongoPkgs)
}

for i := range mongoPkgs {
if err = installPackage(mongoPkgs[i], pacconfer, pacman); err != nil {
break
}
}
if err != nil && len(fallbackPkgs) == 0 {
return errors.Trace(err)
}
if err != nil {
logger.Errorf("installing mongo failed: %v", err)
logger.Infof("will try fallback packages %v", fallbackPkgs)
for i := range fallbackPkgs {
if err = installPackage(fallbackPkgs[i], pacconfer, pacman); err != nil {
return errors.Trace(err)
}
}
}

// Work around SELinux on centos7
if operatingsystem == "centos7" {
cmd := []string{"chcon", "-R", "-v", "-t", "mongod_var_lib_t", "/var/lib/juju/"}
logger.Infof("running %s %v", cmd[0], cmd[1:])
_, err = utils.RunCommand(cmd[0], cmd[1:]...)
_, err := utils.RunCommand(cmd[0], cmd[1:]...)
if err != nil {
logger.Errorf("chcon failed to change file security context error %s", err)
return err
Expand All @@ -796,24 +732,6 @@ func installMongod(operatingsystem string, numaCtl bool, dataDir string) error {
return nil
}

// packagesForSeries returns the name of the mongo package for the series
// of the machine that it is going to be running on plus a fallback for
// options where the package is going to be ready eventually but might not
// yet be.
func packagesForSeries(series string) ([]string, []string) {
switch series {
case "precise", "centos7":
return []string{"mongodb-server"}, []string{}
case "trusty":
return []string{"juju-mongodb"}, []string{}
case "xenial", "artful":
return []string{JujuMongoPackage, JujuMongoToolsPackage}, []string{}
default:
// Bionic and newer
return []string{"mongodb-server-core", "mongodb-clients"}, []string{}
}
}

// DbDir returns the dir where mongo storage is.
func DbDir(dataDir string) string {
return filepath.Join(dataDir, "db")
Expand Down
145 changes: 27 additions & 118 deletions mongo/mongo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"path"
"path/filepath"
"regexp"
"runtime"
"strconv"
"strings"

Expand Down Expand Up @@ -63,8 +62,9 @@ var expectedArgs = struct {
}{
MongoInstall: []jc.SimpleMessage{
{loggo.INFO, "Ensuring mongo server is running; data directory.*"},
{loggo.INFO, regexp.QuoteMeta(`installing "epel-release" via "yum"`)},
{loggo.INFO, "Running: yum --assumeyes --debuglevel=1 install epel-release"},
{loggo.INFO, regexp.QuoteMeta("installing [mongodb-server]")},
{loggo.INFO, regexp.QuoteMeta(`installing "mongodb-server" via "yum"`)},
{loggo.INFO, "Running: yum --assumeyes --debuglevel=1 install mongodb-server"},
},
YumBase: []string{
Expand All @@ -74,7 +74,7 @@ var expectedArgs = struct {
},
AptGetBase: []string{
"--option=Dpkg::Options::=--force-confold",
"--option=Dpkg::options::=--force-unsafe-io",
"--option=Dpkg::Options::=--force-unsafe-io",
"--assume-yes",
"--quiet",
"install",
Expand Down Expand Up @@ -389,94 +389,34 @@ func (s *MongoSuite) testEnsureServerNUMACtl(c *gc.C, setNUMAPolicy bool) string
return dataDir
}

func (s *MongoSuite) TestInstallMongod(c *gc.C) {
func (s *MongoSuite) TestInstallMongodOnUbuntuViaApt(c *gc.C) {
type installs struct {
series string
cmd [][]string
series string
pkgs []string
expOpts []string
}

tests := []installs{
{"precise", [][]string{{"--target-release", "precise-updates/cloud-tools", "mongodb-server"}}},
{"trusty", [][]string{{"juju-mongodb"}}},
{"xenial", [][]string{{"juju-mongodb3.2"}, {"juju-mongo-tools3.2"}}},
{"bionic", [][]string{{"mongodb-server-core"}}},
}

testing.PatchExecutableAsEchoArgs(c, s, "add-apt-repository")
testing.PatchExecutableAsEchoArgs(c, s, "apt-get")
for _, test := range tests {
c.Logf("install for series %v", test.series)
dataDir := c.MkDir()
s.patchSeries(test.series)
_, err := mongo.EnsureServer(makeEnsureServerParams(dataDir))
c.Assert(err, jc.ErrorIsNil)

for _, cmd := range test.cmd {
match := append(expectedArgs.AptGetBase, cmd...)
testing.AssertEchoArgs(c, "apt-get", match...)
}
}
}

var fakeInstallScript = `#!/bin/bash
if [ $# -lt 1 ]
then
echo "Install fail - not enough arguments"
exit 1
fi
# The package name is the last argument
package=${@: -1}
echo $package >> %s
if [ $package == "juju-mongodb" ]
then
echo "Installed successfully!"
exit 0
fi
if [ $package == "mongodb-server" ]
then
echo "Installed successfully!"
exit 0
fi
echo "Unable to locate package $package"
exit 100
`

func (s *MongoSuite) TestInstallMongodFallsBack(c *gc.C) {
if runtime.GOOS == "windows" {
c.Skip("Skipping TestInstallMongodFallsBack as mongo is not installed on windows")
}

type installs struct {
series string
cmd string
}

tests := []installs{
{"precise", "mongodb-server"},
{"trusty", "juju-mongodb"},
{"xenial", "juju-mongodb3.2"},
{"bionic", "mongodb-server-core"},
{"trusty", []string{"juju-mongodb"}, nil},
{"xenial", []string{"juju-mongodb3.2", "juju-mongo-tools3.2"}, nil},
{"bionic", []string{"mongodb-server-core", "mongodb-clients"}, nil},
}

dataDir := c.MkDir()
outputFile := filepath.Join(dataDir, "apt-get-args")
testing.PatchExecutable(c, s, "apt-get", fmt.Sprintf(fakeInstallScript, outputFile))
for _, test := range tests {
c.Logf("Testing mongo install for series: %s", test.series)
testing.PatchExecutableAsEchoArgs(c, s, "apt-get")
s.patchSeries(test.series)
_, err := mongo.EnsureServer(makeEnsureServerParams(dataDir))
c.Assert(err, jc.ErrorIsNil)

args, err := ioutil.ReadFile(outputFile)
c.Assert(err, jc.ErrorIsNil)
c.Check(strings.TrimSpace(string(args)), gc.Equals, test.cmd)
_, err := mongo.EnsureServer(makeEnsureServerParams(dataDir))
c.Assert(err, gc.IsNil)

err = os.Remove(outputFile)
c.Assert(err, jc.ErrorIsNil)
for _, pkg := range test.pkgs {
exp := append([]string{}, expectedArgs.AptGetBase...)
exp = append(exp, test.expOpts...)
exp = append(exp, pkg)
testing.AssertEchoArgs(c, "apt-get", exp...)
}
}
}

Expand Down Expand Up @@ -525,22 +465,14 @@ func (s *MongoSuite) TestInstallFailSemanageMongodCentOS(c *gc.C) {
}

func (s *MongoSuite) assertSuccessWithInstallStepFailCentOS(c *gc.C, exec []string, execNameFail string, returnCode int, expectedResult []jc.SimpleMessage) {
type installs struct {
series string
pkg string
}
test := installs{
"centos7", "mongodb*",
}

for _, e := range exec {
testing.PatchExecutableAsEchoArgs(c, s, e)
}

testing.PatchExecutableThrowError(c, s, execNameFail, returnCode)

dataDir := c.MkDir()
s.patchSeries(test.series)
s.patchSeries("centos7")

var tw loggo.TestWriter
c.Assert(loggo.RegisterWriter("mongosuite", &tw), jc.ErrorIsNil)
Expand All @@ -554,10 +486,10 @@ func (s *MongoSuite) assertSuccessWithInstallStepFailCentOS(c *gc.C, exec []stri
func (s *MongoSuite) TestInstallSuccessMongodCentOS(c *gc.C) {
type installs struct {
series string
pkg string
pkgs []string
}
test := installs{
"centos7", "mongodb*",
"centos7", []string{"epel-release", "mongodb-server"},
}

testing.PatchExecutableAsEchoArgs(c, s, "yum")
Expand All @@ -570,9 +502,10 @@ func (s *MongoSuite) TestInstallSuccessMongodCentOS(c *gc.C) {
_, err := mongo.EnsureServer(makeEnsureServerParams(dataDir))
c.Assert(err, jc.ErrorIsNil)

expected := append(expectedArgs.YumBase, "epel-release")

testing.AssertEchoArgs(c, "yum", expected...)
for _, pkg := range test.pkgs {
exp := append(append([]string{}, expectedArgs.YumBase...), pkg)
testing.AssertEchoArgs(c, "yum", exp...)
}

testing.AssertEchoArgs(c, "chcon", expectedArgs.Chcon...)

Expand Down Expand Up @@ -616,7 +549,7 @@ func (s *MongoSuite) assertTestMongoGetFails(c *gc.C, series string, packageMana

c.Check(tw.Log(), jc.LogMatches, []jc.SimpleMessage{
{loggo.ERROR, `packaging command failed: .+`},
{loggo.ERROR, `cannot install/upgrade mongod \(will proceed anyway\): packaging command failed`},
{loggo.ERROR, `cannot install/upgrade mongod \(will proceed anyway\): installing package.+: packaging command failed:.+`},
})

// Verify that EnsureServer continued and started the mongodb service.
Expand Down Expand Up @@ -735,30 +668,6 @@ func (s *MongoSuite) TestGenerateSharedSecret(c *gc.C) {
c.Assert(err, jc.ErrorIsNil)
}

func (s *MongoSuite) TestAddEpelInCentOS(c *gc.C) {
testing.PatchExecutableAsEchoArgs(c, s, "yum")

s.patchSeries("centos7")

testing.PatchExecutableAsEchoArgs(c, s, "chcon")
testing.PatchExecutableAsEchoArgs(c, s, "semanage")
testing.PatchExecutableAsEchoArgs(c, s, "yum-config-manager")

dataDir := c.MkDir()
_, err := mongo.EnsureServer(makeEnsureServerParams(dataDir))
c.Assert(err, jc.ErrorIsNil)

expectedEpelRelease := append(expectedArgs.YumBase, "epel-release")
testing.AssertEchoArgs(c, "yum", expectedEpelRelease...)

expectedMongodbServer := append(expectedArgs.YumBase, "mongodb-server")
testing.AssertEchoArgs(c, "yum", expectedMongodbServer...)

testing.AssertEchoArgs(c, "chcon", expectedArgs.Chcon...)

testing.AssertEchoArgs(c, "semanage", expectedArgs.Semanage...)
}

// failCmd creates an executable file at the given location that will do nothing
// except return an error.
func failCmd(path string) {
Expand Down
Loading

0 comments on commit bbdd5b5

Please sign in to comment.