github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/mongo/admin_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package mongo_test 5 6 import ( 7 "net" 8 "os" 9 "path/filepath" 10 "strconv" 11 12 gitjujutesting "github.com/juju/testing" 13 jc "github.com/juju/testing/checkers" 14 gc "gopkg.in/check.v1" 15 "gopkg.in/mgo.v2" 16 "gopkg.in/mgo.v2/bson" 17 18 "github.com/juju/juju/mongo" 19 svctesting "github.com/juju/juju/service/common/testing" 20 coretesting "github.com/juju/juju/testing" 21 ) 22 23 type adminSuite struct { 24 coretesting.BaseSuite 25 26 data *svctesting.FakeServiceData 27 } 28 29 var _ = gc.Suite(&adminSuite{}) 30 31 func (s *adminSuite) SetUpTest(c *gc.C) { 32 s.BaseSuite.SetUpTest(c) 33 34 s.data = svctesting.NewFakeServiceData() 35 mongo.PatchService(s.PatchValue, s.data) 36 } 37 38 func (s *adminSuite) TestEnsureAdminUser(c *gc.C) { 39 inst := &gitjujutesting.MgoInstance{} 40 err := inst.Start(coretesting.Certs) 41 c.Assert(err, jc.ErrorIsNil) 42 defer inst.DestroyWithLog() 43 dialInfo := inst.DialInfo() 44 45 // Mock out mongod, so the --noauth execution doesn't 46 // do anything nasty. Also mock out the Signal method. 47 gitjujutesting.PatchExecutableAsEchoArgs(c, s, "mongod") 48 mongodDir := filepath.SplitList(os.Getenv("PATH"))[0] 49 s.PatchValue(&mongo.JujuMongodPath, filepath.Join(mongodDir, "mongod")) 50 s.PatchValue(mongo.ProcessSignal, func(*os.Process, os.Signal) error { 51 return nil 52 }) 53 54 // First call succeeds, as there are no users yet. 55 added, err := s.ensureAdminUser(c, dialInfo, "whomever", "whatever") 56 c.Assert(err, jc.ErrorIsNil) 57 c.Assert(added, jc.IsTrue) 58 59 // EnsureAdminUser should have stopped the mongo service, 60 // started a new mongod with --noauth, and then finally 61 // started the service back up. 62 s.data.CheckCallNames(c, "Stop", "Start") 63 _, portString, err := net.SplitHostPort(dialInfo.Addrs[0]) 64 c.Assert(err, jc.ErrorIsNil) 65 gitjujutesting.AssertEchoArgs(c, "mongod", 66 "--noauth", 67 "--dbpath", "db", 68 "--sslOnNormalPorts", 69 "--sslPEMKeyFile", "server.pem", 70 "--sslPEMKeyPassword", "ignored", 71 "--bind_ip", "127.0.0.1", 72 "--port", portString, 73 "--noprealloc", 74 "--syslog", 75 "--smallfiles", 76 "--journal", 77 ) 78 79 // Second call succeeds, as the admin user is already there. 80 added, err = s.ensureAdminUser(c, dialInfo, "whomever", "whatever") 81 c.Assert(err, jc.ErrorIsNil) 82 c.Assert(added, jc.IsFalse) 83 84 // There should have been no additional start/stop. 85 s.data.CheckCallNames(c, "Stop", "Start") 86 } 87 88 func (s *adminSuite) TestEnsureAdminUserError(c *gc.C) { 89 inst := &gitjujutesting.MgoInstance{} 90 inst.EnableAuth = true 91 err := inst.Start(coretesting.Certs) 92 c.Assert(err, jc.ErrorIsNil) 93 defer inst.Destroy() 94 dialInfo := inst.DialInfo() 95 96 // First call succeeds, as there are no users yet (mimics --noauth). 97 added, err := s.ensureAdminUser(c, dialInfo, "whomever", "whatever") 98 c.Assert(err, jc.ErrorIsNil) 99 c.Assert(added, jc.IsTrue) 100 101 // Second call fails, as there is another user and the database doesn't 102 // actually get reopened with --noauth in the test; mimics AddUser failure 103 _, err = s.ensureAdminUser(c, dialInfo, "whomeverelse", "whateverelse") 104 c.Assert(err, gc.ErrorMatches, `failed to add "whomeverelse" to admin database: cannot set admin password: not authorized .*`) 105 } 106 107 func (s *adminSuite) ensureAdminUser(c *gc.C, dialInfo *mgo.DialInfo, user, password string) (added bool, err error) { 108 _, portString, err := net.SplitHostPort(dialInfo.Addrs[0]) 109 c.Assert(err, jc.ErrorIsNil) 110 port, err := strconv.Atoi(portString) 111 c.Assert(err, jc.ErrorIsNil) 112 return mongo.EnsureAdminUser(mongo.EnsureAdminUserParams{ 113 DialInfo: dialInfo, 114 Port: port, 115 User: user, 116 Password: password, 117 }) 118 } 119 120 func (s *adminSuite) setUpMongo(c *gc.C) *mgo.DialInfo { 121 inst := &gitjujutesting.MgoInstance{} 122 err := inst.Start(coretesting.Certs) 123 c.Assert(err, jc.ErrorIsNil) 124 s.AddCleanup(func(*gc.C) { inst.Destroy() }) 125 dialInfo := inst.DialInfo() 126 dialInfo.Direct = true 127 return dialInfo 128 } 129 130 func checkRoles(c *gc.C, session *mgo.Session, db, user string, expected []interface{}) { 131 admin := session.DB("admin") 132 133 var info map[string]interface{} 134 err := admin.C("system.users").Find(bson.D{{"user", user}}).One(&info) 135 c.Assert(err, jc.ErrorIsNil) 136 137 var roles []interface{} 138 for _, role := range info["roles"].([]interface{}) { 139 switch role := role.(type) { 140 case map[string]interface{}: 141 // Mongo 2.6 142 if role["db"] == db { 143 roles = append(roles, role["role"]) 144 } 145 default: 146 // Mongo 2.4 147 roles = append(roles, role) 148 } 149 } 150 c.Assert(roles, jc.SameContents, expected) 151 } 152 153 func (s *adminSuite) TestSetAdminMongoPassword(c *gc.C) { 154 dialInfo := s.setUpMongo(c) 155 session, err := mgo.DialWithInfo(dialInfo) 156 c.Assert(err, jc.ErrorIsNil) 157 defer session.Close() 158 159 // Check that we can SetAdminMongoPassword to nothing when there's 160 // no password currently set. 161 err = mongo.SetAdminMongoPassword(session, "auser", "") 162 c.Assert(err, jc.ErrorIsNil) 163 164 admin := session.DB("admin") 165 err = mongo.SetAdminMongoPassword(session, "auser", "foo") 166 c.Assert(err, jc.ErrorIsNil) 167 err = admin.Login("auser", "") 168 c.Assert(err, gc.ErrorMatches, "auth fail(s|ed)") 169 err = admin.Login("auser", "foo") 170 c.Assert(err, jc.ErrorIsNil) 171 172 checkRoles(c, session, "admin", "auser", 173 []interface{}{ 174 string(mgo.RoleReadWriteAny), 175 string(mgo.RoleDBAdminAny), 176 string(mgo.RoleUserAdminAny), 177 string(mgo.RoleClusterAdmin)}) 178 }