~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/mongo/mongo.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2014 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package mongo
 
5
 
 
6
import (
 
7
        "crypto/rand"
 
8
        "encoding/base64"
 
9
        "fmt"
 
10
        "net"
 
11
        "os"
 
12
        "os/exec"
 
13
        "path"
 
14
        "path/filepath"
 
15
        "strconv"
 
16
        "strings"
 
17
 
 
18
        "github.com/juju/errors"
 
19
        "github.com/juju/loggo"
 
20
        "github.com/juju/replicaset"
 
21
        "github.com/juju/utils"
 
22
        "github.com/juju/utils/packaging/config"
 
23
        "github.com/juju/utils/packaging/manager"
 
24
        "github.com/juju/utils/series"
 
25
        "gopkg.in/mgo.v2"
 
26
 
 
27
        "github.com/juju/juju/controller"
 
28
        "github.com/juju/juju/network"
 
29
        "github.com/juju/juju/service"
 
30
)
 
31
 
 
32
var (
 
33
        logger          = loggo.GetLogger("juju.mongo")
 
34
        mongoConfigPath = "/etc/default/mongodb"
 
35
 
 
36
        // JujuMongod24Path holds the default path to the legacy Juju
 
37
        // mongod.
 
38
        JujuMongod24Path = "/usr/lib/juju/bin/mongod"
 
39
 
 
40
        // This is NUMACTL package name for apt-get
 
41
        numaCtlPkg = "numactl"
 
42
)
 
43
 
 
44
// StorageEngine represents the storage used by mongo.
 
45
type StorageEngine string
 
46
 
 
47
const (
 
48
        // JujuMongoPackage is the mongo package Juju uses when
 
49
        // installing mongo.
 
50
        JujuMongoPackage = "juju-mongodb3.2"
 
51
 
 
52
        // JujuMongoTooldPackage is the mongo package Juju uses when
 
53
        // installing mongo tools to get mongodump etc.
 
54
        JujuMongoToolsPackage = "juju-mongo-tools3.2"
 
55
 
 
56
        // MMAPV1 is the default storage engine in mongo db up to 3.x
 
57
        MMAPV1 StorageEngine = "mmapv1"
 
58
 
 
59
        // WiredTiger is a storage type introduced in 3
 
60
        WiredTiger StorageEngine = "wiredTiger"
 
61
 
 
62
        // Upgrading is a special case where mongo is being upgraded.
 
63
        Upgrading StorageEngine = "Upgrading"
 
64
)
 
65
 
 
66
// Version represents the major.minor version of the runnig mongo.
 
67
type Version struct {
 
68
        Major         int
 
69
        Minor         int
 
70
        Patch         string // supports variants like 1-alpha
 
71
        StorageEngine StorageEngine
 
72
}
 
73
 
 
74
// NewerThan will return 1 if the passed version is older than
 
75
// v, 0 if they are equal (or ver is a special case such as
 
76
// Upgrading and -1 if ver is newer.
 
77
func (v Version) NewerThan(ver Version) int {
 
78
        if v == MongoUpgrade || ver == MongoUpgrade {
 
79
                return 0
 
80
        }
 
81
        if v.Major > ver.Major {
 
82
                return 1
 
83
        }
 
84
        if v.Major < ver.Major {
 
85
                return -1
 
86
        }
 
87
        if v.Minor > ver.Minor {
 
88
                return 1
 
89
        }
 
90
        if v.Minor < ver.Minor {
 
91
                return -1
 
92
        }
 
93
        return 0
 
94
}
 
95
 
 
96
// NewVersion returns a mongo Version parsing the passed version string
 
97
// or error if not possible.
 
98
// A valid version string is of the form:
 
99
// 1.2.patch/storage
 
100
// major and minor are positive integers, patch is a string containing
 
101
// any ascii character except / and storage is one of the above defined
 
102
// StorageEngine. Only major is mandatory.
 
