Merge lp:~natefinch/juju-core/026-EnsureMongoServer into lp:~go-bot/juju-core/trunk

Proposed by Nate Finch
Status: Work in progress
Proposed branch: lp:~natefinch/juju-core/026-EnsureMongoServer
Merge into: lp:~go-bot/juju-core/trunk
Diff against target: 756 lines (+448/-26) (has conflicts)
10 files modified
agent/agent.go (+10/-0)
cmd/jujud/machine.go (+136/-14)
cmd/jujud/machine_test.go (+9/-0)
environs/cloudinit/cloudinit.go (+16/-3)
provider/local/config.go (+0/-5)
provider/local/environ.go (+210/-0)
replicaset/replicaset.go (+4/-0)
testing/mockupstart.go (+42/-0)
upstart/service.go (+13/-2)
upstart/upstart.go (+8/-2)
Text conflict in cmd/jujud/machine.go
Text conflict in cmd/jujud/machine_test.go
Text conflict in environs/cloudinit/cloudinit.go
Text conflict in provider/local/environ.go
Text conflict in replicaset/replicaset.go
To merge this branch: bzr merge lp:~natefinch/juju-core/026-EnsureMongoServer
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+201961@code.launchpad.net

Description of the change

EnsureMongoServer function for MachineAgent

Implement a method to allow the machine agent to create & run the upstart script for mongo.

https://codereview.appspot.com/53220043/

To post a comment you must log in.
Revision history for this message
Roger Peppe (rogpeppe) wrote :

Looks good so far, with a couple of suggestions/queries below.

https://codereview.appspot.com/53220043/diff/20001/agent/agent.go
File agent/agent.go (right):

