github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/featuretests/dblog_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package featuretests
     5  
     6  import (
     7  	"bufio"
     8  	"io/ioutil"
     9  	"time"
    10  
    11  	"github.com/juju/loggo"
    12  	"github.com/juju/names"
    13  	jujutesting "github.com/juju/testing"
    14  	jc "github.com/juju/testing/checkers"
    15  	gc "gopkg.in/check.v1"
    16  	"gopkg.in/mgo.v2/bson"
    17  
    18  	"github.com/juju/juju/agent"
    19  	"github.com/juju/juju/api"
    20  	agentcmd "github.com/juju/juju/cmd/jujud/agent"
    21  	agenttesting "github.com/juju/juju/cmd/jujud/agent/testing"
    22  	"github.com/juju/juju/cmd/jujud/util/password"
    23  	"github.com/juju/juju/feature"
    24  	"github.com/juju/juju/state"
    25  	coretesting "github.com/juju/juju/testing"
    26  	"github.com/juju/juju/testing/factory"
    27  	"github.com/juju/juju/version"
    28  	"github.com/juju/juju/worker/logsender"
    29  	"github.com/juju/juju/worker/peergrouper"
    30  )
    31  
    32  // dblogSuite tests that logs flow correctly from the machine and unit
    33  // agents over the API into MongoDB. These are very much integration
    34  // tests with more detailed testing of the individual components
    35  // being done in unit tests.
    36  type dblogSuite struct {
    37  	agenttesting.AgentSuite
    38  }
    39  
    40  func (s *dblogSuite) SetUpTest(c *gc.C) {
    41  	s.SetInitialFeatureFlags("db-log")
    42  	s.AgentSuite.SetUpTest(c)
    43  	s.PatchValue(&password.EnsureJujudPassword, func() error { return nil })
    44  
    45  	// Change the path to "juju-run", so that the
    46  	// tests don't try to write to /usr/local/bin.
    47  	file, _ := ioutil.TempFile("", "juju-run")
    48  	defer file.Close()
    49  	s.PatchValue(&agentcmd.JujuRun, file.Name())
    50  }
    51  
    52  func (s *dblogSuite) TestMachineAgentLogsGoToDB(c *gc.C) {
    53  	s.SetFeatureFlags("db-log")
    54  	foundLogs := s.runMachineAgentTest(c)
    55  	c.Assert(foundLogs, jc.IsTrue)
    56  }
    57  
    58  func (s *dblogSuite) TestMachineAgentLogsGoToDBWithJES(c *gc.C) {
    59  	s.SetFeatureFlags(feature.JES)
    60  	foundLogs := s.runMachineAgentTest(c)
    61  	c.Assert(foundLogs, jc.IsTrue)
    62  }
    63  
    64  func (s *dblogSuite) TestMachineAgentWithoutFeatureFlag(c *gc.C) {
    65  	s.SetFeatureFlags()
    66  	foundLogs := s.runMachineAgentTest(c)
    67  	c.Assert(foundLogs, jc.IsFalse)
    68  }
    69  
    70  func (s *dblogSuite) TestUnitAgentLogsGoToDB(c *gc.C) {
    71  	s.SetFeatureFlags("db-log")
    72  	foundLogs := s.runUnitAgentTest(c)
    73  	c.Assert(foundLogs, jc.IsTrue)
    74  }
    75  
    76  func (s *dblogSuite) TestUnitAgentLogsGoToDBWithJES(c *gc.C) {
    77  	s.SetFeatureFlags(feature.JES)
    78  	foundLogs := s.runUnitAgentTest(c)
    79  	c.Assert(foundLogs, jc.IsTrue)
    80  }
    81  
    82  func (s *dblogSuite) TestUnitAgentWithoutFeatureFlag(c *gc.C) {
    83  	s.SetFeatureFlags()
    84  	foundLogs := s.runUnitAgentTest(c)
    85  	c.Assert(foundLogs, jc.IsFalse)
    86  }
    87  
    88  func (s *dblogSuite) runMachineAgentTest(c *gc.C) bool {
    89  	// Create a machine and an agent for it.
    90  	m, password := s.Factory.MakeMachineReturningPassword(c, &factory.MachineParams{
    91  		Nonce: agent.BootstrapNonce,
    92  	})
    93  
    94  	s.PrimeAgent(c, m.Tag(), password, version.Current)
    95  	agentConf := agentcmd.NewAgentConf(s.DataDir())
    96  	agentConf.ReadConfig(m.Tag().String())
    97  	logsCh, err := logsender.InstallBufferedLogWriter(1000)
    98  	c.Assert(err, jc.ErrorIsNil)
    99  	machineAgentFactory := agentcmd.MachineAgentFactoryFn(agentConf, logsCh, nil)
   100  	a := machineAgentFactory(m.Id())
   101  
   102  	// Ensure there's no logs to begin with.
   103  	c.Assert(s.getLogCount(c, m.Tag()), gc.Equals, 0)
   104  
   105  	// Start the agent.
   106  	go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }()
   107  	defer a.Stop()
   108  
   109  	return s.waitForLogs(c, m.Tag())
   110  }
   111  
   112  func (s *dblogSuite) runUnitAgentTest(c *gc.C) bool {
   113  	// Create a unit and an agent for it.
   114  	u, password := s.Factory.MakeUnitReturningPassword(c, nil)
   115  	s.PrimeAgent(c, u.Tag(), password, version.Current)
   116  	logsCh, err := logsender.InstallBufferedLogWriter(1000)
   117  	c.Assert(err, jc.ErrorIsNil)
   118  	a := agentcmd.NewUnitAgent(nil, logsCh)
   119  	s.InitAgent(c, a, "--unit-name", u.Name(), "--log-to-stderr=true")
   120  
   121  	// Ensure there's no logs to begin with.
   122  	c.Assert(s.getLogCount(c, u.Tag()), gc.Equals, 0)
   123  
   124  	// Start the agent.
   125  	go func() { c.Assert(a.Run(nil), jc.ErrorIsNil) }()
   126  	defer a.Stop()
   127  
   128  	return s.waitForLogs(c, u.Tag())
   129  }
   130  
   131  func (s *dblogSuite) getLogCount(c *gc.C, entity names.Tag) int {
   132  	// TODO(mjs) - replace this with State's functionality for reading
   133  	// logs from the DB, once it gets this. This will happen before
   134  	// the DB logging feature branch is merged.
   135  	logs := s.Session.DB("logs").C("logs")
   136  	count, err := logs.Find(bson.M{"n": entity.String()}).Count()
   137  	c.Assert(err, jc.ErrorIsNil)
   138  	return count
   139  }
   140  
   141  func (s *dblogSuite) waitForLogs(c *gc.C, entityTag names.Tag) bool {
   142  	for a := coretesting.LongAttempt.Start(); a.Next(); {
   143  		if s.getLogCount(c, entityTag) > 0 {
   144  			return true
   145  		}
   146  	}
   147  	return false
   148  }
   149  
   150  // debugLogDbSuite tests that the debuglog API works when logs are
   151  // being read from the database.
   152  type debugLogDbSuite struct {
   153  	agenttesting.AgentSuite
   154  }
   155  
   156  var _ = gc.Suite(&debugLogDbSuite{})
   157  
   158  func (s *debugLogDbSuite) SetUpSuite(c *gc.C) {
   159  	s.SetInitialFeatureFlags("db-log")
   160  
   161  	// Restart mongod with a the replicaset enabled.
   162  	mongod := jujutesting.MgoServer
   163  	mongod.Params = []string{"--replSet", "juju"}
   164  	mongod.Restart()
   165  
   166  	// Initiate the replicaset.
   167  	info := mongod.DialInfo()
   168  	args := peergrouper.InitiateMongoParams{
   169  		DialInfo:       info,
   170  		MemberHostPort: mongod.Addr(),
   171  	}
   172  	err := peergrouper.MaybeInitiateMongoServer(args)
   173  	c.Assert(err, jc.ErrorIsNil)
   174  
   175  	s.AgentSuite.SetUpSuite(c)
   176  }
   177  
   178  func (s *debugLogDbSuite) TearDownSuite(c *gc.C) {
   179  	// Restart mongod without the replicaset enabled so as not to
   180  	// affect other test that reply on this mongod instance in this
   181  	// package.
   182  	mongod := jujutesting.MgoServer
   183  	mongod.Params = []string{}
   184  	mongod.Restart()
   185  
   186  	s.AgentSuite.TearDownSuite(c)
   187  }
   188  
   189  func (s *debugLogDbSuite) TestLogsAPI(c *gc.C) {
   190  	dbLogger := state.NewDbLogger(s.State, names.NewMachineTag("99"))
   191  	defer dbLogger.Close()
   192  
   193  	t := time.Date(2015, 6, 23, 13, 8, 49, 0, time.UTC)
   194  	dbLogger.Log(t, "juju.foo", "code.go:42", loggo.INFO, "all is well")
   195  	dbLogger.Log(t.Add(time.Second), "juju.bar", "go.go:99", loggo.ERROR, "no it isn't")
   196  
   197  	lines := make(chan string)
   198  	go func(numLines int) {
   199  		client := s.APIState.Client()
   200  		reader, err := client.WatchDebugLog(api.DebugLogParams{})
   201  		c.Assert(err, jc.ErrorIsNil)
   202  		defer reader.Close()
   203  
   204  		bufReader := bufio.NewReader(reader)
   205  		for n := 0; n < numLines; n++ {
   206  			line, err := bufReader.ReadString('\n')
   207  			c.Assert(err, jc.ErrorIsNil)
   208  			lines <- line
   209  		}
   210  	}(3)
   211  
   212  	assertLine := func(expected string) {
   213  		select {
   214  		case actual := <-lines:
   215  			c.Assert(actual, gc.Equals, expected)
   216  		case <-time.After(coretesting.LongWait):
   217  			c.Fatal("timed out waiting for log line")
   218  		}
   219  	}
   220  
   221  	// Read the 2 lines that are in the logs collection.
   222  	assertLine("machine-99: 2015-06-23 13:08:49 INFO juju.foo code.go:42 all is well\n")
   223  	assertLine("machine-99: 2015-06-23 13:08:50 ERROR juju.bar go.go:99 no it isn't\n")
   224  
   225  	// Now write and observe another log. This should be read from the oplog.
   226  	dbLogger.Log(t.Add(2*time.Second), "ju.jitsu", "no.go:3", loggo.WARNING, "beep beep")
   227  	assertLine("machine-99: 2015-06-23 13:08:51 WARNING ju.jitsu no.go:3 beep beep\n")
   228  }