~ubuntu-branches/ubuntu/trusty/juju-core/trusty

« back to all changes in this revision

Viewing changes to src/launchpad.net/juju-core/agent/mongo/mongo.go

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-03-24 16:05:44 UTC
  • mfrom: (1.1.20)
  • Revision ID: package-import@ubuntu.com-20140324160544-g8lsfufby18d5fj4
Tags: 1.17.6-0ubuntu1
* New upstream point release, including fixes for:
  - br0 not bought up by cloud-init with MAAS provider (LP: #1271144).
  - ppc64el enablement for juju/lxc (LP: #1273769).
  - juju userdata should not restart networking (LP: #1248283).
  - error detecting hardware characteristics (LP: #1276909).
  - juju instances not including the default security group (LP: #1129720).
  - juju bootstrap does not honor https_proxy (LP: #1240260).
* d/control,rules: Drop BD on bash-completion, install bash-completion
  direct from upstream source code.
* d/rules: Set HOME prior to generating man pages.
* d/control: Drop alternative dependency on mongodb-server; juju now only
  works on trusty with juju-mongodb.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package mongo
 
2
 
 
3
import (
 
4
        "fmt"
 
5
        "os"
 
6
        "os/exec"
 
7
        "path"
 
8
        "path/filepath"
 
9
 
 
10
        "github.com/juju/loggo"
 
11
 
 
12
        "launchpad.net/juju-core/upstart"
 
13
        "launchpad.net/juju-core/utils"
 
14
)
 
15
 
 
16
const (
 
17
        maxFiles = 65000
 
18
        maxProcs = 20000
 
19
)
 
20
 
 
21
var (
 
22
        logger = loggo.GetLogger("juju.agent.mongo")
 
23
 
 
24
        oldMongoServiceName = "juju-db"
 
25
 
 
26
        // JujuMongodPath holds the default path to the juju-specific mongod.
 
27
        JujuMongodPath = "/usr/lib/juju/bin/mongod"
 
28
        // MongodbServerPath holds the default path to the generic mongod.
 
29
        MongodbServerPath = "/usr/bin/mongod"
 
30
)
 
31
 
 
32
// MongoPackageForSeries returns the name of the mongo package for the series
 
33
// of the machine that it is going to be running on.
 
34
func MongoPackageForSeries(series string) string {
 
35
        switch series {
 
36
        case "precise", "quantal", "raring", "saucy":
 
37
                return "mongodb-server"
 
38
        default:
 
39
                // trusty and onwards
 
40
                return "juju-mongodb"
 
41
        }
 
42
}
 
43
 
 
44
// MongodPathForSeries returns the path to the mongod executable for the
 
45
// series of the machine that it is going to be running on.
 
46
func MongodPathForSeries(series string) string {
 
47
        if series == "trusty" {
 
48
                return JujuMongodPath
 
49
        }
 
50
        return MongodbServerPath
 
51
}
 
52
 
 
53
// MongoPath returns the executable path to be used to run mongod on this
 
54
// machine. If the juju-bundled version of mongo exists, it will return that
 
55
// path, otherwise it will return the command to run mongod from the path.
 
56
func MongodPath() (string, error) {
 
57
        if _, err := os.Stat(JujuMongodPath); err == nil {
 
58
                return JujuMongodPath, nil
 
59
        }
 
60
 
 
61
        path, err := exec.LookPath("mongod")
 
62
        if err != nil {
 
63
                return "", err
 
64
        }
 
65
        return path, nil
 
66
}
 
67
 
 
68
// EnsureMongoServer ensures that the correct mongo upstart script is installed
 
69
// and running.
 
70
//
 
71
// This method will remove old versions of the mongo upstart script as necessary
 
72
// before installing the new version.
 
73
func EnsureMongoServer(dir string, port int) error {
 
74
        // NOTE: ensure that the right package is installed?
 
75
        name := makeServiceName(mongoScriptVersion)
 
76
        // TODO: get the series from somewhere, non trusty values return
 
77
        // the existing default path.
 
78
        mongodPath := MongodPathForSeries("some-series")
 
79
        service, err := MongoUpstartService(name, mongodPath, dir, port)
 
80
        if err != nil {
 
81
                return err
 
82
        }
 
83
        if service.Installed() {
 
84
                return nil
 
85
        }
 
86
 
 
87
        if err := removeOldMongoServices(mongoScriptVersion); err != nil {
 
88
                return err
 
89
        }
 
90
 
 
91
        if err := makeJournalDirs(dir); err != nil {
 
92
                return err
 
93
        }
 
94
 
 
95
        if err := service.Install(); err != nil {
 
96
                return fmt.Errorf("failed to install mongo service %q: %v", service.Name, err)
 
97
        }
 
98
        return service.Start()
 
99
}
 
100
 
 
101
func makeJournalDirs(dir string) error {
 
102
        journalDir := path.Join(dir, "journal")
 
103
 
 
104
        if err := os.MkdirAll(journalDir, 0700); err != nil {
 
105
                logger.Errorf("failed to make mongo journal dir %s: %v", journalDir, err)
 
106
                return err
 
107
        }
 
108
 
 
109
        // manually create the prealloc files, since otherwise they get created as 100M files.
 
110
        zeroes := make([]byte, 64*1024) // should be enough for anyone
 
111
        for x := 0; x < 3; x++ {
 
112
                name := fmt.Sprintf("prealloc.%d", x)
 
113
                filename := filepath.Join(journalDir, name)
 
114
                f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0700)
 
115
                if err != nil {
 
116
                        return fmt.Errorf("failed to open mongo prealloc file %q: %v", filename, err)
 
117
                }
 
118
                defer f.Close()
 
119
                for total := 0; total < 1024*1024; {
 
120
                        n, err := f.Write(zeroes)
 
121
                        if err != nil {
 
122
                                return fmt.Errorf("failed to write to mongo prealloc file %q: %v", filename, err)
 
123
                        }
 
124
                        total += n
 
125
                }
 
126
        }
 
127
        return nil
 
128
}
 
129
 
 
130
// removeOldMongoServices looks for any old juju mongo upstart scripts and
 
131
// removes them.
 
132
func removeOldMongoServices(curVersion int) error {
 
133
        old := upstart.NewService(oldMongoServiceName)
 
134
        if err := old.StopAndRemove(); err != nil {
 
135
                logger.Errorf("Failed to remove old mongo upstart service %q: %v", old.Name, err)
 
136
                return err
 
137
        }
 
138
 
 
139
        // the new formatting for the script name started at version 2
 
140
        for x := 2; x < curVersion; x++ {
 
141
                old := upstart.NewService(makeServiceName(x))
 
142
                if err := old.StopAndRemove(); err != nil {
 
143
                        logger.Errorf("Failed to remove old mongo upstart service %q: %v", old.Name, err)
 
144
                        return err
 
145
                }
 
146
        }
 
147
        return nil
 
148
}
 
149
 
 
150
func makeServiceName(version int) string {
 
151
        return fmt.Sprintf("juju-db-v%d", version)
 
152
}
 
153
 
 
154
// mongoScriptVersion keeps track of changes to the mongo upstart script.
 
155
// Update this version when you update the script that gets installed from
 
156
// MongoUpstartService.
 
157
const mongoScriptVersion = 2
 
158
 
 
159
// MongoUpstartService returns the upstart config for the mongo state service.
 
160
//
 
161
// This method assumes there is a server.pem keyfile in dataDir.
 
162
func MongoUpstartService(name, mongodExec, dataDir string, port int) (*upstart.Conf, error) {
 
163
 
 
164
        keyFile := path.Join(dataDir, "server.pem")
 
165
        svc := upstart.NewService(name)
 
166
 
 
167
        dbDir := path.Join(dataDir, "db")
 
168
 
 
169
        conf := &upstart.Conf{
 
170
                Service: *svc,
 
171
                Desc:    "juju state database",
 
172
                Limit: map[string]string{
 
173
                        "nofile": fmt.Sprintf("%d %d", maxFiles, maxFiles),
 
174
                        "nproc":  fmt.Sprintf("%d %d", maxProcs, maxProcs),
 
175
                },
 
176
                Cmd: mongodExec +
 
177
                        " --auth" +
 
178
                        " --dbpath=" + dbDir +
 
179
                        " --sslOnNormalPorts" +
 
180
                        " --sslPEMKeyFile " + utils.ShQuote(keyFile) +
 
181
                        " --sslPEMKeyPassword ignored" +
 
182
                        " --bind_ip 0.0.0.0" +
 
183
                        " --port " + fmt.Sprint(port) +
 
184
                        " --noprealloc" +
 
185
                        " --syslog" +
 
186
                        " --smallfiles",
 
187
                // TODO(Nate): uncomment when we commit HA stuff
 
188
                // +
 
189
                //      " --replSet juju",
 
190
        }
 
191
        return conf, nil
 
192
}