github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/featuretests/leadership_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  	"fmt"
     8  	"io/ioutil"
     9  	"time"
    10  
    11  	"github.com/juju/names"
    12  	gitjujutesting "github.com/juju/testing"
    13  	gc "gopkg.in/check.v1"
    14  
    15  	"github.com/juju/juju/agent"
    16  	"github.com/juju/juju/api/base"
    17  	"github.com/juju/juju/api/leadership"
    18  	"github.com/juju/juju/api/uniter"
    19  	leadershipapi "github.com/juju/juju/apiserver/leadership"
    20  	"github.com/juju/juju/apiserver/params"
    21  	agentcmd "github.com/juju/juju/cmd/jujud/agent"
    22  	agenttesting "github.com/juju/juju/cmd/jujud/agent/testing"
    23  	cmdutil "github.com/juju/juju/cmd/jujud/util"
    24  	"github.com/juju/juju/mongo"
    25  	"github.com/juju/juju/state"
    26  	coretesting "github.com/juju/juju/testing"
    27  	"github.com/juju/juju/testing/factory"
    28  	"github.com/juju/juju/version"
    29  )
    30  
    31  type leadershipSuite struct {
    32  	agenttesting.AgentSuite
    33  
    34  	clientFacade base.ClientFacade
    35  	facadeCaller base.FacadeCaller
    36  	machineAgent *agentcmd.MachineAgent
    37  	unitId       string
    38  	serviceId    string
    39  }
    40  
    41  func (s *leadershipSuite) SetUpTest(c *gc.C) {
    42  
    43  	s.AgentSuite.SetUpTest(c)
    44  
    45  	file, _ := ioutil.TempFile("", "juju-run")
    46  	defer file.Close()
    47  	s.AgentSuite.PatchValue(&agentcmd.JujuRun, file.Name())
    48  
    49  	fakeEnsureMongo := agenttesting.FakeEnsure{}
    50  	s.AgentSuite.PatchValue(&cmdutil.EnsureMongoServer, fakeEnsureMongo.FakeEnsureMongo)
    51  
    52  	// Create a machine to manage the environment.
    53  	stateServer, password := s.Factory.MakeMachineReturningPassword(c, &factory.MachineParams{
    54  		InstanceId: "id-1",
    55  		Nonce:      agent.BootstrapNonce,
    56  		Jobs:       []state.MachineJob{state.JobManageEnviron},
    57  	})
    58  	c.Assert(stateServer.PasswordValid(password), gc.Equals, true)
    59  	c.Assert(stateServer.SetMongoPassword(password), gc.IsNil)
    60  
    61  	// Create a machine to host some units.
    62  	unitHostMachine := s.Factory.MakeMachine(c, &factory.MachineParams{
    63  		Nonce:    agent.BootstrapNonce,
    64  		Password: password,
    65  	})
    66  
    67  	// Create a service and an instance of that service so that we can
    68  	// create a client.
    69  	service := s.Factory.MakeService(c, &factory.ServiceParams{})
    70  	s.serviceId = service.Tag().Id()
    71  
    72  	unit := s.Factory.MakeUnit(c, &factory.UnitParams{Machine: unitHostMachine, Service: service})
    73  	s.unitId = unit.UnitTag().Id()
    74  
    75  	c.Assert(unit.SetPassword(password), gc.IsNil)
    76  	unitState := s.OpenAPIAs(c, unit.Tag(), password)
    77  
    78  	// Create components needed to construct a client.
    79  	s.clientFacade, s.facadeCaller = base.NewClientFacade(unitState, leadershipapi.FacadeName)
    80  	c.Assert(s.clientFacade, gc.NotNil)
    81  	c.Assert(s.facadeCaller, gc.NotNil)
    82  
    83  	// Tweak and write out the config file for the state server.
    84  	writeStateAgentConfig(
    85  		c,
    86  		s.MongoInfo(c),
    87  		s.DataDir(),
    88  		stateServer.Tag(),
    89  		s.State.EnvironTag(),
    90  		password,
    91  		version.Current,
    92  	)
    93  
    94  	// Create & start a machine agent so the tests have something to call into.
    95  	agentConf := agentcmd.AgentConf{DataDir: s.DataDir()}
    96  	machineAgentFactory := agentcmd.MachineAgentFactoryFn(&agentConf, &agentConf)
    97  	s.machineAgent = machineAgentFactory(stateServer.Id())
    98  
    99  	c.Log("Starting machine agent...")
   100  	go func() {
   101  		err := s.machineAgent.Run(coretesting.Context(c))
   102  		c.Assert(err, gc.IsNil)
   103  	}()
   104  }
   105  
   106  func (s *leadershipSuite) TearDownTest(c *gc.C) {
   107  	c.Log("Stopping machine agent...")
   108  	err := s.machineAgent.Stop()
   109  	c.Assert(err, gc.IsNil)
   110  
   111  	s.AgentSuite.TearDownTest(c)
   112  }
   113  
   114  func (s *leadershipSuite) TestClaimLeadership(c *gc.C) {
   115  
   116  	client := leadership.NewClient(s.clientFacade, s.facadeCaller)
   117  	defer func() { err := client.Close(); c.Assert(err, gc.IsNil) }()
   118  
   119  	duration, err := client.ClaimLeadership(s.serviceId, s.unitId)
   120  
   121  	c.Assert(err, gc.IsNil)
   122  	c.Check(duration, gc.Equals, 30*time.Second)
   123  }
   124  
   125  func (s *leadershipSuite) TestReleaseLeadership(c *gc.C) {
   126  
   127  	client := leadership.NewClient(s.clientFacade, s.facadeCaller)
   128  	defer func() { err := client.Close(); c.Assert(err, gc.IsNil) }()
   129  
   130  	_, err := client.ClaimLeadership(s.serviceId, s.unitId)
   131  	c.Assert(err, gc.IsNil)
   132  
   133  	err = client.ReleaseLeadership(s.serviceId, s.unitId)
   134  	c.Assert(err, gc.IsNil)
   135  }
   136  
   137  func (s *leadershipSuite) TestUnblock(c *gc.C) {
   138  
   139  	client := leadership.NewClient(s.clientFacade, s.facadeCaller)
   140  	defer func() { err := client.Close(); c.Assert(err, gc.IsNil) }()
   141  
   142  	_, err := client.ClaimLeadership(s.serviceId, s.unitId)
   143  	c.Assert(err, gc.IsNil)
   144  
   145  	unblocked := make(chan struct{})
   146  	go func() {
   147  		err := client.BlockUntilLeadershipReleased(s.serviceId)
   148  		c.Check(err, gc.IsNil)
   149  		unblocked <- struct{}{}
   150  	}()
   151  
   152  	time.Sleep(coretesting.ShortWait)
   153  
   154  	err = client.ReleaseLeadership(s.serviceId, s.unitId)
   155  	c.Assert(err, gc.IsNil)
   156  
   157  	select {
   158  	case <-time.After(coretesting.LongWait):
   159  		c.Errorf("Timed out waiting for leadership to release.")
   160  	case <-unblocked:
   161  	}
   162  }
   163  
   164  type uniterLeadershipSuite struct {
   165  	agenttesting.AgentSuite
   166  
   167  	factory      *factory.Factory
   168  	clientFacade base.ClientFacade
   169  	facadeCaller base.FacadeCaller
   170  	machineAgent *agentcmd.MachineAgent
   171  	unitId       string
   172  	serviceId    string
   173  }
   174  
   175  func (s *uniterLeadershipSuite) TestReadLeadershipSettings(c *gc.C) {
   176  
   177  	// First, the unit must be elected leader; otherwise merges will be denied.
   178  	leaderClient := leadership.NewClient(s.clientFacade, s.facadeCaller)
   179  	defer func() { err := leaderClient.Close(); c.Assert(err, gc.IsNil) }()
   180  	_, err := leaderClient.ClaimLeadership(s.serviceId, s.unitId)
   181  	c.Assert(err, gc.IsNil)
   182  
   183  	client := uniter.NewState(s.facadeCaller.RawAPICaller(), names.NewUnitTag(s.unitId))
   184  
   185  	// Toss a few settings in.
   186  	desiredSettings := map[string]string{
   187  		"foo": "bar",
   188  		"baz": "biz",
   189  	}
   190  
   191  	err = client.LeadershipSettings.Merge(s.serviceId, desiredSettings)
   192  	c.Assert(err, gc.IsNil)
   193  
   194  	settings, err := client.LeadershipSettings.Read(s.serviceId)
   195  	c.Assert(err, gc.IsNil)
   196  	c.Check(settings, gc.DeepEquals, desiredSettings)
   197  }
   198  
   199  func (s *uniterLeadershipSuite) TestMergeLeadershipSettings(c *gc.C) {
   200  
   201  	// First, the unit must be elected leader; otherwise merges will be denied.
   202  	leaderClient := leadership.NewClient(s.clientFacade, s.facadeCaller)
   203  	defer func() { err := leaderClient.Close(); c.Assert(err, gc.IsNil) }()
   204  	_, err := leaderClient.ClaimLeadership(s.serviceId, s.unitId)
   205  	c.Assert(err, gc.IsNil)
   206  
   207  	client := uniter.NewState(s.facadeCaller.RawAPICaller(), names.NewUnitTag(s.unitId))
   208  
   209  	// Grab what settings exist.
   210  	settings, err := client.LeadershipSettings.Read(s.serviceId)
   211  	c.Assert(err, gc.IsNil)
   212  	// Double check that it's empty so that we don't pass the test by
   213  	// happenstance.
   214  	c.Assert(settings, gc.HasLen, 0)
   215  
   216  	// Toss a few settings in.
   217  	settings["foo"] = "bar"
   218  	settings["baz"] = "biz"
   219  
   220  	err = client.LeadershipSettings.Merge(s.serviceId, settings)
   221  	c.Assert(err, gc.IsNil)
   222  
   223  	settings, err = client.LeadershipSettings.Read(s.serviceId)
   224  	c.Assert(err, gc.IsNil)
   225  	c.Check(settings["foo"], gc.Equals, "bar")
   226  	c.Check(settings["baz"], gc.Equals, "biz")
   227  }
   228  
   229  func (s *uniterLeadershipSuite) TestSettingsChangeNotifier(c *gc.C) {
   230  
   231  	// First, the unit must be elected leader; otherwise merges will be denied.
   232  	leadershipClient := leadership.NewClient(s.clientFacade, s.facadeCaller)
   233  	defer func() { err := leadershipClient.Close(); c.Assert(err, gc.IsNil) }()
   234  	_, err := leadershipClient.ClaimLeadership(s.serviceId, s.unitId)
   235  	c.Assert(err, gc.IsNil)
   236  
   237  	client := uniter.NewState(s.facadeCaller.RawAPICaller(), names.NewUnitTag(s.unitId))
   238  
   239  	// Listen for changes
   240  	sawChanges := make(chan struct{})
   241  	go func() {
   242  		watcher, err := client.LeadershipSettings.WatchLeadershipSettings(s.serviceId)
   243  		c.Assert(err, gc.IsNil)
   244  		sawChanges <- <-watcher.Changes()
   245  	}()
   246  
   247  	err = client.LeadershipSettings.Merge(s.serviceId, map[string]string{"foo": "bar"})
   248  	c.Assert(err, gc.IsNil)
   249  
   250  	<-sawChanges
   251  }
   252  
   253  func (s *uniterLeadershipSuite) SetUpTest(c *gc.C) {
   254  
   255  	s.AgentSuite.SetUpTest(c)
   256  
   257  	file, _ := ioutil.TempFile("", "juju-run")
   258  	defer file.Close()
   259  	s.AgentSuite.PatchValue(&agentcmd.JujuRun, file.Name())
   260  
   261  	fakeEnsureMongo := agenttesting.FakeEnsure{}
   262  	s.AgentSuite.PatchValue(&cmdutil.EnsureMongoServer, fakeEnsureMongo.FakeEnsureMongo)
   263  
   264  	s.factory = factory.NewFactory(s.State)
   265  
   266  	// Create a machine to manage the environment, and set all
   267  	// passwords to something known.
   268  	stateServer, password := s.factory.MakeMachineReturningPassword(c, &factory.MachineParams{
   269  		InstanceId: "id-1",
   270  		Nonce:      agent.BootstrapNonce,
   271  		Jobs:       []state.MachineJob{state.JobManageEnviron},
   272  	})
   273  	c.Assert(stateServer.PasswordValid(password), gc.Equals, true)
   274  	c.Assert(stateServer.SetMongoPassword(password), gc.IsNil)
   275  
   276  	// Create a machine to host some units.
   277  	unitHostMachine := s.factory.MakeMachine(c, &factory.MachineParams{
   278  		Nonce:    agent.BootstrapNonce,
   279  		Password: password,
   280  	})
   281  
   282  	// Create a service and an instance of that service so that we can
   283  	// create a client.
   284  	service := s.factory.MakeService(c, &factory.ServiceParams{})
   285  	s.serviceId = service.Tag().Id()
   286  
   287  	unit := s.factory.MakeUnit(c, &factory.UnitParams{Machine: unitHostMachine, Service: service})
   288  	s.unitId = unit.UnitTag().Id()
   289  
   290  	c.Assert(unit.SetPassword(password), gc.IsNil)
   291  	unitState := s.OpenAPIAs(c, unit.Tag(), password)
   292  
   293  	// Create components needed to construct a client.
   294  	s.clientFacade, s.facadeCaller = base.NewClientFacade(unitState, leadershipapi.FacadeName)
   295  	c.Assert(s.clientFacade, gc.NotNil)
   296  	c.Assert(s.facadeCaller, gc.NotNil)
   297  
   298  	// Tweak and write out the config file for the state server.
   299  	writeStateAgentConfig(
   300  		c,
   301  		s.MongoInfo(c),
   302  		s.DataDir(),
   303  		names.NewMachineTag(stateServer.Id()),
   304  		s.State.EnvironTag(),
   305  		password,
   306  		version.Current,
   307  	)
   308  
   309  	// Create & start a machine agent so the tests have something to call into.
   310  	agentConf := agentcmd.AgentConf{DataDir: s.DataDir()}
   311  	machineAgentFactory := agentcmd.MachineAgentFactoryFn(&agentConf, &agentConf)
   312  	s.machineAgent = machineAgentFactory(stateServer.Id())
   313  
   314  	c.Log("Starting machine agent...")
   315  	go func() {
   316  		err := s.machineAgent.Run(coretesting.Context(c))
   317  		c.Assert(err, gc.IsNil)
   318  	}()
   319  }
   320  
   321  func (s *uniterLeadershipSuite) TearDownTest(c *gc.C) {
   322  	c.Log("Stopping machine agent...")
   323  	err := s.machineAgent.Stop()
   324  	c.Assert(err, gc.IsNil)
   325  
   326  	s.AgentSuite.TearDownTest(c)
   327  }
   328  
   329  func writeStateAgentConfig(
   330  	c *gc.C,
   331  	stateInfo *mongo.MongoInfo,
   332  	dataDir string,
   333  	tag names.Tag,
   334  	environTag names.EnvironTag,
   335  	password string,
   336  	vers version.Binary,
   337  ) agent.ConfigSetterWriter {
   338  
   339  	port := gitjujutesting.FindTCPPort()
   340  	apiAddr := []string{fmt.Sprintf("localhost:%d", port)}
   341  	conf, err := agent.NewStateMachineConfig(
   342  		agent.AgentConfigParams{
   343  			DataDir:           dataDir,
   344  			Tag:               tag,
   345  			Environment:       environTag,
   346  			UpgradedToVersion: vers.Number,
   347  			Password:          password,
   348  			Nonce:             agent.BootstrapNonce,
   349  			StateAddresses:    stateInfo.Addrs,
   350  			APIAddresses:      apiAddr,
   351  			CACert:            stateInfo.CACert,
   352  		},
   353  		params.StateServingInfo{
   354  			Cert:         coretesting.ServerCert,
   355  			PrivateKey:   coretesting.ServerKey,
   356  			CAPrivateKey: coretesting.CAKey,
   357  			StatePort:    gitjujutesting.MgoServer.Port(),
   358  			APIPort:      port,
   359  		})
   360  	c.Assert(err, gc.IsNil)
   361  	conf.SetPassword(password)
   362  	c.Assert(conf.Write(), gc.IsNil)
   363  	return conf
   364  }