103
// An alternative valid string is 0.0/Upgrading which represents that
 
104
// mongo is being upgraded.
 
105
func NewVersion(v string) (Version, error) {
 
106
        version := Version{}
 
107
        if v == "" {
 
108
                return Mongo24, nil
 
109
        }
 
110
 
 
111
        parts := strings.SplitN(v, "/", 2)
 
112
        switch len(parts) {
 
113
        case 0:
 
114
                return Version{}, errors.New("invalid version string")
 
115
        case 1:
 
116
                version.StorageEngine = MMAPV1
 
117
        case 2:
 
118
                switch StorageEngine(parts[1]) {
 
119
                case MMAPV1:
 
120
                        version.StorageEngine = MMAPV1
 
121
                case WiredTiger:
 
122
                        version.StorageEngine = WiredTiger
 
123
                case Upgrading:
 
124
                        version.StorageEngine = Upgrading
 
125
                }
 
126
        }
 
127
        vParts := strings.SplitN(parts[0], ".", 3)
 
128
 
 
129
        if len(vParts) >= 1 {
 
130
                i, err := strconv.Atoi(vParts[0])
 
131
                if err != nil {
 
132
                        return Version{}, errors.Annotate(err, "Invalid version string, major is not an int")
 
133
                }
 
134
                version.Major = i
 
135
        }
 
136
        if len(vParts) >= 2 {
 
137
                i, err := strconv.Atoi(vParts[1])
 
138
                if err != nil {
 
139
                        return Version{}, errors.Annotate(err, "Invalid version string, minor is not an int")
 
140
                }
 
141
                version.Minor = i
 
142
        }
 
143
        if len(vParts) == 3 {
 
144
                version.Patch = vParts[2]
 
145
        }
 
146
 
 
147
        if version.Major == 2 && version.StorageEngine == WiredTiger {
 
148
                return Version{}, errors.Errorf("Version 2.x does not support Wired Tiger storage engine")
 
149
        }
 
150
 
 
151
        // This deserialises the special "Mongo Upgrading" version
 
152
        if version.Major == 0 && version.Minor == 0 {
 
153
                return Version{StorageEngine: Upgrading}, nil
 
154
        }
 
155
 
 
156
        return version, nil
 
157
}
 
158
 
 
159
// String serializes the version into a string.
 
160
func (v Version) String() string {
 
161
        s := fmt.Sprintf("%d.%d", v.Major, v.Minor)
 
162
        if v.Patch != "" {
 
163
                s = fmt.Sprintf("%s.%s", s, v.Patch)
 
164
        }
 
165
        if v.StorageEngine != "" {
 
166
                s = fmt.Sprintf("%s/%s", s, v.StorageEngine)
 
167
        }
 
168
        return s
 
169
}
 
170
 
 
171
// JujuMongodPath returns the path for the mongod binary
 
172
// with the specified version.
 
173
func JujuMongodPath(v Version) string {
 
174
        return fmt.Sprintf("/usr/lib/juju/mongo%d.%d/bin/mongod", v.Major, v.Minor)
 
175
}
 
176
 
 
177
var (
 
178
        // Mongo24 represents juju-mongodb 2.4.x
 
179
        Mongo24 = Version{Major: 2,
 
180
                Minor:         4,
 
181
                Patch:         "",
 
182
                StorageEngine: MMAPV1,
 
183
        }
 
184
        // Mongo26 represents juju-mongodb26 2.6.x
 
185
        Mongo26 = Version{Major: 2,
 
186
                Minor:         6,
 
187
                Patch:         "",
 
188
                StorageEngine: MMAPV1,
 
189
        }
 
190
        // Mongo32wt represents juju-mongodb3 3.2.x with wiredTiger storage.
 
191
        Mongo32wt = Version{Major: 3,
 
192
                Minor:         2,
 
193
                Patch:         "",
 
194
                StorageEngine: WiredTiger,
 
195
        }
 
196
        // MongoUpgrade represents a sepacial case where an upgrade is in
 
197
        // progress.
 
198
        MongoUpgrade = Version{Major: 0,
 
199
                Minor:         0,
 
200
                Patch:         "Upgrading",
 
201
                StorageEngine: Upgrading,
 
202
        }
 
203
)
 
