github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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: ¶ms.MeterStatus{Color: "green", Message: "test information"}, 120 }, { 121 setStatus: &state.MeterStatus{Code: state.MeterAmber, Info: "test information"}, 122 expectedStatus: ¶ms.MeterStatus{Color: "amber", Message: "test information"}, 123 }, { 124 setStatus: &state.MeterStatus{Code: state.MeterRed, Info: "test information"}, 125 expectedStatus: ¶ms.MeterStatus{Color: "red", Message: "test information"}, 126 }, { 127 setStatus: &state.MeterStatus{Code: state.MeterGreen, Info: "test information"}, 128 expectedStatus: ¶ms.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 }