https://codereview.appspot.com/53220043/diff/20001/agent/agent.go#newcode232
agent/agent.go:232: func MongoDbDir(dir string) string {
or this could be a method on Config.

at the least, dir should be named "dataDir"

https://codereview.appspot.com/53220043/diff/20001/cmd/jujud/machine.go
File cmd/jujud/machine.go (right):

https://codereview.appspot.com/53220043/diff/20001/cmd/jujud/machine.go#newcode386
cmd/jujud/machine.go:386: if err := conf.Install(); err != nil {
Do we really want to do this every time the machine agent bounces?
If possible I'd prefer to avoid bouncing mongod in that case.

https://codereview.appspot.com/53220043/diff/20001/replicaset/replicaset.go
File replicaset/replicaset.go (right):

https://codereview.appspot.com/53220043/diff/20001/replicaset/replicaset.go#newcode257
replicaset/replicaset.go:257: State MemberState `bson:"State"`
"state", surely?

https://codereview.appspot.com/53220043/

Revision history for this message
Nate Finch (natefinch) wrote :

Reviewers: mp+201961_code.launchpad.net, rog,

Message:
Some more clean up, and now add the "ensure" part of ensure mongo
server. Also consolidated the code so we only do this in machine agent.

Also, just ignore the stuff in replicaset.go, it's not really part of
this change and I'll remove it.

Description:
EnxureMongoServer function for MachineAgent

IMplement a method to allow the machine agent to create & run the
upstart script for mongo.

https://code.launchpad.net/~natefinch/juju-core/026-EnsureMongoServer/+merge/201961

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/53220043/

Affected files (+130, -58 lines):
   A [revision details]
   M agent/agent.go
   cmd/jujud/machine.go
   M environs/cloudinit/cloudinit.go
   M provider/local/config.go
   M provider/local/environ.go
   M replicaset/replicaset.go
   M replicaset/replicaset_test.go
   M upstart/service.go

Revision history for this message
Nate Finch (natefinch) wrote :
Revision history for this message
William Reade (fwereade) wrote :

couple of quick comments, I think I may have misunderstood the StatePort
bits, can we chat when you're free?

https://codereview.appspot.com/53220043/diff/60001/agent/agent.go
File agent/agent.go (right):

https://codereview.appspot.com/53220043/diff/60001/agent/agent.go#newcode99
agent/agent.go:99: StatePort() int
I'm a bit bothered about storing this in agent config. And actually
about storing *any* of this stuff in agent config -- we have manual
bootstrap now, and I don't see why this is needed any more.

https://codereview.appspot.com/53220043/diff/60001/provider/local/environ.go
File provider/local/environ.go (right):

https://codereview.appspot.com/53220043/diff/60001/provider/local/environ.go#newcode427
provider/local/environ.go:427: journalDir :=
filepath.Join(env.config.rootDir(), "db/journal")
"db", "journal"?

https://codereview.appspot.com/53220043/diff/60001/upstart/service.go
File upstart/service.go (right):

https://codereview.appspot.com/53220043/diff/60001/upstart/service.go#newcode26
upstart/service.go:26: func MongoUpstartService(name, dataDir string,
port int) *Conf {
Hmm, I'm really not sure this is the right package for this file. Isn't
this stuff all specific to instance config?

https://codereview.appspot.com/53220043/

2185. By Nate Finch

Add code to mock out upstart so we can successfully run the new machine agent code during tests. Also added code to only run EnsureMongoServer when the machine agent has the ManageEnviron job

2186. By Nate Finch

fix a couple build errors

2187. By Nate Finch

make sure the bootstrap node doesn't try to connect to the API to get its state

2188. By Nate Finch

I should learn to hit save before commiting

Unmerged revisions

2188. By Nate Finch

I should learn to hit save before commiting

2187. By Nate Finch

make sure the bootstrap node doesn't try to connect to the API to get its state

2186. By Nate Finch

fix a couple build errors

2185. By Nate Finch

Add code to mock out upstart so we can successfully run the new machine agent code during tests. Also added code to only run EnsureMongoServer when the machine agent has the ManageEnviron job

2184. By Nate Finch

add the ensure part of ensuremongoserver, also remove the old upstart stuff so we always run it from machine agent

2183. By Nate Finch

twiddle the comment to help kick rietveld

2182. By Nate Finch

line got deleted somehow

2181. By Nate Finch

create ensuremongoserver function to create/rewrite the mongo upstart script from the machine agent

2180. By Nate Finch

Let's spell replSet correctly, eh?

2179. By Nate Finch

uncomment some tests, change mongo upstart to always set mongo in replicaset mode

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'agent/agent.go'
--- agent/agent.go 2014-01-23 05:21:21 +0000
+++ agent/agent.go 2014-01-28 15:13:44 +0000
@@ -95,6 +95,10 @@
95 // SetValue updates the value for the specified key.95 // SetValue updates the value for the specified key.
96 SetValue(key, value string)96 SetValue(key, value string)
9797
98 // StatePort specifies the TCP port that will be used
99 // by the MongoDB server if one is running on this machine.
100 StatePort() int
101
98 StateInitializer102 StateInitializer
99}103}
100104
@@ -133,6 +137,7 @@
133 stateServerKey []byte137 stateServerKey []byte
134 apiPort int138 apiPort int
135 values map[string]string139 values map[string]string
140 statePort int
136}141}
137142
138type AgentConfigParams struct {143type AgentConfigParams struct {
@@ -215,6 +220,7 @@
215 config.stateServerCert = params.StateServerCert220 config.stateServerCert = params.StateServerCert
216 config.stateServerKey = params.StateServerKey221 config.stateServerKey = params.StateServerKey
217 config.apiPort = params.APIPort222 config.apiPort = params.APIPort
223 config.statePort = params.StatePort
218 return config, nil224 return config, nil
219}225}
220226
@@ -321,6 +327,10 @@
321 return Dir(c.dataDir, c.tag)327 return Dir(c.dataDir, c.tag)
322}328}
323329
330func (c *configInternal) StatePort() int {
331 return c.statePort
332}
333
324func (c *configInternal) check() error {334func (c *configInternal) check() error {
325 if c.stateDetails == nil && c.apiDetails == nil {335 if c.stateDetails == nil && c.apiDetails == nil {
326 return requiredError("state or API addresses")336 return requiredError("state or API addresses")
327337
=== modified file 'cmd/jujud/machine.go'
--- cmd/jujud/machine.go 2014-01-24 14:52:58 +0000
+++ cmd/jujud/machine.go 2014-01-28 15:13:44 +0000
@@ -5,6 +5,7 @@
55
6import (6import (
7 "fmt"7 "fmt"
8 "io/ioutil"
8 "os"9 "os"
9 "path/filepath"10 "path/filepath"
10 "time"11 "time"
@@ -45,15 +46,23 @@
45 "launchpad.net/juju-core/worker/upgrader"46 "launchpad.net/juju-core/worker/upgrader"
46)47)
4748
48var logger = loggo.GetLogger("juju.cmd.jujud")49const (
4950 mongoSvcFmt = "juju-db-v%d"
50var newRunner = func(isFatal func(error) bool, moreImportant func(e0, e1 error) bool) worker.Runner {51 bootstrapMachineId = "0"
51 return worker.NewRunner(isFatal, moreImportant)52 oldMongoServiceName = "juju-db"
52}53)
5354
54const bootstrapMachineId = "0"55var (
5556 logger = loggo.GetLogger("juju.cmd.jujud")
56var retryDelay = 3 * time.Second57
58 newRunner = func(isFatal func(error) bool, moreImportant func(e0, e1 error) bool) worker.Runner {
59 return worker.NewRunner(isFatal, moreImportant)
60 }
61
62 mongoServiceName = fmt.Sprintf(mongoSvcFmt, upstart.MongoScriptVersion)
63
64 retryDelay = 3 * time.Second
65)
5766
58var jujuRun = "/usr/local/bin/juju-run"67var jujuRun = "/usr/local/bin/juju-run"
5968
@@ -119,6 +128,16 @@
119 return err128 return err
120 }129 }
121130
131 mgr, err := a.isEnvironManager()
132 if err != nil {
133 return err
134 }
135 if mgr {
136 if err := a.ensureMongoServer(); err != nil {
137 return err
138 }
139 }
140
122 // ensureStateWorker ensures that there is a worker that141 // ensureStateWorker ensures that there is a worker that
123 // connects to the state that runs within itself all the workers142 // connects to the state that runs within itself all the workers
124 // that need a state connection. Unless we're bootstrapping, we143 // that need a state connection. Unless we're bootstrapping, we
@@ -144,10 +163,14 @@
144 a.runner.StartWorker("api", func() (worker.Worker, error) {163 a.runner.StartWorker("api", func() (worker.Worker, error) {
145 return a.APIWorker(ensureStateWorker)164 return a.APIWorker(ensureStateWorker)
146 })165 })
166<<<<<<< TREE
147 a.runner.StartWorker("termination", func() (worker.Worker, error) {167 a.runner.StartWorker("termination", func() (worker.Worker, error) {
148 return terminationworker.NewWorker(), nil168 return terminationworker.NewWorker(), nil
149 })169 })
150 err := a.runner.Wait()170 err := a.runner.Wait()
171=======
172 err = a.runner.Wait()
173>>>>>>> MERGE-SOURCE
151 if err == worker.ErrTerminateAgent {174 if err == worker.ErrTerminateAgent {
152 err = a.uninstallAgent()175 err = a.uninstallAgent()
153 }176 }
@@ -361,6 +384,7 @@
361 return names.MachineTag(a.MachineId)384 return names.MachineTag(a.MachineId)
362}385}
363386
387<<<<<<< TREE
364func (a *MachineAgent) initAgent() error {388func (a *MachineAgent) initAgent() error {
365 if err := os.Remove(jujuRun); err != nil && !os.IsNotExist(err) {389 if err := os.Remove(jujuRun); err != nil && !os.IsNotExist(err) {
366 return err390 return err
@@ -369,6 +393,29 @@
369 return os.Symlink(jujud, jujuRun)393 return os.Symlink(jujud, jujuRun)
370}394}
371395
396=======
397// isEnvironManager returns if the current agent has the ManageEnviron job.
398func (a *MachineAgent) isEnvironManager() (bool, error) {
399 if a.MachineId == bootstrapMachineId {
400 return true, nil
401 }
402
403 st, entity, err := openAPIState(a.Conf.config, a)
404 if err != nil {
405 return false, err
406 }
407 defer st.Close()
408 reportOpenedAPI(st)
409
410 for _, job := range entity.Jobs() {
411 if job == params.JobManageEnviron {
412 return true, nil
413 }
414 }
415 return false, nil
416}
417
418>>>>>>> MERGE-SOURCE
372func (a *MachineAgent) uninstallAgent() error {419func (a *MachineAgent) uninstallAgent() error {
373 var errors []error420 var errors []error
374 agentServiceName := a.Conf.config.Value(agent.AgentServiceName)421 agentServiceName := a.Conf.config.Value(agent.AgentServiceName)
@@ -381,6 +428,7 @@
381 errors = append(errors, fmt.Errorf("cannot remove service %q: %v", agentServiceName, err))428 errors = append(errors, fmt.Errorf("cannot remove service %q: %v", agentServiceName, err))
382 }429 }
383 }430 }
431<<<<<<< TREE
384 // Remove the rsyslog conf file and restart rsyslogd.432 // Remove the rsyslog conf file and restart rsyslogd.
385 if rsyslogConfPath := a.Conf.config.Value(agent.RsyslogConfPath); rsyslogConfPath != "" {433 if rsyslogConfPath := a.Conf.config.Value(agent.RsyslogConfPath); rsyslogConfPath != "" {
386 if err := os.Remove(rsyslogConfPath); err != nil {434 if err := os.Remove(rsyslogConfPath); err != nil {
@@ -394,15 +442,16 @@
394 if err := os.Remove(jujuRun); err != nil && !os.IsNotExist(err) {442 if err := os.Remove(jujuRun); err != nil && !os.IsNotExist(err) {
395 errors = append(errors, err)443 errors = append(errors, err)
396 }444 }
445=======
446
447>>>>>>> MERGE-SOURCE
397 // The machine agent may terminate without knowing its jobs,448 // The machine agent may terminate without knowing its jobs,
398 // for example if the machine's entry in state was removed.449 // for example if the machine's entry in state was removed.
399 // Thus, we do not rely on jobs here, and instead just check450 // Thus, we do not rely on jobs here, and instead just check
400 // if the upstart config exists.451 // if the upstart config exists.
401 mongoServiceName := a.Conf.config.Value(agent.MongoServiceName)452 mongo := a.mongoService()
402 if mongoServiceName != "" {453 if err := mongo.StopAndRemove(); err != nil {
403 if err := upstart.NewService(mongoServiceName).StopAndRemove(); err != nil {454 errors = append(errors, fmt.Errorf("cannot stop/remove service %q: %v", mongo.Name, err))
404 errors = append(errors, fmt.Errorf("cannot stop/remove service %q: %v", mongoServiceName, err))
405 }
406 }455 }
407 if err := os.RemoveAll(a.Conf.dataDir); err != nil {456 if err := os.RemoveAll(a.Conf.dataDir); err != nil {
408 errors = append(errors, err)457 errors = append(errors, err)
@@ -413,6 +462,79 @@
413 return fmt.Errorf("uninstall failed: %v", errors)462 return fmt.Errorf("uninstall failed: %v", errors)
414}463}
415464
465// ensureMongoServer ensures that the correct mongo upstart script is installed
466// and running.
467//
468// This method will remove old versions of the mongo upstart script as necessary
469// before installing the new version.
470func (a *MachineAgent) ensureMongoServer() error {
471 service := a.mongoService()
472 if service.Installed() {
473 return nil
474 }
475
476 if err := removeOldMongoServices(); err != nil {
477 return err
478 }
479
480 journalDir := filepath.Join(a.mongoDir(), "journal")
481
482 if err := os.MkdirAll(journalDir, 0700); err != nil {
483 logger.Errorf("failed to make mongo journal dir %s: %v", journalDir, err)
484 return err
485 }
486
487 // manually create the prealloc files, since otherwise they get created as 100M files.
488 zeroes := make([]byte, 1024*1024)
489 for x := 0; x < 3; x++ {
490 name := fmt.Sprintf("prealloc.%d", x)
491 filename := filepath.Join(journalDir, name)
492 if err := ioutil.WriteFile(filename, zeroes, 700); err != nil {
493 logger.Errorf("failed to make write mongo prealloc file: %v", journalDir, err)
494 return err
495 }
496 }
497
498 if err := service.Install(); err != nil {
499 logger.Errorf("Failed to install mongo service %q: %v", service.Name, err)
500 return err
501 }
502 return service.Start()
503}
504
505// mongoDir returns the directory that mongo should use to store its data.
506func (a *MachineAgent) mongoDir() string {
507 return a.Conf.dataDir
508}
509
510// mongoSvcConfig returns the upstart configuration object for mongo.
511func (a *MachineAgent) mongoService() *upstart.Conf {
512 return upstart.MongoUpstartService(
513 mongoServiceName,
514 a.mongoDir(),
515 a.Conf.config.StatePort())
516}
517
518// removeOldMongoServices looks for any old juju mongo upstart scripts and
519// removes them.
520func removeOldMongoServices() error {
521 old := upstart.NewService(oldMongoServiceName)
522 if err := old.StopAndRemove(); err != nil {
523 logger.Errorf("Failed to remove old mongo upstart service %q: %v", old.Name, err)
524 return err
525 }
526
527 // the new formatting for the script name started at version 2
528 for x := 2; x < upstart.MongoScriptVersion; x++ {
529 old := upstart.NewService(fmt.Sprintf(mongoSvcFmt, x))
530 if err := old.StopAndRemove(); err != nil {
531 logger.Errorf("Failed to remove old mongo upstart service %q: %v", old.Name, err)
532 return err
533 }
534 }
535 return nil
536}
537
416// Below pieces are used for testing,to give us access to the *State opened538// Below pieces are used for testing,to give us access to the *State opened
417// by the agent, and allow us to trigger syncs without waiting 5s for them539// by the agent, and allow us to trigger syncs without waiting 5s for them
418// to happen automatically.540// to happen automatically.
419541
=== modified file 'cmd/jujud/machine_test.go'
--- cmd/jujud/machine_test.go 2014-01-24 14:52:58 +0000
+++ cmd/jujud/machine_test.go 2014-01-28 15:13:44 +0000
@@ -29,6 +29,7 @@
29 charmtesting "launchpad.net/juju-core/state/apiserver/charmrevisionupdater/testing"29 charmtesting "launchpad.net/juju-core/state/apiserver/charmrevisionupdater/testing"
30 statetesting "launchpad.net/juju-core/state/testing"30 statetesting "launchpad.net/juju-core/state/testing"
31 "launchpad.net/juju-core/state/watcher"31 "launchpad.net/juju-core/state/watcher"
32 "launchpad.net/juju-core/testing"
32 coretesting "launchpad.net/juju-core/testing"33 coretesting "launchpad.net/juju-core/testing"
33 jc "launchpad.net/juju-core/testing/checkers"34 jc "launchpad.net/juju-core/testing/checkers"
34 "launchpad.net/juju-core/testing/testbase"35 "launchpad.net/juju-core/testing/testbase"
@@ -44,6 +45,7 @@
44type MachineSuite struct {45type MachineSuite struct {
45 agentSuite46 agentSuite
46 lxctesting.TestSuite47 lxctesting.TestSuite
48 testing.MockUpstartSuite
47}49}
4850
49var _ = gc.Suite(&MachineSuite{})51var _ = gc.Suite(&MachineSuite{})
@@ -51,6 +53,7 @@
51func (s *MachineSuite) SetUpSuite(c *gc.C) {53func (s *MachineSuite) SetUpSuite(c *gc.C) {
52 s.agentSuite.SetUpSuite(c)54 s.agentSuite.SetUpSuite(c)
53 s.TestSuite.SetUpSuite(c)55 s.TestSuite.SetUpSuite(c)
56 s.MockUpstartSuite.SetUpSuite(c)
54 restore := testbase.PatchValue(&charm.CacheDir, c.MkDir())57 restore := testbase.PatchValue(&charm.CacheDir, c.MkDir())
55 s.AddSuiteCleanup(func(*gc.C) { restore() })58 s.AddSuiteCleanup(func(*gc.C) { restore() })
56}59}
@@ -58,21 +61,27 @@
58func (s *MachineSuite) TearDownSuite(c *gc.C) {61func (s *MachineSuite) TearDownSuite(c *gc.C) {
59 s.TestSuite.TearDownSuite(c)62 s.TestSuite.TearDownSuite(c)
60 s.agentSuite.TearDownSuite(c)63 s.agentSuite.TearDownSuite(c)
64 s.MockUpstartSuite.TearDownSuite(c)
61}65}
6266
63func (s *MachineSuite) SetUpTest(c *gc.C) {67func (s *MachineSuite) SetUpTest(c *gc.C) {
64 s.agentSuite.SetUpTest(c)68 s.agentSuite.SetUpTest(c)
65 s.TestSuite.SetUpTest(c)69 s.TestSuite.SetUpTest(c)
70<<<<<<< TREE
66 os.Remove(jujuRun) // ignore error; may not exist71 os.Remove(jujuRun) // ignore error; may not exist
67 // Fake $HOME, and ssh user to avoid touching ~ubuntu/.ssh/authorized_keys.72 // Fake $HOME, and ssh user to avoid touching ~ubuntu/.ssh/authorized_keys.
68 fakeHome := coretesting.MakeEmptyFakeHomeWithoutJuju(c)73 fakeHome := coretesting.MakeEmptyFakeHomeWithoutJuju(c)
69 s.AddCleanup(func(*gc.C) { fakeHome.Restore() })74 s.AddCleanup(func(*gc.C) { fakeHome.Restore() })
70 s.PatchValue(&authenticationworker.SSHUser, "")75 s.PatchValue(&authenticationworker.SSHUser, "")
76=======
77 s.MockUpstartSuite.SetUpTest(c)
78>>>>>>> MERGE-SOURCE
71}79}
7280
73func (s *MachineSuite) TearDownTest(c *gc.C) {81func (s *MachineSuite) TearDownTest(c *gc.C) {
74 s.TestSuite.TearDownTest(c)82 s.TestSuite.TearDownTest(c)
75 s.agentSuite.TearDownTest(c)83 s.agentSuite.TearDownTest(c)
84 s.MockUpstartSuite.TearDownTest(c)
76}85}
7786
78const initialMachinePassword = "machine-password-1234567890"87const initialMachinePassword = "machine-password-1234567890"
7988
=== modified file 'environs/cloudinit/cloudinit.go'
--- environs/cloudinit/cloudinit.go 2014-01-26 23:28:43 +0000
+++ environs/cloudinit/cloudinit.go 2014-01-28 15:13:44 +0000
@@ -352,9 +352,7 @@
352 }352 }
353 certKey := string(cfg.StateServerCert) + string(cfg.StateServerKey)353 certKey := string(cfg.StateServerCert) + string(cfg.StateServerKey)
354 c.AddFile(cfg.dataFile("server.pem"), certKey, 0600)354 c.AddFile(cfg.dataFile("server.pem"), certKey, 0600)
355 if err := cfg.addMongoToBoot(c); err != nil {355
356 return err
357 }
358 // We temporarily give bootstrap-state a directory356 // We temporarily give bootstrap-state a directory
359 // of its own so that it can get the state info via the357 // of its own so that it can get the state info via the
360 // same mechanism as other jujud commands.358 // same mechanism as other jujud commands.
@@ -449,11 +447,16 @@
449 if err != nil {447 if err != nil {
450 return nil, err448 return nil, err
451 }449 }
450<<<<<<< TREE
452 acfg.SetValue(agent.RsyslogConfPath, cfg.RsyslogConfPath)451 acfg.SetValue(agent.RsyslogConfPath, cfg.RsyslogConfPath)
453 acfg.SetValue(agent.AgentServiceName, cfg.MachineAgentServiceName)452 acfg.SetValue(agent.AgentServiceName, cfg.MachineAgentServiceName)
454 if cfg.StateServer {453 if cfg.StateServer {
455 acfg.SetValue(agent.MongoServiceName, cfg.MongoServiceName)454 acfg.SetValue(agent.MongoServiceName, cfg.MongoServiceName)
456 }455 }
456=======
457 acfg.SetValue(agent.AgentServiceName, machineAgentServiceName(tag))
458
459>>>>>>> MERGE-SOURCE
457 cmds, err := acfg.WriteCommands()460 cmds, err := acfg.WriteCommands()
458 if err != nil {461 if err != nil {
459 return nil, err462 return nil, err
@@ -462,6 +465,13 @@
462 return acfg, nil465 return acfg, nil
463}466}
464467
468<<<<<<< TREE
469=======
470func machineAgentServiceName(tag string) string {
471 return "jujud-" + tag
472}
473
474>>>>>>> MERGE-SOURCE
465func (cfg *MachineConfig) addMachineAgentToBoot(c *cloudinit.Config, tag, machineId string) error {475func (cfg *MachineConfig) addMachineAgentToBoot(c *cloudinit.Config, tag, machineId string) error {
466 // Make the agent run via a symbolic link to the actual tools476 // Make the agent run via a symbolic link to the actual tools
467 // directory, so it can upgrade itself without needing to change477 // directory, so it can upgrade itself without needing to change
@@ -481,6 +491,7 @@
481 return nil491 return nil
482}492}
483493
494<<<<<<< TREE
484func (cfg *MachineConfig) addMongoToBoot(c *cloudinit.Config) error {495func (cfg *MachineConfig) addMongoToBoot(c *cloudinit.Config) error {
485 dbDir := path.Join(cfg.DataDir, "db")496 dbDir := path.Join(cfg.DataDir, "db")
486 c.AddScripts(497 c.AddScripts(
@@ -503,6 +514,8 @@
503 return nil514 return nil
504}515}
505516
517=======
518>>>>>>> MERGE-SOURCE
506// versionDir converts a tools URL into a name519// versionDir converts a tools URL into a name
507// to use as a directory for storing the tools executables in520// to use as a directory for storing the tools executables in
508// by using the last element stripped of its extension.521// by using the last element stripped of its extension.
509522
=== modified file 'provider/local/config.go'
--- provider/local/config.go 2014-01-24 01:50:07 +0000
+++ provider/local/config.go 2014-01-28 15:13:44 +0000
@@ -81,10 +81,6 @@
81 return filepath.Join(c.rootDir(), "storage")81 return filepath.Join(c.rootDir(), "storage")
82}82}
8383
84func (c *environConfig) mongoDir() string {
85 return filepath.Join(c.rootDir(), "db")
86}
87
88func (c *environConfig) logDir() string {84func (c *environConfig) logDir() string {
89 return filepath.Join(c.rootDir(), "log")85 return filepath.Join(c.rootDir(), "log")
90}86}
@@ -127,7 +123,6 @@
127 for _, dirname := range []string{123 for _, dirname := range []string{
128 c.sharedStorageDir(),124 c.sharedStorageDir(),
129 c.storageDir(),125 c.storageDir(),
130 c.mongoDir(),
131 c.logDir(),126 c.logDir(),
132 } {127 } {
133 logger.Tracef("creating directory %s", dirname)128 logger.Tracef("creating directory %s", dirname)
134129
=== modified file 'provider/local/environ.go'
--- provider/local/environ.go 2014-01-24 14:52:58 +0000
+++ provider/local/environ.go 2014-01-28 15:13:44 +0000
@@ -449,3 +449,213 @@
449func (env *localEnviron) Provider() environs.EnvironProvider {449func (env *localEnviron) Provider() environs.EnvironProvider {
450 return providerInstance450 return providerInstance
451}451}
452<<<<<<< TREE
453=======
454
455// setupLocalMongoService returns the cert and key if there was no error.
456func (env *localEnviron) setupLocalMongoService() ([]byte, []byte, error) {
457 journalDir := filepath.Join(env.config.rootDir(), "db/journal")
458 logger.Debugf("create mongo journal dir: %v", journalDir)
459 if err := os.MkdirAll(journalDir, 0755); err != nil {
460 logger.Errorf("failed to make mongo journal dir %s: %v", journalDir, err)
461 return nil, nil, err
462 }
463
464 logger.Debugf("generate server cert")
465 cert, key, err := env.config.GenerateStateServerCertAndKey()
466 if err != nil {
467 logger.Errorf("failed to generate server cert: %v", err)
468 return nil, nil, err
469 }
470 if err := ioutil.WriteFile(
471 env.config.configFile("server.pem"),
472 append(cert, key...),
473 0600); err != nil {
474 logger.Errorf("failed to write server.pem: %v", err)
475 return nil, nil, err
476 }
477
478 mongo := upstart.MongoUpstartService(
479 env.mongoServiceName(),
480 env.config.rootDir(),
481 env.config.StatePort())
482 mongo.InitDir = upstartScriptLocation
483 logger.Infof("installing service %s to %s", env.mongoServiceName(), mongo.InitDir)
484 if err := mongo.Install(); err != nil {
485 logger.Errorf("could not install mongo service: %v", err)
486 return nil, nil, err
487 }
488 return cert, key, nil
489}
490
491func (env *localEnviron) setupLocalMachineAgent(cons constraints.Value, possibleTools tools.List) error {
492 dataDir := env.config.rootDir()
493 // unpack the first tools into the agent dir.
494 agentTools := possibleTools[0]
495 logger.Debugf("tools: %#v", agentTools)
496 // brutally abuse our knowledge of storage to directly open the file
497 toolsUrl, err := url.Parse(agentTools.URL)
498 if err != nil {
499 return err
500 }
501 toolsLocation := filepath.Join(env.config.storageDir(), toolsUrl.Path)
502 logger.Infof("tools location: %v", toolsLocation)
503 toolsFile, err := os.Open(toolsLocation)
504 defer toolsFile.Close()
505 // Again, brutally abuse our knowledge here.
506
507 // The tools that possible bootstrap tools are based on the
508 // default series in the config. However we are running potentially on a
509 // different series. When the machine agent is started, it will be
510 // looking based on the current series, so we need to override the series
511 // returned in the tools to be the current series.
512 agentTools.Version.Series = version.Current.Series
513 err = agenttools.UnpackTools(dataDir, agentTools, toolsFile)
514
515 machineId := "0" // Always machine 0
516 tag := names.MachineTag(machineId)
517
518 // make sure we create the symlink so we have it for the upstart config to use
519 if _, err := agenttools.ChangeAgentTools(dataDir, tag, agentTools.Version); err != nil {
520 logger.Errorf("could not create tools directory symlink: %v", err)
521 return err
522 }
523
524 toolsDir := agenttools.ToolsDir(dataDir, tag)
525
526 logDir := env.config.logDir()
527 machineEnvironment := map[string]string{
528 "USER": env.config.user,
529 "HOME": osenv.Home(),
530 }
531 agentService := upstart.MachineAgentUpstartService(
532 env.machineAgentServiceName(),
533 toolsDir, dataDir, logDir, tag, machineId, machineEnvironment)
534
535 agentService.InitDir = upstartScriptLocation
536 logger.Infof("installing service %s to %s", env.machineAgentServiceName(), agentService.InitDir)
537 if err := agentService.Install(); err != nil {
538 logger.Errorf("could not install machine agent service: %v", err)
539 return err
540 }
541 return nil
542}
543
544func (env *localEnviron) findBridgeAddress(networkBridge string) (string, error) {
545 return getAddressForInterface(networkBridge)
546}
547
548func (env *localEnviron) writeBootstrapAgentConfFile(secret string, cert, key []byte) (agent.Config, error) {
549 tag := names.MachineTag("0")
550 passwordHash := utils.UserPasswordHash(secret, utils.CompatSalt)
551 // We don't check the existance of the CACert here as if it wasn't set, we
552 // wouldn't get this far.
553 cfg := env.config.Config
554 caCert, _ := cfg.CACert()
555 agentValues := map[string]string{
556 agent.ProviderType: env.config.Type(),
557 agent.Namespace: env.config.namespace(),
558 agent.StorageDir: env.config.storageDir(),
559 agent.StorageAddr: env.config.storageAddr(),
560 agent.SharedStorageDir: env.config.sharedStorageDir(),
561 agent.SharedStorageAddr: env.config.sharedStorageAddr(),
562 agent.AgentServiceName: env.machineAgentServiceName(),
563 agent.MongoServiceName: env.mongoServiceName(),
564 }
565 // NOTE: the state address HAS to be localhost, otherwise the mongo
566 // initialization fails. There is some magic code somewhere in the mongo
567 // connection code that treats connections from localhost as special, and
568 // will raise unauthorized errors during the initialization if the caller
569 // is not connected from localhost.
570 stateAddress := fmt.Sprintf("localhost:%d", cfg.StatePort())
571 apiAddress := fmt.Sprintf("localhost:%d", cfg.APIPort())
572 config, err := agent.NewStateMachineConfig(
573 agent.StateMachineConfigParams{
574 AgentConfigParams: agent.AgentConfigParams{
575 DataDir: env.config.rootDir(),
576 Tag: tag,
577 Password: passwordHash,
578 Nonce: state.BootstrapNonce,
579 StateAddresses: []string{stateAddress},
580 APIAddresses: []string{apiAddress},
581 CACert: caCert,
582 Values: agentValues,
583 },
584 StateServerCert: cert,
585 StateServerKey: key,
586 StatePort: cfg.StatePort(),
587 APIPort: cfg.APIPort(),
588 })
589 if err != nil {
590 return nil, err
591 }
592 if err := config.Write(); err != nil {
593 logger.Errorf("failed to write bootstrap agent file: %v", err)
594 return nil, err
595 }
596 return config, nil
597}
598
599func (env *localEnviron) initializeState(agentConfig agent.Config, cons constraints.Value) error {
600 bootstrapCfg, err := environs.BootstrapConfig(env.config.Config)
601 if err != nil {
602 return err
603 }
604 st, m, err := agentConfig.InitializeState(bootstrapCfg, agent.BootstrapMachineConfig{
605 Constraints: cons,
606 Jobs: []state.MachineJob{
607 state.JobManageEnviron,
608 state.JobManageState,
609 },
610 InstanceId: bootstrapInstanceId,
611 }, state.DialOpts{
612 Timeout: 60 * time.Second,
613 })
614 if err != nil {
615 return err
616 }
617 defer st.Close()
618 addr, err := env.findBridgeAddress(env.config.networkBridge())
619 if err != nil {
620 return fmt.Errorf("failed to get bridge address: %v", err)
621 }
622 err = m.SetAddresses([]instance.Address{{
623 NetworkScope: instance.NetworkPublic,
624 Type: instance.HostName,
625 Value: "localhost",
626 }, {
627 NetworkScope: instance.NetworkCloudLocal,
628 Type: instance.Ipv4Address,
629 Value: addr,
630 }})
631 if err != nil {
632 return fmt.Errorf("cannot set addresses on bootstrap instance: %v", err)
633 }
634 return nil
635}
636
637func (env *localEnviron) configureLocalSyslog() error {
638 tag := names.MachineTag("0")
639 syslogConfigRenderer := syslog.NewAccumulateConfig(tag, env.config.SyslogPort(), env.config.namespace())
640 syslogConfigRenderer.ConfigDir = syslogConfigDir
641 syslogConfigRenderer.ConfigFileName = env.syslogFilename()
642 syslogConfigRenderer.LogDir = env.config.logDir()
643 if err := syslogConfigRenderer.Write(); err != nil {
644 return err
645 }
646 if err := syslog.Restart(); err != nil {
647 logger.Warningf("cannot restart syslog daemon: %v", err)
648 }
649 return nil
650}
651
652func (env *localEnviron) removeLocalSyslog() {
653 // Don't fail if we have issues, but warn the user.
654 if err := os.Remove(filepath.Join(syslogConfigDir, env.syslogFilename())); err != nil {
655 logger.Warningf("could not remove local syslog config: %v", err)
656 }
657 if err := syslog.Restart(); err != nil {
658 logger.Warningf("cannot restart syslog daemon: %v", err)
659 }
660}
661>>>>>>> MERGE-SOURCE
452662
=== modified file 'replicaset/replicaset.go'
--- replicaset/replicaset.go 2014-01-21 19:26:14 +0000
+++ replicaset/replicaset.go 2014-01-28 15:13:44 +0000
@@ -275,7 +275,11 @@
275 Healthy bool `bson:"health"`275 Healthy bool `bson:"health"`
276276
277 // State describes the current state of the member.277 // State describes the current state of the member.
278<<<<<<< TREE
278 State MemberState `bson:"state"`279 State MemberState `bson:"state"`
280=======
281 State MemberState `bson:"State"`
282>>>>>>> MERGE-SOURCE
279283
280 // Uptime describes how long the member has been online.284 // Uptime describes how long the member has been online.
281 Uptime time.Duration `bson:"uptime"`285 Uptime time.Duration `bson:"uptime"`
282286
=== modified file 'replicaset/replicaset_test.go'
=== added file 'testing/mockupstart.go'
--- testing/mockupstart.go 1970-01-01 00:00:00 +0000
+++ testing/mockupstart.go 2014-01-28 15:13:44 +0000
@@ -0,0 +1,42 @@
1package testing
2
3import (
4 "fmt"
5 "io/ioutil"
6 "os"
7 "path/filepath"
8
9 gc "launchpad.net/gocheck"
10
11 "launchpad.net/juju-core/testing/testbase"
12 "launchpad.net/juju-core/upstart"
13)
14
15// MockUpstartSuite is a testing suite that you can embed to easily mock out
16// upstart.
17type MockUpstartSuite struct {
18 testbase.CleanupSuite
19 binDir string
20}
21
22var _ = gc.Suite(&MockUpstartSuite{})
23
24func (s *MockUpstartSuite) SetUpSuite(c *gc.C) {
25 s.CleanupSuite.SetUpSuite(c)
26 s.binDir = c.MkDir()
27 s.PatchEnvironment("PATH", fmt.Sprintf("%v%v%v", s.binDir, filepath.ListSeparator, os.Getenv("PATH")))
28 s.PatchValue(&upstart.InitDir, c.MkDir())
29 s.makeBin(c, "status", `echo "blah stop/waiting"`)
30 s.makeBin(c, "stopped-status", `echo "blah stop/waiting"`)
31 s.makeBin(c, "started-status", `echo "blah start/running, process 666"`)
32 s.makeBin(c, "start", "cp $(which started-status) $(which status)")
33 s.makeBin(c, "stop", "cp $(which stopped-status) $(which status)")
34}
35
36// makeBin makes a binary with the given name and contents in the binDir. This
37// is an easy way to mock the behavior of built-in applications.
38func (s *MockUpstartSuite) makeBin(c *gc.C, name, script string) {
39 path := filepath.Join(s.binDir, name)
40 err := ioutil.WriteFile(path, []byte("#!/bin/bash --norc\n"+script), 0755)
41 c.Assert(err, gc.IsNil)
42}
043
=== modified file 'upstart/service.go'
--- upstart/service.go 2013-11-19 08:53:40 +0000
+++ upstart/service.go 2014-01-28 15:13:44 +0000
@@ -13,12 +13,22 @@
13const (13const (
14 maxMongoFiles = 6500014 maxMongoFiles = 65000
15 maxAgentFiles = 2000015 maxAgentFiles = 20000
16
17 // MongoScriptVersion keeps track of changes to the mongo upstart script.
18 // Update this version when you update the script that gets installed from
19 // MongoUpstartService.
20 MongoScriptVersion = 2
16)21)
1722
18// MongoUpstartService returns the upstart config for the mongo state service.23// MongoUpstartService returns the upstart config for the mongo state service.
19func MongoUpstartService(name, dataDir, dbDir string, port int) *Conf {24//
25// This method assumes there is a server.pem keyfile in dataDir.
26func MongoUpstartService(name, dataDir string, port int) *Conf {
20 keyFile := path.Join(dataDir, "server.pem")27 keyFile := path.Join(dataDir, "server.pem")
21 svc := NewService(name)28 svc := NewService(name)
29
30 dbDir := path.Join(dataDir, "db")
31
22 return &Conf{32 return &Conf{
23 Service: *svc,33 Service: *svc,
24 Desc: "juju state database",34 Desc: "juju state database",
@@ -36,7 +46,8 @@
36 " --port " + fmt.Sprint(port) +46 " --port " + fmt.Sprint(port) +
37 " --noprealloc" +47 " --noprealloc" +
38 " --syslog" +48 " --syslog" +
39 " --smallfiles",49 " --smallfiles" +
50 " --replSet juju",
40 }51 }
41}52}
4253
4354
=== modified file 'upstart/upstart.go'
--- upstart/upstart.go 2013-10-02 03:44:40 +0000
+++ upstart/upstart.go 2014-01-28 15:13:44 +0000
@@ -18,7 +18,13 @@
18 "launchpad.net/juju-core/utils"18 "launchpad.net/juju-core/utils"
19)19)
2020
21var startedRE = regexp.MustCompile(`^.* start/running, process (\d+)\n$`)21var (
22 startedRE = regexp.MustCompile(`^.* start/running, process (\d+)\n$`)
23
24 // InitDir is the directory where upstart scripts will be created by
25 // default.
26 InitDir = "/etc/init"
27)
2228
23var InstallStartRetryAttempts = utils.AttemptStrategy{29var InstallStartRetryAttempts = utils.AttemptStrategy{
24 Total: 1 * time.Second,30 Total: 1 * time.Second,
@@ -32,7 +38,7 @@
32}38}
3339
34func NewService(name string) *Service {40func NewService(name string) *Service {
35 return &Service{Name: name, InitDir: "/etc/init"}41 return &Service{Name: name, InitDir: InitDir}
36}42}
3743
38// confPath returns the path to the service's configuration file.44// confPath returns the path to the service's configuration file.

Subscribers

People subscribed via source and target branches

to status/vote changes: