github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/apiserver/client/status_test.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package client_test
     5  
     6  import (
     7  	"time"
     8  
     9  	jc "github.com/juju/testing/checkers"
    10  	"github.com/juju/utils"
    11  	gc "gopkg.in/check.v1"
    12  	"gopkg.in/juju/names.v2"
    13  
    14  	"github.com/juju/juju/api"
    15  	"github.com/juju/juju/apiserver/charmrevisionupdater"
    16  	"github.com/juju/juju/apiserver/charmrevisionupdater/testing"
    17  	"github.com/juju/juju/apiserver/client"
    18  	"github.com/juju/juju/apiserver/common"
    19  	"github.com/juju/juju/apiserver/params"
    20  	apiservertesting "github.com/juju/juju/apiserver/testing"
    21  	"github.com/juju/juju/core/migration"
    22  	"github.com/juju/juju/instance"
    23  	jujutesting "github.com/juju/juju/juju/testing"
    24  	"github.com/juju/juju/state"
    25  	"github.com/juju/juju/testing/factory"
    26  )
    27  
    28  type statusSuite struct {
    29  	baseSuite
    30  }
    31  
    32  var _ = gc.Suite(&statusSuite{})
    33  
    34  func (s *statusSuite) addMachine(c *gc.C) *state.Machine {
    35  	machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
    36  	c.Assert(err, jc.ErrorIsNil)
    37  	return machine
    38  }
    39  
    40  // Complete testing of status functionality happens elsewhere in the codebase,
    41  // these tests just sanity-check the api itself.
    42  
    43  func (s *statusSuite) TestFullStatus(c *gc.C) {
    44  	machine := s.addMachine(c)
    45  	client := s.APIState.Client()
    46  	status, err := client.Status(nil)
    47  	c.Assert(err, jc.ErrorIsNil)
    48  	c.Check(status.Model.Name, gc.Equals, "controller")
    49  	c.Check(status.Model.CloudTag, gc.Equals, "cloud-dummy")
    50  	c.Check(status.Applications, gc.HasLen, 0)
    51  	c.Check(status.Machines, gc.HasLen, 1)
    52  	resultMachine, ok := status.Machines[machine.Id()]
    53  	if !ok {
    54  		c.Fatalf("Missing machine with id %q", machine.Id())
    55  	}
    56  	c.Check(resultMachine.Id, gc.Equals, machine.Id())
    57  	c.Check(resultMachine.Series, gc.Equals, machine.Series())
    58  }
    59  
    60  func (s *statusSuite) TestFullStatusUnitLeadership(c *gc.C) {
    61  	u := s.Factory.MakeUnit(c, nil)
    62  	s.State.LeadershipClaimer().ClaimLeadership(u.ApplicationName(), u.Name(), time.Minute)
    63  	client := s.APIState.Client()
    64  	status, err := client.Status(nil)
    65  	c.Assert(err, jc.ErrorIsNil)
    66  	app, ok := status.Applications[u.ApplicationName()]
    67  	c.Assert(ok, jc.IsTrue)
    68  	unit, ok := app.Units[u.Name()]
    69  	c.Assert(ok, jc.IsTrue)
    70  	c.Assert(unit.Leader, jc.IsTrue)
    71  }
    72  
    73  var _ = gc.Suite(&statusUnitTestSuite{})
    74  
    75  type statusUnitTestSuite struct {
    76  	baseSuite
    77  }
    78  
    79  func (s *statusUnitTestSuite) TestProcessMachinesWithOneMachineAndOneContainer(c *gc.C) {
    80  	host := s.Factory.MakeMachine(c, &factory.MachineParams{InstanceId: instance.Id("0")})
    81  	container := s.Factory.MakeMachineNested(c, host.Id(), nil)
    82  	machines := map[string][]*state.Machine{
    83  		host.Id(): {host, container},
    84  	}
    85  
    86  	statuses := client.ProcessMachines(machines)
    87  	c.Assert(statuses, gc.Not(gc.IsNil))
    88  
    89  	containerStatus := client.MakeMachineStatus(container)
    90  	c.Check(statuses[host.Id()].Containers[container.Id()].Id, gc.Equals, containerStatus.Id)
    91  }
    92  
    93  func (s *statusUnitTestSuite) TestProcessMachinesWithEmbeddedContainers(c *gc.C) {
    94  	host := s.Factory.MakeMachine(c, &factory.MachineParams{InstanceId: instance.Id("1")})
    95  	lxdHost := s.Factory.MakeMachineNested(c, host.Id(), nil)
    96  	machines := map[string][]*state.Machine{
    97  		host.Id(): {
    98  			host,
    99  			lxdHost,
   100  			s.Factory.MakeMachineNested(c, lxdHost.Id(), nil),
   101  			s.Factory.MakeMachineNested(c, host.Id(), nil),
   102  		},
   103  	}
   104  
   105  	statuses := client.ProcessMachines(machines)
   106  	c.Assert(statuses, gc.Not(gc.IsNil))
   107  
   108  	hostContainer := statuses[host.Id()].Containers
   109  	c.Check(hostContainer, gc.HasLen, 2)
   110  	c.Check(hostContainer[lxdHost.Id()].Containers, gc.HasLen, 1)
   111  }
   112  
   113  var testUnits = []struct {
   114  	unitName       string
   115  	setStatus      *state.MeterStatus
   116  	expectedStatus *params.MeterStatus
   117  }{{
   118  	setStatus:      &state.MeterStatus{Code: state.MeterGreen, Info: "test information"},
   119  	expectedStatus: &params.MeterStatus{Color: "green", Message: "test information"},
   120  }, {
   121  	setStatus:      &state.MeterStatus{Code: state.MeterAmber, Info: "test information"},
   122  	expectedStatus: &params.MeterStatus{Color: "amber", Message: "test information"},
   123  }, {
   124  	setStatus:      &state.MeterStatus{Code: state.MeterRed, Info: "test information"},
   125  	expectedStatus: &params.MeterStatus{Color: "red", Message: "test information"},
   126  }, {
   127  	setStatus:      &state.MeterStatus{Code: state.MeterGreen, Info: "test information"},
   128  	expectedStatus: &params.MeterStatus{Color: "green", Message: "test information"},
   129  }, {},
   130  }
   131  
   132  func (s *statusUnitTestSuite) TestMeterStatus(c *gc.C) {
   133  	meteredCharm := s.Factory.MakeCharm(c, &factory.CharmParams{Name: "metered", URL: "cs:quantal/metered"})
   134  	service := s.Factory.MakeApplication(c, &factory.ApplicationParams{Charm: meteredCharm})
   135  
   136  	units, err := service.AllUnits()
   137  	c.Assert(err, jc.ErrorIsNil)
   138  	c.Assert(units, gc.HasLen, 0)
   139  
   140  	for i, unit := range testUnits {
   141  		u, err := service.AddUnit()
   142  		testUnits[i].unitName = u.Name()
   143  		c.Assert(err, jc.ErrorIsNil)
   144  		if unit.setStatus != nil {
   145  			err := u.SetMeterStatus(unit.setStatus.Code.String(), unit.setStatus.Info)
   146  			c.Assert(err, jc.ErrorIsNil)
   147  		}
   148  	}
   149  
   150  	client := s.APIState.Client()
   151  	status, err := client.Status(nil)
   152  	c.Assert(err, jc.ErrorIsNil)
   153  	c.Assert(status, gc.NotNil)
   154  	serviceStatus, ok := status.Applications[service.Name()]
   155  	c.Assert(ok, gc.Equals, true)
   156  
   157  	c.Assert(serviceStatus.MeterStatuses, gc.HasLen, len(testUnits)-1)
   158  	for _, unit := range testUnits {
   159  		unitStatus, ok := serviceStatus.MeterStatuses[unit.unitName]
   160  
   161  		if unit.expectedStatus != nil {
   162  			c.Assert(ok, gc.Equals, true)
   163  			c.Assert(&unitStatus, gc.DeepEquals, unit.expectedStatus)
   164  		} else {
   165  			c.Assert(ok, gc.Equals, false)
   166  		}
   167  	}
   168  }
   169  
   170  func (s *statusUnitTestSuite) TestNoMeterStatusWhenNotRequired(c *gc.C) {
   171  	service := s.Factory.MakeApplication(c, nil)
   172  
   173  	units, err := service.AllUnits()
   174  	c.Assert(err, jc.ErrorIsNil)
   175  	c.Assert(units, gc.HasLen, 0)
   176  
   177  	for i, unit := range testUnits {
   178  		u, err := service.AddUnit()
   179  		testUnits[i].unitName = u.Name()
   180  		c.Assert(err, jc.ErrorIsNil)
   181  		if unit.setStatus != nil {
   182  			err := u.SetMeterStatus(unit.setStatus.Code.String(), unit.setStatus.Info)
   183  			c.Assert(err, jc.ErrorIsNil)
   184  		}
   185  	}
   186  
   187  	client := s.APIState.Client()
   188  	status, err := client.Status(nil)
   189  	c.Assert(err, jc.ErrorIsNil)
   190  	c.Assert(status, gc.NotNil)
   191  	serviceStatus, ok := status.Applications[service.Name()]
   192  	c.Assert(ok, gc.Equals, true)
   193  
   194  	c.Assert(serviceStatus.MeterStatuses, gc.HasLen, 0)
   195  }
   196  
   197  func (s *statusUnitTestSuite) TestMeterStatusWithCredentials(c *gc.C) {
   198  	service := s.Factory.MakeApplication(c, nil)
   199  	c.Assert(service.SetMetricCredentials([]byte("magic-ticket")), jc.ErrorIsNil)
   200  
   201  	units, err := service.AllUnits()
   202  	c.Assert(err, jc.ErrorIsNil)
   203  	c.Assert(units, gc.HasLen, 0)
   204  
   205  	for i, unit := range testUnits {
   206  		u, err := service.AddUnit()
   207  		testUnits[i].unitName = u.Name()
   208  		c.Assert(err, jc.ErrorIsNil)
   209  		if unit.setStatus != nil {
   210  			err := u.SetMeterStatus(unit.setStatus.Code.String(), unit.setStatus.Info)
   211  			c.Assert(err, jc.ErrorIsNil)
   212  		}
   213  	}
   214  
   215  	client := s.APIState.Client()
   216  	status, err := client.Status(nil)
   217  	c.Assert(err, jc.ErrorIsNil)
   218  	c.Assert(status, gc.NotNil)
   219  	serviceStatus, ok := status.Applications[service.Name()]
   220  	c.Assert(ok, gc.Equals, true)
   221  
   222  	c.Assert(serviceStatus.MeterStatuses, gc.HasLen, len(testUnits)-1)
   223  	for _, unit := range testUnits {
   224  		unitStatus, ok := serviceStatus.MeterStatuses[unit.unitName]
   225  
   226  		if unit.expectedStatus != nil {
   227  			c.Assert(ok, gc.Equals, true)
   228  			c.Assert(&unitStatus, gc.DeepEquals, unit.expectedStatus)
   229  		} else {
   230  			c.Assert(ok, gc.Equals, false)
   231  		}
   232  	}
   233  }
   234  
   235  func addUnitWithVersion(c *gc.C, application *state.Application, version string) *state.Unit {
   236  	unit, err := application.AddUnit()
   237  	c.Assert(err, jc.ErrorIsNil)
   238  	// Ensure that the timestamp on this version record is different
   239  	// from the previous one.
   240  	// TODO(babbageclunk): when Application and Unit have clocks, change
   241  	// that instead of sleeping (lp:1558657)
   242  	time.Sleep(time.Millisecond * 1)
   243  	err = unit.SetWorkloadVersion(version)
   244  	c.Assert(err, jc.ErrorIsNil)
   245  	return unit
   246  }
   247  
   248  func (s *statusUnitTestSuite) checkAppVersion(c *gc.C, application *state.Application, expectedVersion string) params.ApplicationStatus {
   249  	client := s.APIState.Client()
   250  	status, err := client.Status(nil)
   251  	c.Assert(err, jc.ErrorIsNil)
   252  	appStatus, found := status.Applications[application.Name()]
   253  	c.Assert(found, jc.IsTrue)
   254  	c.Check(appStatus.WorkloadVersion, gc.Equals, expectedVersion)
   255  	return appStatus
   256  }
   257  
   258  func checkUnitVersion(c *gc.C, appStatus params.ApplicationStatus, unit *state.Unit, expectedVersion string) {
   259  	unitStatus, found := appStatus.Units[unit.Name()]
   260  	c.Check(found, jc.IsTrue)
   261  	c.Check(unitStatus.WorkloadVersion, gc.Equals, expectedVersion)
   262  }
   263  
   264  func (s *statusUnitTestSuite) TestWorkloadVersionLastWins(c *gc.C) {
   265  	application := s.Factory.MakeApplication(c, nil)
   266  	unit1 := addUnitWithVersion(c, application, "voltron")
   267  	unit2 := addUnitWithVersion(c, application, "voltron")
   268  	unit3 := addUnitWithVersion(c, application, "zarkon")
   269  
   270  	appStatus := s.checkAppVersion(c, application, "zarkon")
   271  	checkUnitVersion(c, appStatus, unit1, "voltron")
   272  	checkUnitVersion(c, appStatus, unit2, "voltron")
   273  	checkUnitVersion(c, appStatus, unit3, "zarkon")
   274  }
   275  
   276  func (s *statusUnitTestSuite) TestWorkloadVersionSimple(c *gc.C) {
   277  	application := s.Factory.MakeApplication(c, nil)
   278  	unit1 := addUnitWithVersion(c, application, "voltron")
   279  
   280  	appStatus := s.checkAppVersion(c, application, "voltron")
   281  	checkUnitVersion(c, appStatus, unit1, "voltron")
   282  }
   283  
   284  func (s *statusUnitTestSuite) TestWorkloadVersionBlanksCanWin(c *gc.C) {
   285  	application := s.Factory.MakeApplication(c, nil)
   286  	unit1 := addUnitWithVersion(c, application, "voltron")
   287  	unit2 := addUnitWithVersion(c, application, "")
   288  
   289  	appStatus := s.checkAppVersion(c, application, "")
   290  	checkUnitVersion(c, appStatus, unit1, "voltron")
   291  	checkUnitVersion(c, appStatus, unit2, "")
   292  }
   293  
   294  func (s *statusUnitTestSuite) TestWorkloadVersionNoUnits(c *gc.C) {
   295  	application := s.Factory.MakeApplication(c, nil)
   296  	s.checkAppVersion(c, application, "")
   297  }
   298  
   299  func (s *statusUnitTestSuite) TestWorkloadVersionOkWithUnset(c *gc.C) {
   300  	application := s.Factory.MakeApplication(c, nil)
   301  	unit, err := application.AddUnit()
   302  	c.Assert(err, jc.ErrorIsNil)
   303  	appStatus := s.checkAppVersion(c, application, "")
   304  	checkUnitVersion(c, appStatus, unit, "")
   305  }
   306  
   307  func (s *statusUnitTestSuite) TestMigrationInProgress(c *gc.C) {
   308  
   309  	// Create a host model because controller models can't be migrated.
   310  	state2 := s.Factory.MakeModel(c, nil)
   311  	defer state2.Close()
   312  
   313  	// Get API connection to hosted model.
   314  	apiInfo := s.APIInfo(c)
   315  	apiInfo.ModelTag = state2.ModelTag()
   316  	conn, err := api.Open(apiInfo, api.DialOpts{})
   317  	c.Assert(err, jc.ErrorIsNil)
   318  	client := conn.Client()
   319  
   320  	checkMigStatus := func(expected string) {
   321  		status, err := client.Status(nil)
   322  		c.Assert(err, jc.ErrorIsNil)
   323  		c.Check(status.Model.Migration, gc.Equals, expected)
   324  	}
   325  
   326  	// Migration status should be empty when no migration is happening.
   327  	checkMigStatus("")
   328  
   329  	// Start it migrating.
   330  	mig, err := state2.CreateMigration(state.MigrationSpec{
   331  		InitiatedBy: names.NewUserTag("admin"),
   332  		TargetInfo: migration.TargetInfo{
   333  			ControllerTag: names.NewControllerTag(utils.MustNewUUID().String()),
   334  			Addrs:         []string{"1.2.3.4:5555", "4.3.2.1:6666"},
   335  			CACert:        "cert",
   336  			AuthTag:       names.NewUserTag("user"),
   337  			Password:      "password",
   338  		},
   339  	})
   340  	c.Assert(err, jc.ErrorIsNil)
   341  
   342  	// Check initial message.
   343  	checkMigStatus("starting")
   344  
   345  	// Check status is reported when set.
   346  	setAndCheckMigStatus := func(message string) {
   347  		err := mig.SetStatusMessage(message)
   348  		c.Assert(err, jc.ErrorIsNil)
   349  		checkMigStatus(message)
   350  	}
   351  	setAndCheckMigStatus("proceeding swimmingly")
   352  	setAndCheckMigStatus("oh noes")
   353  }
   354  
   355  type statusUpgradeUnitSuite struct {
   356  	testing.CharmSuite
   357  	jujutesting.JujuConnSuite
   358  
   359  	charmrevisionupdater *charmrevisionupdater.CharmRevisionUpdaterAPI
   360  	resources            *common.Resources
   361  	authoriser           apiservertesting.FakeAuthorizer
   362  }
   363  
   364  var _ = gc.Suite(&statusUpgradeUnitSuite{})
   365  
   366  func (s *statusUpgradeUnitSuite) SetUpSuite(c *gc.C) {
   367  	s.JujuConnSuite.SetUpSuite(c)
   368  	s.CharmSuite.SetUpSuite(c, &s.JujuConnSuite)
   369  }
   370  
   371  func (s *statusUpgradeUnitSuite) TearDownSuite(c *gc.C) {
   372  	s.CharmSuite.TearDownSuite(c)
   373  	s.JujuConnSuite.TearDownSuite(c)
   374  }
   375  
   376  func (s *statusUpgradeUnitSuite) SetUpTest(c *gc.C) {
   377  	s.JujuConnSuite.SetUpTest(c)
   378  	s.CharmSuite.SetUpTest(c)
   379  	s.resources = common.NewResources()
   380  	s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() })
   381  	s.authoriser = apiservertesting.FakeAuthorizer{
   382  		EnvironManager: true,
   383  	}
   384  	var err error
   385  	s.charmrevisionupdater, err = charmrevisionupdater.NewCharmRevisionUpdaterAPI(s.State, s.resources, s.authoriser)
   386  	c.Assert(err, jc.ErrorIsNil)
   387  }
   388  
   389  func (s *statusUpgradeUnitSuite) TearDownTest(c *gc.C) {
   390  	s.CharmSuite.TearDownTest(c)
   391  	s.JujuConnSuite.TearDownTest(c)
   392  }
   393  
   394  func (s *statusUpgradeUnitSuite) TestUpdateRevisions(c *gc.C) {
   395  	s.AddMachine(c, "0", state.JobManageModel)
   396  	s.SetupScenario(c)
   397  	client := s.APIState.Client()
   398  	status, _ := client.Status(nil)
   399  
   400  	serviceStatus, ok := status.Applications["mysql"]
   401  	c.Assert(ok, gc.Equals, true)
   402  	c.Assert(serviceStatus.CanUpgradeTo, gc.Equals, "")
   403  
   404  	// Update to the latest available charm revision.
   405  	result, err := s.charmrevisionupdater.UpdateLatestRevisions()
   406  	c.Assert(err, jc.ErrorIsNil)
   407  	c.Assert(result.Error, gc.IsNil)
   408  
   409  	// Check if CanUpgradeTo suggest the latest revision.
   410  	status, _ = client.Status(nil)
   411  	serviceStatus, ok = status.Applications["mysql"]
   412  	c.Assert(ok, gc.Equals, true)
   413  	c.Assert(serviceStatus.CanUpgradeTo, gc.Equals, "cs:quantal/mysql-23")
   414  }