204
 
 
205
// InstalledVersion returns the version of mongo installed.
 
206
// We look for a specific, known version supported by this Juju,
 
207
// and fall back to the original mongo 2.4.
 
208
func InstalledVersion() Version {
 
209
        mgoVersion := Mongo24
 
210
        if binariesAvailable(Mongo32wt, os.Stat) {
 
211
                mgoVersion = Mongo32wt
 
212
        }
 
213
        return mgoVersion
 
214
}
 
215
 
 
216
// binariesAvailable returns true if the binaries for the
 
217
// given Version of mongo are available.
 
218
func binariesAvailable(v Version, statFunc func(string) (os.FileInfo, error)) bool {
 
219
        var path string
 
220
        switch v {
 
221
        case Mongo24:
 
222
                // 2.4 has a fixed path.
 
223
                path = JujuMongod24Path
 
224
        default:
 
225
                path = JujuMongodPath(v)
 
226
        }
 
227
        if _, err := statFunc(path); err == nil {
 
228
                return true
 
229
        }
 
230
        return false
 
231
}
 
232
 
 
233
// WithAddresses represents an entity that has a set of
 
234
// addresses. e.g. a state Machine object
 
235
type WithAddresses interface {
 
236
        Addresses() []network.Address
 
237
}
 
238
 
 
239
// IsMaster returns a boolean that represents whether the given
 
240
// machine's peer address is the primary mongo host for the replicaset
 
241
func IsMaster(session *mgo.Session, obj WithAddresses) (bool, error) {
 
242
        addrs := obj.Addresses()
 
243
 
 
244
        masterHostPort, err := replicaset.MasterHostPort(session)
 
245
 
 
246
        // If the replica set has not been configured, then we
 
247
        // can have only one master and the caller must
 
248
        // be that master.
 
249
        if err == replicaset.ErrMasterNotConfigured {
 
250
                return true, nil
 
251
        }
 
252
        if err != nil {
 
253
                return false, err
 
254
        }
 
255
 
 
256
        masterAddr, _, err := net.SplitHostPort(masterHostPort)
 
257
        if err != nil {
 
258
                return false, err
 
259
        }
 
260
 
 
261
        for _, addr := range addrs {
 
262
                if addr.Value == masterAddr {
 
263
                        return true, nil
 
264
                }
 
265
        }
 
266
        return false, nil
 
267
}
 
268
 
 
269
// SelectPeerAddress returns the address to use as the mongo replica set peer
 
270
// address by selecting it from the given addresses. If no addresses are
 
271
// available an empty string is returned.
 
272
func SelectPeerAddress(addrs []network.Address) string {
 
273
        logger.Debugf("selecting mongo peer address from %+v", addrs)
 
274
        // ScopeMachineLocal addresses are OK if we can't pick by space, also the
 
275
        // second bool return is ignored intentionally.
 
276
        addr, _ := network.SelectControllerAddress(addrs, true)
 
277
        return addr.Value
 
278
}
 
279
 
 
280
// SelectPeerHostPort returns the HostPort to use as the mongo replica set peer
 
281
// by selecting it from the given hostPorts.
 
282
func SelectPeerHostPort(hostPorts []network.HostPort) string {
 
283
        logger.Debugf("selecting mongo peer hostPort by scope from %+v", hostPorts)
 
284
        return network.SelectMongoHostPortsByScope(hostPorts, true)[0]
 
285
}
 
286
 
 
287
// SelectPeerHostPortBySpace returns the HostPort to use as the mongo replica set peer
 
288
// by selecting it from the given hostPorts.
 
289
func SelectPeerHostPortBySpace(hostPorts []network.HostPort, space network.SpaceName) string {
 
290
        logger.Debugf("selecting mongo peer hostPort in space %s from %+v", space, hostPorts)
 
291
        // ScopeMachineLocal addresses are OK if we can't pick by space.
 
292
        suitableHostPorts, foundHostPortsInSpaces := network.SelectMongoHostPortsBySpaces(hostPorts, []network.SpaceName{space})
 
293
 
 
294
        if !foundHostPortsInSpaces {
 
295
                logger.Debugf("Failed to select hostPort by space - trying by scope from %+v", hostPorts)
 
296
                suitableHostPorts = network.SelectMongoHostPortsByScope(hostPorts, true)
 
297
        }
 
298
        return suitableHostPorts[0]
 
299
}
 
300
 
 
301
// GenerateSharedSecret generates a pseudo-random shared secret (keyfile)
 
302
// for use with Mongo replica sets.
 
303
func GenerateSharedSecret() (string, error) {
 
304
        // "A key’s length must be between 6 and 1024 characters and may
 
305
        // only contain characters in the base64 set."
 
306
        //   -- http://docs.mongodb.org/manual/tutorial/generate-key-file/
 
307
        buf := make([]byte, base64.StdEncoding.DecodedLen(1024))
 
308
        if _, err := rand.Read(buf); err != nil {
 
309
                return "", fmt.Errorf("cannot read random secret: %v", err)
 
310
        }
 
311
        return base64.StdEncoding.EncodeToString(buf), nil
 
312
}
 
313
 
 
314
// Path returns the executable path to be used to run mongod on this
 
315
// machine. If the juju-bundled version of mongo exists, it will return that
 
316
// path, otherwise it will return the command to run mongod from the path.
 
317
func Path(version Version) (string, error) {
 
318
        return mongoPath(version, os.Stat, exec.LookPath)
 
319
}
 
320
 
 
321
func mongoPath(version Version, stat func(string) (os.FileInfo, error), lookPath func(string) (string, error)) (string, error) {
 
322
        switch version {
 
323
        case Mongo24:
 
324
                if _, err := stat(JujuMongod24Path); err == nil {
 
325
                        return JujuMongod24Path, nil
 
326
                }
 
327
 
 
328
                path, err := lookPath("mongod")
 
329
                if err != nil {
 
330
                        logger.Infof("could not find %v or mongod in $PATH", JujuMongod24Path)
 
331
                        return "", err
 
332
                }
 
333
                return path, nil
 
334
        default:
 
335
                path := JujuMongodPath(version)
 
336
                var err error
 
337
                if _, err = stat(path); err == nil {
 
338
                        return path, nil
 
339
                }
 
340
        }
 
341
 
 
342
        logger.Infof("could not find a suitable binary for %q", version)
 
343
        errMsg := fmt.Sprintf("no suitable binary for %q", version)
 
344
        return "", errors.New(errMsg)
 
345
 
 
346
}
 
347
 
 
348
// EnsureServerParams is a parameter struct for EnsureServer.
 
349
type EnsureServerParams struct {
 
350
        // APIPort is the port to connect to the api server.
 
351
        APIPort int
 
352
 
 
353
        // StatePort is the port to connect to the mongo server.
 
354
        StatePort int
 
355
 
 
356
        // Cert is the certificate.
 
357
        Cert string
 
358
 
 
359
        // PrivateKey is the certificate's private key.
 
360
        PrivateKey string
 
361
 
 
362
        // CAPrivateKey is the CA certificate's private key.
 
363
        CAPrivateKey string
 
364
 
 
365
        // SharedSecret is a secret shared between mongo servers.
 
366
        SharedSecret string
 
367
 
 
368
        // SystemIdentity is the identity of the system.
 
369
        SystemIdentity string
 
370
 
 
371
        // DataDir is the machine agent data directory.
 
372
        DataDir string
 
373
 
 
374
        // Namespace is the machine agent's namespace, which is used to
 
375
        // generate a unique service name for Mongo.
 
376
        Namespace string
 
377
 
 
378
        // OplogSize is the size of the Mongo oplog.
 
379
        // If this is zero, then EnsureServer will
 
380
        // calculate a default size according to the
 
381
        // algorithm defined in Mongo.
 
382
        OplogSize int
 
383
 
 
384
        // SetNumaControlPolicy preference - whether the user
 
385
        // wants to set the numa control policy when starting mongo.
 
386
        SetNumaControlPolicy bool
 
387
}
 
