Merge lp:~axwalk/juju-core/lp1306902-mongo-ensureadminuser into lp:~go-bot/juju-core/trunk

Proposed by Andrew Wilkins
Status: Merged
Approved by: Andrew Wilkins
Approved revision: no longer in the source branch.
Merged at revision: 2629
Proposed branch: lp:~axwalk/juju-core/lp1306902-mongo-ensureadminuser
Merge into: lp:~go-bot/juju-core/trunk
Diff against target: 433 lines (+258/-48)
7 files modified
agent/mongo/mongo.go (+24/-0)
agent/mongo/mongo_test.go (+55/-0)
agent/mongo/upgrade.go (+101/-0)
cmd/jujud/machine.go (+42/-6)
cmd/jujud/machine_test.go (+34/-0)
state/compat_test.go (+0/-32)
state/open.go (+2/-10)
To merge this branch: bzr merge lp:~axwalk/juju-core/lp1306902-mongo-ensureadminuser
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+215821@code.launchpad.net

Commit message

Ensure state server has Mongo admin rights

The machine agent is updated so that if it
fails to open state with an unauthorized error,
then the agent will attempt to give itself
admin rights by temporarily restarting mongo
with --noauth.

There will be follow-ups to perform replset
initiation, and to upgrade the upstart config.

https://codereview.appspot.com/88030043/

Description of the change

Ensure state server has Mongo admin rights

The machine agent is updated so that if it
fails to open state with an unauthorized error,
then the agent will attempt to give itself
admin rights by temporarily restarting mongo
with --noauth.

There will be follow-ups to perform replset
initiation, and to upgrade the upstart config.

https://codereview.appspot.com/88030043/

To post a comment you must log in.
Revision history for this message
Andrew Wilkins (axwalk) wrote :

Reviewers: mp+215821_code.launchpad.net,

Message:
Please take a look.

Description:
Ensure state server has Mongo admin rights

The machine agent is updated so that if it
fails to open state with an unauthorized error,
then the agent will attempt to give itself
admin rights by temporarily restarting mongo
with --noauth.

There will be follow-ups to perform replset
initiation, and to upgrade the upstart config.

https://code.launchpad.net/~axwalk/juju-core/lp1306902-mongo-ensureadminuser/+merge/215821

(do not edit description out of merge proposal)

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

Affected files (+255, -48 lines):
   A [revision details]
   M agent/mongo/mongo.go
   M agent/mongo/mongo_test.go
   A agent/mongo/upgrade.go
   M cmd/jujud/machine.go
   M cmd/jujud/machine_test.go
   M state/compat_test.go
   M state/open.go

Revision history for this message
Roger Peppe (rogpeppe) wrote :

LGTM assuming it's been tested live (both upgrade and normal bootstrap).

Good stuff.

https://codereview.appspot.com/88030043/diff/1/agent/mongo/mongo_test.go
File agent/mongo/mongo_test.go (right):

https://codereview.appspot.com/88030043/diff/1/agent/mongo/mongo_test.go#newcode156
agent/mongo/mongo_test.go:156: defer inst.Destroy()
Hmm, I wonder if that was the source of some problems.

https://codereview.appspot.com/88030043/diff/1/agent/mongo/upgrade.go
File agent/mongo/upgrade.go (right):

https://codereview.appspot.com/88030043/diff/1/agent/mongo/upgrade.go#newcode92
agent/mongo/upgrade.go:92: return false, fmt.Errorf("mongod did not
cleanly terminate: %v", err)
"cannot kill mongod: %v"
?

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

https://codereview.appspot.com/88030043/diff/1/cmd/jujud/machine.go#newcode431
cmd/jujud/machine.go:431: if errors.IsUnauthorizedError(err) {
// TODO remove this when we no longer need
// compatibility with pre-HA environments.

?

https://codereview.appspot.com/88030043/diff/1/cmd/jujud/machine.go#newcode433
cmd/jujud/machine.go:433: added, ensureErr :=
a.ensureMongoAdminUser(agentConfig, info.StatePort, namespace)
Perhaps slightly easier to follow the logic if we return
early when possible?

added, ensureErr := a.ensureMongoAdminUser(agentConfig, info.StatePort,
namespace)
if ensureErr != nil {
     return nil, fmt.Errorf("cannot ensure admin user: %v", ensureErr)
}
if !added {
     // No user added, so it's probably a genuine unauthorized error.
     return nil, err
}
st, m, err = openState(agentConfig)

https://codereview.appspot.com/88030043/

Revision history for this message
Andrew Wilkins (axwalk) wrote :

Please take a look.

https://codereview.appspot.com/88030043/diff/1/agent/mongo/upgrade.go
File agent/mongo/upgrade.go (right):

https://codereview.appspot.com/88030043/diff/1/agent/mongo/upgrade.go#newcode92
agent/mongo/upgrade.go:92: return false, fmt.Errorf("mongod did not
cleanly terminate: %v", err)
On 2014/04/15 08:33:38, rog wrote:
> "cannot kill mongod: %v"
> ?

Done.

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

https://codereview.appspot.com/88030043/diff/1/cmd/jujud/machine.go#newcode431
cmd/jujud/machine.go:431: if errors.IsUnauthorizedError(err) {
On 2014/04/15 08:33:38, rog wrote:
> // TODO remove this when we no longer need
> // compatibility with pre-HA environments.

> ?

Done.

https://codereview.appspot.com/88030043/diff/1/cmd/jujud/machine.go#newcode433
cmd/jujud/machine.go:433: added, ensureErr :=
a.ensureMongoAdminUser(agentConfig, info.StatePort, namespace)
On 2014/04/15 08:33:38, rog wrote:
> Perhaps slightly easier to follow the logic if we return
> early when possible?

> added, ensureErr := a.ensureMongoAdminUser(agentConfig,
info.StatePort,
> namespace)
> if ensureErr != nil {
> return nil, fmt.Errorf("cannot ensure admin user: %v", ensureErr)
> }
> if !added {
> // No user added, so it's probably a genuine unauthorized error.
> return nil, err
> }
> st, m, err = openState(agentConfig)

Done.

https://codereview.appspot.com/88030043/

Revision history for this message
Andrew Wilkins (axwalk) wrote :
Revision history for this message
Go Bot (go-bot) wrote :
Download full text (166.1 KiB)

The attempt to merge lp:~axwalk/juju-core/lp1306902-mongo-ensureadminuser into lp:juju-core failed. Below is the output from the failed tests.

ok launchpad.net/juju-core 0.013s
ok launchpad.net/juju-core/agent 1.716s
ok launchpad.net/juju-core/agent/mongo 2.285s
ok launchpad.net/juju-core/agent/tools 0.176s
ok launchpad.net/juju-core/bzr 5.267s
ok launchpad.net/juju-core/cert 2.738s
ok launchpad.net/juju-core/charm 0.453s
? launchpad.net/juju-core/charm/hooks [no test files]
? launchpad.net/juju-core/charm/testing [no test files]
ok launchpad.net/juju-core/cloudinit 0.030s
ok launchpad.net/juju-core/cloudinit/sshinit 0.748s
ok launchpad.net/juju-core/cmd 0.217s
ok launchpad.net/juju-core/cmd/charm-admin 0.724s
? launchpad.net/juju-core/cmd/charmd [no test files]
? launchpad.net/juju-core/cmd/charmload [no test files]
ok launchpad.net/juju-core/cmd/envcmd 0.184s
ok launchpad.net/juju-core/cmd/juju 221.673s
panic: Session already closed

goroutine 1955 [running]:
labix.org/v2/mgo.(*Session).cluster(0xc20033f000, 0x0)
 /home/tarmac/trees/src/labix.org/v2/mgo/session.go:1037 +0x64
labix.org/v2/mgo.(*Session).acquireSocket(0xc20033f000, 0xc200000001, 0x0, 0x0, 0x0, ...)
 /home/tarmac/trees/src/labix.org/v2/mgo/session.go:3099 +0x212
labix.org/v2/mgo.(*Query).Iter(0xc200ede0e0, 0x7f8754dbde78)
 /home/tarmac/trees/src/labix.org/v2/mgo/session.go:2249 +0x18a
launchpad.net/juju-core/state/watcher.(*Watcher).sync(0xc20077ae10, 0xc200ef1a80, 0x7f8754dbdf70)
 /home/tarmac/trees/src/launchpad.net/juju-core/state/watcher/watcher.go:350 +0xe8
launchpad.net/juju-core/state/watcher.(*Watcher).loop(0xc20077ae10, 0x417ed0, 0xc2003266c0)
 /home/tarmac/trees/src/launchpad.net/juju-core/state/watcher/watcher.go:220 +0x87
launchpad.net/juju-core/state/watcher.func·001()
 /home/tarmac/trees/src/launchpad.net/juju-core/state/watcher/watcher.go:118 +0x2c
created by launchpad.net/juju-core/state/watcher.New
 /home/tarmac/trees/src/launchpad.net/juju-core/state/watcher/watcher.go:120 +0x100

goroutine 1 [chan receive]:
testing.RunTests(0x10a1328, 0x17282e0, 0x2, 0x2, 0xe2a901, ...)
 /usr/lib/go/src/pkg/testing/testing.go:434 +0x88e
testing.Main(0x10a1328, 0x17282e0, 0x2, 0x2, 0x1734d40, ...)
 /usr/lib/go/src/pkg/testing/testing.go:365 +0x8a
main.main()
 launchpad.net/juju-core/cmd/jujud/_test/_testmain.go:45 +0x9a

goroutine 2 [syscall]:

goroutine 4 [syscall]:
os/signal.loop()
 /usr/lib/go/src/pkg/os/signal/signal_unix.go:21 +0x1c
created by os/signal.init·1
 /usr/lib/go/src/pkg/os/signal/signal_unix.go:27 +0x2f

goroutine 6 [chan receive]:
launchpad.net/juju-core/provider/dummy.func·001()
 /home/tarmac/trees/src/launchpad.net/juju-core/provider/dummy/environs.go:208 +0x3a
created by launchpad.net/juju-core/provider/dummy.init·1
 /home/tarmac/trees/src/launchpad.net/juju-core/provider/dummy/environs.go:210 +0xcf

goroutine 9 [chan receive]:
launchpad.net/gocheck.(*suiteRunner).runTest(0xc200804070, 0xc200783000, 0xc20037a820)
 /home/tarmac/trees/src/launchpad.net/gocheck/gocheck.go:771 +0x4f
launchpad.net/gocheck.(*suiteRunner).run(0xc200804070, 0xc200395600)
 /home/tarmac/trees/src/launchpad.net/gocheck/gocheck.go:584 +0x1c5
laun...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'agent/mongo/mongo.go'
2--- agent/mongo/mongo.go 2014-04-15 03:40:01 +0000
3+++ agent/mongo/mongo.go 2014-04-15 09:07:40 +0000
4@@ -302,3 +302,27 @@
5 }
6 return conf, nil
7 }
8+
9+// mongoNoauthCommand returns an os/exec.Cmd that may be executed to
10+// run mongod without security.
11+func mongoNoauthCommand(dataDir string, port int) (*exec.Cmd, error) {
12+ sslKeyFile := path.Join(dataDir, "server.pem")
13+ dbDir := filepath.Join(dataDir, "db")
14+ mongopath, err := MongodPath()
15+ if err != nil {
16+ return nil, err
17+ }
18+ cmd := exec.Command(mongopath,
19+ "--noauth",
20+ "--dbpath", dbDir,
21+ "--sslOnNormalPorts",
22+ "--sslPEMKeyFile", sslKeyFile,
23+ "--sslPEMKeyPassword", "ignored",
24+ "--bind_ip", "127.0.0.1",
25+ "--port", fmt.Sprint(port),
26+ "--noprealloc",
27+ "--syslog",
28+ "--smallfiles",
29+ )
30+ return cmd, nil
31+}
32
33=== modified file 'agent/mongo/mongo_test.go'
34--- agent/mongo/mongo_test.go 2014-04-15 03:40:01 +0000
35+++ agent/mongo/mongo_test.go 2014-04-15 09:07:40 +0000
36@@ -3,13 +3,16 @@
37 import (
38 "encoding/base64"
39 "io/ioutil"
40+ "net"
41 "os"
42 "path"
43 "path/filepath"
44+ "strconv"
45 "strings"
46 "testing"
47
48 jc "github.com/juju/testing/checkers"
49+ "labix.org/v2/mgo"
50 gc "launchpad.net/gocheck"
51
52 "launchpad.net/juju-core/instance"
53@@ -165,6 +168,7 @@
54 inst := &coretesting.MgoInstance{Params: []string{"--replSet", "juju"}}
55 err = inst.Start(true)
56 c.Assert(err, gc.IsNil)
57+ defer inst.Destroy()
58
59 info := inst.DialInfo()
60
61@@ -230,6 +234,57 @@
62 c.Assert(address, gc.Equals, "10.0.0.1:37017")
63 }
64
65+func (s *MongoSuite) TestEnsureAdminUser(c *gc.C) {
66+ inst := &coretesting.MgoInstance{}
67+ err := inst.Start(true)
68+ c.Assert(err, gc.IsNil)
69+ defer inst.Destroy()
70+ dialInfo := inst.DialInfo()
71+ // First call succeeds, as there are no users yet.
72+ added, err := s.ensureAdminUser(c, dialInfo, "whomever", "whatever")
73+ c.Assert(err, gc.IsNil)
74+ c.Assert(added, jc.IsTrue)
75+ // Second call succeeds, as the admin user is already there.
76+ added, err = s.ensureAdminUser(c, dialInfo, "whomever", "whatever")
77+ c.Assert(err, gc.IsNil)
78+ c.Assert(added, jc.IsFalse)
79+}
80+
81+func (s *MongoSuite) TestEnsureAdminUserError(c *gc.C) {
82+ inst := &coretesting.MgoInstance{}
83+ err := inst.Start(true)
84+ c.Assert(err, gc.IsNil)
85+ defer inst.Destroy()
86+ dialInfo := inst.DialInfo()
87+
88+ // First call succeeds, as there are no users yet (mimics --noauth).
89+ added, err := s.ensureAdminUser(c, dialInfo, "whomever", "whatever")
90+ c.Assert(err, gc.IsNil)
91+ c.Assert(added, jc.IsTrue)
92+
93+ // Second call fails, as there is another user and the database doesn't
94+ // actually get reopened with --noauth in the test; mimics AddUser failure
95+ _, err = s.ensureAdminUser(c, dialInfo, "whomeverelse", "whateverelse")
96+ c.Assert(err, gc.ErrorMatches, `failed to add "whomeverelse" to admin database: not authorized for upsert on admin.system.users`)
97+}
98+
99+func (s *MongoSuite) ensureAdminUser(c *gc.C, dialInfo *mgo.DialInfo, user, password string) (added bool, err error) {
100+ _, portString, err := net.SplitHostPort(dialInfo.Addrs[0])
101+ c.Assert(err, gc.IsNil)
102+ port, err := strconv.Atoi(portString)
103+ c.Assert(err, gc.IsNil)
104+ s.PatchValue(&JujuMongodPath, "/bin/true")
105+ s.PatchValue(&processSignal, func(*os.Process, os.Signal) error {
106+ return nil
107+ })
108+ return EnsureAdminUser(EnsureAdminUserParams{
109+ DialInfo: dialInfo,
110+ Port: port,
111+ User: user,
112+ Password: password,
113+ })
114+}
115+
116 func (s *MongoSuite) TestGenerateSharedSecret(c *gc.C) {
117 secret, err := GenerateSharedSecret()
118 c.Assert(err, gc.IsNil)
119
120=== added file 'agent/mongo/upgrade.go'
121--- agent/mongo/upgrade.go 1970-01-01 00:00:00 +0000
122+++ agent/mongo/upgrade.go 2014-04-15 09:07:40 +0000
123@@ -0,0 +1,101 @@
124+// Copyright 2014 Canonical Ltd.
125+// Licensed under the AGPLv3, see LICENCE file for details.
126+
127+package mongo
128+
129+import (
130+ "fmt"
131+ "os"
132+ "syscall"
133+
134+ "labix.org/v2/mgo"
135+
136+ "launchpad.net/juju-core/upstart"
137+)
138+
139+var (
140+ processSignal = (*os.Process).Signal
141+)
142+
143+type EnsureAdminUserParams struct {
144+ // DialInfo specifies how to connect to the mongo server.
145+ DialInfo *mgo.DialInfo
146+ // Namespace is the agent namespace, used to derive the Mongo service name.
147+ Namespace string
148+ // DataDir is the Juju data directory, used to start a --noauth server.
149+ DataDir string
150+ // Port is the listening port of the Mongo server.
151+ Port int
152+ // User holds the user to log in to the mongo server as.
153+ User string
154+ // Password holds the password for the user to log in as.
155+ Password string
156+}
157+
158+// EnsureAdminUser ensures that the specified user and password
159+// are added to the admin database.
160+//
161+// This function will stop the Mongo service if it needs to add
162+// the admin user, as it must restart Mongo in --noauth mode.
163+func EnsureAdminUser(p EnsureAdminUserParams) (added bool, err error) {
164+ if len(p.DialInfo.Addrs) > 1 {
165+ logger.Infof("more than one state server; admin user must exist")
166+ return false, nil
167+ }
168+ p.DialInfo.Addrs = []string{fmt.Sprintf("127.0.0.1:%d", p.Port)}
169+ p.DialInfo.Direct = true
170+
171+ // Attempt to login to the admin database first.
172+ session, err := mgo.DialWithInfo(p.DialInfo)
173+ if err != nil {
174+ return false, fmt.Errorf("can't dial mongo to ensure admin user: %v", err)
175+ }
176+ err = session.DB("admin").Login(p.User, p.Password)
177+ session.Close()
178+ if err == nil {
179+ return false, nil
180+ }
181+
182+ // Login failed, so we need to add the user.
183+ // Stop mongo, so we can start it in --noauth mode.
184+ mongoServiceName := ServiceName(p.Namespace)
185+ mongoService := upstart.NewService(mongoServiceName)
186+ if err := mongoService.Stop(); err != nil {
187+ return false, fmt.Errorf("failed to stop %v: %v", mongoServiceName, err)
188+ }
189+
190+ // Start mongod in --noauth mode.
191+ logger.Debugf("starting mongo with --noauth")
192+ cmd, err := mongoNoauthCommand(p.DataDir, p.Port)
193+ if err != nil {
194+ return false, fmt.Errorf("failed to prepare mongod command: %v", err)
195+ }
196+ if err := cmd.Start(); err != nil {
197+ return false, fmt.Errorf("failed to start mongod: %v", err)
198+ }
199+ defer cmd.Process.Kill()
200+
201+ // Add the user to the admin database.
202+ logger.Debugf("setting admin password")
203+ if session, err = mgo.DialWithInfo(p.DialInfo); err != nil {
204+ return false, fmt.Errorf("can't dial mongo to ensure admin user: %v", err)
205+ }
206+ err = session.DB("admin").AddUser(p.User, p.Password, false)
207+ session.Close()
208+ if err != nil {
209+ return false, fmt.Errorf("failed to add %q to admin database: %v", p.User, err)
210+ }
211+ logger.Infof("added %q to admin database", p.User)
212+
213+ // Restart mongo using upstart.
214+ if err := processSignal(cmd.Process, syscall.SIGTERM); err != nil {
215+ return false, fmt.Errorf("cannot kill mongod: %v", err)
216+ }
217+ if err := cmd.Wait(); err != nil {
218+ return false, fmt.Errorf("mongod did not cleanly terminate: %v", err)
219+ }
220+ if err := mongoService.Start(); err != nil {
221+ return false, err
222+ }
223+ return true, nil
224+}
225
226=== modified file 'cmd/jujud/machine.go'
227--- cmd/jujud/machine.go 2014-04-15 03:40:01 +0000
228+++ cmd/jujud/machine.go 2014-04-15 09:07:40 +0000
229@@ -74,6 +74,7 @@
230 // allow the tests to intercept calls to the functions.
231 ensureMongoServer = mongo.EnsureMongoServer
232 maybeInitiateMongoServer = mongo.MaybeInitiateMongoServer
233+ ensureMongoAdminUser = mongo.EnsureAdminUser
234 newSingularRunner = singular.New
235
236 // reportOpenedAPI is exposed for tests to know when
237@@ -390,6 +391,26 @@
238 return nil
239 }
240
241+func (a *MachineAgent) ensureMongoAdminUser(agentConfig agent.Config, port int, namespace string) (added bool, err error) {
242+ stateInfo := agentConfig.StateInfo()
243+ dialInfo, err := state.DialInfo(stateInfo, state.DefaultDialOpts())
244+ if err != nil {
245+ return false, err
246+ }
247+ if len(dialInfo.Addrs) > 1 {
248+ logger.Infof("more than one state server; admin user must exist")
249+ return false, nil
250+ }
251+ return ensureMongoAdminUser(mongo.EnsureAdminUserParams{
252+ DialInfo: dialInfo,
253+ Namespace: namespace,
254+ DataDir: agentConfig.DataDir(),
255+ Port: port,
256+ User: stateInfo.Tag,
257+ Password: stateInfo.Password,
258+ })
259+}
260+
261 // StateJobs returns a worker running all the workers that require
262 // a *state.State connection.
263 func (a *MachineAgent) StateWorker() (worker.Worker, error) {
264@@ -408,16 +429,31 @@
265 if err != nil {
266 return nil, err
267 }
268+
269+ st, m, err := openState(agentConfig)
270+ if errors.IsUnauthorizedError(err) {
271+ // TODO(axw) remove this when we no longer need
272+ // to upgrade from pre-HA-capable environments.
273+ logger.Debugf("failed to open state, reattempt after ensuring admin user exists: %v", err)
274+ added, ensureErr := a.ensureMongoAdminUser(agentConfig, info.StatePort, namespace)
275+ if ensureErr != nil {
276+ err = ensureErr
277+ }
278+ if !added {
279+ // No user added, so it's probably a genuine unauthorized error.
280+ return nil, err
281+ }
282+ st, m, err = openState(agentConfig)
283+ }
284+ if err != nil {
285+ return nil, err
286+ }
287+ reportOpenedState(st)
288+
289 // TODO(rog) call maybeInitiateMongoServer to upgrade mongo
290 // from old environments. We'll need to acquire a non-localhost
291 // address for the current instance before we do.
292
293- st, m, err := openState(agentConfig)
294- if err != nil {
295- return nil, err
296- }
297- reportOpenedState(st)
298-
299 singularStateConn := singularStateConn{st.MongoSession(), m}
300 runner := newRunner(connectionIsFatal(st), moreImportant)
301 singularRunner, err := newSingularRunner(runner, singularStateConn)
302
303=== modified file 'cmd/jujud/machine_test.go'
304--- cmd/jujud/machine_test.go 2014-04-15 03:40:01 +0000
305+++ cmd/jujud/machine_test.go 2014-04-15 09:07:40 +0000
306@@ -17,6 +17,7 @@
307 gc "launchpad.net/gocheck"
308
309 "launchpad.net/juju-core/agent"
310+ "launchpad.net/juju-core/agent/mongo"
311 "launchpad.net/juju-core/charm"
312 "launchpad.net/juju-core/cmd"
313 lxctesting "launchpad.net/juju-core/container/lxc/testing"
314@@ -895,6 +896,39 @@
315 c.Fatalf("timeout while waiting for agent config to change")
316 }
317
318+func (s *MachineSuite) TestMachineAgentEnsureAdminUser(c *gc.C) {
319+ m, _, _ := s.primeAgent(c, version.Current, state.JobManageEnviron)
320+ err := s.State.MongoSession().DB("admin").RemoveUser(m.Tag())
321+ c.Assert(err, gc.IsNil)
322+
323+ s.PatchValue(&ensureMongoAdminUser, func(p mongo.EnsureAdminUserParams) (bool, error) {
324+ err := s.State.MongoSession().DB("admin").AddUser(p.User, p.Password, false)
325+ c.Assert(err, gc.IsNil)
326+ return true, nil
327+ })
328+
329+ stateOpened := make(chan eitherState, 1)
330+ s.PatchValue(&reportOpenedState, func(st eitherState) {
331+ select {
332+ case stateOpened <- st:
333+ default:
334+ }
335+ })
336+
337+ // Start the machine agent, and wait for state to be opened.
338+ a := s.newAgent(c, m)
339+ done := make(chan error)
340+ go func() { done <- a.Run(nil) }()
341+ defer a.Stop() // in case of failure
342+ select {
343+ case st := <-stateOpened:
344+ c.Assert(st, gc.NotNil)
345+ case <-time.After(coretesting.LongWait):
346+ c.Fatalf("state not opened")
347+ }
348+ s.waitStopped(c, state.JobManageEnviron, a, done)
349+}
350+
351 // MachineWithCharmsSuite provides infrastructure for tests which need to
352 // work with charms.
353 type MachineWithCharmsSuite struct {
354
355=== modified file 'state/compat_test.go'
356--- state/compat_test.go 2014-04-14 19:17:58 +0000
357+++ state/compat_test.go 2014-04-15 09:07:40 +0000
358@@ -10,7 +10,6 @@
359
360 "launchpad.net/juju-core/testing"
361 "launchpad.net/juju-core/testing/testbase"
362- "launchpad.net/juju-core/utils"
363 )
364
365 // compatSuite contains backwards compatibility tests,
366@@ -105,34 +104,3 @@
367 c.Assert(include, gc.HasLen, 0)
368 c.Assert(exclude, gc.HasLen, 0)
369 }
370-
371-func (s *compatSuite) TestOpenStateWithoutAdmin(c *gc.C) {
372- // https://launchpad.net/bugs/1306902
373- // In 1.18, machine-0 did not have access to the "admin" database. In
374- // newer versions we need access in order to do replicaSet mutations.
375- // However, we have not added the ability during upgrade to add
376- // machine-0 to the admin db, so we should still continue even when it
377- // doesn't have rights.
378- machine, err := s.state.AddMachine("quantal", JobManageEnviron)
379- c.Assert(err, gc.IsNil)
380- machinePassword, err := utils.RandomPassword()
381- c.Assert(err, gc.IsNil)
382- err = machine.SetPassword(machinePassword)
383- c.Assert(err, gc.IsNil)
384- err = machine.SetMongoPassword(machinePassword)
385- c.Assert(err, gc.IsNil)
386- // (jam) The only way I've found to actually ensure "machine-0" is
387- // removed from the Admin database is to actually login *as* the
388- // machine agent we just gave admin rights to, and then remove it.
389- adminDB := s.state.db.Session.DB("admin")
390- err = adminDB.Login(machine.Tag(), machinePassword)
391- c.Assert(err, gc.IsNil)
392- err = adminDB.RemoveUser(machine.Tag())
393- c.Assert(err, gc.IsNil)
394- info := TestingStateInfo()
395- info.Tag = machine.Tag()
396- info.Password = machinePassword
397- machineState, err := Open(info, TestingDialOpts(), Policy(nil))
398- c.Assert(err, gc.IsNil)
399- machineState.Close()
400-}
401
402=== modified file 'state/open.go'
403--- state/open.go 2014-04-14 19:30:01 +0000
404+++ state/open.go 2014-04-15 09:07:40 +0000
405@@ -251,6 +251,7 @@
406 func newState(session *mgo.Session, info *Info, policy Policy) (*State, error) {
407 db := session.DB("juju")
408 pdb := session.DB("presence")
409+ admin := session.DB("admin")
410 if info.Tag != "" {
411 if err := db.Login(info.Tag, info.Password); err != nil {
412 return nil, maybeUnauthorized(err, fmt.Sprintf("cannot log in to juju database as %q", info.Tag))
413@@ -258,19 +259,10 @@
414 if err := pdb.Login(info.Tag, info.Password); err != nil {
415 return nil, maybeUnauthorized(err, fmt.Sprintf("cannot log in to presence database as %q", info.Tag))
416 }
417- admin := session.DB("admin")
418 if err := admin.Login(info.Tag, info.Password); err != nil {
419- if isUnauthorized(err) {
420- // TODO(jam) https://launchpad.net/bugs/1306902 in juju <=1.18,
421- // machine-0 was not an admin, so it cannot login to the "admin"
422- // database until bug #1306902 is fixed.
423- logger.Infof("ignoring failure to login to \"admin\" database as %q (bug #1306902): %v", info.Tag, err)
424- } else {
425- return nil, maybeUnauthorized(err, fmt.Sprintf("cannot log in to admin database as %q", info.Tag))
426- }
427+ return nil, maybeUnauthorized(err, fmt.Sprintf("cannot log in to admin database as %q", info.Tag))
428 }
429 } else if info.Password != "" {
430- admin := session.DB("admin")
431 if err := admin.Login(AdminUser, info.Password); err != nil {
432 return nil, maybeUnauthorized(err, "cannot log in to admin database")
433 }

Subscribers

People subscribed via source and target branches

to status/vote changes: