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  }