388
 
 
389
// EnsureServer ensures that the MongoDB server is installed,
 
390
// configured, and ready to run.
 
391
//
 
392
// This method will remove old versions of the mongo init service as necessary
 
393
// before installing the new version.
 
394
func EnsureServer(args EnsureServerParams) error {
 
395
        logger.Infof(
 
396
                "Ensuring mongo server is running; data directory %s; port %d",
 
397
                args.DataDir, args.StatePort,
 
398
        )
 
399
 
 
400
        dbDir := filepath.Join(args.DataDir, "db")
 
401
        if err := os.MkdirAll(dbDir, 0700); err != nil {
 
402
                return fmt.Errorf("cannot create mongo database directory: %v", err)
 
403
        }
 
404
 
 
405
        oplogSizeMB := args.OplogSize
 
406
        if oplogSizeMB == 0 {
 
407
                var err error
 
408
                if oplogSizeMB, err = defaultOplogSize(dbDir); err != nil {
 
409
                        return err
 
410
                }
 
411
        }
 
412
 
 
413
        operatingsystem := series.HostSeries()
 
414
        if err := installMongod(operatingsystem, args.SetNumaControlPolicy); err != nil {
 
415
                // This isn't treated as fatal because the Juju MongoDB
 
416
                // package is likely to be already installed anyway. There
 
417
                // could just be a temporary issue with apt-get/yum/whatever
 
418
                // and we don't want this to stop jujud from starting.
 
419
                // (LP #1441904)
 
420
                logger.Errorf("cannot install/upgrade mongod (will proceed anyway): %v", err)
 
421
        }
 
422
        mgoVersion := InstalledVersion()
 
423
        mongoPath, err := Path(mgoVersion)
 
424
        if err != nil {
 
425
                return err
 
426
        }
 
427
        logVersion(mongoPath)
 
428
 
 
429
        if err := UpdateSSLKey(args.DataDir, args.Cert, args.PrivateKey); err != nil {
 
430
                return err
 
431
        }
 
432
 
 
433
        err = utils.AtomicWriteFile(sharedSecretPath(args.DataDir), []byte(args.SharedSecret), 0600)
 
434
        if err != nil {
 
435
                return fmt.Errorf("cannot write mongod shared secret: %v", err)
 
436
        }
 
437
 
 
438
        // Disable the default mongodb installed by the mongodb-server package.
 
439
        // Only do this if the file doesn't exist already, so users can run
 
440
        // their own mongodb server if they wish to.
 
441
        if _, err := os.Stat(mongoConfigPath); os.IsNotExist(err) {
 
442
                err = utils.AtomicWriteFile(
 
443
                        mongoConfigPath,
 
444
                        []byte("ENABLE_MONGODB=no"),
 
445
                        0644,
 
446
                )
 
447
                if err != nil {
 
448
                        return err
 
449
                }
 
450
        }
 
451
 
 
452
        svcConf := newConf(args.DataDir, dbDir, mongoPath, args.StatePort, oplogSizeMB, args.SetNumaControlPolicy, mgoVersion, true)
 
453
        svc, err := newService(ServiceName, svcConf)
 
454
        if err != nil {
 
455
                return err
 
456
        }
 
457
        installed, err := svc.Installed()
 
458
        if err != nil {
 
459
                return errors.Trace(err)
 
460
        }
 
461
        if installed {
 
462
                exists, err := svc.Exists()
 
463
                if err != nil {
 
464
                        return errors.Trace(err)
 
465
                }
 
466
                if exists {
 
467
                        logger.Debugf("mongo exists as expected")
 
468
                        running, err := svc.Running()
 
469
                        if err != nil {
 
470
                                return errors.Trace(err)
 
471
                        }
 
472
                        if !running {
 
473
                                return svc.Start()
 
474
                        }
 
475
                        return nil
 
476
                }
 
477
        }
 
478
 
 
479
        if err := svc.Stop(); err != nil {
 
480
                return errors.Annotatef(err, "failed to stop mongo")
 
481
        }
 
482
        if err := makeJournalDirs(dbDir); err != nil {
 
483
                return fmt.Errorf("error creating journal directories: %v", err)
 
484
        }
 
485
        if err := preallocOplog(dbDir, oplogSizeMB); err != nil {
 
486
                return fmt.Errorf("error creating oplog files: %v", err)
 
487
        }
 
488
        if err := service.InstallAndStart(svc); err != nil {
 
489
                return errors.Trace(err)
 
490
        }
 
491
        return nil
 
492
}
 
493
 
 
494
// UpdateSSLKey writes a new SSL key used by mongo to validate connections from Juju controller(s)
 
495
func UpdateSSLKey(dataDir, cert, privateKey string) error {
 
496
        certKey := cert + "\n" + privateKey
 
497
        err := utils.AtomicWriteFile(sslKeyPath(dataDir), []byte(certKey), 0600)
 
498
        return errors.Annotate(err, "cannot write SSL key")
 
499
}
 
500
 
 
501
func makeJournalDirs(dataDir string) error {
 
502
        journalDir := path.Join(dataDir, "journal")
 
503
        if err := os.MkdirAll(journalDir, 0700); err != nil {
 
504
                logger.Errorf("failed to make mongo journal dir %s: %v", journalDir, err)
 
505
                return err
 
506
        }
 
507
 
 
508
        // Manually create the prealloc files, since otherwise they get
 
509
        // created as 100M files. We create three files of 1MB each.
 
510
        prefix := filepath.Join(journalDir, "prealloc.")
 
511
        preallocSize := 1024 * 1024
 
512
        return preallocFiles(prefix, preallocSize, preallocSize, preallocSize)
 
513
}
 
514
 
 
515
func logVersion(mongoPath string) {
 
516
        cmd := exec.Command(mongoPath, "--version")
 
517
        output, err := cmd.CombinedOutput()
 
518
        if err != nil {
 
519
                logger.Infof("failed to read the output from %s --version: %v", mongoPath, err)
 
520
                return
 
521
        }
 
522
        logger.Debugf("using mongod: %s --version: %q", mongoPath, output)
 
523
}
 
524
 
 
525
func installPackage(pkg string, pacconfer config.PackagingConfigurer, pacman manager.PackageManager) error {
 
526
        // apply release targeting if needed.
 
527
        if pacconfer.IsCloudArchivePackage(pkg) {
 
528
                pkg = strings.Join(pacconfer.ApplyCloudArchiveTarget(pkg), " ")
 
529
        }
 
530
 
 
531
        return pacman.Install(pkg)
 
532
}
 
533
 
 
534
func installMongod(operatingsystem string, numaCtl bool) error {
 
535
        // fetch the packaging configuration manager for the current operating system.
 
536
        pacconfer, err := config.NewPackagingConfigurer(operatingsystem)
 
537
        if err != nil {
 
538
                return err
 
539
        }
 
540
 
 
541
        // fetch the package manager implementation for the current operating system.
 
542
        pacman, err := manager.NewPackageManager(operatingsystem)
 
543
        if err != nil {
 
544
                return err
 
545
        }
 
546
 
 
547
        // CentOS requires "epel-release" for the epel repo mongodb-server is in.
 
548
        if operatingsystem == "centos7" {
 
549
                // install epel-release
 
550
                if err := pacman.Install("epel-release"); err != nil {
 
551
                        return err
 
552
                }
 
553
        }
 
554
 
 
555
        mongoPkgs, fallbackPkgs := packagesForSeries(operatingsystem)
 
556
 
 
557
        if numaCtl {
 
558
                logger.Infof("installing %v and %s", mongoPkgs, numaCtlPkg)
 
559
                if err = installPackage(numaCtlPkg, pacconfer, pacman); err != nil {
 
560
                        return errors.Trace(err)
 
561
                }
 
562
        } else {
 
563
                logger.Infof("installing %v", mongoPkgs)
 
564
        }
 
565
 
 
566
        for i := range mongoPkgs {
 
567
                if err = installPackage(mongoPkgs[i], pacconfer, pacman); err != nil {
 
568
                        break
 
569
                }
 
570
        }
 
571
        if err != nil && len(fallbackPkgs) == 0 {
 
572
                return errors.Trace(err)
 
573
        }
 
574
        if err != nil {
 
575
                logger.Errorf("installing mongo failed: %v", err)
 
576
                logger.Infof("will try fallback packages %v", fallbackPkgs)
 
577
                for i := range fallbackPkgs {
 
578
                        if err = installPackage(fallbackPkgs[i], pacconfer, pacman); err != nil {
 
579
                                return errors.Trace(err)
 
580
                        }
 
581
                }
 
582
        }
 
583
 
 
584
        // Work around SELinux on centos7
 
585
        if operatingsystem == "centos7" {
 
586
                cmd := []string{"chcon", "-R", "-v", "-t", "mongod_var_lib_t", "/var/lib/juju/"}
 
587
                logger.Infof("running %s %v", cmd[0], cmd[1:])
 
588
                _, err = utils.RunCommand(cmd[0], cmd[1:]...)
 
589
                if err != nil {
 
590
                        logger.Errorf("chcon failed to change file security context error %s", err)
 
591
                        return err
 
592
                }
 
593
 
 
594
                cmd = []string{"semanage", "port", "-a", "-t", "mongod_port_t", "-p", "tcp", strconv.Itoa(controller.DefaultStatePort)}
 
595
                logger.Infof("running %s %v", cmd[0], cmd[1:])
 
596
                _, err = utils.RunCommand(cmd[0], cmd[1:]...)
 
597
                if err != nil {
 
598
                        if !strings.Contains(err.Error(), "exit status 1") {
 
599
                                logger.Errorf("semanage failed to provide access on port %d error %s", controller.DefaultStatePort, err)
 
600
                                return err
 
601
                        }
 
602
                }
 
603
        }
 
604
 
 
605
        return nil
 
606
}
 
607
 
 
608
// packagesForSeries returns the name of the mongo package for the series
 
609
// of the machine that it is going to be running on plus a fallback for
 
610
// options where the package is going to be ready eventually but might not
 
611
// yet be.
 
612
func packagesForSeries(series string) ([]string, []string) {
 
613
        switch series {
 
614
        case "precise", "quantal", "raring", "saucy", "centos7":
 
615
                return []string{"mongodb-server"}, []string{}
 
616
        case "trusty", "wily", "xenial":
 
617
                return []string{JujuMongoPackage, JujuMongoToolsPackage}, []string{"juju-mongodb"}
 
618
        default:
 
619
                // y and onwards
 
620
                return []string{JujuMongoPackage, JujuMongoToolsPackage}, []string{}
 
621
        }
 
622
}
 
623
 
 
624
// DbDir returns the dir where mongo storage is.
 
625
func DbDir(dataDir string) string {
 
626
        return filepath.Join(dataDir, "db")
 
627
}